File indexing completed on 2024-12-22 05:36:47
0001 <?php 0002 0003 /** 0004 * Zend Framework 0005 * 0006 * LICENSE 0007 * 0008 * This source file is subject to the new BSD license that is bundled 0009 * with this package in the file LICENSE.txt. 0010 * It is also available through the world-wide-web at this URL: 0011 * http://framework.zend.com/license/new-bsd 0012 * If you did not receive a copy of the license and are unable to 0013 * obtain it through the world-wide-web, please send an email 0014 * to license@zend.com so we can send you a copy immediately. 0015 * 0016 * @category Zend 0017 * @package Zend_Http 0018 * @subpackage Client 0019 * @version $Id$ 0020 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0021 * @license http://framework.zend.com/license/new-bsd New BSD License 0022 */ 0023 0024 /** 0025 * @see Zend_Loader 0026 */ 0027 // require_once 'Zend/Loader.php'; 0028 0029 0030 /** 0031 * @see Zend_Uri 0032 */ 0033 // require_once 'Zend/Uri.php'; 0034 0035 0036 /** 0037 * @see Zend_Http_Client_Adapter_Interface 0038 */ 0039 // require_once 'Zend/Http/Client/Adapter/Interface.php'; 0040 0041 0042 /** 0043 * @see Zend_Http_Header_HeaderValue 0044 */ 0045 // require_once 'Zend/Http/Header/HeaderValue.php'; 0046 0047 0048 /** 0049 * @see Zend_Http_Response 0050 */ 0051 // require_once 'Zend/Http/Response.php'; 0052 0053 /** 0054 * @see Zend_Http_Response_Stream 0055 */ 0056 // require_once 'Zend/Http/Response/Stream.php'; 0057 0058 /** 0059 * Zend_Http_Client is an implementation of an HTTP client in PHP. The client 0060 * supports basic features like sending different HTTP requests and handling 0061 * redirections, as well as more advanced features like proxy settings, HTTP 0062 * authentication and cookie persistence (using a Zend_Http_CookieJar object) 0063 * 0064 * @todo Implement proxy settings 0065 * @category Zend 0066 * @package Zend_Http 0067 * @subpackage Client 0068 * @throws Zend_Http_Client_Exception 0069 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0070 * @license http://framework.zend.com/license/new-bsd New BSD License 0071 */ 0072 class Zend_Http_Client 0073 { 0074 /** 0075 * HTTP request methods 0076 */ 0077 const GET = 'GET'; 0078 const POST = 'POST'; 0079 const PUT = 'PUT'; 0080 const HEAD = 'HEAD'; 0081 const DELETE = 'DELETE'; 0082 const TRACE = 'TRACE'; 0083 const OPTIONS = 'OPTIONS'; 0084 const CONNECT = 'CONNECT'; 0085 const MERGE = 'MERGE'; 0086 const PATCH = 'PATCH'; 0087 0088 /** 0089 * Supported HTTP Authentication methods 0090 */ 0091 const AUTH_BASIC = 'basic'; 0092 //const AUTH_DIGEST = 'digest'; <-- not implemented yet 0093 0094 /** 0095 * HTTP protocol versions 0096 */ 0097 const HTTP_1 = '1.1'; 0098 const HTTP_0 = '1.0'; 0099 0100 /** 0101 * Content attributes 0102 */ 0103 const CONTENT_TYPE = 'Content-Type'; 0104 const CONTENT_LENGTH = 'Content-Length'; 0105 0106 /** 0107 * POST data encoding methods 0108 */ 0109 const ENC_URLENCODED = 'application/x-www-form-urlencoded'; 0110 const ENC_FORMDATA = 'multipart/form-data'; 0111 0112 /** 0113 * Value types for Body key/value pairs 0114 */ 0115 const VTYPE_SCALAR = 'SCALAR'; 0116 const VTYPE_FILE = 'FILE'; 0117 0118 /** 0119 * Configuration array, set using the constructor or using ::setConfig() 0120 * 0121 * @var array 0122 */ 0123 protected $config = array( 0124 'maxredirects' => 5, 0125 'strictredirects' => false, 0126 'useragent' => 'Zend_Http_Client', 0127 'timeout' => 10, 0128 'adapter' => 'Zend_Http_Client_Adapter_Socket', 0129 'httpversion' => self::HTTP_1, 0130 'keepalive' => false, 0131 'storeresponse' => true, 0132 'strict' => true, 0133 'output_stream' => false, 0134 'encodecookies' => true, 0135 'rfc3986_strict' => false 0136 ); 0137 0138 /** 0139 * The adapter used to perform the actual connection to the server 0140 * 0141 * @var Zend_Http_Client_Adapter_Interface 0142 */ 0143 protected $adapter = null; 0144 0145 /** 0146 * Request URI 0147 * 0148 * @var Zend_Uri_Http 0149 */ 0150 protected $uri = null; 0151 0152 /** 0153 * Associative array of request headers 0154 * 0155 * @var array 0156 */ 0157 protected $headers = array(); 0158 0159 /** 0160 * HTTP request method 0161 * 0162 * @var string 0163 */ 0164 protected $method = self::GET; 0165 0166 /** 0167 * Associative array of GET parameters 0168 * 0169 * @var array 0170 */ 0171 protected $paramsGet = array(); 0172 0173 /** 0174 * Associative array of POST parameters 0175 * 0176 * @var array 0177 */ 0178 protected $paramsPost = array(); 0179 0180 /** 0181 * Request body content type (for POST requests) 0182 * 0183 * @var string 0184 */ 0185 protected $enctype = null; 0186 0187 /** 0188 * The raw post data to send. Could be set by setRawData($data, $enctype). 0189 * 0190 * @var string 0191 */ 0192 protected $raw_post_data = null; 0193 0194 /** 0195 * HTTP Authentication settings 0196 * 0197 * Expected to be an associative array with this structure: 0198 * $this->auth = array('user' => 'username', 'password' => 'password', 'type' => 'basic') 0199 * Where 'type' should be one of the supported authentication types (see the AUTH_* 0200 * constants), for example 'basic' or 'digest'. 0201 * 0202 * If null, no authentication will be used. 0203 * 0204 * @var array|null 0205 */ 0206 protected $auth; 0207 0208 /** 0209 * File upload arrays (used in POST requests) 0210 * 0211 * An associative array, where each element is of the format: 0212 * 'name' => array('filename.txt', 'text/plain', 'This is the actual file contents') 0213 * 0214 * @var array 0215 */ 0216 protected $files = array(); 0217 0218 /** 0219 * Ordered list of keys from key/value pair data to include in body 0220 * 0221 * An associative array, where each element is of the format: 0222 * '<field name>' => VTYPE_SCALAR | VTYPE_FILE 0223 * 0224 * @var array 0225 */ 0226 protected $body_field_order = array(); 0227 0228 /** 0229 * The client's cookie jar 0230 * 0231 * @var Zend_Http_CookieJar 0232 */ 0233 protected $cookiejar = null; 0234 0235 /** 0236 * The last HTTP request sent by the client, as string 0237 * 0238 * @var string 0239 */ 0240 protected $last_request = null; 0241 0242 /** 0243 * The last HTTP response received by the client 0244 * 0245 * @var Zend_Http_Response 0246 */ 0247 protected $last_response = null; 0248 0249 /** 0250 * Redirection counter 0251 * 0252 * @var int 0253 */ 0254 protected $redirectCounter = 0; 0255 0256 /** 0257 * Status for unmasking GET array params 0258 * 0259 * @var boolean 0260 */ 0261 protected $_unmaskStatus = false; 0262 0263 /** 0264 * Status if the http_build_query function escapes brackets 0265 * 0266 * @var boolean 0267 */ 0268 protected $_queryBracketsEscaped = true; 0269 0270 /** 0271 * Fileinfo magic database resource 0272 * 0273 * This variable is populated the first time _detectFileMimeType is called 0274 * and is then reused on every call to this method 0275 * 0276 * @var resource 0277 */ 0278 protected static $_fileInfoDb = null; 0279 0280 /** 0281 * Constructor method. Will create a new HTTP client. Accepts the target 0282 * URL and optionally configuration array. 0283 * 0284 * @param Zend_Uri_Http|string $uri 0285 * @param array $config Configuration key-value pairs. 0286 * @throws Zend_Http_Client_Exception 0287 * @throws Zend_Uri_Exception 0288 */ 0289 public function __construct($uri = null, $config = null) 0290 { 0291 if ($uri !== null) { 0292 $this->setUri($uri); 0293 } 0294 if ($config !== null) { 0295 $this->setConfig($config); 0296 } 0297 0298 $this->_queryBracketsEscaped = version_compare(phpversion(), '5.1.3', '>='); 0299 } 0300 0301 /** 0302 * Set the URI for the next request 0303 * 0304 * @param Zend_Uri_Http|string $uri 0305 * @return Zend_Http_Client 0306 * @throws Zend_Http_Client_Exception 0307 * @throws Zend_Uri_Exception 0308 */ 0309 public function setUri($uri) 0310 { 0311 if ($uri instanceof Zend_Uri_Http) { 0312 // clone the URI in order to keep the passed parameter constant 0313 $uri = clone $uri; 0314 } elseif (is_string($uri)) { 0315 $uri = Zend_Uri::factory($uri); 0316 } 0317 0318 if (!$uri instanceof Zend_Uri_Http) { 0319 /** @see Zend_Http_Client_Exception */ 0320 // require_once 'Zend/Http/Client/Exception.php'; 0321 throw new Zend_Http_Client_Exception('Passed parameter is not a valid HTTP URI.'); 0322 } 0323 0324 // Set auth if username and password has been specified in the uri 0325 if ($uri->getUsername() && $uri->getPassword()) { 0326 $this->setAuth($uri->getUsername(), $uri->getPassword()); 0327 } 0328 0329 // We have no ports, set the defaults 0330 if (! $uri->getPort()) { 0331 $uri->setPort(($uri->getScheme() == 'https' ? 443 : 80)); 0332 } 0333 0334 $this->uri = $uri; 0335 0336 return $this; 0337 } 0338 0339 /** 0340 * Get the URI for the next request 0341 * 0342 * @param boolean $as_string If true, will return the URI as a string 0343 * @return Zend_Uri_Http|string 0344 */ 0345 public function getUri($as_string = false) 0346 { 0347 if ($as_string && $this->uri instanceof Zend_Uri_Http) { 0348 return $this->uri->__toString(); 0349 } else { 0350 return $this->uri; 0351 } 0352 } 0353 0354 /** 0355 * Set configuration parameters for this HTTP client 0356 * 0357 * @param Zend_Config | array $config 0358 * @return Zend_Http_Client 0359 * @throws Zend_Http_Client_Exception 0360 */ 0361 public function setConfig($config = array()) 0362 { 0363 if ($config instanceof Zend_Config) { 0364 $config = $config->toArray(); 0365 0366 } elseif (! is_array($config)) { 0367 /** @see Zend_Http_Client_Exception */ 0368 // require_once 'Zend/Http/Client/Exception.php'; 0369 throw new Zend_Http_Client_Exception('Array or Zend_Config object expected, got ' . gettype($config)); 0370 } 0371 0372 foreach ($config as $k => $v) { 0373 $this->config[strtolower($k)] = $v; 0374 } 0375 0376 // Pass configuration options to the adapter if it exists 0377 if ($this->adapter instanceof Zend_Http_Client_Adapter_Interface) { 0378 $this->adapter->setConfig($config); 0379 } 0380 0381 return $this; 0382 } 0383 0384 /** 0385 * Set the next request's method 0386 * 0387 * Validated the passed method and sets it. If we have files set for 0388 * POST requests, and the new method is not POST, the files are silently 0389 * dropped. 0390 * 0391 * @param string $method 0392 * @return Zend_Http_Client 0393 * @throws Zend_Http_Client_Exception 0394 */ 0395 public function setMethod($method = self::GET) 0396 { 0397 if (! preg_match('/^[^\x00-\x1f\x7f-\xff\(\)<>@,;:\\\\"\/\[\]\?={}\s]+$/', $method)) { 0398 // require_once 'Zend/Http/Client/Exception.php'; 0399 throw new Zend_Http_Client_Exception("'{$method}' is not a valid HTTP request method."); 0400 } 0401 0402 if (($method == self::POST 0403 || $method == self::PUT 0404 || $method == self::DELETE 0405 || $method == self::PATCH 0406 || $method == self::OPTIONS) 0407 && $this->enctype === null 0408 ) { 0409 $this->setEncType(self::ENC_URLENCODED); 0410 } 0411 0412 $this->method = $method; 0413 0414 return $this; 0415 } 0416 0417 /** 0418 * Set one or more request headers 0419 * 0420 * This function can be used in several ways to set the client's request 0421 * headers: 0422 * 1. By providing two parameters: $name as the header to set (e.g. 'Host') 0423 * and $value as it's value (e.g. 'www.example.com'). 0424 * 2. By providing a single header string as the only parameter 0425 * e.g. 'Host: www.example.com' 0426 * 3. By providing an array of headers as the first parameter 0427 * e.g. array('host' => 'www.example.com', 'x-foo: bar'). In This case 0428 * the function will call itself recursively for each array item. 0429 * 0430 * @param string|array $name Header name, full header string ('Header: value') 0431 * or an array of headers 0432 * @param mixed $value Header value or null 0433 * @return Zend_Http_Client 0434 * @throws Zend_Http_Client_Exception 0435 */ 0436 public function setHeaders($name, $value = null) 0437 { 0438 // If we got an array, go recursive! 0439 if (is_array($name)) { 0440 foreach ($name as $k => $v) { 0441 if (is_string($k)) { 0442 $this->setHeaders($k, $v); 0443 continue; 0444 } 0445 $this->setHeaders($v, null); 0446 } 0447 return $this; 0448 } 0449 0450 // Check if $name needs to be split 0451 if ($value === null && (strpos($name, ':') > 0)) { 0452 list($name, $value) = explode(':', $name, 2); 0453 } 0454 0455 // Make sure the name is valid if we are in strict mode 0456 if ($this->config['strict'] && (! preg_match('/^[a-zA-Z0-9-]+$/', $name))) { 0457 // require_once 'Zend/Http/Client/Exception.php'; 0458 throw new Zend_Http_Client_Exception("{$name} is not a valid HTTP header name"); 0459 } 0460 0461 $normalized_name = strtolower($name); 0462 0463 // If $value is null or false, unset the header 0464 if ($value === null || $value === false) { 0465 unset($this->headers[$normalized_name]); 0466 return $this; 0467 } 0468 0469 // Validate value 0470 $this->_validateHeaderValue($value); 0471 0472 // Header names are stored lowercase internally. 0473 if (is_string($value)) { 0474 $value = trim($value); 0475 } 0476 $this->headers[$normalized_name] = array($name, $value); 0477 0478 return $this; 0479 } 0480 0481 /** 0482 * Get the value of a specific header 0483 * 0484 * Note that if the header has more than one value, an array 0485 * will be returned. 0486 * 0487 * @param string $key 0488 * @return string|array|null The header value or null if it is not set 0489 */ 0490 public function getHeader($key) 0491 { 0492 $key = strtolower($key); 0493 if (isset($this->headers[$key])) { 0494 return $this->headers[$key][1]; 0495 } else { 0496 return null; 0497 } 0498 } 0499 0500 /** 0501 * Set a GET parameter for the request. Wrapper around _setParameter 0502 * 0503 * @param string|array $name 0504 * @param string $value 0505 * @return Zend_Http_Client 0506 */ 0507 public function setParameterGet($name, $value = null) 0508 { 0509 if (is_array($name)) { 0510 foreach ($name as $k => $v) 0511 $this->_setParameter('GET', $k, $v); 0512 } else { 0513 $this->_setParameter('GET', $name, $value); 0514 } 0515 0516 return $this; 0517 } 0518 0519 /** 0520 * Set a POST parameter for the request. Wrapper around _setParameter 0521 * 0522 * @param string|array $name 0523 * @param string $value 0524 * @return Zend_Http_Client 0525 */ 0526 public function setParameterPost($name, $value = null) 0527 { 0528 if (is_array($name)) { 0529 foreach ($name as $k => $v) 0530 $this->_setParameter('POST', $k, $v); 0531 } else { 0532 $this->_setParameter('POST', $name, $value); 0533 } 0534 0535 return $this; 0536 } 0537 0538 /** 0539 * Set a GET or POST parameter - used by SetParameterGet and SetParameterPost 0540 * 0541 * @param string $type GET or POST 0542 * @param string $name 0543 * @param string $value 0544 * @return null 0545 */ 0546 protected function _setParameter($type, $name, $value) 0547 { 0548 $parray = array(); 0549 $type = strtolower($type); 0550 switch ($type) { 0551 case 'get': 0552 $parray = &$this->paramsGet; 0553 break; 0554 case 'post': 0555 $parray = &$this->paramsPost; 0556 if ( $value === null ) { 0557 if (isset($this->body_field_order[$name])) 0558 unset($this->body_field_order[$name]); 0559 } else { 0560 $this->body_field_order[$name] = self::VTYPE_SCALAR; 0561 } 0562 break; 0563 } 0564 0565 if ($value === null) { 0566 if (isset($parray[$name])) unset($parray[$name]); 0567 } else { 0568 $parray[$name] = $value; 0569 } 0570 } 0571 0572 /** 0573 * Get the number of redirections done on the last request 0574 * 0575 * @return int 0576 */ 0577 public function getRedirectionsCount() 0578 { 0579 return $this->redirectCounter; 0580 } 0581 0582 /** 0583 * Set HTTP authentication parameters 0584 * 0585 * $type should be one of the supported types - see the self::AUTH_* 0586 * constants. 0587 * 0588 * To enable authentication: 0589 * <code> 0590 * $this->setAuth('shahar', 'secret', Zend_Http_Client::AUTH_BASIC); 0591 * </code> 0592 * 0593 * To disable authentication: 0594 * <code> 0595 * $this->setAuth(false); 0596 * </code> 0597 * 0598 * @see http://www.faqs.org/rfcs/rfc2617.html 0599 * @param string|false $user User name or false disable authentication 0600 * @param string $password Password 0601 * @param string $type Authentication type 0602 * @return Zend_Http_Client 0603 * @throws Zend_Http_Client_Exception 0604 */ 0605 public function setAuth($user, $password = '', $type = self::AUTH_BASIC) 0606 { 0607 // If we got false or null, disable authentication 0608 if ($user === false || $user === null) { 0609 $this->auth = null; 0610 0611 // Clear the auth information in the uri instance as well 0612 if ($this->uri instanceof Zend_Uri_Http) { 0613 $this->getUri()->setUsername(''); 0614 $this->getUri()->setPassword(''); 0615 } 0616 // Else, set up authentication 0617 } else { 0618 // Check we got a proper authentication type 0619 if (! defined('self::AUTH_' . strtoupper($type))) { 0620 /** @see Zend_Http_Client_Exception */ 0621 // require_once 'Zend/Http/Client/Exception.php'; 0622 throw new Zend_Http_Client_Exception("Invalid or not supported authentication type: '$type'"); 0623 } 0624 0625 $this->auth = array( 0626 'user' => (string) $user, 0627 'password' => (string) $password, 0628 'type' => $type 0629 ); 0630 } 0631 0632 return $this; 0633 } 0634 0635 /** 0636 * Set the HTTP client's cookie jar. 0637 * 0638 * A cookie jar is an object that holds and maintains cookies across HTTP requests 0639 * and responses. 0640 * 0641 * @param Zend_Http_CookieJar|boolean $cookiejar Existing cookiejar object, true to create a new one, false to disable 0642 * @return Zend_Http_Client 0643 * @throws Zend_Http_Client_Exception 0644 */ 0645 public function setCookieJar($cookiejar = true) 0646 { 0647 Zend_Loader::loadClass('Zend_Http_CookieJar'); 0648 0649 if ($cookiejar instanceof Zend_Http_CookieJar) { 0650 $this->cookiejar = $cookiejar; 0651 } elseif ($cookiejar === true) { 0652 $this->cookiejar = new Zend_Http_CookieJar(); 0653 } elseif (! $cookiejar) { 0654 $this->cookiejar = null; 0655 } else { 0656 /** @see Zend_Http_Client_Exception */ 0657 // require_once 'Zend/Http/Client/Exception.php'; 0658 throw new Zend_Http_Client_Exception('Invalid parameter type passed as CookieJar'); 0659 } 0660 0661 return $this; 0662 } 0663 0664 /** 0665 * Return the current cookie jar or null if none. 0666 * 0667 * @return Zend_Http_CookieJar|null 0668 */ 0669 public function getCookieJar() 0670 { 0671 return $this->cookiejar; 0672 } 0673 0674 /** 0675 * Add a cookie to the request. If the client has no Cookie Jar, the cookies 0676 * will be added directly to the headers array as "Cookie" headers. 0677 * 0678 * @param Zend_Http_Cookie|string $cookie 0679 * @param string|null $value If "cookie" is a string, this is the cookie value. 0680 * @return Zend_Http_Client 0681 * @throws Zend_Http_Client_Exception 0682 */ 0683 public function setCookie($cookie, $value = null) 0684 { 0685 Zend_Loader::loadClass('Zend_Http_Cookie'); 0686 0687 if (is_array($cookie)) { 0688 foreach ($cookie as $c => $v) { 0689 if (is_string($c)) { 0690 $this->setCookie($c, $v); 0691 } else { 0692 $this->setCookie($v); 0693 } 0694 } 0695 0696 return $this; 0697 } 0698 0699 if ($value !== null && $this->config['encodecookies']) { 0700 $value = urlencode($value); 0701 } 0702 0703 if (isset($this->cookiejar)) { 0704 if ($cookie instanceof Zend_Http_Cookie) { 0705 $this->cookiejar->addCookie($cookie); 0706 } elseif (is_string($cookie) && $value !== null) { 0707 $cookie = Zend_Http_Cookie::fromString("{$cookie}={$value}", 0708 $this->uri, 0709 $this->config['encodecookies']); 0710 $this->cookiejar->addCookie($cookie); 0711 } 0712 } else { 0713 if ($cookie instanceof Zend_Http_Cookie) { 0714 $name = $cookie->getName(); 0715 $value = $cookie->getValue(); 0716 $cookie = $name; 0717 } 0718 0719 if (preg_match("/[=,; \t\r\n\013\014]/", $cookie)) { 0720 /** @see Zend_Http_Client_Exception */ 0721 // require_once 'Zend/Http/Client/Exception.php'; 0722 throw new Zend_Http_Client_Exception("Cookie name cannot contain these characters: =,; \t\r\n\013\014 ({$cookie})"); 0723 } 0724 0725 $value = addslashes($value); 0726 0727 if (! isset($this->headers['cookie'])) { 0728 $this->headers['cookie'] = array('Cookie', ''); 0729 } 0730 $this->headers['cookie'][1] .= $cookie . '=' . $value . '; '; 0731 } 0732 0733 return $this; 0734 } 0735 0736 /** 0737 * Set a file to upload (using a POST request) 0738 * 0739 * Can be used in two ways: 0740 * 0741 * 1. $data is null (default): $filename is treated as the name if a local file which 0742 * will be read and sent. Will try to guess the content type using mime_content_type(). 0743 * 2. $data is set - $filename is sent as the file name, but $data is sent as the file 0744 * contents and no file is read from the file system. In this case, you need to 0745 * manually set the Content-Type ($ctype) or it will default to 0746 * application/octet-stream. 0747 * 0748 * @param string $filename Name of file to upload, or name to save as 0749 * @param string $formname Name of form element to send as 0750 * @param string $data Data to send (if null, $filename is read and sent) 0751 * @param string $ctype Content type to use (if $data is set and $ctype is 0752 * null, will be application/octet-stream) 0753 * @return Zend_Http_Client 0754 * @throws Zend_Http_Client_Exception 0755 */ 0756 public function setFileUpload($filename, $formname, $data = null, $ctype = null) 0757 { 0758 if ($data === null) { 0759 if (($data = @file_get_contents($filename)) === false) { 0760 /** @see Zend_Http_Client_Exception */ 0761 // require_once 'Zend/Http/Client/Exception.php'; 0762 throw new Zend_Http_Client_Exception("Unable to read file '{$filename}' for upload"); 0763 } 0764 0765 if (! $ctype) { 0766 $ctype = $this->_detectFileMimeType($filename); 0767 } 0768 } 0769 0770 // Force enctype to multipart/form-data 0771 $this->setEncType(self::ENC_FORMDATA); 0772 0773 $this->files[] = array( 0774 'formname' => $formname, 0775 'filename' => basename($filename), 0776 'ctype' => $ctype, 0777 'data' => $data 0778 ); 0779 0780 $this->body_field_order[$formname] = self::VTYPE_FILE; 0781 0782 return $this; 0783 } 0784 0785 /** 0786 * Set the encoding type for POST data 0787 * 0788 * @param string $enctype 0789 * @return Zend_Http_Client 0790 */ 0791 public function setEncType($enctype = self::ENC_URLENCODED) 0792 { 0793 $this->enctype = $enctype; 0794 0795 return $this; 0796 } 0797 0798 /** 0799 * Set the raw (already encoded) POST data. 0800 * 0801 * This function is here for two reasons: 0802 * 1. For advanced user who would like to set their own data, already encoded 0803 * 2. For backwards compatibilty: If someone uses the old post($data) method. 0804 * this method will be used to set the encoded data. 0805 * 0806 * $data can also be stream (such as file) from which the data will be read. 0807 * 0808 * @param string|resource $data 0809 * @param string $enctype 0810 * @return Zend_Http_Client 0811 */ 0812 public function setRawData($data, $enctype = null) 0813 { 0814 $this->raw_post_data = $data; 0815 $this->setEncType($enctype); 0816 if (is_resource($data)) { 0817 // We've got stream data 0818 $stat = @fstat($data); 0819 if($stat) { 0820 $this->setHeaders(self::CONTENT_LENGTH, $stat['size']); 0821 } 0822 } 0823 return $this; 0824 } 0825 0826 /** 0827 * Set the unmask feature for GET parameters as array 0828 * 0829 * Example: 0830 * foo%5B0%5D=a&foo%5B1%5D=b 0831 * becomes 0832 * foo=a&foo=b 0833 * 0834 * This is usefull for some services 0835 * 0836 * @param boolean $status 0837 * @return Zend_Http_Client 0838 */ 0839 public function setUnmaskStatus($status = true) 0840 { 0841 $this->_unmaskStatus = (BOOL)$status; 0842 return $this; 0843 } 0844 0845 /** 0846 * Returns the currently configured unmask status 0847 * 0848 * @return boolean 0849 */ 0850 public function getUnmaskStatus() 0851 { 0852 return $this->_unmaskStatus; 0853 } 0854 0855 /** 0856 * Clear all GET and POST parameters 0857 * 0858 * Should be used to reset the request parameters if the client is 0859 * used for several concurrent requests. 0860 * 0861 * clearAll parameter controls if we clean just parameters or also 0862 * headers and last_* 0863 * 0864 * @param bool $clearAll Should all data be cleared? 0865 * @return Zend_Http_Client 0866 */ 0867 public function resetParameters($clearAll = false) 0868 { 0869 // Reset parameter data 0870 $this->paramsGet = array(); 0871 $this->paramsPost = array(); 0872 $this->files = array(); 0873 $this->raw_post_data = null; 0874 $this->enctype = null; 0875 0876 if($clearAll) { 0877 $this->headers = array(); 0878 $this->last_request = null; 0879 $this->last_response = null; 0880 } else { 0881 // Clear outdated headers 0882 if (isset($this->headers[strtolower(self::CONTENT_TYPE)])) { 0883 unset($this->headers[strtolower(self::CONTENT_TYPE)]); 0884 } 0885 if (isset($this->headers[strtolower(self::CONTENT_LENGTH)])) { 0886 unset($this->headers[strtolower(self::CONTENT_LENGTH)]); 0887 } 0888 } 0889 0890 return $this; 0891 } 0892 0893 /** 0894 * Get the last HTTP request as string 0895 * 0896 * @return string 0897 */ 0898 public function getLastRequest() 0899 { 0900 return $this->last_request; 0901 } 0902 0903 /** 0904 * Get the last HTTP response received by this client 0905 * 0906 * If $config['storeresponse'] is set to false, or no response was 0907 * stored yet, will return null 0908 * 0909 * @return Zend_Http_Response or null if none 0910 */ 0911 public function getLastResponse() 0912 { 0913 return $this->last_response; 0914 } 0915 0916 /** 0917 * Load the connection adapter 0918 * 0919 * While this method is not called more than one for a client, it is 0920 * seperated from ->request() to preserve logic and readability 0921 * 0922 * @param Zend_Http_Client_Adapter_Interface|string $adapter 0923 * @return null 0924 * @throws Zend_Http_Client_Exception 0925 */ 0926 public function setAdapter($adapter) 0927 { 0928 if (is_string($adapter)) { 0929 try { 0930 Zend_Loader::loadClass($adapter); 0931 } catch (Zend_Exception $e) { 0932 /** @see Zend_Http_Client_Exception */ 0933 // require_once 'Zend/Http/Client/Exception.php'; 0934 throw new Zend_Http_Client_Exception("Unable to load adapter '$adapter': {$e->getMessage()}", 0, $e); 0935 } 0936 0937 $adapter = new $adapter; 0938 } 0939 0940 if (! $adapter instanceof Zend_Http_Client_Adapter_Interface) { 0941 /** @see Zend_Http_Client_Exception */ 0942 // require_once 'Zend/Http/Client/Exception.php'; 0943 throw new Zend_Http_Client_Exception('Passed adapter is not a HTTP connection adapter'); 0944 } 0945 0946 $this->adapter = $adapter; 0947 $config = $this->config; 0948 unset($config['adapter']); 0949 $this->adapter->setConfig($config); 0950 } 0951 0952 /** 0953 * Load the connection adapter 0954 * 0955 * @return Zend_Http_Client_Adapter_Interface $adapter 0956 */ 0957 public function getAdapter() 0958 { 0959 if (null === $this->adapter) { 0960 $this->setAdapter($this->config['adapter']); 0961 } 0962 0963 return $this->adapter; 0964 } 0965 0966 /** 0967 * Set streaming for received data 0968 * 0969 * @param string|boolean $streamfile Stream file, true for temp file, false/null for no streaming 0970 * @return Zend_Http_Client 0971 */ 0972 public function setStream($streamfile = true) 0973 { 0974 $this->setConfig(array("output_stream" => $streamfile)); 0975 return $this; 0976 } 0977 0978 /** 0979 * Get status of streaming for received data 0980 * @return boolean|string 0981 */ 0982 public function getStream() 0983 { 0984 return $this->config["output_stream"]; 0985 } 0986 0987 /** 0988 * Create temporary stream 0989 * 0990 * @return resource 0991 */ 0992 protected function _openTempStream() 0993 { 0994 $this->_stream_name = $this->config['output_stream']; 0995 if(!is_string($this->_stream_name)) { 0996 // If name is not given, create temp name 0997 $this->_stream_name = tempnam(isset($this->config['stream_tmp_dir'])?$this->config['stream_tmp_dir']:sys_get_temp_dir(), 0998 'Zend_Http_Client'); 0999 } 1000 1001 if (false === ($fp = @fopen($this->_stream_name, "w+b"))) { 1002 if ($this->adapter instanceof Zend_Http_Client_Adapter_Interface) { 1003 $this->adapter->close(); 1004 } 1005 // require_once 'Zend/Http/Client/Exception.php'; 1006 throw new Zend_Http_Client_Exception("Could not open temp file {$this->_stream_name}"); 1007 } 1008 1009 return $fp; 1010 } 1011 1012 /** 1013 * Send the HTTP request and return an HTTP response object 1014 * 1015 * @param string $method 1016 * @return Zend_Http_Response 1017 * @throws Zend_Http_Client_Exception 1018 */ 1019 public function request($method = null) 1020 { 1021 if (! $this->uri instanceof Zend_Uri_Http) { 1022 /** @see Zend_Http_Client_Exception */ 1023 // require_once 'Zend/Http/Client/Exception.php'; 1024 throw new Zend_Http_Client_Exception('No valid URI has been passed to the client'); 1025 } 1026 1027 if ($method) { 1028 $this->setMethod($method); 1029 } 1030 $this->redirectCounter = 0; 1031 $response = null; 1032 1033 // Make sure the adapter is loaded 1034 if ($this->adapter == null) { 1035 $this->setAdapter($this->config['adapter']); 1036 } 1037 1038 // Send the first request. If redirected, continue. 1039 do { 1040 // Clone the URI and add the additional GET parameters to it 1041 $uri = clone $this->uri; 1042 if (! empty($this->paramsGet)) { 1043 $query = $uri->getQuery(); 1044 if (! empty($query)) { 1045 $query .= '&'; 1046 } 1047 $query .= http_build_query($this->paramsGet, null, '&'); 1048 if ($this->config['rfc3986_strict']) { 1049 $query = str_replace('+', '%20', $query); 1050 } 1051 1052 // @see ZF-11671 to unmask for some services to foo=val1&foo=val2 1053 if ($this->getUnmaskStatus()) { 1054 if ($this->_queryBracketsEscaped) { 1055 $query = preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '=', $query); 1056 } else { 1057 $query = preg_replace('/\\[(?:[0-9]|[1-9][0-9]+)\\]=/', '=', $query); 1058 } 1059 } 1060 1061 $uri->setQuery($query); 1062 } 1063 1064 $body = $this->_prepareBody(); 1065 $headers = $this->_prepareHeaders(); 1066 1067 // check that adapter supports streaming before using it 1068 if(is_resource($body) && !($this->adapter instanceof Zend_Http_Client_Adapter_Stream)) { 1069 /** @see Zend_Http_Client_Exception */ 1070 // require_once 'Zend/Http/Client/Exception.php'; 1071 throw new Zend_Http_Client_Exception('Adapter does not support streaming'); 1072 } 1073 1074 // Open the connection, send the request and read the response 1075 $this->adapter->connect($uri->getHost(), $uri->getPort(), 1076 ($uri->getScheme() == 'https' ? true : false)); 1077 1078 if($this->config['output_stream']) { 1079 if($this->adapter instanceof Zend_Http_Client_Adapter_Stream) { 1080 $stream = $this->_openTempStream(); 1081 $this->adapter->setOutputStream($stream); 1082 } else { 1083 /** @see Zend_Http_Client_Exception */ 1084 // require_once 'Zend/Http/Client/Exception.php'; 1085 throw new Zend_Http_Client_Exception('Adapter does not support streaming'); 1086 } 1087 } 1088 1089 $this->last_request = $this->adapter->write($this->method, 1090 $uri, $this->config['httpversion'], $headers, $body); 1091 1092 $response = $this->adapter->read(); 1093 if (! $response) { 1094 /** @see Zend_Http_Client_Exception */ 1095 // require_once 'Zend/Http/Client/Exception.php'; 1096 throw new Zend_Http_Client_Exception('Unable to read response, or response is empty'); 1097 } 1098 1099 if($this->config['output_stream']) { 1100 $streamMetaData = stream_get_meta_data($stream); 1101 if ($streamMetaData['seekable']) { 1102 rewind($stream); 1103 } 1104 // cleanup the adapter 1105 $this->adapter->setOutputStream(null); 1106 $response = Zend_Http_Response_Stream::fromStream($response, $stream); 1107 $response->setStreamName($this->_stream_name); 1108 if(!is_string($this->config['output_stream'])) { 1109 // we used temp name, will need to clean up 1110 $response->setCleanup(true); 1111 } 1112 } else { 1113 $response = Zend_Http_Response::fromString($response); 1114 } 1115 1116 if ($this->config['storeresponse']) { 1117 $this->last_response = $response; 1118 } 1119 1120 // Load cookies into cookie jar 1121 if (isset($this->cookiejar)) { 1122 $this->cookiejar->addCookiesFromResponse($response, $uri, $this->config['encodecookies']); 1123 } 1124 1125 // If we got redirected, look for the Location header 1126 if ($response->isRedirect() && ($location = $response->getHeader('location'))) { 1127 1128 // Avoid problems with buggy servers that add whitespace at the 1129 // end of some headers (See ZF-11283) 1130 $location = trim($location); 1131 1132 // Check whether we send the exact same request again, or drop the parameters 1133 // and send a GET request 1134 if ($response->getStatus() == 303 || 1135 ((! $this->config['strictredirects']) && ($response->getStatus() == 302 || 1136 $response->getStatus() == 301))) { 1137 1138 $this->resetParameters(); 1139 $this->setMethod(self::GET); 1140 } 1141 1142 // If we got a well formed absolute URI 1143 if (($scheme = substr($location, 0, 6)) && ($scheme == 'http:/' || $scheme == 'https:')) { 1144 $this->setHeaders('host', null); 1145 $this->setUri($location); 1146 1147 } else { 1148 1149 // Split into path and query and set the query 1150 if (strpos($location, '?') !== false) { 1151 list($location, $query) = explode('?', $location, 2); 1152 } else { 1153 $query = ''; 1154 } 1155 $this->uri->setQuery($query); 1156 1157 // Else, if we got just an absolute path, set it 1158 if(strpos($location, '/') === 0) { 1159 $this->uri->setPath($location); 1160 1161 // Else, assume we have a relative path 1162 } else { 1163 // Get the current path directory, removing any trailing slashes 1164 $path = $this->uri->getPath(); 1165 $path = rtrim(substr($path, 0, strrpos($path, '/')), "/"); 1166 $this->uri->setPath($path . '/' . $location); 1167 } 1168 } 1169 ++$this->redirectCounter; 1170 1171 } else { 1172 // If we didn't get any location, stop redirecting 1173 break; 1174 } 1175 1176 } while ($this->redirectCounter < $this->config['maxredirects']); 1177 1178 return $response; 1179 } 1180 1181 /** 1182 * Prepare the request headers 1183 * 1184 * @return array 1185 */ 1186 protected function _prepareHeaders() 1187 { 1188 $headers = array(); 1189 1190 // Set the host header 1191 if (! isset($this->headers['host'])) { 1192 $host = $this->uri->getHost(); 1193 1194 // If the port is not default, add it 1195 if (! (($this->uri->getScheme() == 'http' && $this->uri->getPort() == 80) || 1196 ($this->uri->getScheme() == 'https' && $this->uri->getPort() == 443))) { 1197 $host .= ':' . $this->uri->getPort(); 1198 } 1199 1200 $headers[] = "Host: {$host}"; 1201 } 1202 1203 // Set the connection header 1204 if (! isset($this->headers['connection'])) { 1205 if (! $this->config['keepalive']) { 1206 $headers[] = "Connection: close"; 1207 } 1208 } 1209 1210 // Set the Accept-encoding header if not set - depending on whether 1211 // zlib is available or not. 1212 if (! isset($this->headers['accept-encoding'])) { 1213 if (function_exists('gzinflate')) { 1214 $headers[] = 'Accept-encoding: gzip, deflate'; 1215 } else { 1216 $headers[] = 'Accept-encoding: identity'; 1217 } 1218 } 1219 1220 // Set the Content-Type header 1221 if (($this->method == self::POST || $this->method == self::PUT) && 1222 (! isset($this->headers[strtolower(self::CONTENT_TYPE)]) && isset($this->enctype))) { 1223 1224 $headers[] = self::CONTENT_TYPE . ': ' . $this->enctype; 1225 } 1226 1227 // Set the user agent header 1228 if (! isset($this->headers['user-agent']) && isset($this->config['useragent'])) { 1229 $headers[] = "User-Agent: {$this->config['useragent']}"; 1230 } 1231 1232 // Set HTTP authentication if needed 1233 if (is_array($this->auth)) { 1234 $auth = self::encodeAuthHeader($this->auth['user'], $this->auth['password'], $this->auth['type']); 1235 $headers[] = "Authorization: {$auth}"; 1236 } 1237 1238 // Load cookies from cookie jar 1239 if (isset($this->cookiejar)) { 1240 $cookstr = $this->cookiejar->getMatchingCookies($this->uri, 1241 true, Zend_Http_CookieJar::COOKIE_STRING_CONCAT); 1242 1243 if ($cookstr) { 1244 $headers[] = "Cookie: {$cookstr}"; 1245 } 1246 } 1247 1248 // Add all other user defined headers 1249 foreach ($this->headers as $header) { 1250 list($name, $value) = $header; 1251 if (is_array($value)) { 1252 $value = implode(', ', $value); 1253 } 1254 1255 $headers[] = "$name: $value"; 1256 } 1257 1258 return $headers; 1259 } 1260 1261 /** 1262 * Prepare the request body (for POST and PUT requests) 1263 * 1264 * @return string 1265 * @throws Zend_Http_Client_Exception 1266 */ 1267 protected function _prepareBody() 1268 { 1269 // According to RFC2616, a TRACE request should not have a body. 1270 if ($this->method == self::TRACE) { 1271 return ''; 1272 } 1273 1274 if (isset($this->raw_post_data) && is_resource($this->raw_post_data)) { 1275 return $this->raw_post_data; 1276 } 1277 // If mbstring overloads substr and strlen functions, we have to 1278 // override it's internal encoding 1279 if (function_exists('mb_internal_encoding') && 1280 ((int) ini_get('mbstring.func_overload')) & 2) { 1281 1282 $mbIntEnc = mb_internal_encoding(); 1283 mb_internal_encoding('ASCII'); 1284 } 1285 1286 // If we have raw_post_data set, just use it as the body. 1287 if (isset($this->raw_post_data)) { 1288 $this->setHeaders(self::CONTENT_LENGTH, strlen($this->raw_post_data)); 1289 if (isset($mbIntEnc)) { 1290 mb_internal_encoding($mbIntEnc); 1291 } 1292 1293 return $this->raw_post_data; 1294 } 1295 1296 $body = ''; 1297 1298 // If we have files to upload, force enctype to multipart/form-data 1299 if (count ($this->files) > 0) { 1300 $this->setEncType(self::ENC_FORMDATA); 1301 } 1302 1303 // If we have POST parameters or files, encode and add them to the body 1304 if (count($this->paramsPost) > 0 || count($this->files) > 0) { 1305 switch($this->enctype) { 1306 case self::ENC_FORMDATA: 1307 // Encode body as multipart/form-data 1308 $boundary = '---ZENDHTTPCLIENT-' . md5(microtime()); 1309 $this->setHeaders(self::CONTENT_TYPE, self::ENC_FORMDATA . "; boundary={$boundary}"); 1310 1311 // Encode all files and POST vars in the order they were given 1312 foreach ($this->body_field_order as $fieldName=>$fieldType) { 1313 switch ($fieldType) { 1314 case self::VTYPE_FILE: 1315 foreach ($this->files as $file) { 1316 if ($file['formname']===$fieldName) { 1317 $fhead = array(self::CONTENT_TYPE => $file['ctype']); 1318 $body .= self::encodeFormData($boundary, $file['formname'], $file['data'], $file['filename'], $fhead); 1319 } 1320 } 1321 break; 1322 case self::VTYPE_SCALAR: 1323 if (isset($this->paramsPost[$fieldName])) { 1324 if (is_array($this->paramsPost[$fieldName])) { 1325 $flattened = self::_flattenParametersArray($this->paramsPost[$fieldName], $fieldName); 1326 foreach ($flattened as $pp) { 1327 $body .= self::encodeFormData($boundary, $pp[0], $pp[1]); 1328 } 1329 } else { 1330 $body .= self::encodeFormData($boundary, $fieldName, $this->paramsPost[$fieldName]); 1331 } 1332 } 1333 break; 1334 } 1335 } 1336 1337 $body .= "--{$boundary}--\r\n"; 1338 break; 1339 1340 case self::ENC_URLENCODED: 1341 // Encode body as application/x-www-form-urlencoded 1342 $this->setHeaders(self::CONTENT_TYPE, self::ENC_URLENCODED); 1343 $body = http_build_query($this->paramsPost, '', '&'); 1344 break; 1345 1346 default: 1347 if (isset($mbIntEnc)) { 1348 mb_internal_encoding($mbIntEnc); 1349 } 1350 1351 /** @see Zend_Http_Client_Exception */ 1352 // require_once 'Zend/Http/Client/Exception.php'; 1353 throw new Zend_Http_Client_Exception("Cannot handle content type '{$this->enctype}' automatically." . 1354 " Please use Zend_Http_Client::setRawData to send this kind of content."); 1355 break; 1356 } 1357 } 1358 1359 // Set the Content-Length if we have a body or if request is POST/PUT 1360 if ($body || $this->method == self::POST || $this->method == self::PUT) { 1361 $this->setHeaders(self::CONTENT_LENGTH, strlen($body)); 1362 } 1363 1364 if (isset($mbIntEnc)) { 1365 mb_internal_encoding($mbIntEnc); 1366 } 1367 1368 return $body; 1369 } 1370 1371 /** 1372 * Helper method that gets a possibly multi-level parameters array (get or 1373 * post) and flattens it. 1374 * 1375 * The method returns an array of (key, value) pairs (because keys are not 1376 * necessarily unique. If one of the parameters in as array, it will also 1377 * add a [] suffix to the key. 1378 * 1379 * This method is deprecated since Zend Framework 1.9 in favour of 1380 * self::_flattenParametersArray() and will be dropped in 2.0 1381 * 1382 * @deprecated since 1.9 1383 * 1384 * @param array $parray The parameters array 1385 * @param bool $urlencode Whether to urlencode the name and value 1386 * @return array 1387 */ 1388 protected function _getParametersRecursive($parray, $urlencode = false) 1389 { 1390 // Issue a deprecated notice 1391 trigger_error("The " . __METHOD__ . " method is deprecated and will be dropped in 2.0.", 1392 E_USER_NOTICE); 1393 1394 if (! is_array($parray)) { 1395 return $parray; 1396 } 1397 $parameters = array(); 1398 1399 foreach ($parray as $name => $value) { 1400 if ($urlencode) { 1401 $name = urlencode($name); 1402 } 1403 1404 // If $value is an array, iterate over it 1405 if (is_array($value)) { 1406 $name .= ($urlencode ? '%5B%5D' : '[]'); 1407 foreach ($value as $subval) { 1408 if ($urlencode) { 1409 $subval = urlencode($subval); 1410 } 1411 $parameters[] = array($name, $subval); 1412 } 1413 } else { 1414 if ($urlencode) { 1415 $value = urlencode($value); 1416 } 1417 $parameters[] = array($name, $value); 1418 } 1419 } 1420 1421 return $parameters; 1422 } 1423 1424 /** 1425 * Attempt to detect the MIME type of a file using available extensions 1426 * 1427 * This method will try to detect the MIME type of a file. If the fileinfo 1428 * extension is available, it will be used. If not, the mime_magic 1429 * extension which is deprected but is still available in many PHP setups 1430 * will be tried. 1431 * 1432 * If neither extension is available, the default application/octet-stream 1433 * MIME type will be returned 1434 * 1435 * @param string $file File path 1436 * @return string MIME type 1437 */ 1438 protected function _detectFileMimeType($file) 1439 { 1440 $type = null; 1441 1442 // First try with fileinfo functions 1443 if (function_exists('finfo_open')) { 1444 if (self::$_fileInfoDb === null) { 1445 self::$_fileInfoDb = @finfo_open(FILEINFO_MIME); 1446 } 1447 1448 if (self::$_fileInfoDb) { 1449 $type = finfo_file(self::$_fileInfoDb, $file); 1450 } 1451 1452 } elseif (function_exists('mime_content_type')) { 1453 $type = mime_content_type($file); 1454 } 1455 1456 // Fallback to the default application/octet-stream 1457 if (! $type) { 1458 $type = 'application/octet-stream'; 1459 } 1460 1461 return $type; 1462 } 1463 1464 /** 1465 * Encode data to a multipart/form-data part suitable for a POST request. 1466 * 1467 * @param string $boundary 1468 * @param string $name 1469 * @param mixed $value 1470 * @param string $filename 1471 * @param array $headers Associative array of optional headers @example ("Content-Transfer-Encoding" => "binary") 1472 * @return string 1473 */ 1474 public static function encodeFormData($boundary, $name, $value, $filename = null, $headers = array()) 1475 { 1476 $ret = "--{$boundary}\r\n" . 1477 'Content-Disposition: form-data; name="' . $name .'"'; 1478 1479 if ($filename) { 1480 $ret .= '; filename="' . $filename . '"'; 1481 } 1482 $ret .= "\r\n"; 1483 1484 foreach ($headers as $hname => $hvalue) { 1485 $ret .= "{$hname}: {$hvalue}\r\n"; 1486 } 1487 $ret .= "\r\n"; 1488 1489 $ret .= "{$value}\r\n"; 1490 1491 return $ret; 1492 } 1493 1494 /** 1495 * Create a HTTP authentication "Authorization:" header according to the 1496 * specified user, password and authentication method. 1497 * 1498 * @see http://www.faqs.org/rfcs/rfc2617.html 1499 * @param string $user 1500 * @param string $password 1501 * @param string $type 1502 * @return string 1503 * @throws Zend_Http_Client_Exception 1504 */ 1505 public static function encodeAuthHeader($user, $password, $type = self::AUTH_BASIC) 1506 { 1507 $authHeader = null; 1508 1509 switch ($type) { 1510 case self::AUTH_BASIC: 1511 // In basic authentication, the user name cannot contain ":" 1512 if (strpos($user, ':') !== false) { 1513 /** @see Zend_Http_Client_Exception */ 1514 // require_once 'Zend/Http/Client/Exception.php'; 1515 throw new Zend_Http_Client_Exception("The user name cannot contain ':' in 'Basic' HTTP authentication"); 1516 } 1517 1518 $authHeader = 'Basic ' . base64_encode($user . ':' . $password); 1519 break; 1520 1521 //case self::AUTH_DIGEST: 1522 /** 1523 * @todo Implement digest authentication 1524 */ 1525 // break; 1526 1527 default: 1528 /** @see Zend_Http_Client_Exception */ 1529 // require_once 'Zend/Http/Client/Exception.php'; 1530 throw new Zend_Http_Client_Exception("Not a supported HTTP authentication type: '$type'"); 1531 } 1532 1533 return $authHeader; 1534 } 1535 1536 /** 1537 * Convert an array of parameters into a flat array of (key, value) pairs 1538 * 1539 * Will flatten a potentially multi-dimentional array of parameters (such 1540 * as POST parameters) into a flat array of (key, value) paris. In case 1541 * of multi-dimentional arrays, square brackets ([]) will be added to the 1542 * key to indicate an array. 1543 * 1544 * @since 1.9 1545 * 1546 * @param array $parray 1547 * @param string $prefix 1548 * @return array 1549 */ 1550 protected static function _flattenParametersArray($parray, $prefix = null) 1551 { 1552 if (! is_array($parray)) { 1553 return $parray; 1554 } 1555 1556 $parameters = array(); 1557 1558 foreach($parray as $name => $value) { 1559 1560 // Calculate array key 1561 if ($prefix) { 1562 if (is_int($name)) { 1563 $key = $prefix . '[]'; 1564 } else { 1565 $key = $prefix . "[$name]"; 1566 } 1567 } else { 1568 $key = $name; 1569 } 1570 1571 if (is_array($value)) { 1572 $parameters = array_merge($parameters, self::_flattenParametersArray($value, $key)); 1573 1574 } else { 1575 $parameters[] = array($key, $value); 1576 } 1577 } 1578 1579 return $parameters; 1580 } 1581 1582 /** 1583 * Ensure a header value is valid per RFC 7230. 1584 * 1585 * @see http://tools.ietf.org/html/rfc7230#section-3.2 1586 * @param string|object|array $value 1587 * @param bool $recurse 1588 */ 1589 protected function _validateHeaderValue($value, $recurse = true) 1590 { 1591 if (is_array($value) && $recurse) { 1592 foreach ($value as $v) { 1593 $this->_validateHeaderValue($v, false); 1594 } 1595 return; 1596 } 1597 1598 // Cast integers and floats to strings for purposes of header representation. 1599 if (is_int($value) || is_float($value)) { 1600 $value = (string) $value; 1601 } 1602 1603 if (! is_string($value) && (! is_object($value) || ! method_exists($value, '__toString'))) { 1604 // require_once 'Zend/Http/Exception.php'; 1605 throw new Zend_Http_Exception('Invalid header value detected'); 1606 } 1607 1608 Zend_Http_Header_HeaderValue::assertValid($value); 1609 } 1610 }