From c8f6e11b0c722b6a19071655aaf3987cd4e719f5 Mon Sep 17 00:00:00 2001 From: Gary Hockin Date: Fri, 6 Nov 2015 08:17:34 -0500 Subject: [PATCH] Added base documentation --- doc/book/zend.http.client-static.md | 54 ++ doc/book/zend.http.client.adapters.md | 451 +++++++++++ doc/book/zend.http.client.advanced.md | 341 ++++++++ doc/book/zend.http.client.md | 230 ++++++ doc/book/zend.http.headers.md | 1052 +++++++++++++++++++++++++ doc/book/zend.http.request.md | 451 +++++++++++ doc/book/zend.http.response.md | 352 +++++++++ doc/bookdown.json | 13 + 8 files changed, 2944 insertions(+) create mode 100644 doc/book/zend.http.client-static.md create mode 100644 doc/book/zend.http.client.adapters.md create mode 100644 doc/book/zend.http.client.advanced.md create mode 100644 doc/book/zend.http.client.md create mode 100644 doc/book/zend.http.headers.md create mode 100644 doc/book/zend.http.request.md create mode 100644 doc/book/zend.http.response.md create mode 100644 doc/bookdown.json diff --git a/doc/book/zend.http.client-static.md b/doc/book/zend.http.client-static.md new file mode 100644 index 0000000000..d5921aa1cd --- /dev/null +++ b/doc/book/zend.http.client-static.md @@ -0,0 +1,54 @@ +# HTTP Client - Static Usage + +## Overview + +The `Zend\Http` component also provides `Zend\Http\ClientStatic`, a static HTTP client which exposes +a simplified API for quickly performing GET and POST operations: + +## Quick Start + +```php +use Zend\Http\ClientStatic; + +// Simple GET request +$response = ClientStatic::get('http://example.org'); + +// More complex GET request, specifying query string 'foo=bar' and adding a +// custom header to request JSON data be returned (Accept: application/json) +$response = ClientStatic::get( + 'http://example.org', + array('foo' => 'bar'), + array('Accept' => 'application/json') +); + +// We can also do a POST request using the same format. Here we POST +// login credentials (username/password) to a login page: +$response = ClientStatic::post('https://example.org/login.php', array( + 'username' => 'foo', + 'password' => 'bar', +)); +``` + +## Available Methods + +**get** +`get(string $url, array $query = array(), array $headers = array(), mixed $body = null, +$clientOptions = null)` + +Perform an HTTP `GET` request using the provided URL, query string variables, headers and request +body. The fifth parameter can be used to pass configuration options to the HTTP Client instance. + +Returns Zend\\Http\\Response + + + +**post** +`post(string $url, array $params, array $headers = array(), mixed $body = null, $clientOptions = +null)` + +Perform an HTTP `POST` request using the provided URL, parameters, headers and request body. The +fifth parameter can be used to pass configuration options to the HTTP Client instance. + +Returns Zend\\Http\\Response + + diff --git a/doc/book/zend.http.client.adapters.md b/doc/book/zend.http.client.adapters.md new file mode 100644 index 0000000000..a346326c8d --- /dev/null +++ b/doc/book/zend.http.client.adapters.md @@ -0,0 +1,451 @@ +# HTTP Client - Connection Adapters + +## Overview + +`Zend\Http\Client` is based on a connection adapter design. The connection adapter is the object in +charge of performing the actual connection to the server, as well as writing requests and reading +responses. This connection adapter can be replaced, and you can create and extend the default +connection adapters to suite your special needs, without the need to extend or replace the entire +*HTTP* client class, and with the same interface. + +Currently, the `Zend\Http\Client` class provides four built-in connection adapters: + +- `Zend\Http\Client\Adapter\Socket` (default) +- `Zend\Http\Client\Adapter\Proxy` +- `Zend\Http\Client\Adapter\Curl` +- `Zend\Http\Client\Adapter\Test` + +The `Zend\Http\Client` object's adapter connection adapter is set using the 'adapter' configuration +option. When instantiating the client object, you can set the 'adapter' configuration option to a +string containing the adapter's name (eg. 'Zend\\Http\\Client\\Adapter\\Socket') or to a variable +holding an adapter object (eg. `new Zend\Http\Client\Adapter\Socket`). You can also set the adapter +later, using the `Zend\Http\Client->setAdapter()` method. + +## The Socket Adapter + +The default connection adapter is the `Zend\Http\Client\Adapter\Socket` adapter - this adapter will +be used unless you explicitly set the connection adapter. The Socket adapter is based on *PHP*'s +built-in fsockopen() function, and does not require any special extensions or compilation flags. + +The Socket adapter allows several extra configuration options that can be set using +`Zend\Http\Client->setOptions()` or passed to the client constructor. + +> ## Note +#### Persistent TCP Connections +Using persistent *TCP* connections can potentially speed up *HTTP* requests - but in most use cases, +will have little positive effect and might overload the *HTTP* server you are connecting to. +It is recommended to use persistent *TCP* connections only if you connect to the same server very +frequently, and are sure that the server is capable of handling a large number of concurrent +connections. In any case you are encouraged to benchmark the effect of persistent connections on +both the client speed and server load before using this option. +Additionally, when using persistent connections it is recommended to enable Keep-Alive *HTTP* +requests as described in \[the configuration section\](zend.http.client.options)- otherwise +persistent connections might have little or no effect. +#### note +#### HTTPS SSL Stream Parameters +`ssltransport`, `sslcert` and `sslpassphrase` are only relevant when connecting using *HTTPS*. +While the default *SSL* settings should work for most applications, you might need to change them if +the server you are connecting to requires special client setup. If so, you should read the sections +about *SSL* transport layers and options +[here](http://www.php.net/manual/en/transports.php#transports.inet). + +**Changing the HTTPS transport layer** + +```php +// Set the configuration parameters +$config = array( + 'adapter' => 'Zend\Http\Client\Adapter\Socket', + 'ssltransport' => 'tls' +); + +// Instantiate a client object +$client = new Zend\Http\Client('https://www.example.com', $config); + +// The following request will be sent over a TLS secure connection. +$response = $client->send(); +``` + +The result of the example above will be similar to opening a *TCP* connection using the following +*PHP* command: + +`fsockopen('tls://www.example.com', 443)` + +### Customizing and accessing the Socket adapter stream context + +`Zend\Http\Client\Adapter\Socket` provides direct access to the underlying [stream +context](http://php.net/manual/en/stream.contexts.php) used to connect to the remote server. This +allows the user to pass specific options and parameters to the *TCP* stream, and to the *SSL* +wrapper in case of *HTTPS* connections. + +You can access the stream context using the following methods of `Zend\Http\Client\Adapter\Socket`: + +> - **setStreamContext($context)** Sets the stream context to be used by the adapter. Can accept +either a stream context resource created using the +[stream\_context\_create()](http://php.net/manual/en/function.stream-context-create.php) *PHP* +function, or an array of stream context options, in the same format provided to this function. +Providing an array will create a new stream context using these options, and set it. +- **getStreamContext()** Get the stream context of the adapter. If no stream context was set, will +create a default stream context and return it. You can then set or get the value of different +context options using regular *PHP* stream context functions. + +**Setting stream context options for the Socket adapter** + +```php +// Array of options +$options = array( + 'socket' => array( + // Bind local socket side to a specific interface + 'bindto' => '10.1.2.3:50505' + ), + 'ssl' => array( + // Verify server side certificate, + // do not accept invalid or self-signed SSL certificates + 'verify_peer' => true, + 'allow_self_signed' => false, + + // Capture the peer's certificate + 'capture_peer_cert' => true + ) +); + +// Create an adapter object and attach it to the HTTP client +$adapter = new Zend\Http\Client\Adapter\Socket(); +$client = new Zend\Http\Client(); +$client->setAdapter($adapter); + +// Method 1: pass the options array to setStreamContext() +$adapter->setStreamContext($options); + +// Method 2: create a stream context and pass it to setStreamContext() +$context = stream_context_create($options); +$adapter->setStreamContext($context); + +// Method 3: get the default stream context and set the options on it +$context = $adapter->getStreamContext(); +stream_context_set_option($context, $options); + +// Now, perform the request +$response = $client->send(); + +// If everything went well, you can now access the context again +$opts = stream_context_get_options($adapter->getStreamContext()); +echo $opts['ssl']['peer_certificate']; +``` + +> ## Note +Note that you must set any stream context options before using the adapter to perform actual +requests. If no context is set before performing *HTTP* requests with the Socket adapter, a default +stream context will be created. This context resource could be accessed after performing any +requests using the `getStreamContext()` method. + +## The Proxy Adapter + +The `Zend\Http\Client\Adapter\Proxy` adapter is similar to the default Socket adapter - only the +connection is made through an *HTTP* proxy server instead of a direct connection to the target +server. This allows usage of `Zend\Http\Client` behind proxy servers - which is sometimes needed for +security or performance reasons. + +Using the Proxy adapter requires several additional configuration parameters to be set, in addition +to the default 'adapter' option: + +`proxy_host` should always be set - if it is not set, the client will fall back to a direct +connection using `Zend\Http\Client\Adapter\Socket`. `proxy_port` defaults to '8080' - if your proxy +listens on a different port you must set this one as well. + +`proxy_user` and `proxy_pass` are only required if your proxy server requires you to authenticate. +Providing these will add a 'Proxy-Authentication' header to the request. If your proxy does not +require authentication, you can leave these two options out. + +`proxy_auth` sets the proxy authentication type, if your proxy server requires authentication. +Possibly values are similar to the ones accepted by the `Zend\Http\Client::setAuth()` method. +Currently, only basic authentication (`Zend\Http\Client::AUTH_BASIC`) is supported. + +**Using Zend\\Http\\Client behind a proxy server** + +```php +// Set the configuration parameters +$config = array( + 'adapter' => 'Zend\Http\Client\Adapter\Proxy', + 'proxy_host' => 'proxy.int.zend.com', + 'proxy_port' => 8000, + 'proxy_user' => 'shahar.e', + 'proxy_pass' => 'bananashaped' +); + +// Instantiate a client object +$client = new Zend\Http\Client('http://www.example.com', $config); + +// Continue working... +``` + +As mentioned, if `proxy_host` is not set or is set to a blank string, the connection will fall back +to a regular direct connection. This allows you to easily write your application in a way that +allows a proxy to be used optionally, according to a configuration parameter. + +> ## Note +Since the proxy adapter inherits from `Zend\Http\Client\Adapter\Socket`, you can use the stream +context access method (see \[this section\](zend.http.client.adapters.socket.streamcontext)) to set +stream context options on Proxy connections as demonstrated above. + +## The cURL Adapter + +cURL is a standard *HTTP* client library that is distributed with many operating systems and can be +used in *PHP* via the cURL extension. It offers functionality for many special cases which can occur +for a *HTTP* client and make it a perfect choice for a *HTTP* adapter. It supports secure +connections, proxy, all sorts of authentication mechanisms and shines in applications that move +large files around between servers. + +**Setting cURL options** + +```php +$config = array( + 'adapter' => 'Zend\Http\Client\Adapter\Curl', + 'curloptions' => array(CURLOPT_FOLLOWLOCATION => true), +); +$client = new Zend\Http\Client($uri, $config); +``` + +By default the cURL adapter is configured to behave exactly like the Socket Adapter and it also +accepts the same configuration parameters as the Socket and Proxy adapters. You can also change the +cURL options by either specifying the 'curloptions' key in the constructor of the adapter or by +calling `setCurlOption($name, $value)`. The `$name` key corresponds to the CURL\_\* constants of the +cURL extension. You can get access to the Curl handle by calling `$adapter->getHandle();` + +**Transfering Files by Handle** + +You can use cURL to transfer very large files over *HTTP* by filehandle. + +```php +$putFileSize = filesize("filepath"); +$putFileHandle = fopen("filepath", "r"); + +$adapter = new Zend\Http\Client\Adapter\Curl(); +$client = new Zend\Http\Client(); +$client->setAdapter($adapter); +$client->setMethod('PUT'); +$adapter->setOptions(array( + 'curloptions' => array( + CURLOPT_INFILE => $putFileHandle, + CURLOPT_INFILESIZE => $putFileSize + ) +)); +$client->send(); +``` + +## The Test Adapter + +Sometimes, it is very hard to test code that relies on *HTTP* connections. For example, testing an +application that pulls an *RSS* feed from a remote server will require a network connection, which +is not always available. + +For this reason, the `Zend\Http\Client\Adapter\Test` adapter is provided. You can write your +application to use `Zend\Http\Client`, and just for testing purposes, for example in your unit +testing suite, you can replace the default adapter with a Test adapter (a mock object), allowing you +to run tests without actually performing server connections. + +The `Zend\Http\Client\Adapter\Test` adapter provides an additional method, `setResponse()`. This +method takes one parameter, which represents an *HTTP* response as either text or a +`Zend\Http\Response` object. Once set, your Test adapter will always return this response, without +even performing an actual *HTTP* request. + +**Testing Against a Single HTTP Response Stub** + +```php +// Instantiate a new adapter and client +$adapter = new Zend\Http\Client\Adapter\Test(); +$client = new Zend\Http\Client('http://www.example.com', array( + 'adapter' => $adapter +)); + +// Set the expected response +$adapter->setResponse( + "HTTP/1.1 200 OK" . "\r\n" . + "Content-type: text/xml" . "\r\n" . + "\r\n" . + '' . + '' . + ' ' . + ' Premature Optimization' . + // and so on... + ''); + +$response = $client->send(); +// .. continue parsing $response.. +``` + +The above example shows how you can preset your *HTTP* client to return the response you need. Then, +you can continue testing your own code, without being dependent on a network connection, the +server's response, etc. In this case, the test would continue to check how the application parses +the *XML* in the response body. + +Sometimes, a single method call to an object can result in that object performing multiple *HTTP* +transactions. In this case, it's not possible to use setResponse() alone because there's no +opportunity to set the next response(s) your program might need before returning to the caller. + +**Testing Against Multiple HTTP Response Stubs** + +```php +// Instantiate a new adapter and client +$adapter = new Zend\Http\Client\Adapter\Test(); +$client = new Zend\Http\Client('http://www.example.com', array( + 'adapter' => $adapter +)); + +// Set the first expected response +$adapter->setResponse( + "HTTP/1.1 302 Found" . "\r\n" . + "Location: /" . "\r\n" . + "Content-Type: text/html" . "\r\n" . + "\r\n" . + '' . + ' Moved' . + '

