web/lib/Zend/Http/Client.php
changeset 807 877f952ae2bd
parent 207 621fa6caec0c
child 1230 68c69c656a2c
--- a/web/lib/Zend/Http/Client.php	Thu Mar 21 17:31:31 2013 +0100
+++ b/web/lib/Zend/Http/Client.php	Thu Mar 21 19:50:53 2013 +0100
@@ -16,8 +16,8 @@
  * @category   Zend
  * @package    Zend_Http
  * @subpackage Client
- * @version    $Id: Client.php 23443 2010-11-24 11:53:13Z shahar $
- * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @version    $Id: Client.php 24593 2012-01-05 20:35:02Z matthew $
+ * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 
@@ -60,7 +60,7 @@
  * @package    Zend_Http
  * @subpackage Client
  * @throws     Zend_Http_Client_Exception
- * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
 class Zend_Http_Client
@@ -103,6 +103,12 @@
     const ENC_FORMDATA   = 'multipart/form-data';
 
     /**
+     * Value types for Body key/value pairs
+     */
+    const VTYPE_SCALAR  = 'SCALAR';
+    const VTYPE_FILE    = 'FILE';
+
+    /**
      * Configuration array, set using the constructor or using ::setConfig()
      *
      * @var array
@@ -203,6 +209,16 @@
     protected $files = array();
 
     /**
+     * Ordered list of keys from key/value pair data to include in body
+     *
+     * An associative array, where each element is of the format:
+     *   '<field name>' => VTYPE_SCALAR | VTYPE_FILE
+     *
+     * @var array
+     */
+    protected $body_field_order = array();
+
+    /**
      * The client's cookie jar
      *
      * @var Zend_Http_CookieJar
@@ -231,6 +247,20 @@
     protected $redirectCounter = 0;
 
     /**
+     * Status for unmasking GET array params
+     *
+     * @var boolean
+     */
+    protected $_unmaskStatus = false;
+
+    /**
+     * Status if the http_build_query function escapes brackets
+     *
+     * @var boolean
+     */
+    protected $_queryBracketsEscaped = true;
+
+    /**
      * Fileinfo magic database resource
      *
      * This variable is populated the first time _detectFileMimeType is called
@@ -255,6 +285,8 @@
         if ($config !== null) {
             $this->setConfig($config);
         }
+
+        $this->_queryBracketsEscaped = version_compare(phpversion(), '5.1.3', '>=');
     }
 
     /**
@@ -266,7 +298,10 @@
      */
     public function setUri($uri)
     {
-        if (is_string($uri)) {
+        if ($uri instanceof Zend_Uri_Http) {
+            // clone the URI in order to keep the passed parameter constant
+            $uri = clone $uri;
+        } elseif (is_string($uri)) {
             $uri = Zend_Uri::factory($uri);
         }
 
@@ -355,7 +390,7 @@
             throw new Zend_Http_Client_Exception("'{$method}' is not a valid HTTP request method.");
         }
 
-        if ($method == self::POST && $this->enctype === null) {
+        if (($method == self::POST || $method == self::PUT || $method == self::DELETE) && $this->enctype === null) {
             $this->setEncType(self::ENC_URLENCODED);
         }
 
@@ -501,6 +536,12 @@
                 break;
             case 'post':
                 $parray = &$this->paramsPost;
+                if ( $value === null ) {
+                    if (isset($this->body_field_order[$name]))
+                        unset($this->body_field_order[$name]);
+                } else {
+                    $this->body_field_order[$name] = self::VTYPE_SCALAR;
+                }
                 break;
         }
 
@@ -718,6 +759,8 @@
             'ctype'    => $ctype,
             'data'     => $data
         );
+        
+        $this->body_field_order[$formname] = self::VTYPE_FILE;
 
         return $this;
     }
@@ -764,6 +807,35 @@
     }
 
     /**
+     * Set the unmask feature for GET parameters as array
+     *
+     * Example:
+     * foo%5B0%5D=a&foo%5B1%5D=b
+     * becomes
+     * foo=a&foo=b
+     *
+     * This is usefull for some services
+     *
+     * @param boolean $status
+     * @return Zend_Http_Client
+     */
+    public function setUnmaskStatus($status = true)
+    {
+        $this->_unmaskStatus = (BOOL)$status;
+        return $this;
+    }
+
+    /**
+     * Returns the currently configured unmask status
+     *
+     * @return boolean
+     */
+    public function getUnmaskStatus()
+    {
+        return $this->_unmaskStatus;
+    }
+
+    /**
      * Clear all GET and POST parameters
      *
      * Should be used to reset the request parameters if the client is
@@ -782,6 +854,7 @@
         $this->paramsPost    = array();
         $this->files         = array();
         $this->raw_post_data = null;
+        $this->enctype       = null;
 
         if($clearAll) {
             $this->headers = array();
@@ -866,6 +939,10 @@
      */
     public function getAdapter()
     {
+        if (null === $this->adapter) {
+            $this->setAdapter($this->config['adapter']);
+        }
+
         return $this->adapter;
     }
 
