getMessage(), "\n"; exit -1; } spl_autoload_register(function ($class) { $class = str_replace(array('_', '\\'), '/', $class); if (file_exists('phar://' . __FILE__ . '/Zend_Http-2.0.0dev20110916/php/' . $class . '.php')) { include 'phar://' . __FILE__ . '/Zend_Http-2.0.0dev20110916/php/' . $class . '.php'; } }); $phar = new Phar(__FILE__); $sig = $phar->getSignature(); define('Zend_Http_SIG', $sig['hash']); define('Zend_Http_SIGTYPE', $sig['hash_type']); __HALT_COMPILER(); ?> !]ss:106:"Zend_Http-2.0.0dev20110916/.xmlregistry/packages/zfcampus.org!packages/Zend_Http/2.0.0dev20110916-info.xml";jZend_Http-2.0.0dev20110916/.xmlregistry/packages/zfcampus.org!packages/Zend_Http/2.0.0dev20110916-info.xmlsNr package.xml>sN>I ܶ@Zend_Http-2.0.0dev20110916/php/Zend/Http/Client/Adapter/Curl.phpJ?sNJ?@]Zend_Http-2.0.0dev20110916/php/Zend/Http/Client/Adapter/Exception/InitializationException.phpsN(Lƶ^Zend_Http-2.0.0dev20110916/php/Zend/Http/Client/Adapter/Exception/InvalidArgumentException.phpsNyTYZend_Http-2.0.0dev20110916/php/Zend/Http/Client/Adapter/Exception/OutOfRangeException.phpsNÄVZend_Http-2.0.0dev20110916/php/Zend/Http/Client/Adapter/Exception/RuntimeException.phpysNyjVZend_Http-2.0.0dev20110916/php/Zend/Http/Client/Adapter/Exception/TimeoutException.phpsN1LOEZend_Http-2.0.0dev20110916/php/Zend/Http/Client/Adapter/Exception.phpgsNg2նAZend_Http-2.0.0dev20110916/php/Zend/Http/Client/Adapter/Proxy.php:"sN:"Dc\BZend_Http-2.0.0dev20110916/php/Zend/Http/Client/Adapter/Socket.phpdDsNdD5?&BZend_Http-2.0.0dev20110916/php/Zend/Http/Client/Adapter/Stream.phpsNm,-@Zend_Http-2.0.0dev20110916/php/Zend/Http/Client/Adapter/Test.phpzsNzV;Zend_Http-2.0.0dev20110916/php/Zend/Http/Client/Adapter.phpsNo'к;Zend_Http-2.0.0dev20110916/php/Zend/Http/Client/Cookies.php~=sN~={VZend_Http-2.0.0dev20110916/php/Zend/Http/Client/Exception/InvalidArgumentException.phpqsNqr}(NZend_Http-2.0.0dev20110916/php/Zend/Http/Client/Exception/RuntimeException.phpasNab޶=Zend_Http-2.0.0dev20110916/php/Zend/Http/Client/Exception.phpAsNA8ȍK3Zend_Http-2.0.0dev20110916/php/Zend/Http/Client.php$sN$c\9Zend_Http-2.0.0dev20110916/php/Zend/Http/ClientStatic.php sN 4Zend_Http-2.0.0dev20110916/php/Zend/Http/Cookies.phpZ0sNZ0n&OZend_Http-2.0.0dev20110916/php/Zend/Http/Exception/InvalidArgumentException.phpsNwGZend_Http-2.0.0dev20110916/php/Zend/Http/Exception/RuntimeException.phpsN(6Zend_Http-2.0.0dev20110916/php/Zend/Http/Exception.php5sN5o4:Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Accept.phpG sNG ډ_˶AZend_Http-2.0.0dev20110916/php/Zend/Http/Header/AcceptCharset.phpMsNM\(BZend_Http-2.0.0dev20110916/php/Zend/Http/Header/AcceptEncoding.phpsN+DBZend_Http-2.0.0dev20110916/php/Zend/Http/Header/AcceptLanguage.phpsN97@Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/AcceptRanges.phpsNUC%]7Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Age.phpsNr9Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Allow.phpsN FZend_Http-2.0.0dev20110916/php/Zend/Http/Header/AuthenticationInfo.phpsN ӶAZend_Http-2.0.0dev20110916/php/Zend/Http/Header/Authorization.phpsN @Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/CacheControl.phpsNs>Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Connection.phpsNsFZend_Http-2.0.0dev20110916/php/Zend/Http/Header/ContentDisposition.phpsNZCZend_Http-2.0.0dev20110916/php/Zend/Http/Header/ContentEncoding.phpsNfCZend_Http-2.0.0dev20110916/php/Zend/Http/Header/ContentLanguage.phpsN#AZend_Http-2.0.0dev20110916/php/Zend/Http/Header/ContentLength.phpsN)CZend_Http-2.0.0dev20110916/php/Zend/Http/Header/ContentLocation.phpsN&ɶ>Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/ContentMD5.phpsN-̶@Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/ContentRange.phpsN|V?Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/ContentType.phpsNRz:Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Cookie.php(sN({8Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Date.phpsN[ƒ8Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Etag.phpsN4*VZend_Http-2.0.0dev20110916/php/Zend/Http/Header/Exception/InvalidArgumentException.phpsN..$zNZend_Http-2.0.0dev20110916/php/Zend/Http/Header/Exception/RuntimeException.phpsN0=Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Exception.php<sN<cuM:Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Expect.phpsNĈ0;Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Expires.phpsNͨ~K8Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/From.phpsN v-AZend_Http-2.0.0dev20110916/php/Zend/Http/Header/GenericHeader.php sN nt#FZend_Http-2.0.0dev20110916/php/Zend/Http/Header/GenericMultiHeader.php sN RjEZend_Http-2.0.0dev20110916/php/Zend/Http/Header/HeaderDescription.phpsN8Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Host.phpsN>1t;Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/IfMatch.phpsNwŶCZend_Http-2.0.0dev20110916/php/Zend/Http/Header/IfModifiedSince.phpsN6?Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/IfNoneMatch.phpsN'ᬹ;Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/IfRange.phpsNEZend_Http-2.0.0dev20110916/php/Zend/Http/Header/IfUnmodifiedSince.phpsNж=Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/KeepAlive.phpsNS̸@Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/LastModified.phpsNm[<Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Location.phpYsNY VSU?Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/MaxForwards.phpsN:%MZend_Http-2.0.0dev20110916/php/Zend/Http/Header/MultipleHeaderDescription.phpsNw:Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Pragma.phpsN2EZend_Http-2.0.0dev20110916/php/Zend/Http/Header/ProxyAuthenticate.phpsNL FZend_Http-2.0.0dev20110916/php/Zend/Http/Header/ProxyAuthorization.phpsNL|9Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Range.phpsNi2;Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Referer.phpsNM>;Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Refresh.phpsN[>Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/RetryAfter.phpsNqUaƶ:Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Server.phpsNO ݶ=Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/SetCookie.php%sN% 6Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/TE.phpsN9 ;Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Trailer.phpsNpADZend_Http-2.0.0dev20110916/php/Zend/Http/Header/TransferEncoding.phpsN1;Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Upgrade.phpsNʕҶ=Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/UserAgent.phpsN$88Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Vary.phpsNC7Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Via.phpsNlK;Zend_Http-2.0.0dev20110916/php/Zend/Http/Header/Warning.phpsN*DCZend_Http-2.0.0dev20110916/php/Zend/Http/Header/WWWAuthenticate.phpsN4Zend_Http-2.0.0dev20110916/php/Zend/Http/Headers.php\@sN\@mZJCZend_Http-2.0.0dev20110916/php/Zend/Http/PhpEnvironment/Request.php6sN6B DZend_Http-2.0.0dev20110916/php/Zend/Http/PhpEnvironment/Response.phpsN4Zend_Http-2.0.0dev20110916/php/Zend/Http/Request.php4sN4~<Zend_Http-2.0.0dev20110916/php/Zend/Http/Response/Stream.phpUsNUe :5Zend_Http-2.0.0dev20110916/php/Zend/Http/Response.php7sN7u%Zend_Http-2.0.0dev20110916/php/PEAR2/sN1Zend_Http-2.0.0dev20110916/php/PEAR2/MultiErrors/sN>Zend_Http-2.0.0dev20110916/php/PEAR2/MultiErrors/Exception.phpNsNN7  Zend_Http zfcampus.org/packages Package Zend_Http summary. Package detailed description here (found in README) Your Name handle handle@php.net yes 2011-09-16 2.0.0dev20110916 2.0.0dev20110916 devel devel New BSD License Package Zend_Http release notes for version 0.1.0. Package Zend_Http API release notes for version 0.1.0. 5.2.0 2.0.0a1 Zend_Uri zfcampus.org/packages 2.0.0dev20110916 Zend_Stdlib zfcampus.org/packages 2.0.0dev20110916 Zend_Http zfcampus.org/packages Package Zend_Http summary. Package detailed description here (found in README) Your Name handle handle@php.net yes 2011-09-16 2.0.0dev20110916 2.0.0dev20110916 devel devel New BSD License Package Zend_Http release notes for version 0.1.0. Package Zend_Http API release notes for version 0.1.0. 5.2.0 1.4.8 invalidOverwritableCurlOptions = array( CURLOPT_HTTPGET, CURLOPT_POST, CURLOPT_PUT, CURLOPT_CUSTOMREQUEST, CURLOPT_HEADER, CURLOPT_RETURNTRANSFER, CURLOPT_HTTPHEADER, CURLOPT_POSTFIELDS, CURLOPT_INFILE, CURLOPT_INFILESIZE, CURLOPT_PORT, CURLOPT_MAXREDIRS, CURLOPT_CONNECTTIMEOUT, CURL_HTTP_VERSION_1_1, CURL_HTTP_VERSION_1_0, ); } /** * Set the configuration array for the adapter * * @throws \Zend\Http\Client\Adapter\Exception * @param \Zend\Config\Config | array $config * @return \Zend\Http\Client\Adapter\Curl */ public function setConfig($config = array()) { if ($config instanceof \Zend\Config\Config) { $config = $config->toArray(); } elseif (!is_array($config)) { throw new AdapterException\InvalidArgumentException( 'Array or Zend\Config\Config object expected, got ' . gettype($config) ); } /** Config Key Normalization */ foreach ($config as $k => $v) { unset($config[$k]); // unset original value $config[str_replace(array('-', '_', ' ', '.'), '', strtolower($k))] = $v; // replace w/ normalized } if(isset($config['proxyuser']) && isset($config['proxypass'])) { $this->setCurlOption(CURLOPT_PROXYUSERPWD, $config['proxyuser'].":".$config['proxypass']); unset($config['proxyuser'], $config['proxypass']); } foreach ($config as $k => $v) { $option = strtolower($k); switch($option) { case 'proxyhost': $this->setCurlOption(CURLOPT_PROXY, $v); break; case 'proxyport': $this->setCurlOption(CURLOPT_PROXYPORT, $v); break; default: $this->config[$option] = $v; break; } } return $this; } /** * Retrieve the array of all configuration options * * @return array */ public function getConfig() { return $this->config; } /** * Direct setter for cURL adapter related options. * * @param string|int $option * @param mixed $value * @return Zend\Http\Adapter\Curl */ public function setCurlOption($option, $value) { if (!isset($this->config['curloptions'])) { $this->config['curloptions'] = array(); } $this->config['curloptions'][$option] = $value; return $this; } /** * Initialize curl * * @param string $host * @param int $port * @param boolean $secure * @return void * @throws \Zend\Http\Client\Adapter\Exception if unable to connect */ public function connect($host, $port = 80, $secure = false) { // If we're already connected, disconnect first if ($this->curl) { $this->close(); } // If we are connected to a different server or port, disconnect first if ($this->curl && is_array($this->connectedTo) && ($this->connectedTo[0] != $host || $this->connectedTo[1] != $port) ) { $this->close(); } // Do the actual connection $this->curl = curl_init(); if ($port != 80) { curl_setopt($this->curl, CURLOPT_PORT, intval($port)); } // Set timeout curl_setopt($this->curl, CURLOPT_CONNECTTIMEOUT, $this->config['timeout']); // Set Max redirects curl_setopt($this->curl, CURLOPT_MAXREDIRS, $this->config['maxredirects']); if (!$this->curl) { $this->close(); throw new AdapterException\RuntimeException('Unable to Connect to ' . $host . ':' . $port); } if ($secure !== false) { // Behave the same like Zend\Http\Adapter\Socket on SSL options. if (isset($this->config['sslcert'])) { curl_setopt($this->curl, CURLOPT_SSLCERT, $this->config['sslcert']); } if (isset($this->config['sslpassphrase'])) { curl_setopt($this->curl, CURLOPT_SSLCERTPASSWD, $this->config['sslpassphrase']); } } // Update connected_to $this->connectedTo = array($host, $port); } /** * Send request to the remote server * * @param string $method * @param \Zend\Uri\Uri $uri * @param float $httpVersion * @param array $headers * @param string $body * @return string $request * @throws \Zend\Http\Client\Adapter\Exception If connection fails, connected to wrong host, no PUT file defined, unsupported method, or unsupported cURL option */ public function write($method, $uri, $httpVersion = 1.1, $headers = array(), $body = '') { // Make sure we're properly connected if (!$this->curl) { throw new AdapterException\RuntimeException("Trying to write but we are not connected"); } if ($this->connectedTo[0] != $uri->getHost() || $this->connectedTo[1] != $uri->getPort()) { throw new AdapterException\RuntimeException("Trying to write but we are connected to the wrong host"); } // set URL curl_setopt($this->curl, CURLOPT_URL, $uri->__toString()); // ensure correct curl call $curlValue = true; switch ($method) { case 'GET' : $curlMethod = CURLOPT_HTTPGET; break; case 'POST' : $curlMethod = CURLOPT_POST; break; case 'PUT' : // There are two different types of PUT request, either a Raw Data string has been set // or CURLOPT_INFILE and CURLOPT_INFILESIZE are used. if(is_resource($body)) { $this->config['curloptions'][CURLOPT_INFILE] = $body; } if (isset($this->config['curloptions'][CURLOPT_INFILE])) { // Now we will probably already have Content-Length set, so that we have to delete it // from $headers at this point: foreach ($headers AS $k => $header) { if (preg_match('/Content-Length:\s*(\d+)/i', $header, $m)) { if(is_resource($body)) { $this->config['curloptions'][CURLOPT_INFILESIZE] = (int)$m[1]; } unset($headers[$k]); } } if (!isset($this->config['curloptions'][CURLOPT_INFILESIZE])) { throw new AdapterException\RuntimeException("Cannot set a file-handle for cURL option CURLOPT_INFILE without also setting its size in CURLOPT_INFILESIZE."); } if(is_resource($body)) { $body = ''; } $curlMethod = CURLOPT_PUT; } else { $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "PUT"; } break; case 'DELETE' : $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "DELETE"; break; case 'OPTIONS' : $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "OPTIONS"; break; case 'TRACE' : $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "TRACE"; break; case 'HEAD' : $curlMethod = CURLOPT_CUSTOMREQUEST; $curlValue = "HEAD"; break; default: // For now, through an exception for unsupported request methods throw new AdapterException\InvalidArgumentException("Method currently not supported"); } if(is_resource($body) && $curlMethod != CURLOPT_PUT) { throw new AdapterException\RuntimeException("Streaming requests are allowed only with PUT"); } // get http version to use $curlHttp = ($httpVersion == 1.1) ? CURL_HTTP_VERSION_1_1 : CURL_HTTP_VERSION_1_0; // mark as HTTP request and set HTTP method curl_setopt($this->curl, $curlHttp, true); curl_setopt($this->curl, $curlMethod, $curlValue); if($this->outputStream) { // headers will be read into the response curl_setopt($this->curl, CURLOPT_HEADER, false); curl_setopt($this->curl, CURLOPT_HEADERFUNCTION, array($this, "readHeader")); // and data will be written into the file curl_setopt($this->curl, CURLOPT_FILE, $this->outputStream); } else { // ensure headers are also returned curl_setopt($this->curl, CURLOPT_HEADER, true); // ensure actual response is returned curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); } // set additional headers $headers['Accept'] = ''; curl_setopt($this->curl, CURLOPT_HTTPHEADER, $headers); /** * Make sure POSTFIELDS is set after $curlMethod is set: * @link http://de2.php.net/manual/en/function.curl-setopt.php#81161 */ if ($method == 'POST') { curl_setopt($this->curl, CURLOPT_POSTFIELDS, $body); } elseif ($curlMethod == CURLOPT_PUT) { // this covers a PUT by file-handle: // Make the setting of this options explicit (rather than setting it through the loop following a bit lower) // to group common functionality together. curl_setopt($this->curl, CURLOPT_INFILE, $this->config['curloptions'][CURLOPT_INFILE]); curl_setopt($this->curl, CURLOPT_INFILESIZE, $this->config['curloptions'][CURLOPT_INFILESIZE]); unset($this->config['curloptions'][CURLOPT_INFILE]); unset($this->config['curloptions'][CURLOPT_INFILESIZE]); } elseif ($method == 'PUT') { // This is a PUT by a setRawData string, not by file-handle curl_setopt($this->curl, CURLOPT_POSTFIELDS, $body); } // set additional curl options if (isset($this->config['curloptions'])) { foreach ((array)$this->config['curloptions'] as $k => $v) { if (!in_array($k, $this->invalidOverwritableCurlOptions)) { if (curl_setopt($this->curl, $k, $v) == false) { throw new AdapterException\RuntimeException(sprintf("Unknown or erroreous cURL option '%s' set", $k)); } } } } // send the request $response = curl_exec($this->curl); // if we used streaming, headers are already there if(!is_resource($this->outputStream)) { $this->response = $response; } $request = curl_getinfo($this->curl, CURLINFO_HEADER_OUT); $request .= $body; if (empty($this->response)) { throw new AdapterException\RuntimeException("Error in cURL request: " . curl_error($this->curl)); } // cURL automatically decodes chunked-messages, this means we have to disallow the Zend\Http\Response to do it again if (stripos($this->response, "Transfer-Encoding: chunked\r\n")) { $this->response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $this->response); } // Eliminate multiple HTTP responses. do { $parts = preg_split('|(?:\r?\n){2}|m', $this->response, 2); $again = false; if (isset($parts[1]) && preg_match("|^HTTP/1\.[01](.*?)\r\n|mi", $parts[1])) { $this->response = $parts[1]; $again = true; } } while ($again); // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string: if (stripos($this->response, "HTTP/1.0 200 Connection established\r\n\r\n") !== false) { $this->response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $this->response); } return $request; } /** * Return read response from server * * @return string */ public function read() { return $this->response; } /** * Close the connection to the server * */ public function close() { if(is_resource($this->curl)) { curl_close($this->curl); } $this->curl = null; $this->connectedTo = array(null, null); } /** * Get cUrl Handle * * @return resource */ public function getHandle() { return $this->curl; } /** * Set output stream for the response * * @param resource $stream * @return \Zend\Http\Client\Adapter\Socket */ public function setOutputStream($stream) { $this->outputStream = $stream; return $this; } /** * Header reader function for CURL * * @param resource $curl * @param string $header * @return int */ public function readHeader($curl, $header) { $this->response .= $header; return strlen($header); } } 'ssl', 'sslcert' => null, 'sslpassphrase' => null, 'sslusecontext' => false, 'proxy_host' => '', 'proxy_port' => 8080, 'proxy_user' => '', 'proxy_pass' => '', 'proxy_auth' => Client::AUTH_BASIC, 'persistent' => false ); /** * Whether HTTPS CONNECT was already negotiated with the proxy or not * * @var boolean */ protected $negotiated = false; /** * Connect to the remote server * * Will try to connect to the proxy server. If no proxy was set, will * fall back to the target server (behave like regular Socket adapter) * * @param string $host * @param int $port * @param boolean $secure */ public function connect($host, $port = 80, $secure = false) { // If no proxy is set, fall back to Socket adapter if (! $this->config['proxy_host']) { return parent::connect($host, $port, $secure); } /* Url might require stream context even if proxy connection doesn't */ if ($secure) { $this->config['sslusecontext'] = true; } // Connect (a non-secure connection) to the proxy server return parent::connect( $this->config['proxy_host'], $this->config['proxy_port'], false ); } /** * Send request to the proxy server * * @param string $method * @param \Zend\Uri\Uri $uri * @param string $http_ver * @param array $headers * @param string $body * @return string Request as string */ public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') { // If no proxy is set, fall back to default Socket adapter if (! $this->config['proxy_host']) return parent::write($method, $uri, $http_ver, $headers, $body); // Make sure we're properly connected if (! $this->socket) { throw new AdapterException\RuntimeException("Trying to write but we are not connected"); } $host = $this->config['proxy_host']; $port = $this->config['proxy_port']; if ($this->connected_to[0] != "tcp://$host" || $this->connected_to[1] != $port) { throw new AdapterException\RuntimeException("Trying to write but we are connected to the wrong proxy server"); } // Add Proxy-Authorization header if ($this->config['proxy_user'] && ! isset($headers['proxy-authorization'])) { $headers['proxy-authorization'] = Client::encodeAuthHeader( $this->config['proxy_user'], $this->config['proxy_pass'], $this->config['proxy_auth'] ); } // if we are proxying HTTPS, preform CONNECT handshake with the proxy if ($uri->getScheme() == 'https' && (! $this->negotiated)) { $this->connectHandshake($uri->getHost(), $uri->getPort(), $http_ver, $headers); $this->negotiated = true; } // Save request method for later $this->method = $method; // Build request headers if ($this->negotiated) { $path = $uri->getPath(); if ($uri->getQuery()) { $path .= '?' . $uri->getQuery(); } $request = "$method $path HTTP/$http_ver\r\n"; } else { $request = "$method $uri HTTP/$http_ver\r\n"; } // Add all headers to the request string foreach ($headers as $k => $v) { if (is_string($k)) $v = "$k: $v"; $request .= "$v\r\n"; } if(is_resource($body)) { $request .= "\r\n"; } else { // Add the request body $request .= "\r\n" . $body; } // Send the request if (! @fwrite($this->socket, $request)) { throw new AdapterException\RuntimeException("Error writing request to proxy server"); } if (is_resource($body)) { if(stream_copy_to_stream($body, $this->socket) == 0) { throw new AdapterException\RuntimeException('Error writing request to server'); } } return $request; } /** * Preform handshaking with HTTPS proxy using CONNECT method * * @param string $host * @param integer $port * @param string $http_ver * @param array $headers */ protected function connectHandshake($host, $port = 443, $http_ver = '1.1', array &$headers = array()) { $request = "CONNECT $host:$port HTTP/$http_ver\r\n" . "Host: " . $this->config['proxy_host'] . "\r\n"; // Add the user-agent header if (isset($this->config['useragent'])) { $request .= "User-agent: " . $this->config['useragent'] . "\r\n"; } // If the proxy-authorization header is set, send it to proxy but remove // it from headers sent to target host if (isset($headers['proxy-authorization'])) { $request .= "Proxy-authorization: " . $headers['proxy-authorization'] . "\r\n"; unset($headers['proxy-authorization']); } $request .= "\r\n"; // Send the request if (! @fwrite($this->socket, $request)) { throw new AdapterException\RuntimeException("Error writing request to proxy server"); } // Read response headers only $response = ''; $gotStatus = false; while ($line = @fgets($this->socket)) { $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false); if ($gotStatus) { $response .= $line; if (!rtrim($line)) break; } } // Check that the response from the proxy is 200 if (\Zend\Http\Response::extractCode($response) != 200) { throw new AdapterException\RuntimeException("Unable to connect to HTTPS proxy. Server response: " . $response); } // If all is good, switch socket to secure mode. We have to fall back // through the different modes $modes = array( STREAM_CRYPTO_METHOD_TLS_CLIENT, STREAM_CRYPTO_METHOD_SSLv3_CLIENT, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, STREAM_CRYPTO_METHOD_SSLv2_CLIENT ); $success = false; foreach($modes as $mode) { $success = stream_socket_enable_crypto($this->socket, true, $mode); if ($success) break; } if (! $success) { throw new AdapterException\RuntimeException("Unable to connect to" . " HTTPS server through proxy: could not negotiate secure connection."); } } /** * Close the connection to the server * */ public function close() { parent::close(); $this->negotiated = false; } /** * Destructor: make sure the socket is disconnected * */ public function __destruct() { if ($this->socket) $this->close(); } } false, 'ssltransport' => 'ssl', 'sslcert' => null, 'sslpassphrase' => null, 'sslusecontext' => false ); /** * Request method - will be set by write() and might be used by read() * * @var string */ protected $method = null; /** * Stream context * * @var resource */ protected $_context = null; /** * Adapter constructor, currently empty. Config is set using setConfig() * */ public function __construct() { } /** * Set the configuration array for the adapter * * @param \Zend\Config\Config | array $config */ public function setConfig($config = array()) { if ($config instanceof \Zend\Config\Config) { $config = $config->toArray(); } elseif (! is_array($config)) { throw new AdapterException\InvalidArgumentException( 'Array or Zend_Config object expected, got ' . gettype($config) ); } foreach ($config as $k => $v) { $this->config[strtolower($k)] = $v; } } /** * Retrieve the array of all configuration options * * @return array */ public function getConfig() { return $this->config; } /** * Set the stream context for the TCP connection to the server * * Can accept either a pre-existing stream context resource, or an array * of stream options, similar to the options array passed to the * stream_context_create() PHP function. In such case a new stream context * will be created using the passed options. * * @since Zend Framework 1.9 * * @param mixed $context Stream context or array of context options * @return \Zend\Http\Client\Adapter\Socket */ public function setStreamContext($context) { if (is_resource($context) && get_resource_type($context) == 'stream-context') { $this->_context = $context; } elseif (is_array($context)) { $this->_context = stream_context_create($context); } else { // Invalid parameter throw new AdapterException\InvalidArgumentException( "Expecting either a stream context resource or array, got " . gettype($context) ); } return $this; } /** * Get the stream context for the TCP connection to the server. * * If no stream context is set, will create a default one. * * @return resource */ public function getStreamContext() { if (! $this->_context) { $this->_context = stream_context_create(); } return $this->_context; } /** * Connect to the remote server * * @param string $host * @param int $port * @param boolean $secure */ public function connect($host, $port = 80, $secure = false) { // If the URI should be accessed via SSL, prepend the Hostname with ssl:// $host = ($secure ? $this->config['ssltransport'] : 'tcp') . '://' . $host; // If we are connected to the wrong host, disconnect first if (($this->connected_to[0] != $host || $this->connected_to[1] != $port)) { if (is_resource($this->socket)) $this->close(); } // Now, if we are not connected, connect if (! is_resource($this->socket) || ! $this->config['keepalive']) { $context = $this->getStreamContext(); if ($secure || $this->config['sslusecontext']) { if ($this->config['sslcert'] !== null) { if (! stream_context_set_option($context, 'ssl', 'local_cert', $this->config['sslcert'])) { throw new AdapterException\RuntimeException('Unable to set sslcert option'); } } if ($this->config['sslpassphrase'] !== null) { if (! stream_context_set_option($context, 'ssl', 'passphrase', $this->config['sslpassphrase'])) { throw new AdapterException\RuntimeException('Unable to set sslpassphrase option'); } } } $flags = STREAM_CLIENT_CONNECT; if ($this->config['persistent']) $flags |= STREAM_CLIENT_PERSISTENT; $this->socket = @stream_socket_client($host . ':' . $port, $errno, $errstr, (int) $this->config['timeout'], $flags, $context); if (! $this->socket) { $this->close(); throw new AdapterException\RuntimeException( 'Unable to Connect to ' . $host . ':' . $port . '. Error #' . $errno . ': ' . $errstr); } // Set the stream timeout if (! stream_set_timeout($this->socket, (int) $this->config['timeout'])) { throw new AdapterException\RuntimeException('Unable to set the connection timeout'); } // Update connected_to $this->connected_to = array($host, $port); } } /** * Send request to the remote server * * @param string $method * @param \Zend\Uri\Uri $uri * @param string $http_ver * @param array $headers * @param string $body * @return string Request as string */ public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') { // Make sure we're properly connected if (! $this->socket) { throw new AdapterException\RuntimeException('Trying to write but we are not connected'); } $host = $uri->getHost(); $host = (strtolower($uri->getScheme()) == 'https' ? $this->config['ssltransport'] : 'tcp') . '://' . $host; if ($this->connected_to[0] != $host || $this->connected_to[1] != $uri->getPort()) { throw new AdapterException\RuntimeException('Trying to write but we are connected to the wrong host'); } // Save request method for later $this->method = $method; // Build request headers $path = $uri->getPath(); if ($uri->getQuery()) $path .= '?' . $uri->getQuery(); $request = "{$method} {$path} HTTP/{$http_ver}\r\n"; foreach ($headers as $k => $v) { if (is_string($k)) $v = ucfirst($k) . ": $v"; $request .= "$v\r\n"; } if(is_resource($body)) { $request .= "\r\n"; } else { // Add the request body $request .= "\r\n" . $body; } // Send the request if (! @fwrite($this->socket, $request)) { throw new AdapterException\RuntimeException('Error writing request to server'); } if(is_resource($body)) { if(stream_copy_to_stream($body, $this->socket) == 0) { throw new AdapterException\RuntimeException('Error writing request to server'); } } return $request; } /** * Read response from server * * @return string */ public function read() { // First, read headers only $response = ''; $gotStatus = false; $stream = !empty($this->config['stream']); while (($line = @fgets($this->socket)) !== false) { $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false); if ($gotStatus) { $response .= $line; if (rtrim($line) === '') break; } } $this->_checkSocketReadTimeout(); $responseObj= Response::fromString($response); $statusCode = $responseObj->getStatusCode(); // Handle 100 and 101 responses internally by restarting the read again if ($statusCode == 100 || $statusCode == 101) return $this->read(); // Check headers to see what kind of connection / transfer encoding we have $headers = $responseObj->headers()->toArray(); /** * Responses to HEAD requests and 204 or 304 responses are not expected * to have a body - stop reading here */ if ($statusCode == 304 || $statusCode == 204 || $this->method == \Zend\Http\Request::METHOD_HEAD) { // Close the connection if requested to do so by the server if (isset($headers['connection']) && $headers['connection'] == 'close') { $this->close(); } return $response; } // If we got a 'transfer-encoding: chunked' header if (isset($headers['transfer-encoding'])) { if (strtolower($headers['transfer-encoding']) == 'chunked') { do { $line = @fgets($this->socket); $this->_checkSocketReadTimeout(); $chunk = $line; // Figure out the next chunk size $chunksize = trim($line); if (! ctype_xdigit($chunksize)) { $this->close(); throw new AdapterException\RuntimeException('Invalid chunk size "' . $chunksize . '" unable to read chunked body'); } // Convert the hexadecimal value to plain integer $chunksize = hexdec($chunksize); // Read next chunk $read_to = ftell($this->socket) + $chunksize; do { $current_pos = ftell($this->socket); if ($current_pos >= $read_to) break; if($this->out_stream) { if(stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0) { $this->_checkSocketReadTimeout(); break; } } else { $line = @fread($this->socket, $read_to - $current_pos); if ($line === false || strlen($line) === 0) { $this->_checkSocketReadTimeout(); break; } $chunk .= $line; } } while (! feof($this->socket)); $chunk .= @fgets($this->socket); $this->_checkSocketReadTimeout(); if(!$this->out_stream) { $response .= $chunk; } } while ($chunksize > 0); } else { $this->close(); throw new AdapterException\RuntimeException('Cannot handle "' . $headers['transfer-encoding'] . '" transfer encoding'); } // We automatically decode chunked-messages when writing to a stream // this means we have to disallow the Zend_Http_Response to do it again if ($this->out_stream) { $response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $response); } // Else, if we got the content-length header, read this number of bytes } elseif (isset($headers['content-length'])) { // If we got more than one Content-Length header (see ZF-9404) use // the last value sent if (is_array($headers['content-length'])) { $contentLength = $headers['content-length'][count($headers['content-length']) - 1]; } else { $contentLength = $headers['content-length']; } $current_pos = ftell($this->socket); $chunk = ''; for ($read_to = $current_pos + $contentLength; $read_to > $current_pos; $current_pos = ftell($this->socket)) { if($this->out_stream) { if(@stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0) { $this->_checkSocketReadTimeout(); break; } } else { $chunk = @fread($this->socket, $read_to - $current_pos); if ($chunk === false || strlen($chunk) === 0) { $this->_checkSocketReadTimeout(); break; } $response .= $chunk; } // Break if the connection ended prematurely if (feof($this->socket)) break; } // Fallback: just read the response until EOF } else { do { if($this->out_stream) { if(@stream_copy_to_stream($this->socket, $this->out_stream) == 0) { $this->_checkSocketReadTimeout(); break; } } else { $buff = @fread($this->socket, 8192); if ($buff === false || strlen($buff) === 0) { $this->_checkSocketReadTimeout(); break; } else { $response .= $buff; } } } while (feof($this->socket) === false); $this->close(); } // Close the connection if requested to do so by the server if (isset($headers['connection']) && $headers['connection'] == 'close') { $this->close(); } return $response; } /** * Close the connection to the server * */ public function close() { if (is_resource($this->socket)) @fclose($this->socket); $this->socket = null; $this->connected_to = array(null, null); } /** * Check if the socket has timed out - if so close connection and throw * an exception * * @throws \Zend\Http\Client\Adapter\Exception with READ_TIMEOUT code */ protected function _checkSocketReadTimeout() { if ($this->socket) { $info = stream_get_meta_data($this->socket); $timedout = $info['timed_out']; if ($timedout) { $this->close(); throw new AdapterException\TimeoutException( "Read timed out after {$this->config['timeout']} seconds", AdapterException\TimeoutException::READ_TIMEOUT ); } } } /** * Set output stream for the response * * @param resource $stream * @return \Zend\Http\Client\Adapter\Socket */ public function setOutputStream($stream) { $this->out_stream = $stream; return $this; } /** * Destructor: make sure the socket is disconnected * * If we are in persistent TCP mode, will not close the connection * */ public function __destruct() { if (! $this->config['persistent']) { if ($this->socket) $this->close(); } } } _nextRequestWillFail = (bool) $flag; return $this; } /** * Set the configuration array for the adapter * * @param \Zend\Config\Config | array $config */ public function setConfig($config = array()) { if ($config instanceof \Zend\Config\Config) { $config = $config->toArray(); } elseif (! is_array($config)) { throw new AdapterException\InvalidArgumentException( 'Array or Zend\Config\Config object expected, got ' . gettype($config) ); } foreach ($config as $k => $v) { $this->config[strtolower($k)] = $v; } } /** * Connect to the remote server * * @param string $host * @param int $port * @param boolean $secure * @param int $timeout * @throws \Zend\Http\Client\Adapter\Exception */ public function connect($host, $port = 80, $secure = false) { if ($this->_nextRequestWillFail) { $this->_nextRequestWillFail = false; throw new AdapterException\RuntimeException('Request failed'); } } /** * Send request to the remote server * * @param string $method * @param \Zend\Uri\Uri $uri * @param string $http_ver * @param array $headers * @param string $body * @return string Request as string */ public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') { $host = $uri->getHost(); $host = (strtolower($uri->getScheme()) == 'https' ? 'sslv2://' . $host : $host); // Build request headers $path = $uri->getPath(); if (empty($path)) { $path = '/'; } if ($uri->getQuery()) $path .= '?' . $uri->getQuery(); $request = "{$method} {$path} HTTP/{$http_ver}\r\n"; foreach ($headers as $k => $v) { if (is_string($k)) $v = ucfirst($k) . ": $v"; $request .= "$v\r\n"; } // Add the request body $request .= "\r\n" . $body; // Do nothing - just return the request as string return $request; } /** * Return the response set in $this->setResponse() * * @return string */ public function read() { if ($this->responseIndex >= count($this->responses)) { $this->responseIndex = 0; } return $this->responses[$this->responseIndex++]; } /** * Close the connection (dummy) * */ public function close() { } /** * Set the HTTP response(s) to be returned by this adapter * * @param \Zend\Http\Response|array|string $response */ public function setResponse($response) { if ($response instanceof Response) { $response = $response->asString("\r\n"); } $this->responses = (array)$response; $this->responseIndex = 0; } /** * Add another response to the response buffer. * * @param string \Zend\Http\Response|$response */ public function addResponse($response) { if ($response instanceof Response) { $response = $response->toString(); } $this->responses[] = $response; } /** * Sets the position of the response buffer. Selects which * response will be returned on the next call to read(). * * @param integer $index */ public function setResponseIndex($index) { if ($index < 0 || $index >= count($this->responses)) { throw new AdapterException\OutOfRangeException( 'Index out of range of response buffer size'); } $this->responseIndex = $index; } } getDomain(); $path = $cookie->getPath(); if (!isset($this->cookies[$domain])) { $this->cookies[$domain] = array(); } if (!isset($this->cookies[$domain][$path])) { $this->cookies[$domain][$path] = array(); } $this->cookies[$domain][$path][$cookie->getName()] = $cookie; $this->_rawCookies[] = $cookie; } else { throw new Exception\InvalidArgumentException('Supplient argument is not a valid cookie string or object'); } } /** * Parse an HTTP response, adding all the cookies set in that response * * @param Response $response * @param Uri\Uri|string $ref_uri Requested URI */ public function addCookiesFromResponse($response, $ref_uri) { if (!$response instanceof Response) { throw new Exception\InvalidArgumentException('$response is expected to be a Response object'); } $cookie_hdrs = $response->headers()->get('Set-Cookie'); if (is_array($cookie_hdrs)) { foreach ($cookie_hdrs as $cookie) { $this->addCookie($cookie, $ref_uri); } } elseif (is_string($cookie_hdrs)) { $this->addCookie($cookie_hdrs, $ref_uri); } } /** * Get all cookies in the cookie jar as an array * * @param int $ret_as Whether to return cookies as objects of \Zend\Http\Header\Cookie or as strings * @return array|string */ public function getAllCookies($ret_as = self::COOKIE_OBJECT) { $cookies = $this->_flattenCookiesArray($this->cookies, $ret_as); return $cookies; } /** * Return an array of all cookies matching a specific request according to the request URI, * whether session cookies should be sent or not, and the time to consider as "now" when * checking cookie expiry time. * * @param string|Uri\Uri $uri URI to check against (secure, domain, path) * @param boolean $matchSessionCookies Whether to send session cookies * @param int $ret_as Whether to return cookies as objects of \Zend\Http\Header\Cookie or as strings * @param int $now Override the current time when checking for expiry time * @return array|string */ public function getMatchingCookies($uri, $matchSessionCookies = true, $ret_as = self::COOKIE_OBJECT, $now = null) { if (is_string($uri)) { $uri = Uri\UriFactory::factory($uri, 'http'); } if (!$uri instanceof Uri\Uri) { throw new Exception\InvalidArgumentException("Invalid URI string or object passed"); } $host = $uri->getHost(); if (empty($host)) { throw new Exception\InvalidArgumentException('Invalid URI specified; does not contain a host'); } // First, reduce the array of cookies to only those matching domain and path $cookies = $this->_matchDomain($host); $cookies = $this->_matchPath($cookies, $uri->getPath()); $cookies = $this->_flattenCookiesArray($cookies, self::COOKIE_OBJECT); // Next, run Cookie->match on all cookies to check secure, time and session mathcing $ret = array(); foreach ($cookies as $cookie) if ($cookie->match($uri, $matchSessionCookies, $now)) $ret[] = $cookie; // Now, use self::_flattenCookiesArray again - only to convert to the return format ;) $ret = $this->_flattenCookiesArray($ret, $ret_as); return $ret; } /** * Get a specific cookie according to a URI and name * * @param Uri\Uri|string $uri The uri (domain and path) to match * @param string $cookie_name The cookie's name * @param int $ret_as Whether to return cookies as objects of \Zend\Http\Header\Cookie or as strings * @return Cookie|string */ public function getCookie($uri, $cookie_name, $ret_as = self::COOKIE_OBJECT) { if (is_string($uri)) { $uri = Uri\UriFactory::factory($uri, 'http'); } if (!$uri instanceof Uri\Uri) { throw new Exception\InvalidArgumentException('Invalid URI specified'); } $host = $uri->getHost(); if (empty($host)) { throw new Exception\InvalidArgumentException('Invalid URI specified; host missing'); } // Get correct cookie path $path = $uri->getPath(); $path = substr($path, 0, strrpos($path, '/')); if (! $path) $path = '/'; if (isset($this->cookies[$uri->getHost()][$path][$cookie_name])) { $cookie = $this->cookies[$uri->getHost()][$path][$cookie_name]; switch ($ret_as) { case self::COOKIE_OBJECT: return $cookie; break; case self::COOKIE_STRING_ARRAY: case self::COOKIE_STRING_CONCAT: return $cookie->__toString(); break; default: throw new Exception\InvalidArgumentException("Invalid value passed for \$ret_as: {$ret_as}"); break; } } else { return false; } } /** * Helper function to recursivly flatten an array. Shoud be used when exporting the * cookies array (or parts of it) * * @param \Zend\Http\Header\Cookie|array $ptr * @param int $ret_as What value to return * @return array|string */ protected function _flattenCookiesArray($ptr, $ret_as = self::COOKIE_OBJECT) { if (is_array($ptr)) { $ret = ($ret_as == self::COOKIE_STRING_CONCAT ? '' : array()); foreach ($ptr as $item) { if ($ret_as == self::COOKIE_STRING_CONCAT) { $ret .= $this->_flattenCookiesArray($item, $ret_as); } else { $ret = array_merge($ret, $this->_flattenCookiesArray($item, $ret_as)); } } return $ret; } elseif ($ptr instanceof Cookie) { switch ($ret_as) { case self::COOKIE_STRING_ARRAY: return array($ptr->__toString()); break; case self::COOKIE_STRING_CONCAT: return $ptr->__toString(); break; case self::COOKIE_OBJECT: default: return array($ptr); break; } } return null; } /** * Return a subset of the cookies array matching a specific domain * * @param string $domain * @return array */ protected function _matchDomain($domain) { $ret = array(); foreach (array_keys($this->cookies) as $cdom) { if (Cookie::matchCookieDomain($cdom, $domain)) { $ret[$cdom] = $this->cookies[$cdom]; } } return $ret; } /** * Return a subset of a domain-matching cookies that also match a specified path * * @param array $dom_array * @param string $path * @return array */ protected function _matchPath($domains, $path) { $ret = array(); foreach ($domains as $dom => $paths_array) { foreach (array_keys($paths_array) as $cpath) { if (Cookie::matchCookiePath($cpath, $path)) { if (! isset($ret[$dom])) { $ret[$dom] = array(); } $ret[$dom][$cpath] = $paths_array[$cpath]; } } } return $ret; } /** * Create a new Cookies object and automatically load into it all the * cookies set in an Http_Response object. If $uri is set, it will be * considered as the requested URI for setting default domain and path * of the cookie. * * @param Response $response HTTP Response object * @param Uri\Uri|string $uri The requested URI * @return Cookies * @todo Add the $uri functionality. */ public static function fromResponse(Response $response, $ref_uri) { $jar = new self(); $jar->addCookiesFromResponse($response, $ref_uri); return $jar; } /** * Required by Countable interface * * @return int */ public function count() { return count($this->_rawCookies); } /** * Required by IteratorAggregate interface * * @return ArrayIterator */ public function getIterator() { return new \ArrayIterator($this->_rawCookies); } /** * Tells if the array of cookies is empty * * @return bool */ public function isEmpty() { return count($this) == 0; } /** * Empties the cookieJar of any cookie * * @return Cookies */ public function reset() { $this->cookies = $this->_rawCookies = array(); return $this; } /** * (PHP 5 >= 5.1.0)
* Whether a offset exists * @link http://php.net/manual/en/arrayaccess.offsetexists.php * @param mixed $offset

* An offset to check for. *

* @return boolean Returns true on success or false on failure. *

*

* The return value will be casted to boolean if non-boolean was returned. */ public function offsetExists($offset) { // TODO: Implement offsetExists() method. } /** * (PHP 5 >= 5.1.0)
* Offset to retrieve * @link http://php.net/manual/en/arrayaccess.offsetget.php * @param mixed $offset

* The offset to retrieve. *

* @return mixed Can return all value types. */ public function offsetGet($offset) { // TODO: Implement offsetGet() method. } /** * (PHP 5 >= 5.1.0)
* Offset to set * @link http://php.net/manual/en/arrayaccess.offsetset.php * @param mixed $offset

* The offset to assign the value to. *

* @param mixed $value

* The value to set. *

* @return void */ public function offsetSet($offset, $value) { // TODO: Implement offsetSet() method. } /** * (PHP 5 >= 5.1.0)
* Offset to unset * @link http://php.net/manual/en/arrayaccess.offsetunset.php * @param mixed $offset

* The offset to unset. *

* @return void */ public function offsetUnset($offset) { // TODO: Implement offsetUnset() method. } /** * (PHP 5 >= 5.1.0)
* String representation of object * @link http://php.net/manual/en/serializable.serialize.php * @return string the string representation of the object or &null; */ public function serialize() { // TODO: Implement serialize() method. } /** * (PHP 5 >= 5.1.0)
* Constructs the object * @link http://php.net/manual/en/serializable.unserialize.php * @param string $serialized

* The string representation of the object. *

* @return mixed the original value unserialized. */ public function unserialize($serialized) { // TODO: Implement unserialize() method. } public function fromArray(array $values) { // TODO: Implement fromArray() method. } public function fromString($string) { // TODO: Implement fromString() method. } public function toArray() { // TODO: Implement toArray() method. } public function toString() { // TODO: Implement toString() method. } public function get($name, $default = null) { // TODO: Implement get() method. } public function set($name, $value) { // TODO: Implement set() method. } } 5, 'strictredirects' => false, 'useragent' => 'Zend\Http\Client', 'timeout' => 10, 'adapter' => 'Zend\Http\Client\Adapter\Socket', 'httpversion' => Request::VERSION_11, 'storeresponse' => true, 'keepalive' => false, 'outputstream' => false, 'encodecookies' => true, 'rfc3986strict' => false ); /** * Fileinfo magic database resource * * This variable is populated the first time _detectFileMimeType is called * and is then reused on every call to this method * * @var resource */ static protected $_fileInfoDb = null; /** * Constructor * * @param string $uri * @param array $config */ public function __construct($uri = null, $config = null) { if ($uri !== null) { $this->setUri($uri); } if ($config !== null) { $this->setConfig($config); } } /** * Dispatch * * @param RequestDescription $request * @param ResponseDescription $response * @return ResponseDescription */ public function dispatch(RequestDescription $request, ResponseDescription $response = null) { $response= $this->send($request); return $response; } /** * Set configuration parameters for this HTTP client * * @param Config|array $config * @return Client * @throws Client\Exception */ public function setConfig($config = array()) { if ($config instanceof Config) { $config = $config->toArray(); } elseif (!is_array($config)) { throw new Exception\InvalidArgumentException('Config parameter is not valid'); } /** Config Key Normalization */ foreach ($config as $k => $v) { $this->config[str_replace(array('-', '_', ' ', '.'), '', strtolower($k))] = $v; // replace w/ normalized } // Pass configuration options to the adapter if it exists if ($this->adapter instanceof Client\Adapter) { $this->adapter->setConfig($config); } return $this; } /** * Load the connection adapter * * While this method is not called more than one for a client, it is * seperated from ->request() to preserve logic and readability * * @param Client\Adapter|string $adapter * @return null * @throws \Zend\Http\Client\Exception */ public function setAdapter($adapter) { if (is_string($adapter)) { if (!class_exists($adapter)) { throw new Client\Exception\InvalidArgumentException('Unable to locate adapter class "' . $adapter . '"'); } $adapter = new $adapter; } if (! $adapter instanceof Client\Adapter) { throw new Client\Exception\InvalidArgumentException('Passed adapter is not a HTTP connection adapter'); } $this->adapter = $adapter; $config = $this->config; unset($config['adapter']); $this->adapter->setConfig($config); } /** * Load the connection adapter * * @return \Zend\Http\Client\Adapter $adapter */ public function getAdapter() { return $this->adapter; } /** * Get Request * * @return Request */ public function getRequest() { if (empty($this->request)) { $this->request = new Request(); } return $this->request; } /** * Get Response * * @return Response */ public function getResponse() { if (empty($this->response)) { $this->response = new Response(); } return $this->response; } /** * Set request * * @param Zend\Http\Request $request */ public function setRequest(Request $request) { $this->request = $request; } /** * Set response * * @param Zend\Http\Response $response */ public function setResponse(Response $response) { $this->response = $response; } /** * Get the last request (as a string) * * @return string */ public function getLastRequest() { return $this->lastRequest; } /** * Get the last response (as a string) * * @return string */ public function getLastResponse() { return $this->lastResponse; } /** * Get the redirections count * * @return integer */ public function getRedirectionsCount() { return $this->redirectCounter; } /** * Set Uri (to the request) * * @param string|Zend\Uri\Http $uri */ public function setUri($uri) { if (!empty($uri)) { $this->getRequest()->setUri($uri); // Set auth if username and password has been specified in the uri if ($this->getUri()->getUser() && $this->getUri()->getPassword()) { $this->setAuth($this->getUri()->getUser(), $this->getUri()->getPassword()); } // We have no ports, set the defaults if (! $this->getUri()->getPort()) { $this->getUri()->setPort(($this->getUri()->getScheme() == 'https' ? 443 : 80)); } } } /** * Get uri (from the request) * * @return Zend\Uri\Http */ public function getUri() { return $this->getRequest()->uri(); } /** * Set the HTTP method (to the request) * * @param string $method * @return Client */ public function setMethod($method) { $this->getRequest()->setMethod($method); if (($method == Request::METHOD_POST || $method == Request::METHOD_PUT || $method == Request::METHOD_DELETE) && empty($this->encType)) { $this->setEncType(self::ENC_URLENCODED); } return $this; } /** * Get the HTTP method * * @return string */ public function getMethod() { return $this->getRequest()->getMethod(); } /** * Set the encoding type and the boundary (if any) * * @param string $encType * @param string $boundary */ public function setEncType($encType, $boundary = null) { if (!empty($encType)) { if (!empty($boundary)) { $this->encType = $encType . "; boundary={$boundary}"; } else { $this->encType = $encType; } } return $this; } /** * Get the encoding type * * @return type */ public function getEncType() { return $this->encType; } /** * Set raw body (for advanced use cases) * * @param string $body * @return Client */ public function setRawBody($body) { $this->getRequest()->setRawBody($body); return $this; } /** * Set the POST parameters * * @param array $post * @return Client */ public function setParameterPost(array $post) { $this->getRequest()->post()->fromArray($post); return $this; } /** * Set the GET parameters * * @param array $query * @return Client */ public function setParameterGet(array $query) { $this->getRequest()->query()->fromArray($query); return $this; } /** * Return the current cookies * * @return array */ public function getCookies() { return $this->cookies; } /** * Get the cookie Id (name+domain+path) * * @param SetCookie|Cookie $cookie * @return string|boolean */ protected function getCookieId($cookie) { if (($cookie instanceof SetCookie) || ($cookie instanceof Cookie)) { return $cookie->getName() . $cookie->getDomain() . $cookie->getPath(); } return false; } /** * Add a cookie * * @param ArrayIterator|SetCookie|string $cookie * @param string $value * @param string $domain * @param string $expire * @param string $path * @param boolean $secure * @param boolean $httponly * @return Client */ public function addCookie($cookie, $value=null, $domain=null, $expire=null, $path=null, $secure=false, $httponly=true) { if ($cookie instanceof \ArrayIterator) { foreach ($cookie as $setCookie) { if ($setCookie instanceof SetCookie) { $this->cookies[$this->getCookieId($setCookie)] = $setCookie; } else { throw new Exception\InvalidArgumentException('The cookie parameter is not a valid Set-Cookie type'); } } } elseif ($cookie instanceof SetCookie) { $this->cookies[$this->getCookieId($cookie)] = $cookie; } elseif (is_string($cookie) && !empty($value)) { if (!empty($value) && $this->config['encodecookies']) { $value = urlencode($value); } $setCookie = new SetCookie($cookie, $value, $domain, $expire, $path, $secure, $httponly); $this->cookies[$this->getCookieId($setCookie)] = $setCookie; } else { throw new Exception\InvalidArgumentException('Invalid parameter type passed as Cookie'); } return $this; } /** * Set an array of cookies * * @param array $cookies * @return Client */ public function setCookies($cookies) { if (is_array($cookies)) { $this->clearCookies(); foreach ($cookies as $name => $value) { $this->addCookie($name,$value); } } else { throw new Exception\InvalidArgumentException('Invalid cookies passed as parameter, it must be an array'); } return $this; } /** * Clear all the cookies */ public function clearCookies() { $this->cookies= array(); } /** * Set the headers (for the request) * * @param Headers|array $headers * @return Client */ public function setHeaders($headers) { if (is_array($headers)) { $newHeaders= new Headers(); $newHeaders->addHeaders($headers); $this->getRequest()->setHeaders($newHeaders); } elseif ($headers instanceof Headers) { $this->getRequest()->setHeaders($headers); } else { throw new Exception\InvalidArgumentException('Invalid parameter headers passed'); } return $this; } /** * Check if exists the header type specified * * @param string $name * @return boolean */ public function hasHeader($name) { $headers = $this->getRequest()->headers(); if ($headers instanceof Headers) { return $headers->has($name); } return false; } /** * Get the header value of the request * * @param string $name * @return string|boolean */ public function getHeader($name) { $headers = $this->getRequest()->headers(); if ($headers instanceof Headers) { if ($headers->get($name)) { return $headers->get($name)->getFieldValue(); } } return false; } /** * Set streaming for received data * * @param string|boolean $streamfile Stream file, true for temp file, false/null for no streaming * @return \Zend\Http\Client */ public function setStream($streamfile = true) { $this->setConfig(array("outputstream" => $streamfile)); return $this; } /** * Get status of streaming for received data * @return boolean|string */ public function getStream() { return $this->config["output_stream"]; } /** * Create temporary stream * * @return resource */ protected function openTempStream() { $this->streamName = $this->config['outputstream']; if(!is_string($this->streamName)) { // If name is not given, create temp name $this->streamName = tempnam( isset($this->config['stream_tmp_dir']) ? $this->config['stream_tmp_dir'] : sys_get_temp_dir(), 'Zend\Http\Client' ); } if (false === ($fp = @fopen($this->streamName, "w+b"))) { if ($this->adapter instanceof Client\Adapter) { $this->adapter->close(); } throw new Exception\RuntimeException("Could not open temp file {$this->streamName}"); } return $fp; } /** * Create a HTTP authentication "Authorization:" header according to the * specified user, password and authentication method. * * @param string $user * @param string $password * @param string $type * @return Client */ public function setAuth($user, $password, $type = self::AUTH_BASIC) { if (!defined('self::AUTH_' . strtoupper($type))) { throw new Exception\InvalidArgumentException("Invalid or not supported authentication type: '$type'"); } if (empty($user) || empty($password)) { throw new Exception\InvalidArgumentException("The username and the password cannot be empty"); } $this->auth = array ( 'user' => $user, 'password' => $password, 'type' => $type ); return $this; } /** * Calculate the response value according to the HTTP authentication type * * @see http://www.faqs.org/rfcs/rfc2617.html * @param string $user * @param string $password * @param string $type * @param array $digest * @return string|boolean */ protected function calcAuthDigest($user, $password, $type = self::AUTH_BASIC, $digest = array(), $entityBody = null) { if (!defined('self::AUTH_' . strtoupper($type))) { throw new Exception\InvalidArgumentException("Invalid or not supported authentication type: '$type'"); } $response = false; switch(strtolower($type)) { case self::AUTH_BASIC : // In basic authentication, the user name cannot contain ":" if (strpos($user, ':') !== false) { throw new Exception\InvalidArgumentException("The user name cannot contain ':' in Basic HTTP authentication"); } $response = base64_encode($user . ':' . $password); break; case self::AUTH_DIGEST : if (empty($digest)) { throw new Exception\InvalidArgumentException("The digest cannot be empty"); } foreach ($digest as $key => $value) { if (!defined('self::DIGEST_' . strtoupper($key))) { throw new Exception\InvalidArgumentException("Invalid or not supported digest authentication parameter: '$key'"); } } $ha1 = md5($user . ':' . $digest['realm'] . ':' . $password); if (empty($digest['qop']) || strtolower($digest['qop'])=='auth') { $ha2 = md5($this->getMethod() . ':' . $this->getUri()->getPath()); } elseif (strtolower($digest['qop'])=='auth-int') { if (empty($entityBody)) { throw new Exception\InvalidArgumentException("I cannot use the auth-int digest authentication without the entity body"); } $ha2 = md5($this->getMethod() . ':' . $this->getUri()->getPath() . ':' . md5($entityBody)); } if (empty($digest['qop'])) { $response = md5 ($ha1 . ':' . $digest['nonce'] . ':' . $ha2); } else { $response = md5 ($ha1 . ':' . $digest['nonce'] . ':' . $digest['nc'] . ':' . $digest['cnonce'] . ':' . $digest['qoc'] . ':' . $ha2); } break; } return $response; } /** * Reset all the HTTP parameters (auth,cookies,request, response, etc) * */ public function resetParameters() { $uri = $this->getUri(); $this->auth = null; $this->streamName = null; $this->cookies = null; $this->encType = null; $this->request = null; $this->response = null; $this->setUri($uri); } /** * Send HTTP request * * @param Request $request * @return Response */ public function send(Request $request = null) { if ($request !== null) { $this->setRequest($request); } $this->redirectCounter = 0; $response = null; // Make sure the adapter is loaded if ($this->adapter == null) { $this->setAdapter($this->config['adapter']); } // Send the first request. If redirected, continue. do { // uri $uri = $this->getUri(); // query $query = $this->getRequest()->query(); if (!empty($query)) { $queryArray = $query->toArray(); if (!empty($queryArray)) { $newUri = $uri->toString(); $queryString = http_build_query($query); if ($this->config['rfc3986strict']) { $queryString = str_replace('+', '%20', $queryString); } if (strpos($newUri,'?') !== false) { $newUri .= '&' . $queryString; } else { $newUri .= '?' . $queryString; } $uri = new \Zend\Uri\Http($newUri); } } // If we have no ports, set the defaults if (!$uri->getPort()) { $uri->setPort(($uri->getScheme() == 'https' ? 443 : 80)); } // method $method = $this->getRequest()->getMethod(); // body $body = $this->prepareBody(); // headers $headers = $this->prepareHeaders($body,$uri); $secure= $uri->getScheme() == 'https' ? true : false; // cookies $cookie = $this->prepareCookies($uri->getHost(), $uri->getPath(), $secure); if ($cookie->getFieldValue()) { $headers['Cookie']= $cookie->getFieldValue(); } // check that adapter supports streaming before using it if(is_resource($body) && !($this->adapter instanceof Client\Adapter\Stream)) { throw new Client\Exception\RuntimeException('Adapter does not support streaming'); } // Open the connection, send the request and read the response $this->adapter->connect($uri->getHost(), $uri->getPort(), $secure); if($this->config['outputstream']) { if($this->adapter instanceof Client\Adapter\Stream) { $stream = $this->openTempStream(); $this->adapter->setOutputStream($stream); } else { throw new Exception\RuntimeException('Adapter does not support streaming'); } } // HTTP connection $this->lastRequest = $this->adapter->write($method, $uri, $this->config['httpversion'], $headers, $body); $response = $this->adapter->read(); if (! $response) { throw new Exception\RuntimeException('Unable to read response, or response is empty'); } if ($this->config['storeresponse']) { $this->lastResponse = $response; } else { $this->lastResponse = null; } if($this->config['outputstream']) { $streamMetaData = stream_get_meta_data($stream); if ($streamMetaData['seekable']) { rewind($stream); } // cleanup the adapter $this->adapter->setOutputStream(null); $response = Response\Stream::fromStream($response, $stream); $response->setStreamName($this->streamName); if(!is_string($this->config['outputstream'])) { // we used temp name, will need to clean up $response->setCleanup(true); } } else { $response = Response::fromString($response); } // Get the cookies from response (if any) $setCookie= $response->cookie(); if (!empty($setCookie)) { $this->addCookie($setCookie); } // If we got redirected, look for the Location header if ($response->isRedirect() && ($response->headers()->has('Location'))) { // Avoid problems with buggy servers that add whitespace at the // end of some headers $location = trim($response->headers()->get('Location')->getFieldValue()); // Check whether we send the exact same request again, or drop the parameters // and send a GET request if ($response->getStatusCode() == 303 || ((! $this->config['strictredirects']) && ($response->getStatusCode() == 302 || $response->getStatusCode() == 301))) { $this->resetParameters(); $this->setMethod(Request::METHOD_GET); } // If we got a well formed absolute URI if (($scheme = substr($location, 0, 6)) && ($scheme == 'http:/' || $scheme == 'https:')) { $this->setUri($location); } else { // Split into path and query and set the query if (strpos($location, '?') !== false) { list($location, $query) = explode('?', $location, 2); } else { $query = ''; } $this->getUri()->setQuery($query); // Else, if we got just an absolute path, set it if(strpos($location, '/') === 0) { $this->getUri()->setPath($location); // Else, assume we have a relative path } else { // Get the current path directory, removing any trailing slashes $path = $this->getUri()->getPath(); $path = rtrim(substr($path, 0, strrpos($path, '/')), "/"); $this->getUri()->setPath($path . '/' . $location); } } ++$this->redirectCounter; } else { // If we didn't get any location, stop redirecting break; } } while ($this->redirectCounter < $this->config['maxredirects']); $this->response = $response; return $response; } /** * Set a file to upload (using a POST request) * * Can be used in two ways: * * 1. $data is null (default): $filename is treated as the name if a local file which * will be read and sent. Will try to guess the content type using mime_content_type(). * 2. $data is set - $filename is sent as the file name, but $data is sent as the file * contents and no file is read from the file system. In this case, you need to * manually set the Content-Type ($ctype) or it will default to * application/octet-stream. * * @param string $filename Name of file to upload, or name to save as * @param string $formname Name of form element to send as * @param string $data Data to send (if null, $filename is read and sent) * @param string $ctype Content type to use (if $data is set and $ctype is * null, will be application/octet-stream) * @return Client * @throws Exception */ public function setFileUpload($filename, $formname, $data = null, $ctype = null) { if ($data === null) { if (($data = @file_get_contents($filename)) === false) { throw new Exception\RuntimeException("Unable to read file '{$filename}' for upload"); } if (! $ctype) { $ctype = $this->detectFileMimeType($filename); } } $this->getRequest()->file()->set($filename, array( 'formname' => $formname, 'filename' => basename($filename), 'ctype' => $ctype, 'data' => $data )); return $this; } /** * Remove a file to upload * * @param string $filename * @return boolean */ public function removeFileUpload($filename) { $file = $this->getRequest()->file()->get($filename); if (!empty($file)) { $this->getRequest()->file()->set($filename,null); return true; } return false; } /** * Prepare Cookies * * @param string $uri * @param string $domain * @param boolean $secure * @return Cookie|boolean */ protected function prepareCookies($domain, $path, $secure) { $validCookies = array(); if (!empty($this->cookies)) { foreach ($this->cookies as $id => $cookie) { if ($cookie->isExpired()) { unset($this->cookies[$id]); continue; } if ($cookie->isValidForRequest($domain, $path, $secure)) { $validCookies[] = $cookie; } } } $cookies = Cookie::fromSetCookieArray($validCookies); return $cookies; } /** * Prepare the request headers * * @return array */ protected function prepareHeaders($body, $uri) { $headers = array(); // Set the host header if ($this->config['httpversion'] == Request::VERSION_11) { $host = $uri->getHost(); // If the port is not default, add it if (!(($uri->getScheme() == 'http' && $uri->getPort() == 80) || ($uri->getScheme() == 'https' && $uri->getPort() == 443))) { $host .= ':' . $uri->getPort(); } $headers['Host'] = $host; } // Set the connection header if (!$this->getRequest()->headers()->has('Connection')) { if (!$this->config['keepalive']) { $headers['Connection'] = 'close'; } } // Set the Accept-encoding header if not set - depending on whether // zlib is available or not. if (! isset($this->headers['accept-encoding'])) { if (function_exists('gzinflate')) { $headers['Accept-encoding'] = 'gzip, deflate'; } else { $headers['Accept-encoding'] = 'identity'; } } // Set the user agent header if (!$this->getRequest()->headers()->has('User-Agent') && isset($this->config['useragent'])) { $headers['User-Agent'] = $this->config['useragent']; } // Set HTTP authentication if needed if (!empty($this->auth)) { switch ($this->auth['type']) { case self::AUTH_BASIC : $auth = $this->calcAuthDigest($this->auth['user'], $this->auth['password'], $this->auth['type']); if ($auth !== false) { $headers['Authorization'] = 'Basic ' . $auth; } break; case self::AUTH_DIGEST : throw new Exception\RuntimeException("The digest authentication is not implemented yet"); } } // Content-type $encType = $this->getEncType(); if (!empty($encType)) { $headers['Content-Type'] = $encType; } if (!empty($body)) { if (is_resource($body)) { $fstat = fstat($body); $headers['Content-Length'] = $fstat['size']; } else { $headers['Content-Length'] = strlen($body); } } // Merge the headers of the request (if any) $requestHeaders = $this->getRequest()->headers()->toArray(); foreach ($requestHeaders as $key => $value) { $headers[$key] = $value; } return $headers; } /** * Prepare the request body (for POST and PUT requests) * * @return string * @throws \Zend\Http\Client\Exception */ protected function prepareBody() { // According to RFC2616, a TRACE request should not have a body. if ($this->getRequest()->isTrace()) { return ''; } // If mbstring overloads substr and strlen functions, we have to // override it's internal encoding if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) { $mbIntEnc = mb_internal_encoding(); mb_internal_encoding('ASCII'); } $rawBody = $this->getRequest()->getRawBody(); if (!empty($rawBody)) { if (isset($mbIntEnc)) { mb_internal_encoding($mbIntEnc); } return $rawBody; } $body = ''; $totalFiles = 0; if (!$this->getRequest()->headers()->has('Content-Type')) { $totalFiles = count($this->getRequest()->file()->toArray()); // If we have files to upload, force encType to multipart/form-data if ($totalFiles > 0) { $this->setEncType(self::ENC_FORMDATA); } } else { $this->setEncType($this->getHeader('Content-Type')); } // If we have POST parameters or files, encode and add them to the body if (count($this->getRequest()->post()->toArray()) > 0 || $totalFiles > 0) { switch($this->getEncType()) { case self::ENC_FORMDATA: // Encode body as multipart/form-data $boundary = '---ZENDHTTPCLIENT-' . md5(microtime()); $this->setEncType(self::ENC_FORMDATA, $boundary); // Get POST parameters and encode them $params = self::flattenParametersArray($this->getRequest()->post()->toArray()); foreach ($params as $pp) { $body .= self::encodeFormData($boundary, $pp[0], $pp[1]); } // Encode files foreach ($this->getRequest()->file()->toArray() as $key => $file) { $fhead = array('Content-Type' => $file['ctype']); $body .= self::encodeFormData($boundary, $file['formname'], $file['data'], $file['filename'], $fhead); } $body .= "--{$boundary}--\r\n"; break; case self::ENC_URLENCODED: // Encode body as application/x-www-form-urlencoded $body = http_build_query($this->getRequest()->post()->toArray()); break; default: if (isset($mbIntEnc)) { mb_internal_encoding($mbIntEnc); } throw new Exception\RuntimeException("Cannot handle content type '{$this->encType}' automatically"); break; } } if (isset($mbIntEnc)) { mb_internal_encoding($mbIntEnc); } return $body; } /** * Attempt to detect the MIME type of a file using available extensions * * This method will try to detect the MIME type of a file. If the fileinfo * extension is available, it will be used. If not, the mime_magic * extension which is deprected but is still available in many PHP setups * will be tried. * * If neither extension is available, the default application/octet-stream * MIME type will be returned * * @param string $file File path * @return string MIME type */ protected function detectFileMimeType($file) { $type = null; // First try with fileinfo functions if (function_exists('finfo_open')) { if (self::$_fileInfoDb === null) { self::$_fileInfoDb = @finfo_open(FILEINFO_MIME); } if (self::$_fileInfoDb) { $type = finfo_file(self::$_fileInfoDb, $file); } } elseif (function_exists('mime_content_type')) { $type = mime_content_type($file); } // Fallback to the default application/octet-stream if (! $type) { $type = 'application/octet-stream'; } return $type; } /** * Encode data to a multipart/form-data part suitable for a POST request. * * @param string $boundary * @param string $name * @param mixed $value * @param string $filename * @param array $headers Associative array of optional headers @example ("Content-Transfer-Encoding" => "binary") * @return string */ public static function encodeFormData($boundary, $name, $value, $filename = null, $headers = array()) { $ret = "--{$boundary}\r\n" . 'Content-Disposition: form-data; name="' . $name .'"'; if ($filename) { $ret .= '; filename="' . $filename . '"'; } $ret .= "\r\n"; foreach ($headers as $hname => $hvalue) { $ret .= "{$hname}: {$hvalue}\r\n"; } $ret .= "\r\n"; $ret .= "{$value}\r\n"; return $ret; } /** * Convert an array of parameters into a flat array of (key, value) pairs * * Will flatten a potentially multi-dimentional array of parameters (such * as POST parameters) into a flat array of (key, value) paris. In case * of multi-dimentional arrays, square brackets ([]) will be added to the * key to indicate an array. * * @since 1.9 * * @param array $parray * @param string $prefix * @return array */ static protected function flattenParametersArray($parray, $prefix = null) { if (!is_array($parray)) { return $parray; } $parameters = array(); foreach($parray as $name => $value) { // Calculate array key if ($prefix) { if (is_int($name)) { $key = $prefix . '[]'; } else { $key = $prefix . "[$name]"; } } else { $key = $name; } if (is_array($value)) { $parameters = array_merge($parameters, self::flattenParametersArray($value, $key)); } else { $parameters[] = array($key, $value); } } return $parameters; } }setUri($url); $request->setMethod(Request::METHOD_GET); if (!empty($query) && is_array($query)) { $request->query()->fromArray($query); } if (!empty($headers) && is_array($headers)) { $request->headers()->addHeaders($headers); } if (!empty($body)) { $request->setBody($body); } return self::getStaticClient()->send($request); } /** * HTTP POST METHOD (static) * * @param string $url * @param array $params * @param array $headers * @return Response|boolean */ public static function post($url, $params, $headers=array(), $body=null) { if (empty($url)) { return false; } $request= new Request(); $request->setUri($url); $request->setMethod(Request::METHOD_POST); if (!empty($params) && is_array($params)) { $request->post()->fromArray($params); } else { throw new Exception\InvalidArgumentException('The array of post parameters is empty'); } if (!isset($headers['Content-Type'])) { $headers['Content-Type']= Client::ENC_URLENCODED; } if (!empty($headers) && is_array($headers)) { $request->headers()->addHeaders($headers); } if (!empty($body)) { $request->setBody($body); } return self::getStaticClient()->send($request); } }headers = $headers; parent::__construct(); } /** * Add a cookie to the class. Cookie should be passed either as a Zend\Http\Header\Cookie object * or as a string - in which case an object is created from the string. * * @param Cookie|string $cookie * @param Uri\Uri|string $ref_uri Optional reference URI (for domain, path, secure) */ public function addCookie(Cookie $cookie, $ref_uri = null) { if (is_string($cookie)) { $cookie = Cookie::fromString($cookie, $ref_uri); } if ($cookie instanceof Cookie) { $domain = $cookie->getDomain(); $path = $cookie->getPath(); if (!isset($this->cookies[$domain])) { $this->cookies[$domain] = array(); } if (!isset($this->cookies[$domain][$path])) { $this->cookies[$domain][$path] = array(); } $this->cookies[$domain][$path][$cookie->getName()] = $cookie; $this->_rawCookies[] = $cookie; } else { throw new Exception\InvalidArgumentException('Supplient argument is not a valid cookie string or object'); } } /** * Parse an HTTP response, adding all the cookies set in that response * * @param Response $response * @param Uri\Uri|string $ref_uri Requested URI */ public function addCookiesFromResponse($response, $ref_uri) { if (!$response instanceof Response) { throw new Exception\InvalidArgumentException('$response is expected to be a Response object'); } $cookie_hdrs = $response->headers()->get('Set-Cookie'); if (is_array($cookie_hdrs)) { foreach ($cookie_hdrs as $cookie) { $this->addCookie($cookie, $ref_uri); } } elseif (is_string($cookie_hdrs)) { $this->addCookie($cookie_hdrs, $ref_uri); } } /** * Get all cookies in the cookie jar as an array * * @param int $ret_as Whether to return cookies as objects of \Zend\Http\Header\Cookie or as strings * @return array|string */ public function getAllCookies($ret_as = self::COOKIE_OBJECT) { $cookies = $this->_flattenCookiesArray($this->cookies, $ret_as); return $cookies; } /** * Return an array of all cookies matching a specific request according to the request URI, * whether session cookies should be sent or not, and the time to consider as "now" when * checking cookie expiry time. * * @param string|Uri\Uri $uri URI to check against (secure, domain, path) * @param boolean $matchSessionCookies Whether to send session cookies * @param int $ret_as Whether to return cookies as objects of \Zend\Http\Header\Cookie or as strings * @param int $now Override the current time when checking for expiry time * @return array|string */ public function getMatchingCookies($uri, $matchSessionCookies = true, $ret_as = self::COOKIE_OBJECT, $now = null) { if (is_string($uri)) { $uri = Uri\UriFactory::factory($uri, 'http'); } if (!$uri instanceof Uri\Uri) { throw new Exception\InvalidArgumentException("Invalid URI string or object passed"); } $host = $uri->getHost(); if (empty($host)) { throw new Exception\InvalidArgumentException('Invalid URI specified; does not contain a host'); } // First, reduce the array of cookies to only those matching domain and path $cookies = $this->_matchDomain($host); $cookies = $this->_matchPath($cookies, $uri->getPath()); $cookies = $this->_flattenCookiesArray($cookies, self::COOKIE_OBJECT); // Next, run Cookie->match on all cookies to check secure, time and session mathcing $ret = array(); foreach ($cookies as $cookie) if ($cookie->match($uri, $matchSessionCookies, $now)) $ret[] = $cookie; // Now, use self::_flattenCookiesArray again - only to convert to the return format ;) $ret = $this->_flattenCookiesArray($ret, $ret_as); return $ret; } /** * Get a specific cookie according to a URI and name * * @param Uri\Uri|string $uri The uri (domain and path) to match * @param string $cookie_name The cookie's name * @param int $ret_as Whether to return cookies as objects of \Zend\Http\Header\Cookie or as strings * @return Cookie|string */ public function getCookie($uri, $cookie_name, $ret_as = self::COOKIE_OBJECT) { if (is_string($uri)) { $uri = Uri\UriFactory::factory($uri, 'http'); } if (!$uri instanceof Uri\Uri) { throw new Exception\InvalidArgumentException('Invalid URI specified'); } $host = $uri->getHost(); if (empty($host)) { throw new Exception\InvalidArgumentException('Invalid URI specified; host missing'); } // Get correct cookie path $path = $uri->getPath(); $path = substr($path, 0, strrpos($path, '/')); if (! $path) $path = '/'; if (isset($this->cookies[$uri->getHost()][$path][$cookie_name])) { $cookie = $this->cookies[$uri->getHost()][$path][$cookie_name]; switch ($ret_as) { case self::COOKIE_OBJECT: return $cookie; break; case self::COOKIE_STRING_ARRAY: case self::COOKIE_STRING_CONCAT: return $cookie->__toString(); break; default: throw new Exception\InvalidArgumentException("Invalid value passed for \$ret_as: {$ret_as}"); break; } } else { return false; } } /** * Helper function to recursivly flatten an array. Shoud be used when exporting the * cookies array (or parts of it) * * @param \Zend\Http\Header\Cookie|array $ptr * @param int $ret_as What value to return * @return array|string */ protected function _flattenCookiesArray($ptr, $ret_as = self::COOKIE_OBJECT) { if (is_array($ptr)) { $ret = ($ret_as == self::COOKIE_STRING_CONCAT ? '' : array()); foreach ($ptr as $item) { if ($ret_as == self::COOKIE_STRING_CONCAT) { $ret .= $this->_flattenCookiesArray($item, $ret_as); } else { $ret = array_merge($ret, $this->_flattenCookiesArray($item, $ret_as)); } } return $ret; } elseif ($ptr instanceof Cookie) { switch ($ret_as) { case self::COOKIE_STRING_ARRAY: return array($ptr->__toString()); break; case self::COOKIE_STRING_CONCAT: return $ptr->__toString(); break; case self::COOKIE_OBJECT: default: return array($ptr); break; } } return null; } /** * Return a subset of the cookies array matching a specific domain * * @param string $domain * @return array */ protected function _matchDomain($domain) { $ret = array(); foreach (array_keys($this->cookies) as $cdom) { if (Cookie::matchCookieDomain($cdom, $domain)) { $ret[$cdom] = $this->cookies[$cdom]; } } return $ret; } /** * Return a subset of a domain-matching cookies that also match a specified path * * @param array $dom_array * @param string $path * @return array */ protected function _matchPath($domains, $path) { $ret = array(); foreach ($domains as $dom => $paths_array) { foreach (array_keys($paths_array) as $cpath) { if (Cookie::matchCookiePath($cpath, $path)) { if (! isset($ret[$dom])) { $ret[$dom] = array(); } $ret[$dom][$cpath] = $paths_array[$cpath]; } } } return $ret; } /** * Create a new Cookies object and automatically load into it all the * cookies set in an Http_Response object. If $uri is set, it will be * considered as the requested URI for setting default domain and path * of the cookie. * * @param Response $response HTTP Response object * @param Uri\Uri|string $uri The requested URI * @return Cookies * @todo Add the $uri functionality. */ public static function fromResponse(Response $response, $ref_uri) { $jar = new self(); $jar->addCookiesFromResponse($response, $ref_uri); return $jar; } /** * Tells if the array of cookies is empty * * @return bool */ public function isEmpty() { return count($this) == 0; } /** * Empties the cookieJar of any cookie * * @return Cookies */ public function reset() { $this->cookies = $this->_rawCookies = array(); return $this; } } values = explode(',', $values); foreach ($acceptHeader->values as $index => $value) { $acceptHeader->values[$index] = explode(';', $value); } return $acceptHeader; } public function getFieldName() { return 'Accept'; } public function getFieldValue() { $strings = array(); foreach ($this->values as $value) { $strings[] = implode('; ', $value); } return implode(',', $strings); } public function toString() { return 'Accept: ' . $this->getFieldValue(); } // // /** // * Get the quality factor of the value (q=) // * // * @param string $value // * @return float // */ // public function getQualityFactor($value) // { // if ($this->hasValue($value)) { // if (!empty($this->arrayValue)) { // if (isset($this->arrayValue[$value])) { // foreach ($this->arrayValue[$value] as $val) { // if (preg_match('/q=(\d\.?\d?)/',$val,$matches)) { // return $matches[1]; // } // } // } // return 1; // } // } // return false; // } // // /** // * Get the level of a value (level=) // * // * @param string $value // * @return integer // */ // public function getLevel($value) // { // if ($this->hasValue($value)) { // if (isset($this->arrayValue[$value])) { // foreach ($this->arrayValue[$value] as $val) { // if (preg_match('/level=(\d+)/',$val,$matches)) { // return $matches[1]; // } // } // } // } // return false; // } // } = 1) { $acceptCharsetHeader->charsets = explode(',', $valueParts[0]); } if (count($valueParts) == 2 && preg_match('#q=(?P\d(?\.\d)+)#', $valueParts[1], $matches)) { $acceptCharsetHeader->qualityValue = $matches['qvalue']; } return $acceptCharsetHeader; } public function getFieldName() { return 'Accept-Charset'; } public function getFieldValue() { return implode(', ', $this->charsets) . ';q=' . $this->qualityValue; } public function toString() { return 'Accept-Charset: ' . $this->getFieldValue(); } } value= $value; return $acceptEncodingHeader; } public function getFieldName() { return 'Accept-Encoding'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Accept-Encoding: ' . $this->getFieldValue(); } } value = $value; return $header; } public function getFieldName() { return 'Accept-Language'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Accept-Language: ' . $this->getFieldValue(); } } rangeUnit = trim($value); return $header; } public function getFieldName() { return 'Accept-Ranges'; } public function getFieldValue() { return $this->getRangeUnit(); } public function setRangeUnit($rangeUnit) { $this->rangeUnit = $rangeUnit; return $this; } public function getRangeUnit() { return $this->rangeUnit; } public function toString() { return 'Accept-Ranges: ' . $this->getFieldValue(); } } deltaSeconds = $value; return $header; } public function getFieldName() { return 'Age'; } public function getFieldValue() { return $this->getDeltaSeconds(); } public function setDeltaSeconds($deltaSeconds) { $this->deltaSeconds = $deltaSeconds; return $this; } public function getDeltaSeconds() { return $this->deltaSeconds; } public function toString() { return 'Age: ' . $this->getFieldValue(); } } allowedMethods[] = trim(strtoupper($method)); } return $header; } public function getFieldName() { return 'Allow'; } public function getFieldValue() { return implode(', ', $this->allowedMethods); } public function getAllowedMethods() { return $this->allowedMethods; } public function setAllowedMethods(array $allowedMethods) { $this->allowedMethods = $allowedMethods; } public function toString() { return 'Allow: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Authentication-Info'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Authentication-Info: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Authorization'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Authorization: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Cache-Control'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Cache-Control: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Connection'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Connection: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Content-Disposition'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Content-Disposition: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Content-Encoding'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Content-Encoding: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Content-Language'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Content-Language: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Content-Length'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Content-Length: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Content-Location'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Content-Location: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Content-MD5'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Content-MD5: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Content-Range'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Content-Range: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Content-Type'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Content-Type: ' . $this->getFieldValue(); } } getName(), $nvPairs)) { throw new Exception\InvalidArgumentException('Two cookies with the same name were provided to ' . __CLASS__ . '::' . __METHOD__); } $nvPairs[$setCookie->getName()] = $setCookie->getValue(); } return new static($nvPairs); } public static function fromString($headerLine) { $header = new static(); list($name, $value) = preg_split('#: #', $headerLine, 2); // check to ensure proper header type for this factory if (strtolower($name) !== 'cookie') { throw new Exception\InvalidArgumentException('Invalid header line for Server string'); } $nvPairs = preg_split('#;\s*#', $value); $arrayInfo = array(); foreach ($nvPairs as $nvPair) { $parts = explode('=', $nvPair, 2); if (count($parts) != 2) { throw new Exception\RuntimeException('Malformed Cookie header found'); } list($name, $value) = $parts; $arrayInfo[$name] = urldecode($value); } $header->exchangeArray($arrayInfo); return $header; } public function __construct(array $array = array()) { parent::__construct($array, ArrayObject::ARRAY_AS_PROPS); } public function setEncodeValue($encodeValue) { $this->encodeValue = (bool) $encodeValue; return $this; } public function getEncodeValue() { return $this->encodeValue; } public function getFieldName() { return 'Cookie'; } public function getFieldValue() { $nvPairs = array(); foreach ($this as $name => $value) { $nvPairs[] = $name . '=' . (($this->encodeValue) ? urlencode($value) : $value); } return implode('; ', $nvPairs); } public function toString() { return 'Cookie: ' . $this->getFieldValue(); } /** * Get the cookie as a string, suitable for sending as a "Cookie" header in an * HTTP request * * @return string */ public function __toString() { return $this->toString(); } } value= $value; return $header; } public function getFieldName() { return 'Date'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Date: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Etag'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Etag: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Expect'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Expect: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Expires'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Expires: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'From'; } public function getFieldValue() { return $this->value; } public function toString() { return 'From: ' . $this->getFieldValue(); } } setFieldName($fieldName); } if ($fieldValue) { $this->setFieldValue($fieldValue); } } /** * Set header field name * * @param string $fieldName * @return GenericHeader */ public function setFieldName($fieldName) { if (!is_string($fieldName) || empty($fieldName)) { throw new Exception\InvalidArgumentException('Header name must be a string'); } // Pre-filter to normalize valid characters, change underscore to dash $fieldName = str_replace(' ', '-', ucwords(str_replace(array('_', '-'), ' ', $fieldName))); // Validate what we have if (!preg_match('/^[a-z][a-z0-9-]*$/i', $fieldName)) { throw new Exception\InvalidArgumentException('Header name must start with a letter, and consist of only letters, numbers, and dashes'); } $this->fieldName = $fieldName; return $this; } /** * Retrieve header field name * * @return string */ public function getFieldName() { return $this->fieldName; } /** * Set header field value * * @param string $fieldValue * @return GenericHeader */ public function setFieldValue($fieldValue) { $fieldValue = (string) $fieldValue; if (empty($fieldValue) || preg_match('/^\s+$/', $fieldValue)) { $fieldValue = ''; } $this->fieldValue = $fieldValue; return $this; } /** * Retrieve header field value * * @return string */ public function getFieldValue() { return $this->fieldValue; } /** * Cast to string as a well formed HTTP header line * * Returns in form of "NAME: VALUE\r\n" * * @return string */ public function toString() { $name = $this->getFieldName(); $value = $this->getFieldValue(); return $name. ': ' . $value . "\r\n"; } } setFieldName($fieldName); } if ($fieldValue) { $this->setFieldValue($fieldValue); } } /** * Set header name * * @param string $fieldName * @return GenericHeader */ public function setFieldName($fieldName) { if (!is_string($fieldName) || empty($fieldName)) { throw new Exception\InvalidArgumentException('Header name must be a string'); } // Pre-filter to normalize valid characters, change underscore to dash $fieldName = str_replace(' ', '-', ucwords(str_replace(array('_', '-'), ' ', $fieldName))); // Validate what we have if (!preg_match('/^[a-z][a-z0-9-]*$/i', $fieldName)) { throw new Exception\InvalidArgumentException('Header name must start with a letter, and consist of only letters, numbers, and dashes'); } $this->fieldName = $fieldName; return $this; } /** * Retrieve header name * * @return string */ public function getFieldName() { return $this->fieldName; } /** * Set header value * * @param string|array $fieldValue * @return GenericHeader */ public function setFieldValue($fieldValue) { $fieldValue = (string) $fieldValue; if (empty($fieldValue) || preg_match('/^\s+$/', $fieldValue)) { $fieldValue = ''; } $this->fieldValue = $fieldValue; return $this; } /** * Retrieve header value * * @return string */ public function getFieldValue() { return $this->fieldValue; } /** * Cast to string * * Returns in form of "NAME: VALUE\r\n" * * @return string */ public function toString() { $name = $this->getFieldName(); $value = $this->getFieldValue(); return $name. ': ' . $value . "\r\n"; } public function toStringMultipleHeaders(array $headers) { $name = $this->getFieldName(); $values = array($this->getFieldValue()); foreach ($headers as $header) { if (!$header instanceof static) { throw new Exception\InvalidArgumentException('This method toStringMultipleHeaders was expecting an array of headers of the same type'); } $values[] = $header->getFieldValue(); } return $name. ': ' . implode(',', $values) . "\r\n"; } } value= $value; return $header; } public function getFieldName() { return 'Host'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Host: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'If-Match'; } public function getFieldValue() { return $this->value; } public function toString() { return 'If-Match: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'If-Modified-Since'; } public function getFieldValue() { return $this->value; } public function toString() { return 'If-Modified-Since: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'If-None-Match'; } public function getFieldValue() { return $this->value; } public function toString() { return 'If-None-Match: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'If-Range'; } public function getFieldValue() { return $this->value; } public function toString() { return 'If-Range: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'If-Unmodified-Since'; } public function getFieldValue() { return $this->value; } public function toString() { return 'If-Unmodified-Since: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Keep-Alive'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Keep-Alive: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Last-Modified'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Last-Modified: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Location'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Location: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Max-Forwards'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Max-Forwards: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Pragma'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Pragma: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Proxy-Authenticate'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Proxy-Authenticate: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Proxy-Authorization'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Proxy-Authorization: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Range'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Range: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Referer'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Referer: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Refresh'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Refresh: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Retry-After'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Retry-After: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Server'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Server: ' . $this->getFieldValue(); } } setExpires($headerValue); break; case 'domain': $header->setDomain($headerValue); break; case 'path': $header->setPath($headerValue); break; case 'secure': $header->setSecure(true); break; case 'httponly': $header->setHttponly(true); break; default: $header->setName($headerKey); $header->setValue($headerValue); } } return $header; }; } list($name, $value) = preg_split('#: #', $headerLine, 2); // check to ensure proper header type for this factory if (strtolower($name) !== 'set-cookie') { throw new Exception\InvalidArgumentException('Invalid header line for Set-Cookie string'); } $multipleHeaders = preg_split('#(?type = 'Cookie'; if ($name) { $this->setName($name); } if ($value) { $this->setValue($value); // in parent } if ($domain) { $this->setDomain($domain); } if ($expires) { $this->setExpires($expires); } if ($secure) { $this->setSecure($secure); } } /** * @return string 'Set-Cookie' */ public function getFieldName() { return 'Set-Cookie'; } /** * @throws Exception\RuntimeException * @return string */ public function getFieldValue() { if ($this->getName() == '') { throw new Exception\RuntimeException('A cookie name is required to generate a field value for this cookie'); } $fieldValue = $this->getName() . '=' . urlencode($this->getValue()); if (($expires = $this->getExpires())) { $fieldValue .= '; Expires=' . $expires; } if (($domain = $this->getDomain())) { $fieldValue .= '; Domain=' . $domain; } if (($path = $this->getPath())) { $fieldValue .= '; Path=' . $path; } if ($this->isSecure()) { $fieldValue .= '; Secure'; } if ($this->isHttponly()) { $fieldValue .= '; HttpOnly'; } return $fieldValue; } /** * @param string $name * @return SetCookie */ public function setName($name) { if (preg_match("/[=,; \t\r\n\013\014]/", $name)) { throw new Exception\InvalidArgumentException("Cookie name cannot contain these characters: =,; \\t\\r\\n\\013\\014 ({$name})"); } $this->name = $name; return $this; } /** * @return string */ public function getName() { return $this->name; } /** * @param string $value */ public function setValue($value) { $this->value = $value; } /** * @return string */ public function getValue() { return $this->value; } /** * @param int $expires * @return SetCookie */ public function setExpires($expires) { if (!empty($expires)) { if (is_string($expires)) { $expires = strtotime($expires); } elseif (!is_int($expires)) { throw new Exception\InvalidArgumentException('Invalid expires time specified'); } $this->expires = (int) $expires; } return $this; } /** * @return int */ public function getExpires($inSeconds = false) { if ($this->expires == null) { return; } if ($inSeconds) { return $this->expires; } return gmdate('D, d-M-Y H:i:s', $this->expires) . ' GMT'; } /** * @param string $domain */ public function setDomain($domain) { $this->domain = $domain; } /** * @return string */ public function getDomain() { return $this->domain; } /** * @param string $path */ public function setPath($path) { $this->path = $path; } /** * @return string */ public function getPath() { return $this->path; } /** * @param boolean $secure */ public function setSecure($secure) { $this->secure = $secure; } /** * @return boolean */ public function isSecure() { return $this->secure; } /** * @param \Zend\Http\Header\true $httponly */ public function setHttponly($httponly) { $this->httponly = $httponly; } /** * @return \Zend\Http\Header\true */ public function isHttponly() { return $this->httponly; } /** * Check whether the cookie has expired * * Always returns false if the cookie is a session cookie (has no expiry time) * * @param int $now Timestamp to consider as "now" * @return boolean */ public function isExpired($now = null) { if ($now === null) { $now = time(); } if (is_int($this->expires) && $this->expires < $now) { return true; } else { return false; } } /** * Check whether the cookie is a session cookie (has no expiry time set) * * @return boolean */ public function isSessionCookie() { return ($this->expires === null); } public function isValidForRequest($requestDomain, $path, $isSecure = false) { if ($this->getDomain() && (strrpos($requestDomain, $this->getDomain()) !== false)) { return false; } if ($this->getPath() && (strpos($path, $this->getPath()) !== 0)) { return false; } if ($this->secure && $this->isSecure()!==$isSecure) { return false; } return true; } public function toString() { return 'Set-Cookie: ' . $this->getFieldValue(); } public function toStringMultipleHeaders(array $headers) { $headerLine = $this->toString(); /* @var $header SetCookie */ foreach ($headers as $header) { if (!$header instanceof SetCookie) { throw new Exception\RuntimeException( 'The SetCookie multiple header implementation can only accept an array of SetCookie headers' ); } $headerLine .= ', ' . $header->getFieldValue(); } return $headerLine; } } value= $value; return $header; } public function getFieldName() { return 'TE'; } public function getFieldValue() { return $this->value; } public function toString() { return 'TE: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Trailer'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Trailer: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Transfer-Encoding'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Transfer-Encoding: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Upgrade'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Upgrade: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'User-Agent'; } public function getFieldValue() { return $this->value; } public function toString() { return 'User-Agent: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Vary'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Vary: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Via'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Via: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'Warning'; } public function getFieldValue() { return $this->value; } public function toString() { return 'Warning: ' . $this->getFieldValue(); } } value= $value; return $header; } public function getFieldName() { return 'WWW-Authenticate'; } public function getFieldValue() { return $this->value; } public function toString() { return 'WWW-Authenticate: ' . $this->getFieldValue(); } } [^()><@,;:\"\\/\[\]?=}{ \t]+):.*$/', $line, $matches)) { if ($current) { // a header name was present, then store the current complete line $headers->headersKeys[] = str_replace(array('-', '_'), '', strtolower($current['name'])); $headers->headers[] = $current; } $current = array( 'name' => $matches['name'], 'line' => trim($line) ); } elseif (preg_match('/^\s+.*$/', $line, $matches)) { // continuation: append to current line $current['line'] .= trim($line); } elseif (preg_match('/^\s*$/', $line)) { // empty line indicates end of headers break; } else { // Line does not match header format! throw new Exception\RuntimeException(sprintf( 'Line "%s"does not match header format!', $line )); } } if ($current) { $headers->headersKeys[] = str_replace(array('-', '_'), '', strtolower($current['name'])); $headers->headers[] = $current; } return $headers; } /** * Set an alternate implementation for the PluginClassLoader * * @param \Zend\Loader\PluginClassLocator $pluginClassLoader * @return Headers */ public function setPluginClassLoader(PluginClassLocator $pluginClassLoader) { $this->pluginClassLoader = $pluginClassLoader; return $this; } /** * Return an instance of a PluginClassLocator, lazyload and inject map if necessary * * @return PluginClassLocator */ public function getPluginClassLoader() { if ($this->pluginClassLoader === null) { $this->pluginClassLoader = new \Zend\Loader\PluginClassLoader(array( 'accept' => 'Zend\Http\Header\Accept', 'acceptcharset' => 'Zend\Http\Header\AcceptCharset', 'acceptencoding' => 'Zend\Http\Header\AcceptEncoding', 'acceptlanguage' => 'Zend\Http\Header\AcceptLanguage', 'acceptranges' => 'Zend\Http\Header\AcceptRanges', 'age' => 'Zend\Http\Header\Age', 'allow' => 'Zend\Http\Header\Allow', 'authenticationinfo' => 'Zend\Http\Header\AuthenticationInfo', 'authorization' => 'Zend\Http\Header\Authorization', 'cachecontrol' => 'Zend\Http\Header\CacheControl', 'connection' => 'Zend\Http\Header\Connection', 'contentdisposition' => 'Zend\Http\Header\ContentDisposition', 'contentencoding' => 'Zend\Http\Header\ContentEncoding', 'contentlanguage' => 'Zend\Http\Header\ContentLanguage', 'contentlength' => 'Zend\Http\Header\ContentLength', 'contentlocation' => 'Zend\Http\Header\ContentLocation', 'contentmd5' => 'Zend\Http\Header\ContentMD5', 'contentrange' => 'Zend\Http\Header\ContentRange', 'contenttype' => 'Zend\Http\Header\ContentType', 'cookie' => 'Zend\Http\Header\Cookie', 'date' => 'Zend\Http\Header\Date', 'etag' => 'Zend\Http\Header\Etag', 'expect' => 'Zend\Http\Header\Expect', 'expires' => 'Zend\Http\Header\Expires', 'from' => 'Zend\Http\Header\From', 'host' => 'Zend\Http\Header\Host', 'ifmatch' => 'Zend\Http\Header\IfMatch', 'ifmodifiedsince' => 'Zend\Http\Header\IfModifiedSince', 'ifnonematch' => 'Zend\Http\Header\IfNoneMatch', 'ifrange' => 'Zend\Http\Header\IfRange', 'ifunmodifiedsince' => 'Zend\Http\Header\IfUnmodifiedSince', 'keepalive' => 'Zend\Http\Header\KeepAlive', 'lastmodified' => 'Zend\Http\Header\LastModified', 'location' => 'Zend\Http\Header\Location', 'maxforwards' => 'Zend\Http\Header\MaxForwards', 'pragma' => 'Zend\Http\Header\Pragma', 'proxyauthenticate' => 'Zend\Http\Header\ProxyAuthenticate', 'proxyauthorization' => 'Zend\Http\Header\ProxyAuthorization', 'range' => 'Zend\Http\Header\Range', 'referer' => 'Zend\Http\Header\Referer', 'refresh' => 'Zend\Http\Header\Refresh', 'retryafter' => 'Zend\Http\Header\RetryAfter', 'server' => 'Zend\Http\Header\Server', 'setcookie' => 'Zend\Http\Header\SetCookie', 'te' => 'Zend\Http\Header\TE', 'trailer' => 'Zend\Http\Header\Trailer', 'transferencoding' => 'Zend\Http\Header\TransferEncoding', 'upgrade' => 'Zend\Http\Header\Upgrade', 'useragent' => 'Zend\Http\Header\UserAgent', 'vary' => 'Zend\Http\Header\Vary', 'via' => 'Zend\Http\Header\Via', 'warning' => 'Zend\Http\Header\Warning', 'wwwauthenticate' => 'Zend\Http\Header\WWWAuthenticate' )); } return $this->pluginClassLoader; } /** * Add many headers at once * * Expects an array (or Traversable object) of type/value pairs. * * @param array|Traversable $headers * @return Headers */ public function addHeaders($headers) { if (!is_array($headers) && !$headers instanceof \Traversable) { throw new Exception\InvalidArgumentException(sprintf( 'Expected array or Traversable; received "%s"', (is_object($headers) ? get_class($headers) : gettype($headers)) )); } foreach ($headers as $name => $value) { if (is_int($name)) { if (is_string($value)) { $this->addHeaderLine($value); } elseif (is_array($value) && count($value) == 1) { $this->addHeaderLine(key($value), current($value)); } elseif (is_array($value) && count($value) == 2) { $this->addHeaderLine($value[0], $value[1]); } elseif ($value instanceof Header\HeaderDescription) { $this->addHeader($value); } } elseif (is_string($name)) { $this->addHeaderLine($name, $value); } } return $this; } /** * Add a raw header line, either in name => value, or as a single string 'name: value' * * This method allows for lazy-loading in that the parsing and instantiation of Header object * will be delayed until they are retrieved by either get() or current() * * @throws Exception\InvalidArgumentException * @param string $headerFieldNameOrLine * @param string $fieldValue optional * @return Headers */ public function addHeaderLine($headerFieldNameOrLine, $fieldValue = null) { $matches = null; if (preg_match('/^(?P[^()><@,;:\"\\/\[\]?=}{ \t]+):.*$/', $headerFieldNameOrLine, $matches) && $fieldValue === null) { // is a header $headerName = $matches['name']; $headerKey = str_replace(array('-', '_', ' ', '.'), '', strtolower($matches['name'])); $line = $headerFieldNameOrLine; } elseif ($fieldValue === null) { throw new Exception\InvalidArgumentException('A field name was provided without a field value'); } else { $headerName = $headerFieldNameOrLine; $headerKey = str_replace(array('-', '_', ' ', '.'), '', strtolower($headerFieldNameOrLine)); $line = $headerFieldNameOrLine . ': ' . $fieldValue; } $this->headersKeys[] = $headerKey; $this->headers[] = array('name' => $headerName, 'line' => $line); return $this; } /** * Add a Header to this container, for raw values @see addHeaderLine() and addHeaders() * * @param Header\HeaderDescription $header * @return Headers */ public function addHeader(Header\HeaderDescription $header) { $key = str_replace(array('-', '_', ' ', '.'), '', strtolower($header->getFieldName())); $this->headersKeys[] = $key; $this->headers[] = $header; return $this; } /** * Remove a Header from the container * * @param Header\HeaderDescription $header * @return bool */ public function removeHeader(Header\HeaderDescription $header) { $index = array_search($header, $this->headers, true); if ($index !== false) { unset($this->headersKeys[$index]); unset($this->headers[$index]); return true; } return false; } /** * Clear all headers * * Removes all headers from queue * * @return Headers */ public function clearHeaders() { $this->headers = $this->headersKeys = array(); return $this; } /** * Get all headers of a certain name/type * * @param string $name * @return false|Header\HeaderDescription|\ArrayIterator */ public function get($name) { $key = str_replace(array('-', '_', ' ', '.'), '', strtolower($name)); if (!in_array($key, $this->headersKeys)) { return false; } $class = ($this->getPluginClassLoader()->load($key)) ?: 'Zend\Http\Header\GenericHeader'; if (in_array('Zend\Http\Header\MultipleHeaderDescription', class_implements($class, true))) { $headers = array(); foreach (array_keys($this->headersKeys, $key) as $index) { if (is_array($this->headers[$index])) { $this->lazyLoadHeader($index); } } foreach (array_keys($this->headersKeys, $key) as $index) { $headers[] = $this->headers[$index]; } return new \ArrayIterator($headers); } else { $index = array_search($key, $this->headersKeys); if ($index === false) { return false; } if (is_array($this->headers[$index])) { return $this->lazyLoadHeader($index); } else { return $this->headers[$index]; } } } /** * Test for existence of a type of header * * @param string $name * @return bool */ public function has($name) { $name = str_replace(array('-', '_', ' ', '.'), '', strtolower($name)); return (in_array($name, $this->headersKeys)); } /** * Advance the pointer for this object as an interator * * @return void */ public function next() { next($this->headers); } /** * Return the current key for this object as an interator * * @return mixed */ public function key() { return (key($this->headers)); } /** * Is this iterator still valid? * * @return bool */ public function valid() { return (current($this->headers) !== false); } /** * Reset the internal pointer for this object as an iterator * * @return void */ public function rewind() { reset($this->headers); } /** * Return the current value for this iterator, lazy loading it if need be * * @return Header\HeaderDescription */ public function current() { $current = current($this->headers); if (is_array($current)) { $current = $this->lazyLoadHeader(key($this->headers)); } return $current; } /** * Return the number of headers in this contain, if all headers have not been parsed, actual count could * increase if MultipleHeader objects exist in the Request/Response. If you need an exact count, iterate * * @return int count of currently known headers */ public function count() { return count($this->headers); } /** * Render all headers at once * * This method handles the normal iteration of headers; it is up to the * concrete classes to prepend with the appropriate status/request line. * * @return string */ public function toString() { $headers = ''; /* @var $header Header\HeaderDescription */ foreach ($this->toArray() as $fieldName => $fieldValue) { $headers .= $fieldName . ': ' . $fieldValue . "\r\n"; } return $headers; } /** * Return the headers container as an array * * @todo determine how to produce single line headers, if they are supported * @return array */ public function toArray() { $headers = array(); /* @var $header Header\HeaderDescription */ foreach ($this->headers as $header) { if ($header instanceof Header\HeaderDescription) { $headers[$header->getFieldName()] = $header->getFieldValue(); } else { $matches = null; preg_match('/^(?P[^()><@,;:\"\\/\[\]?=}{ \t]+):\s*(?P.*)$/', $header['line'], $matches); if ($matches) { $headers[$matches['name']] = $matches['value']; } } } return $headers; } /** * By calling this, it will force parsing and loading of all headers, after this count() will be accurate * * @return bool */ public function forceLoading() { foreach ($this as $item) { // $item should now be loaded } return true; } /** * @param $index * @return mixed|void */ protected function lazyLoadHeader($index) { $current = $this->headers[$index]; $key = $this->headersKeys[$index]; /* @var $class Header\HeaderDescription */ $class = ($this->getPluginClassLoader()->load($key)) ?: 'Zend\Http\Header\GenericHeader'; $headers = $class::fromString($current['line']); if (is_array($headers)) { $this->headers[$index] = $current = array_shift($headers); foreach ($headers as $header) { $this->headersKeys[] = $key; $this->headers[] = $header; } return $current; } else { $this->headers[$index] = $current = $headers; return $current; } } } setEnv(new Parameters($_ENV)); $this->setPost(new Parameters($_POST)); $this->setQuery(new Parameters($_GET)); $this->setServer(new Parameters($_SERVER)); if ($_COOKIE) { $this->setCookies(new Parameters($_COOKIE)); } if ($_FILES) { $this->setFiles(new Parameters($_FILES)); } } }' . $methods . ')\s(?[^ ]*)(?:\sHTTP\/(?\d+\.\d+)){0,1}'; $firstLine = array_shift($lines); if (!preg_match('#' . $regex . '#', $firstLine, $matches)) { throw new Exception\InvalidArgumentException('A valid request line was not found in the provided string'); } $request->setMethod($matches['method']); $request->setUri($matches['uri']); if ($matches['version']) { $request->setVersion($matches['version']); } if (count($lines) == 0) { return $request; } $isHeader = true; $headers = $rawBody = array(); while ($lines) { $nextLine = array_shift($lines); if ($nextLine == '') { $isHeader = false; continue; } if ($isHeader) { $headers[] .= $nextLine; } else { $rawBody[] .= $nextLine; } } if ($headers) { $request->headers = implode("\r\n", $headers); } if ($rawBody) { $request->setRawBody(implode("\r\n", $rawBody)); } return $request; } /** * Set the method for this request * * @param string $method * @return Request */ public function setMethod($method) { if (!defined('self::METHOD_'.strtoupper($method))) { throw new Exception\InvalidArgumentException('Invalid HTTP method passed'); } $this->method = $method; return $this; } /** * Return the method for this request * * @return string */ public function getMethod() { return $this->method; } /** * Set the URI/URL for this request, this can be a string or an instance of Zend\Uri\Http * * @throws Exception\InvalidArgumentException * @param string|HttpUri $uri * @return Request */ public function setUri($uri) { if (is_string($uri)) { if (!\Zend\Uri\Uri::validateHost($uri)) { throw new Exception\InvalidArgumentException('Invalid URI passed as string'); } } elseif (!($uri instanceof HttpUri)) { throw new Exception\InvalidArgumentException('URI must be an instance of Zend\Uri\Http or a string'); } $this->uri = $uri; return $this; } /** * Return the URI for this request object * * @return string */ public function getUri() { if ($this->uri instanceof HttpUri) { return $this->uri->toString(); } return $this->uri; } /** * Return the URI for this request object as an instance of Zend\Uri\Http * * @return HttpUri */ public function uri() { if ($this->uri === null || is_string($this->uri)) { $this->uri = new HttpUri($this->uri); } return $this->uri; } /** * Set the HTTP version for this object, one of 1.0 or 1.1 (Request::VERSION_10, Request::VERSION_11) * * @throws Exception\InvalidArgumentException * @param string $version (Must be 1.0 or 1.1) * @return Request */ public function setVersion($version) { if (!in_array($version, array(self::VERSION_10, self::VERSION_11))) { throw new Exception\InvalidArgumentException('Version provided is not a valid version for this HTTP request object'); } $this->version = $version; return $this; } /** * Return the HTTP version for this request * * @return string */ public function getVersion() { return $this->version; } /** * Provide an alternate Parameter Container implementation for query parameters in this object, (this is NOT the * primary API for value setting, for that see query()) * * @param \Zend\Stdlib\ParametersDescription $query * @return Request */ public function setQuery(ParametersDescription $query) { $this->queryParams = $query; return $this; } /** * Return the parameter container responsible for query parameters * * @return \Zend\Stdlib\ParametersDescription */ public function query() { if ($this->queryParams === null) { $this->queryParams = new Parameters(); } return $this->queryParams; } /** * Provide an alternate Parameter Container implementation for post parameters in this object, (this is NOT the * primary API for value setting, for that see post()) * * @param \Zend\Stdlib\ParametersDescription $post * @return Request */ public function setPost(ParametersDescription $post) { $this->postParams = $post; return $this; } /** * Return the parameter container responsible for post parameters * * @return \Zend\Stdlib\ParametersDescription */ public function post() { if ($this->postParams === null) { $this->postParams = new Parameters(); } return $this->postParams; } /** * Return the Cookie header, this is the same as calling $request->headers()->get('Cookie'); * * @convenience $request->headers()->get('Cookie'); * @return Header\Cookie */ public function cookie() { return $this->headers()->get('Cookie'); } /** * Provide an alternate Parameter Container implementation for file parameters in this object, (this is NOT the * primary API for value setting, for that see file()) * * @param \Zend\Stdlib\ParametersDescription $files * @return Request */ public function setFile(ParametersDescription $files) { $this->fileParams = $files; return $this; } /** * Return the parameter container responsible for file parameters * * @return ParametersDescription */ public function file() { if ($this->fileParams === null) { $this->fileParams = new Parameters(); } return $this->fileParams; } /** * Provide an alternate Parameter Container implementation for server parameters in this object, (this is NOT the * primary API for value setting, for that see server()) * * @param \Zend\Stdlib\ParametersDescription $server * @return Request */ public function setServer(ParametersDescription $server) { $this->serverParams = $server; return $this; } /** * Return the parameter container responsible for server parameters * * @see http://www.faqs.org/rfcs/rfc3875.html * @return \Zend\Stdlib\ParametersDescription */ public function server() { if ($this->serverParams === null) { $this->serverParams = new Parameters(); } return $this->serverParams; } /** * Provide an alternate Parameter Container implementation for env parameters in this object, (this is NOT the * primary API for value setting, for that see env()) * * @param \Zend\Stdlib\ParametersDescription $env * @return \Zend\Http\Request */ public function setEnv(ParametersDescription $env) { $this->envParams = $env; return $this; } /** * Return the parameter container responsible for env parameters * * @return \Zend\Stdlib\ParametersDescription */ public function env() { if ($this->envParams === null) { $this->envParams = new Parameters(); } return $this->envParams; } /** * Provide an alternate Parameter Container implementation for headers in this object, (this is NOT the * primary API for value setting, for that see headers()) * * @param \Zend\Http\Headers $headers * @return \Zend\Http\Request */ public function setHeaders(Headers $headers) { $this->headers = $headers; return $this; } /** * Return the header container responsible for headers * * @return \Zend\Http\Headers */ public function headers() { if ($this->headers === null || is_string($this->headers)) { // this is only here for fromString lazy loading $this->headers = (is_string($this->headers)) ? Headers::fromString($this->headers) : new Headers(); } return $this->headers; } /** * Set the raw body for the request * * @param string $string * @return \Zend\Http\Request */ public function setRawBody($string) { $this->rawBody = $string; return $this; } /** * Get the raw body for the request * * @return string */ public function getRawBody() { return $this->rawBody; } /** * Is this an OPTIONS method request? * * @return bool */ public function isOptions() { return ($this->method === self::METHOD_OPTIONS); } /** * Is this a GET method request? * * @return bool */ public function isGet() { return ($this->method === self::METHOD_GET); } /** * Is this a HEAD method request? * * @return bool */ public function isHead() { return ($this->method === self::METHOD_HEAD); } /** * Is this a POST method request? * * @return bool */ public function isPost() { return ($this->method === self::METHOD_POST); } /** * Is this a PUT method request? * * @return bool */ public function isPut() { return ($this->method === self::METHOD_PUT); } /** * Is this a DELETE method request? * * @return bool */ public function isDelete() { return ($this->method === self::METHOD_DELETE); } /** * Is this a TRACE method request? * * @return bool */ public function isTrace() { return ($this->method === self::METHOD_TRACE); } /** * Is this a CONNECT method request? * * @return bool */ public function isConnect() { return ($this->method === self::METHOD_CONNECT); } /** * Return the formatted request line (first line) for this http request * * @return string */ public function renderRequestLine() { return $this->method . ' ' . (string) $this->uri . ' HTTP/' . $this->version; } /** * @return string */ public function toString() { $str = $this->renderRequestLine() . "\r\n"; if ($this->headers) { $str .= $this->headers->toString(); } $str .= "\r\n"; $str .= $this->getContent(); return $str; } /** * Allow PHP casting of this object * * @return string */ public function __toString() { return $this->toString(); } } stream; } /** * Set the response stream * * @param resourse $stream * @return \Zend\Http\Response\Stream */ public function setStream($stream) { $this->stream = $stream; return $this; } /** * Get the cleanup trigger * * @return boolean */ public function getCleanup() { return $this->_cleanup; } /** * Set the cleanup trigger * * @param $cleanup Set cleanup trigger */ public function setCleanup($cleanup = true) { $this->_cleanup = $cleanup; } /** * Get file name associated with the stream * * @return string */ public function getStreamName() { return $this->stream_name; } /** * Set file name associated with the stream * * @param string $stream_name Name to set * @return \Zend\Http\Response\Stream */ public function setStreamName($stream_name) { $this->stream_name = $stream_name; return $this; } /** * Create a new Zend\Http\Response\Stream object from a string * * @param string $response_str * @param resource $stream * @return Stream */ public static function fromStream($response_str, $stream) { $response= new static(); $response::fromString($response_str); if (is_resource($stream)) { $response->setStream($stream); } return $response; } /** * Get the response body as string * * This method returns the body of the HTTP response (the content), as it * should be in it's readable version - that is, after decoding it (if it * was decoded), deflating it (if it was gzip compressed), etc. * * If you want to get the raw body (as transfered on wire) use * $this->getRawBody() instead. * * @return string */ public function getBody() { if($this->stream != null) { $this->readStream(); } return parent::getBody(); } /** * Get the raw response body (as transfered "on wire") as string * * If the body is encoded (with Transfer-Encoding, not content-encoding - * IE "chunked" body), gzip compressed, etc. it will not be decoded. * * @return string */ public function getRawBody() { if($this->stream) { $this->readStream(); } return $this->body; } /** * Read stream content and return it as string * * Function reads the remainder of the body from the stream and closes the stream. * * @return string */ protected function readStream() { if(!is_resource($this->stream)) { return ''; } if(isset($headers['content-length'])) { $this->body = stream_get_contents($this->stream, $headers['content-length']); } else { $this->body = stream_get_contents($this->stream); } fclose($this->stream); $this->stream = null; } public function __destruct() { if(is_resource($this->stream)) { fclose($this->stream); $this->stream = null; } if($this->_cleanup) { @unlink($this->stream_name); } } } 'Continue', 101 => 'Switching Protocols', // SUCCESS CODES 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', // REDIRECTION CODES 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => 'Switch Proxy', // Deprecated 307 => 'Temporary Redirect', // CLIENT ERROR 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed', // SERVER ERROR 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported', ); /** * @var int Status code */ protected $statusCode = 200; /** * @var string|null Null means it will be looked up from the $reasonPhrase list above */ protected $reasonPhrase = null; /** * @var Headers */ protected $headers = null; /** * Populate object from string * * @param string $string * @return Response */ public static function fromString($string) { $lines = preg_split('/\r\n/', $string); if (!is_array($lines) || count($lines)==1) { $lines = preg_split ('/\n/',$string); } $firstLine = array_shift($lines); $response = new static(); $matches = null; if (!preg_match('/^HTTP\/(?P1\.[01]) (?P\d{3}) (?P.*)$/', $firstLine, $matches)) { throw new Exception\InvalidArgumentException('A valid response status line was not found in the provided string'); } $response->version = $matches['version']; if (!defined(get_called_class() . '::STATUS_CODE_' . $matches['status'])) { throw new Exception\InvalidArgumentException('Unknown status code found in provided string'); } $response->setStatusCode($matches['status']); $response->setReasonPhrase($matches['reason']); if (count($lines) == 0) { return $response; } $isHeader = true; $headers = $content = array(); while ($lines) { $nextLine = array_shift($lines); if ($nextLine == '') { $isHeader = false; continue; } if ($isHeader) { $headers[] .= $nextLine; } else { $content[] .= $nextLine; } } if ($headers) { $response->headers = implode("\r\n", $headers); } if ($content) { $response->setContent(implode("\r\n", $content)); } return $response; } /** * Render the status line header * * @return string */ public function renderStatusLine() { $status = sprintf( 'HTTP/%s %d %s', $this->getVersion(), $this->getStatusCode(), $this->getReasonPhrase() ); return trim($status); } /** * Set response headers * * @param Headers $headers * @return Response */ public function setHeaders(Headers $headers) { $this->headers = $headers; return $this; } /** * Get response headers * * @return Headers */ public function headers() { if ($this->headers === null || is_string($this->headers)) { $this->headers = (is_string($this->headers)) ? Headers::fromString($this->headers) : new Headers(); } return $this->headers; } /** * @return Header\SetCookie[] */ public function cookie() { return $this->headers()->get('Set-Cookie'); } /** * @param string $version * @return Response */ public function setVersion($version) { $this->version = $version; return $this; } /** * @return string */ public function getVersion() { return $this->version; } /** * Retrieve HTTP status code * * @return int */ public function getStatusCode() { return $this->statusCode; } /** * @param string $reasonPhrase * @return Response */ public function setReasonPhrase($reasonPhrase) { $this->reasonPhrase = trim($reasonPhrase); return $this; } /** * Get HTTP status message * * @return string */ public function getReasonPhrase() { if ($this->reasonPhrase == null) { return $this->recommendedReasonPhrases[$this->statusCode]; } return $this->reasonPhrase; } /** * Set HTTP status code and (optionally) message * * @param numeric $code * @return Response */ public function setStatusCode($code) { $const = get_called_class() . '::STATUS_CODE_' . $code; if (!is_numeric($code) || !defined($const)) { $code = is_scalar($code) ? $code : gettype($code); throw new Exception\InvalidArgumentException(sprintf( 'Invalid status code provided: "%s"', $code )); } $this->statusCode = $code; return $this; } public function setRawBody($body) { $this->setContent($body); return $this; } public function getRawBody() { return (string) $this->getContent(); } public function setBody($body, $encoding = null) { } /** * Get the body of the response * * @return string */ public function getBody() { $body = (string) $this->getContent(); $transferEncoding = $this->headers()->get('Transfer-Encoding'); if (!empty($transferEncoding)) { if (strtolower($transferEncoding->getFieldValue()) == 'chunked') { $body = $this->decodeChunkedBody($body); } } $contentEncoding = $this->headers()->get('Content-Encoding'); if (!empty($contentEncoding)) { $contentEncoding = $contentEncoding->getFieldValue(); if ($contentEncoding =='gzip') { $body = $this->decodeGzip($body); } elseif ($contentEncoding == 'deflate') { $body = $this->decodeDeflate($body); } } return $body; } /** * Does the status code indicate a client error? * * @return bool */ public function isClientError() { $code = $this->getStatusCode(); return ($code < 500 && $code >= 400); } /** * Is the request forbidden due to ACLs? * * @return bool */ public function isForbidden() { return (403 == $this->getStatusCode()); } /** * Is the current status "informational"? * * @return bool */ public function isInformational() { $code = $this->getStatusCode(); return ($code >= 100 && $code < 200); } /** * Does the status code indicate the resource is not found? * * @return bool */ public function isNotFound() { return (404 === $this->getStatusCode()); } /** * Do we have a normal, OK response? * * @return bool */ public function isOk() { return (200 === $this->getStatusCode()); } /** * Does the status code reflect a server error? * * @return bool */ public function isServerError() { $code = $this->getStatusCode(); return (500 <= $code && 600 > $code); } /** * Do we have a redirect? * * @return bool */ public function isRedirect() { $code = $this->getStatusCode(); return (300 <= $code && 400 > $code); } /** * Was the response successful? * * @return bool */ public function isSuccess() { $code = $this->getStatusCode(); return (200 <= $code && 300 > $code); } public function renderResponseLine() { return 'HTTP/' . $this->getVersion() . ' ' . $this->getStatusCode() . ' ' . $this->getReasonPhrase(); } public function toString() { $str = $this->renderResponseLine() . "\r\n"; $str .= $this->headers()->toString(); $str .= "\r\n"; $str .= $this->getBody(); return $str; } /** * Decode a "chunked" transfer-encoded body and return the decoded text * * @param string $body * @return string */ protected function decodeChunkedBody($body) { $decBody = ''; // If mbstring overloads substr and strlen functions, we have to // override it's internal encoding if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) { $mbIntEnc = mb_internal_encoding(); mb_internal_encoding('ASCII'); } while (trim($body)) { if (! preg_match("/^([\da-fA-F]+)[^\r\n]*\r\n/sm", $body, $m)) { throw new Exception\RuntimeException("Error parsing body - doesn't seem to be a chunked message"); } $length = hexdec(trim($m[1])); $cut = strlen($m[0]); $decBody .= substr($body, $cut, $length); $body = substr($body, $cut + $length + 2); } if (isset($mbIntEnc)) { mb_internal_encoding($mbIntEnc); } return $decBody; } /** * Decode a gzip encoded message (when Content-encoding = gzip) * * Currently requires PHP with zlib support * * @param string $body * @return string */ protected function decodeGzip($body) { if (!function_exists('gzinflate')) { throw new Exception\RuntimeException( 'zlib extension is required in order to decode "gzip" encoding' ); } return gzinflate(substr($body, 10)); } /** * Decode a zlib deflated message (when Content-encoding = deflate) * * Currently requires PHP with zlib support * * @param string $body * @return string */ protected function decodeDeflate($body) { if (!function_exists('gzuncompress')) { throw new Exception\RuntimeException( 'zlib extension is required in order to decode "deflate" encoding' ); } /** * Some servers (IIS ?) send a broken deflate response, without the * RFC-required zlib header. * * We try to detect the zlib header, and if it does not exsit we * teat the body is plain DEFLATE content. * * This method was adapted from PEAR HTTP_Request2 by (c) Alexey Borzov * * @link http://framework.zend.com/issues/browse/ZF-6040 */ $zlibHeader = unpack('n', substr($body, 0, 2)); if ($zlibHeader[1] % 31 == 0) { return gzuncompress($body); } else { return gzinflate($body); } } }