seeder-migration-issues

This commit is contained in:
RafficMohammed
2023-01-30 14:23:34 +05:30
parent 4d918c722f
commit 2ec836b447
3628 changed files with 116006 additions and 187 deletions

View File

@@ -0,0 +1,53 @@
# Changelog
All notable changes to this project will be documented in this file, in reverse chronological order by release.
## 2.5.3 - 2015-09-14
### Added
- Nothing.
### Deprecated
- Nothing.
### Removed
- Nothing.
### Fixed
- [#23](https://github.com/zendframework/zend-http/pull/23) fixes a BC break
introduced with fixes for [ZF2015-04](http://framework.zend.com/security/advisory/ZF2015-04),
pertaining specifically to the `SetCookie` header. The fix backs out a
check for message splitting syntax, as that particular class already encodes
the value in a manner that prevents the attack. It also adds tests to ensure
the security vulnerability remains patched.
## 2.5.2 - 2015-08-05
### Added
- Nothing.
### Deprecated
- Nothing.
### Removed
- Nothing.
### Fixed
- [#7](https://github.com/zendframework/zend-http/pull/7) fixes a call in the
proxy adapter to `Response::extractCode()`, which does not exist, to
`Response::fromString()->getStatusCode()`, which does.
- [#8](https://github.com/zendframework/zend-http/pull/8) ensures that the Curl
client adapter enables the `CURLINFO_HEADER_OUT`, which is required to ensure
we can fetch the raw request after it is sent.
- [#14](https://github.com/zendframework/zend-http/pull/14) fixes
`Zend\Http\PhpEnvironment\Request` to ensure that empty `SCRIPT_FILENAME` and
`SCRIPT_NAME` values which result in an empty `$baseUrl` will not raise an
`E_WARNING` when used to do a `strpos()` check during base URI detection.

View File

@@ -0,0 +1,229 @@
# CONTRIBUTING
## RESOURCES
If you wish to contribute to Zend Framework, please be sure to
read/subscribe to the following resources:
- [Coding Standards](https://github.com/zendframework/zf2/wiki/Coding-Standards)
- [Contributor's Guide](http://framework.zend.com/participate/contributor-guide)
- ZF Contributor's mailing list:
Archives: http://zend-framework-community.634137.n4.nabble.com/ZF-Contributor-f680267.html
Subscribe: zf-contributors-subscribe@lists.zend.com
- ZF Contributor's IRC channel:
#zftalk.dev on Freenode.net
If you are working on new features or refactoring [create a proposal](https://github.com/zendframework/zend-http/issues/new).
## Reporting Potential Security Issues
If you have encountered a potential security vulnerability, please **DO NOT** report it on the public
issue tracker: send it to us at [zf-security@zend.com](mailto:zf-security@zend.com) instead.
We will work with you to verify the vulnerability and patch it as soon as possible.
When reporting issues, please provide the following information:
- Component(s) affected
- A description indicating how to reproduce the issue
- A summary of the security vulnerability and impact
We request that you contact us via the email address above and give the project
contributors a chance to resolve the vulnerability and issue a new release prior
to any public exposure; this helps protect users and provides them with a chance
to upgrade and/or update in order to protect their applications.
For sensitive email communications, please use [our PGP key](http://framework.zend.com/zf-security-pgp-key.asc).
## RUNNING TESTS
> ### Note: testing versions prior to 2.4
>
> This component originates with Zend Framework 2. During the lifetime of ZF2,
> testing infrastructure migrated from PHPUnit 3 to PHPUnit 4. In most cases, no
> changes were necessary. However, due to the migration, tests may not run on
> versions < 2.4. As such, you may need to change the PHPUnit dependency if
> attempting a fix on such a version.
To run tests:
- Clone the repository:
```console
$ git clone git@github.com:zendframework/zend-http.git
$ cd
```
- Install dependencies via composer:
```console
$ curl -sS https://getcomposer.org/installer | php --
$ ./composer.phar install
```
If you don't have `curl` installed, you can also download `composer.phar` from https://getcomposer.org/
- Run the tests via `phpunit` and the provided PHPUnit config, like in this example:
```console
$ ./vendor/bin/phpunit
```
You can turn on conditional tests with the phpunit.xml file.
To do so:
- Copy `phpunit.xml.dist` file to `phpunit.xml`
- Edit `phpunit.xml` to enable any specific functionality you
want to test, as well as to provide test values to utilize.
## Running Coding Standards Checks
This component uses [php-cs-fixer](http://cs.sensiolabs.org/) for coding
standards checks, and provides configuration for our selected checks.
`php-cs-fixer` is installed by default via Composer.
To run checks only:
```console
$ ./vendor/bin/php-cs-fixer fix . -v --diff --dry-run --config-file=.php_cs
```
To have `php-cs-fixer` attempt to fix problems for you, omit the `--dry-run`
flag:
```console
$ ./vendor/bin/php-cs-fixer fix . -v --diff --config-file=.php_cs
```
If you allow php-cs-fixer to fix CS issues, please re-run the tests to ensure
they pass, and make sure you add and commit the changes after verification.
## Recommended Workflow for Contributions
Your first step is to establish a public repository from which we can
pull your work into the master repository. We recommend using
[GitHub](https://github.com), as that is where the component is already hosted.
1. Setup a [GitHub account](http://github.com/), if you haven't yet
2. Fork the repository (http://github.com/zendframework/zend-http)
3. Clone the canonical repository locally and enter it.
```console
$ git clone git://github.com:zendframework/zend-http.git
$ cd zend-http
```
4. Add a remote to your fork; substitute your GitHub username in the command
below.
```console
$ git remote add {username} git@github.com:{username}/zend-http.git
$ git fetch {username}
```
### Keeping Up-to-Date
Periodically, you should update your fork or personal repository to
match the canonical ZF repository. Assuming you have setup your local repository
per the instructions above, you can do the following:
```console
$ git checkout master
$ git fetch origin
$ git rebase origin/master
# OPTIONALLY, to keep your remote up-to-date -
$ git push {username} master:master
```
If you're tracking other branches -- for example, the "develop" branch, where
new feature development occurs -- you'll want to do the same operations for that
branch; simply substitute "develop" for "master".
### Working on a patch
We recommend you do each new feature or bugfix in a new branch. This simplifies
the task of code review as well as the task of merging your changes into the
canonical repository.
A typical workflow will then consist of the following:
1. Create a new local branch based off either your master or develop branch.
2. Switch to your new local branch. (This step can be combined with the
previous step with the use of `git checkout -b`.)
3. Do some work, commit, repeat as necessary.
4. Push the local branch to your remote repository.
5. Send a pull request.
The mechanics of this process are actually quite trivial. Below, we will
create a branch for fixing an issue in the tracker.
```console
$ git checkout -b hotfix/9295
Switched to a new branch 'hotfix/9295'
```
... do some work ...
```console
$ git commit
```
... write your log message ...
```console
$ git push {username} hotfix/9295:hotfix/9295
Counting objects: 38, done.
Delta compression using up to 2 threads.
Compression objects: 100% (18/18), done.
Writing objects: 100% (20/20), 8.19KiB, done.
Total 20 (delta 12), reused 0 (delta 0)
To ssh://git@github.com/{username}/zend-http.git
b5583aa..4f51698 HEAD -> master
```
To send a pull request, you have two options.
If using GitHub, you can do the pull request from there. Navigate to
your repository, select the branch you just created, and then select the
"Pull Request" button in the upper right. Select the user/organization
"zendframework" as the recipient.
If using your own repository - or even if using GitHub - you can use `git
format-patch` to create a patchset for us to apply; in fact, this is
**recommended** for security-related patches. If you use `format-patch`, please
send the patches as attachments to:
- zf-devteam@zend.com for patches without security implications
- zf-security@zend.com for security patches
#### What branch to issue the pull request against?
Which branch should you issue a pull request against?
- For fixes against the stable release, issue the pull request against the
"master" branch.
- For new features, or fixes that introduce new elements to the public API (such
as new public methods or properties), issue the pull request against the
"develop" branch.
### Branch Cleanup
As you might imagine, if you are a frequent contributor, you'll start to
get a ton of branches both locally and on your remote.
Once you know that your changes have been accepted to the master
repository, we suggest doing some cleanup of these branches.
- Local branch cleanup
```console
$ git branch -d <branchname>
```
- Remote branch removal
```console
$ git push {username} :<branchname>
```

View File

@@ -0,0 +1,28 @@
Copyright (c) 2005-2015, Zend Technologies USA, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of Zend Technologies USA, Inc. nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,12 @@
# zend-http
[![Build Status](https://secure.travis-ci.org/zendframework/zend-http.svg?branch=master)](https://secure.travis-ci.org/zendframework/zend-http)
[![Coverage Status](https://coveralls.io/repos/zendframework/zend-http/badge.svg?branch=master)](https://coveralls.io/r/zendframework/zend-http?branch=master)
`Zend\Http` is a primary foundational component of Zend Framework. Since much of
what PHP does is web-based, specifically HTTP, it makes sense to have a performant,
extensible, concise and consistent API to do all things HTTP.
- File issues at https://github.com/zendframework/zend-http/issues
- Documentation is at http://framework.zend.com/manual/current/en/index.html#zend-http

View File

@@ -0,0 +1,40 @@
{
"name": "zendframework/zend-http",
"description": "provides an easy interface for performing Hyper-Text Transfer Protocol (HTTP) requests",
"license": "BSD-3-Clause",
"keywords": [
"zf2",
"http"
],
"homepage": "https://github.com/zendframework/zend-http",
"autoload": {
"psr-4": {
"Zend\\Http\\": "src/"
}
},
"require": {
"php": ">=5.5",
"zendframework/zend-loader": "~2.5",
"zendframework/zend-stdlib": "~2.5",
"zendframework/zend-uri": "~2.5",
"zendframework/zend-validator": "~2.5"
},
"minimum-stability": "dev",
"prefer-stable": true,
"extra": {
"branch-alias": {
"dev-master": "2.5-dev",
"dev-develop": "2.6-dev"
}
},
"autoload-dev": {
"psr-4": {
"ZendTest\\Http\\": "test/"
}
},
"require-dev": {
"fabpot/php-cs-fixer": "1.7.*",
"phpunit/PHPUnit": "~4.0",
"zendframework/zend-config": "~2.5"
}
}

View File

@@ -0,0 +1,105 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http;
use Zend\Stdlib\Message;
/**
* HTTP standard message (Request/Response)
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4
*/
abstract class AbstractMessage extends Message
{
/**#@+
* @const string Version constant numbers
*/
const VERSION_10 = '1.0';
const VERSION_11 = '1.1';
/**#@-*/
/**
* @var string
*/
protected $version = self::VERSION_11;
/**
* @var Headers|null
*/
protected $headers = null;
/**
* Set the HTTP version for this object, one of 1.0 or 1.1
* (AbstractMessage::VERSION_10, AbstractMessage::VERSION_11)
*
* @param string $version (Must be 1.0 or 1.1)
* @return AbstractMessage
* @throws Exception\InvalidArgumentException
*/
public function setVersion($version)
{
if ($version != self::VERSION_10 && $version != self::VERSION_11) {
throw new Exception\InvalidArgumentException(
'Not valid or not supported HTTP version: ' . $version
);
}
$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 headers in this object,
* (this is NOT the primary API for value setting, for that see getHeaders())
*
* @see getHeaders()
* @param Headers $headers
* @return AbstractMessage
*/
public function setHeaders(Headers $headers)
{
$this->headers = $headers;
return $this;
}
/**
* Return the header container responsible for headers
*
* @return Headers
*/
public function getHeaders()
{
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;
}
/**
* Allow PHP casting of this object
*
* @return string
*/
public function __toString()
{
return $this->toString();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Adapter;
/**
* An interface description for Zend\Http\Client\Adapter classes.
*
* These classes are used as connectors for Zend\Http\Client, performing the
* tasks of connecting, writing, reading and closing connection to the server.
*/
interface AdapterInterface
{
/**
* Set the configuration array for the adapter
*
* @param array $options
*/
public function setOptions($options = []);
/**
* Connect to the remote server
*
* @param string $host
* @param int $port
* @param bool $secure
*/
public function connect($host, $port = 80, $secure = false);
/**
* Send request to the remote server
*
* @param string $method
* @param \Zend\Uri\Uri $url
* @param string $httpVer
* @param array $headers
* @param string $body
* @return string Request as text
*/
public function write($method, $url, $httpVer = '1.1', $headers = [], $body = '');
/**
* Read response from server
*
* @return string
*/
public function read();
/**
* Close the connection to the server
*
*/
public function close();
}

View File

@@ -0,0 +1,527 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Adapter;
use Traversable;
use Zend\Http\Client\Adapter\AdapterInterface as HttpAdapter;
use Zend\Http\Client\Adapter\Exception as AdapterException;
use Zend\Stdlib\ArrayUtils;
/**
* An adapter class for Zend\Http\Client based on the curl extension.
* Curl requires libcurl. See for full requirements the PHP manual: http://php.net/curl
*/
class Curl implements HttpAdapter, StreamInterface
{
/**
* Parameters array
*
* @var array
*/
protected $config = [];
/**
* What host/port are we connected to?
*
* @var array
*/
protected $connectedTo = [null, null];
/**
* The curl session handle
*
* @var resource|null
*/
protected $curl = null;
/**
* List of cURL options that should never be overwritten
*
* @var array
*/
protected $invalidOverwritableCurlOptions;
/**
* Response gotten from server
*
* @var string
*/
protected $response = null;
/**
* Stream for storing output
*
* @var resource
*/
protected $outputStream;
/**
* Adapter constructor
*
* Config is set using setOptions()
*
* @throws AdapterException\InitializationException
*/
public function __construct()
{
if (!extension_loaded('curl')) {
throw new AdapterException\InitializationException(
'cURL extension has to be loaded to use this Zend\Http\Client adapter'
);
}
$this->invalidOverwritableCurlOptions = [
CURLOPT_HTTPGET,
CURLOPT_POST,
CURLOPT_UPLOAD,
CURLOPT_CUSTOMREQUEST,
CURLOPT_HEADER,
CURLOPT_RETURNTRANSFER,
CURLOPT_HTTPHEADER,
CURLOPT_INFILE,
CURLOPT_INFILESIZE,
CURLOPT_PORT,
CURLOPT_MAXREDIRS,
CURLOPT_CONNECTTIMEOUT,
];
}
/**
* Set the configuration array for the adapter
*
* @param array|Traversable $options
* @return Curl
* @throws AdapterException\InvalidArgumentException
*/
public function setOptions($options = [])
{
if ($options instanceof Traversable) {
$options = ArrayUtils::iteratorToArray($options);
}
if (!is_array($options)) {
throw new AdapterException\InvalidArgumentException(
'Array or Traversable object expected, got ' . gettype($options)
);
}
/** Config Key Normalization */
foreach ($options as $k => $v) {
unset($options[$k]); // unset original value
$options[str_replace(['-', '_', ' ', '.'], '', strtolower($k))] = $v; // replace w/ normalized
}
if (isset($options['proxyuser']) && isset($options['proxypass'])) {
$this->setCurlOption(CURLOPT_PROXYUSERPWD, $options['proxyuser'] . ":" . $options['proxypass']);
unset($options['proxyuser'], $options['proxypass']);
}
if (isset($options['sslverifypeer'])) {
$this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $options['sslverifypeer']);
unset($options['sslverifypeer']);
}
foreach ($options 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:
if (is_array($v) && isset($this->config[$option]) && is_array($this->config[$option])) {
$v = ArrayUtils::merge($this->config[$option], $v);
}
$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 Curl
*/
public function setCurlOption($option, $value)
{
if (!isset($this->config['curloptions'])) {
$this->config['curloptions'] = [];
}
$this->config['curloptions'][$option] = $value;
return $this;
}
/**
* Initialize curl
*
* @param string $host
* @param int $port
* @param bool $secure
* @return void
* @throws AdapterException\RuntimeException if unable to connect
*/
public function connect($host, $port = 80, $secure = false)
{
// If we're already connected, disconnect first
if ($this->curl) {
$this->close();
}
// Do the actual connection
$this->curl = curl_init();
if ($port != 80) {
curl_setopt($this->curl, CURLOPT_PORT, intval($port));
}
if (isset($this->config['timeout'])) {
if (defined('CURLOPT_CONNECTTIMEOUT_MS')) {
curl_setopt($this->curl, CURLOPT_CONNECTTIMEOUT_MS, $this->config['timeout'] * 1000);
} else {
curl_setopt($this->curl, CURLOPT_CONNECTTIMEOUT, $this->config['timeout']);
}
if (defined('CURLOPT_TIMEOUT_MS')) {
curl_setopt($this->curl, CURLOPT_TIMEOUT_MS, $this->config['timeout'] * 1000);
} else {
curl_setopt($this->curl, CURLOPT_TIMEOUT, $this->config['timeout']);
}
}
if (isset($this->config['maxredirects'])) {
// 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 = [$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 AdapterException\RuntimeException If connection fails, connected
* to wrong host, no PUT file defined, unsupported method, or unsupported
* cURL option.
* @throws AdapterException\InvalidArgumentException if $method is currently not supported
*/
public function write($method, $uri, $httpVersion = 1.1, $headers = [], $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:
if (!isset($headers['Content-Length'])
&& !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 (isset($headers['Content-Length'])) {
$this->config['curloptions'][CURLOPT_INFILESIZE] = (int) $headers['Content-Length'];
unset($headers['Content-Length']);
}
if (is_resource($body)) {
$body = '';
}
$curlMethod = CURLOPT_UPLOAD;
} else {
$curlMethod = CURLOPT_CUSTOMREQUEST;
$curlValue = "PUT";
}
break;
case 'PATCH':
$curlMethod = CURLOPT_CUSTOMREQUEST;
$curlValue = "PATCH";
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 '$method' currently not supported");
}
if (is_resource($body) && $curlMethod != CURLOPT_UPLOAD) {
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, CURLOPT_HTTP_VERSION, $curlHttp);
curl_setopt($this->curl, $curlMethod, $curlValue);
// Set the CURLINFO_HEADER_OUT flag so that we can retrieve the full request string later
curl_setopt($this->curl, CURLINFO_HEADER_OUT, true);
if ($this->outputStream) {
// headers will be read into the response
curl_setopt($this->curl, CURLOPT_HEADER, false);
curl_setopt($this->curl, CURLOPT_HEADERFUNCTION, [$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);
}
// Treating basic auth headers in a special way
if (array_key_exists('Authorization', $headers) && 'Basic' == substr($headers['Authorization'], 0, 5)) {
curl_setopt($this->curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($this->curl, CURLOPT_USERPWD, base64_decode(substr($headers['Authorization'], 6)));
unset($headers['Authorization']);
}
// set additional headers
if (!isset($headers['Accept'])) {
$headers['Accept'] = '';
}
$curlHeaders = [];
foreach ($headers as $key => $value) {
$curlHeaders[] = $key . ': ' . $value;
}
curl_setopt($this->curl, CURLOPT_HTTPHEADER, $curlHeaders);
/**
* Make sure POSTFIELDS is set after $curlMethod is set:
* @link http://de2.php.net/manual/en/function.curl-setopt.php#81161
*/
if (in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], true)) {
curl_setopt($this->curl, CURLOPT_POSTFIELDS, $body);
} elseif ($curlMethod == CURLOPT_UPLOAD) {
// 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]);
}
// 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));
}
// separating header from body because it is dangerous to accidentially replace strings in the body
$responseHeaderSize = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE);
$responseHeaders = substr($this->response, 0, $responseHeaderSize);
// cURL automatically decodes chunked-messages, this means we have to
// disallow the Zend\Http\Response to do it again.
$responseHeaders = preg_replace("/Transfer-Encoding:\s*chunked\\r\\n/", "", $responseHeaders);
// cURL can automatically handle content encoding; prevent double-decoding from occurring
if (isset($this->config['curloptions'][CURLOPT_ENCODING])
&& '' == $this->config['curloptions'][CURLOPT_ENCODING]
) {
$responseHeaders = preg_replace("/Content-Encoding:\s*gzip\\r\\n/", '', $responseHeaders);
}
// cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string:
$responseHeaders = preg_replace(
"/HTTP\/1.0\s*200\s*Connection\s*established\\r\\n\\r\\n/",
'',
$responseHeaders
);
// replace old header with new, cleaned up, header
$this->response = substr_replace($this->response, $responseHeaders, 0, $responseHeaderSize);
// 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);
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 = [null, null];
}
/**
* Get cUrl Handle
*
* @return resource
*/
public function getHandle()
{
return $this->curl;
}
/**
* Set output stream for the response
*
* @param resource $stream
* @return Curl
*/
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);
}
}

View File

@@ -0,0 +1,16 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Adapter\Exception;
use Zend\Http\Client\Exception\ExceptionInterface as HttpClientException;
interface ExceptionInterface extends HttpClientException
{
}

View File

@@ -0,0 +1,16 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Adapter\Exception;
/**
*/
class InitializationException extends RuntimeException
{
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Adapter\Exception;
use Zend\Http\Client\Exception;
/**
*/
class InvalidArgumentException extends Exception\InvalidArgumentException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Adapter\Exception;
use Zend\Http\Client\Exception;
/**
*/
class OutOfRangeException extends Exception\OutOfRangeException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Adapter\Exception;
use Zend\Http\Client\Exception;
/**
*/
class RuntimeException extends Exception\RuntimeException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Adapter\Exception;
/**
*/
class TimeoutException extends RuntimeException implements ExceptionInterface
{
const READ_TIMEOUT = 1000;
}

View File

@@ -0,0 +1,294 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Adapter;
use Zend\Http\Client;
use Zend\Http\Client\Adapter\Exception as AdapterException;
use Zend\Http\Response;
use Zend\Stdlib\ErrorHandler;
/**
* HTTP Proxy-supporting Zend\Http\Client adapter class, based on the default
* socket based adapter.
*
* Should be used if proxy HTTP access is required. If no proxy is set, will
* fall back to Zend\Http\Client\Adapter\Socket behavior. Just like the
* default Socket adapter, this adapter does not require any special extensions
* installed.
*/
class Proxy extends Socket
{
/**
* Parameters array
*
* @var array
*/
protected $config = [
'ssltransport' => 'ssl',
'sslcert' => null,
'sslpassphrase' => null,
'sslverifypeer' => true,
'sslcapath' => null,
'sslallowselfsigned' => false,
'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 bool
*/
protected $negotiated = false;
/**
* Set the configuration array for the adapter
*
* @param array $options
*/
public function setOptions($options = [])
{
//enforcing that the proxy keys are set in the form proxy_*
foreach ($options as $k => $v) {
if (preg_match("/^proxy[a-z]+/", $k)) {
$options['proxy_' . substr($k, 5, strlen($k))] = $v;
unset($options[$k]);
}
}
parent::setOptions($options);
}
/**
* 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 bool $secure
* @throws AdapterException\RuntimeException
*/
public function connect($host, $port = 80, $secure = false)
{
// If no proxy is set, fall back to Socket adapter
if (! $this->config['proxy_host']) {
parent::connect($host, $port, $secure);
return;
}
/* 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
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 $httpVer
* @param array $headers
* @param string $body
* @throws AdapterException\RuntimeException
* @return string Request as string
*/
public function write($method, $uri, $httpVer = '1.1', $headers = [], $body = '')
{
// If no proxy is set, fall back to default Socket adapter
if (! $this->config['proxy_host']) {
return parent::write($method, $uri, $httpVer, $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->connectedTo[0] != "tcp://$host" || $this->connectedTo[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(), $httpVer, $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/$httpVer\r\n";
} else {
$request = "$method $uri HTTP/$httpVer\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
ErrorHandler::start();
$test = fwrite($this->socket, $request);
$error = ErrorHandler::stop();
if (!$test) {
throw new AdapterException\RuntimeException("Error writing request to proxy server", 0, $error);
}
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 int $port
* @param string $httpVer
* @param array $headers
* @throws AdapterException\RuntimeException
*/
protected function connectHandshake($host, $port = 443, $httpVer = '1.1', array &$headers = [])
{
$request = "CONNECT $host:$port HTTP/$httpVer\r\n" .
"Host: " . $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
ErrorHandler::start();
$test = fwrite($this->socket, $request);
$error = ErrorHandler::stop();
if (!$test) {
throw new AdapterException\RuntimeException("Error writing request to proxy server", 0, $error);
}
// Read response headers only
$response = '';
$gotStatus = false;
ErrorHandler::start();
while ($line = fgets($this->socket)) {
$gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false);
if ($gotStatus) {
$response .= $line;
if (!rtrim($line)) {
break;
}
}
}
ErrorHandler::stop();
// Check that the response from the proxy is 200
if (Response::fromString($response)->getStatusCode() != 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 = [
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();
}
}
}

View File

@@ -0,0 +1,634 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Adapter;
use Traversable;
use Zend\Http\Client\Adapter\AdapterInterface as HttpAdapter;
use Zend\Http\Client\Adapter\Exception as AdapterException;
use Zend\Http\Response;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\ErrorHandler;
/**
* A sockets based (stream\socket\client) adapter class for Zend\Http\Client. Can be used
* on almost every PHP environment, and does not require any special extensions.
*/
class Socket implements HttpAdapter, StreamInterface
{
/**
* Map SSL transport wrappers to stream crypto method constants
*
* @var array
*/
protected static $sslCryptoTypes = [
'ssl' => STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
'sslv2' => STREAM_CRYPTO_METHOD_SSLv2_CLIENT,
'sslv3' => STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
'tls' => STREAM_CRYPTO_METHOD_TLS_CLIENT,
];
/**
* The socket for server connection
*
* @var resource|null
*/
protected $socket = null;
/**
* What host/port are we connected to?
*
* @var array
*/
protected $connectedTo = [null, null];
/**
* Stream for storing output
*
* @var resource
*/
protected $outStream = null;
/**
* Parameters array
*
* @var array
*/
protected $config = [
'persistent' => false,
'ssltransport' => 'ssl',
'sslcert' => null,
'sslpassphrase' => null,
'sslverifypeer' => true,
'sslcafile' => null,
'sslcapath' => null,
'sslallowselfsigned' => false,
'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 setOptions()
*
*/
public function __construct()
{
}
/**
* Set the configuration array for the adapter
*
* @param array|Traversable $options
* @throws AdapterException\InvalidArgumentException
*/
public function setOptions($options = [])
{
if ($options instanceof Traversable) {
$options = ArrayUtils::iteratorToArray($options);
}
if (!is_array($options)) {
throw new AdapterException\InvalidArgumentException(
'Array or Zend\Config object expected, got ' . gettype($options)
);
}
foreach ($options 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
* @throws Exception\InvalidArgumentException
* @return 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 bool $secure
* @throws AdapterException\RuntimeException
*/
public function connect($host, $port = 80, $secure = false)
{
// If we are connected to the wrong host, disconnect first
$connectedHost = (strpos($this->connectedTo[0], '://'))
? substr($this->connectedTo[0], (strpos($this->connectedTo[0], '://') + 3), strlen($this->connectedTo[0]))
: $this->connectedTo[0];
if ($connectedHost != $host || $this->connectedTo[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['sslverifypeer'] !== null) {
if (!stream_context_set_option($context, 'ssl', 'verify_peer', $this->config['sslverifypeer'])) {
throw new AdapterException\RuntimeException('Unable to set sslverifypeer option');
}
}
if ($this->config['sslcafile']) {
if (!stream_context_set_option($context, 'ssl', 'cafile', $this->config['sslcafile'])) {
throw new AdapterException\RuntimeException('Unable to set sslcafile option');
}
}
if ($this->config['sslcapath']) {
if (!stream_context_set_option($context, 'ssl', 'capath', $this->config['sslcapath'])) {
throw new AdapterException\RuntimeException('Unable to set sslcapath option');
}
}
if ($this->config['sslallowselfsigned'] !== null) {
if (!stream_context_set_option($context, 'ssl', 'allow_self_signed', $this->config['sslallowselfsigned'])) {
throw new AdapterException\RuntimeException('Unable to set sslallowselfsigned option');
}
}
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;
}
ErrorHandler::start();
$this->socket = stream_socket_client(
$host . ':' . $port,
$errno,
$errstr,
(int) $this->config['timeout'],
$flags,
$context
);
$error = ErrorHandler::stop();
if (!$this->socket) {
$this->close();
throw new AdapterException\RuntimeException(
sprintf(
'Unable to connect to %s:%d%s',
$host,
$port,
($error ? ' . Error #' . $error->getCode() . ': ' . $error->getMessage() : '')
),
0,
$error
);
}
// Set the stream timeout
if (!stream_set_timeout($this->socket, (int) $this->config['timeout'])) {
throw new AdapterException\RuntimeException('Unable to set the connection timeout');
}
if ($secure || $this->config['sslusecontext']) {
if ($this->config['ssltransport'] && isset(static::$sslCryptoTypes[$this->config['ssltransport']])) {
$sslCryptoMethod = static::$sslCryptoTypes[$this->config['ssltransport']];
} else {
$sslCryptoMethod = STREAM_CRYPTO_METHOD_SSLv3_CLIENT;
}
ErrorHandler::start();
$test = stream_socket_enable_crypto($this->socket, true, $sslCryptoMethod);
$error = ErrorHandler::stop();
if (!$test || $error) {
// Error handling is kind of difficult when it comes to SSL
$errorString = '';
if (extension_loaded('openssl')) {
while (($sslError = openssl_error_string()) != false) {
$errorString .= "; SSL error: $sslError";
}
}
$this->close();
if ((! $errorString) && $this->config['sslverifypeer']) {
// There's good chance our error is due to sslcapath not being properly set
if (! ($this->config['sslcafile'] || $this->config['sslcapath'])) {
$errorString = 'make sure the "sslcafile" or "sslcapath" option are properly set for the environment.';
} elseif ($this->config['sslcafile'] && !is_file($this->config['sslcafile'])) {
$errorString = 'make sure the "sslcafile" option points to a valid SSL certificate file';
} elseif ($this->config['sslcapath'] && !is_dir($this->config['sslcapath'])) {
$errorString = 'make sure the "sslcapath" option points to a valid SSL certificate directory';
}
}
if ($errorString) {
$errorString = ": $errorString";
}
throw new AdapterException\RuntimeException(sprintf(
'Unable to enable crypto on TCP connection %s%s',
$host,
$errorString
), 0, $error);
}
$host = $this->config['ssltransport'] . "://" . $host;
} else {
$host = 'tcp://' . $host;
}
// Update connectedTo
$this->connectedTo = [$host, $port];
}
}
/**
* Send request to the remote server
*
* @param string $method
* @param \Zend\Uri\Uri $uri
* @param string $httpVer
* @param array $headers
* @param string $body
* @throws AdapterException\RuntimeException
* @return string Request as string
*/
public function write($method, $uri, $httpVer = '1.1', $headers = [], $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->connectedTo[0] != $host || $this->connectedTo[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/{$httpVer}\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
ErrorHandler::start();
$test = fwrite($this->socket, $request);
$error = ErrorHandler::stop();
if (false === $test) {
throw new AdapterException\RuntimeException('Error writing request to server', 0, $error);
}
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
*
* @throws AdapterException\RuntimeException
* @return string
*/
public function read()
{
// First, read headers only
$response = '';
$gotStatus = false;
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->getHeaders();
/**
* 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
$connection = $headers->get('connection');
if ($connection && $connection->getFieldValue() == 'close') {
$this->close();
}
return $response;
}
// If we got a 'transfer-encoding: chunked' header
$transferEncoding = $headers->get('transfer-encoding');
$contentLength = $headers->get('content-length');
if ($transferEncoding !== false) {
if (strtolower($transferEncoding->getFieldValue()) == '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
$readTo = ftell($this->socket) + $chunksize;
do {
$currentPos = ftell($this->socket);
if ($currentPos >= $readTo) {
break;
}
if ($this->outStream) {
if (stream_copy_to_stream($this->socket, $this->outStream, $readTo - $currentPos) == 0) {
$this->_checkSocketReadTimeout();
break;
}
} else {
$line = fread($this->socket, $readTo - $currentPos);
if ($line === false || strlen($line) === 0) {
$this->_checkSocketReadTimeout();
break;
}
$chunk .= $line;
}
} while (! feof($this->socket));
ErrorHandler::start();
$chunk .= fgets($this->socket);
ErrorHandler::stop();
$this->_checkSocketReadTimeout();
if (!$this->outStream) {
$response .= $chunk;
}
} while ($chunksize > 0);
} else {
$this->close();
throw new AdapterException\RuntimeException('Cannot handle "' .
$transferEncoding->getFieldValue() . '" 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->outStream) {
$response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $response);
}
// Else, if we got the content-length header, read this number of bytes
} elseif ($contentLength !== false) {
// If we got more than one Content-Length header (see ZF-9404) use
// the last value sent
if (is_array($contentLength)) {
$contentLength = $contentLength[count($contentLength) - 1];
}
$contentLength = $contentLength->getFieldValue();
$currentPos = ftell($this->socket);
for ($readTo = $currentPos + $contentLength;
$readTo > $currentPos;
$currentPos = ftell($this->socket)) {
if ($this->outStream) {
if (stream_copy_to_stream($this->socket, $this->outStream, $readTo - $currentPos) == 0) {
$this->_checkSocketReadTimeout();
break;
}
} else {
$chunk = fread($this->socket, $readTo - $currentPos);
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->outStream) {
if (stream_copy_to_stream($this->socket, $this->outStream) == 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
$connection = $headers->get('connection');
if ($connection && $connection->getFieldValue() == 'close') {
$this->close();
}
return $response;
}
/**
* Close the connection to the server
*
*/
public function close()
{
if (is_resource($this->socket)) {
ErrorHandler::start();
fclose($this->socket);
ErrorHandler::stop();
}
$this->socket = null;
$this->connectedTo = [null, null];
}
/**
* Check if the socket has timed out - if so close connection and throw
* an exception
*
* @throws AdapterException\TimeoutException 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->outStream = $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();
}
}
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Adapter;
/**
* An interface description for Zend\Http\Client\Adapter\Stream classes.
*
* This interface describes Zend\Http\Client\Adapter which supports streaming.
*/
interface StreamInterface
{
/**
* Set output stream
*
* This function sets output stream where the result will be stored.
*
* @param resource $stream Stream to write the output to
*
*/
public function setOutputStream($stream);
}

View File

@@ -0,0 +1,216 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Adapter;
use Traversable;
use Zend\Http\Response;
use Zend\Stdlib\ArrayUtils;
/**
* A testing-purposes adapter.
*
* Should be used to test all components that rely on Zend\Http\Client,
* without actually performing an HTTP request. You should instantiate this
* object manually, and then set it as the client's adapter. Then, you can
* set the expected response using the setResponse() method.
*/
class Test implements AdapterInterface
{
/**
* Parameters array
*
* @var array
*/
protected $config = [];
/**
* Buffer of responses to be returned by the read() method. Can be
* set using setResponse() and addResponse().
*
* @var array
*/
protected $responses = ["HTTP/1.1 400 Bad Request\r\n\r\n"];
/**
* Current position in the response buffer
*
* @var int
*/
protected $responseIndex = 0;
/**
* Whether or not the next request will fail with an exception
*
* @var bool
*/
protected $nextRequestWillFail = false;
/**
* Adapter constructor, currently empty. Config is set using setOptions()
*/
public function __construct()
{
}
/**
* Set the nextRequestWillFail flag
*
* @param bool $flag
* @return \Zend\Http\Client\Adapter\Test
*/
public function setNextRequestWillFail($flag)
{
$this->nextRequestWillFail = (bool) $flag;
return $this;
}
/**
* Set the configuration array for the adapter
*
* @param array|Traversable $options
* @throws Exception\InvalidArgumentException
*/
public function setOptions($options = [])
{
if ($options instanceof Traversable) {
$options = ArrayUtils::iteratorToArray($options);
}
if (! is_array($options)) {
throw new Exception\InvalidArgumentException(
'Array or Traversable object expected, got ' . gettype($options)
);
}
foreach ($options as $k => $v) {
$this->config[strtolower($k)] = $v;
}
}
/**
* Connect to the remote server
*
* @param string $host
* @param int $port
* @param bool $secure
* @throws Exception\RuntimeException
*/
public function connect($host, $port = 80, $secure = false)
{
if ($this->nextRequestWillFail) {
$this->nextRequestWillFail = false;
throw new Exception\RuntimeException('Request failed');
}
}
/**
* Send request to the remote server
*
* @param string $method
* @param \Zend\Uri\Uri $uri
* @param string $httpVer
* @param array $headers
* @param string $body
* @return string Request as string
*/
public function write($method, $uri, $httpVer = '1.1', $headers = [], $body = '')
{
// Build request headers
$path = $uri->getPath();
if (empty($path)) {
$path = '/';
}
if ($uri->getQuery()) {
$path .= '?' . $uri->getQuery();
}
$request = "{$method} {$path} HTTP/{$httpVer}\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->toString();
}
$this->responses = (array) $response;
$this->responseIndex = 0;
}
/**
* Add another response to the response buffer.
*
* @param string|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 int $index
* @throws Exception\OutOfRangeException
*/
public function setResponseIndex($index)
{
if ($index < 0 || $index >= count($this->responses)) {
throw new Exception\OutOfRangeException(
'Index out of range of response buffer size');
}
$this->responseIndex = $index;
}
}

View File

@@ -0,0 +1,16 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Exception;
use Zend\Http\Exception\ExceptionInterface as HttpException;
interface ExceptionInterface extends HttpException
{
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Exception;
use Zend\Http\Exception;
/**
*/
class InvalidArgumentException extends Exception\InvalidArgumentException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Exception;
use Zend\Http\Exception;
class OutOfRangeException extends Exception\OutOfRangeException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Client\Exception;
use Zend\Http\Exception;
/**
*/
class RuntimeException extends Exception\RuntimeException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,112 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http;
/**
* Http static client
*/
class ClientStatic
{
/**
* @var Client
*/
protected static $client;
/**
* Get the static HTTP client
*
* @param array|Traversable $options
* @return Client
*/
protected static function getStaticClient($options = null)
{
if (!isset(static::$client) || $options !== null) {
static::$client = new Client(null, $options);
}
return static::$client;
}
/**
* HTTP GET METHOD (static)
*
* @param string $url
* @param array $query
* @param array $headers
* @param mixed $body
* @param array|Traversable $clientOptions
* @return Response|bool
*/
public static function get($url, $query = [], $headers = [], $body = null, $clientOptions = null)
{
if (empty($url)) {
return false;
}
$request= new Request();
$request->setUri($url);
$request->setMethod(Request::METHOD_GET);
if (!empty($query) && is_array($query)) {
$request->getQuery()->fromArray($query);
}
if (!empty($headers) && is_array($headers)) {
$request->getHeaders()->addHeaders($headers);
}
if (!empty($body)) {
$request->setContent($body);
}
return static::getStaticClient($clientOptions)->send($request);
}
/**
* HTTP POST METHOD (static)
*
* @param string $url
* @param array $params
* @param array $headers
* @param mixed $body
* @param array|Traversable $clientOptions
* @throws Exception\InvalidArgumentException
* @return Response|bool
*/
public static function post($url, $params, $headers = [], $body = null, $clientOptions = null)
{
if (empty($url)) {
return false;
}
$request= new Request();
$request->setUri($url);
$request->setMethod(Request::METHOD_POST);
if (!empty($params) && is_array($params)) {
$request->getPost()->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->getHeaders()->addHeaders($headers);
}
if (!empty($body)) {
$request->setContent($body);
}
return static::getStaticClient($clientOptions)->send($request);
}
}

View File

@@ -0,0 +1,367 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http;
use ArrayIterator;
use Zend\Http\Header\SetCookie;
use Zend\Uri;
/**
* A Zend\Http\Cookies object is designed to contain and maintain HTTP cookies, and should
* be used along with Zend\Http\Client in order to manage cookies across HTTP requests and
* responses.
*
* The class contains an array of Zend\Http\Header\Cookie objects. Cookies can be added
* automatically from a request or manually. Then, the Cookies class can find and return the
* cookies needed for a specific HTTP request.
*
* A special parameter can be passed to all methods of this class that return cookies: Cookies
* can be returned either in their native form (as Zend\Http\Header\Cookie objects) or as strings -
* the later is suitable for sending as the value of the "Cookie" header in an HTTP request.
* You can also choose, when returning more than one cookie, whether to get an array of strings
* (by passing Zend\Http\Client\Cookies::COOKIE_STRING_ARRAY) or one unified string for all cookies
* (by passing Zend\Http\Client\Cookies::COOKIE_STRING_CONCAT).
*
* @link http://wp.netscape.com/newsref/std/cookie_spec.html for some specs.
*/
class Cookies extends Headers
{
/**
* Return cookie(s) as a Zend\Http\Cookie object
*
*/
const COOKIE_OBJECT = 0;
/**
* Return cookie(s) as a string (suitable for sending in an HTTP request)
*
*/
const COOKIE_STRING_ARRAY = 1;
/**
* Return all cookies as one long string (suitable for sending in an HTTP request)
*
*/
const COOKIE_STRING_CONCAT = 2;
/**
* Return all cookies as one long string (strict mode)
* - Single space after the semi-colon separating each cookie
* - Remove trailing semi-colon, if any
*/
const COOKIE_STRING_CONCAT_STRICT = 3;
/**
* @var array
*/
protected $cookies = [];
/**
* @var \Zend\Http\Headers
*/
protected $headers = null;
/**
* @var array
*/
protected $rawCookies;
/**
* @static
* @throws Exception\RuntimeException
* @param $string
* @return void
*/
public static function fromString($string)
{
throw new Exception\RuntimeException(
__CLASS__ . '::' . __FUNCTION__ . ' should not be used as a factory, use '
. __NAMESPACE__ . '\Headers::fromtString() instead.'
);
}
/**
* 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 SetCookie|string $cookie
* @param Uri\Uri|string $refUri Optional reference URI (for domain, path, secure)
* @throws Exception\InvalidArgumentException
*/
public function addCookie($cookie, $refUri = null)
{
if (is_string($cookie)) {
$cookie = SetCookie::fromString($cookie, $refUri);
}
if ($cookie instanceof SetCookie) {
$domain = $cookie->getDomain();
$path = $cookie->getPath();
if (!isset($this->cookies[$domain])) {
$this->cookies[$domain] = [];
}
if (!isset($this->cookies[$domain][$path])) {
$this->cookies[$domain][$path] = [];
}
$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 $refUri Requested URI
*/
public function addCookiesFromResponse(Response $response, $refUri)
{
$cookieHdrs = $response->getHeaders()->get('Set-Cookie');
if (is_array($cookieHdrs) || $cookieHdrs instanceof ArrayIterator) {
foreach ($cookieHdrs as $cookie) {
$this->addCookie($cookie, $refUri);
}
} elseif (is_string($cookieHdrs)) {
$this->addCookie($cookieHdrs, $refUri);
}
}
/**
* Get all cookies in the cookie jar as an array
*
* @param int $retAs Whether to return cookies as objects of \Zend\Http\Header\SetCookie or as strings
* @return array|string
*/
public function getAllCookies($retAs = self::COOKIE_OBJECT)
{
$cookies = $this->_flattenCookiesArray($this->cookies, $retAs);
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 bool $matchSessionCookies Whether to send session cookies
* @param int $retAs 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
* @throws Exception\InvalidArgumentException if invalid URI specified
* @return array|string
*/
public function getMatchingCookies(
$uri,
$matchSessionCookies = true,
$retAs = self::COOKIE_OBJECT,
$now = null
) {
if (is_string($uri)) {
$uri = Uri\UriFactory::factory($uri, 'http');
} elseif (!$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 matching
$ret = [];
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, $retAs);
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 $cookieName The cookie's name
* @param int $retAs Whether to return cookies as objects of \Zend\Http\Header\SetCookie or as strings
* @throws Exception\InvalidArgumentException if invalid URI specified or invalid $retAs value
* @return SetCookie|string
*/
public function getCookie($uri, $cookieName, $retAs = self::COOKIE_OBJECT)
{
if (is_string($uri)) {
$uri = Uri\UriFactory::factory($uri, 'http');
} elseif (!$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();
$lastSlashPos = strrpos($path, '/') ?: 0;
$path = substr($path, 0, $lastSlashPos);
if (! $path) {
$path = '/';
}
if (isset($this->cookies[$uri->getHost()][$path][$cookieName])) {
$cookie = $this->cookies[$uri->getHost()][$path][$cookieName];
switch ($retAs) {
case self::COOKIE_OBJECT:
return $cookie;
case self::COOKIE_STRING_ARRAY:
case self::COOKIE_STRING_CONCAT:
return $cookie->__toString();
default:
throw new Exception\InvalidArgumentException("Invalid value passed for \$retAs: {$retAs}");
}
}
return false;
}
/**
* Helper function to recursively flatten an array. Should be used when exporting the
* cookies array (or parts of it)
*
* @param \Zend\Http\Header\SetCookie|array $ptr
* @param int $retAs What value to return
* @return array|string
*/
protected function _flattenCookiesArray($ptr, $retAs = self::COOKIE_OBJECT)
{
if (is_array($ptr)) {
$ret = ($retAs == self::COOKIE_STRING_CONCAT ? '' : []);
foreach ($ptr as $item) {
if ($retAs == self::COOKIE_STRING_CONCAT) {
$ret .= $this->_flattenCookiesArray($item, $retAs);
} else {
$ret = array_merge($ret, $this->_flattenCookiesArray($item, $retAs));
}
}
return $ret;
} elseif ($ptr instanceof SetCookie) {
switch ($retAs) {
case self::COOKIE_STRING_ARRAY:
return [$ptr->__toString()];
case self::COOKIE_STRING_CONCAT:
return $ptr->__toString();
case self::COOKIE_OBJECT:
default:
return [$ptr];
}
}
return;
}
/**
* Return a subset of the cookies array matching a specific domain
*
* @param string $domain
* @return array
*/
protected function _matchDomain($domain)
{
$ret = [];
foreach (array_keys($this->cookies) as $cdom) {
if (SetCookie::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 $domains
* @param string $path
* @return array
*/
protected function _matchPath($domains, $path)
{
$ret = [];
foreach ($domains as $dom => $pathsArray) {
foreach (array_keys($pathsArray) as $cpath) {
if (SetCookie::matchCookiePath($cpath, $path)) {
if (! isset($ret[$dom])) {
$ret[$dom] = [];
}
$ret[$dom][$cpath] = $pathsArray[$cpath];
}
}
}
return $ret;
}
/**
* Create a new Cookies object and automatically load into it all the
* cookies set in a 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 $refUri The requested URI
* @return Cookies
* @todo Add the $uri functionality.
*/
public static function fromResponse(Response $response, $refUri)
{
$jar = new static();
$jar->addCookiesFromResponse($response, $refUri);
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 = [];
return $this;
}
}

View File

@@ -0,0 +1,14 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Exception;
interface ExceptionInterface
{
}

View File

@@ -0,0 +1,15 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Exception;
class InvalidArgumentException extends \InvalidArgumentException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,14 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Exception;
class OutOfRangeException extends \OutOfRangeException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,15 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Exception;
class RuntimeException extends \RuntimeException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,456 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
use stdClass;
/**
* Abstract Accept Header
*
* Naming conventions:
*
* Accept: audio/mp3; q=0.2; version=0.5, audio/basic+mp3
* |------------------------------------------------------| header line
* |------| field name
* |-----------------------------------------------| field value
* |-------------------------------| field value part
* |------| type
* |--| subtype
* |--| format
* |----| subtype
* |---| format
* |-------------------| parameter set
* |-----------| parameter
* |-----| parameter key
* |--| parameter value
* |---| priority
*
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
* @author Dolf Schimmel - Freeaqingme
*/
abstract class AbstractAccept implements HeaderInterface
{
/**
*
* @var stdClass[]
*/
protected $fieldValueParts = [];
protected $regexAddType;
/**
* Determines if since last mutation the stack was sorted
*
* @var bool
*/
protected $sorted = false;
/**
* Parse a full header line or just the field value part.
*
* @param string $headerLine
*/
public function parseHeaderLine($headerLine)
{
if (strpos($headerLine, ':') !== false) {
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
if (strtolower($name) !== strtolower($this->getFieldName())) {
$value = $headerLine; // This is just for preserve the BC.
}
} else {
$value = $headerLine;
}
HeaderValue::assertValid($value);
foreach ($this->getFieldValuePartsFromHeaderLine($value) as $value) {
$this->addFieldValuePartToQueue($value);
}
}
/**
* Factory method: parse Accept header string
*
* @param string $headerLine
* @return Accept
*/
public static function fromString($headerLine)
{
$obj = new static();
$obj->parseHeaderLine($headerLine);
return $obj;
}
/**
* Parse the Field Value Parts represented by a header line
*
* @param string $headerLine
* @throws Exception\InvalidArgumentException If header is invalid
* @return array
*/
public function getFieldValuePartsFromHeaderLine($headerLine)
{
// process multiple accept values, they may be between quotes
if (!preg_match_all('/(?:[^,"]|"(?:[^\\\"]|\\\.)*")+/', $headerLine, $values)
|| !isset($values[0])
) {
throw new Exception\InvalidArgumentException(
'Invalid header line for ' . $this->getFieldName() . ' header string'
);
}
$out = [];
foreach ($values[0] as $value) {
$value = trim($value);
$out[] = $this->parseFieldValuePart($value);
}
return $out;
}
/**
* Parse the accept params belonging to a media range
*
* @param string $fieldValuePart
* @return stdClass
*/
protected function parseFieldValuePart($fieldValuePart)
{
$raw = $subtypeWhole = $type = $fieldValuePart;
if ($pos = strpos($fieldValuePart, ';')) {
$type = substr($fieldValuePart, 0, $pos);
}
$params = $this->getParametersFromFieldValuePart($fieldValuePart);
if ($pos = strpos($fieldValuePart, ';')) {
$fieldValuePart = trim(substr($fieldValuePart, 0, $pos));
}
$format = '*';
$subtype = '*';
return (object) [
'typeString' => trim($fieldValuePart),
'type' => $type,
'subtype' => $subtype,
'subtypeRaw' => $subtypeWhole,
'format' => $format,
'priority' => isset($params['q']) ? $params['q'] : 1,
'params' => $params,
'raw' => trim($raw)
];
}
/**
* Parse the keys contained in the header line
*
* @param string $fieldValuePart
* @return array
*/
protected function getParametersFromFieldValuePart($fieldValuePart)
{
$params = [];
if ((($pos = strpos($fieldValuePart, ';')) !== false)) {
preg_match_all('/(?:[^;"]|"(?:[^\\\"]|\\\.)*")+/', $fieldValuePart, $paramsStrings);
if (isset($paramsStrings[0])) {
array_shift($paramsStrings[0]);
$paramsStrings = $paramsStrings[0];
}
foreach ($paramsStrings as $param) {
$explode = explode('=', $param, 2);
$value = trim($explode[1]);
if (isset($value[0]) && $value[0] == '"' && substr($value, -1) == '"') {
$value = substr(substr($value, 1), 0, -1);
}
$params[trim($explode[0])] = stripslashes($value);
}
}
return $params;
}
/**
* Get field value
*
* @param array|null $values
* @return string
*/
public function getFieldValue($values = null)
{
if (!$values) {
return $this->getFieldValue($this->fieldValueParts);
}
$strings = [];
foreach ($values as $value) {
$params = $value->params;
array_walk($params, [$this, 'assembleAcceptParam']);
$strings[] = implode(';', [$value->typeString] + $params);
}
return implode(', ', $strings);
}
/**
* Assemble and escape the field value parameters based on RFC 2616 section 2.1
*
* @todo someone should review this thoroughly
* @param string $value
* @param string $key
* @return string
*/
protected function assembleAcceptParam(&$value, $key)
{
$separators = ['(', ')', '<', '>', '@', ',', ';', ':',
'/', '[', ']', '?', '=', '{', '}', ' ', "\t"];
$escaped = preg_replace_callback(
'/[[:cntrl:]"\\\\]/', // escape cntrl, ", \
function ($v) {
return '\\' . $v[0];
},
$value
);
if ($escaped == $value && !array_intersect(str_split($value), $separators)) {
$value = $key . '=' . $value;
} else {
$value = $key . '="' . $escaped . '"';
}
return $value;
}
/**
* Add a type, with the given priority
*
* @param string $type
* @param int|float $priority
* @param array (optional) $params
* @throws Exception\InvalidArgumentException
* @return Accept
*/
protected function addType($type, $priority = 1, array $params = [])
{
if (!preg_match($this->regexAddType, $type)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects a valid type; received "%s"',
__METHOD__,
(string) $type
));
}
if (!is_int($priority) && !is_float($priority) && !is_numeric($priority)
|| $priority > 1 || $priority < 0
) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects a numeric priority; received %s',
__METHOD__,
(string) $priority
));
}
if ($priority != 1) {
$params = ['q' => sprintf('%01.1f', $priority)] + $params;
}
$assembledString = $this->getFieldValue(
[(object) ['typeString' => $type, 'params' => $params]]
);
$value = $this->parseFieldValuePart($assembledString);
$this->addFieldValuePartToQueue($value);
return $this;
}
/**
* Does the header have the requested type?
*
* @param array|string $matchAgainst
* @return bool
*/
protected function hasType($matchAgainst)
{
return (bool) $this->match($matchAgainst);
}
/**
* Match a media string against this header
*
* @param array|string $matchAgainst
* @return Accept\FieldValuePArt\AcceptFieldValuePart|bool The matched value or false
*/
public function match($matchAgainst)
{
if (is_string($matchAgainst)) {
$matchAgainst = $this->getFieldValuePartsFromHeaderLine($matchAgainst);
}
foreach ($this->getPrioritized() as $left) {
foreach ($matchAgainst as $right) {
if ($right->type == '*' || $left->type == '*') {
if ($this->matchAcceptParams($left, $right)) {
$left->setMatchedAgainst($right);
return $left;
}
}
if ($left->type == $right->type) {
if (($left->subtype == $right->subtype || ($right->subtype == '*' || $left->subtype == '*')) &&
($left->format == $right->format || $right->format == '*' || $left->format == '*')
) {
if ($this->matchAcceptParams($left, $right)) {
$left->setMatchedAgainst($right);
return $left;
}
}
}
}
}
return false;
}
/**
* Return a match where all parameters in argument #1 match those in argument #2
*
* @param array $match1
* @param array $match2
* @return bool|array
*/
protected function matchAcceptParams($match1, $match2)
{
foreach ($match2->params as $key => $value) {
if (isset($match1->params[$key])) {
if (strpos($value, '-')) {
preg_match(
'/^(?|([^"-]*)|"([^"]*)")-(?|([^"-]*)|"([^"]*)")\z/',
$value,
$pieces
);
if (count($pieces) == 3 &&
(version_compare($pieces[1], $match1->params[$key], '<=') xor
version_compare($pieces[2], $match1->params[$key], '>=')
)
) {
return false;
}
} elseif (strpos($value, '|')) {
$options = explode('|', $value);
$good = false;
foreach ($options as $option) {
if ($option == $match1->params[$key]) {
$good = true;
break;
}
}
if (!$good) {
return false;
}
} elseif ($match1->params[$key] != $value) {
return false;
}
}
}
return $match1;
}
/**
* Add a key/value combination to the internal queue
*
* @param stdClass $value
* @return number
*/
protected function addFieldValuePartToQueue($value)
{
$this->fieldValueParts[] = $value;
$this->sorted = false;
}
/**
* Sort the internal Field Value Parts
*
* @See rfc2616 sect 14.1
* Media ranges can be overridden by more specific media ranges or
* specific media types. If more than one media range applies to a given
* type, the most specific reference has precedence. For example,
*
* Accept: text/*, text/html, text/html;level=1, * /*
*
* have the following precedence:
*
* 1) text/html;level=1
* 2) text/html
* 3) text/*
* 4) * /*
*
* @return number
*/
protected function sortFieldValueParts()
{
$sort = function ($a, $b) { // If A has higher precedence than B, return -1.
if ($a->priority > $b->priority) {
return -1;
} elseif ($a->priority < $b->priority) {
return 1;
}
// Asterisks
$values = ['type', 'subtype', 'format'];
foreach ($values as $value) {
if ($a->$value == '*' && $b->$value != '*') {
return 1;
} elseif ($b->$value == '*' && $a->$value != '*') {
return -1;
}
}
if ($a->type == 'application' && $b->type != 'application') {
return -1;
} elseif ($b->type == 'application' && $a->type != 'application') {
return 1;
}
//@todo count number of dots in case of type==application in subtype
// So far they're still the same. Longest string length may be more specific
if (strlen($a->raw) == strlen($b->raw)) {
return 0;
}
return (strlen($a->raw) > strlen($b->raw)) ? -1 : 1;
};
usort($this->fieldValueParts, $sort);
$this->sorted = true;
}
/**
* @return array with all the keys, values and parameters this header represents:
*/
public function getPrioritized()
{
if (!$this->sorted) {
$this->sortFieldValueParts();
}
return $this->fieldValueParts;
}
}

View File

@@ -0,0 +1,268 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
use DateTime;
use DateTimeZone;
/**
* Abstract Date/Time Header
* Supports headers that have date/time as value
*
* @see Zend\Http\Header\Date
* @see Zend\Http\Header\Expires
* @see Zend\Http\Header\IfModifiedSince
* @see Zend\Http\Header\IfUnmodifiedSince
* @see Zend\Http\Header\LastModified
*
* Note for 'Location' header:
* While RFC 1945 requires an absolute URI, most of the browsers also support relative URI
* This class allows relative URIs, and let user retrieve URI instance if strict validation needed
*/
abstract class AbstractDate implements HeaderInterface
{
/**
* Date formats according to RFC 2616
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
*/
const DATE_RFC1123 = 0;
const DATE_RFC1036 = 1;
const DATE_ANSIC = 2;
/**
* Date instance for this header
*
* @var DateTime
*/
protected $date = null;
/**
* Date output format
*
* @var string
*/
protected static $dateFormat = 'D, d M Y H:i:s \G\M\T';
/**
* Date formats defined by RFC 2616. RFC 1123 date is required
* RFC 1036 and ANSI C formats are provided for compatibility with old servers/clients
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
*
* @var array
*/
protected static $dateFormats = [
self::DATE_RFC1123 => 'D, d M Y H:i:s \G\M\T',
self::DATE_RFC1036 => 'D, d M y H:i:s \G\M\T',
self::DATE_ANSIC => 'D M j H:i:s Y',
];
/**
* Create date-based header from string
*
* @param string $headerLine
* @return AbstractDate
* @throws Exception\InvalidArgumentException
*/
public static function fromString($headerLine)
{
$dateHeader = new static();
list($name, $date) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== strtolower($dateHeader->getFieldName())) {
throw new Exception\InvalidArgumentException(
'Invalid header line for "' . $dateHeader->getFieldName() . '" header string'
);
}
$dateHeader->setDate($date);
return $dateHeader;
}
/**
* Create date-based header from strtotime()-compatible string
*
* @param int|string $time
*
* @return self
*
* @throws Exception\InvalidArgumentException
*/
public static function fromTimeString($time)
{
return static::fromTimestamp(strtotime($time));
}
/**
* Create date-based header from Unix timestamp
*
* @param int $time
*
* @return self
*
* @throws Exception\InvalidArgumentException
*/
public static function fromTimestamp($time)
{
$dateHeader = new static();
if (! $time || ! is_numeric($time)) {
throw new Exception\InvalidArgumentException(
'Invalid time for "' . $dateHeader->getFieldName() . '" header string'
);
}
$dateHeader->setDate(new DateTime('@' . $time));
return $dateHeader;
}
/**
* Set date output format
*
* @param int $format
* @throws Exception\InvalidArgumentException
*/
public static function setDateFormat($format)
{
if (!isset(static::$dateFormats[$format])) {
throw new Exception\InvalidArgumentException(
"No constant defined for provided date format: {$format}"
);
}
static::$dateFormat = static::$dateFormats[$format];
}
/**
* Return current date output format
*
* @return string
*/
public static function getDateFormat()
{
return static::$dateFormat;
}
/**
* Set the date for this header, this can be a string or an instance of \DateTime
*
* @param string|DateTime $date
* @return AbstractDate
* @throws Exception\InvalidArgumentException
*/
public function setDate($date)
{
if (is_string($date)) {
try {
$date = new DateTime($date, new DateTimeZone('GMT'));
} catch (\Exception $e) {
throw new Exception\InvalidArgumentException(
sprintf('Invalid date passed as string (%s)', (string) $date),
$e->getCode(),
$e
);
}
} elseif (!($date instanceof DateTime)) {
throw new Exception\InvalidArgumentException('Date must be an instance of \DateTime or a string');
}
$date->setTimezone(new DateTimeZone('GMT'));
$this->date = $date;
return $this;
}
/**
* Return date for this header
*
* @return string
*/
public function getDate()
{
return $this->date()->format(static::$dateFormat);
}
/**
* Return date for this header as an instance of \DateTime
*
* @return DateTime
*/
public function date()
{
if ($this->date === null) {
$this->date = new DateTime(null, new DateTimeZone('GMT'));
}
return $this->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()
*
* @param string|DateTime $date
* @return int
* @throws Exception\InvalidArgumentException
*/
public function compareTo($date)
{
if (is_string($date)) {
try {
$date = new DateTime($date, new DateTimeZone('GMT'));
} catch (\Exception $e) {
throw new Exception\InvalidArgumentException(
sprintf('Invalid Date passed as string (%s)', (string) $date),
$e->getCode(),
$e
);
}
} elseif (!($date instanceof DateTime)) {
throw new Exception\InvalidArgumentException('Date must be an instance of \DateTime or a string');
}
$dateTimestamp = $date->getTimestamp();
$thisTimestamp = $this->date()->getTimestamp();
return ($thisTimestamp === $dateTimestamp) ? 0 : (($thisTimestamp > $dateTimestamp) ? 1 : -1);
}
/**
* Get header value as formatted date
*
* @return string
*/
public function getFieldValue()
{
return $this->getDate();
}
/**
* Return header line
*
* @return string
*/
public function toString()
{
return $this->getFieldName() . ': ' . $this->getDate();
}
/**
* Allow casting to string
*
* @return string
*/
public function __toString()
{
return $this->toString();
}
}

View File

@@ -0,0 +1,145 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
use Zend\Uri\Exception as UriException;
use Zend\Uri\UriFactory;
use Zend\Uri\UriInterface;
/**
* Abstract Location Header
* Supports headers that have URI as value
* @see Zend\Http\Header\Location
* @see Zend\Http\Header\ContentLocation
* @see Zend\Http\Header\Referer
*
* Note for 'Location' header:
* While RFC 1945 requires an absolute URI, most of the browsers also support relative URI
* This class allows relative URIs, and let user retrieve URI instance if strict validation needed
*/
abstract class AbstractLocation implements HeaderInterface
{
/**
* URI for this header
*
* @var UriInterface
*/
protected $uri = null;
/**
* Create location-based header from string
*
* @param string $headerLine
* @return AbstractLocation
* @throws Exception\InvalidArgumentException
*/
public static function fromString($headerLine)
{
$locationHeader = new static();
// ZF-5520 - IIS bug, no space after colon
list($name, $uri) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== strtolower($locationHeader->getFieldName())) {
throw new Exception\InvalidArgumentException(
'Invalid header line for "' . $locationHeader->getFieldName() . '" header string'
);
}
HeaderValue::assertValid($uri);
$locationHeader->setUri(trim($uri));
return $locationHeader;
}
/**
* Set the URI/URL for this header, this can be a string or an instance of Zend\Uri\Http
*
* @param string|UriInterface $uri
* @return AbstractLocation
* @throws Exception\InvalidArgumentException
*/
public function setUri($uri)
{
if (is_string($uri)) {
try {
$uri = UriFactory::factory($uri);
} catch (UriException\InvalidUriPartException $e) {
throw new Exception\InvalidArgumentException(
sprintf('Invalid URI passed as string (%s)', (string) $uri),
$e->getCode(),
$e
);
}
} elseif (!($uri instanceof UriInterface)) {
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 header
*
* @return string
*/
public function getUri()
{
if ($this->uri instanceof UriInterface) {
return $this->uri->toString();
}
return $this->uri;
}
/**
* Return the URI for this header as an instance of Zend\Uri\Http
*
* @return UriInterface
*/
public function uri()
{
if ($this->uri === null || is_string($this->uri)) {
$this->uri = UriFactory::factory($this->uri);
}
return $this->uri;
}
/**
* Get header value as URI string
*
* @return string
*/
public function getFieldValue()
{
return $this->getUri();
}
/**
* Output header line
*
* @return string
*/
public function toString()
{
return $this->getFieldName() . ': ' . $this->getUri();
}
/**
* Allow casting to string
*
* @return string
*/
public function __toString()
{
return $this->toString();
}
}

View File

@@ -0,0 +1,119 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
use Zend\Http\Header\Accept\FieldValuePart;
/**
* Accept Header
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
*/
class Accept extends AbstractAccept
{
/**
* @var string
*/
protected $regexAddType = '#^([a-zA-Z+-]+|\*)/(\*|[a-zA-Z0-9+-]+)$#';
/**
* Get field name
*
* @return string
*/
public function getFieldName()
{
return 'Accept';
}
/**
* Cast to string
*
* @return string
*/
public function toString()
{
return 'Accept: ' . $this->getFieldValue();
}
/**
* Add a media type, with the given priority
*
* @param string $type
* @param int|float $priority
* @param array $params
* @return Accept
*/
public function addMediaType($type, $priority = 1, array $params = [])
{
return $this->addType($type, $priority, $params);
}
/**
* Does the header have the requested media type?
*
* @param string $type
* @return bool
*/
public function hasMediaType($type)
{
return $this->hasType($type);
}
/**
* Parse the keys contained in the header line
*
* @param string $fieldValuePart
* @return FieldValuePart\AcceptFieldValuePart
* @see \Zend\Http\Header\AbstractAccept::parseFieldValuePart()
*/
protected function parseFieldValuePart($fieldValuePart)
{
$raw = $fieldValuePart;
if ($pos = strpos($fieldValuePart, '/')) {
$type = trim(substr($fieldValuePart, 0, $pos));
} else {
$type = trim($fieldValuePart);
}
$params = $this->getParametersFromFieldValuePart($fieldValuePart);
if ($pos = strpos($fieldValuePart, ';')) {
$fieldValuePart = trim(substr($fieldValuePart, 0, $pos));
}
if (strpos($fieldValuePart, '/')) {
$subtypeWhole = $format = $subtype = trim(substr($fieldValuePart, strpos($fieldValuePart, '/') + 1));
} else {
$subtypeWhole = '';
$format = '*';
$subtype = '*';
}
$pos = strpos($subtype, '+');
if (false !== $pos) {
$format = trim(substr($subtype, $pos + 1));
$subtype = trim(substr($subtype, 0, $pos));
}
$aggregated = [
'typeString' => trim($fieldValuePart),
'type' => $type,
'subtype' => $subtype,
'subtypeRaw' => $subtypeWhole,
'format' => $format,
'priority' => isset($params['q']) ? $params['q'] : 1,
'params' => $params,
'raw' => trim($raw),
];
return new FieldValuePart\AcceptFieldValuePart((object) $aggregated);
}
}

View File

@@ -0,0 +1,113 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header\Accept\FieldValuePart;
/**
* Field Value Part
*
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
*/
abstract class AbstractFieldValuePart
{
/**
* Internal object used for value retrieval
* @var object
*/
private $internalValues;
/**
* A Field Value Part this Field Value Part matched against.
* @var AbstractFieldValuePart
*/
protected $matchedAgainst;
/**
*
* @param object $internalValues
*/
public function __construct($internalValues)
{
$this->internalValues = $internalValues;
}
/**
* Set a Field Value Part this Field Value Part matched against.
*
* @param AbstractFieldValuePart $matchedAgainst
* @return AbstractFieldValuePart provides fluent interface
*/
public function setMatchedAgainst(AbstractFieldValuePart $matchedAgainst)
{
$this->matchedAgainst = $matchedAgainst;
return $this;
}
/**
* Get a Field Value Part this Field Value Part matched against.
*
* @return AbstractFieldValuePart|null
*/
public function getMatchedAgainst()
{
return $this->matchedAgainst;
}
/**
*
* @return object
*/
protected function getInternalValues()
{
return $this->internalValues;
}
/**
* @return string $typeString
*/
public function getTypeString()
{
return $this->getInternalValues()->typeString;
}
/**
* @return float $priority
*/
public function getPriority()
{
return (float) $this->getInternalValues()->priority;
}
/**
* @return \stdClass $params
*/
public function getParams()
{
return (object) $this->getInternalValues()->params;
}
/**
* @return string $raw
*/
public function getRaw()
{
return $this->getInternalValues()->raw;
}
/**
*
* @param mixed
* @return mixed
*/
public function __get($key)
{
return $this->getInternalValues()->$key;
}
}

View File

@@ -0,0 +1,43 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header\Accept\FieldValuePart;
/**
* Field Value Part
*
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
*/
class AcceptFieldValuePart extends AbstractFieldValuePart
{
/**
* @return string
*/
public function getSubtype()
{
return $this->getInternalValues()->subtype;
}
/**
* @return string
*/
public function getSubtypeRaw()
{
return $this->getInternalValues()->subtypeRaw;
}
/**
* @return string
*/
public function getFormat()
{
return $this->getInternalValues()->format;
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header\Accept\FieldValuePart;
/**
* Field Value Part
*
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
*/
class CharsetFieldValuePart extends AbstractFieldValuePart
{
/**
*
* @return string
*/
public function getCharset()
{
return $this->getInternalValues()->type;
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header\Accept\FieldValuePart;
/**
* Field Value Part
*
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
*/
class EncodingFieldValuePart extends AbstractFieldValuePart
{
/**
*
* @return string
*/
public function getEncoding()
{
return $this->getInternalValues()->type;
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header\Accept\FieldValuePart;
/**
* Field Value Part
*
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
*/
class LanguageFieldValuePart extends AbstractFieldValuePart
{
public function getLanguage()
{
return $this->getInternalValues()->typeString;
}
public function getPrimaryTag()
{
return $this->getInternalValues()->type;
}
public function getSubTag()
{
return $this->getInternalValues()->subtype;
}
}

View File

@@ -0,0 +1,79 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
use Zend\Http\Header\Accept\FieldValuePart;
/**
* Accept Charset Header
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2
*/
class AcceptCharset extends AbstractAccept
{
protected $regexAddType = '#^([a-zA-Z0-9+-]+|\*)$#';
/**
* Get field name
*
* @return string
*/
public function getFieldName()
{
return 'Accept-Charset';
}
/**
* Cast to string
*
* @return string
*/
public function toString()
{
return 'Accept-Charset: ' . $this->getFieldValue();
}
/**
* Add a charset, with the given priority
*
* @param string $type
* @param int|float $priority
* @return Accept
*/
public function addCharset($type, $priority = 1)
{
return $this->addType($type, $priority);
}
/**
* Does the header have the requested charset?
*
* @param string $type
* @return bool
*/
public function hasCharset($type)
{
return $this->hasType($type);
}
/**
* Parse the keys contained in the header line
*
* @param string $fieldValuePart
* @return \Zend\Http\Header\Accept\FieldValuePart\CharsetFieldValuePart
* @see \Zend\Http\Header\AbstractAccept::parseFieldValuePart()
*/
protected function parseFieldValuePart($fieldValuePart)
{
$internalValues = parent::parseFieldValuePart($fieldValuePart);
return new FieldValuePart\CharsetFieldValuePart($internalValues);
}
}

View File

@@ -0,0 +1,79 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
use Zend\Http\Header\Accept\FieldValuePart;
/**
* Accept Encoding Header
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
*/
class AcceptEncoding extends AbstractAccept
{
protected $regexAddType = '#^([a-zA-Z0-9+-]+|\*)$#';
/**
* Get field name
*
* @return string
*/
public function getFieldName()
{
return 'Accept-Encoding';
}
/**
* Cast to string
*
* @return string
*/
public function toString()
{
return 'Accept-Encoding: ' . $this->getFieldValue();
}
/**
* Add an encoding, with the given priority
*
* @param string $type
* @param int|float $priority
* @return Accept
*/
public function addEncoding($type, $priority = 1)
{
return $this->addType($type, $priority);
}
/**
* Does the header have the requested encoding?
*
* @param string $type
* @return bool
*/
public function hasEncoding($type)
{
return $this->hasType($type);
}
/**
* Parse the keys contained in the header line
*
* @param string $fieldValuePart
* @return \Zend\Http\Header\Accept\FieldValuePart\EncodingFieldValuePart
* @see \Zend\Http\Header\AbstractAccept::parseFieldValuePart()
*/
protected function parseFieldValuePart($fieldValuePart)
{
$internalValues = parent::parseFieldValuePart($fieldValuePart);
return new FieldValuePart\EncodingFieldValuePart($internalValues);
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
use Zend\Http\Header\Accept\FieldValuePart;
/**
* Accept Language Header
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
*/
class AcceptLanguage extends AbstractAccept
{
protected $regexAddType = '#^([a-zA-Z0-9+-]+|\*)$#';
/**
* Get field name
*
* @return string
*/
public function getFieldName()
{
return 'Accept-Language';
}
/**
* Cast to string
*
* @return string
*/
public function toString()
{
return 'Accept-Language: ' . $this->getFieldValue();
}
/**
* Add a language, with the given priority
*
* @param string $type
* @param int|float $priority
* @return Accept
*/
public function addLanguage($type, $priority = 1)
{
return $this->addType($type, $priority);
}
/**
* Does the header have the requested language?
*
* @param string $type
* @return bool
*/
public function hasLanguage($type)
{
return $this->hasType($type);
}
/**
* Parse the keys contained in the header line
*
* @param string $fieldValuePart
* @return \Zend\Http\Header\Accept\FieldValuePart\LanguageFieldValuePart
* @see \Zend\Http\Header\AbstractAccept::parseFieldValuePart()
*/
protected function parseFieldValuePart($fieldValuePart)
{
$raw = $fieldValuePart;
if ($pos = strpos($fieldValuePart, '-')) {
$type = trim(substr($fieldValuePart, 0, $pos));
} else {
$type = trim(substr($fieldValuePart, 0));
}
$params = $this->getParametersFromFieldValuePart($fieldValuePart);
if ($pos = strpos($fieldValuePart, ';')) {
$fieldValuePart = $type = trim(substr($fieldValuePart, 0, $pos));
}
if (strpos($fieldValuePart, '-')) {
$subtypeWhole = $format = $subtype = trim(substr($fieldValuePart, strpos($fieldValuePart, '-')+1));
} else {
$subtypeWhole = '';
$format = '*';
$subtype = '*';
}
$aggregated = [
'typeString' => trim($fieldValuePart),
'type' => $type,
'subtype' => $subtype,
'subtypeRaw' => $subtypeWhole,
'format' => $format,
'priority' => isset($params['q']) ? $params['q'] : 1,
'params' => $params,
'raw' => trim($raw)
];
return new FieldValuePart\LanguageFieldValuePart((object) $aggregated);
}
}

View File

@@ -0,0 +1,70 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* Accept Ranges Header
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.5
*/
class AcceptRanges implements HeaderInterface
{
protected $rangeUnit;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'accept-ranges') {
throw new Exception\InvalidArgumentException(
'Invalid header line for Accept-Ranges string'
);
}
$header = new static($value);
return $header;
}
public function __construct($rangeUnit = null)
{
if ($rangeUnit) {
$this->setRangeUnit($rangeUnit);
}
}
public function getFieldName()
{
return 'Accept-Ranges';
}
public function getFieldValue()
{
return $this->getRangeUnit();
}
public function setRangeUnit($rangeUnit)
{
HeaderValue::assertValid($rangeUnit);
$this->rangeUnit = $rangeUnit;
return $this;
}
public function getRangeUnit()
{
return $this->rangeUnit;
}
public function toString()
{
return 'Accept-Ranges: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* Age HTTP Header
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.6
*/
class Age implements HeaderInterface
{
/**
* Estimate of the amount of time in seconds since the response
*
* @var int
*/
protected $deltaSeconds;
/**
* Create Age header from string
*
* @param string $headerLine
* @return Age
* @throws Exception\InvalidArgumentException
*/
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'age') {
throw new Exception\InvalidArgumentException('Invalid header line for Age string: "' . $name . '"');
}
$header = new static($value);
return $header;
}
public function __construct($deltaSeconds = null)
{
if ($deltaSeconds) {
$this->setDeltaSeconds($deltaSeconds);
}
}
/**
* Get header name
*
* @return string
*/
public function getFieldName()
{
return 'Age';
}
/**
* Get header value (number of seconds)
*
* @return int
*/
public function getFieldValue()
{
return $this->getDeltaSeconds();
}
/**
* Set number of seconds
*
* @param int $delta
* @return RetryAfter
*/
public function setDeltaSeconds($delta)
{
if (! is_int($delta) && ! is_numeric($delta)) {
throw new Exception\InvalidArgumentException('Invalid delta provided');
}
$this->deltaSeconds = (int) $delta;
return $this;
}
/**
* Get number of seconds
*
* @return int
*/
public function getDeltaSeconds()
{
return $this->deltaSeconds;
}
/**
* Return header line
* In case of overflow RFC states to set value of 2147483648 (2^31)
*
* @return string
*/
public function toString()
{
return 'Age: ' . (($this->deltaSeconds >= PHP_INT_MAX) ? '2147483648' : $this->deltaSeconds);
}
}

View File

@@ -0,0 +1,185 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
use Zend\Http\Request;
/**
* Allow Header
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.7
*/
class Allow implements HeaderInterface
{
/**
* List of request methods
* true states that method is allowed, false - disallowed
* By default GET and POST are allowed
*
* @var array
*/
protected $methods = [
Request::METHOD_OPTIONS => false,
Request::METHOD_GET => true,
Request::METHOD_HEAD => false,
Request::METHOD_POST => true,
Request::METHOD_PUT => false,
Request::METHOD_DELETE => false,
Request::METHOD_TRACE => false,
Request::METHOD_CONNECT => false,
Request::METHOD_PATCH => false,
];
/**
* Create Allow header from header line
*
* @param string $headerLine
* @return Allow
* @throws Exception\InvalidArgumentException
*/
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'allow') {
throw new Exception\InvalidArgumentException('Invalid header line for Allow string: "' . $name . '"');
}
$header = new static();
$header->disallowMethods(array_keys($header->getAllMethods()));
$header->allowMethods(explode(',', $value));
return $header;
}
/**
* Get header name
*
* @return string
*/
public function getFieldName()
{
return 'Allow';
}
/**
* Get comma-separated list of allowed methods
*
* @return string
*/
public function getFieldValue()
{
return implode(', ', array_keys($this->methods, true, true));
}
/**
* Get list of all defined methods
*
* @return array
*/
public function getAllMethods()
{
return $this->methods;
}
/**
* Get list of allowed methods
*
* @return array
*/
public function getAllowedMethods()
{
return array_keys($this->methods, true, true);
}
/**
* Allow methods or list of methods
*
* @param array|string $allowedMethods
* @return Allow
*/
public function allowMethods($allowedMethods)
{
foreach ((array) $allowedMethods as $method) {
$method = trim(strtoupper($method));
if (preg_match('/\s/', $method)) {
throw new Exception\InvalidArgumentException(sprintf(
'Unable to whitelist method; "%s" is not a valid method',
$method
));
}
$this->methods[$method] = true;
}
return $this;
}
/**
* Disallow methods or list of methods
*
* @param array|string $disallowedMethods
* @return Allow
*/
public function disallowMethods($disallowedMethods)
{
foreach ((array) $disallowedMethods as $method) {
$method = trim(strtoupper($method));
if (preg_match('/\s/', $method)) {
throw new Exception\InvalidArgumentException(sprintf(
'Unable to blacklist method; "%s" is not a valid method',
$method
));
}
$this->methods[$method] = false;
}
return $this;
}
/**
* Convenience alias for @see disallowMethods()
*
* @param array|string $disallowedMethods
* @return Allow
*/
public function denyMethods($disallowedMethods)
{
return $this->disallowMethods($disallowedMethods);
}
/**
* Check whether method is allowed
*
* @param string $method
* @return bool
*/
public function isAllowedMethod($method)
{
$method = trim(strtoupper($method));
// disallow unknown method
if (! isset($this->methods[$method])) {
$this->methods[$method] = false;
}
return $this->methods[$method];
}
/**
* Return header as string
*
* @return string
*/
public function toString()
{
return 'Allow: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.ietf.org/rfc/rfc2617.txt
*/
class AuthenticationInfo implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'authentication-info') {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for Authentication-Info string: "%s"',
$name
));
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Authentication-Info';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Authentication-Info: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.8
*/
class Authorization implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'authorization') {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for Authorization string: "%s"',
$name
));
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Authorization';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Authorization: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,252 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
*/
class CacheControl implements HeaderInterface
{
/**
* @var string
*/
protected $value;
/**
* Array of Cache-Control directives
*
* @var array
*/
protected $directives = [];
/**
* Creates a CacheControl object from a headerLine
*
* @param string $headerLine
* @throws Exception\InvalidArgumentException
* @return CacheControl
*/
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'cache-control') {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for Cache-Control string: ""',
$name
));
}
HeaderValue::assertValid($value);
$directives = static::parseValue($value);
// @todo implementation details
$header = new static();
foreach ($directives as $key => $value) {
$header->addDirective($key, $value);
}
return $header;
}
/**
* Required from HeaderDescription interface
*
* @return string
*/
public function getFieldName()
{
return 'Cache-Control';
}
/**
* Checks if the internal directives array is empty
*
* @return bool
*/
public function isEmpty()
{
return empty($this->directives);
}
/**
* Add a directive
* For directives like 'max-age=60', $value = '60'
* For directives like 'private', use the default $value = true
*
* @param string $key
* @param string|bool $value
* @return CacheControl - provides the fluent interface
*/
public function addDirective($key, $value = true)
{
HeaderValue::assertValid($key);
if (! is_bool($value)) {
HeaderValue::assertValid($value);
}
$this->directives[$key] = $value;
return $this;
}
/**
* Check the internal directives array for a directive
*
* @param string $key
* @return bool
*/
public function hasDirective($key)
{
return array_key_exists($key, $this->directives);
}
/**
* Fetch the value of a directive from the internal directive array
*
* @param string $key
* @return string|null
*/
public function getDirective($key)
{
return array_key_exists($key, $this->directives) ? $this->directives[$key] : null;
}
/**
* Remove a directive
*
* @param string $key
* @return CacheControl - provides the fluent interface
*/
public function removeDirective($key)
{
unset($this->directives[$key]);
return $this;
}
/**
* Assembles the directives into a comma-delimited string
*
* @return string
*/
public function getFieldValue()
{
$parts = [];
ksort($this->directives);
foreach ($this->directives as $key => $value) {
if (true === $value) {
$parts[] = $key;
} else {
if (preg_match('#[^a-zA-Z0-9._-]#', $value)) {
$value = '"' . $value.'"';
}
$parts[] = "$key=$value";
}
}
return implode(', ', $parts);
}
/**
* Returns a string representation of the HTTP Cache-Control header
*
* @return string
*/
public function toString()
{
return 'Cache-Control: ' . $this->getFieldValue();
}
/**
* Internal function for parsing the value part of a
* HTTP Cache-Control header
*
* @param string $value
* @throws Exception\InvalidArgumentException
* @return array
*/
protected static function parseValue($value)
{
$value = trim($value);
$directives = [];
// handle empty string early so we don't need a separate start state
if ($value == '') {
return $directives;
}
$lastMatch = null;
state_directive:
switch (static::match(['[a-zA-Z][a-zA-Z_-]*'], $value, $lastMatch)) {
case 0:
$directive = $lastMatch;
goto state_value;
// intentional fall-through
default:
throw new Exception\InvalidArgumentException('expected DIRECTIVE');
}
state_value:
switch (static::match(['="[^"]*"', '=[^",\s;]*'], $value, $lastMatch)) {
case 0:
$directives[$directive] = substr($lastMatch, 2, -1);
goto state_separator;
// intentional fall-through
case 1:
$directives[$directive] = rtrim(substr($lastMatch, 1));
goto state_separator;
// intentional fall-through
default:
$directives[$directive] = true;
goto state_separator;
}
state_separator:
switch (static::match(['\s*,\s*', '$'], $value, $lastMatch)) {
case 0:
goto state_directive;
// intentional fall-through
case 1:
return $directives;
default:
throw new Exception\InvalidArgumentException('expected SEPARATOR or END');
}
}
/**
* Internal function used by parseValue to match tokens
*
* @param array $tokens
* @param string $string
* @param string $lastMatch
* @return int
*/
protected static function match($tokens, &$string, &$lastMatch)
{
// Ensure we have a string
$value = (string) $string;
foreach ($tokens as $i => $token) {
if (preg_match('/^' . $token . '/', $value, $matches)) {
$lastMatch = $matches[0];
$string = substr($value, strlen($matches[0]));
return $i;
}
}
return -1;
}
}

View File

@@ -0,0 +1,117 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* Connection Header
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.10
*/
class Connection implements HeaderInterface
{
const CONNECTION_CLOSE = 'close';
const CONNECTION_KEEP_ALIVE = 'keep-alive';
/**
* Value of this header
*
* @var string
*/
protected $value = self::CONNECTION_KEEP_ALIVE;
/**
* @param $headerLine
* @return Connection
* @throws Exception\InvalidArgumentException
*/
public static function fromString($headerLine)
{
$header = new static();
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'connection') {
throw new Exception\InvalidArgumentException('Invalid header line for Connection string: "' . $name . '"');
}
$header->setValue(trim($value));
return $header;
}
/**
* Set Connection header to define persistent connection
*
* @param bool $flag
* @return Connection
*/
public function setPersistent($flag)
{
$this->value = (bool) $flag
? self::CONNECTION_KEEP_ALIVE
: self::CONNECTION_CLOSE;
return $this;
}
/**
* Get whether this connection is persistent
*
* @return bool
*/
public function isPersistent()
{
return ($this->value === self::CONNECTION_KEEP_ALIVE);
}
/**
* Set arbitrary header value
* RFC allows any token as value, 'close' and 'keep-alive' are commonly used
*
* @param string $value
* @return Connection
*/
public function setValue($value)
{
HeaderValue::assertValid($value);
$this->value = strtolower($value);
return $this;
}
/**
* Connection header name
*
* @return string
*/
public function getFieldName()
{
return 'Connection';
}
/**
* Connection header value
*
* @return string
*/
public function getFieldValue()
{
return $this->value;
}
/**
* Return header line
*
* @return string
*/
public function toString()
{
return 'Connection: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1
*/
class ContentDisposition implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'content-disposition') {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for Content-Disposition string: "%s"',
$name
));
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Content-Disposition';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Content-Disposition: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,62 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11
*/
class ContentEncoding implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'content-encoding') {
throw new Exception\InvalidArgumentException(
'Invalid header line for Content-Encoding string: "' . $name . '"'
);
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Content-Encoding';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Content-Encoding: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.12
*/
class ContentLanguage implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'content-language') {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for Content-Language string: "%s"',
$name
));
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Content-Language';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Content-Language: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
*/
class ContentLength implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'content-length') {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for Content-Length string: "%s"',
$name
));
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Content-Length';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Content-Length: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* Content-Location Header
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.14
*/
class ContentLocation extends AbstractLocation
{
/**
* Return header name
*
* @return string
*/
public function getFieldName()
{
return 'Content-Location';
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.15
*/
class ContentMD5 implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'content-md5') {
throw new Exception\InvalidArgumentException('Invalid header line for Content-MD5 string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Content-MD5';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Content-MD5: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16
*/
class ContentRange implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'content-range') {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for Content-Range string: "%s"',
$name
));
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Content-Range';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Content-Range: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,153 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* Content Security Policy 1.0 Header
*
* @link http://www.w3.org/TR/CSP/
*/
class ContentSecurityPolicy implements HeaderInterface
{
/**
* Valid directive names
*
* @var array
*/
protected $validDirectiveNames = [
// As per http://www.w3.org/TR/CSP/#directives
'default-src',
'script-src',
'object-src',
'style-src',
'img-src',
'media-src',
'frame-src',
'font-src',
'connect-src',
'sandbox',
'report-uri',
];
/**
* The directives defined for this policy
*
* @var array
*/
protected $directives = [];
/**
* Get the list of defined directives
*
* @return array
*/
public function getDirectives()
{
return $this->directives;
}
/**
* Sets the directive to consist of the source list
*
* Reverses http://www.w3.org/TR/CSP/#parsing-1
*
* @param string $name The directive name.
* @param array $sources The source list.
* @return self
* @throws Exception\InvalidArgumentException If the name is not a valid directive name.
*/
public function setDirective($name, array $sources)
{
if (! in_array($name, $this->validDirectiveNames, true)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects a valid directive name; received "%s"',
__METHOD__,
(string) $name
));
}
if (empty($sources)) {
$this->directives[$name] = "'none'";
return $this;
}
array_walk($sources, [__NAMESPACE__ . '\HeaderValue', 'assertValid']);
$this->directives[$name] = implode(' ', $sources);
return $this;
}
/**
* Create Content Security Policy header from a given header line
*
* @param string $headerLine The header line to parse.
* @return self
* @throws Exception\InvalidArgumentException If the name field in the given header line does not match.
*/
public static function fromString($headerLine)
{
$header = new static();
$headerName = $header->getFieldName();
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// Ensure the proper header name
if (strcasecmp($name, $headerName) != 0) {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for %s string: "%s"',
$headerName,
$name
));
}
// As per http://www.w3.org/TR/CSP/#parsing
$tokens = explode(';', $value);
foreach ($tokens as $token) {
$token = trim($token);
if ($token) {
list($directiveName, $directiveValue) = explode(' ', $token, 2);
if (!isset($header->directives[$directiveName])) {
$header->setDirective($directiveName, [$directiveValue]);
}
}
}
return $header;
}
/**
* Get the header name
*
* @return string
*/
public function getFieldName()
{
return 'Content-Security-Policy';
}
/**
* Get the header value
*
* @return string
*/
public function getFieldValue()
{
$directives = [];
foreach ($this->directives as $name => $value) {
$directives[] = sprintf('%s %s;', $name, $value);
}
return implode(' ', $directives);
}
/**
* Return the header as a string
*
* @return string
*/
public function toString()
{
return sprintf('%s: %s', $this->getFieldName(), $this->getFieldValue());
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11 @todo find section
*/
class ContentTransferEncoding implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'content-transfer-encoding') {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for Content-Transfer-Encoding string: "%s"',
$name
));
}
// @todo implementation details
$header = new static(strtolower($value));
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Content-Transfer-Encoding';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Content-Transfer-Encoding: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,404 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
use stdClass;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17
*/
class ContentType implements HeaderInterface
{
/**
* @var string
*/
protected $mediaType;
/**
* @var array
*/
protected $parameters = [];
/**
* @var string
*/
protected $value;
/**
* Factory method: create an object from a string representation
*
* @param string $headerLine
* @return self
*/
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'content-type') {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for Content-Type string: "%s"',
$name
));
}
$parts = explode(';', $value);
$mediaType = array_shift($parts);
$header = new static($value, trim($mediaType));
if (count($parts) > 0) {
$parameters = [];
foreach ($parts as $parameter) {
$parameter = trim($parameter);
if (!preg_match('/^(?P<key>[^\s\=]+)\="?(?P<value>[^\s\"]*)"?$/', $parameter, $matches)) {
continue;
}
$parameters[$matches['key']] = $matches['value'];
}
$header->setParameters($parameters);
}
return $header;
}
public function __construct($value = null, $mediaType = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
$this->mediaType = $mediaType;
}
/**
* Determine if the mediatype value in this header matches the provided criteria
*
* @param array|string $matchAgainst
* @return string|bool Matched value or false
*/
public function match($matchAgainst)
{
if (is_string($matchAgainst)) {
$matchAgainst = $this->splitMediaTypesFromString($matchAgainst);
}
$mediaType = $this->getMediaType();
$left = $this->getMediaTypeObjectFromString($mediaType);
foreach ($matchAgainst as $matchType) {
$matchType = strtolower($matchType);
if ($mediaType == $matchType) {
return $matchType;
}
$right = $this->getMediaTypeObjectFromString($matchType);
// Is the right side a wildcard type?
if ($right->type == '*') {
if ($this->validateSubtype($right, $left)) {
return $matchType;
}
}
// Do the types match?
if ($right->type == $left->type) {
if ($this->validateSubtype($right, $left)) {
return $matchType;
}
}
}
return false;
}
/**
* Create a string representation of the header
*
* @return string
*/
public function toString()
{
return 'Content-Type: ' . $this->getFieldValue();
}
/**
* Get the field name
*
* @return string
*/
public function getFieldName()
{
return 'Content-Type';
}
/**
* Get the field value
*
* @return string
*/
public function getFieldValue()
{
if (null !== $this->value) {
return $this->value;
}
return $this->assembleValue();
}
/**
* Set the media type
*
* @param string $mediaType
* @return self
*/
public function setMediaType($mediaType)
{
HeaderValue::assertValid($mediaType);
$this->mediaType = strtolower($mediaType);
$this->value = null;
return $this;
}
/**
* Get the media type
*
* @return string
*/
public function getMediaType()
{
return $this->mediaType;
}
/**
* Set additional content-type parameters
*
* @param array $parameters
* @return self
*/
public function setParameters(array $parameters)
{
foreach ($parameters as $key => $value) {
HeaderValue::assertValid($key);
HeaderValue::assertValid($value);
}
$this->parameters = array_merge($this->parameters, $parameters);
$this->value = null;
return $this;
}
/**
* Get any additional content-type parameters currently set
*
* @return array
*/
public function getParameters()
{
return $this->parameters;
}
/**
* Set the content-type character set encoding
*
* @param string $charset
* @return self
*/
public function setCharset($charset)
{
HeaderValue::assertValid($charset);
$this->parameters['charset'] = $charset;
$this->value = null;
return $this;
}
/**
* Get the content-type character set encoding, if any
*
* @return null|string
*/
public function getCharset()
{
if (isset($this->parameters['charset'])) {
return $this->parameters['charset'];
}
return;
}
/**
* Assemble the value based on the media type and any available parameters
*
* @return string
*/
protected function assembleValue()
{
$mediaType = $this->getMediaType();
if (empty($this->parameters)) {
return $mediaType;
}
$parameters = [];
foreach ($this->parameters as $key => $value) {
$parameters[] = sprintf('%s=%s', $key, $value);
}
return sprintf('%s; %s', $mediaType, implode('; ', $parameters));
}
/**
* Split comma-separated media types into an array
*
* @param string $criteria
* @return array
*/
protected function splitMediaTypesFromString($criteria)
{
$mediaTypes = explode(',', $criteria);
array_walk(
$mediaTypes,
function (&$value) {
$value = trim($value);
}
);
return $mediaTypes;
}
/**
* Split a mediatype string into an object with the following parts:
*
* - type
* - subtype
* - format
*
* @param string $string
* @return stdClass
*/
protected function getMediaTypeObjectFromString($string)
{
if (!is_string($string)) {
throw new Exception\InvalidArgumentException(sprintf(
'Non-string mediatype "%s" provided',
(is_object($string) ? get_class($string) : gettype($string))
));
}
$parts = explode('/', $string, 2);
if (1 == count($parts)) {
throw new Exception\DomainException(sprintf(
'Invalid mediatype "%s" provided',
$string
));
}
$type = array_shift($parts);
$subtype = array_shift($parts);
$format = $subtype;
if (strstr($subtype, '+')) {
$parts = explode('+', $subtype, 2);
$subtype = array_shift($parts);
$format = array_shift($parts);
}
$mediaType = (object) [
'type' => $type,
'subtype' => $subtype,
'format' => $format,
];
return $mediaType;
}
/**
* Validate a subtype
*
* @param stdClass $right
* @param stdClass $left
* @return bool
*/
protected function validateSubtype($right, $left)
{
// Is the right side a wildcard subtype?
if ($right->subtype == '*') {
return $this->validateFormat($right, $left);
}
// Do the right side and left side subtypes match?
if ($right->subtype == $left->subtype) {
return $this->validateFormat($right, $left);
}
// Is the right side a partial wildcard?
if ('*' == substr($right->subtype, -1)) {
// validate partial-wildcard subtype
if (!$this->validatePartialWildcard($right->subtype, $left->subtype)) {
return false;
}
// Finally, verify format is valid
return $this->validateFormat($right, $left);
}
// Does the right side subtype match the left side format?
if ($right->subtype == $left->format) {
return true;
}
// At this point, there is no valid match
return false;
}
/**
* Validate the format
*
* Validate that the right side format matches what the left side defines.
*
* @param string $right
* @param string $left
* @return bool
*/
protected function validateFormat($right, $left)
{
if ($right->format && $left->format) {
if ($right->format == '*') {
return true;
}
if ($right->format == $left->format) {
return true;
}
return false;
}
return true;
}
/**
* Validate a partial wildcard (i.e., string ending in '*')
*
* @param string $right
* @param string $left
* @return bool
*/
protected function validatePartialWildcard($right, $left)
{
$requiredSegment = substr($right, 0, strlen($right) - 1);
if ($requiredSegment == $left) {
return true;
}
if (strlen($requiredSegment) >= strlen($left)) {
return false;
}
if (0 === strpos($left, $requiredSegment)) {
return true;
}
return false;
}
}

View File

@@ -0,0 +1,122 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
use ArrayObject;
/**
* @see http://www.ietf.org/rfc/rfc2109.txt
* @see http://www.w3.org/Protocols/rfc2109/rfc2109
*/
class Cookie extends ArrayObject implements HeaderInterface
{
protected $encodeValue = true;
public static function fromSetCookieArray(array $setCookies)
{
$nvPairs = [];
foreach ($setCookies as $setCookie) {
if (! $setCookie instanceof SetCookie) {
throw new Exception\InvalidArgumentException(sprintf(
'%s requires an array of SetCookie objects',
__METHOD__
));
}
if (array_key_exists($setCookie->getName(), $nvPairs)) {
throw new Exception\InvalidArgumentException(sprintf(
'Two cookies with the same name were provided to %s',
__METHOD__
));
}
$nvPairs[$setCookie->getName()] = $setCookie->getValue();
}
return new static($nvPairs);
}
public static function fromString($headerLine)
{
$header = new static();
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'cookie') {
throw new Exception\InvalidArgumentException('Invalid header line for Server string: "' . $name . '"');
}
$nvPairs = preg_split('#;\s*#', $value);
$arrayInfo = [];
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 = [])
{
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 = [];
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();
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* Date Header
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.18
*/
class Date extends AbstractDate
{
/**
* Get header name
*
* @return string
*/
public function getFieldName()
{
return 'Date';
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19
*/
class Etag implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'etag') {
throw new Exception\InvalidArgumentException('Invalid header line for Etag string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Etag';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Etag: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,14 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header\Exception;
class DomainException extends \DomainException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,16 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header\Exception;
use Zend\Http\Exception\ExceptionInterface as HttpException;
interface ExceptionInterface extends HttpException
{
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header\Exception;
use Zend\Http\Exception;
class InvalidArgumentException extends Exception\InvalidArgumentException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header\Exception;
use Zend\Http\Exception;
class RuntimeException extends Exception\RuntimeException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.20
*/
class Expect implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'expect') {
throw new Exception\InvalidArgumentException('Invalid header line for Expect string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Expect';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Expect: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* Expires Header
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21
*/
class Expires extends AbstractDate
{
/**
* Get header name
*
* @return string
*/
public function getFieldName()
{
return 'Expires';
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.22
*/
class From implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'from') {
throw new Exception\InvalidArgumentException('Invalid header line for From string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'From';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'From: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,164 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* Content-Location Header
*
*/
class GenericHeader implements HeaderInterface
{
/**
* @var string
*/
protected $fieldName = null;
/**
* @var string
*/
protected $fieldValue = null;
/**
* Factory to generate a header object from a string
*
* @static
* @param string $headerLine
* @return GenericHeader
*/
public static function fromString($headerLine)
{
list($fieldName, $fieldValue) = GenericHeader::splitHeaderLine($headerLine);
$header = new static($fieldName, $fieldValue);
return $header;
}
/**
* Splits the header line in `name` and `value` parts.
*
* @param string $headerLine
* @return string[] `name` in the first index and `value` in the second.
* @throws Exception\InvalidArgumentException If header does not match with the format ``name:value``
*/
public static function splitHeaderLine($headerLine)
{
$parts = explode(':', $headerLine, 2);
if (count($parts) !== 2) {
throw new Exception\InvalidArgumentException('Header must match with the format "name:value"');
}
if (! HeaderValue::isValid($parts[1])) {
throw new Exception\InvalidArgumentException('Invalid header value detected');
}
$parts[1] = ltrim($parts[1]);
return $parts;
}
/**
* Constructor
*
* @param null|string $fieldName
* @param null|string $fieldValue
*/
public function __construct($fieldName = null, $fieldValue = null)
{
if ($fieldName) {
$this->setFieldName($fieldName);
}
if ($fieldValue !== null) {
$this->setFieldValue($fieldValue);
}
}
/**
* Set header field name
*
* @param string $fieldName
* @return GenericHeader
* @throws Exception\InvalidArgumentException If the name does not match with RFC 2616 format.
*/
public function setFieldName($fieldName)
{
if (!is_string($fieldName) || empty($fieldName)) {
throw new Exception\InvalidArgumentException('Header name must be a string');
}
/*
* Following RFC 7230 section 3.2
*
* header-field = field-name ":" [ field-value ]
* field-name = token
* token = 1*tchar
* tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
* "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
*/
if (!preg_match('/^[!#$%&\'*+\-\.\^_`|~0-9a-zA-Z]+$/', $fieldName)) {
throw new Exception\InvalidArgumentException(
'Header name must be a valid RFC 7230 (section 3.2) field-name.'
);
}
$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;
HeaderValue::assertValid($fieldValue);
if (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()
{
return $this->getFieldName() . ': ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,42 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
class GenericMultiHeader extends GenericHeader implements MultipleHeaderInterface
{
public static function fromString($headerLine)
{
list($fieldName, $fieldValue) = GenericHeader::splitHeaderLine($headerLine);
if (strpos($fieldValue, ',')) {
$headers = [];
foreach (explode(',', $fieldValue) as $multiValue) {
$headers[] = new static($fieldName, $multiValue);
}
return $headers;
} else {
$header = new static($fieldName, $fieldValue);
return $header;
}
}
public function toStringMultipleHeaders(array $headers)
{
$name = $this->getFieldName();
$values = [$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";
}
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* Interface for HTTP Header classes.
*/
interface HeaderInterface
{
/**
* Factory to generate a header object from a string
*
* @param string $headerLine
* @return self
* @throws Exception\InvalidArgumentException If the header does not match RFC 2616 definition.
* @see http://tools.ietf.org/html/rfc2616#section-4.2
*/
public static function fromString($headerLine);
/**
* Retrieve header name
*
* @return string
*/
public function getFieldName();
/**
* Retrieve header value
*
* @return string
*/
public function getFieldValue();
/**
* Cast to string
*
* Returns in form of "NAME: VALUE"
*
* @return string
*/
public function toString();
}

View File

@@ -0,0 +1,107 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
final class HeaderValue
{
/**
* Private constructor; non-instantiable.
*/
private function __construct()
{
}
/**
* Filter a header value
*
* Ensures CRLF header injection vectors are filtered.
*
* Per RFC 7230, only VISIBLE ASCII characters, spaces, and horizontal
* tabs are allowed in values; only one whitespace character is allowed
* between visible characters.
*
* @see http://en.wikipedia.org/wiki/HTTP_response_splitting
* @param string $value
* @return string
*/
public static function filter($value)
{
$value = (string) $value;
$length = strlen($value);
$string = '';
for ($i = 0; $i < $length; $i += 1) {
$ascii = ord($value[$i]);
// Non-visible, non-whitespace characters
// 9 === horizontal tab
// 32-126, 128-254 === visible
// 127 === DEL
// 255 === null byte
if (($ascii < 32 && $ascii !== 9)
|| $ascii === 127
|| $ascii > 254
) {
continue;
}
$string .= $value[$i];
}
return $string;
}
/**
* Validate a header value.
*
* Per RFC 7230, only VISIBLE ASCII characters, spaces, and horizontal
* tabs are allowed in values; only one whitespace character is allowed
* between visible characters.
*
* @see http://en.wikipedia.org/wiki/HTTP_response_splitting
* @param string $value
* @return bool
*/
public static function isValid($value)
{
$value = (string) $value;
$length = strlen($value);
for ($i = 0; $i < $length; $i += 1) {
$ascii = ord($value[$i]);
// Non-visible, non-whitespace characters
// 9 === horizontal tab
// 32-126, 128-254 === visible
// 127 === DEL
// 255 === null byte
if (($ascii < 32 && $ascii !== 9)
|| $ascii === 127
|| $ascii > 254
) {
return false;
}
}
return true;
}
/**
* Assert a header value is valid.
*
* @param string $value
* @throws Exception\RuntimeException for invalid values
* @return void
*/
public static function assertValid($value)
{
if (! self::isValid($value)) {
throw new Exception\InvalidArgumentException('Invalid header value');
}
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.23
*/
class Host implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'host') {
throw new Exception\InvalidArgumentException('Invalid header line for Host string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Host';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Host: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24
*/
class IfMatch implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'if-match') {
throw new Exception\InvalidArgumentException('Invalid header line for If-Match string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'If-Match';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'If-Match: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* If-Modified-Since Header
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25
*/
class IfModifiedSince extends AbstractDate
{
/**
* Get header name
*
* @return string
*/
public function getFieldName()
{
return 'If-Modified-Since';
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26
*/
class IfNoneMatch implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'if-none-match') {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for If-None-Match string: "%s"',
$name
));
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'If-None-Match';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'If-None-Match: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.27
*/
class IfRange implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'if-range') {
throw new Exception\InvalidArgumentException('Invalid header line for If-Range string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'If-Range';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'If-Range: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* If-Unmodified-Since Header
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.28
*/
class IfUnmodifiedSince extends AbstractDate
{
/**
* Get header name
*
* @return string
*/
public function getFieldName()
{
return 'If-Unmodified-Since';
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @todo Search for RFC for this header
*/
class KeepAlive implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'keep-alive') {
throw new Exception\InvalidArgumentException('Invalid header line for Keep-Alive string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Keep-Alive';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Keep-Alive: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* Last-Modified Header
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.29
*/
class LastModified extends AbstractDate
{
/**
* Get header name
*
* @return string
*/
public function getFieldName()
{
return 'Last-Modified';
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* Location Header
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.30
*/
class Location extends AbstractLocation
{
/**
* Return header name
*
* @return string
*/
public function getFieldName()
{
return 'Location';
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.31
*/
class MaxForwards implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'max-forwards') {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for Max-Forwards string: "%s"',
$name
));
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Max-Forwards';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Max-Forwards: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,15 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
interface MultipleHeaderInterface extends HeaderInterface
{
public function toStringMultipleHeaders(array $headers);
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
use Zend\Uri\UriFactory;
/**
* @throws Exception\InvalidArgumentException
* @see http://tools.ietf.org/id/draft-abarth-origin-03.html#rfc.section.2
*/
class Origin implements HeaderInterface
{
/**
* @var string
*/
protected $value = '';
public static function fromString($headerLine)
{
list($name, $value) = explode(': ', $headerLine, 2);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'origin') {
throw new Exception\InvalidArgumentException('Invalid header line for Origin string: "' . $name . '"');
}
$uri = UriFactory::factory($value);
if (!$uri->isValid()) {
throw new Exception\InvalidArgumentException('Invalid header value for Origin key: "' . $name . '"');
}
return new static($value);
}
/**
* @param string|null $value
*/
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Origin';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Origin: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.32
*/
class Pragma implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'pragma') {
throw new Exception\InvalidArgumentException('Invalid header line for Pragma string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Pragma';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Pragma: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,78 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.33
*/
class ProxyAuthenticate implements MultipleHeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'proxy-authenticate') {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for Proxy-Authenticate string: "%s"',
$name
));
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Proxy-Authenticate';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Proxy-Authenticate: ' . $this->getFieldValue();
}
public function toStringMultipleHeaders(array $headers)
{
$strings = [$this->toString()];
foreach ($headers as $header) {
if (!$header instanceof ProxyAuthenticate) {
throw new Exception\RuntimeException(
'The ProxyAuthenticate multiple header implementation can only accept'
. ' an array of ProxyAuthenticate headers'
);
}
$strings[] = $header->toString();
}
return implode("\r\n", $strings);
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.34
*/
class ProxyAuthorization implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'proxy-authorization') {
throw new Exception\InvalidArgumentException(sprintf(
'Invalid header line for Proxy-Authorization string: "%s"',
$name
));
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Proxy-Authorization';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Proxy-Authorization: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2
*/
class Range implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'range') {
throw new Exception\InvalidArgumentException('Invalid header line for Range string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Range';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Range: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,45 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
use Zend\Uri\Http as HttpUri;
/**
* Content-Location Header
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.36
*/
class Referer extends AbstractLocation
{
/**
* Set the URI/URL for this header
* according to RFC Referer URI should not have fragment
*
* @param string|HttpUri $uri
* @return Referer
*/
public function setUri($uri)
{
parent::setUri($uri);
$this->uri->setFragment(null);
return $this;
}
/**
* Return header name
*
* @return string
*/
public function getFieldName()
{
return 'Referer';
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @todo FIND SPEC FOR THIS
*/
class Refresh implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'refresh') {
throw new Exception\InvalidArgumentException('Invalid header line for Refresh string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Refresh';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Refresh: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,107 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* Retry-After HTTP Header
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.37
*/
class RetryAfter extends AbstractDate
{
/**
* Value of header in delta-seconds
* By default set to 1 hour
*
* @var int
*/
protected $deltaSeconds = 3600;
/**
* Create Retry-After header from string
*
* @param string $headerLine
* @return RetryAfter
* @throws Exception\InvalidArgumentException
*/
public static function fromString($headerLine)
{
$dateHeader = new static();
list($name, $date) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== strtolower($dateHeader->getFieldName())) {
throw new Exception\InvalidArgumentException(
'Invalid header line for "' . $dateHeader->getFieldName() . '" header string'
);
}
if (is_numeric($date)) {
$dateHeader->setDeltaSeconds($date);
} else {
$dateHeader->setDate($date);
}
return $dateHeader;
}
/**
* Set number of seconds
*
* @param int $delta
* @return RetryAfter
*/
public function setDeltaSeconds($delta)
{
$this->deltaSeconds = (int) $delta;
return $this;
}
/**
* Get number of seconds
*
* @return int
*/
public function getDeltaSeconds()
{
return $this->deltaSeconds;
}
/**
* Get header name
*
* @return string
*/
public function getFieldName()
{
return 'Retry-After';
}
/**
* Returns date if it's set, or number of seconds
*
* @return int|string
*/
public function getFieldValue()
{
return ($this->date === null) ? $this->deltaSeconds : $this->getDate();
}
/**
* Return header line
*
* @return string
*/
public function toString()
{
return 'Retry-After: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.38
*/
class Server implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'server') {
throw new Exception\InvalidArgumentException('Invalid header line for Server string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Server';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Server: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,674 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
use DateTime;
use Zend\Uri\UriFactory;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.ietf.org/rfc/rfc2109.txt
* @see http://www.w3.org/Protocols/rfc2109/rfc2109
*/
class SetCookie implements MultipleHeaderInterface
{
/**
* Cookie name
*
* @var string|null
*/
protected $name = null;
/**
* Cookie value
*
* @var string|null
*/
protected $value = null;
/**
* Version
*
* @var int|null
*/
protected $version = null;
/**
* Max Age
*
* @var int|null
*/
protected $maxAge = null;
/**
* Cookie expiry date
*
* @var int|null
*/
protected $expires = null;
/**
* Cookie domain
*
* @var string|null
*/
protected $domain = null;
/**
* Cookie path
*
* @var string|null
*/
protected $path = null;
/**
* Whether the cookie is secure or not
*
* @var bool|null
*/
protected $secure = null;
/**
* If the value need to be quoted or not
*
* @var bool
*/
protected $quoteFieldValue = false;
/**
* @var bool|null
*/
protected $httponly = null;
/**
* @static
* @throws Exception\InvalidArgumentException
* @param $headerLine
* @param bool $bypassHeaderFieldName
* @return array|SetCookie
*/
public static function fromString($headerLine, $bypassHeaderFieldName = false)
{
static $setCookieProcessor = null;
if ($setCookieProcessor === null) {
$setCookieClass = get_called_class();
$setCookieProcessor = function ($headerLine) use ($setCookieClass) {
$header = new $setCookieClass;
$keyValuePairs = preg_split('#;\s*#', $headerLine);
foreach ($keyValuePairs as $keyValue) {
if (preg_match('#^(?P<headerKey>[^=]+)=\s*("?)(?P<headerValue>[^"]*)\2#', $keyValue, $matches)) {
$headerKey = $matches['headerKey'];
$headerValue= $matches['headerValue'];
} else {
$headerKey = $keyValue;
$headerValue = null;
}
// First K=V pair is always the cookie name and value
if ($header->getName() === null) {
$header->setName($headerKey);
$header->setValue(urldecode($headerValue));
continue;
}
// Process the remaining elements
switch (str_replace(['-', '_'], '', strtolower($headerKey))) {
case 'expires':
$header->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;
case 'version':
$header->setVersion((int) $headerValue);
break;
case 'maxage':
$header->setMaxAge((int) $headerValue);
break;
default:
// Intentionally omitted
}
}
return $header;
};
}
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
HeaderValue::assertValid($value);
// some sites return set-cookie::value, this is to get rid of the second :
$name = (strtolower($name) =='set-cookie:') ? 'set-cookie' : $name;
// 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: "' . $name . '"');
}
$multipleHeaders = preg_split('#(?<!Sun|Mon|Tue|Wed|Thu|Fri|Sat),\s*#', $value);
if (count($multipleHeaders) <= 1) {
return $setCookieProcessor(array_pop($multipleHeaders));
} else {
$headers = [];
foreach ($multipleHeaders as $headerLine) {
$headers[] = $setCookieProcessor($headerLine);
}
return $headers;
}
}
/**
* Cookie object constructor
*
* @todo Add validation of each one of the parameters (legal domain, etc.)
*
* @param string $name
* @param string $value
* @param int|string|DateTime $expires
* @param string $path
* @param string $domain
* @param bool $secure
* @param bool $httponly
* @param string $maxAge
* @param int $version
*/
public function __construct(
$name = null,
$value = null,
$expires = null,
$path = null,
$domain = null,
$secure = false,
$httponly = false,
$maxAge = null,
$version = null
) {
$this->type = 'Cookie';
$this->setName($name)
->setValue($value)
->setVersion($version)
->setMaxAge($maxAge)
->setDomain($domain)
->setExpires($expires)
->setPath($path)
->setSecure($secure)
->setHttpOnly($httponly);
}
/**
* @return string 'Set-Cookie'
*/
public function getFieldName()
{
return 'Set-Cookie';
}
/**
* @throws Exception\RuntimeException
* @return string
*/
public function getFieldValue()
{
if ($this->getName() == '') {
return '';
}
$value = urlencode($this->getValue());
if ($this->hasQuoteFieldValue()) {
$value = '"'. $value . '"';
}
$fieldValue = $this->getName() . '=' . $value;
$version = $this->getVersion();
if ($version !== null) {
$fieldValue .= '; Version=' . $version;
}
$maxAge = $this->getMaxAge();
if ($maxAge!==null) {
$fieldValue .= '; Max-Age=' . $maxAge;
}
$expires = $this->getExpires();
if ($expires) {
$fieldValue .= '; Expires=' . $expires;
}
$domain = $this->getDomain();
if ($domain) {
$fieldValue .= '; Domain=' . $domain;
}
$path = $this->getPath();
if ($path) {
$fieldValue .= '; Path=' . $path;
}
if ($this->isSecure()) {
$fieldValue .= '; Secure';
}
if ($this->isHttponly()) {
$fieldValue .= '; HttpOnly';
}
return $fieldValue;
}
/**
* @param string $name
* @throws Exception\InvalidArgumentException
* @return SetCookie
*/
public function setName($name)
{
HeaderValue::assertValid($name);
$this->name = $name;
return $this;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $value
* @return SetCookie
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* @return string
*/
public function getValue()
{
return $this->value;
}
/**
* Set version
*
* @param int $version
* @throws Exception\InvalidArgumentException
* @return SetCookie
*/
public function setVersion($version)
{
if ($version !== null && !is_int($version)) {
throw new Exception\InvalidArgumentException('Invalid Version number specified');
}
$this->version = $version;
return $this;
}
/**
* Get version
*
* @return int
*/
public function getVersion()
{
return $this->version;
}
/**
* Set Max-Age
*
* @param int $maxAge
* @throws Exception\InvalidArgumentException
* @return SetCookie
*/
public function setMaxAge($maxAge)
{
if ($maxAge !== null && (!is_int($maxAge) || ($maxAge < 0))) {
throw new Exception\InvalidArgumentException('Invalid Max-Age number specified');
}
$this->maxAge = $maxAge;
return $this;
}
/**
* Get Max-Age
*
* @return int
*/
public function getMaxAge()
{
return $this->maxAge;
}
/**
* Set Expires
*
* @param int|string|DateTime $expires
*
* @return self
*
* @throws Exception\InvalidArgumentException
*/
public function setExpires($expires)
{
if ($expires === null) {
$this->expires = null;
return $this;
}
if ($expires instanceof DateTime) {
$expires = $expires->format(DateTime::COOKIE);
}
$tsExpires = $expires;
if (is_string($expires)) {
$tsExpires = strtotime($expires);
// if $tsExpires is invalid and PHP is compiled as 32bit. Check if it fail reason is the 2038 bug
if (!is_int($tsExpires) && PHP_INT_SIZE === 4) {
$dateTime = new DateTime($expires);
if ($dateTime->format('Y') > 2038) {
$tsExpires = PHP_INT_MAX;
}
}
}
if (!is_int($tsExpires) || $tsExpires < 0) {
throw new Exception\InvalidArgumentException('Invalid expires time specified');
}
$this->expires = $tsExpires;
return $this;
}
/**
* @param bool $inSeconds
* @return int|string
*/
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
* @return SetCookie
*/
public function setDomain($domain)
{
HeaderValue::assertValid($domain);
$this->domain = $domain;
return $this;
}
/**
* @return string
*/
public function getDomain()
{
return $this->domain;
}
/**
* @param string $path
* @return SetCookie
*/
public function setPath($path)
{
HeaderValue::assertValid($path);
$this->path = $path;
return $this;
}
/**
* @return string
*/
public function getPath()
{
return $this->path;
}
/**
* @param bool $secure
* @return SetCookie
*/
public function setSecure($secure)
{
if (null !== $secure) {
$secure = (bool) $secure;
}
$this->secure = $secure;
return $this;
}
/**
* Set whether the value for this cookie should be quoted
*
* @param bool $quotedValue
* @return SetCookie
*/
public function setQuoteFieldValue($quotedValue)
{
$this->quoteFieldValue = (bool) $quotedValue;
return $this;
}
/**
* @return bool
*/
public function isSecure()
{
return $this->secure;
}
/**
* @param bool $httponly
* @return SetCookie
*/
public function setHttponly($httponly)
{
if (null !== $httponly) {
$httponly = (bool) $httponly;
}
$this->httponly = $httponly;
return $this;
}
/**
* @return bool
*/
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 bool
*/
public function isExpired($now = null)
{
if ($now === null) {
$now = time();
}
if (is_int($this->expires) && $this->expires < $now) {
return true;
}
return false;
}
/**
* Check whether the cookie is a session cookie (has no expiry time set)
*
* @return bool
*/
public function isSessionCookie()
{
return ($this->expires === null);
}
/**
* Check whether the value for this cookie should be quoted
*
* @return bool
*/
public function hasQuoteFieldValue()
{
return $this->quoteFieldValue;
}
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;
}
/**
* Checks whether the cookie should be sent or not in a specific scenario
*
* @param string|\Zend\Uri\Uri $uri URI to check against (secure, domain, path)
* @param bool $matchSessionCookies Whether to send session cookies
* @param int $now Override the current time when checking for expiry time
* @return bool
* @throws Exception\InvalidArgumentException If URI does not have HTTP or HTTPS scheme.
*/
public function match($uri, $matchSessionCookies = true, $now = null)
{
if (is_string($uri)) {
$uri = UriFactory::factory($uri);
}
// Make sure we have a valid Zend_Uri_Http object
if (! ($uri->isValid() && ($uri->getScheme() == 'http' || $uri->getScheme() =='https'))) {
throw new Exception\InvalidArgumentException('Passed URI is not a valid HTTP or HTTPS URI');
}
// Check that the cookie is secure (if required) and not expired
if ($this->secure && $uri->getScheme() != 'https') {
return false;
}
if ($this->isExpired($now)) {
return false;
}
if ($this->isSessionCookie() && ! $matchSessionCookies) {
return false;
}
// Check if the domain matches
if (! self::matchCookieDomain($this->getDomain(), $uri->getHost())) {
return false;
}
// Check that path matches using prefix match
if (! self::matchCookiePath($this->getPath(), $uri->getPath())) {
return false;
}
// If we didn't die until now, return true.
return true;
}
/**
* Check if a cookie's domain matches a host name.
*
* Used by Zend\Http\Cookies for cookie matching
*
* @param string $cookieDomain
* @param string $host
*
* @return bool
*/
public static function matchCookieDomain($cookieDomain, $host)
{
$cookieDomain = strtolower($cookieDomain);
$host = strtolower($host);
// Check for either exact match or suffix match
return ($cookieDomain == $host ||
preg_match('/' . preg_quote($cookieDomain) . '$/', $host));
}
/**
* Check if a cookie's path matches a URL path
*
* Used by Zend\Http\Cookies for cookie matching
*
* @param string $cookiePath
* @param string $path
* @return bool
*/
public static function matchCookiePath($cookiePath, $path)
{
return (strpos($path, $cookiePath) === 0);
}
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 .= "\n" . $header->toString();
}
return $headerLine;
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.39
*/
class TE implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'te') {
throw new Exception\InvalidArgumentException('Invalid header line for TE string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'TE';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'TE: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.40
*/
class Trailer implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'trailer') {
throw new Exception\InvalidArgumentException('Invalid header line for Trailer string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Trailer';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Trailer: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,62 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.41
*/
class TransferEncoding implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'transfer-encoding') {
throw new Exception\InvalidArgumentException(
'Invalid header line for Transfer-Encoding string: "' . $name . '"'
);
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Transfer-Encoding';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Transfer-Encoding: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.42
*/
class Upgrade implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'upgrade') {
throw new Exception\InvalidArgumentException('Invalid header line for Upgrade string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Upgrade';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Upgrade: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
*/
class UserAgent implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (str_replace(['_', ' ', '.'], '-', strtolower($name)) !== 'user-agent') {
throw new Exception\InvalidArgumentException('Invalid header line for User-Agent string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'User-Agent';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'User-Agent: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44
*/
class Vary implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'vary') {
throw new Exception\InvalidArgumentException('Invalid header line for Vary string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Vary';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Vary: ' . $this->getFieldValue();
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Http\Header;
/**
* @throws Exception\InvalidArgumentException
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.45
*/
class Via implements HeaderInterface
{
/**
* @var string
*/
protected $value;
public static function fromString($headerLine)
{
list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
// check to ensure proper header type for this factory
if (strtolower($name) !== 'via') {
throw new Exception\InvalidArgumentException('Invalid header line for Via string: "' . $name . '"');
}
// @todo implementation details
$header = new static($value);
return $header;
}
public function __construct($value = null)
{
if ($value) {
HeaderValue::assertValid($value);
$this->value = $value;
}
}
public function getFieldName()
{
return 'Via';
}
public function getFieldValue()
{
return $this->value;
}
public function toString()
{
return 'Via: ' . $this->getFieldValue();
}
}

Some files were not shown because too many files have changed in this diff Show More