@@ -911,10 +988,10 @@
                 require_once 'Zend/Http/Client/Exception.php';
                 throw new Zend_Http_Client_Exception("Could not open temp file {$this->_stream_name}");
         }
-        
+
         return $fp;
     }
-    
+
     /**
      * Send the HTTP request and return an HTTP response object
      *
@@ -955,6 +1032,15 @@
                     $query = str_replace('+', '%20', $query);
                 }
 
+                // @see ZF-11671 to unmask for some services to foo=val1&foo=val2
+                if ($this->getUnmaskStatus()) {
+                    if ($this->_queryBracketsEscaped) {
+                        $query = preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '=', $query);
+                    } else {
+                        $query = preg_replace('/\\[(?:[0-9]|[1-9][0-9]+)\\]=/', '=', $query);
+                    }
+                }
+
                 $uri->setQuery($query);
             }
 
@@ -994,7 +1080,10 @@
             }
 
             if($this->config['output_stream']) {
-                rewind($stream);
+                $streamMetaData = stream_get_meta_data($stream);
+                if ($streamMetaData['seekable']) {
+                    rewind($stream);
+                }
                 // cleanup the adapter
                 $this->adapter->setOutputStream(null);
                 $response = Zend_Http_Response_Stream::fromStream($response, $stream);
@@ -1019,6 +1108,10 @@
             // If we got redirected, look for the Location header
             if ($response->isRedirect() && ($location = $response->getHeader('location'))) {
 
+                // Avoid problems with buggy servers that add whitespace at the
+                // end of some headers (See ZF-11283)
+                $location = trim($location);
+
                 // Check whether we send the exact same request again, or drop the parameters
                 // and send a GET request
                 if ($response->getStatus() == 303 ||
@@ -1030,7 +1123,7 @@
                 }
 
                 // If we got a well formed absolute URI
-                if (Zend_Uri_Http::check($location)) {
+                if (($scheme = substr($location, 0, 6)) && ($scheme == 'http:/' || $scheme == 'https:')) {
                     $this->setHeaders('host', null);
                     $this->setUri($location);
 
@@ -1198,16 +1291,30 @@
                     $boundary = '---ZENDHTTPCLIENT-' . md5(microtime());
                     $this->setHeaders(self::CONTENT_TYPE, self::ENC_FORMDATA . "; boundary={$boundary}");
 
-                    // Get POST parameters and encode them
-                    $params = self::_flattenParametersArray($this->paramsPost);
-                    foreach ($params as $pp) {
-                        $body .= self::encodeFormData($boundary, $pp[0], $pp[1]);
-                    }
-
-                    // Encode files
-                    foreach ($this->files as $file) {
-                        $fhead = array(self::CONTENT_TYPE => $file['ctype']);
-                        $body .= self::encodeFormData($boundary, $file['formname'], $file['data'], $file['filename'], $fhead);
+                    // Encode all files and POST vars in the order they were given
+                    foreach ($this->body_field_order as $fieldName=>$fieldType) {
+                        switch ($fieldType) {
+                            case self::VTYPE_FILE:
+                                foreach ($this->files as $file) {
+                                    if ($file['formname']===$fieldName) {
+                                        $fhead = array(self::CONTENT_TYPE => $file['ctype']);
+                                        $body .= self::encodeFormData($boundary, $file['formname'], $file['data'], $file['filename'], $fhead);
+                                    }
+                                }
+                                break;
+                            case self::VTYPE_SCALAR:
+                                if (isset($this->paramsPost[$fieldName])) {
+                                    if (is_array($this->paramsPost[$fieldName])) {
+                                        $flattened = self::_flattenParametersArray($this->paramsPost[$fieldName], $fieldName);
+                                        foreach ($flattened as $pp) {
+                                            $body .= self::encodeFormData($boundary, $pp[0], $pp[1]);
+                                        }
+                                    } else {
+                                        $body .= self::encodeFormData($boundary, $fieldName, $this->paramsPost[$fieldName]);
+                                    }
+                                }
+                                break;
+                        }
                     }
 
                     $body .= "--{$boundary}--\r\n";