web/lib/Zend/Http/Client.php
changeset 886 1e110b03ae96
parent 807 877f952ae2bd
child 1230 68c69c656a2c
equal deleted inserted replaced
885:2251fb41dbc7 886:1e110b03ae96
    14  * to license@zend.com so we can send you a copy immediately.
    14  * to license@zend.com so we can send you a copy immediately.
    15  *
    15  *
    16  * @category   Zend
    16  * @category   Zend
    17  * @package    Zend_Http
    17  * @package    Zend_Http
    18  * @subpackage Client
    18  * @subpackage Client
    19  * @version    $Id: Client.php 23443 2010-11-24 11:53:13Z shahar $
    19  * @version    $Id: Client.php 24593 2012-01-05 20:35:02Z matthew $
    20  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
    20  * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
    21  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    21  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    22  */
    22  */
    23 
    23 
    24 /**
    24 /**
    25  * @see Zend_Loader
    25  * @see Zend_Loader
    58  * @todo Implement proxy settings
    58  * @todo Implement proxy settings
    59  * @category   Zend
    59  * @category   Zend
    60  * @package    Zend_Http
    60  * @package    Zend_Http
    61  * @subpackage Client
    61  * @subpackage Client
    62  * @throws     Zend_Http_Client_Exception
    62  * @throws     Zend_Http_Client_Exception
    63  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
    63  * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
    64  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    64  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    65  */
    65  */
    66 class Zend_Http_Client
    66 class Zend_Http_Client
    67 {
    67 {
    68     /**
    68     /**
    99     /**
    99     /**
   100      * POST data encoding methods
   100      * POST data encoding methods
   101      */
   101      */
   102     const ENC_URLENCODED = 'application/x-www-form-urlencoded';
   102     const ENC_URLENCODED = 'application/x-www-form-urlencoded';
   103     const ENC_FORMDATA   = 'multipart/form-data';
   103     const ENC_FORMDATA   = 'multipart/form-data';
       
   104 
       
   105     /**
       
   106      * Value types for Body key/value pairs
       
   107      */
       
   108     const VTYPE_SCALAR  = 'SCALAR';
       
   109     const VTYPE_FILE    = 'FILE';
   104 
   110 
   105     /**
   111     /**
   106      * Configuration array, set using the constructor or using ::setConfig()
   112      * Configuration array, set using the constructor or using ::setConfig()
   107      *
   113      *
   108      * @var array
   114      * @var array
   201      * @var array
   207      * @var array
   202      */
   208      */
   203     protected $files = array();
   209     protected $files = array();
   204 
   210 
   205     /**
   211     /**
       
   212      * Ordered list of keys from key/value pair data to include in body
       
   213      *
       
   214      * An associative array, where each element is of the format:
       
   215      *   '<field name>' => VTYPE_SCALAR | VTYPE_FILE
       
   216      *
       
   217      * @var array
       
   218      */
       
   219     protected $body_field_order = array();
       
   220 
       
   221     /**
   206      * The client's cookie jar
   222      * The client's cookie jar
   207      *
   223      *
   208      * @var Zend_Http_CookieJar
   224      * @var Zend_Http_CookieJar
   209      */
   225      */
   210     protected $cookiejar = null;
   226     protected $cookiejar = null;
   227      * Redirection counter
   243      * Redirection counter
   228      *
   244      *
   229      * @var int
   245      * @var int
   230      */
   246      */
   231     protected $redirectCounter = 0;
   247     protected $redirectCounter = 0;
       
   248 
       
   249     /**
       
   250      * Status for unmasking GET array params
       
   251      *
       
   252      * @var boolean
       
   253      */
       
   254     protected $_unmaskStatus = false;
       
   255 
       
   256     /**
       
   257      * Status if the http_build_query function escapes brackets
       
   258      *
       
   259      * @var boolean
       
   260      */
       
   261     protected $_queryBracketsEscaped = true;
   232 
   262 
   233     /**
   263     /**
   234      * Fileinfo magic database resource
   264      * Fileinfo magic database resource
   235      *
   265      *
   236      * This variable is populated the first time _detectFileMimeType is called
   266      * This variable is populated the first time _detectFileMimeType is called
   253             $this->setUri($uri);
   283             $this->setUri($uri);
   254         }
   284         }
   255         if ($config !== null) {
   285         if ($config !== null) {
   256             $this->setConfig($config);
   286             $this->setConfig($config);
   257         }
   287         }
       
   288 
       
   289         $this->_queryBracketsEscaped = version_compare(phpversion(), '5.1.3', '>=');
   258     }
   290     }
   259 
   291 
   260     /**
   292     /**
   261      * Set the URI for the next request
   293      * Set the URI for the next request
   262      *
   294      *
   264      * @return Zend_Http_Client
   296      * @return Zend_Http_Client
   265      * @throws Zend_Http_Client_Exception
   297      * @throws Zend_Http_Client_Exception
   266      */
   298      */
   267     public function setUri($uri)
   299     public function setUri($uri)
   268     {
   300     {
   269         if (is_string($uri)) {
   301         if ($uri instanceof Zend_Uri_Http) {
       
   302             // clone the URI in order to keep the passed parameter constant
       
   303             $uri = clone $uri;
       
   304         } elseif (is_string($uri)) {
   270             $uri = Zend_Uri::factory($uri);
   305             $uri = Zend_Uri::factory($uri);
   271         }
   306         }
   272 
   307 
   273         if (!$uri instanceof Zend_Uri_Http) {
   308         if (!$uri instanceof Zend_Uri_Http) {
   274             /** @see Zend_Http_Client_Exception */
   309             /** @see Zend_Http_Client_Exception */
   353             /** @see Zend_Http_Client_Exception */
   388             /** @see Zend_Http_Client_Exception */
   354             require_once 'Zend/Http/Client/Exception.php';
   389             require_once 'Zend/Http/Client/Exception.php';
   355             throw new Zend_Http_Client_Exception("'{$method}' is not a valid HTTP request method.");
   390             throw new Zend_Http_Client_Exception("'{$method}' is not a valid HTTP request method.");
   356         }
   391         }
   357 
   392 
   358         if ($method == self::POST && $this->enctype === null) {
   393         if (($method == self::POST || $method == self::PUT || $method == self::DELETE) && $this->enctype === null) {
   359             $this->setEncType(self::ENC_URLENCODED);
   394             $this->setEncType(self::ENC_URLENCODED);
   360         }
   395         }
   361 
   396 
   362         $this->method = $method;
   397         $this->method = $method;
   363 
   398 
   499             case 'get':
   534             case 'get':
   500                 $parray = &$this->paramsGet;
   535                 $parray = &$this->paramsGet;
   501                 break;
   536                 break;
   502             case 'post':
   537             case 'post':
   503                 $parray = &$this->paramsPost;
   538                 $parray = &$this->paramsPost;
       
   539                 if ( $value === null ) {
       
   540                     if (isset($this->body_field_order[$name]))
       
   541                         unset($this->body_field_order[$name]);
       
   542                 } else {
       
   543                     $this->body_field_order[$name] = self::VTYPE_SCALAR;
       
   544                 }
   504                 break;
   545                 break;
   505         }
   546         }
   506 
   547 
   507         if ($value === null) {
   548         if ($value === null) {
   508             if (isset($parray[$name])) unset($parray[$name]);
   549             if (isset($parray[$name])) unset($parray[$name]);
   716             'formname' => $formname,
   757             'formname' => $formname,
   717             'filename' => basename($filename),
   758             'filename' => basename($filename),
   718             'ctype'    => $ctype,
   759             'ctype'    => $ctype,
   719             'data'     => $data
   760             'data'     => $data
   720         );
   761         );
       
   762         
       
   763         $this->body_field_order[$formname] = self::VTYPE_FILE;
   721 
   764 
   722         return $this;
   765         return $this;
   723     }
   766     }
   724 
   767 
   725     /**
   768     /**
   762         }
   805         }
   763         return $this;
   806         return $this;
   764     }
   807     }
   765 
   808 
   766     /**
   809     /**
       
   810      * Set the unmask feature for GET parameters as array
       
   811      *
       
   812      * Example:
       
   813      * foo%5B0%5D=a&foo%5B1%5D=b
       
   814      * becomes
       
   815      * foo=a&foo=b
       
   816      *
       
   817      * This is usefull for some services
       
   818      *
       
   819      * @param boolean $status
       
   820      * @return Zend_Http_Client
       
   821      */
       
   822     public function setUnmaskStatus($status = true)
       
   823     {
       
   824         $this->_unmaskStatus = (BOOL)$status;
       
   825         return $this;
       
   826     }
       
   827 
       
   828     /**
       
   829      * Returns the currently configured unmask status
       
   830      *
       
   831      * @return boolean
       
   832      */
       
   833     public function getUnmaskStatus()
       
   834     {
       
   835         return $this->_unmaskStatus;
       
   836     }
       
   837 
       
   838     /**
   767      * Clear all GET and POST parameters
   839      * Clear all GET and POST parameters
   768      *
   840      *
   769      * Should be used to reset the request parameters if the client is
   841      * Should be used to reset the request parameters if the client is
   770      * used for several concurrent requests.
   842      * used for several concurrent requests.
   771      *
   843      *
   780         // Reset parameter data
   852         // Reset parameter data
   781         $this->paramsGet     = array();
   853         $this->paramsGet     = array();
   782         $this->paramsPost    = array();
   854         $this->paramsPost    = array();
   783         $this->files         = array();
   855         $this->files         = array();
   784         $this->raw_post_data = null;
   856         $this->raw_post_data = null;
       
   857         $this->enctype       = null;
   785 
   858 
   786         if($clearAll) {
   859         if($clearAll) {
   787             $this->headers = array();
   860             $this->headers = array();
   788             $this->last_request = null;
   861             $this->last_request = null;
   789             $this->last_response = null;
   862             $this->last_response = null;
   864      *
   937      *
   865      * @return Zend_Http_Client_Adapter_Interface $adapter
   938      * @return Zend_Http_Client_Adapter_Interface $adapter
   866      */
   939      */
   867     public function getAdapter()
   940     public function getAdapter()
   868     {
   941     {
       
   942         if (null === $this->adapter) {
       
   943             $this->setAdapter($this->config['adapter']);
       
   944         }
       
   945 
   869         return $this->adapter;
   946         return $this->adapter;
   870     }
   947     }
   871 
   948 
   872     /**
   949     /**
   873      * Set streaming for received data
   950      * Set streaming for received data
   909                     $this->adapter->close();
   986                     $this->adapter->close();
   910                 }
   987                 }
   911                 require_once 'Zend/Http/Client/Exception.php';
   988                 require_once 'Zend/Http/Client/Exception.php';
   912                 throw new Zend_Http_Client_Exception("Could not open temp file {$this->_stream_name}");
   989                 throw new Zend_Http_Client_Exception("Could not open temp file {$this->_stream_name}");
   913         }
   990         }
   914         
   991 
   915         return $fp;
   992         return $fp;
   916     }
   993     }
   917     
   994 
   918     /**
   995     /**
   919      * Send the HTTP request and return an HTTP response object
   996      * Send the HTTP request and return an HTTP response object
   920      *
   997      *
   921      * @param string $method
   998      * @param string $method
   922      * @return Zend_Http_Response
   999      * @return Zend_Http_Response
   953                 $query .= http_build_query($this->paramsGet, null, '&');
  1030                 $query .= http_build_query($this->paramsGet, null, '&');
   954                 if ($this->config['rfc3986_strict']) {
  1031                 if ($this->config['rfc3986_strict']) {
   955                     $query = str_replace('+', '%20', $query);
  1032                     $query = str_replace('+', '%20', $query);
   956                 }
  1033                 }
   957 
  1034 
       
  1035                 // @see ZF-11671 to unmask for some services to foo=val1&foo=val2
       
  1036                 if ($this->getUnmaskStatus()) {
       
  1037                     if ($this->_queryBracketsEscaped) {
       
  1038                         $query = preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '=', $query);
       
  1039                     } else {
       
  1040                         $query = preg_replace('/\\[(?:[0-9]|[1-9][0-9]+)\\]=/', '=', $query);
       
  1041                     }
       
  1042                 }
       
  1043 
   958                 $uri->setQuery($query);
  1044                 $uri->setQuery($query);
   959             }
  1045             }
   960 
  1046 
   961             $body = $this->_prepareBody();
  1047             $body = $this->_prepareBody();
   962             $headers = $this->_prepareHeaders();
  1048             $headers = $this->_prepareHeaders();
   992                 require_once 'Zend/Http/Client/Exception.php';
  1078                 require_once 'Zend/Http/Client/Exception.php';
   993                 throw new Zend_Http_Client_Exception('Unable to read response, or response is empty');
  1079                 throw new Zend_Http_Client_Exception('Unable to read response, or response is empty');
   994             }
  1080             }
   995 
  1081 
   996             if($this->config['output_stream']) {
  1082             if($this->config['output_stream']) {
   997                 rewind($stream);
  1083                 $streamMetaData = stream_get_meta_data($stream);
       
  1084                 if ($streamMetaData['seekable']) {
       
  1085                     rewind($stream);
       
  1086                 }
   998                 // cleanup the adapter
  1087                 // cleanup the adapter
   999                 $this->adapter->setOutputStream(null);
  1088                 $this->adapter->setOutputStream(null);
  1000                 $response = Zend_Http_Response_Stream::fromStream($response, $stream);
  1089                 $response = Zend_Http_Response_Stream::fromStream($response, $stream);
  1001                 $response->setStreamName($this->_stream_name);
  1090                 $response->setStreamName($this->_stream_name);
  1002                 if(!is_string($this->config['output_stream'])) {
  1091                 if(!is_string($this->config['output_stream'])) {
  1017             }
  1106             }
  1018 
  1107 
  1019             // If we got redirected, look for the Location header
  1108             // If we got redirected, look for the Location header
  1020             if ($response->isRedirect() && ($location = $response->getHeader('location'))) {
  1109             if ($response->isRedirect() && ($location = $response->getHeader('location'))) {
  1021 
  1110 
       
  1111                 // Avoid problems with buggy servers that add whitespace at the
       
  1112                 // end of some headers (See ZF-11283)
       
  1113                 $location = trim($location);
       
  1114 
  1022                 // Check whether we send the exact same request again, or drop the parameters
  1115                 // Check whether we send the exact same request again, or drop the parameters
  1023                 // and send a GET request
  1116                 // and send a GET request
  1024                 if ($response->getStatus() == 303 ||
  1117                 if ($response->getStatus() == 303 ||
  1025                    ((! $this->config['strictredirects']) && ($response->getStatus() == 302 ||
  1118                    ((! $this->config['strictredirects']) && ($response->getStatus() == 302 ||
  1026                        $response->getStatus() == 301))) {
  1119                        $response->getStatus() == 301))) {
  1028                     $this->resetParameters();
  1121                     $this->resetParameters();
  1029                     $this->setMethod(self::GET);
  1122                     $this->setMethod(self::GET);
  1030                 }
  1123                 }
  1031 
  1124 
  1032                 // If we got a well formed absolute URI
  1125                 // If we got a well formed absolute URI
  1033                 if (Zend_Uri_Http::check($location)) {
  1126                 if (($scheme = substr($location, 0, 6)) && ($scheme == 'http:/' || $scheme == 'https:')) {
  1034                     $this->setHeaders('host', null);
  1127                     $this->setHeaders('host', null);
  1035                     $this->setUri($location);
  1128                     $this->setUri($location);
  1036 
  1129 
  1037                 } else {
  1130                 } else {
  1038 
  1131 
  1196                 case self::ENC_FORMDATA:
  1289                 case self::ENC_FORMDATA:
  1197                     // Encode body as multipart/form-data
  1290                     // Encode body as multipart/form-data
  1198                     $boundary = '---ZENDHTTPCLIENT-' . md5(microtime());
  1291                     $boundary = '---ZENDHTTPCLIENT-' . md5(microtime());
  1199                     $this->setHeaders(self::CONTENT_TYPE, self::ENC_FORMDATA . "; boundary={$boundary}");
  1292                     $this->setHeaders(self::CONTENT_TYPE, self::ENC_FORMDATA . "; boundary={$boundary}");
  1200 
  1293 
  1201                     // Get POST parameters and encode them
  1294                     // Encode all files and POST vars in the order they were given
  1202                     $params = self::_flattenParametersArray($this->paramsPost);
  1295                     foreach ($this->body_field_order as $fieldName=>$fieldType) {
  1203                     foreach ($params as $pp) {
  1296                         switch ($fieldType) {
  1204                         $body .= self::encodeFormData($boundary, $pp[0], $pp[1]);
  1297                             case self::VTYPE_FILE:
  1205                     }
  1298                                 foreach ($this->files as $file) {
  1206 
  1299                                     if ($file['formname']===$fieldName) {
  1207                     // Encode files
  1300                                         $fhead = array(self::CONTENT_TYPE => $file['ctype']);
  1208                     foreach ($this->files as $file) {
  1301                                         $body .= self::encodeFormData($boundary, $file['formname'], $file['data'], $file['filename'], $fhead);
  1209                         $fhead = array(self::CONTENT_TYPE => $file['ctype']);
  1302                                     }
  1210                         $body .= self::encodeFormData($boundary, $file['formname'], $file['data'], $file['filename'], $fhead);
  1303                                 }
       
  1304                                 break;
       
  1305                             case self::VTYPE_SCALAR:
       
  1306                                 if (isset($this->paramsPost[$fieldName])) {
       
  1307                                     if (is_array($this->paramsPost[$fieldName])) {
       
  1308                                         $flattened = self::_flattenParametersArray($this->paramsPost[$fieldName], $fieldName);
       
  1309                                         foreach ($flattened as $pp) {
       
  1310                                             $body .= self::encodeFormData($boundary, $pp[0], $pp[1]);
       
  1311                                         }
       
  1312                                     } else {
       
  1313                                         $body .= self::encodeFormData($boundary, $fieldName, $this->paramsPost[$fieldName]);
       
  1314                                     }
       
  1315                                 }
       
  1316                                 break;
       
  1317                         }
  1211                     }
  1318                     }
  1212 
  1319 
  1213                     $body .= "--{$boundary}--\r\n";
  1320                     $body .= "--{$boundary}--\r\n";
  1214                     break;
  1321                     break;
  1215 
  1322