This page has moved.

' . + ''); + +// Set the next successive response +$adapter->addResponse( + "HTTP/1.1 200 OK" . "\r\n" . + "Content-Type: text/html" . "\r\n" . + "\r\n" . + '' . + ' My Pet Store Home Page' . + '

...

' . + ''); + +// inject the http client object ($client) into your object +// being tested and then test your object's behavior below +``` + +The `setResponse()` method clears any responses in the `Zend\Http\Client\Adapter\Test`'s buffer and +sets the first response that will be returned. The `addResponse()` method will add successive +responses. + +The responses will be replayed in the order that they were added. If more requests are made than the +number of responses stored, the responses will cycle again in order. + +In the example above, the adapter is configured to test your object's behavior when it encounters a +302 redirect. Depending on your application, following a redirect may or may not be desired +behavior. In our example, we expect that the redirect will be followed and we configure the test +adapter to help us test this. The initial 302 response is set up with the `setResponse()` method and +the 200 response to be returned next is added with the `addResponse()` method. After configuring the +test adapter, inject the *HTTP* client containing the adapter into your object under test and test +its behavior. + +If you need the adapter to fail on demand you can use `setNextRequestWillFail($flag)`. The method +will cause the next call to `connect()` to throw an +`Zend\Http\Client\Adapter\Exception\RuntimeException` exception. This can be useful when our +application caches content from an external site (in case the site goes down) and you want to test +this feature. + +**Forcing the adapter to fail** + +```php +// Instantiate a new adapter and client +$adapter = new Zend\Http\Client\Adapter\Test(); +$client = new Zend\Http\Client('http://www.example.com', array( + 'adapter' => $adapter +)); + +// Force the next request to fail with an exception +$adapter->setNextRequestWillFail(true); + +try { + // This call will result in a Zend\Http\Client\Adapter\Exception\RuntimeException + $client->send(); +} catch (Zend\Http\Client\Adapter\Exception\RuntimeException $e) { + // ... +} + +// Further requests will work as expected until +// you call setNextRequestWillFail(true) again +``` + +## Creating your own connection adapters + +`Zend\Http\Client` has been designed so that you can create and use your own connection adapters. +You could, for example, create a connection adapter that uses persistent sockets, or a connection +adapter with caching abilities, and use them as needed in your application. + +In order to do so, you must create your own adapter class that implements the +`Zend\Http\Client\Adapter\AdapterInterface` interface. The following example shows the skeleton of a +user-implemented adapter class. All the public functions defined in this example must be defined in +your adapter as well: + +**Creating your own connection adapter** + +```php +class MyApp\Http\Client\Adapter\BananaProtocol + implements Zend\Http\Client\Adapter\AdapterInterface +{ + /** + * Set Adapter Options + * + * @param array $config + */ + public function setOptions($config = array()) + { + // This rarely changes - you should usually copy the + // implementation in Zend\Http\Client\Adapter\Socket. + } + + /** + * Connect to the remote server + * + * @param string $host + * @param int $port + * @param boolean $secure + */ + public function connect($host, $port = 80, $secure = false) + { + // Set up the connection to the remote server + } + + /** + * Send request to the remote server + * + * @param string $method + * @param Zend\Uri\Http $url + * @param string $http_ver + * @param array $headers + * @param string $body + * @return string Request as text + */ + public function write($method, + $url, + $http_ver = '1.1', + $headers = array(), + $body = '') + { + // Send request to the remote server. + // This function is expected to return the full request + // (headers and body) as a string + } + + /** + * Read response from server + * + * @return string + */ + public function read() + { + // Read response from remote server and return it as a string + } + + /** + * Close the connection to the server + * + */ + public function close() + { + // Close the connection to the remote server - called last. + } +} + +// Then, you could use this adapter: +$client = new Zend\Http\Client(array( + 'adapter' => 'MyApp\Http\Client\Adapter\BananaProtocol' +)); +``` diff --git a/doc/book/zend.http.client.advanced.md b/doc/book/zend.http.client.advanced.md new file mode 100644 index 0000000000..307d9dd163 --- /dev/null +++ b/doc/book/zend.http.client.advanced.md @@ -0,0 +1,341 @@ +# HTTP Client - Advanced Usage + +## HTTP Redirections + +`Zend\Http\Client` automatically handles *HTTP* redirections, and by default will follow up to 5 +redirections. This can be changed by setting the `maxredirects` configuration parameter. + +According to the *HTTP*/1.1 RFC, *HTTP* 301 and 302 responses should be treated by the client by +resending the same request to the specified location - using the same request method. However, most +clients to not implement this and always use a `GET` request when redirecting. By default, +`Zend\Http\Client` does the same - when redirecting on a 301 or 302 response, all `GET` and POST +parameters are reset, and a `GET` request is sent to the new location. This behavior can be changed +by setting the `strictredirects` configuration parameter to boolean `TRUE`: + +**Forcing RFC 2616 Strict Redirections on 301 and 302 Responses** + +```php +// Strict Redirections +$client->setOptions(array('strictredirects' => true)); + +// Non-strict Redirections +$client->setOptions(array('strictredirects' => false)); +``` + +You can always get the number of redirections done after sending a request using the +`getRedirectionsCount()` method. + +## Adding Cookies and Using Cookie Persistence + +`Zend\Http\Client` provides an easy interface for adding cookies to your request, so that no direct +header modification is required. Cookies can be added using either the addCookie() or `setCookies` +method. The `addCookie` method has a number of operating modes: + +**Setting Cookies Using addCookie()** + +```php +// Easy and simple: by providing a cookie name and cookie value +$client->addCookie('flavor', 'chocolate chips'); + +// By providing a Zend\Http\Header\SetCookie object +$cookie = Zend\Http\Header\SetCookie::fromString('Set-Cookie: flavor=chocolate%20chips'); +$client->addCookie($cookie); + +// Multiple cookies can be set at once by providing an +// array of Zend\Http\Header\SetCookie objects +$cookies = array( + Zend\Http\Header\SetCookie::fromString('Set-Cookie: flavorOne=chocolate%20chips'), + Zend\Http\Header\SetCookie::fromString('Set-Cookie: flavorTwo=vanilla'), +); +$client->addCookie($cookies); +``` + +The `setCookies()` method works in a similar manner, except that it requires an array of cookie +values as its only argument and also clears the cookie container before adding the new cookies: + +**Setting Cookies Using setCookies()** + +```php +// setCookies accepts an array of cookie values as $name => $value +$client->setCookies(array( + 'flavor' => 'chocolate chips', + 'amount' => 10, +)); +``` + +For more information about `Zend\Http\Header\SetCookie` objects, see \[this +section\](zend.http.headers). + +`Zend\Http\Client` also provides a means for simplifying cookie stickiness - that is having the +client internally store all sent and received cookies, and resend them on subsequent requests: +`Zend\Http\Cookies`. This is useful, for example when you need to log in to a remote site first and +receive and authentication or session ID cookie before sending further requests. + +**Enabling Cookie Stickiness** + +```php +$headers = $client->getRequest()->getHeaders(); +$cookies = new Zend\Http\Cookies($headers); + +// First request: log in and start a session +$client->setUri('http://example.com/login.php'); +$client->setParameterPost(array('user' => 'h4x0r', 'password' => 'l33t')); +$client->setMethod('POST'); + +$response = $client->getResponse(); +$cookies->addCookiesFromResponse($response, $client->getUri()); + +// Now we can send our next request +$client->setUri('http://example.com/read_member_news.php'); +$client->setCookies($cookies->getMatchingCookies($client->getUri())); +$client->setMethod('GET'); +``` + +For more information about the `Zend\Http\Cookies` class, see this section +<zend.http.client.cookies>. + +## Setting Custom Request Headers + +Setting custom headers is performed by first fetching the header container from the client's +`Zend\Http\Request` object. This method is quite diverse and can be used in several ways, as the +following example shows: + +**Setting A Single Custom Request Header** + +```php +// Fetch the container +$headers = $client->getRequest()->getHeaders(); + +// Setting a single header. Will not overwrite any +// previously-added headers of the same name. +$headers->addHeaderLine('Host', 'www.example.com'); + +// Another way of doing the exact same thing +$headers->addHeaderLine('Host: www.example.com'); + +// Another way of doing the exact same thing using +// the provided Zend\Http\Header class +$headers->addHeader(Zend\Http\Header\Host::fromString('Host: www.example.com')); + +// You can also add multiple headers at once by passing an +// array to addHeaders using any of the formats below: +$headers->addHeaders(array( + // Zend\Http\Header\* object + Zend\Http\Header\Host::fromString('Host: www.example.com'), + + // Header name as array key, header value as array key value + 'Cookie' => 'PHPSESSID=1234567890abcdef1234567890abcdef', + + // Raw header string + 'Cookie: language=he', +)); +``` + +`Zend\Http\Client` also provides a convenience method for setting request headers, `setHeaders`. +This method will create a new header container, add the specified headers and then store the new +header container in it's `Zend\Http\Request` object. As a consequence, any pre-existing headers will +be erased. + +**Setting Multiple Custom Request Headers** + +```php +// Setting multiple headers. Will remove all existing +// headers and add new ones to the Request header container +$client->setHeaders(array( + Zend\Http\Header\Host::fromString('Host: www.example.com'), + 'Accept-Encoding' => 'gzip,deflate', + 'X-Powered-By: Zend Framework', +)); +``` + +## File Uploads + +You can upload files through *HTTP* using the setFileUpload method. This method takes a file name as +the first parameter, a form name as the second parameter, and data as a third optional parameter. If +the third data parameter is `NULL`, the first file name parameter is considered to be a real file on +disk, and `Zend\Http\Client` will try to read this file and upload it. If the data parameter is not +`NULL`, the first file name parameter will be sent as the file name, but no actual file needs to +exist on the disk. The second form name parameter is always required, and is equivalent to the +"name" attribute of an `` tag, if the file was to be uploaded through an *HTML* form. A +fourth optional parameter provides the file's content-type. If not specified, and `Zend\Http\Client` +reads the file from the disk, the `mime_content_type` function will be used to guess the file's +content type, if it is available. In any case, the default MIME type will be +application/octet-stream. + +**Using setFileUpload to Upload Files** + +```php +// Uploading arbitrary data as a file +$text = 'this is some plain text'; +$client->setFileUpload('some_text.txt', 'upload', $text, 'text/plain'); + +// Uploading an existing file +$client->setFileUpload('/tmp/Backup.tar.gz', 'bufile'); + +// Send the files +$client->setMethod('POST'); +$client->send(); +``` + +In the first example, the `$text` variable is uploaded and will be available as `$_FILES['upload']` +on the server side. In the second example, the existing file `/tmp/Backup.tar.gz` is uploaded to the +server and will be available as `$_FILES['bufile']`. The content type will be guessed automatically +if possible - and if not, the content type will be set to 'application/octet-stream'. + +> ## Note +#### Uploading files +When uploading files, the *HTTP* request content-type is automatically set to multipart/form-data. +Keep in mind that you must send a POST or PUT request in order to upload files. Most servers will +ignore the request body on other request methods. + +## Sending Raw POST Data + +You can use a `Zend\Http\Client` to send raw POST data using the `setRawBody()` method. This method +takes one parameter: the data to send in the request body. When sending raw POST data, it is +advisable to also set the encoding type using `setEncType()`. + +**Sending Raw POST Data** + +```php +$xml = '' . + ' Islands in the Stream' . + ' Ernest Hemingway' . + ' 1970' . + ''; +$client->setMethod('POST'); +$client->setRawBody($xml); +$client->setEncType('text/xml'); +$client->send(); +``` + +The data should be available on the server side through *PHP*'s `$HTTP_RAW_POST_DATA` variable or +through the `php://input` stream. + +> ## Note +#### Using raw POST data +Setting raw POST data for a request will override any POST parameters or file uploads. You should +not try to use both on the same request. Keep in mind that most servers will ignore the request body +unless you send a POST request. + +## HTTP Authentication + +Currently, `Zend\Http\Client` only supports basic *HTTP* authentication. This feature is utilized +using the `setAuth()` method, or by specifying a username and a password in the URI. The `setAuth()` +method takes 3 parameters: The user name, the password and an optional authentication type +parameter. As mentioned, currently only basic authentication is supported (digest authentication +support is planned). + +**Setting HTTP Authentication User and Password** + +```php +// Using basic authentication +$client->setAuth('shahar', 'myPassword!', Zend\Http\Client::AUTH_BASIC); + +// Since basic auth is default, you can just do this: +$client->setAuth('shahar', 'myPassword!'); + +// You can also specify username and password in the URI +$client->setUri('http://christer:secret@example.com'); +``` + +## Sending Multiple Requests With the Same Client + +`Zend\Http\Client` was also designed specifically to handle several consecutive requests with the +same object. This is useful in cases where a script requires data to be fetched from several places, +or when accessing a specific *HTTP* resource requires logging in and obtaining a session cookie, for +example. + +When performing several requests to the same host, it is highly recommended to enable the +'keepalive' configuration flag. This way, if the server supports keep-alive connections, the +connection to the server will only be closed once all requests are done and the Client object is +destroyed. This prevents the overhead of opening and closing *TCP* connections to the server. + +When you perform several requests with the same client, but want to make sure all the +request-specific parameters are cleared, you should use the `resetParameters()` method. This ensures +that GET and POST parameters, request body and headers are reset and are not reused in the next +request. + +> ## Note +#### Resetting parameters +Note that cookies are not reset by default when the `resetParameters()` method is used. To clean all +cookies as well, use `resetParameters(true)`, or call `clearCookies()` after calling +`resetParameters()`. + +Another feature designed specifically for consecutive requests is the `Zend\Http\Cookies` object. +This "Cookie Jar" allow you to save cookies set by the server in a request, and send them back on +consecutive requests transparently. This allows, for example, going through an authentication +request before sending the actual data-fetching request. + +If your application requires one authentication request per user, and consecutive requests might be +performed in more than one script in your application, it might be a good idea to store the Cookies +object in the user's session. This way, you will only need to authenticate the user once every +session. + +**Performing consecutive requests with one client** + +```php +// First, instantiate the client +$client = new Zend\Http\Client('http://www.example.com/fetchdata.php', array( + 'keepalive' => true +)); + +// Do we have the cookies stored in our session? +if (isset($_SESSION['cookiejar']) && + $_SESSION['cookiejar'] instanceof Zend\Http\Cookies) { + + $cookieJar = $_SESSION['cookiejar']; +} else { + // If we don't, authenticate and store cookies + $client->setUri('http://www.example.com/login.php'); + $client->setParameterPost(array( + 'user' => 'shahar', + 'pass' => 'somesecret' + )); + $response = $client->setMethod('POST')->send(); + $cookieJar = Zend\Http\Cookies::fromResponse($response); + + // Now, clear parameters and set the URI to the original one + // (note that the cookies that were set by the server are now + // stored in the jar) + $client->resetParameters(); + $client->setUri('http://www.example.com/fetchdata.php'); +} + +// Add the cookies to the new request +$client->setCookies($cookieJar->getMatchingCookies($client->getUri())); +$response = $client->setMethod('GET')->send(); + +// Store cookies in session, for next page +$_SESSION['cookiejar'] = $cookieJar; +``` + +## Data Streaming + +By default, `Zend\Http\Client` accepts and returns data as *PHP* strings. However, in many cases +there are big files to be received, thus keeping them in memory might be unnecessary or too +expensive. For these cases, `Zend\Http\Client` supports writing data to files (streams). + +In order to receive data from the server as stream, use `setStream()`. Optional argument specifies +the filename where the data will be stored. If the argument is just `TRUE` (default), temporary file +will be used and will be deleted once response object is destroyed. Setting argument to `FALSE` +disables the streaming functionality. + +When using streaming, `send()` method will return object of class `Zend\Http\Response\Stream`, which +has two useful methods: `getStreamName()` will return the name of the file where the response is +stored, and `getStream()` will return stream from which the response could be read. + +You can either write the response to pre-defined file, or use temporary file for storing it and send +it out or write it to another file using regular stream functions. + +> ## Receiving file from HTTP server with streaming +```php +$client-setStream(); // will use temp file +$response = $client-send(); +// copy file +copy($response-getStreamName(), "my/downloads/file"); +// use stream +$fp = fopen("my/downloads/file2", "w"); +stream_copy_to_stream($response-getStream(), $fp); +// Also can write to known file +$client-setStream("my/downloads/myfile")-send(); +``` diff --git a/doc/book/zend.http.client.md b/doc/book/zend.http.client.md new file mode 100644 index 0000000000..e54c5b3fd1 --- /dev/null +++ b/doc/book/zend.http.client.md @@ -0,0 +1,230 @@ +# HTTP Client + +## Overview + +`Zend\Http\Client` provides an easy interface for performing Hyper-Text Transfer Protocol (HTTP) +requests. `Zend\Http\Client` supports the most simple features expected from an *HTTP* client, as +well as some more complex features such as *HTTP* authentication and file uploads. Successful +requests (and most unsuccessful ones too) return a `Zend\Http\Response` object, which provides +access to the response's headers and body (see this +section <zend.http.response>). + +## Quick Start + +The class constructor optionally accepts a URL as its first parameter (can be either a string or a +`Zend\Uri\Http` object), and an array or `Zend\Config\Config` object containing configuration +options. The `send()` method is used to submit the request to the remote server, and a +`Zend\Http\Response` object is returned: + +```php +use Zend\Http\Client; + +$client = new Client('http://example.org', array( + 'maxredirects' => 0, + 'timeout' => 30 +)); +$response = $client->send(); +``` + +Both constructor parameters can be left out, and set later using the setUri() and setConfig() +methods: + +```php +use Zend\Http\Client; + +$client = new Client(); +$client->setUri('http://example.org'); +$client->setOptions(array( + 'maxredirects' => 0, + 'timeout' => 30 +)); +$response = $client->send(); +``` + +`Zend\Http\Client` can also dispatch requests using a separately configured `request` object (see +the Zend\\\\Http\\\\Request manual page<zend.http.request> for full details of the methods +available): + +```php +use Zend\Http\Client; +use Zend\Http\Request; + +$request = new Request(); +$request->setUri('http://example.org'); + +$client = new Client(); + +$response = $client->send($request); +``` + +> ## Note +`Zend\Http\Client` uses `Zend\Uri\Http` to validate URLs. See the Zend\\\\Uri manual +page<zend.uri> for more information on the validation process. + +## Configuration + +The constructor and setOptions() method accepts an associative array of configuration parameters, or +a `Zend\Config\Config` object. Setting these parameters is optional, as they all have default +values. + +The options are also passed to the adapter class upon instantiation, so the same array or +`Zend\Config\Config` object) can be used for adapter configuration. See the Zend Http Client adapter +section<zend.http.client.adapters> for more information on the adapter-specific options +available. + +## Examples + +### Performing a Simple GET Request + +Performing simple *HTTP* requests is very easily done: + +```php +use Zend\Http\Client; + +$client = new Client('http://example.org'); +$response = $client->send(); +``` + +### Using Request Methods Other Than GET + +The request method can be set using `setMethod()`. If no method is specified, the method set by the +last `setMethod()` call is used. If `setMethod()` was never called, the default request method is +`GET`. + +```php +use Zend\Http\Client; + +$client = new Client('http://example.org'); + +// Performing a POST request +$client->setMethod('POST'); +$response = $client->send(); +``` + +For convenience, `Zend\Http\Request` defines all the request methods as class constants, +`Zend\Http\Request::METHOD_GET`, `Zend\Http\Request::METHOD_POST` and so on: + +```php +use Zend\Http\Client; +use Zend\Http\Request; + +$client = new Client('http://example.org'); + +// Performing a POST request +$client->setMethod(Request::METHOD_POST); +$response = $client->send(); +``` + +### Setting GET parameters + +Adding `GET` parameters to an *HTTP* request is quite simple, and can be done either by specifying +them as part of the URL, or by using the `setParameterGet()` method. This method takes the `GET` +parameters as an associative array of name => value `GET` variables. + +```php +use Zend\Http\Client; +$client = new Client(); + +// This is equivalent to setting a URL in the Client's constructor: +$client->setUri('http://example.com/index.php?knight=lancelot'); + +// Adding several parameters with one call +$client->setParameterGet(array( + 'first_name' => 'Bender', + 'middle_name' => 'Bending', + 'last_name' => 'Rodríguez', + 'made_in' => 'Mexico', +)); +``` + +### Setting POST Parameters + +While `GET` parameters can be sent with every request method, `POST` parameters are only sent in the +body of `POST` requests. Adding `POST` parameters to a request is very similar to adding `GET` +parameters, and can be done with the `setParameterPost()` method, which is identical to the +`setParameterGet()` method in structure. + +```php +use Zend\Http\Client; + +$client = new Client(); + +// Setting several POST parameters, one of them with several values +$client->setParameterPost(array( + 'language' => 'es', + 'country' => 'ar', + 'selection' => array(45, 32, 80) +)); +``` + +Note that when sending `POST` requests, you can set both `GET` and `POST` parameters. On the other +hand, setting POST parameters on a non-`POST` request will not trigger an error, rendering it +useless. Unless the request is a `POST` request, `POST` parameters are simply ignored. + +### Connecting to SSL URLs + +If you are trying to connect to an SSL (https) URL and are using the default +(`Zend\Http\Client\Adapter\Socket`) adapter, you may need to set the `sslcapath` configuration +option in order to allow PHP to validate the SSL certificate: + +```php +use Zend\Http\Client; + +$client = new Client('https://example.org', array( + 'sslcapath' => '/etc/ssl/certs' +)); +$response = $client->send(); +``` + +The exact path to use will vary depending on your Operating System. Without this you'll get the +exception "Unable to enable crypto on TCP connection" when trying to connect. + +Alternatively, you could switch to the curl adapter, which negotiates SSL connections more +transparently: + +```php +use Zend\Http\Client; + +$client = new Client('https://example.org', array( + 'adapter' => 'Zend\Http\Client\Adapter\Curl' +)); +$response = $client->send(); +``` + +### A Complete Example + +```php +use Zend\Http\Client; + +$client = new Client(); +$client->setUri('http://www.example.com'); +$client->setMethod('POST'); +$client->setParameterPost(array( + 'foo' => 'bar' +)); + +$response = $client->send(); + +if ($response->isSuccess()) { + // the POST was successful +} +``` + +or the same thing, using a request object: + +```php +use Zend\Http\Client; +use Zend\Http\Request; + +$request = new Request(); +$request->setUri('http://www.example.com'); +$request->setMethod('POST'); +$request->getPost()->set('foo', 'bar'); + +$client = new Client(); +$response = $client->send($request); + +if ($response->isSuccess()) { + // the POST was successful +} +``` diff --git a/doc/book/zend.http.headers.md b/doc/book/zend.http.headers.md new file mode 100644 index 0000000000..67b89d69ee --- /dev/null +++ b/doc/book/zend.http.headers.md @@ -0,0 +1,1052 @@ +# The Headers Class + +## Overview + +The `Zend\Http\Headers` class is a container for HTTP headers. It is typically accessed as part of a +`Zend\Http\Request` or `Zend\Http\Response` `getHeaders()` call. The Headers container will lazily +load actual Header objects as to reduce the overhead of header specific parsing. + +The `Zend\Http\Header\*` classes are the domain specific implementations for the various types of +Headers that one might encounter during the typical HTTP request. If a header of unknown type is +encountered, it will be implemented as a `Zend\Http\Header\GenericHeader` instance. See the below +table for a list of the various HTTP headers and the API that is specific to each header type. + +## Quick Start + +The quickest way to get started interacting with header objects is by getting an already populated +Headers container from a request or response object. + +```php +// $client is an instance of Zend\Http\Client + +// You can retrieve the request headers by first retrieving +// the Request object and then calling getHeaders on it +$requestHeaders = $client->getRequest()->getHeaders(); + +// The same method also works for retrieving Response headers +$responseHeaders = $client->getResponse()->getHeaders(); +``` + +`Zend\Http\Headers` can also extract headers from a string: + +```php +$headerString = << + +**setPluginClassLoader** +`setPluginClassLoader(Zend\Loader\PluginClassLocator $pluginClassLoader)` + +Set an alternate implementation for the plugin class loader + +Returns `Zend\Http\Headers` + + + +**getPluginClassLoader** +`getPluginClassLoader()` + +Return an instance of a `Zend\Loader\PluginClassLocator`, lazyload and inject map if necessary. + +Returns `Zend\Loader\PluginClassLocator` + + + +**addHeaders** +`addHeaders(array|Traversable $headers)` + +Add many headers at once + +Expects an array (or `Traversable` object) of type/value pairs. + +Returns `Zend\Http\Headers` + + + +**addHeaderLine** +`addHeaderLine(string $headerFieldNameOrLine, string $fieldValue)` + +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()`. + +Returns `Zend\Http\Headers` + + + +**addHeader** +`addHeader(Zend\Http\Header\HeaderInterface $header)` + +Add a Header to this container, for raw values see `addHeaderLine()` and `addHeaders()`. + +Returns `Zend\Http\Headers` + + + +**removeHeader** +`removeHeader(Zend\Http\Header\HeaderInterface $header)` + +Remove a Header from the container + +Returns bool + + + +**clearHeaders** +`clearHeaders()` + +Clear all headers + +Removes all headers from queue + +Returns `Zend\Http\Headers` + + + +**get** +`get(string $name)` + +Get all headers of a certain name/type + +Returns false| `Zend\Http\Header\HeaderInterface`| `ArrayIterator` + + + +**has** +`has(string $name)` + +Test for existence of a type of header + +Returns bool + + + +**next** +`next()` + +Advance the pointer for this object as an iterator + +Returns void + + + +**key** +`key()` + +Return the current key for this object as an iterator + +Returns mixed + + + +**valid** +`valid()` + +Is this iterator still valid? + +Returns bool + + + +**rewind** +`rewind()` + +Reset the internal pointer for this object as an iterator + +Returns void + + + +**current** +`current()` + +Return the current value for this iterator, lazy loading it if need be + +Returns `Zend\Http\Header\HeaderInterface` + + + +**count** +`count()` + +Return the number of headers in this container. 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. + +Returns int + + + +**toString** +`toString()` + +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. + +Returns string + + + +**toArray** +`toArray()` + +Return the headers container as an array + +Returns array + + + +**forceLoading** +`forceLoading()` + +By calling this, it will force parsing and loading of all headers, after this `count()` will be +accurate + +Returns bool + +## Zend\\Http\\Header\\HeaderInterface Methods + +**fromString** +`fromString(string $headerLine)` + +Factory to generate a header object from a string + +Returns `Zend\Http\Header\GenericHeader` + + + +**getFieldName** +`getFieldName()` + +Retrieve header field name + +Returns string + + + +**getFieldValue** +`getFieldValue()` + +Retrieve header field value + +Returns string + + + +**toString** +`toString()` + +Cast to string as a well formed HTTP header line + +Returns in form of "NAME: VALUE" + +Returns string + +## Zend\\Http\\Header\\AbstractAccept Methods + +**parseHeaderLine** +`parseHeaderLine(string $headerLine)` + +Parse the given header line and add the values + +Returns void + +**getFieldValuePartsFromHeaderLine** +`getFieldValuePartsFromHeaderLine(string $headerLine)` + +Parse the Field Value Parts represented by a header line + +Throws `Zend\Http\Header\Exception\InvalidArgumentException` if the header is invalid + +Returns array + +**getFieldValue** +`getFieldValue(array|null $values = null)` + +Get field value + +Returns string + +**match** +`match(array|string $matchAgainst)` + +Match a media string against this header. Returns the matched value or false + +Returns `Accept\FieldValuePart\AcceptFieldValuePart` or bool + +**getPrioritized** +`getPrioritized()` + +Returns all the keys, values and parameters this header represents + +Returns array + +## Zend\\Http\\Header\\AbstractDate Methods + +**setDateFormat** +static `setDateFormat(int $format)` + +Set date output format. + +Returns void + +**getDateFormat** +static `getDateFormat()` + +Return current date output format + +Returns string + +**setDate** +`setDate(string|DateTime $date)` + +Set the date for this header, this can be a string or an instance of DateTime + +Throws `Zend\Http\Header\Exception\InvalidArgumentException` if the date is neither a valid string +nor an instance of `\DateTime`. + +Returns self + +**getDate** +`getDate()` + +Return date for this header + +Returns self + +**compareTo** +`compareTo(string|DateTime $date)` + +Compare provided date to date for this header. Returns < 0 if date in header is less than +`$date`; > 0 if it's greater, and 0 if they are equal. See +[strcmp](http://www.php.net/manual/en/function.strcmp.php). + +Returns int + +**date** +`date()` + +Return date for this header as an instance of `\DateTime` + +Returns `\DateTime` + +**fromTimestamp** +`fromTimestamp(int $time)` + +Create date-based header from Unix timestamp + +Returns self + +**fromTimeString** +`fromTimeString(string $time)` + +Create date-based header from strtotime()-compatible string + +Returns self + +## Zend\\Http\\Header\\AbstractLocation Methods + +**setUri** +`setUri(string|Zend\Uri\UriInterface $uri)` + +Set the URI/URL for this header, this can be a string or an instance of `Zend\Uri\Http` + +Throws `Zend\Http\Header\Exception\InvalidArgumentException` if `$uri` is neither a valid URL nor an +instance of `Zend\Uri\UriInterface`. + +Returns self + +**getUri** +`getUri()` + +Return the URI for this header + +Returns string + +**uri** +`uri()` + +Return the URI for this header as an instance of `Zend\Uri\Http` + +Returns `Zend\Uri\UriInterface` + +## List of HTTP Header Types + +Some header classes expose methods for manipulating their value. The following list contains all of +the classes available in the `Zend\Http\Header\*` namespace, as well as any specific methods they +contain. All these classes implement `Zend\Http\Header\HeaderInterface` and its +methods<zend.http.headers.header-description>. + +**Accept** +See `Zend\Http\Header\AbstractAccept` methods<zend.http.header.abstractaccept.methods>. + +`addMediaType(string $type, int|float $priority = 1)` +Add a media type, with the given priority + +Returns self + +`hasMediaType(string $type)` +Does the header have the requested media type? + +Returns bool + + + +**AcceptCharset** +See `Zend\Http\Header\AbstractAccept` methods<zend.http.header.abstractaccept.methods>. + +`addCharset(string $type, int|float $priority = 1)` +Add a charset, with the given priority + +Returns self + +`hasCharset(string $type)` +Does the header have the requested charset? + +Returns bool + + + +**AcceptEncoding** +See `Zend\Http\Header\AbstractAccept` methods<zend.http.header.abstractaccept.methods>. + +`addEncoding(string $type, int|float $priority = 1)` +Add an encoding, with the given priority + +Returns self + +`hasEncoding(string $type)` +Does the header have the requested encoding? + +Returns bool + + + +**AcceptLanguage** +See `Zend\Http\Header\AbstractAccept` methods<zend.http.header.abstractaccept.methods>. + +`addLanguage(string $type, int|float $priority = 1)` +Add a language, with the given priority + +Returns self + +`hasLanguage(string $type)` +Does the header have the requested language? + +Returns bool + + + +**AcceptRanges** +`getRangeUnit()` + +`setRangeUnit($rangeUnit)` + + + +**Age** +`getDeltaSeconds()` +Get number of seconds + +Returns int + +`setDeltaSeconds()` +Set number of seconds + +Returns self + + + +**Allow** +`getAllMethods()` +Get list of all defined methods + +Returns array + +`getAllowedMethods()` +Get list of allowed methods + +Returns array + +`allowMethods(array|string $allowedMethods)` +Allow methods or list of methods + +Returns self + +`disallowMethods(array|string $allowedMethods)` +Disallow methods or list of methods + +Returns self + +`denyMethods(array|string $allowedMethods)` +Convenience alias for `disallowMethods()` + +Returns self + +`isAllowedMethod(string $method)` +Check whether method is allowed + +Returns bool + + + +**AuthenticationInfo** +No additional methods + + + +**Authorization** +No additional methods + + + +**CacheControl** +`isEmpty()` +Checks if the internal directives array is empty + +Returns bool + +`addDirective(string $key, string|bool $value)` +Add a directive + +For directives like 'max-age=60', $value = '60' + +For directives like 'private', use the default $value = true + +Returns self + +`hasDirective(string $key)` +Check the internal directives array for a directive + +Returns bool + +`getDirective(string $key)` +Fetch the value of a directive from the internal directive array + +Returns string|null + +`removeDirective(string $key)` +Remove a directive + +Returns self + + + +**Connection** +`setValue($value)` +Set arbitrary header value + +RFC allows any token as value, 'close' and 'keep-alive' are commonly used + +Returns self + +`isPersistent()` +Whether the connection is persistent + +Returns bool + +`setPersistent(bool $flag)` +Set Connection header to define persistent connection + +Returns self + + + +**ContentDisposition** +No additional methods + + + +**ContentEncoding** +No additional methods + + + +**ContentLanguage** +No additional methods + + + +**ContentLength** +No additional methods + + + +**ContentLocation** +See `Zend\Http\Header\AbstractLocation` methods<zend.http.header.abstractlocation.methods>. + + + +**ContentMD5** +No additional methods + + + +**ContentRange** +No additional methods + + + +**ContentSecurityPolicy** +`getDirectives()` +Retrieve the defined directives for the policy + +Returns an array + +`setDirective(string $name, array $sources)` +Set the directive with the given name to include the sources + +As an example: an auction site wishes to load images from any URI, plugin content from a list of +trusted media providers (including a content distribution network), and scripts only from a server +under its control hosting sanitized ECMAScript: + +```php +// http://www.w3.org/TR/2012/CR-CSP-20121115/#sample-policy-definitions +// Example #2 +$csp = new ContentSecurityPolicy(); +$csp->setDirective('default-src', array()) // No sources + ->setDirective('img-src', array('*')) + ->setDirective('object-src' array('media1.example.com', 'media2.example.com', +'*.cdn.example.com')) + ->setDirective('script-src', array('trustedscripts.example.com')); +``` + +Returns self + + + +**ContentTransferEncoding** +No additional methods + + + +**ContentType** +`match(array|string $matchAgainst)` +Determine if the mediatype value in this header matches the provided criteria + +Returns bool|string + +`getMediaType()` +Get the media type + +Returns string + +`setMediaType(string $mediaType)` +Set the media type + +Returns self + +`getParameters()` +Get any additional content-type parameters currently set + +Returns array + +`setParameters(array $parameters)` +Set additional content-type parameters + +Returns self + +`getCharset()` +Get the content-type character set encoding, if any + +Returns string|null + +`setCharset(string $charset)` +Set the content-type character set encoding + +Returns self + + + +**Cookie** +Extends `ArrayObject` + +static `fromSetCookieArray(array $setCookies)` + +`setEncodeValue()` + +`getEncodeValue()` + + + +**Date** +See `Zend\Http\Header\AbstractDate` methods<zend.http.header.abstractdate.methods>. + + + +**Etag** +No additional methods + + + +**Expect** +No additional methods + + + +**Expires** +See `Zend\Http\Header\AbstractDate` methods<zend.http.header.abstractdate.methods>. + + + +**From** +No additional methods + + + +**Host** +No additional methods + + + +**IfMatch** +No additional methods + + + +**IfModifiedSince** +See `Zend\Http\Header\AbstractDate` methods<zend.http.header.abstractdate.methods>. + + + +**IfNoneMatch** +No additional methods + + + +**IfRange** +No additional methods + + + +**IfUnmodifiedSince** +See `Zend\Http\Header\AbstractDate` methods<zend.http.header.abstractdate.methods>. + + + +**KeepAlive** +No additional methods + + + +**LastModified** +See `Zend\Http\Header\AbstractDate` methods<zend.http.header.abstractdate.methods>. + + + +**Location** +See `Zend\Http\Header\AbstractLocation` methods<zend.http.header.abstractlocation.methods>. + + + +**MaxForwards** +No additional methods + + + +**Origin** +No additional methods + + + +**Pragma** +No additional methods + + + +**ProxyAuthenticate** +`toStringMultipleHeaders(array $headers)` + + + +**ProxyAuthorization** +No additional methods + + + +**Range** +No additional methods + + + +**Referer** +See `Zend\Http\Header\AbstractLocation` methods<zend.http.header.abstractlocation.methods>. + + + +**Refresh** +No additional methods + + + +**RetryAfter** +See `Zend\Http\Header\AbstractDate` methods<zend.http.header.abstractdate.methods>. + +`setDeltaSeconds(int $delta)` +Set number of seconds + +Returns self + +`getDeltaSeconds()` +Get number of seconds + +Returns int + + + +**Server** +No additional methods + + + +**SetCookie** +`getName()` / `setName(string $name)` +The cookie name + +`getValue()` / `setValue(string $value)` +The cookie value + +`getExpires()` / `setExpires(int|string $expires)` +The time frame the cookie is valid for, null is a session cookie + +`getPath()` / `setPath(string $path)` +The URI path the cookie is bound to + +`getDomain()` / `setDomain(string $domain)` +The domain the cookie applies to + +`getMaxAge()` / `setMaxAge(int $maxAge)` +The maximum age of the cookie + +`getVersion()` / `setVersion(int $version)` +The cookie version + +`isSecure()` +Whether the cookies contains the Secure flag + +Returns bool + +`setSecure(bool $secure)` +Set whether the cookies contains the Secure flag + +Returns self + +`isHttponly()` +Whether the cookies can be accessed via HTTP only + +Returns bool + +`setHttponly(bool $httponly)` +Set whether the cookies can be accessed via HTTP only + +Returns self + +`isExpired()` +Whether the cookie is expired + +Returns bool + +`isSessionCookie()` +Whether the cookie is a session cookie + +Returns bool + +`setQuoteFieldValue(bool $quotedValue)` +Set whether the value for this cookie should be quoted + +Returns self + +`hasQuoteFieldValue()` +Check whether the value for this cookie should be quoted + +Returns bool + +`isValidForRequest()` +Whether the cookie is valid for a given request domain, path and isSecure + +Returns bool + +`match(string $uri, bool $matchSessionCookies, int $now)` +Checks whether the cookie should be sent or not in a specific scenario + +Returns bool + +static `matchCookieDomain(string $cookieDomain, string $host)` +Check if a cookie's domain matches a host name. + +Returns bool + +static `matchCookiePath(string $cookiePath, string $path)` +Check if a cookie's path matches a URL path + +Returns bool + +`toStringMultipleHeaders(array $headers)` +Returns string + + + +**TE** +No additional methods + + + +**Trailer** +No additional methods + + + +**TransferEncoding** +No additional methods + + + +**Upgrade** +No additional methods + + + +**UserAgent** +No additional methods + + + +**Vary** +No additional methods + + + +**Via** +No additional methods + + + +**Warning** +No additional methods + + + +**WWWAuthenticate** +`toStringMultipleHeaders(array $headers)` + +## Examples + +**Retrieving headers from a Zend\\Http\\Headers object** + +```php +// $client is an instance of Zend\Http\Client +$response = $client->send(); +$headers = $response->getHeaders(); + +// We can check if the Request contains a specific header by +// using the ``has`` method. Returns boolean ``TRUE`` if at least +// one matching header found, and ``FALSE`` otherwise +$headers->has('Content-Type'); + +// We can retrieve all instances of a specific header by using +// the ``get`` method: +$contentTypeHeaders = $headers->get('Content-Type'); +``` + +There are three possibilities for the return value of the above call to the `get` method: + +> - If no Content-Type header was set in the Request, `get` will return false. +- If only one Content-Type header was set in the Request, `get` will return an instance of +`Zend\Http\Header\ContentType`. +- If more than one Content-Type header was set in the Request, `get` will return an ArrayIterator +containing one `Zend\Http\Header\ContentType` instance per header. + +**Adding headers to a Zend\\Http\\Headers object** + +```php +$headers = new Zend\Http\Headers(); + +// We can directly add any object that implements Zend\Http\Header\HeaderInterface +$typeHeader = Zend\Http\Header\ContentType::fromString('Content-Type: text/html'); +$headers->addHeader($typeHeader); + +// We can add headers using the raw string representation, either +// passing the header name and value as separate arguments... +$headers->addHeaderLine('Content-Type', 'text/html'); + +// .. or we can pass the entire header as the only argument +$headers->addHeaderLine('Content-Type: text/html'); + +// We can also add headers in bulk using addHeaders, which accepts +// an array of individual header definitions that can be in any of +// the accepted formats outlined below: +$headers->addHeaders(array( + + // An object implementing Zend\Http\Header\HeaderInterface + Zend\Http\Header\ContentType::fromString('Content-Type: text/html'), + + // A raw header string + 'Content-Type: text/html', + + // We can also pass the header name as the array key and the + // header content as that array key's value + 'Content-Type' => 'text/html'); + +)); +``` + +**Removing headers from a Zend\\Http\\Headers object** + +We can remove all headers of a specific type using the `removeHeader` method, which accepts a single +object implementing `Zend\Http\Header\HeaderInterface` + +```php +// $headers is a pre-configured instance of Zend\Http\Headers + +// We can also delete individual headers or groups of headers +$matches = $headers->get('Content-Type'); + +// If more than one header was found, iterate over the collection +// and remove each one individually +if ($matches instanceof ArrayIterator) { + foreach ($headers as $header) { + $headers->removeHeader($header); + } +// If only a single header was found, remove it directly +} elseif ($matches instanceof Zend\Http\Header\HeaderInterface) { + $headers->removeHeader($header); +} + +// In addition to this, we can clear all the headers currently stored in +// the container by calling the clearHeaders() method +$matches->clearHeaders(); +``` diff --git a/doc/book/zend.http.request.md b/doc/book/zend.http.request.md new file mode 100644 index 0000000000..fb3297f88a --- /dev/null +++ b/doc/book/zend.http.request.md @@ -0,0 +1,451 @@ +# The Request Class + +## Overview + +The `Zend\Http\Request` object is responsible for providing a fluent API that allows a developer to +interact with all the various parts of an HTTP request. + +A typical HTTP request looks like this: +## +## | METHOD | URI | VERSION | +## | HEADERS | +## | BODY | + +In simplified terms, the request consists of a method, *URI* and HTTP version number which together +make up the "Request Line." Next come the HTTP headers, of which there can be 0 or more. After that +is the request body, which is typically used when a client wishes to send data to the server in the +form of an encoded file, or include a set of POST parameters, for example. More information on the +structure and specification of a HTTP request can be found in [RFC-2616 on the W3.org +site](http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html). + +## Quick Start + +Request objects can either be created from the provided `fromString()` factory, or, if you wish to +have a completely empty object to start with, by simply instantiating the `Zend\Http\Request` class. + +```php +use Zend\Http\Request; + +$request = Request::fromString(<<setMethod(Request::METHOD_POST); +$request->setUri('/foo'); +$request->getHeaders()->addHeaders(array( + 'HeaderField1' => 'header-field-value1', + 'HeaderField2' => 'header-field-value2', +)); +$request->getPost()->set('foo', 'bar'); +``` + +## Configuration Options + +No configuration options are available. + +## Available Methods + +**Request::fromString** +`Request::fromString(string $string)` + +A factory that produces a Request object from a well-formed HTTP Request string. + +Returns `Zend\Http\Request` + + + +**setMethod** +`setMethod(string $method)` + +Set the method for this request. + +Returns `Zend\Http\Request` + + + +**getMethod** +`getMethod()` + +Return the method for this request. + +Returns string + + + +**setUri** +`setUri(string|Zend\Uri\Http $uri)` + +Set the URI/URL for this request; this can be a string or an instance of `Zend\Uri\Http`. + +Returns `Zend\Http\Request` + + + +**getUri** +`getUri()` + +Return the URI for this request object. + +Returns `Zend\Uri\Http` + + + +**getUriString** +`getUriString()` + +Return the URI for this request object as a string. + +Returns string + + + +**setVersion** +`setVersion(string $version)` + +Set the HTTP version for this object, one of 1.0 or 1.1 (`Request::VERSION_10`, +`Request::VERSION_11`). + +Returns `Zend\Http\Request` + + + +**getVersion** +`getVersion()` + +Return the HTTP version for this request. + +Returns string + + + +**setQuery** +`setQuery(Zend\Stdlib\ParametersInterface $query)` + +Provide an alternate Parameter Container implementation for query parameters in this object. (This +is NOT the primary API for value setting; for that, see `getQuery()`). + +Returns `Zend\Http\Request` + + + +**getQuery** +`getQuery(string|null $name, mixed|null $default)` + +Return the parameter container responsible for query parameters or a single query parameter. + +Returns `string`, `Zend\Stdlib\ParametersInterface`, or `null` depending on value of `$name` +argument. + + + +**setPost** +`setPost(Zend\Stdlib\ParametersInterface $post)` + +Provide an alternate Parameter Container implementation for POST parameters in this object. (This is +NOT the primary API for value setting; for that, see `getPost()`). + +Returns `Zend\Http\Request` + + + +**getPost** +`getPost(string|null $name, mixed|null $default)` + +Return the parameter container responsible for POST parameters or a single POST parameter. + +Returns `string`, `Zend\Stdlib\ParametersInterface`, or `null` depending on value of `$name` +argument. + + + +**getCookie** +`getCookie()` + +Return the Cookie header, this is the same as calling +*$request->getHeaders()->get('Cookie');*. + +Returns `Zend\Http\Header\Cookie` + + + +**setFiles** +`setFiles(Zend\Stdlib\ParametersInterface $files)` + +Provide an alternate Parameter Container implementation for file parameters in this object, (This is +NOT the primary API for value setting; for that, see `getFiles()`). + +Returns `Zend\Http\Request` + + + +**getFiles** +`getFiles(string|null $name, mixed|null $default)` + +Return the parameter container responsible for file parameters or a single file parameter. + +Returns `string`, `Zend\Stdlib\ParametersInterface`, or `null` depending on value of `$name` +argument. + + + +**setHeaders** +`setHeaders(Zend\Http\Headers $headers)` + +Provide an alternate Parameter Container implementation for headers in this object, (this is NOT the +primary API for value setting, for that see `getHeaders()`). + +Returns `Zend\Http\Request` + + + +**getHeaders** +`getHeaders(string|null $name, mixed|null $default)` + +Return the container responsible for storing HTTP headers. This container exposes the primary API +for manipulating headers set in the HTTP request. See the section on +Zend\\\\Http\\\\Headers<zend.http.headers> for more information. + +Returns `Zend\Http\Headers` if `$name` is `null`. Returns `Zend\Http\Header\HeaderInterface` or +`ArrayIterator` if `$name` matches one or more stored headers, respectively. + + + +**setMetadata** +`setMetadata(string|int|array|Traversable $spec, mixed $value)` + +Set message metadata. + +Non-destructive setting of message metadata; always adds to the metadata, never overwrites the +entire metadata container. + +Returns `Zend\Http\Request` + + + +**getMetadata** +`getMetadata(null|string|int $key, null|mixed $default)` + +Retrieve all metadata or a single metadatum as specified by key. + +Returns mixed + + + +**setContent** +`setContent(mixed $value)` + +Set request body (content). + +Returns `Zend\Http\Request` + + + +**getContent** +`getContent()` + +Get request body (content). + +Returns mixed + + + +**isOptions** +`isOptions()` + +Is this an OPTIONS method request? + +Returns bool + + + +**isGet** +`isGet()` + +Is this a GET method request? + +Returns bool + + + +**isHead** +`isHead()` + +Is this a HEAD method request? + +Returns bool + + + +**isPost** +`isPost()` + +Is this a POST method request? + +Returns bool + + + +**isPut** +`isPut()` + +Is this a PUT method request? + +Returns bool + + + +**isDelete** +`isDelete()` + +Is this a DELETE method request? + +Returns bool + + + +**isTrace** +`isTrace()` + +Is this a TRACE method request? + +Returns bool + + + +**isConnect** +`isConnect()` + +Is this a CONNECT method request? + +Returns bool + + + +**isPatch** +`isPatch()` + +Is this a PATCH method request? + +Returns bool + + + +**isXmlHttpRequest** +`isXmlHttpRequest()` + +Is this a Javascript XMLHttpRequest? + +Returns bool + + + +**isFlashRequest** +`isFlashRequest()` + +Is this a Flash request? + +Returns bool + + + +**renderRequestLine** +`renderRequestLine()` + +Return the formatted request line (first line) for this HTTP request. + +Returns string + + + +**toString** +`toString()` + +Returns string + + + +**\_\_toString** +`__toString()` + +Allow PHP casting of this object. + +Returns string + +## Examples + +**Generating a Request object from a string** + +```php +use Zend\Http\Request; + +$string = "GET /foo HTTP/1.1\r\n\r\nSome Content"; +$request = Request::fromString($string); + +$request->getMethod(); // returns Request::METHOD_GET +$request->getUri(); // returns Zend\Uri\Http object +$request->getUriString(); // returns '/foo' +$request->getVersion(); // returns Request::VERSION_11 or '1.1' +$request->getContent(); // returns 'Some Content' +``` + +**Retrieving and setting headers** + +```php +use Zend\Http\Request; +use Zend\Http\Header\Cookie; + +$request = new Request(); +$request->getHeaders()->get('Content-Type'); // return content type +$request->getHeaders()->addHeader(new Cookie(array('foo' => 'bar'))); +foreach ($request->getHeaders() as $header) { + echo $header->getFieldName() . ' with value ' . $header->getFieldValue(); +} +``` + +**Retrieving and setting GET and POST values** + +```php +use Zend\Http\Request; + +$request = new Request(); + +// getPost() and getQuery() both return, by default, a Parameters object, which extends ArrayObject +$request->getPost()->foo = 'Foo value'; +$request->getQuery()->bar = 'Bar value'; +$request->getPost('foo'); // returns 'Foo value' +$request->getQuery()->offsetGet('bar'); // returns 'Bar value' +``` + +**Generating a formatted HTTP Request from a Request object** + +```php +use Zend\Http\Request; + +$request = new Request(); +$request->setMethod(Request::METHOD_POST); +$request->setUri('/foo'); +$request->getHeaders()->addHeaders(array( + 'HeaderField1' => 'header-field-value1', + 'HeaderField2' => 'header-field-value2', +)); +$request->getPost()->set('foo', 'bar'); +$request->setContent($request->getPost()->toString()); +echo $request->toString(); + +/** Will produce: +POST /foo HTTP/1.1 +HeaderField1: header-field-value1 +HeaderField2: header-field-value2 + +foo=bar +*/ +``` diff --git a/doc/book/zend.http.response.md b/doc/book/zend.http.response.md new file mode 100644 index 0000000000..4cd9f44a36 --- /dev/null +++ b/doc/book/zend.http.response.md @@ -0,0 +1,352 @@ +# The Response Class + +## Overview + +The `Zend\Http\Response` class is responsible for providing a fluent API that allows a developer to +interact with all the various parts of an HTTP response. + +A typical HTTP Response looks like this: +## +## | VERSION | CODE | REASON | +## | HEADERS | +## | BODY | + +The first line of the response consists of the HTTP version, status code, and the reason string for +the provided status code; this is called the Response Line. Next is a set of headers; there can be 0 +or an unlimited number of headers. The remainder of the response is the response body, which is +typically a string of HTML that will render on the client's browser, but which can also be a place +for request/response payload data typical of an AJAX request. More information on the structure and +specification of an HTTP response can be found in [RFC-2616 on the W3.org +site](http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html). + +## Quick Start + +Response objects can either be created from the provided `fromString()` factory, or, if you wish to +have a completely empty object to start with, by simply instantiating the `Zend\Http\Response` +class. + +```php +use Zend\Http\Response; +$response = Response::fromString(<< + + Hello World + + +EOS); + +// OR + +$response = new Response(); +$response->setStatusCode(Response::STATUS_CODE_200); +$response->getHeaders()->addHeaders(array( + 'HeaderField1' => 'header-field-value', + 'HeaderField2' => 'header-field-value2', +)); +$response->setContent(<< + + Hello World + + +EOS +); +``` + +## Configuration Options + +No configuration options are available. + +## Available Methods + +**Response::fromString** +`Response::fromString(string $string)` + +Populate object from string + +Returns `Zend\Http\Response` + + + +**renderStatusLine** +`renderStatusLine()` + +Render the status line header + +Returns string + + + +**setHeaders** +`setHeaders(Zend\Http\Headers $headers)` + +Provide an alternate Parameter Container implementation for headers in this object. (This is NOT the +primary API for value setting; for that, see `getHeaders()`.) + +Returns `Zend\Http\Request` + + + +**getHeaders** +`getHeaders()` + +Return the container responsible for storing HTTP headers. This container exposes the primary API +for manipulating headers set in the HTTP response. See the section on +Zend\\\\Http\\\\Headers<zend.http.headers> for more information. + +Returns `Zend\Http\Headers` + + + +**setVersion** +`setVersion(string $version)` + +Set the HTTP version for this object, one of 1.0 or 1.1 (`Request::VERSION_10`, +`Request::VERSION_11`). + +Returns `Zend\Http\Request`. + + + +**getVersion** +`getVersion()` + +Return the HTTP version for this request + +Returns string + + + +**setStatusCode** +`setStatusCode(numeric $code)` + +Set HTTP status code + +Returns `Zend\Http\Response` + + + +**getStatusCode** +`getStatusCode()` + +Retrieve HTTP status code + +Returns int + + + +**setReasonPhrase** +`setReasonPhrase(string $reasonPhrase)` + +Set custom HTTP status message + +Returns `Zend\Http\Response` + + + +**getReasonPhrase** +`getReasonPhrase()` + +Get HTTP status message + +Returns string + + + +**isClientError** +`isClientError()` + +Does the status code indicate a client error? + +Returns bool + + + +**isForbidden** +`isForbidden()` + +Is the request forbidden due to ACLs? + +Returns bool + + + +**isInformational** +`isInformational()` + +Is the current status "informational"? + +Returns bool + + + +**isNotFound** +`isNotFound()` + +Does the status code indicate the resource is not found? + +Returns bool + + + +**isOk** +`isOk()` + +Do we have a normal, OK response? + +Returns bool + + + +**isServerError** +`isServerError()` + +Does the status code reflect a server error? + +Returns bool + + + +**isRedirect** +`isRedirect()` + +Do we have a redirect? + +Returns bool + + + +**isSuccess** +`isSuccess()` + +Was the response successful? + +Returns bool + + + +**decodeChunkedBody** +`decodeChunkedBody(string $body)` + +Decode a "chunked" transfer-encoded body and return the decoded text + +Returns string + + + +**decodeGzip** +`decodeGzip(string $body)` + +Decode a gzip encoded message (when Content-encoding = gzip) + +Currently requires PHP with zlib support + +Returns string + + + +**decodeDeflate** +`decodeDeflate(string $body)` + +Decode a zlib deflated message (when Content-encoding = deflate) + +Currently requires PHP with zlib support + +Returns string + + + +**setMetadata** +`setMetadata(string|int|array|Traversable $spec, mixed $value)` + +Set message metadata + +Non-destructive setting of message metadata; always adds to the metadata, never overwrites the +entire metadata container. + +Returns `Zend\Stdlib\Message` + + + +**getMetadata** +`getMetadata(null|string|int $key, null|mixed $default)` + +Retrieve all metadata or a single metadatum as specified by key + +Returns mixed + + + +**setContent** +`setContent(mixed $value)` + +Set message content + +Returns `Zend\Stdlib\Message` + + + +**getContent** +`getContent()` + +Get raw message content + +Returns mixed + + + +**getBody** +`getBody()` + +Get decoded message content + +Returns mixed + + + +**toString** +`toString()` + +Returns string + +## Examples + +**Generating a Response object from a string** + +```php +use Zend\Http\Response; +$request = Response::fromString(<< + + Hello World + + +EOS); +``` + +**Generating a formatted HTTP Response from a Response object** + +```php +use Zend\Http\Response; +$response = new Response(); +$response->setStatusCode(Response::STATUS_CODE_200); +$response->getHeaders()->addHeaders(array( + 'HeaderField1' => 'header-field-value', + 'HeaderField2' => 'header-field-value2', +)); +$response->setContent(<< + + Hello World + + +EOS); +``` diff --git a/doc/bookdown.json b/doc/bookdown.json new file mode 100644 index 0000000000..a6e395b202 --- /dev/null +++ b/doc/bookdown.json @@ -0,0 +1,13 @@ +{ + "title": "Zend\\Http", + "target": "html/", + "content": [ + "book/zend.http.request.md", + "book/zend.http.response.md", + "book/zend.http.headers.md", + "book/zend.http.client.md", + "book/zend.http.client.adapters.md", + "book/zend.http.client.advanced.md", + "book/zend.http.client-static.md" + ] +} \ No newline at end of file