|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00027 require_once 'Zend/Loader.php'; 00028 00029 00033 require_once 'Zend/Uri.php'; 00034 00035 00039 require_once 'Zend/Http/Client/Adapter/Interface.php'; 00040 00041 00045 require_once 'Zend/Http/Response.php'; 00046 00050 require_once 'Zend/Http/Response/Stream.php'; 00051 00066 class Zend_Http_Client 00067 { 00071 const GET = 'GET'; 00072 const POST = 'POST'; 00073 const PUT = 'PUT'; 00074 const HEAD = 'HEAD'; 00075 const DELETE = 'DELETE'; 00076 const TRACE = 'TRACE'; 00077 const OPTIONS = 'OPTIONS'; 00078 const CONNECT = 'CONNECT'; 00079 const MERGE = 'MERGE'; 00080 00084 const AUTH_BASIC = 'basic'; 00085 //const AUTH_DIGEST = 'digest'; <-- not implemented yet 00086 00090 const HTTP_1 = '1.1'; 00091 const HTTP_0 = '1.0'; 00092 00096 const CONTENT_TYPE = 'Content-Type'; 00097 const CONTENT_LENGTH = 'Content-Length'; 00098 00102 const ENC_URLENCODED = 'application/x-www-form-urlencoded'; 00103 const ENC_FORMDATA = 'multipart/form-data'; 00104 00110 protected $config = array( 00111 'maxredirects' => 5, 00112 'strictredirects' => false, 00113 'useragent' => 'Zend_Http_Client', 00114 'timeout' => 10, 00115 'adapter' => 'Zend_Http_Client_Adapter_Socket', 00116 'httpversion' => self::HTTP_1, 00117 'keepalive' => false, 00118 'storeresponse' => true, 00119 'strict' => true, 00120 'output_stream' => false, 00121 'encodecookies' => true, 00122 ); 00123 00129 protected $adapter = null; 00130 00136 protected $uri = null; 00137 00143 protected $headers = array(); 00144 00150 protected $method = self::GET; 00151 00157 protected $paramsGet = array(); 00158 00164 protected $paramsPost = array(); 00165 00171 protected $enctype = null; 00172 00178 protected $raw_post_data = null; 00179 00192 protected $auth; 00193 00202 protected $files = array(); 00203 00209 protected $cookiejar = null; 00210 00216 protected $last_request = null; 00217 00223 protected $last_response = null; 00224 00230 protected $redirectCounter = 0; 00231 00240 static protected $_fileInfoDb = null; 00241 00249 public function __construct($uri = null, $config = null) 00250 { 00251 if ($uri !== null) { 00252 $this->setUri($uri); 00253 } 00254 if ($config !== null) { 00255 $this->setConfig($config); 00256 } 00257 } 00258 00266 public function setUri($uri) 00267 { 00268 if (is_string($uri)) { 00269 $uri = Zend_Uri::factory($uri); 00270 } 00271 00272 if (!$uri instanceof Zend_Uri_Http) { 00274 require_once 'Zend/Http/Client/Exception.php'; 00275 throw new Zend_Http_Client_Exception('Passed parameter is not a valid HTTP URI.'); 00276 } 00277 00278 // Set auth if username and password has been specified in the uri 00279 if ($uri->getUsername() && $uri->getPassword()) { 00280 $this->setAuth($uri->getUsername(), $uri->getPassword()); 00281 } 00282 00283 // We have no ports, set the defaults 00284 if (! $uri->getPort()) { 00285 $uri->setPort(($uri->getScheme() == 'https' ? 443 : 80)); 00286 } 00287 00288 $this->uri = $uri; 00289 00290 return $this; 00291 } 00292 00299 public function getUri($as_string = false) 00300 { 00301 if ($as_string && $this->uri instanceof Zend_Uri_Http) { 00302 return $this->uri->__toString(); 00303 } else { 00304 return $this->uri; 00305 } 00306 } 00307 00315 public function setConfig($config = array()) 00316 { 00317 if ($config instanceof Zend_Config) { 00318 $config = $config->toArray(); 00319 00320 } elseif (! is_array($config)) { 00322 require_once 'Zend/Http/Client/Exception.php'; 00323 throw new Zend_Http_Client_Exception('Array or Zend_Config object expected, got ' . gettype($config)); 00324 } 00325 00326 foreach ($config as $k => $v) { 00327 $this->config[strtolower($k)] = $v; 00328 } 00329 00330 // Pass configuration options to the adapter if it exists 00331 if ($this->adapter instanceof Zend_Http_Client_Adapter_Interface) { 00332 $this->adapter->setConfig($config); 00333 } 00334 00335 return $this; 00336 } 00337 00349 public function setMethod($method = self::GET) 00350 { 00351 if (! preg_match('/^[^\x00-\x1f\x7f-\xff\(\)<>@,;:\\\\"\/\[\]\?={}\s]+$/', $method)) { 00353 require_once 'Zend/Http/Client/Exception.php'; 00354 throw new Zend_Http_Client_Exception("'{$method}' is not a valid HTTP request method."); 00355 } 00356 00357 if ($method == self::POST && $this->enctype === null) { 00358 $this->setEncType(self::ENC_URLENCODED); 00359 } 00360 00361 $this->method = $method; 00362 00363 return $this; 00364 } 00365 00385 public function setHeaders($name, $value = null) 00386 { 00387 // If we got an array, go recusive! 00388 if (is_array($name)) { 00389 foreach ($name as $k => $v) { 00390 if (is_string($k)) { 00391 $this->setHeaders($k, $v); 00392 } else { 00393 $this->setHeaders($v, null); 00394 } 00395 } 00396 } else { 00397 // Check if $name needs to be split 00398 if ($value === null && (strpos($name, ':') > 0)) { 00399 list($name, $value) = explode(':', $name, 2); 00400 } 00401 00402 // Make sure the name is valid if we are in strict mode 00403 if ($this->config['strict'] && (! preg_match('/^[a-zA-Z0-9-]+$/', $name))) { 00405 require_once 'Zend/Http/Client/Exception.php'; 00406 throw new Zend_Http_Client_Exception("{$name} is not a valid HTTP header name"); 00407 } 00408 00409 $normalized_name = strtolower($name); 00410 00411 // If $value is null or false, unset the header 00412 if ($value === null || $value === false) { 00413 unset($this->headers[$normalized_name]); 00414 00415 // Else, set the header 00416 } else { 00417 // Header names are stored lowercase internally. 00418 if (is_string($value)) { 00419 $value = trim($value); 00420 } 00421 $this->headers[$normalized_name] = array($name, $value); 00422 } 00423 } 00424 00425 return $this; 00426 } 00427 00437 public function getHeader($key) 00438 { 00439 $key = strtolower($key); 00440 if (isset($this->headers[$key])) { 00441 return $this->headers[$key][1]; 00442 } else { 00443 return null; 00444 } 00445 } 00446 00454 public function setParameterGet($name, $value = null) 00455 { 00456 if (is_array($name)) { 00457 foreach ($name as $k => $v) 00458 $this->_setParameter('GET', $k, $v); 00459 } else { 00460 $this->_setParameter('GET', $name, $value); 00461 } 00462 00463 return $this; 00464 } 00465 00473 public function setParameterPost($name, $value = null) 00474 { 00475 if (is_array($name)) { 00476 foreach ($name as $k => $v) 00477 $this->_setParameter('POST', $k, $v); 00478 } else { 00479 $this->_setParameter('POST', $name, $value); 00480 } 00481 00482 return $this; 00483 } 00484 00493 protected function _setParameter($type, $name, $value) 00494 { 00495 $parray = array(); 00496 $type = strtolower($type); 00497 switch ($type) { 00498 case 'get': 00499 $parray = &$this->paramsGet; 00500 break; 00501 case 'post': 00502 $parray = &$this->paramsPost; 00503 break; 00504 } 00505 00506 if ($value === null) { 00507 if (isset($parray[$name])) unset($parray[$name]); 00508 } else { 00509 $parray[$name] = $value; 00510 } 00511 } 00512 00518 public function getRedirectionsCount() 00519 { 00520 return $this->redirectCounter; 00521 } 00522 00546 public function setAuth($user, $password = '', $type = self::AUTH_BASIC) 00547 { 00548 // If we got false or null, disable authentication 00549 if ($user === false || $user === null) { 00550 $this->auth = null; 00551 00552 // Clear the auth information in the uri instance as well 00553 if ($this->uri instanceof Zend_Uri_Http) { 00554 $this->getUri()->setUsername(''); 00555 $this->getUri()->setPassword(''); 00556 } 00557 // Else, set up authentication 00558 } else { 00559 // Check we got a proper authentication type 00560 if (! defined('self::AUTH_' . strtoupper($type))) { 00562 require_once 'Zend/Http/Client/Exception.php'; 00563 throw new Zend_Http_Client_Exception("Invalid or not supported authentication type: '$type'"); 00564 } 00565 00566 $this->auth = array( 00567 'user' => (string) $user, 00568 'password' => (string) $password, 00569 'type' => $type 00570 ); 00571 } 00572 00573 return $this; 00574 } 00575 00586 public function setCookieJar($cookiejar = true) 00587 { 00588 if (! class_exists('Zend_Http_CookieJar')) { 00589 require_once 'Zend/Http/CookieJar.php'; 00590 } 00591 00592 if ($cookiejar instanceof Zend_Http_CookieJar) { 00593 $this->cookiejar = $cookiejar; 00594 } elseif ($cookiejar === true) { 00595 $this->cookiejar = new Zend_Http_CookieJar(); 00596 } elseif (! $cookiejar) { 00597 $this->cookiejar = null; 00598 } else { 00600 require_once 'Zend/Http/Client/Exception.php'; 00601 throw new Zend_Http_Client_Exception('Invalid parameter type passed as CookieJar'); 00602 } 00603 00604 return $this; 00605 } 00606 00612 public function getCookieJar() 00613 { 00614 return $this->cookiejar; 00615 } 00616 00626 public function setCookie($cookie, $value = null) 00627 { 00628 if (! class_exists('Zend_Http_Cookie')) { 00629 require_once 'Zend/Http/Cookie.php'; 00630 } 00631 00632 if (is_array($cookie)) { 00633 foreach ($cookie as $c => $v) { 00634 if (is_string($c)) { 00635 $this->setCookie($c, $v); 00636 } else { 00637 $this->setCookie($v); 00638 } 00639 } 00640 00641 return $this; 00642 } 00643 00644 if ($value !== null && $this->config['encodecookies']) { 00645 $value = urlencode($value); 00646 } 00647 00648 if (isset($this->cookiejar)) { 00649 if ($cookie instanceof Zend_Http_Cookie) { 00650 $this->cookiejar->addCookie($cookie); 00651 } elseif (is_string($cookie) && $value !== null) { 00652 $cookie = Zend_Http_Cookie::fromString("{$cookie}={$value}", 00653 $this->uri, 00654 $this->config['encodecookies']); 00655 $this->cookiejar->addCookie($cookie); 00656 } 00657 } else { 00658 if ($cookie instanceof Zend_Http_Cookie) { 00659 $name = $cookie->getName(); 00660 $value = $cookie->getValue(); 00661 $cookie = $name; 00662 } 00663 00664 if (preg_match("/[=,; \t\r\n\013\014]/", $cookie)) { 00666 require_once 'Zend/Http/Client/Exception.php'; 00667 throw new Zend_Http_Client_Exception("Cookie name cannot contain these characters: =,; \t\r\n\013\014 ({$cookie})"); 00668 } 00669 00670 $value = addslashes($value); 00671 00672 if (! isset($this->headers['cookie'])) { 00673 $this->headers['cookie'] = array('Cookie', ''); 00674 } 00675 $this->headers['cookie'][1] .= $cookie . '=' . $value . '; '; 00676 } 00677 00678 return $this; 00679 } 00680 00701 public function setFileUpload($filename, $formname, $data = null, $ctype = null) 00702 { 00703 if ($data === null) { 00704 if (($data = @file_get_contents($filename)) === false) { 00706 require_once 'Zend/Http/Client/Exception.php'; 00707 throw new Zend_Http_Client_Exception("Unable to read file '{$filename}' for upload"); 00708 } 00709 00710 if (! $ctype) { 00711 $ctype = $this->_detectFileMimeType($filename); 00712 } 00713 } 00714 00715 // Force enctype to multipart/form-data 00716 $this->setEncType(self::ENC_FORMDATA); 00717 00718 $this->files[] = array( 00719 'formname' => $formname, 00720 'filename' => basename($filename), 00721 'ctype' => $ctype, 00722 'data' => $data 00723 ); 00724 00725 return $this; 00726 } 00727 00734 public function setEncType($enctype = self::ENC_URLENCODED) 00735 { 00736 $this->enctype = $enctype; 00737 00738 return $this; 00739 } 00740 00755 public function setRawData($data, $enctype = null) 00756 { 00757 $this->raw_post_data = $data; 00758 $this->setEncType($enctype); 00759 if (is_resource($data)) { 00760 // We've got stream data 00761 $stat = @fstat($data); 00762 if($stat) { 00763 $this->setHeaders(self::CONTENT_LENGTH, $stat['size']); 00764 } 00765 } 00766 return $this; 00767 } 00768 00781 public function resetParameters($clearAll = false) 00782 { 00783 // Reset parameter data 00784 $this->paramsGet = array(); 00785 $this->paramsPost = array(); 00786 $this->files = array(); 00787 $this->raw_post_data = null; 00788 00789 if($clearAll) { 00790 $this->headers = array(); 00791 $this->last_request = null; 00792 $this->last_response = null; 00793 } else { 00794 // Clear outdated headers 00795 if (isset($this->headers[strtolower(self::CONTENT_TYPE)])) { 00796 unset($this->headers[strtolower(self::CONTENT_TYPE)]); 00797 } 00798 if (isset($this->headers[strtolower(self::CONTENT_LENGTH)])) { 00799 unset($this->headers[strtolower(self::CONTENT_LENGTH)]); 00800 } 00801 } 00802 00803 return $this; 00804 } 00805 00811 public function getLastRequest() 00812 { 00813 return $this->last_request; 00814 } 00815 00824 public function getLastResponse() 00825 { 00826 return $this->last_response; 00827 } 00828 00839 public function setAdapter($adapter) 00840 { 00841 if (is_string($adapter)) { 00842 if (!class_exists($adapter)) { 00843 try { 00844 require_once 'Zend/Loader.php'; 00845 Zend_Loader::loadClass($adapter); 00846 } catch (Zend_Exception $e) { 00848 require_once 'Zend/Http/Client/Exception.php'; 00849 throw new Zend_Http_Client_Exception("Unable to load adapter '$adapter': {$e->getMessage()}", 0, $e); 00850 } 00851 } 00852 00853 $adapter = new $adapter; 00854 } 00855 00856 if (! $adapter instanceof Zend_Http_Client_Adapter_Interface) { 00858 require_once 'Zend/Http/Client/Exception.php'; 00859 throw new Zend_Http_Client_Exception('Passed adapter is not a HTTP connection adapter'); 00860 } 00861 00862 $this->adapter = $adapter; 00863 $config = $this->config; 00864 unset($config['adapter']); 00865 $this->adapter->setConfig($config); 00866 } 00867 00873 public function getAdapter() 00874 { 00875 return $this->adapter; 00876 } 00877 00884 public function setStream($streamfile = true) 00885 { 00886 $this->setConfig(array("output_stream" => $streamfile)); 00887 return $this; 00888 } 00889 00894 public function getStream() 00895 { 00896 return $this->config["output_stream"]; 00897 } 00898 00904 protected function _openTempStream() 00905 { 00906 $this->_stream_name = $this->config['output_stream']; 00907 if(!is_string($this->_stream_name)) { 00908 // If name is not given, create temp name 00909 $this->_stream_name = tempnam(isset($this->config['stream_tmp_dir'])?$this->config['stream_tmp_dir']:sys_get_temp_dir(), 00910 'Zend_Http_Client'); 00911 } 00912 00913 if (false === ($fp = @fopen($this->_stream_name, "w+b"))) { 00914 if ($this->adapter instanceof Zend_Http_Client_Adapter_Interface) { 00915 $this->adapter->close(); 00916 } 00917 require_once 'Zend/Http/Client/Exception.php'; 00918 throw new Zend_Http_Client_Exception("Could not open temp file {$this->_stream_name}"); 00919 } 00920 00921 return $fp; 00922 } 00923 00931 public function request($method = null) 00932 { 00933 if (! $this->uri instanceof Zend_Uri_Http) { 00935 require_once 'Zend/Http/Client/Exception.php'; 00936 throw new Zend_Http_Client_Exception('No valid URI has been passed to the client'); 00937 } 00938 00939 if ($method) { 00940 $this->setMethod($method); 00941 } 00942 $this->redirectCounter = 0; 00943 $response = null; 00944 00945 // Make sure the adapter is loaded 00946 if ($this->adapter == null) { 00947 $this->setAdapter($this->config['adapter']); 00948 } 00949 00950 // Send the first request. If redirected, continue. 00951 do { 00952 // Clone the URI and add the additional GET parameters to it 00953 $uri = clone $this->uri; 00954 if (! empty($this->paramsGet)) { 00955 $query = $uri->getQuery(); 00956 if (! empty($query)) { 00957 $query .= '&'; 00958 } 00959 $query .= http_build_query($this->paramsGet, null, '&'); 00960 00961 $uri->setQuery($query); 00962 } 00963 00964 $body = $this->_prepareBody(); 00965 $headers = $this->_prepareHeaders(); 00966 00967 // check that adapter supports streaming before using it 00968 if(is_resource($body) && !($this->adapter instanceof Zend_Http_Client_Adapter_Stream)) { 00970 require_once 'Zend/Http/Client/Exception.php'; 00971 throw new Zend_Http_Client_Exception('Adapter does not support streaming'); 00972 } 00973 00974 // Open the connection, send the request and read the response 00975 $this->adapter->connect($uri->getHost(), $uri->getPort(), 00976 ($uri->getScheme() == 'https' ? true : false)); 00977 00978 if($this->config['output_stream']) { 00979 if($this->adapter instanceof Zend_Http_Client_Adapter_Stream) { 00980 $stream = $this->_openTempStream(); 00981 $this->adapter->setOutputStream($stream); 00982 } else { 00984 require_once 'Zend/Http/Client/Exception.php'; 00985 throw new Zend_Http_Client_Exception('Adapter does not support streaming'); 00986 } 00987 } 00988 00989 $this->last_request = $this->adapter->write($this->method, 00990 $uri, $this->config['httpversion'], $headers, $body); 00991 00992 $response = $this->adapter->read(); 00993 if (! $response) { 00995 require_once 'Zend/Http/Client/Exception.php'; 00996 throw new Zend_Http_Client_Exception('Unable to read response, or response is empty'); 00997 } 00998 00999 if($this->config['output_stream']) { 01000 rewind($stream); 01001 // cleanup the adapter 01002 $this->adapter->setOutputStream(null); 01003 $response = Zend_Http_Response_Stream::fromStream($response, $stream); 01004 $response->setStreamName($this->_stream_name); 01005 if(!is_string($this->config['output_stream'])) { 01006 // we used temp name, will need to clean up 01007 $response->setCleanup(true); 01008 } 01009 } else { 01010 $response = Zend_Http_Response::fromString($response); 01011 } 01012 01013 if ($this->config['storeresponse']) { 01014 $this->last_response = $response; 01015 } 01016 01017 // Load cookies into cookie jar 01018 if (isset($this->cookiejar)) { 01019 $this->cookiejar->addCookiesFromResponse($response, $uri); 01020 } 01021 01022 // If we got redirected, look for the Location header 01023 if ($response->isRedirect() && ($location = $response->getHeader('location'))) { 01024 01025 // Check whether we send the exact same request again, or drop the parameters 01026 // and send a GET request 01027 if ($response->getStatus() == 303 || 01028 ((! $this->config['strictredirects']) && ($response->getStatus() == 302 || 01029 $response->getStatus() == 301))) { 01030 01031 $this->resetParameters(); 01032 $this->setMethod(self::GET); 01033 } 01034 01035 // If we got a well formed absolute URI 01036 if (Zend_Uri_Http::check($location)) { 01037 $this->setHeaders('host', null); 01038 $this->setUri($location); 01039 01040 } else { 01041 01042 // Split into path and query and set the query 01043 if (strpos($location, '?') !== false) { 01044 list($location, $query) = explode('?', $location, 2); 01045 } else { 01046 $query = ''; 01047 } 01048 $this->uri->setQuery($query); 01049 01050 // Else, if we got just an absolute path, set it 01051 if(strpos($location, '/') === 0) { 01052 $this->uri->setPath($location); 01053 01054 // Else, assume we have a relative path 01055 } else { 01056 // Get the current path directory, removing any trailing slashes 01057 $path = $this->uri->getPath(); 01058 $path = rtrim(substr($path, 0, strrpos($path, '/')), "/"); 01059 $this->uri->setPath($path . '/' . $location); 01060 } 01061 } 01062 ++$this->redirectCounter; 01063 01064 } else { 01065 // If we didn't get any location, stop redirecting 01066 break; 01067 } 01068 01069 } while ($this->redirectCounter < $this->config['maxredirects']); 01070 01071 return $response; 01072 } 01073 01079 protected function _prepareHeaders() 01080 { 01081 $headers = array(); 01082 01083 // Set the host header 01084 if (! isset($this->headers['host'])) { 01085 $host = $this->uri->getHost(); 01086 01087 // If the port is not default, add it 01088 if (! (($this->uri->getScheme() == 'http' && $this->uri->getPort() == 80) || 01089 ($this->uri->getScheme() == 'https' && $this->uri->getPort() == 443))) { 01090 $host .= ':' . $this->uri->getPort(); 01091 } 01092 01093 $headers[] = "Host: {$host}"; 01094 } 01095 01096 // Set the connection header 01097 if (! isset($this->headers['connection'])) { 01098 if (! $this->config['keepalive']) { 01099 $headers[] = "Connection: close"; 01100 } 01101 } 01102 01103 // Set the Accept-encoding header if not set - depending on whether 01104 // zlib is available or not. 01105 if (! isset($this->headers['accept-encoding'])) { 01106 if (function_exists('gzinflate')) { 01107 $headers[] = 'Accept-encoding: gzip, deflate'; 01108 } else { 01109 $headers[] = 'Accept-encoding: identity'; 01110 } 01111 } 01112 01113 // Set the Content-Type header 01114 if ($this->method == self::POST && 01115 (! isset($this->headers[strtolower(self::CONTENT_TYPE)]) && isset($this->enctype))) { 01116 01117 $headers[] = self::CONTENT_TYPE . ': ' . $this->enctype; 01118 } 01119 01120 // Set the user agent header 01121 if (! isset($this->headers['user-agent']) && isset($this->config['useragent'])) { 01122 $headers[] = "User-Agent: {$this->config['useragent']}"; 01123 } 01124 01125 // Set HTTP authentication if needed 01126 if (is_array($this->auth)) { 01127 $auth = self::encodeAuthHeader($this->auth['user'], $this->auth['password'], $this->auth['type']); 01128 $headers[] = "Authorization: {$auth}"; 01129 } 01130 01131 // Load cookies from cookie jar 01132 if (isset($this->cookiejar)) { 01133 $cookstr = $this->cookiejar->getMatchingCookies($this->uri, 01134 true, Zend_Http_CookieJar::COOKIE_STRING_CONCAT); 01135 01136 if ($cookstr) { 01137 $headers[] = "Cookie: {$cookstr}"; 01138 } 01139 } 01140 01141 // Add all other user defined headers 01142 foreach ($this->headers as $header) { 01143 list($name, $value) = $header; 01144 if (is_array($value)) { 01145 $value = implode(', ', $value); 01146 } 01147 01148 $headers[] = "$name: $value"; 01149 } 01150 01151 return $headers; 01152 } 01153 01160 protected function _prepareBody() 01161 { 01162 // According to RFC2616, a TRACE request should not have a body. 01163 if ($this->method == self::TRACE) { 01164 return ''; 01165 } 01166 01167 if (isset($this->raw_post_data) && is_resource($this->raw_post_data)) { 01168 return $this->raw_post_data; 01169 } 01170 // If mbstring overloads substr and strlen functions, we have to 01171 // override it's internal encoding 01172 if (function_exists('mb_internal_encoding') && 01173 ((int) ini_get('mbstring.func_overload')) & 2) { 01174 01175 $mbIntEnc = mb_internal_encoding(); 01176 mb_internal_encoding('ASCII'); 01177 } 01178 01179 // If we have raw_post_data set, just use it as the body. 01180 if (isset($this->raw_post_data)) { 01181 $this->setHeaders(self::CONTENT_LENGTH, strlen($this->raw_post_data)); 01182 if (isset($mbIntEnc)) { 01183 mb_internal_encoding($mbIntEnc); 01184 } 01185 01186 return $this->raw_post_data; 01187 } 01188 01189 $body = ''; 01190 01191 // If we have files to upload, force enctype to multipart/form-data 01192 if (count ($this->files) > 0) { 01193 $this->setEncType(self::ENC_FORMDATA); 01194 } 01195 01196 // If we have POST parameters or files, encode and add them to the body 01197 if (count($this->paramsPost) > 0 || count($this->files) > 0) { 01198 switch($this->enctype) { 01199 case self::ENC_FORMDATA: 01200 // Encode body as multipart/form-data 01201 $boundary = '---ZENDHTTPCLIENT-' . md5(microtime()); 01202 $this->setHeaders(self::CONTENT_TYPE, self::ENC_FORMDATA . "; boundary={$boundary}"); 01203 01204 // Get POST parameters and encode them 01205 $params = self::_flattenParametersArray($this->paramsPost); 01206 foreach ($params as $pp) { 01207 $body .= self::encodeFormData($boundary, $pp[0], $pp[1]); 01208 } 01209 01210 // Encode files 01211 foreach ($this->files as $file) { 01212 $fhead = array(self::CONTENT_TYPE => $file['ctype']); 01213 $body .= self::encodeFormData($boundary, $file['formname'], $file['data'], $file['filename'], $fhead); 01214 } 01215 01216 $body .= "--{$boundary}--\r\n"; 01217 break; 01218 01219 case self::ENC_URLENCODED: 01220 // Encode body as application/x-www-form-urlencoded 01221 $this->setHeaders(self::CONTENT_TYPE, self::ENC_URLENCODED); 01222 $body = http_build_query($this->paramsPost, '', '&'); 01223 break; 01224 01225 default: 01226 if (isset($mbIntEnc)) { 01227 mb_internal_encoding($mbIntEnc); 01228 } 01229 01231 require_once 'Zend/Http/Client/Exception.php'; 01232 throw new Zend_Http_Client_Exception("Cannot handle content type '{$this->enctype}' automatically." . 01233 " Please use Zend_Http_Client::setRawData to send this kind of content."); 01234 break; 01235 } 01236 } 01237 01238 // Set the Content-Length if we have a body or if request is POST/PUT 01239 if ($body || $this->method == self::POST || $this->method == self::PUT) { 01240 $this->setHeaders(self::CONTENT_LENGTH, strlen($body)); 01241 } 01242 01243 if (isset($mbIntEnc)) { 01244 mb_internal_encoding($mbIntEnc); 01245 } 01246 01247 return $body; 01248 } 01249 01267 protected function _getParametersRecursive($parray, $urlencode = false) 01268 { 01269 // Issue a deprecated notice 01270 trigger_error("The " . __METHOD__ . " method is deprecated and will be dropped in 2.0.", 01271 E_USER_NOTICE); 01272 01273 if (! is_array($parray)) { 01274 return $parray; 01275 } 01276 $parameters = array(); 01277 01278 foreach ($parray as $name => $value) { 01279 if ($urlencode) { 01280 $name = urlencode($name); 01281 } 01282 01283 // If $value is an array, iterate over it 01284 if (is_array($value)) { 01285 $name .= ($urlencode ? '%5B%5D' : '[]'); 01286 foreach ($value as $subval) { 01287 if ($urlencode) { 01288 $subval = urlencode($subval); 01289 } 01290 $parameters[] = array($name, $subval); 01291 } 01292 } else { 01293 if ($urlencode) { 01294 $value = urlencode($value); 01295 } 01296 $parameters[] = array($name, $value); 01297 } 01298 } 01299 01300 return $parameters; 01301 } 01302 01317 protected function _detectFileMimeType($file) 01318 { 01319 $type = null; 01320 01321 // First try with fileinfo functions 01322 if (function_exists('finfo_open')) { 01323 if (self::$_fileInfoDb === null) { 01324 self::$_fileInfoDb = @finfo_open(FILEINFO_MIME); 01325 } 01326 01327 if (self::$_fileInfoDb) { 01328 $type = finfo_file(self::$_fileInfoDb, $file); 01329 } 01330 01331 } elseif (function_exists('mime_content_type')) { 01332 $type = mime_content_type($file); 01333 } 01334 01335 // Fallback to the default application/octet-stream 01336 if (! $type) { 01337 $type = 'application/octet-stream'; 01338 } 01339 01340 return $type; 01341 } 01342 01353 public static function encodeFormData($boundary, $name, $value, $filename = null, $headers = array()) { 01354 $ret = "--{$boundary}\r\n" . 01355 'Content-Disposition: form-data; name="' . $name .'"'; 01356 01357 if ($filename) { 01358 $ret .= '; filename="' . $filename . '"'; 01359 } 01360 $ret .= "\r\n"; 01361 01362 foreach ($headers as $hname => $hvalue) { 01363 $ret .= "{$hname}: {$hvalue}\r\n"; 01364 } 01365 $ret .= "\r\n"; 01366 01367 $ret .= "{$value}\r\n"; 01368 01369 return $ret; 01370 } 01371 01383 public static function encodeAuthHeader($user, $password, $type = self::AUTH_BASIC) 01384 { 01385 $authHeader = null; 01386 01387 switch ($type) { 01388 case self::AUTH_BASIC: 01389 // In basic authentication, the user name cannot contain ":" 01390 if (strpos($user, ':') !== false) { 01392 require_once 'Zend/Http/Client/Exception.php'; 01393 throw new Zend_Http_Client_Exception("The user name cannot contain ':' in 'Basic' HTTP authentication"); 01394 } 01395 01396 $authHeader = 'Basic ' . base64_encode($user . ':' . $password); 01397 break; 01398 01399 //case self::AUTH_DIGEST: 01403 // break; 01404 01405 default: 01407 require_once 'Zend/Http/Client/Exception.php'; 01408 throw new Zend_Http_Client_Exception("Not a supported HTTP authentication type: '$type'"); 01409 } 01410 01411 return $authHeader; 01412 } 01413 01428 static protected function _flattenParametersArray($parray, $prefix = null) 01429 { 01430 if (! is_array($parray)) { 01431 return $parray; 01432 } 01433 01434 $parameters = array(); 01435 01436 foreach($parray as $name => $value) { 01437 01438 // Calculate array key 01439 if ($prefix) { 01440 if (is_int($name)) { 01441 $key = $prefix . '[]'; 01442 } else { 01443 $key = $prefix . "[$name]"; 01444 } 01445 } else { 01446 $key = $name; 01447 } 01448 01449 if (is_array($value)) { 01450 $parameters = array_merge($parameters, self::_flattenParametersArray($value, $key)); 01451 01452 } else { 01453 $parameters[] = array($key, $value); 01454 } 01455 } 01456 01457 return $parameters; 01458 } 01459 01460 }