updated mailgun librarie

This commit is contained in:
Bachir Soussi Chiadmi 2019-05-14 10:47:30 +02:00
parent c97e0f8ba1
commit dc39ddbbea
1599 changed files with 40314 additions and 143527 deletions

View File

@ -1,47 +0,0 @@
## 1.7 (2014-1-30)
Bugfixes:
- patched bug for attachments related to duplicate aggregator bug in Guzzle (#32 @travelton)
## 1.6 (2014-1-13)
Enhancement:
- adjust file attachment/inline name (#21 @travelton)
Bugfixes:
- fixed issue with unordered route actions (#23 @travelton)
## 1.5 (2013-12-13)
Enhancement:
- added ability to define non-https endpoint for debugging purposes (#23 @travelton)
## 1.4 (2013-10-16)
Bugfixes:
- template IDs were missing from recipient-variables (#15 @travelton)
- batch jobs trigger on to, cc, and bcc (#18 @travelton)
- batch jobs include recipient-variables for to, cc, and bcc (#18 @travelton)
- added method to return message-ids, for easier access (#19 @travelton)
## 1.3 (2013-09-12)
Bugfixes:
- relaxed Guzzle requirement (#7 @travelton)
- fixed reply-to bug (#9 @travelton)
## 1.2 (2013-09-05)
Bugfixes:
- fixed exception handling constants (@travelton)
- fixed MessageBuilder $baseAddress return (#1 @yoye)
- adjusted scope of recipient-variables (#3 @yoye)
- fixed misspellings of Exceptions (#2 @dboggus)
- undefined DEFAULT_TIME_ZONE (#4 @yoye)
- added message IDs to return for BatchMessage (@travelton)
## 1.1 (2013-08-21)
Initial Release!

View File

@ -1,180 +0,0 @@
Mailgun-PHP
===========
This is the Mailgun PHP SDK. This SDK contains methods for easily interacting
with the Mailgun API.
Below are examples to get you started. For additional examples, please see our
official documentation
at http://documentation.mailgun.com
[![Latest Stable Version](https://poser.pugx.org/mailgun/mailgun-php/v/stable.png)](https://packagist.org/packages/mailgun/mailgun-php)
[![Build Status](https://travis-ci.org/mailgun/mailgun-php.png)](https://travis-ci.org/mailgun/mailgun-php)
Installation
------------
To install the SDK, you will need to be using [Composer](http://getcomposer.org/)
in your project.
If you aren't using Composer yet, it's really simple! Here's how to install
composer and the Mailgun SDK.
```PHP
# Install Composer
curl -sS https://getcomposer.org/installer | php
# Add Mailgun as a dependency
php composer.phar require mailgun/mailgun-php:~1.7.1
```
**For shared hosts without SSH access, check out our [Shared Host Instructions](SharedHostInstall.md).**
**Rather just download the files? [Library Download](https://9f67cbbd1116d8afb399-7760483f5d1e5f28c2d253278a2a5045.ssl.cf2.rackcdn.com/mailgun-php-1.7.1.zip).**
Next, require Composer's autoloader, in your application, to automatically
load the Mailgun SDK in your project:
```PHP
require 'vendor/autoload.php';
use Mailgun\Mailgun;
```
Usage
-----
Here's how to send a message using the SDK:
```php
# First, instantiate the SDK with your API credentials and define your domain.
$mg = new Mailgun("key-example");
$domain = "example.com";
# Now, compose and send your message.
$mg->sendMessage($domain, array('from' => 'bob@example.com',
'to' => 'sally@example.com',
'subject' => 'The PHP SDK is awesome!',
'text' => 'It is so simple to send a message.'));
```
Or obtain the last 25 log items:
```php
# First, instantiate the SDK with your API credentials and define your domain.
$mg = new Mailgun("key-example");
$domain = "example.com";
# Now, issue a GET against the Logs endpoint.
$mg->get("$domain/log", array('limit' => 25,
'skip' => 0));
```
Response
--------
The results, provided by the endpoint, are returned as an object, which you
can traverse like an array.
Example:
```php
$mg = new Mailgun("key-example");
$domain = "example.com";
$result = $mg->get("$domain/log", array('limit' => 25,
'skip' => 0));
$httpResponseCode = $result->http_response_code;
$httpResponseBody = $result->http_response_body;
# Iterate through the results and echo the message IDs.
$logItems = $result->http_response_body->items;
foreach($logItems as $logItem){
echo $logItem->message_id . "\n";
}
```
Example Contents:
**$httpResponseCode** will contain an integer. You can find how we use HTTP response
codes in our documentation:
http://documentation.mailgun.com/api-intro.html?highlight=401#errors
**$httpResponseBody** will contain an object of the API response. In the above
example, a var_dump($result) would contain the following:
```
object(stdClass)#26 (2) {
["http_response_body"]=>
object(stdClass)#26 (2) {
["total_count"]=>
int(12)
["items"]=>
array(1) {
[0]=>
object(stdClass)#31 (5) {
["hap"]=>
string(9) "delivered"
["created_at"]=>
string(29) "Tue, 20 Aug 2013 20:24:34 GMT"
["message"]=>
string(66) "Delivered: me@samples.mailgun.org → travis@mailgunhq.com 'Hello'"
["type"]=>
string(4) "info"
["message_id"]=>
string(46) "20130820202406.24739.21973@samples.mailgun.org"
}
}
}
}
```
Debugging
---------
Debugging the PHP SDK can be really helpful when things aren't working quite right.
To debug the SDK, here are some suggestions:
Set the endpoint to Mailgun's Postbin. A Postbin is a web service that allows you to
post data, which is then displayed through a browser. This allows you to quickly determine
what is actually being transmitted to Mailgun's API.
**Step 1 - Create a new Postbin.**
Go to http://bin.mailgun.net. The Postbin will generate a special URL. Save that URL.
**Step 2 - Instantiate the Mailgun client using Postbin.**
*Tip: The bin id will be the URL part after bin.mailgun.net. It will be random generated letters and numbers. For example, the bin id in this URL, http://bin.mailgun.net/aecf68de, is "aecf68de".*
```php
# First, instantiate the SDK with your API credentials and define your domain.
$mg = new Mailgun('key-example', 'bin.mailgun.net', 'aecf68de', $ssl = False);
$domain = 'example.com';
# Now, compose and send your message.
$mg->sendMessage($domain, array('from' => 'bob@example.com',
'to' => 'sally@example.com',
'subject' => 'The PHP SDK is awesome!',
'text' => 'It is so simple to send a message.'));
```
Additional Info
---------------
For usage examples on each API endpoint, head over to our official documentation
pages.
This SDK includes a [Message Builder](src/Mailgun/Messages/README.md),
[Batch Message](src/Mailgun/Messages/README.md) and [Opt-In Handler](src/Mailgun/Lists/README.md) component.
Message Builder allows you to quickly create the array of parameters, required
to send a message, by calling a methods for each parameter.
Batch Message is an extension of Message Builder, and allows you to easily send
a batch message job within a few seconds. The complexity of
batch messaging is eliminated!
Support and Feedback
--------------------
Be sure to visit the Mailgun official
[documentation website](http://documentation.mailgun.com/) for additional
information about our API.
If you find a bug, please submit the issue in Github directly.
[Mailgun-PHP Issues](https://github.com/mailgun/Mailgun-PHP/issues)
As always, if you need additional assistance, drop us a note through your Control Panel at
[https://mailgun.com/cp/support](https://mailgun.com/cp/support).

View File

@ -1,39 +0,0 @@
Shared Host Installation
========================
If you do not have SSH access to your server, fear not! You can still run
composer and download the SDK. Here's how...
Installation
------------
Linux / Mac OSX:
*PHP is typically installed by default, consult your distribution documentation. Instructions from [getcomposer.org](http://getcomposer.org/doc/00-intro.md#installation-nix).*
1. curl -sS https://getcomposer.org/installer | php
2. php composer.phar require mailgun/mailgun-php:~1.7.1
3. The files will be downloaded to your local computer.
4. Upload the files to your webserver.
Windows:
*PHP must be installed on your computer, [download](http://windows.php.net/download/0). Instructions from [getcomposer.org](http://getcomposer.org/doc/00-intro.md#installation-windows).*
1. Download and run [Composer-Setup.exe](https://getcomposer.org/Composer-Setup.exe).
2. Open a Command Prompt and type "php composer require mailgun/mailgun-php:~1.7.1".
3. The files will be downloaded to your local computer.
4. Upload the files to your webserver.
Support and Feedback
--------------------
Be sure to visit the Mailgun official
[documentation website](http://documentation.mailgun.com/) for additional
information about our API.
If you find a bug, please submit the issue in Github directly.
[Mailgun-PHP Issues](https://github.com/mailgun/Mailgun-PHP/issues)
As always, if you need additional assistance, drop us a note at
[support@mailgun.com](mailto:support@mailgun.com).

View File

@ -1,24 +1,7 @@
{
"name": "mailgun/mailgun-php",
"description": "The Mailgun SDK provides methods for all API functions.",
"require": {
"guzzle/guzzle": "<4.0,>=3.8"
},
"require-dev": {
"phpunit/phpunit": "3.7.*"
},
"autoload": {
"psr-0": {
"Mailgun\\Tests": "tests/",
"Mailgun": "src/"
}
},
"license": "MIT",
"authors": [
{
"name": "Travis Swientek",
"email": "travis@mailgunhq.com"
}
],
"minimum-stability": "stable"
"mailgun/mailgun-php": "^2.8",
"php-http/curl-client": "^1.7",
"guzzlehttp/psr7": "^1.5"
}
}

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/Bootstrap.php"
colors="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
testSuiteLoaderClass="PHPUnit_Runner_StandardTestSuiteLoader">
<testsuites>
<testsuite>
<directory>tests/Mailgun/Tests</directory>
</testsuite>
</testsuites>
</phpunit>

View File

@ -1,25 +0,0 @@
<?php
namespace Mailgun\Connection\Exceptions;
class GenericHTTPError extends \Exception
{
protected $httpResponseCode;
protected $httpResponseBody;
public function __construct($message=null, $response_code=null, $response_body=null, $code=0, \Exception $previous=null) {
parent::__construct($message, $code, $previous);
$this->httpResponseCode = $response_code;
$this->httpResponseBody = $response_body;
}
public function getHttpResponseCode() {
return $this->httpResponseCode;
}
public function getHttpResponseBody() {
return $this->httpResponseBody;
}
}
?>

View File

@ -1,4 +0,0 @@
<?php
namespace Mailgun\Connection\Exceptions;
class InvalidCredentials extends \Exception{}

View File

@ -1,4 +0,0 @@
<?php
namespace Mailgun\Connection\Exceptions;
class MissingEndpoint extends \Exception{}

View File

@ -1,4 +0,0 @@
<?php
namespace Mailgun\Connection\Exceptions;
class MissingRequiredParameters extends \Exception{}

View File

@ -1,4 +0,0 @@
<?php
namespace Mailgun\Connection\Exceptions;
class NoDomainsConfigured extends \Exception{}

View File

@ -1,150 +0,0 @@
<?PHP
namespace Mailgun\Connection;
use Guzzle\Http\Client as Guzzle;
use Mailgun\MailgunClient;
use Mailgun\Connection\Exceptions\GenericHTTPError;
use Guzzle\Http\QueryAggregator\DuplicateAggregator;
use Guzzle\Http\QueryAggregator\PhpAggregator;
use Mailgun\Connection\Exceptions\InvalidCredentials;
use Mailgun\Connection\Exceptions\NoDomainsConfigured;
use Mailgun\Connection\Exceptions\MissingRequiredParameters;
use Mailgun\Connection\Exceptions\MissingEndpoint;
/*
This class is a wrapper for the Guzzle (HTTP Client Library).
*/
class RestClient{
private $apiKey;
protected $mgClient;
protected $hasFiles = False;
public function __construct($apiKey, $apiEndpoint, $apiVersion, $ssl){
$this->apiKey = $apiKey;
$this->mgClient = new Guzzle($this->generateEndpoint($apiEndpoint, $apiVersion, $ssl));
$this->mgClient->setDefaultOption('curl.options', array('CURLOPT_FORBID_REUSE' => true));
$this->mgClient->setDefaultOption('auth', array (API_USER, $this->apiKey));
$this->mgClient->setDefaultOption('exceptions', false);
$this->mgClient->setUserAgent(SDK_USER_AGENT . '/' . SDK_VERSION);
}
public function post($endpointUrl, $postData = array(), $files = array()){
$request = $this->mgClient->post($endpointUrl, array(), $postData);
if(isset($files["message"])){
$this->hasFiles = True;
foreach($files as $message){
$request->addPostFile("message", $message);
}
}
if(isset($files["attachment"])){
$this->hasFiles = True;
foreach($files["attachment"] as $attachment){
// Backward compatibility code
if (is_array($attachment)){
$request->addPostFile("attachment",
$attachment['filePath'], null,
$attachment['remoteName']);
}
else{
$request->addPostFile("attachment", $attachment);
}
}
}
if(isset($files["inline"])){
$this->hasFiles = True;
foreach($files["inline"] as $inline){
// Backward compatibility code
if (is_array($inline)){
$request->addPostFile("inline",
$inline['filePath'], null,
$inline['remoteName']);
}
else{
$request->addPostFile("inline", $inline);
}
}
}
/*
This block of code is to accommodate for a bug in Guzzle.
See https://github.com/guzzle/guzzle/issues/545.
It can be removed when Guzzle resolves the issue.
*/
if($this->hasFiles){
$request->getPostFields()->setAggregator(new PhpAggregator());
}
else{
$request->getPostFields()->setAggregator(new DuplicateAggregator());
}
$response = $request->send();
return $this->responseHandler($response);
}
public function get($endpointUrl, $queryString = array()){
$request = $this->mgClient->get($endpointUrl);
if(isset($queryString)){
foreach($queryString as $key=>$value){
$request->getQuery()->set($key, $value);
}
}
$response = $request->send();
return $this->responseHandler($response);
}
public function delete($endpointUrl){
$request = $this->mgClient->delete($endpointUrl);
$response = $request->send();
return $this->responseHandler($response);
}
public function put($endpointUrl, $putData){
$request = $this->mgClient->put($endpointUrl, array(), $putData);
$request->getPostFields()->setAggregator(new DuplicateAggregator());
$response = $request->send();
return $this->responseHandler($response);
}
public function responseHandler($responseObj){
$httpResponseCode = $responseObj->getStatusCode();
if($httpResponseCode === 200){
$data = (string) $responseObj->getBody();
$jsonResponseData = json_decode($data, false);
$result = new \stdClass();
// return response data as json if possible, raw if not
$result->http_response_body = $data && $jsonResponseData === null ? $data : $jsonResponseData;
}
elseif($httpResponseCode == 400){
throw new MissingRequiredParameters(EXCEPTION_MISSING_REQUIRED_PARAMETERS);
}
elseif($httpResponseCode == 401){
throw new InvalidCredentials(EXCEPTION_INVALID_CREDENTIALS);
}
elseif($httpResponseCode == 404){
throw new MissingEndpoint(EXCEPTION_MISSING_ENDPOINT);
}
else{
throw new GenericHTTPError(EXCEPTION_GENERIC_HTTP_ERROR, $httpResponseCode, $responseObj->getBody());
}
$result->http_response_code = $httpResponseCode;
return $result;
}
private function generateEndpoint($apiEndpoint, $apiVersion, $ssl){
if(!$ssl){
return "http://" . $apiEndpoint . "/" . $apiVersion . "/";
}
else{
return "https://" . $apiEndpoint . "/" . $apiVersion . "/";
}
}
}

View File

@ -1,23 +0,0 @@
<?PHP
const API_USER = "api";
const SDK_VERSION = "1.7";
const SDK_USER_AGENT = "mailgun-sdk-php";
const RECIPIENT_COUNT_LIMIT = 1000;
const CAMPAIGN_ID_LIMIT = 3;
const TAG_LIMIT = 3;
const DEFAULT_TIME_ZONE = "UTC";
//Common Exception Messages
const EXCEPTION_INVALID_CREDENTIALS = "Your credentials are incorrect.";
const EXCEPTION_GENERIC_HTTP_ERROR = "An HTTP Error has occurred! Check your network connection and try again.";
const EXCEPTION_MISSING_REQUIRED_PARAMETERS = "The parameters passed to the API were invalid. Check your inputs!";
const EXCEPTION_MISSING_REQUIRED_MIME_PARAMETERS = "The parameters passed to the API were invalid. Check your inputs!";
const EXCEPTION_MISSING_ENDPOINT = "The endpoint you've tried to access does not exist. Check your URL.";
const TOO_MANY_RECIPIENTS = "You've exceeded the maximum recipient count (1,000) on the to field with autosend disabled.";
const INVALID_PARAMETER_NON_ARRAY = "The parameter you've passed in position 2 must be an array.";
const INVALID_PARAMETER_ATTACHMENT = "Attachments must be passed with an \"@\" preceding the file path. Web resources not supported.";
const INVALID_PARAMETER_INLINE = "Inline images must be passed with an \"@\" preceding the file path. Web resources not supported.";
const TOO_MANY_PARAMETERS_CAMPAIGNS = "You've exceeded the maximum (3) campaigns for a single message.";
const TOO_MANY_PARAMETERS_TAGS = "You've exceeded the maximum (3) tags for a single message.";
const TOO_MANY_PARAMETERS_RECIPIENT = "You've exceeded the maximum recipient count (1,000) on the to field with autosend disabled.";

View File

@ -1,45 +0,0 @@
<?PHP
namespace Mailgun\Lists;
use Mailgun\Messages\Exceptions\InvalidParameter;
use Mailgun\Messages\Exceptions\TooManyParameters;
use Mailgun\Messages\Expcetions\InvalidParameterType;
/*
This class is used for creating a unique hash for
mailing list subscription double-opt in requests.
*/
class OptInHandler{
function __construct(){
}
public function generateHash($mailingList, $secretAppId, $recipientAddress){
$innerPayload = array('r' => $recipientAddress, 'l' => $mailingList);
$encodedInnerPayload = base64_encode(json_encode($innerPayload));
$innerHash = hash_hmac("sha1", $encodedInnerPayload, $secretAppId);
$outerPayload = array('h' => $innerHash, 'p' => $encodedInnerPayload);
return urlencode(base64_encode(json_encode($outerPayload)));
}
public function validateHash($secretAppId, $uniqueHash){
$decodedOuterPayload = json_decode(base64_decode(urldecode($uniqueHash)), true);
$decodedHash = $decodedOuterPayload['h'];
$innerPayload = $decodedOuterPayload['p'];
$decodedInnerPayload = json_decode(base64_decode($innerPayload), true);
$computedInnerHash = hash_hmac("sha1", $innerPayload, $secretAppId);
if($computedInnerHash == $decodedHash){
return array('recipientAddress' => $decodedInnerPayload['r'], 'mailingList' => $decodedInnerPayload['l']);
}
return false;
}
}

View File

@ -1,106 +0,0 @@
<?PHP
namespace Mailgun;
require_once 'Constants/Constants.php';
use Mailgun\Messages\Messages;
use Mailgun\Messages\Exceptions;
use Mailgun\Connection\RestClient;
use Mailgun\Messages\BatchMessage;
use Mailgun\Lists\OptInHandler;
use Mailgun\Messages\MessageBuilder;
/*
This class is the base class for the Mailgun SDK.
See the official documentation for usage instructions.
*/
class Mailgun{
protected $workingDomain;
protected $restClient;
protected $apiKey;
public function __construct($apiKey = null, $apiEndpoint = "api.mailgun.net", $apiVersion = "v2", $ssl = true){
$this->apiKey = $apiKey;
$this->restClient = new RestClient($apiKey, $apiEndpoint, $apiVersion, $ssl);
}
public function sendMessage($workingDomain, $postData, $postFiles = array()){
/*
* This function allows the sending of a fully formed message OR a custom
* MIME string. If sending MIME, the string must be passed in to the 3rd
* position of the function call.
*/
if(is_array($postFiles)){
return $this->post("$workingDomain/messages", $postData, $postFiles);
}
else if(is_string($postFiles)){
$tempFile = tempnam(sys_get_temp_dir(), "MG_TMP_MIME");
$fileHandle = fopen($tempFile, "w");
fwrite($fileHandle, $postFiles);
$result = $this->post("$workingDomain/messages.mime", $postData, array("message" => $tempFile));
fclose($fileHandle);
unlink($tempFile);
return $result;
}
else{
throw new Exceptions\MissingRequiredMIMEParameters(EXCEPTION_MISSING_REQUIRED_MIME_PARAMETERS);
}
}
public function verifyWebhookSignature($postData = NULL) {
/*
* This function checks the signature in a POST request to see if it is
* authentic.
*
* Pass an array of parameters. If you pass nothing, $_POST will be
* used instead.
*
* If this function returns FALSE, you must not process the request.
* You should reject the request with status code 403 Forbidden.
*/
if(is_null($postData)) {
$postData = $_POST;
}
$hmac = hash_hmac('sha256', "{$postData["timestamp"]}{$postData["token"]}", $this->apiKey);
$sig = $postData['signature'];
if(function_exists('hash_equals')) {
// hash_equals is constant time, but will not be introduced until PHP 5.6
return hash_equals($hmac, $sig);
}
else {
return ($hmac == $sig);
}
}
public function post($endpointUrl, $postData = array(), $files = array()){
return $this->restClient->post($endpointUrl, $postData, $files);
}
public function get($endpointUrl, $queryString = array()){
return $this->restClient->get($endpointUrl, $queryString);
}
public function delete($endpointUrl){
return $this->restClient->delete($endpointUrl);
}
public function put($endpointUrl, $putData){
return $this->restClient->put($endpointUrl, $putData);
}
public function MessageBuilder(){
return new MessageBuilder();
}
public function OptInHandler(){
return new OptInHandler();
}
public function BatchMessage($workingDomain, $autoSend = true){
return new BatchMessage($this->restClient, $workingDomain, $autoSend);
}
}

View File

@ -1,97 +0,0 @@
<?PHP
namespace Mailgun\Messages;
use Mailgun\Messages\MessageBuilder;
use Mailgun\Messages\Exceptions\TooManyParameters;
use Mailgun\Messages\Exceptions\MissingRequiredMIMEParameters;
/*
This class is used for batch sending. See the official documentation
for usage instructions.
*/
class BatchMessage extends MessageBuilder{
private $batchRecipientAttributes;
private $autoSend;
private $restClient;
private $workingDomain;
private $messageIds = array();
public function __construct($restClient, $workingDomain, $autoSend){
$this->batchRecipientAttributes = array();
$this->autoSend = $autoSend;
$this->restClient = $restClient;
$this->workingDomain = $workingDomain;
$this->endpointUrl = $workingDomain . "/messages";
}
protected function addRecipient($headerName, $address, $variables){
if(array_key_exists($headerName, $this->counters['recipients'])){
if($this->counters['recipients'][$headerName] == RECIPIENT_COUNT_LIMIT){
if($this->autoSend == false){
throw new TooManyParameters(TOO_MANY_RECIPIENTS);
}
$this->sendMessage();
}
}
$compiledAddress = $this->parseAddress($address, $variables);
if(isset($this->message[$headerName])){
array_push($this->message[$headerName], $compiledAddress);
}
elseif($headerName == "h:reply-to"){
$this->message[$headerName] = $compiledAddress;
}
else{
$this->message[$headerName] = array($compiledAddress);
}
if(array_key_exists($headerName, $this->counters['recipients'])){
$this->counters['recipients'][$headerName] += 1;
if(!array_key_exists("id", $variables)){
$variables['id'] = $this->counters['recipients'][$headerName];
}
}
$this->batchRecipientAttributes["$address"] = $variables;
}
public function sendMessage($message = array(), $files = array()){
if(count($message) < 1){
$message = $this->message;
$files = $this->files;
}
if(!array_key_exists("from", $message)){
throw new MissingRequiredMIMEParameters(EXCEPTION_MISSING_REQUIRED_MIME_PARAMETERS);
}
elseif(!array_key_exists("to", $message)){
throw new MissingRequiredMIMEParameters(EXCEPTION_MISSING_REQUIRED_MIME_PARAMETERS);
}
elseif(!array_key_exists("subject", $message)){
throw new MissingRequiredMIMEParameters(EXCEPTION_MISSING_REQUIRED_MIME_PARAMETERS);
}
elseif((!array_key_exists("text", $message) && !array_key_exists("html", $message))){
throw new MissingRequiredMIMEParameters(EXCEPTION_MISSING_REQUIRED_MIME_PARAMETERS);
}
else{
$message["recipient-variables"] = json_encode($this->batchRecipientAttributes);
$response = $this->restClient->post($this->endpointUrl, $message, $files);
$this->batchRecipientAttributes = array();
$this->counters['recipients']['to'] = 0;
$this->counters['recipients']['cc'] = 0;
$this->counters['recipients']['bcc'] = 0;
unset($this->message["to"]);
array_push($this->messageIds, $response->http_response_body->id);
}
}
public function finalize(){
return $this->sendMessage();
}
public function getMessageIds(){
return $this->messageIds;
}
}

View File

@ -1,4 +0,0 @@
<?php
namespace Mailgun\Messages\Exceptions;
class InvalidParameter extends \Exception{}

View File

@ -1,4 +0,0 @@
<?php
namespace Mailgun\Messages\Exceptions;
class InvalidParameterType extends \Exception{}

View File

@ -1,4 +0,0 @@
<?php
namespace Mailgun\Messages\Exceptions;
class MissingRequiredMIMEParameters extends \Exception{}

View File

@ -1,4 +0,0 @@
<?php
namespace Mailgun\Messages\Exceptions;
class TooManyParameters extends \Exception{}

View File

@ -1,343 +0,0 @@
<?PHP
namespace Mailgun\Messages;
use Mailgun\Messages\Exceptions\InvalidParameter;
use Mailgun\Messages\Exceptions\TooManyParameters;
use Mailgun\Messages\Exceptions\InvalidParameterType;
/*
This class is used for composing a properly formed
message object. Dealing with arrays can be cumbersome,
this class makes the process easier. See the official
documentation for usage instructions.
*/
class MessageBuilder
{
protected $message = array();
protected $variables = array();
protected $files = array();
protected $counters = array(
'recipients' => array(
'to' => 0,
'cc' => 0,
'bcc' => 0
),
'attributes' => array(
'attachment' => 0,
'campaign_id' => 0,
'custom_option' => 0,
'tag' => 0
)
);
protected function safeGet($params, $key, $default)
{
if (array_key_exists($key, $params)) {
return $params[$key];
}
return $default;
}
protected function getFullName($params)
{
if (array_key_exists("first", $params)) {
$first = $this->safeGet($params, "first", "");
$last = $this->safeGet($params, "last", "");
return trim("$first $last");
}
return $this->safeGet($params, "full_name", "");
}
protected function parseAddress($address, $variables)
{
if (!is_array($variables)) {
return $address;
}
$fullName = $this->getFullName($variables);
if ($fullName != null) {
return "'$fullName' <$address>";
}
return $address;
}
protected function addRecipient($headerName, $address, $variables)
{
$compiledAddress = $this->parseAddress($address, $variables);
if (isset($this->message[$headerName])) {
array_push($this->message[$headerName], $compiledAddress);
} elseif ($headerName == "h:reply-to") {
$this->message[$headerName] = $compiledAddress;
} else {
$this->message[$headerName] = array($compiledAddress);
}
if (array_key_exists($headerName, $this->counters['recipients'])) {
$this->counters['recipients'][$headerName] += 1;
}
}
public function addToRecipient($address, $variables = null)
{
if ($this->counters['recipients']['to'] > RECIPIENT_COUNT_LIMIT) {
throw new TooManyParameters(TOO_MANY_PARAMETERS_RECIPIENT);
}
$this->addRecipient("to", $address, $variables);
return end($this->message['to']);
}
public function addCcRecipient($address, $variables = null)
{
if ($this->counters['recipients']['cc'] > RECIPIENT_COUNT_LIMIT) {
throw new TooManyParameters(TOO_MANY_PARAMETERS_RECIPIENT);
}
$this->addRecipient("cc", $address, $variables);
return end($this->message['cc']);
}
public function addBccRecipient($address, $variables = null)
{
if ($this->counters['recipients']['bcc'] > RECIPIENT_COUNT_LIMIT) {
throw new TooManyParameters(TOO_MANY_PARAMETERS_RECIPIENT);
}
$this->addRecipient("bcc", $address, $variables);
return end($this->message['bcc']);
}
public function setFromAddress($address, $variables = null)
{
$this->addRecipient("from", $address, $variables);
return $this->message['from'];
}
public function setReplyToAddress($address, $variables = null)
{
$this->addRecipient("h:reply-to", $address, $variables);
return $this->message['h:reply-to'];
}
public function setSubject($subject = null)
{
if ($subject == null || $subject == "") {
$subject = " ";
}
$this->message['subject'] = $subject;
return $this->message['subject'];
}
public function addCustomHeader($headerName, $headerData)
{
if (!preg_match("/^h:/i", $headerName)) {
$headerName = "h:" . $headerName;
}
$this->message[$headerName] = array($headerData);
return $this->message[$headerName];
}
public function setTextBody($textBody)
{
if ($textBody == null || $textBody == "") {
$textBody = " ";
}
$this->message['text'] = $textBody;
return $this->message['text'];
}
public function setHtmlBody($htmlBody)
{
if ($htmlBody == null || $htmlBody == "") {
$htmlBody = " ";
}
$this->message['html'] = $htmlBody;
return $this->message['html'];
}
public function addAttachment($attachmentPath, $attachmentName = null)
{
if (isset($this->files["attachment"])) {
$attachment = array(
'filePath' => $attachmentPath,
'remoteName' => $attachmentName
);
array_push($this->files["attachment"], $attachment);
} else {
$this->files["attachment"] = array(
array(
'filePath' => $attachmentPath,
'remoteName' => $attachmentName
)
);
}
return true;
}
public function addInlineImage($inlineImagePath, $inlineImageName = null)
{
if (preg_match("/^@/", $inlineImagePath)) {
if (isset($this->files['inline'])) {
$inlineAttachment = array(
'filePath' => $inlineImagePath,
'remoteName' => $inlineImageName
);
array_push($this->files['inline'], $inlineAttachment);
} else {
$this->files['inline'] = array(
array(
'filePath' => $inlineImagePath,
'remoteName' => $inlineImageName
)
);
}
return true;
} else {
throw new InvalidParameter(INVALID_PARAMETER_INLINE);
}
}
public function setTestMode($testMode)
{
if (filter_var($testMode, FILTER_VALIDATE_BOOLEAN)) {
$testMode = "yes";
} else {
$testMode = "no";
}
$this->message['o:testmode'] = $testMode;
return $this->message['o:testmode'];
}
public function addCampaignId($campaignId)
{
if ($this->counters['attributes']['campaign_id'] < CAMPAIGN_ID_LIMIT) {
if (isset($this->message['o:campaign'])) {
array_push($this->message['o:campaign'], $campaignId);
} else {
$this->message['o:campaign'] = array($campaignId);
}
$this->counters['attributes']['campaign_id'] += 1;
return $this->message['o:campaign'];
} else {
throw new TooManyParameters(TOO_MANY_PARAMETERS_CAMPAIGNS);
}
}
public function addTag($tag)
{
if ($this->counters['attributes']['tag'] < TAG_LIMIT) {
if (isset($this->message['o:tag'])) {
array_push($this->message['o:tag'], $tag);
} else {
$this->message['o:tag'] = array($tag);
}
$this->counters['attributes']['tag'] += 1;
return $this->message['o:tag'];
} else {
throw new TooManyParameters(TOO_MANY_PARAMETERS_TAGS);
}
}
public function setDkim($enabled)
{
if (filter_var($enabled, FILTER_VALIDATE_BOOLEAN)) {
$enabled = "yes";
} else {
$enabled = "no";
}
$this->message["o:dkim"] = $enabled;
return $this->message["o:dkim"];
}
public function setOpenTracking($enabled)
{
if (filter_var($enabled, FILTER_VALIDATE_BOOLEAN)) {
$enabled = "yes";
} else {
$enabled = "no";
}
$this->message['o:tracking-opens'] = $enabled;
return $this->message['o:tracking-opens'];
}
public function setClickTracking($enabled)
{
if (filter_var($enabled, FILTER_VALIDATE_BOOLEAN)) {
$enabled = "yes";
} elseif ($enabled == "html") {
$enabled = "html";
} else {
$enabled = "no";
}
$this->message['o:tracking-clicks'] = $enabled;
return $this->message['o:tracking-clicks'];
}
public function setDeliveryTime($timeDate, $timeZone = null)
{
if (isset($timeZone)) {
$timeZoneObj = new \DateTimeZone("$timeZone");
} else {
$timeZoneObj = new \DateTimeZone(\DEFAULT_TIME_ZONE);
}
$dateTimeObj = new \DateTime($timeDate, $timeZoneObj);
$formattedTimeDate = $dateTimeObj->format(\DateTime::RFC2822);
$this->message['o:deliverytime'] = $formattedTimeDate;
return $this->message['o:deliverytime'];
}
public function addCustomData($customName, $data)
{
$this->message['v:' . $customName] = json_encode($data);
}
public function addCustomParameter($parameterName, $data)
{
if (isset($this->message[$parameterName])) {
array_push($this->message[$parameterName], $data);
return $this->message[$parameterName];
} else {
$this->message[$parameterName] = array($data);
return $this->message[$parameterName];
}
}
public function setMessage($message)
{
$this->message = $message;
}
public function getMessage()
{
return $this->message;
}
public function getFiles()
{
return $this->files;
}
}

View File

@ -1,138 +0,0 @@
Mailgun - Messages
====================
This is the Mailgun PHP *Message* utilities.
The below assumes you've already installed the Mailgun PHP SDK in to your
project. If not, go back to the master README for instructions.
There are two utilities included, Message Builder and Batch Message.
Message Builder: Allows you to build a message object by calling methods for
each MIME attribute.
Batch Message: Inherits Message Builder and allows you to iterate through
recipients from a list. Messages will fire after the 1,000th recipient has been
added.
Usage - Message Builder
-----------------------
Here's how to use Message Builder to build your Message.
```php
# First, instantiate the SDK with your API credentials and define your domain.
$mg = new Mailgun("key-example");
$domain = "example.com";
# Next, instantiate a Message Builder object from the SDK.
$messageBldr = $mg->MessageBuilder();
# Define the from address.
$messageBldr->setFromAddress("me@example.com", array("first"=>"PHP", "last" => "SDK"));
# Define a to recipient.
$messageBldr->addToRecipient("john.doe@example.com", array("first" => "John", "last" => "Doe"));
# Define a cc recipient.
$messageBldr->addCcRecipient("sally.doe@example.com", array("first" => "Sally", "last" => "Doe"));
# Define the subject.
$messageBldr->setSubject("A message from the PHP SDK using Message Builder!");
# Define the body of the message.
$messageBldr->setTextBody("This is the text body of the message!");
# Other Optional Parameters.
$messageBldr->addCampaignId("My-Awesome-Campaign");
$messageBldr->addCustomHeader("Customer-Id", "12345");
$messageBldr->addAttachment("@/tron.jpg");
$messageBldr->setDeliveryTime("tomorrow 8:00AM", "PST");
$messageBldr->setClickTracking(true);
# Finally, send the message.
$mg->post("{$domain}/messages", $messageBldr->getMessage(), $messageBldr->getFiles());
```
Available Functions
-----------------------------------------------------
`string addToRecipient(string $address, array $attributes)`
`string addCcRecipient(string $address, array $attributes)`
`string addBccRecipient(string $address, array $attributes)`
`string setFromAddress(string $address, array $attributes)`
`string setSubject(string $subject)`
`string setTextBody(string $textBody)`
`string setHtmlBody(string $htmlBody)`
`bool addAttachment(string $attachmentPath)`
`bool addInlineImage(string $inlineImagePath)`
`string setTestMode(bool $testMode)`
`string addCampaignId(string $campaignId)`
`string setDkim(bool $enabled)`
`string setOpenTracking($enabled)`
`string setClickTracking($enabled)`
`string setDeliveryTime(string $timeDate, string $timeZone)`
`string addCustomData(string $optionName, string $data)`
`string addCustomParameter(string $parameterName, string $data)`
`array getMessage()`
`array getFiles()`
Usage - Batch Message
---------------------
Here's how to use Batch Message to easily handle batch sending jobs.
```php
# First, instantiate the SDK with your API credentials and define your domain.
$mg = new Mailgun("key-example");
$domain = "example.com";
# Next, instantiate a Message Builder object from the SDK, pass in your sending
domain.
$batchMsg = $mg->BatchMessage($domain);
# Define the from address.
$batchMsg->setFromAddress("me@example.com", array("first"=>"PHP", "last" => "SDK"));
# Define the subject.
$batchMsg->setSubject("A Batch Message from the PHP SDK!");
# Define the body of the message.
$batchMsg->setTextBody("This is the text body of the message!");
# Next, let's add a few recipients to the batch job.
$batchMsg->addToRecipient("john.doe@example.com", array("first" => "John", "last" => "Doe"));
$batchMsg->addToRecipient("sally.doe@example.com", array("first" => "Sally", "last" => "Doe"));
$batchMsg->addToRecipient("mike.jones@example.com", array("first" => "Mike", "last" => "Jones"));
...
// After 1,000 recipeints, Batch Message will automatically post your message to
the messages endpoint.
// Call finalize() to send any remaining recipients still in the buffer.
$batchMsg->finalize();
```
Available Functions (Inherits all Batch Message and Messages Functions)
-----------------------------------------------------------------------
`addToRecipient(string $address, string $attributes)`
`sendMessage(array $message, array $files)`
`array finalize()`
More Documentation
------------------
See the official [Mailgun Docs](http://documentation.mailgun.com/api-sending.html)
for more information.

View File

@ -1,5 +0,0 @@
<?php
//Grab the composer Autoloader!
$autoloader = require dirname(__DIR__) . '/vendor/autoload.php';

View File

@ -1,19 +0,0 @@
<?PHP
namespace Mailgun\Tests\Connection;
use Mailgun\Tests\Mock\Mailgun;
class ConnectionTest extends \Mailgun\Tests\MailgunTestCase
{
private $client;
public function setUp()
{
}
public function testNewClientInstantiation()
{
$this->client = new Mailgun("My-Super-Awesome-API-Key", "samples.mailgun.org", false);
}
}

View File

@ -1,48 +0,0 @@
<?PHP
namespace Mailgun\Tests\Lists;
use Mailgun\Tests\Mock\Mailgun;
class OptInHandler extends \Mailgun\Tests\MailgunTestCase
{
private $client;
private $sampleDomain = "samples.mailgun.org";
private $optInHandler;
public function setUp()
{
$this->client = new Mailgun("My-Super-Awesome-API-Key");
$this->optInHandler = $this->client->OptInHandler();
}
public function testReturnOfGenerateHash()
{
$generatedHash = $this->optInHandler->generateHash(
'mytestlist@example.com',
'mysupersecretappid',
'testrecipient@example.com'
);
$knownHash = "eyJoIjoiMTllODc2YWNkMWRmNzk4NTc0ZTU0YzhjMzIzOTNiYTNjNzdhNGMxOCIsInAiOiJleUp5SWpvaWRHVnpkSEpsWTJsd2FXVnVkRUJsZUdGdGNHeGxMbU52YlNJc0ltd2lPaUp0ZVhSbGMzUnNhWE4wUUdWNFlXMXdiR1V1WTI5dEluMD0ifQ%3D%3D";
$this->assertEquals($generatedHash, $knownHash);
}
public function testGoodHash()
{
$validation = $this->optInHandler->validateHash(
'mysupersecretappid',
'eyJoIjoiMTllODc2YWNkMWRmNzk4NTc0ZTU0YzhjMzIzOTNiYTNjNzdhNGMxOCIsInAiOiJleUp5SWpvaWRHVnpkSEpsWTJsd2FXVnVkRUJsZUdGdGNHeGxMbU52YlNJc0ltd2lPaUp0ZVhSbGMzUnNhWE4wUUdWNFlXMXdiR1V1WTI5dEluMD0ifQ%3D%3D'
);
$this->assertArrayHasKey('recipientAddress', $validation);
$this->assertArrayHasKey('mailingList', $validation);
}
public function testBadHash()
{
$validation = $this->optInHandler->validateHash(
'mybadsecretappid',
'eyJoIjoiMTllODc2YWNkMWRmNzk4NTc0ZTU0YzhjMzIzOTNiYTNjNzdhNGMxOCIsInAiOiJleUp5SWpvaWRHVnpkSEpsWTJsd2FXVnVkRUJsZUdGdGNHeGxMbU52YlNJc0ltd2lPaUp0ZVhSbGMzUnNhWE4wUUdWNFlXMXdiR1V1WTI5dEluMD0ifQ%3D%3D'
);
$this->assertFalse($validation);
}
}

View File

@ -1,36 +0,0 @@
<?PHP
namespace Mailgun\Tests\Lists;
use Mailgun\Mailgun;
class MailgunTest extends \Mailgun\Tests\MailgunTestCase
{
public function testSendMessageMissingRequiredMIMEParametersExceptionGetsFlung()
{
$this->setExpectedException("\\Mailgun\\Messages\\Exceptions\\MissingRequiredMIMEParameters");
$client = new Mailgun();
$client->sendMessage("test.mailgun.com", "etss", 1);
}
public function testVerifyWebhookGood() {
$client = new Mailgun('key-3ax6xnjp29jd6fds4gc373sgvjxteol0');
$postData = [
'timestamp' => '1403645220',
'token' => '5egbgr1vjgqxtrnp65xfznchgdccwh5d6i09vijqi3whgowmn6',
'signature' => '9cfc5c41582e51246e73c88d34db3af0a3a2692a76fbab81492842f000256d33',
];
assert($client->verifyWebhookSignature($postData));
}
public function testVerifyWebhookBad() {
$client = new Mailgun('key-3ax6xnjp29jd6fds4gc373sgvjxteol0');
$postData = [
'timestamp' => '1403645220',
'token' => 'owyldpe6nxhmrn78epljl6bj0orrki1u3d2v5e6cnlmmuox8jr',
'signature' => '9cfc5c41582e51246e73c88d34db3af0a3a2692a76fbab81492842f000256d33',
];
assert(!$client->verifyWebhookSignature($postData));
}
}

View File

@ -1,9 +0,0 @@
<?PHP
namespace Mailgun\Tests;
use Guzzle\Tests\GuzzleTestCase;
abstract class MailgunTestCase extends GuzzleTestCase
{
}

View File

@ -1,172 +0,0 @@
<?PHP
namespace Mailgun\Tests\Messages;
use Mailgun\Tests\Mock\Mailgun;
class BatchMessageTest extends \Mailgun\Tests\MailgunTestCase
{
private $client;
private $sampleDomain = "samples.mailgun.org";
public function setUp()
{
$this->client = new Mailgun("My-Super-Awesome-API-Key");
}
public function testBlankInstantiation()
{
$message = $this->client->BatchMessage($this->sampleDomain);
$this->assertTrue(is_array($message->getMessage()));
}
public function testAddRecipient()
{
$message = $this->client->BatchMessage($this->sampleDomain);
$message->addToRecipient("test@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$messageObj = $message->getMessage();
$this->assertEquals(array("to" => array("'Test User' <test@samples.mailgun.org>")), $messageObj);
$reflectionClass = new \ReflectionClass(get_class($message));
$property = $reflectionClass->getProperty('counters');
$property->setAccessible(true);
$array = $property->getValue($message);
$this->assertEquals(1, $array['recipients']['to']);
}
public function testRecipientVariablesOnTo()
{
$message = $this->client->BatchMessage($this->sampleDomain);
$message->addToRecipient("test@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$messageObj = $message->getMessage();
$this->assertEquals(array("to" => array("'Test User' <test@samples.mailgun.org>")), $messageObj);
$reflectionClass = new \ReflectionClass(get_class($message));
$property = $reflectionClass->getProperty('batchRecipientAttributes');
$property->setAccessible(true);
$propertyValue = $property->getValue($message);
$this->assertEquals("Test", $propertyValue['test@samples.mailgun.org']['first']);
$this->assertEquals("User", $propertyValue['test@samples.mailgun.org']['last']);
}
public function testRecipientVariablesOnCc()
{
$message = $this->client->BatchMessage($this->sampleDomain);
$message->addCcRecipient("test@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$messageObj = $message->getMessage();
$this->assertEquals(array("cc" => array("'Test User' <test@samples.mailgun.org>")), $messageObj);
$reflectionClass = new \ReflectionClass(get_class($message));
$property = $reflectionClass->getProperty('batchRecipientAttributes');
$property->setAccessible(true);
$propertyValue = $property->getValue($message);
$this->assertEquals("Test", $propertyValue['test@samples.mailgun.org']['first']);
$this->assertEquals("User", $propertyValue['test@samples.mailgun.org']['last']);
}
public function testRecipientVariablesOnBcc()
{
$message = $this->client->BatchMessage($this->sampleDomain);
$message->addBccRecipient("test@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$messageObj = $message->getMessage();
$this->assertEquals(array("bcc" => array("'Test User' <test@samples.mailgun.org>")), $messageObj);
$reflectionClass = new \ReflectionClass(get_class($message));
$property = $reflectionClass->getProperty('batchRecipientAttributes');
$property->setAccessible(true);
$propertyValue = $property->getValue($message);
$this->assertEquals("Test", $propertyValue['test@samples.mailgun.org']['first']);
$this->assertEquals("User", $propertyValue['test@samples.mailgun.org']['last']);
}
public function testAddMultipleBatchRecipients()
{
$message = $this->client->BatchMessage($this->sampleDomain);
for ($i = 0; $i < 100; $i++) {
$message->addToRecipient("$i@samples.mailgun.org", array("first" => "Test", "last" => "User $i"));
}
$messageObj = $message->getMessage();
$this->assertEquals(100, count($messageObj["to"]));
}
public function testMaximumBatchSize()
{
$message = $this->client->BatchMessage($this->sampleDomain);
$message->setFromAddress("samples@mailgun.org", array("first" => "Test", "last" => "User"));
$message->setSubject("This is the subject of the message!");
$message->setTextBody("This is the text body of the message!");
for ($i = 0; $i < 1001; $i++) {
$message->addToRecipient("$i@samples.mailgun.org", array("first" => "Test", "last" => "User $i"));
}
$messageObj = $message->getMessage();
$this->assertEquals(1, count($messageObj["to"]));
}
public function testAttributeResetOnEndBatchMessage()
{
$message = $this->client->BatchMessage($this->sampleDomain);
$message->addToRecipient("test-user@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$message->setFromAddress("samples@mailgun.org", array("first" => "Test", "last" => "User"));
$message->setSubject("This is the subject of the message!");
$message->setTextBody("This is the text body of the message!");
$message->finalize();
$messageObj = $message->getMessage();
$this->assertTrue(true, empty($messageObj));
}
public function testDefaultIDInVariables()
{
$message = $this->client->BatchMessage($this->sampleDomain);
$message->addToRecipient("test-user@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$reflectionClass = new \ReflectionClass(get_class($message));
$property = $reflectionClass->getProperty('batchRecipientAttributes');
$property->setAccessible(true);
$propertyValue = $property->getValue($message);
$this->assertEquals(1, $propertyValue['test-user@samples.mailgun.org']['id']);
}
public function testgetMessageIds()
{
$message = $this->client->BatchMessage($this->sampleDomain);
$message->addToRecipient("test-user@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$message->setFromAddress("samples@mailgun.org", array("first" => "Test", "last" => "User"));
$message->setSubject("This is the subject of the message!");
$message->setTextBody("This is the text body of the message!");
$message->finalize();
$this->assertEquals(array("1234"), $message->getMessageIds());
}
public function testInvalidMissingRequiredMIMEParametersExceptionGetsFlungNoFrom()
{
$this->setExpectedException("\\Mailgun\\Messages\\Exceptions\\MissingRequiredMIMEParameters");
$message = $this->client->BatchMessage($this->sampleDomain);
$message->sendMessage(array(1, 2, 3));
}
public function testInvalidMissingRequiredMIMEParametersExceptionGetsFlungNoTo()
{
$this->setExpectedException("\\Mailgun\\Messages\\Exceptions\\MissingRequiredMIMEParameters");
$message = $this->client->BatchMessage($this->sampleDomain);
$message->sendMessage(array("from" => 1, 2, 3));
}
public function testInvalidMissingRequiredMIMEParametersExceptionGetsFlungNoSubject()
{
$this->setExpectedException("\\Mailgun\\Messages\\Exceptions\\MissingRequiredMIMEParameters");
$message = $this->client->BatchMessage($this->sampleDomain);
$message->sendMessage(array("from" => 1, "to" => 2, 3));
}
public function testInvalidMissingRequiredMIMEParametersExceptionGetsFlungNoTextOrHtml()
{
$this->setExpectedException("\\Mailgun\\Messages\\Exceptions\\MissingRequiredMIMEParameters");
$message = $this->client->BatchMessage($this->sampleDomain);
$message->sendMessage(array("from" => 1, "to" => 2, "subject" => 3));
}
}

View File

@ -1,356 +0,0 @@
<?PHP
namespace Mailgun\Tests\Messages;
use Mailgun\Tests\Mock\Mailgun;
class MessageBuilderTest extends \Mailgun\Tests\MailgunTestCase
{
private $client;
public function setUp()
{
$this->client = new Mailgun("My-Super-Awesome-API-Key", "samples.mailgun.org", false);
}
public function testBlankInstantiation()
{
$message = $this->client->MessageBuilder();
$this->assertTrue(is_array($message->getMessage()));
}
public function testCountersSetToZero()
{
$message = $this->client->MessageBuilder();
$reflectionClass = new \ReflectionClass(get_class($message));
$property = $reflectionClass->getProperty('counters');
$property->setAccessible(true);
$propertyValue = $property->getValue($message);
$this->assertEquals(0, $propertyValue['recipients']['to']);
$this->assertEquals(0, $propertyValue['recipients']['cc']);
$this->assertEquals(0, $propertyValue['recipients']['bcc']);
$this->assertEquals(0, $propertyValue['attributes']['attachment']);
$this->assertEquals(0, $propertyValue['attributes']['campaign_id']);
$this->assertEquals(0, $propertyValue['attributes']['custom_option']);
$this->assertEquals(0, $propertyValue['attributes']['tag']);
}
public function testAddToRecipient()
{
$message = $this->client->MessageBuilder();
$message->addToRecipient("test@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$messageObj = $message->getMessage();
$this->assertEquals(array("to" => array("'Test User' <test@samples.mailgun.org>")), $messageObj);
}
public function testAddCcRecipient()
{
$message = $this->client->MessageBuilder();
$message->addCcRecipient("test@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$messageObj = $message->getMessage();
$this->assertEquals(array("cc" => array("'Test User' <test@samples.mailgun.org>")), $messageObj);
}
public function testAddBccRecipient()
{
$message = $this->client->MessageBuilder();
$message->addBccRecipient("test@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$messageObj = $message->getMessage();
$this->assertEquals(array("bcc" => array("'Test User' <test@samples.mailgun.org>")), $messageObj);
}
public function testToRecipientCount()
{
$message = $this->client->MessageBuilder();
$message->addToRecipient("test-user@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$reflectionClass = new \ReflectionClass(get_class($message));
$property = $reflectionClass->getProperty('counters');
$property->setAccessible(true);
$array = $property->getValue($message);
$this->assertEquals(1, $array['recipients']['to']);
}
public function testCcRecipientCount()
{
$message = $this->client->MessageBuilder();
$message->addCcRecipient("test-user@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$reflectionClass = new \ReflectionClass(get_class($message));
$property = $reflectionClass->getProperty('counters');
$property->setAccessible(true);
$array = $property->getValue($message);
$this->assertEquals(1, $array['recipients']['cc']);
}
public function testBccRecipientCount()
{
$message = $this->client->MessageBuilder();
$message->addBccRecipient("test-user@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$reflectionClass = new \ReflectionClass(get_class($message));
$property = $reflectionClass->getProperty('counters');
$property->setAccessible(true);
$array = $property->getValue($message);
$this->assertEquals(1, $array['recipients']['bcc']);
}
public function testSetFromAddress()
{
$message = $this->client->MessageBuilder();
$message->setFromAddress("test@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$messageObj = $message->getMessage();
$this->assertEquals(array("from" => array("'Test User' <test@samples.mailgun.org>")), $messageObj);
}
public function testSetReplyTo()
{
$message = $this->client->MessageBuilder();
$message->setReplyToAddress("test@samples.mailgun.org", array("first" => "Test", "last" => "User"));
$messageObj = $message->getMessage();
$this->assertEquals(array("h:reply-to" => "'Test User' <test@samples.mailgun.org>"), $messageObj);
}
public function testSetSubject()
{
$message = $this->client->MessageBuilder();
$message->setSubject("Test Subject");
$messageObj = $message->getMessage();
$this->assertEquals(array("subject" => "Test Subject"), $messageObj);
}
public function testAddCustomHeader()
{
$message = $this->client->MessageBuilder();
$message->addCustomHeader("My-Header", "123");
$messageObj = $message->getMessage();
$this->assertEquals(array("h:My-Header" => array("123")), $messageObj);
}
public function testSetTextBody()
{
$message = $this->client->MessageBuilder();
$message->setTextBody("This is the text body!");
$messageObj = $message->getMessage();
$this->assertEquals(array("text" => "This is the text body!"), $messageObj);
}
public function testSetHtmlBody()
{
$message = $this->client->MessageBuilder();
$message->setHtmlBody("<html><body>This is an awesome email</body></html>");
$messageObj = $message->getMessage();
$this->assertEquals(array("html" => "<html><body>This is an awesome email</body></html>"), $messageObj);
}
public function testAddAttachments()
{
$message = $this->client->MessageBuilder();
$message->addAttachment("@../TestAssets/mailgun_icon.png");
$message->addAttachment("@../TestAssets/rackspace_logo.png");
$messageObj = $message->getFiles();
$this->assertEquals(
array(
array(
'filePath' => "@../TestAssets/mailgun_icon.png",
'remoteName' => null
),
array(
'filePath' => "@../TestAssets/rackspace_logo.png",
'remoteName' => null
)
),
$messageObj["attachment"]
);
}
public function testAddInlineImages()
{
$message = $this->client->MessageBuilder();
$message->addInlineImage("@../TestAssets/mailgun_icon.png");
$message->addInlineImage("@../TestAssets/rackspace_logo.png");
$messageObj = $message->getFiles();
$this->assertEquals(
array(
array(
'filePath' => "@../TestAssets/mailgun_icon.png",
'remoteName' => null
),
array(
'filePath' => "@../TestAssets/rackspace_logo.png",
'remoteName' => null
)
),
$messageObj['inline']
);
}
public function testAddAttachmentsPostName()
{
$message = $this->client->MessageBuilder();
$message->addAttachment('@../TestAssets/mailgun_icon.png', 'mg_icon.png');
$message->addAttachment('@../TestAssets/rackspace_logo.png', 'rs_logo.png');
$messageObj = $message->getFiles();
$this->assertEquals(
array(
array(
'filePath' => '@../TestAssets/mailgun_icon.png',
'remoteName' => 'mg_icon.png'
),
array(
'filePath' => '@../TestAssets/rackspace_logo.png',
'remoteName' => 'rs_logo.png'
)
),
$messageObj["attachment"]
);
}
public function testAddInlineImagePostName()
{
$message = $this->client->MessageBuilder();
$message->addInlineImage('@../TestAssets/mailgun_icon.png', 'mg_icon.png');
$message->addInlineImage('@../TestAssets/rackspace_logo.png', 'rs_logo.png');
$messageObj = $message->getFiles();
$this->assertEquals(
array(
array(
'filePath' => '@../TestAssets/mailgun_icon.png',
'remoteName' => 'mg_icon.png'
),
array(
'filePath' => '@../TestAssets/rackspace_logo.png',
'remoteName' => 'rs_logo.png'
)
),
$messageObj['inline']
);
}
public function testsetTestMode()
{
$message = $this->client->MessageBuilder();
$message->setTestMode(true);
$messageObj = $message->getMessage();
$this->assertEquals(array("o:testmode" => "yes"), $messageObj);
$message->setTestMode(false);
$messageObj = $message->getMessage();
$this->assertEquals(array("o:testmode" => "no"), $messageObj);
$message->setTestMode("yes");
$messageObj = $message->getMessage();
$this->assertEquals(array("o:testmode" => "yes"), $messageObj);
$message->setTestMode("no");
$messageObj = $message->getMessage();
$this->assertEquals(array("o:testmode" => "no"), $messageObj);
}
public function addCampaignId()
{
$message = $this->client->MessageBuilder();
$message->addCampaignId("ABC123");
$message->addCampaignId("XYZ987");
$message->addCampaignId("TUV456");
$message->addCampaignId("NONO123");
$messageObj = $message->getMessage();
$this->assertEquals(array("o:campaign" => array("ABC123", "XYZ987", "TUV456")), $messageObj);
}
public function testSetDkim()
{
$message = $this->client->MessageBuilder();
$message->setDkim(true);
$messageObj = $message->getMessage();
$this->assertEquals(array("o:dkim" => "yes"), $messageObj);
$message->setDkim(false);
$messageObj = $message->getMessage();
$this->assertEquals(array("o:dkim" => "no"), $messageObj);
$message->setDkim("yes");
$messageObj = $message->getMessage();
$this->assertEquals(array("o:dkim" => "yes"), $messageObj);
$message->setDkim("no");
$messageObj = $message->getMessage();
$this->assertEquals(array("o:dkim" => "no"), $messageObj);
}
public function testSetClickTracking()
{
$message = $this->client->MessageBuilder();
$message->setClickTracking(true);
$messageObj = $message->getMessage();
$this->assertEquals(array("o:tracking-clicks" => "yes"), $messageObj);
$message->setClickTracking(false);
$messageObj = $message->getMessage();
$this->assertEquals(array("o:tracking-clicks" => "no"), $messageObj);
$message->setClickTracking("yes");
$messageObj = $message->getMessage();
$this->assertEquals(array("o:tracking-clicks" => "yes"), $messageObj);
$message->setClickTracking("no");
$messageObj = $message->getMessage();
$this->assertEquals(array("o:tracking-clicks" => "no"), $messageObj);
}
public function testSetOpenTracking()
{
$message = $this->client->MessageBuilder();
$message->setOpenTracking(true);
$messageObj = $message->getMessage();
$this->assertEquals(array("o:tracking-opens" => "yes"), $messageObj);
$message->setOpenTracking(false);
$messageObj = $message->getMessage();
$this->assertEquals(array("o:tracking-opens" => "no"), $messageObj);
$message->setOpenTracking("yes");
$messageObj = $message->getMessage();
$this->assertEquals(array("o:tracking-opens" => "yes"), $messageObj);
$message->setOpenTracking("no");
$messageObj = $message->getMessage();
$this->assertEquals(array("o:tracking-opens" => "no"), $messageObj);
}
public function testSetDeliveryTime()
{
$message = $this->client->MessageBuilder();
$message->setDeliveryTime("January 15, 2014 8:00AM", "CST");
$messageObj = $message->getMessage();
$this->assertEquals(array("o:deliverytime" => "Wed, 15 Jan 2014 08:00:00 -0600"), $messageObj);
$message->setDeliveryTime("January 15, 2014 8:00AM", "UTC");
$messageObj = $message->getMessage();
$this->assertEquals(array("o:deliverytime" => "Wed, 15 Jan 2014 08:00:00 +0000"), $messageObj);
$message->setDeliveryTime("January 15, 2014 8:00AM");
$messageObj = $message->getMessage();
$this->assertEquals(array("o:deliverytime" => "Wed, 15 Jan 2014 08:00:00 +0000"), $messageObj);
$message->setDeliveryTime("1/15/2014 13:50:01", "CDT");
$messageObj = $message->getMessage();
$this->assertEquals(array("o:deliverytime" => "Wed, 15 Jan 2014 13:50:01 -0600"), $messageObj);
// https://github.com/mailgun/mailgun-php/pull/42
// https://github.com/mailgun/mailgun-php/issues/43
//$message->setDeliveryTime("first saturday of July 2013 8:00AM", "CDT");
//$messageObj = $message->getMessage();
//$this->assertEquals(array("o:deliverytime" => "Sat, 06 Jul 2013 08:00:00 -0500"), $messageObj);
}
public function testAddCustomData()
{
$message = $this->client->MessageBuilder();
$message->addCustomData("My-Super-Awesome-Data", array("What" => "Mailgun Rocks!"));
$messageObj = $message->getMessage();
$this->assertEquals(array("v:My-Super-Awesome-Data" => "{\"What\":\"Mailgun Rocks!\"}"), $messageObj);
}
public function testAddCustomParameter()
{
$message = $this->client->MessageBuilder();
$message->addCustomParameter("my-option", "yes");
$message->addCustomParameter("o:my-other-option", "no");
$messageObj = $message->getMessage();
$this->assertEquals(array("my-option" => array("yes"), "o:my-other-option" => array("no")), $messageObj);
}
public function testSetMessage()
{
$message = array(1, 2, 3, 4, 5);
$messageBuilder = $this->client->MessageBuilder();
$messageBuilder->setMessage($message);
$this->assertEquals($message, $messageBuilder->getMessage());
}
}

View File

@ -1,48 +0,0 @@
<?PHP
namespace Mailgun\Tests\Messages;
use Mailgun\Tests\Mock\Mailgun;
class StandardMessageTest extends \Mailgun\Tests\MailgunTestCase
{
private $client;
private $sampleDomain = "samples.mailgun.org";
public function setUp()
{
$this->client = new Mailgun("My-Super-Awesome-API-Key");
}
public function testSendMIMEMessage()
{
$customMime = "Received: by luna.mailgun.net with SMTP mgrt 8728174999085; Mon, 10 Jun 2013 09:50:58 +0000
Mime-Version: 1.0
Content-Type: text/plain; charset=\"ascii\"
Subject: This is the Subject!
From: Mailgun Testing <test@test.mailgun.com>
To: test@test.mailgun.com
Message-Id: <20130610095049.30790.4334@test.mailgun.com>
Content-Transfer-Encoding: 7bit
X-Mailgun-Sid: WyIxYTdhMyIsICJmaXplcmtoYW5AcXVhZG1zLmluIiwgImExOWQiXQ==
Date: Mon, 10 Jun 2013 09:50:58 +0000
Sender: test@test.mailgun.com
Mailgun is testing!";
$envelopeFields = array('to' => 'test@test.mailgun.org');
$result = $this->client->sendMessage("test.mailgun.org", $envelopeFields, $customMime);
$this->assertEquals("test.mailgun.org/messages.mime", $result->http_endpoint_url);
}
public function testSendMessage()
{
$message = array('to' => 'test@test.mailgun.org',
'from' => 'sender@test.mailgun.org',
'subject' => 'This is my test subject',
'text' => 'Testing!'
);
$result = $this->client->sendMessage("test.mailgun.org", $message);
$this->assertEquals("test.mailgun.org/messages", $result->http_endpoint_url);
}
}

View File

@ -1,67 +0,0 @@
<?php
namespace Mailgun\Tests\Mock\Connection;
use Mailgun\Connection\RestClient;
class TestBroker extends RestClient
{
private $apiKey;
protected $apiEndpoint;
public function __construct($apiKey = null, $apiEndpoint = "api.mailgun.net", $apiVersion = "v2")
{
$this->apiKey = $apiKey;
$this->apiEndpoint = $apiEndpoint;
}
public function post($endpointUrl, $postData = array(), $files = array())
{
return $this->responseHandler($endpointUrl, $httpResponseCode = 200);
}
public function get($endpointUrl, $queryString = array())
{
return $this->responseHandler($endpointUrl, $httpResponseCode = 200);
}
public function delete($endpointUrl)
{
return $this->responseHandler($endpointUrl, $httpResponseCode = 200);
}
public function put($endpointUrl, $queryString)
{
return $this->responseHandler($endpointUrl, $httpResponseCode = 200);
}
public function responseHandler($endpointUrl, $httpResponseCode = 200)
{
if ($httpResponseCode === 200) {
$result = new \stdClass();
$result->http_response_body = new \stdClass();
$jsonResponseData = json_decode('{"message": "Some JSON Response Data", "id": "1234"}');
foreach ($jsonResponseData as $key => $value) {
$result->http_response_body->$key = $value;
}
} elseif ($httpStatusCode == 400) {
throw new MissingRequiredMIMEParameters(EXCEPTION_MISSING_REQUIRED_MIME_PARAMETERS);
} elseif ($httpStatusCode == 401) {
throw new InvalidCredentials(EXCEPTION_INVALID_CREDENTIALS);
} elseif ($httpStatusCode == 401) {
throw new GenericHTTPError(EXCEPTION_INVALID_CREDENTIALS);
} elseif ($httpStatusCode == 404) {
throw new MissingEndpoint(EXCEPTION_MISSING_ENDPOINT);
} else {
throw new GenericHTTPError(EXCEPTION_GENERIC_HTTP_ERROR);
return false;
}
$result->http_response_code = $httpResponseCode;
$result->http_endpoint_url = $endpointUrl;
return $result;
}
}

View File

@ -1,17 +0,0 @@
<?PHP
namespace Mailgun\Tests\Mock;
use Mailgun\Mailgun as Base;
use Mailgun\Tests\Mock\Connection\TestBroker;
class Mailgun extends Base
{
protected $debug;
protected $restClient;
public function __construct($apiKey = null, $apiEndpoint = "api.mailgun.net", $apiVersion = "v2")
{
$this->restClient = new TestBroker($apiKey, $apiEndpoint, $apiVersion);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

View File

@ -2,6 +2,6 @@
// autoload.php @generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit4ddb0bfe747486746b07c9365ebf26f5::getLoader();
return ComposerAutoloaderInit312a1f75dce9c5adc27329538beefb51::getLoader();

View File

@ -1 +0,0 @@
../phpunit/phpunit/composer/bin/phpunit

View File

@ -0,0 +1,2 @@
/vendor
/composer.lock

View File

@ -0,0 +1,27 @@
language: php
php:
# - 5.3 # requires old distro, see below
- 5.4
- 5.5
- 5.6
- 7.0
- 7.1
- 7.2
- hhvm # ignore errors, see below
# lock distro so new future defaults will not break the build
dist: trusty
matrix:
include:
- php: 5.3
dist: precise
allow_failures:
- php: hhvm
install:
- composer install --no-interaction
script:
- vendor/bin/phpunit --coverage-text

View File

@ -0,0 +1,63 @@
# Changelog
## 1.4.1 (2019-04-09)
* Fix: Check if the function is declared before declaring it.
(#23 by @Niko9911)
* Improve test suite to also test against PHP 7.2 and
add test for base64 encoding and decoding filters.
(#22 by @arubacao and #25 by @Nyholm and @clue)
## 1.4.0 (2017-08-18)
* Feature / Fix: The `fun()` function does not pass filter parameter `null`
to underlying `stream_filter_append()` by default
(#15 by @Nyholm)
Certain filters (such as `convert.quoted-printable-encode`) do not accept
a filter parameter at all. If no explicit filter parameter is given, we no
longer pass a default `null` value.
```php
$encode = Filter\fun('convert.quoted-printable-encode');
assert('t=C3=A4st' === $encode('täst'));
```
* Add examples and improve documentation
(#13 and #20 by @clue and #18 by @Nyholm)
* Improve test suite by adding PHPUnit to require-dev,
fix HHVM build for now again and ignore future HHVM build errors,
lock Travis distro so new future defaults will not break the build
and test on PHP 7.1
(#12, #14 and #19 by @clue and #16 by @Nyholm)
## 1.3.0 (2015-11-08)
* Feature: Support accessing built-in filters as callbacks
(#5 by @clue)
```php
$fun = Filter\fun('zlib.deflate');
$ret = $fun('hello') . $fun('world') . $fun();
assert('helloworld' === gzinflate($ret));
```
## 1.2.0 (2015-10-23)
* Feature: Invoke close event when closing filter (flush buffer)
(#9 by @clue)
## 1.1.0 (2015-10-22)
* Feature: Abort filter operation when catching an Exception
(#10 by @clue)
* Feature: Additional safeguards to prevent filter state corruption
(#7 by @clue)
## 1.0.0 (2015-10-18)
* First tagged release

View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Christian Lück
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,301 @@
# clue/stream-filter [![Build Status](https://travis-ci.org/clue/php-stream-filter.svg?branch=master)](https://travis-ci.org/clue/php-stream-filter)
A simple and modern approach to stream filtering in PHP
**Table of contents**
* [Why?](#why)
* [Usage](#usage)
* [append()](#append)
* [prepend()](#prepend)
* [fun()](#fun)
* [remove()](#remove)
* [Install](#install)
* [Tests](#tests)
* [License](#license)
## Why?
PHP's stream filtering system is great!
It offers very powerful stream filtering options and comes with a useful set of built-in filters.
These filters can be used to easily and efficiently perform various transformations on-the-fly, such as:
* read from a gzip'ed input file,
* transcode from ISO-8859-1 (Latin1) to UTF-8,
* write to a bzip output file
* and much more.
But let's face it:
Its API is [*difficult to work with*](https://www.php.net/manual/en/php-user-filter.filter.php)
and its documentation is [*subpar*](https://stackoverflow.com/questions/27103269/what-is-a-bucket-brigade).
This combined means its powerful features are often neglected.
This project aims to make these features more accessible to a broader audience.
* **Lightweight, SOLID design** -
Provides a thin abstraction that is [*just good enough*](https://en.wikipedia.org/wiki/Principle_of_good_enough)
and does not get in your way.
Custom filters require trivial effort.
* **Good test coverage** -
Comes with an automated tests suite and is regularly tested in the *real world*
## Usage
This lightweight library consists only of a few simple functions.
All functions reside under the `Clue\StreamFilter` namespace.
The below examples assume you use an import statement similar to this:
```php
use Clue\StreamFilter as Filter;
Filter\append(…);
```
Alternatively, you can also refer to them with their fully-qualified name:
```php
\Clue\StreamFilter\append(…);
```
### append()
The `append($stream, $callback, $read_write = STREAM_FILTER_ALL)` function can be used to
append a filter callback to the given stream.
Each stream can have a list of filters attached.
This function appends a filter to the end of this list.
This function returns a filter resource which can be passed to [`remove()`](#remove).
If the given filter can not be added, it throws an `Exception`.
The `$stream` can be any valid stream resource, such as:
```php
$stream = fopen('demo.txt', 'w+');
```
The `$callback` should be a valid callable function which accepts an individual chunk of data
and should return the updated chunk:
```php
$filter = Filter\append($stream, function ($chunk) {
// will be called each time you read or write a $chunk to/from the stream
return $chunk;
});
```
As such, you can also use native PHP functions or any other `callable`:
```php
Filter\append($stream, 'strtoupper');
// will write "HELLO" to the underlying stream
fwrite($stream, 'hello');
```
If the `$callback` accepts invocation without parameters, then this signature
will be invoked once ending (flushing) the filter:
```php
Filter\append($stream, function ($chunk = null) {
if ($chunk === null) {
// will be called once ending the filter
return 'end';
}
// will be called each time you read or write a $chunk to/from the stream
return $chunk;
});
fclose($stream);
```
> Note: Legacy PHP versions (PHP < 5.4) do not support passing additional data
from the end signal handler if the stream is being closed.
If your callback throws an `Exception`, then the filter process will be aborted.
In order to play nice with PHP's stream handling, the `Exception` will be
transformed to a PHP warning instead:
```php
Filter\append($stream, function ($chunk) {
throw new \RuntimeException('Unexpected chunk');
});
// raises an E_USER_WARNING with "Error invoking filter: Unexpected chunk"
fwrite($stream, 'hello');
```
The optional `$read_write` parameter can be used to only invoke the `$callback` when either writing to the stream or only when reading from the stream:
```php
Filter\append($stream, function ($chunk) {
// will be called each time you write to the stream
return $chunk;
}, STREAM_FILTER_WRITE);
Filter\append($stream, function ($chunk) {
// will be called each time you read from the stream
return $chunk;
}, STREAM_FILTER_READ);
```
> Note that once a filter has been added to stream, the stream can no longer be passed to
> [`stream_select()`](https://www.php.net/manual/en/function.stream-select.php)
> (and family).
>
> > Warning: stream_select(): cannot cast a filtered stream on this system in {file} on line {line}
>
> This is due to limitations of PHP's stream filter support, as it can no longer reliably
> tell when the underlying stream resource is actually ready.
> As an alternative, consider calling `stream_select()` on the unfiltered stream and
> then pass the unfiltered data through the [`fun()`](#fun) function.
### prepend()
The `prepend($stream, $callback, $read_write = STREAM_FILTER_ALL)` function can be used to
prepend a filter callback to the given stream.
Each stream can have a list of filters attached.
This function prepends a filter to the start of this list.
This function returns a filter resource which can be passed to [`remove()`](#remove).
If the given filter can not be added, it throws an `Exception`.
```php
$filter = Filter\prepend($stream, function ($chunk) {
// will be called each time you read or write a $chunk to/from the stream
return $chunk;
});
```
Except for the position in the list of filters, this function behaves exactly
like the [`append()`](#append) function.
For more details about its behavior, see also the [`append()`](#append) function.
### fun()
The `fun($filter, $parameters = null)` function can be used to
create a filter function which uses the given built-in `$filter`.
PHP comes with a useful set of [built-in filters](https://www.php.net/manual/en/filters.php).
Using `fun()` makes accessing these as easy as passing an input string to filter
and getting the filtered output string.
```php
$fun = Filter\fun('string.rot13');
assert('grfg' === $fun('test'));
assert('test' === $fun($fun('test'));
```
Please note that not all filter functions may be available depending on installed
PHP extensions and the PHP version in use.
In particular, [HHVM](https://hhvm.com/) may not offer the same filter functions
or parameters as Zend PHP.
Accessing an unknown filter function will result in a `RuntimeException`:
```php
Filter\fun('unknown'); // throws RuntimeException
```
Some filters may accept or require additional filter parameters most
filters do not require filter parameters.
If given, the optional `$parameters` argument will be passed to the
underlying filter handler as-is.
In particular, note how *not passing* this parameter at all differs from
explicitly passing a `null` value (which many filters do not accept).
Please refer to the individual filter definition for more details.
For example, the `string.strip_tags` filter can be invoked like this:
```php
$fun = Filter\fun('string.strip_tags', '<a><b>');
$ret = $fun('<b>h<br>i</b>');
assert('<b>hi</b>' === $ret);
```
Under the hood, this function allocates a temporary memory stream, so it's
recommended to clean up the filter function after use.
Also, some filter functions (in particular the
[zlib compression filters](https://www.php.net/manual/en/filters.compression.php))
may use internal buffers and may emit a final data chunk on close.
The filter function can be closed by invoking without any arguments:
```php
$fun = Filter\fun('zlib.deflate');
$ret = $fun('hello') . $fun('world') . $fun();
assert('helloworld' === gzinflate($ret));
```
The filter function must not be used anymore after it has been closed.
Doing so will result in a `RuntimeException`:
```php
$fun = Filter\fun('string.rot13');
$fun();
$fun('test'); // throws RuntimeException
```
> Note: If you're using the zlib compression filters, then you should be wary
about engine inconsistencies between different PHP versions and HHVM.
These inconsistencies exist in the underlying PHP engines and there's little we
can do about this in this library.
[Our test suite](tests/) contains several test cases that exhibit these issues.
If you feel some test case is missing or outdated, we're happy to accept PRs! :)
### remove()
The `remove($filter)` function can be used to
remove a filter previously added via [`append()`](#append) or [`prepend()`](#prepend).
```php
$filter = Filter\append($stream, function () {
// …
});
Filter\remove($filter);
```
## Install
The recommended way to install this library is [through Composer](https://getcomposer.org).
[New to Composer?](https://getcomposer.org/doc/00-intro.md)
This project follows [SemVer](https://semver.org/).
This will install the latest supported version:
```bash
$ composer require clue/stream-filter:^1.4.1
```
See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.
This project aims to run on any platform and thus does not require any PHP
extensions and supports running on legacy PHP 5.3 through current PHP 7+ and
HHVM.
It's *highly recommended to use PHP 7+* for this project.
Older PHP versions may suffer from a number of inconsistencies documented above.
## Tests
To run the test suite, you first need to clone this repo and then install all
dependencies [through Composer](https://getcomposer.org):
```bash
$ composer install
```
To run the test suite, go to the project root and run:
```bash
$ php vendor/bin/phpunit
```
## License
This project is released under the permissive [MIT license](LICENSE).
> Did you know that I offer custom development services and issuing invoices for
sponsorships of releases and for contributions? Contact me (@clue) for details.

View File

@ -0,0 +1,23 @@
{
"name": "clue/stream-filter",
"description": "A simple and modern approach to stream filtering in PHP",
"keywords": ["stream", "callback", "filter", "php_user_filter", "stream_filter_append", "stream_filter_register", "bucket brigade"],
"homepage": "https://github.com/clue/php-stream-filter",
"license": "MIT",
"authors": [
{
"name": "Christian Lück",
"email": "christian@lueck.tv"
}
],
"require": {
"php": ">=5.3"
},
"require-dev": {
"phpunit/phpunit": "^5.0 || ^4.8"
},
"autoload": {
"psr-4": { "Clue\\StreamFilter\\": "src/" },
"files": [ "src/functions_include.php" ]
}
}

View File

@ -0,0 +1,29 @@
<?php
// $ echo test | php examples/base64_encode.php | php examples/base64_decode.php
require __DIR__ . '/../vendor/autoload.php';
// decoding requires buffering in chunks of 4 bytes each
$buffer = '';
Clue\StreamFilter\append(STDIN, function ($chunk = null) use (&$buffer) {
if ($chunk === null) {
if (strlen($buffer) % 4 !== 0) {
throw new \UnexpectedValueException('Invalid length');
}
$chunk = $buffer;
} else {
$buffer .= $chunk;
$len = strlen($buffer) - (strlen($buffer) % 4);
$chunk = (string)substr($buffer, 0, $len);
$buffer = (string)substr($buffer, $len);
}
$ret = base64_decode($chunk, true);
if ($ret === false) {
throw new \UnexpectedValueException('Not a valid base64 encoded chunk');
}
return $ret;
}, STREAM_FILTER_READ);
fpassthru(STDIN);

View File

@ -0,0 +1,21 @@
<?php
// $ echo test | php examples/base64_encode.php | base64 --decode
require __DIR__ . '/../vendor/autoload.php';
// encoding requires buffering in chunks of 3 bytes each
$buffer = '';
Clue\StreamFilter\append(STDIN, function ($chunk = null) use (&$buffer) {
if ($chunk === null) {
return base64_encode($buffer);
}
$buffer .= $chunk;
$len = strlen($buffer) - (strlen($buffer) % 3);
$chunk = substr($buffer, 0, $len);
$buffer = substr($buffer, $len);
return base64_encode($chunk);
}, STREAM_FILTER_READ);
fpassthru(STDIN);

View File

@ -0,0 +1,9 @@
<?php
// $ echo test | php examples/uppercase.php
require __DIR__ . '/../vendor/autoload.php';
Clue\StreamFilter\append(STDIN, 'strtoupper');
fpassthru(STDIN);

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
>
<testsuites>
<testsuite>
<directory>./tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./src/</directory>
</whitelist>
</filter>
</phpunit>

View File

@ -0,0 +1,120 @@
<?php
namespace Clue\StreamFilter;
use php_user_filter;
use InvalidArgumentException;
use ReflectionFunction;
use Exception;
/**
*
* @internal
* @see append()
* @see prepend()
*/
class CallbackFilter extends php_user_filter
{
private $callback;
private $closed = true;
private $supportsClose = false;
public function onCreate()
{
$this->closed = false;
if (!is_callable($this->params)) {
throw new InvalidArgumentException('No valid callback parameter given to stream_filter_(append|prepend)');
}
$this->callback = $this->params;
// callback supports end event if it accepts invocation without arguments
$ref = new ReflectionFunction($this->callback);
$this->supportsClose = ($ref->getNumberOfRequiredParameters() === 0);
return true;
}
public function onClose()
{
$this->closed = true;
// callback supports closing and is not already closed
if ($this->supportsClose) {
$this->supportsClose = false;
// invoke without argument to signal end and discard resulting buffer
try {
call_user_func($this->callback);
} catch (Exception $ignored) {
// this might be called during engine shutdown, so it's not safe
// to raise any errors or exceptions here
// trigger_error('Error closing filter: ' . $ignored->getMessage(), E_USER_WARNING);
}
}
$this->callback = null;
}
public function filter($in, $out, &$consumed, $closing)
{
// concatenate whole buffer from input brigade
$data = '';
while ($bucket = stream_bucket_make_writeable($in)) {
$consumed += $bucket->datalen;
$data .= $bucket->data;
}
// skip processing callback that already ended
if ($this->closed) {
return PSFS_FEED_ME;
}
// only invoke filter function if buffer is not empty
// this may skip flushing a closing filter
if ($data !== '') {
try {
$data = call_user_func($this->callback, $data);
} catch (Exception $e) {
// exception should mark filter as closed
$this->onClose();
trigger_error('Error invoking filter: ' . $e->getMessage(), E_USER_WARNING);
return PSFS_ERR_FATAL;
}
}
// mark filter as closed after processing closing chunk
if ($closing) {
$this->closed = true;
// callback supports closing and is not already closed
if ($this->supportsClose) {
$this->supportsClose = false;
// invoke without argument to signal end and append resulting buffer
try {
$data .= call_user_func($this->callback);
} catch (Exception $e) {
trigger_error('Error ending filter: ' . $e->getMessage(), E_USER_WARNING);
return PSFS_ERR_FATAL;
}
}
}
if ($data !== '') {
// create a new bucket for writing the resulting buffer to the output brigade
// reusing an existing bucket turned out to be bugged in some environments (ancient PHP versions and HHVM)
$bucket = @stream_bucket_new($this->stream, $data);
// legacy PHP versions (PHP < 5.4) do not support passing data from the event signal handler
// because closing the stream invalidates the stream and its stream bucket brigade before
// invoking the filter close handler.
if ($bucket !== false) {
stream_bucket_append($out, $bucket);
}
}
return PSFS_PASS_ON;
}
}

View File

@ -0,0 +1,146 @@
<?php
namespace Clue\StreamFilter;
use RuntimeException;
/**
* append a callback filter to the given stream
*
* @param resource $stream
* @param callable $callback
* @param int $read_write
* @return resource filter resource which can be used for `remove()`
* @throws Exception on error
* @uses stream_filter_append()
*/
function append($stream, $callback, $read_write = STREAM_FILTER_ALL)
{
$ret = @stream_filter_append($stream, register(), $read_write, $callback);
if ($ret === false) {
$error = error_get_last() + array('message' => '');
throw new RuntimeException('Unable to append filter: ' . $error['message']);
}
return $ret;
}
/**
* prepend a callback filter to the given stream
*
* @param resource $stream
* @param callable $callback
* @param int $read_write
* @return resource filter resource which can be used for `remove()`
* @throws Exception on error
* @uses stream_filter_prepend()
*/
function prepend($stream, $callback, $read_write = STREAM_FILTER_ALL)
{
$ret = @stream_filter_prepend($stream, register(), $read_write, $callback);
if ($ret === false) {
$error = error_get_last() + array('message' => '');
throw new RuntimeException('Unable to prepend filter: ' . $error['message']);
}
return $ret;
}
/**
* Creates filter fun (function) which uses the given built-in $filter
*
* Some filters may accept or require additional filter parameters most
* filters do not require filter parameters.
* If given, the optional `$parameters` argument will be passed to the
* underlying filter handler as-is.
* In particular, note how *not passing* this parameter at all differs from
* explicitly passing a `null` value (which many filters do not accept).
* Please refer to the individual filter definition for more details.
*
* @param string $filter built-in filter name. See stream_get_filters() or http://php.net/manual/en/filters.php
* @param mixed $parameters (optional) parameters to pass to the built-in filter as-is
* @return callable a filter callback which can be append()'ed or prepend()'ed
* @throws RuntimeException on error
* @link http://php.net/manual/en/filters.php
* @see stream_get_filters()
* @see append()
*/
function fun($filter, $parameters = null)
{
$fp = fopen('php://memory', 'w');
if (func_num_args() === 1) {
$filter = @stream_filter_append($fp, $filter, STREAM_FILTER_WRITE);
} else {
$filter = @stream_filter_append($fp, $filter, STREAM_FILTER_WRITE, $parameters);
}
if ($filter === false) {
fclose($fp);
$error = error_get_last() + array('message' => '');
throw new RuntimeException('Unable to access built-in filter: ' . $error['message']);
}
// append filter function which buffers internally
$buffer = '';
append($fp, function ($chunk) use (&$buffer) {
$buffer .= $chunk;
// always return empty string in order to skip actually writing to stream resource
return '';
}, STREAM_FILTER_WRITE);
$closed = false;
return function ($chunk = null) use ($fp, $filter, &$buffer, &$closed) {
if ($closed) {
throw new \RuntimeException('Unable to perform operation on closed stream');
}
if ($chunk === null) {
$closed = true;
$buffer = '';
fclose($fp);
return $buffer;
}
// initialize buffer and invoke filters by attempting to write to stream
$buffer = '';
fwrite($fp, $chunk);
// buffer now contains everything the filter function returned
return $buffer;
};
}
/**
* remove a callback filter from the given stream
*
* @param resource $filter
* @return boolean true on success or false on error
* @throws Exception on error
* @uses stream_filter_remove()
*/
function remove($filter)
{
if (@stream_filter_remove($filter) === false) {
throw new RuntimeException('Unable to remove given filter');
}
}
/**
* registers the callback filter and returns the resulting filter name
*
* There should be little reason to call this function manually.
*
* @return string filter name
* @uses CallbackFilter
*/
function register()
{
static $registered = null;
if ($registered === null) {
$registered = 'stream-callback';
stream_filter_register($registered, __NAMESPACE__ . '\CallbackFilter');
}
return $registered;
}

View File

@ -0,0 +1,5 @@
<?php
if (!function_exists('Clue\\StreamFilter\\append')) {
require __DIR__ . '/functions.php';
}

View File

@ -0,0 +1,386 @@
<?php
use Clue\StreamFilter;
class FilterTest extends PHPUnit_Framework_TestCase
{
public function testAppendSimpleCallback()
{
$stream = $this->createStream();
StreamFilter\append($stream, function ($chunk) {
return strtoupper($chunk);
});
fwrite($stream, 'hello');
fwrite($stream, 'world');
rewind($stream);
$this->assertEquals('HELLOWORLD', stream_get_contents($stream));
fclose($stream);
}
public function testAppendNativePhpFunction()
{
$stream = $this->createStream();
StreamFilter\append($stream, 'strtoupper');
fwrite($stream, 'hello');
fwrite($stream, 'world');
rewind($stream);
$this->assertEquals('HELLOWORLD', stream_get_contents($stream));
fclose($stream);
}
public function testAppendChangingChunkSize()
{
$stream = $this->createStream();
StreamFilter\append($stream, function ($chunk) {
return str_replace(array('a','e','i','o','u'), '', $chunk);
});
fwrite($stream, 'hello');
fwrite($stream, 'world');
rewind($stream);
$this->assertEquals('hllwrld', stream_get_contents($stream));
fclose($stream);
}
public function testAppendReturningEmptyStringWillNotPassThrough()
{
$stream = $this->createStream();
StreamFilter\append($stream, function ($chunk) {
return '';
});
fwrite($stream, 'hello');
fwrite($stream, 'world');
rewind($stream);
$this->assertEquals('', stream_get_contents($stream));
fclose($stream);
}
public function testAppendEndEventCanBeBufferedOnClose()
{
if (PHP_VERSION < 5.4) $this->markTestSkipped('Not supported on legacy PHP');
$stream = $this->createStream();
StreamFilter\append($stream, function ($chunk = null) {
if ($chunk === null) {
// this signals the end event
return '!';
}
return $chunk . ' ';
}, STREAM_FILTER_WRITE);
$buffered = '';
StreamFilter\append($stream, function ($chunk) use (&$buffered) {
$buffered .= $chunk;
return '';
});
fwrite($stream, 'hello');
fwrite($stream, 'world');
fclose($stream);
$this->assertEquals('hello world !', $buffered);
}
public function testAppendEndEventWillBeCalledOnRemove()
{
$stream = $this->createStream();
$ended = false;
$filter = StreamFilter\append($stream, function ($chunk = null) use (&$ended) {
if ($chunk === null) {
$ended = true;
}
return $chunk;
}, STREAM_FILTER_WRITE);
$this->assertEquals(0, $ended);
StreamFilter\remove($filter);
$this->assertEquals(1, $ended);
}
public function testAppendEndEventWillBeCalledOnClose()
{
$stream = $this->createStream();
$ended = false;
StreamFilter\append($stream, function ($chunk = null) use (&$ended) {
if ($chunk === null) {
$ended = true;
}
return $chunk;
}, STREAM_FILTER_WRITE);
$this->assertEquals(0, $ended);
fclose($stream);
$this->assertEquals(1, $ended);
}
public function testAppendWriteOnly()
{
$stream = $this->createStream();
$invoked = 0;
StreamFilter\append($stream, function ($chunk) use (&$invoked) {
++$invoked;
return $chunk;
}, STREAM_FILTER_WRITE);
fwrite($stream, 'a');
fwrite($stream, 'b');
fwrite($stream, 'c');
rewind($stream);
$this->assertEquals(3, $invoked);
$this->assertEquals('abc', stream_get_contents($stream));
fclose($stream);
}
public function testAppendReadOnly()
{
$stream = $this->createStream();
$invoked = 0;
StreamFilter\append($stream, function ($chunk) use (&$invoked) {
++$invoked;
return $chunk;
}, STREAM_FILTER_READ);
fwrite($stream, 'a');
fwrite($stream, 'b');
fwrite($stream, 'c');
rewind($stream);
$this->assertEquals(0, $invoked);
$this->assertEquals('abc', stream_get_contents($stream));
$this->assertEquals(1, $invoked);
fclose($stream);
}
public function testOrderCallingAppendAfterPrepend()
{
$stream = $this->createStream();
StreamFilter\append($stream, function ($chunk) {
return '[' . $chunk . ']';
}, STREAM_FILTER_WRITE);
StreamFilter\prepend($stream, function ($chunk) {
return '(' . $chunk . ')';
}, STREAM_FILTER_WRITE);
fwrite($stream, 'hello');
rewind($stream);
$this->assertEquals('[(hello)]', stream_get_contents($stream));
fclose($stream);
}
public function testRemoveFilter()
{
$stream = $this->createStream();
$first = StreamFilter\append($stream, function ($chunk) {
return $chunk . '?';
}, STREAM_FILTER_WRITE);
StreamFilter\append($stream, function ($chunk) {
return $chunk . '!';
}, STREAM_FILTER_WRITE);
StreamFilter\remove($first);
fwrite($stream, 'hello');
rewind($stream);
$this->assertEquals('hello!', stream_get_contents($stream));
fclose($stream);
}
public function testAppendFunDechunk()
{
if (defined('HHVM_VERSION')) $this->markTestSkipped('Not supported on HHVM (dechunk filter does not exist)');
$stream = $this->createStream();
StreamFilter\append($stream, StreamFilter\fun('dechunk'), STREAM_FILTER_WRITE);
fwrite($stream, "2\r\nhe\r\n");
fwrite($stream, "3\r\nllo\r\n");
fwrite($stream, "0\r\n\r\n");
rewind($stream);
$this->assertEquals('hello', stream_get_contents($stream));
fclose($stream);
}
public function testAppendThrows()
{
$this->createErrorHandler($errors);
$stream = $this->createStream();
$this->createErrorHandler($errors);
StreamFilter\append($stream, function ($chunk) {
throw new \DomainException($chunk);
});
fwrite($stream, 'test');
$this->removeErrorHandler();
$this->assertCount(1, $errors);
$this->assertContains('test', $errors[0]);
}
public function testAppendThrowsDuringEnd()
{
$stream = $this->createStream();
$this->createErrorHandler($errors);
StreamFilter\append($stream, function ($chunk = null) {
if ($chunk === null) {
throw new \DomainException('end');
}
return $chunk;
});
fclose($stream);
$this->removeErrorHandler();
// We can only assert we're not seeing an exception here…
// * php 5.3-5.6 sees one error here
// * php 7 does not see any error here
// * hhvm sees the same error twice
//
// If you're curious:
//
// var_dump($errors);
// $this->assertCount(1, $errors);
// $this->assertContains('end', $errors[0]);
}
public function testAppendThrowsShouldTriggerEnd()
{
$stream = $this->createStream();
$this->createErrorHandler($errors);
$ended = false;
StreamFilter\append($stream, function ($chunk = null) use (&$ended) {
if ($chunk === null) {
$ended = true;
return '';
}
throw new \DomainException($chunk);
});
$this->assertEquals(false, $ended);
fwrite($stream, 'test');
$this->assertEquals(true, $ended);
$this->removeErrorHandler();
$this->assertCount(1, $errors);
$this->assertContains('test', $errors[0]);
}
public function testAppendThrowsShouldTriggerEndButIgnoreExceptionDuringEnd()
{
//$this->markTestIncomplete();
$stream = $this->createStream();
$this->createErrorHandler($errors);
StreamFilter\append($stream, function ($chunk = null) {
if ($chunk === null) {
$chunk = 'end';
//return '';
}
throw new \DomainException($chunk);
});
fwrite($stream, 'test');
$this->removeErrorHandler();
$this->assertCount(1, $errors);
$this->assertContains('test', $errors[0]);
}
/**
* @expectedException RuntimeException
*/
public function testAppendInvalidStreamIsRuntimeError()
{
if (defined('HHVM_VERSION')) $this->markTestSkipped('Not supported on HHVM (does not reject invalid stream)');
StreamFilter\append(false, function () { });
}
/**
* @expectedException RuntimeException
*/
public function testPrependInvalidStreamIsRuntimeError()
{
if (defined('HHVM_VERSION')) $this->markTestSkipped('Not supported on HHVM (does not reject invalid stream)');
StreamFilter\prepend(false, function () { });
}
/**
* @expectedException RuntimeException
*/
public function testRemoveInvalidFilterIsRuntimeError()
{
if (defined('HHVM_VERSION')) $this->markTestSkipped('Not supported on HHVM (does not reject invalid filters)');
StreamFilter\remove(false);
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidCallbackIsInvalidArgument()
{
$stream = $this->createStream();
StreamFilter\append($stream, 'a-b-c');
}
private function createStream()
{
return fopen('php://memory', 'r+');
}
private function createErrorHandler(&$errors)
{
$errors = array();
set_error_handler(function ($_, $message) use (&$errors) {
$errors []= $message;
});
}
private function removeErrorHandler()
{
restore_error_handler();
}
}

View File

@ -0,0 +1,61 @@
<?php
use Clue\StreamFilter as Filter;
class FunTest extends PHPUnit_Framework_TestCase
{
public function testFunInRot13()
{
$rot = Filter\fun('string.rot13');
$this->assertEquals('grfg', $rot('test'));
$this->assertEquals('test', $rot($rot('test')));
$this->assertEquals(null, $rot());
}
public function testFunInQuotedPrintable()
{
$encode = Filter\fun('convert.quoted-printable-encode');
$decode = Filter\fun('convert.quoted-printable-decode');
$this->assertEquals('t=C3=A4st', $encode('täst'));
$this->assertEquals('täst', $decode($encode('täst')));
$this->assertEquals(null, $encode());
}
/**
* @expectedException RuntimeException
*/
public function testFunWriteAfterCloseRot13()
{
$rot = Filter\fun('string.rot13');
$this->assertEquals(null, $rot());
$rot('test');
}
/**
* @expectedException RuntimeException
*/
public function testFunInvalid()
{
Filter\fun('unknown');
}
public function testFunInBase64()
{
$encode = Filter\fun('convert.base64-encode');
$decode = Filter\fun('convert.base64-decode');
$string = 'test';
$this->assertEquals(base64_encode($string), $encode($string) . $encode());
$this->assertEquals($string, $decode(base64_encode($string)));
$encode = Filter\fun('convert.base64-encode');
$decode = Filter\fun('convert.base64-decode');
$this->assertEquals($string, $decode($encode($string) . $encode()));
$encode = Filter\fun('convert.base64-encode');
$this->assertEquals(null, $encode());
}
}

View File

@ -0,0 +1,79 @@
<?php
use Clue\StreamFilter;
class BuiltInZlibTest extends PHPUnit_Framework_TestCase
{
public function testFunZlibDeflateHelloWorld()
{
$deflate = StreamFilter\fun('zlib.deflate');
$data = $deflate('hello') . $deflate(' ') . $deflate('world') . $deflate();
$this->assertEquals(gzdeflate('hello world'), $data);
}
public function testFunZlibDeflateEmpty()
{
if (PHP_VERSION >= 7) $this->markTestSkipped('Not supported on PHP7 (empty string does not invoke filter)');
$deflate = StreamFilter\fun('zlib.deflate');
//$data = gzdeflate('');
$data = $deflate();
$this->assertEquals("\x03\x00", $data);
}
public function testFunZlibDeflateBig()
{
$deflate = StreamFilter\fun('zlib.deflate');
$n = 1000;
$expected = str_repeat('hello', $n);
$bytes = '';
for ($i = 0; $i < $n; ++$i) {
$bytes .= $deflate('hello');
}
$bytes .= $deflate();
$this->assertEquals($expected, gzinflate($bytes));
}
public function testFunZlibInflateHelloWorld()
{
$inflate = StreamFilter\fun('zlib.inflate');
$data = $inflate(gzdeflate('hello world')) . $inflate();
$this->assertEquals('hello world', $data);
}
public function testFunZlibInflateEmpty()
{
$inflate = StreamFilter\fun('zlib.inflate');
$data = $inflate("\x03\x00") . $inflate();
$this->assertEquals('', $data);
}
public function testFunZlibInflateBig()
{
if (defined('HHVM_VERSION')) $this->markTestSkipped('Not supported on HHVM (final chunk will not be emitted)');
$inflate = StreamFilter\fun('zlib.inflate');
$expected = str_repeat('hello', 10);
$bytes = gzdeflate($expected);
$ret = '';
foreach (str_split($bytes, 2) as $chunk) {
$ret .= $inflate($chunk);
}
$ret .= $inflate();
$this->assertEquals($expected, $ret);
}
}

View File

@ -53,8 +53,9 @@ class ClassLoader
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;
public function getPrefixes()
{
@ -271,6 +272,26 @@ class ClassLoader
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
@ -313,29 +334,34 @@ class ClassLoader
*/
public function findFile($class)
{
// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
if ('\\' == $class[0]) {
$class = substr($class, 1);
}
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative) {
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if ($file === null && defined('HHVM_VERSION')) {
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if ($file === null) {
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
return $this->classMap[$class] = false;
$this->missingClasses[$class] = true;
}
return $file;
@ -348,10 +374,14 @@ class ClassLoader
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) {
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
@ -399,6 +429,8 @@ class ClassLoader
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}

View File

@ -1,5 +1,5 @@
Copyright (c) 2016 Nils Adermann, Jordi Boggiano
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -6,350 +6,4 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'File_Iterator' => $vendorDir . '/phpunit/php-file-iterator/src/Iterator.php',
'File_Iterator_Facade' => $vendorDir . '/phpunit/php-file-iterator/src/Facade.php',
'File_Iterator_Factory' => $vendorDir . '/phpunit/php-file-iterator/src/Factory.php',
'PHPUnit_Extensions_GroupTestSuite' => $vendorDir . '/phpunit/phpunit/PHPUnit/Extensions/GroupTestSuite.php',
'PHPUnit_Extensions_PhptTestCase' => $vendorDir . '/phpunit/phpunit/PHPUnit/Extensions/PhptTestCase.php',
'PHPUnit_Extensions_PhptTestCase_Logger' => $vendorDir . '/phpunit/phpunit/PHPUnit/Extensions/PhptTestCase/Logger.php',
'PHPUnit_Extensions_PhptTestSuite' => $vendorDir . '/phpunit/phpunit/PHPUnit/Extensions/PhptTestSuite.php',
'PHPUnit_Extensions_RepeatedTest' => $vendorDir . '/phpunit/phpunit/PHPUnit/Extensions/RepeatedTest.php',
'PHPUnit_Extensions_TestDecorator' => $vendorDir . '/phpunit/phpunit/PHPUnit/Extensions/TestDecorator.php',
'PHPUnit_Extensions_TicketListener' => $vendorDir . '/phpunit/phpunit/PHPUnit/Extensions/TicketListener.php',
'PHPUnit_Framework_Assert' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Assert.php',
'PHPUnit_Framework_AssertionFailedError' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/AssertionFailedError.php',
'PHPUnit_Framework_Comparator' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Comparator.php',
'PHPUnit_Framework_ComparatorFactory' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/ComparatorFactory.php',
'PHPUnit_Framework_Comparator_Array' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Array.php',
'PHPUnit_Framework_Comparator_DOMDocument' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Comparator/DOMDocument.php',
'PHPUnit_Framework_Comparator_Double' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Double.php',
'PHPUnit_Framework_Comparator_Exception' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Exception.php',
'PHPUnit_Framework_Comparator_MockObject' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Comparator/MockObject.php',
'PHPUnit_Framework_Comparator_Numeric' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Numeric.php',
'PHPUnit_Framework_Comparator_Object' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Object.php',
'PHPUnit_Framework_Comparator_Resource' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Resource.php',
'PHPUnit_Framework_Comparator_Scalar' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Scalar.php',
'PHPUnit_Framework_Comparator_SplObjectStorage' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Comparator/SplObjectStorage.php',
'PHPUnit_Framework_Comparator_Type' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Type.php',
'PHPUnit_Framework_ComparisonFailure' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/ComparisonFailure.php',
'PHPUnit_Framework_Constraint' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint.php',
'PHPUnit_Framework_Constraint_And' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/And.php',
'PHPUnit_Framework_Constraint_ArrayHasKey' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/ArrayHasKey.php',
'PHPUnit_Framework_Constraint_Attribute' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Attribute.php',
'PHPUnit_Framework_Constraint_Callback' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Callback.php',
'PHPUnit_Framework_Constraint_ClassHasAttribute' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/ClassHasAttribute.php',
'PHPUnit_Framework_Constraint_ClassHasStaticAttribute' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/ClassHasStaticAttribute.php',
'PHPUnit_Framework_Constraint_Composite' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Composite.php',
'PHPUnit_Framework_Constraint_Count' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Count.php',
'PHPUnit_Framework_Constraint_Exception' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Exception.php',
'PHPUnit_Framework_Constraint_ExceptionCode' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/ExceptionCode.php',
'PHPUnit_Framework_Constraint_ExceptionMessage' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/ExceptionMessage.php',
'PHPUnit_Framework_Constraint_FileExists' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/FileExists.php',
'PHPUnit_Framework_Constraint_GreaterThan' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/GreaterThan.php',
'PHPUnit_Framework_Constraint_IsAnything' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsAnything.php',
'PHPUnit_Framework_Constraint_IsEmpty' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsEmpty.php',
'PHPUnit_Framework_Constraint_IsEqual' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsEqual.php',
'PHPUnit_Framework_Constraint_IsFalse' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsFalse.php',
'PHPUnit_Framework_Constraint_IsIdentical' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsIdentical.php',
'PHPUnit_Framework_Constraint_IsInstanceOf' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsInstanceOf.php',
'PHPUnit_Framework_Constraint_IsJson' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsJson.php',
'PHPUnit_Framework_Constraint_IsNull' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsNull.php',
'PHPUnit_Framework_Constraint_IsTrue' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsTrue.php',
'PHPUnit_Framework_Constraint_IsType' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsType.php',
'PHPUnit_Framework_Constraint_JsonMatches' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/JsonMatches.php',
'PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/JsonMatches/ErrorMessageProvider.php',
'PHPUnit_Framework_Constraint_LessThan' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/LessThan.php',
'PHPUnit_Framework_Constraint_Not' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Not.php',
'PHPUnit_Framework_Constraint_ObjectHasAttribute' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/ObjectHasAttribute.php',
'PHPUnit_Framework_Constraint_Or' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Or.php',
'PHPUnit_Framework_Constraint_PCREMatch' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/PCREMatch.php',
'PHPUnit_Framework_Constraint_SameSize' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/SameSize.php',
'PHPUnit_Framework_Constraint_StringContains' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/StringContains.php',
'PHPUnit_Framework_Constraint_StringEndsWith' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/StringEndsWith.php',
'PHPUnit_Framework_Constraint_StringMatches' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/StringMatches.php',
'PHPUnit_Framework_Constraint_StringStartsWith' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/StringStartsWith.php',
'PHPUnit_Framework_Constraint_TraversableContains' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/TraversableContains.php',
'PHPUnit_Framework_Constraint_TraversableContainsOnly' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/TraversableContainsOnly.php',
'PHPUnit_Framework_Constraint_Xor' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Xor.php',
'PHPUnit_Framework_Error' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Error.php',
'PHPUnit_Framework_Error_Deprecated' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Error/Deprecated.php',
'PHPUnit_Framework_Error_Notice' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Error/Notice.php',
'PHPUnit_Framework_Error_Warning' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Error/Warning.php',
'PHPUnit_Framework_Exception' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Exception.php',
'PHPUnit_Framework_ExpectationFailedException' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/ExpectationFailedException.php',
'PHPUnit_Framework_IncompleteTest' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/IncompleteTest.php',
'PHPUnit_Framework_IncompleteTestError' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/IncompleteTestError.php',
'PHPUnit_Framework_MockObject_Builder_Identity' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Builder/Identity.php',
'PHPUnit_Framework_MockObject_Builder_InvocationMocker' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Builder/InvocationMocker.php',
'PHPUnit_Framework_MockObject_Builder_Match' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Builder/Match.php',
'PHPUnit_Framework_MockObject_Builder_MethodNameMatch' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Builder/MethodNameMatch.php',
'PHPUnit_Framework_MockObject_Builder_Namespace' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Builder/Namespace.php',
'PHPUnit_Framework_MockObject_Builder_ParametersMatch' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Builder/ParametersMatch.php',
'PHPUnit_Framework_MockObject_Builder_Stub' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Builder/Stub.php',
'PHPUnit_Framework_MockObject_Generator' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Generator.php',
'PHPUnit_Framework_MockObject_Invocation' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Invocation.php',
'PHPUnit_Framework_MockObject_InvocationMocker' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/InvocationMocker.php',
'PHPUnit_Framework_MockObject_Invocation_Object' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Invocation/Object.php',
'PHPUnit_Framework_MockObject_Invocation_Static' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Invocation/Static.php',
'PHPUnit_Framework_MockObject_Invokable' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Invokable.php',
'PHPUnit_Framework_MockObject_Matcher' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher.php',
'PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/AnyInvokedCount.php',
'PHPUnit_Framework_MockObject_Matcher_AnyParameters' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/AnyParameters.php',
'PHPUnit_Framework_MockObject_Matcher_Invocation' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/Invocation.php',
'PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/InvokedAtIndex.php',
'PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/InvokedAtLeastOnce.php',
'PHPUnit_Framework_MockObject_Matcher_InvokedCount' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/InvokedCount.php',
'PHPUnit_Framework_MockObject_Matcher_InvokedRecorder' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/InvokedRecorder.php',
'PHPUnit_Framework_MockObject_Matcher_MethodName' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/MethodName.php',
'PHPUnit_Framework_MockObject_Matcher_Parameters' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/Parameters.php',
'PHPUnit_Framework_MockObject_Matcher_StatelessInvocation' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/StatelessInvocation.php',
'PHPUnit_Framework_MockObject_MockBuilder' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/MockBuilder.php',
'PHPUnit_Framework_MockObject_MockObject' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/MockObject.php',
'PHPUnit_Framework_MockObject_Stub' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub.php',
'PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/ConsecutiveCalls.php',
'PHPUnit_Framework_MockObject_Stub_Exception' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/Exception.php',
'PHPUnit_Framework_MockObject_Stub_MatcherCollection' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/MatcherCollection.php',
'PHPUnit_Framework_MockObject_Stub_Return' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/Return.php',
'PHPUnit_Framework_MockObject_Stub_ReturnArgument' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/ReturnArgument.php',
'PHPUnit_Framework_MockObject_Stub_ReturnCallback' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/ReturnCallback.php',
'PHPUnit_Framework_MockObject_Stub_ReturnSelf' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/ReturnSelf.php',
'PHPUnit_Framework_MockObject_Stub_ReturnValueMap' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/ReturnValueMap.php',
'PHPUnit_Framework_MockObject_Verifiable' => $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Verifiable.php',
'PHPUnit_Framework_OutputError' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/OutputError.php',
'PHPUnit_Framework_SelfDescribing' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/SelfDescribing.php',
'PHPUnit_Framework_SkippedTest' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/SkippedTest.php',
'PHPUnit_Framework_SkippedTestError' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/SkippedTestError.php',
'PHPUnit_Framework_SkippedTestSuiteError' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/SkippedTestSuiteError.php',
'PHPUnit_Framework_SyntheticError' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/SyntheticError.php',
'PHPUnit_Framework_Test' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Test.php',
'PHPUnit_Framework_TestCase' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/TestCase.php',
'PHPUnit_Framework_TestFailure' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/TestFailure.php',
'PHPUnit_Framework_TestListener' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/TestListener.php',
'PHPUnit_Framework_TestResult' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/TestResult.php',
'PHPUnit_Framework_TestSuite' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/TestSuite.php',
'PHPUnit_Framework_TestSuite_DataProvider' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/TestSuite/DataProvider.php',
'PHPUnit_Framework_Warning' => $vendorDir . '/phpunit/phpunit/PHPUnit/Framework/Warning.php',
'PHPUnit_Runner_BaseTestRunner' => $vendorDir . '/phpunit/phpunit/PHPUnit/Runner/BaseTestRunner.php',
'PHPUnit_Runner_StandardTestSuiteLoader' => $vendorDir . '/phpunit/phpunit/PHPUnit/Runner/StandardTestSuiteLoader.php',
'PHPUnit_Runner_TestSuiteLoader' => $vendorDir . '/phpunit/phpunit/PHPUnit/Runner/TestSuiteLoader.php',
'PHPUnit_Runner_Version' => $vendorDir . '/phpunit/phpunit/PHPUnit/Runner/Version.php',
'PHPUnit_TextUI_Command' => $vendorDir . '/phpunit/phpunit/PHPUnit/TextUI/Command.php',
'PHPUnit_TextUI_ResultPrinter' => $vendorDir . '/phpunit/phpunit/PHPUnit/TextUI/ResultPrinter.php',
'PHPUnit_TextUI_TestRunner' => $vendorDir . '/phpunit/phpunit/PHPUnit/TextUI/TestRunner.php',
'PHPUnit_Util_Class' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/Class.php',
'PHPUnit_Util_Configuration' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/Configuration.php',
'PHPUnit_Util_DeprecatedFeature' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/DeprecatedFeature.php',
'PHPUnit_Util_DeprecatedFeature_Logger' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/DeprecatedFeature/Logger.php',
'PHPUnit_Util_Diff' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/Diff.php',
'PHPUnit_Util_ErrorHandler' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/ErrorHandler.php',
'PHPUnit_Util_Fileloader' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/Fileloader.php',
'PHPUnit_Util_Filesystem' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/Filesystem.php',
'PHPUnit_Util_Filter' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/Filter.php',
'PHPUnit_Util_Getopt' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/Getopt.php',
'PHPUnit_Util_GlobalState' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/GlobalState.php',
'PHPUnit_Util_InvalidArgumentHelper' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/InvalidArgumentHelper.php',
'PHPUnit_Util_Log_JSON' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/Log/JSON.php',
'PHPUnit_Util_Log_JUnit' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/Log/JUnit.php',
'PHPUnit_Util_Log_TAP' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/Log/TAP.php',
'PHPUnit_Util_PHP' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/PHP.php',
'PHPUnit_Util_PHP_Default' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/PHP/Default.php',
'PHPUnit_Util_PHP_Windows' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/PHP/Windows.php',
'PHPUnit_Util_Printer' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/Printer.php',
'PHPUnit_Util_String' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/String.php',
'PHPUnit_Util_Test' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/Test.php',
'PHPUnit_Util_TestDox_NamePrettifier' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/TestDox/NamePrettifier.php',
'PHPUnit_Util_TestDox_ResultPrinter' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/TestDox/ResultPrinter.php',
'PHPUnit_Util_TestDox_ResultPrinter_HTML' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/TestDox/ResultPrinter/HTML.php',
'PHPUnit_Util_TestDox_ResultPrinter_Text' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/TestDox/ResultPrinter/Text.php',
'PHPUnit_Util_TestSuiteIterator' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/TestSuiteIterator.php',
'PHPUnit_Util_Type' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/Type.php',
'PHPUnit_Util_XML' => $vendorDir . '/phpunit/phpunit/PHPUnit/Util/XML.php',
'PHP_CodeCoverage' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage.php',
'PHP_CodeCoverage_Driver' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Driver.php',
'PHP_CodeCoverage_Driver_Xdebug' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Driver/Xdebug.php',
'PHP_CodeCoverage_Exception' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Exception.php',
'PHP_CodeCoverage_Filter' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Filter.php',
'PHP_CodeCoverage_Report_Clover' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/Clover.php',
'PHP_CodeCoverage_Report_Factory' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/Factory.php',
'PHP_CodeCoverage_Report_HTML' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/HTML.php',
'PHP_CodeCoverage_Report_HTML_Renderer' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/HTML/Renderer.php',
'PHP_CodeCoverage_Report_HTML_Renderer_Dashboard' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/HTML/Renderer/Dashboard.php',
'PHP_CodeCoverage_Report_HTML_Renderer_Directory' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/HTML/Renderer/Directory.php',
'PHP_CodeCoverage_Report_HTML_Renderer_File' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/HTML/Renderer/File.php',
'PHP_CodeCoverage_Report_Node' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/Node.php',
'PHP_CodeCoverage_Report_Node_Directory' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/Node/Directory.php',
'PHP_CodeCoverage_Report_Node_File' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/Node/File.php',
'PHP_CodeCoverage_Report_Node_Iterator' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/Node/Iterator.php',
'PHP_CodeCoverage_Report_PHP' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/PHP.php',
'PHP_CodeCoverage_Report_Text' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/Text.php',
'PHP_CodeCoverage_Util' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Util.php',
'PHP_CodeCoverage_Util_InvalidArgumentHelper' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Util/InvalidArgumentHelper.php',
'PHP_CodeCoverage_Version' => $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Version.php',
'PHP_Timer' => $vendorDir . '/phpunit/php-timer/src/Timer.php',
'PHP_Token' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_TokenWithScope' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_TokenWithScopeAndVisibility' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ABSTRACT' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_AMPERSAND' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_AND_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ARRAY' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ARRAY_CAST' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_AS' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_AT' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_BACKTICK' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_BAD_CHARACTER' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_BOOLEAN_AND' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_BOOLEAN_OR' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_BOOL_CAST' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_BREAK' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CALLABLE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CARET' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CASE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CATCH' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CHARACTER' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLASS' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLASS_C' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLASS_NAME_CONSTANT' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLONE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLOSE_BRACKET' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLOSE_CURLY' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLOSE_SQUARE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLOSE_TAG' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_COLON' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_COMMA' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_COMMENT' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CONCAT_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CONST' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CONSTANT_ENCAPSED_STRING' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CONTINUE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CURLY_OPEN' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DEC' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DECLARE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DEFAULT' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DIR' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DIV' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DIV_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DNUMBER' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DO' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOC_COMMENT' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOLLAR' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOLLAR_OPEN_CURLY_BRACES' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOT' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOUBLE_ARROW' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOUBLE_CAST' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOUBLE_COLON' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOUBLE_QUOTES' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ECHO' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ELSE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ELSEIF' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_EMPTY' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ENCAPSED_AND_WHITESPACE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ENDDECLARE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ENDFOR' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ENDFOREACH' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ENDIF' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ENDSWITCH' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ENDWHILE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_END_HEREDOC' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_EVAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_EXCLAMATION_MARK' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_EXIT' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_EXTENDS' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_FILE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_FINAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_FINALLY' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_FOR' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_FOREACH' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_FUNCTION' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_FUNC_C' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_GLOBAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_GOTO' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_GT' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_HALT_COMPILER' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IF' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IMPLEMENTS' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INC' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INCLUDE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INCLUDE_ONCE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INLINE_HTML' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INSTANCEOF' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INSTEADOF' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INTERFACE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INT_CAST' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ISSET' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IS_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IS_GREATER_OR_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IS_IDENTICAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IS_NOT_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IS_NOT_IDENTICAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IS_SMALLER_OR_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_Includes' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_LINE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_LIST' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_LNUMBER' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_LOGICAL_AND' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_LOGICAL_OR' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_LOGICAL_XOR' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_LT' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_METHOD_C' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_MINUS' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_MINUS_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_MOD_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_MULT' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_MUL_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_NAMESPACE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_NEW' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_NS_C' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_NS_SEPARATOR' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_NUM_STRING' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OBJECT_CAST' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OBJECT_OPERATOR' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OPEN_BRACKET' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OPEN_CURLY' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OPEN_SQUARE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OPEN_TAG' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OPEN_TAG_WITH_ECHO' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OR_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PAAMAYIM_NEKUDOTAYIM' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PERCENT' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PIPE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PLUS' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PLUS_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PRINT' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PRIVATE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PROTECTED' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PUBLIC' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_QUESTION_MARK' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_REQUIRE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_REQUIRE_ONCE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_RETURN' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_SEMICOLON' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_SL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_SL_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_SR' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_SR_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_START_HEREDOC' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_STATIC' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_STRING' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_STRING_CAST' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_STRING_VARNAME' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_SWITCH' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_Stream' => $vendorDir . '/phpunit/php-token-stream/PHP/Token/Stream.php',
'PHP_Token_Stream_CachingFactory' => $vendorDir . '/phpunit/php-token-stream/PHP/Token/Stream/CachingFactory.php',
'PHP_Token_THROW' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_TILDE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_TRAIT' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_TRAIT_C' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_TRY' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_UNSET' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_UNSET_CAST' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_USE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_VAR' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_VARIABLE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_WHILE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_WHITESPACE' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_XOR_EQUAL' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_YIELD' => $vendorDir . '/phpunit/php-token-stream/PHP/Token.php',
'Text_Template' => $vendorDir . '/phpunit/php-text-template/src/Template.php',
);

View File

@ -0,0 +1,14 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
'9c67151ae59aff4788964ce8eb2a0f43' => $vendorDir . '/clue/stream-filter/src/functions_include.php',
'8cff32064859f4559445b89279f3199c' => $vendorDir . '/php-http/message/src/filters.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
);

View File

@ -6,8 +6,5 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Mailgun\\Tests' => array($baseDir . '/tests'),
'Mailgun' => array($baseDir . '/src'),
'Guzzle\\Tests' => array($vendorDir . '/guzzle/guzzle/tests'),
'Guzzle' => array($vendorDir . '/guzzle/guzzle/src'),
'Mailgun' => array($vendorDir . '/mailgun/mailgun-php/src'),
);

View File

@ -6,6 +6,17 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'),
'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'),
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
'Http\\Promise\\' => array($vendorDir . '/php-http/promise/src'),
'Http\\Message\\MultipartStream\\' => array($vendorDir . '/php-http/multipart-stream-builder/src'),
'Http\\Message\\' => array($vendorDir . '/php-http/message/src', $vendorDir . '/php-http/message-factory/src'),
'Http\\Discovery\\' => array($vendorDir . '/php-http/discovery/src'),
'Http\\Client\\Curl\\' => array($vendorDir . '/php-http/curl-client/src'),
'Http\\Client\\Common\\' => array($vendorDir . '/php-http/client-common/src'),
'Http\\Client\\' => array($vendorDir . '/php-http/httplug/src'),
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
'Clue\\StreamFilter\\' => array($vendorDir . '/clue/stream-filter/src'),
);

View File

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit4ddb0bfe747486746b07c9365ebf26f5
class ComposerAutoloaderInit312a1f75dce9c5adc27329538beefb51
{
private static $loader;
@ -19,19 +19,15 @@ class ComposerAutoloaderInit4ddb0bfe747486746b07c9365ebf26f5
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit4ddb0bfe747486746b07c9365ebf26f5', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInit312a1f75dce9c5adc27329538beefb51', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit4ddb0bfe747486746b07c9365ebf26f5', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInit312a1f75dce9c5adc27329538beefb51', 'loadClassLoader'));
$includePaths = require __DIR__ . '/include_paths.php';
array_push($includePaths, get_include_path());
set_include_path(join(PATH_SEPARATOR, $includePaths));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION');
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit4ddb0bfe747486746b07c9365ebf26f5::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInit312a1f75dce9c5adc27329538beefb51::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
@ -51,6 +47,24 @@ class ComposerAutoloaderInit4ddb0bfe747486746b07c9365ebf26f5
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit312a1f75dce9c5adc27329538beefb51::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire312a1f75dce9c5adc27329538beefb51($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire312a1f75dce9c5adc27329538beefb51($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}

View File

@ -4,408 +4,122 @@
namespace Composer\Autoload;
class ComposerStaticInit4ddb0bfe747486746b07c9365ebf26f5
class ComposerStaticInit312a1f75dce9c5adc27329538beefb51
{
public static $files = array (
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
'9c67151ae59aff4788964ce8eb2a0f43' => __DIR__ . '/..' . '/clue/stream-filter/src/functions_include.php',
'8cff32064859f4559445b89279f3199c' => __DIR__ . '/..' . '/php-http/message/src/filters.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
);
public static $prefixLengthsPsr4 = array (
'W' =>
array (
'Webmozart\\Assert\\' => 17,
),
'S' =>
array (
'Symfony\\Component\\Yaml\\' => 23,
'Symfony\\Component\\EventDispatcher\\' => 34,
'Symfony\\Polyfill\\Ctype\\' => 23,
'Symfony\\Component\\OptionsResolver\\' => 34,
),
'P' =>
array (
'Psr\\Http\\Message\\' => 17,
),
'H' =>
array (
'Http\\Promise\\' => 13,
'Http\\Message\\MultipartStream\\' => 29,
'Http\\Message\\' => 13,
'Http\\Discovery\\' => 15,
'Http\\Client\\Curl\\' => 17,
'Http\\Client\\Common\\' => 19,
'Http\\Client\\' => 12,
),
'G' =>
array (
'GuzzleHttp\\Psr7\\' => 16,
),
'C' =>
array (
'Clue\\StreamFilter\\' => 18,
),
);
public static $prefixDirsPsr4 = array (
'Symfony\\Component\\Yaml\\' =>
'Webmozart\\Assert\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/yaml',
0 => __DIR__ . '/..' . '/webmozart/assert/src',
),
'Symfony\\Component\\EventDispatcher\\' =>
'Symfony\\Polyfill\\Ctype\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/event-dispatcher',
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
),
'Symfony\\Component\\OptionsResolver\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/options-resolver',
),
'Psr\\Http\\Message\\' =>
array (
0 => __DIR__ . '/..' . '/psr/http-message/src',
),
'Http\\Promise\\' =>
array (
0 => __DIR__ . '/..' . '/php-http/promise/src',
),
'Http\\Message\\MultipartStream\\' =>
array (
0 => __DIR__ . '/..' . '/php-http/multipart-stream-builder/src',
),
'Http\\Message\\' =>
array (
0 => __DIR__ . '/..' . '/php-http/message/src',
1 => __DIR__ . '/..' . '/php-http/message-factory/src',
),
'Http\\Discovery\\' =>
array (
0 => __DIR__ . '/..' . '/php-http/discovery/src',
),
'Http\\Client\\Curl\\' =>
array (
0 => __DIR__ . '/..' . '/php-http/curl-client/src',
),
'Http\\Client\\Common\\' =>
array (
0 => __DIR__ . '/..' . '/php-http/client-common/src',
),
'Http\\Client\\' =>
array (
0 => __DIR__ . '/..' . '/php-http/httplug/src',
),
'GuzzleHttp\\Psr7\\' =>
array (
0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',
),
'Clue\\StreamFilter\\' =>
array (
0 => __DIR__ . '/..' . '/clue/stream-filter/src',
),
);
public static $prefixesPsr0 = array (
'M' =>
array (
'Mailgun\\Tests' =>
array (
0 => __DIR__ . '/../..' . '/tests',
),
'Mailgun' =>
array (
0 => __DIR__ . '/../..' . '/src',
0 => __DIR__ . '/..' . '/mailgun/mailgun-php/src',
),
),
'G' =>
array (
'Guzzle\\Tests' =>
array (
0 => __DIR__ . '/..' . '/guzzle/guzzle/tests',
),
'Guzzle' =>
array (
0 => __DIR__ . '/..' . '/guzzle/guzzle/src',
),
),
);
public static $classMap = array (
'File_Iterator' => __DIR__ . '/..' . '/phpunit/php-file-iterator/src/Iterator.php',
'File_Iterator_Facade' => __DIR__ . '/..' . '/phpunit/php-file-iterator/src/Facade.php',
'File_Iterator_Factory' => __DIR__ . '/..' . '/phpunit/php-file-iterator/src/Factory.php',
'PHPUnit_Extensions_GroupTestSuite' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Extensions/GroupTestSuite.php',
'PHPUnit_Extensions_PhptTestCase' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Extensions/PhptTestCase.php',
'PHPUnit_Extensions_PhptTestCase_Logger' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Extensions/PhptTestCase/Logger.php',
'PHPUnit_Extensions_PhptTestSuite' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Extensions/PhptTestSuite.php',
'PHPUnit_Extensions_RepeatedTest' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Extensions/RepeatedTest.php',
'PHPUnit_Extensions_TestDecorator' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Extensions/TestDecorator.php',
'PHPUnit_Extensions_TicketListener' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Extensions/TicketListener.php',
'PHPUnit_Framework_Assert' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Assert.php',
'PHPUnit_Framework_AssertionFailedError' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/AssertionFailedError.php',
'PHPUnit_Framework_Comparator' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Comparator.php',
'PHPUnit_Framework_ComparatorFactory' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/ComparatorFactory.php',
'PHPUnit_Framework_Comparator_Array' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Array.php',
'PHPUnit_Framework_Comparator_DOMDocument' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Comparator/DOMDocument.php',
'PHPUnit_Framework_Comparator_Double' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Double.php',
'PHPUnit_Framework_Comparator_Exception' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Exception.php',
'PHPUnit_Framework_Comparator_MockObject' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Comparator/MockObject.php',
'PHPUnit_Framework_Comparator_Numeric' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Numeric.php',
'PHPUnit_Framework_Comparator_Object' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Object.php',
'PHPUnit_Framework_Comparator_Resource' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Resource.php',
'PHPUnit_Framework_Comparator_Scalar' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Scalar.php',
'PHPUnit_Framework_Comparator_SplObjectStorage' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Comparator/SplObjectStorage.php',
'PHPUnit_Framework_Comparator_Type' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Comparator/Type.php',
'PHPUnit_Framework_ComparisonFailure' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/ComparisonFailure.php',
'PHPUnit_Framework_Constraint' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint.php',
'PHPUnit_Framework_Constraint_And' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/And.php',
'PHPUnit_Framework_Constraint_ArrayHasKey' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/ArrayHasKey.php',
'PHPUnit_Framework_Constraint_Attribute' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Attribute.php',
'PHPUnit_Framework_Constraint_Callback' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Callback.php',
'PHPUnit_Framework_Constraint_ClassHasAttribute' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/ClassHasAttribute.php',
'PHPUnit_Framework_Constraint_ClassHasStaticAttribute' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/ClassHasStaticAttribute.php',
'PHPUnit_Framework_Constraint_Composite' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Composite.php',
'PHPUnit_Framework_Constraint_Count' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Count.php',
'PHPUnit_Framework_Constraint_Exception' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Exception.php',
'PHPUnit_Framework_Constraint_ExceptionCode' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/ExceptionCode.php',
'PHPUnit_Framework_Constraint_ExceptionMessage' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/ExceptionMessage.php',
'PHPUnit_Framework_Constraint_FileExists' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/FileExists.php',
'PHPUnit_Framework_Constraint_GreaterThan' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/GreaterThan.php',
'PHPUnit_Framework_Constraint_IsAnything' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsAnything.php',
'PHPUnit_Framework_Constraint_IsEmpty' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsEmpty.php',
'PHPUnit_Framework_Constraint_IsEqual' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsEqual.php',
'PHPUnit_Framework_Constraint_IsFalse' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsFalse.php',
'PHPUnit_Framework_Constraint_IsIdentical' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsIdentical.php',
'PHPUnit_Framework_Constraint_IsInstanceOf' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsInstanceOf.php',
'PHPUnit_Framework_Constraint_IsJson' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsJson.php',
'PHPUnit_Framework_Constraint_IsNull' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsNull.php',
'PHPUnit_Framework_Constraint_IsTrue' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsTrue.php',
'PHPUnit_Framework_Constraint_IsType' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/IsType.php',
'PHPUnit_Framework_Constraint_JsonMatches' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/JsonMatches.php',
'PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/JsonMatches/ErrorMessageProvider.php',
'PHPUnit_Framework_Constraint_LessThan' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/LessThan.php',
'PHPUnit_Framework_Constraint_Not' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Not.php',
'PHPUnit_Framework_Constraint_ObjectHasAttribute' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/ObjectHasAttribute.php',
'PHPUnit_Framework_Constraint_Or' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Or.php',
'PHPUnit_Framework_Constraint_PCREMatch' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/PCREMatch.php',
'PHPUnit_Framework_Constraint_SameSize' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/SameSize.php',
'PHPUnit_Framework_Constraint_StringContains' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/StringContains.php',
'PHPUnit_Framework_Constraint_StringEndsWith' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/StringEndsWith.php',
'PHPUnit_Framework_Constraint_StringMatches' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/StringMatches.php',
'PHPUnit_Framework_Constraint_StringStartsWith' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/StringStartsWith.php',
'PHPUnit_Framework_Constraint_TraversableContains' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/TraversableContains.php',
'PHPUnit_Framework_Constraint_TraversableContainsOnly' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/TraversableContainsOnly.php',
'PHPUnit_Framework_Constraint_Xor' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Constraint/Xor.php',
'PHPUnit_Framework_Error' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Error.php',
'PHPUnit_Framework_Error_Deprecated' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Error/Deprecated.php',
'PHPUnit_Framework_Error_Notice' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Error/Notice.php',
'PHPUnit_Framework_Error_Warning' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Error/Warning.php',
'PHPUnit_Framework_Exception' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Exception.php',
'PHPUnit_Framework_ExpectationFailedException' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/ExpectationFailedException.php',
'PHPUnit_Framework_IncompleteTest' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/IncompleteTest.php',
'PHPUnit_Framework_IncompleteTestError' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/IncompleteTestError.php',
'PHPUnit_Framework_MockObject_Builder_Identity' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Builder/Identity.php',
'PHPUnit_Framework_MockObject_Builder_InvocationMocker' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Builder/InvocationMocker.php',
'PHPUnit_Framework_MockObject_Builder_Match' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Builder/Match.php',
'PHPUnit_Framework_MockObject_Builder_MethodNameMatch' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Builder/MethodNameMatch.php',
'PHPUnit_Framework_MockObject_Builder_Namespace' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Builder/Namespace.php',
'PHPUnit_Framework_MockObject_Builder_ParametersMatch' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Builder/ParametersMatch.php',
'PHPUnit_Framework_MockObject_Builder_Stub' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Builder/Stub.php',
'PHPUnit_Framework_MockObject_Generator' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Generator.php',
'PHPUnit_Framework_MockObject_Invocation' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Invocation.php',
'PHPUnit_Framework_MockObject_InvocationMocker' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/InvocationMocker.php',
'PHPUnit_Framework_MockObject_Invocation_Object' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Invocation/Object.php',
'PHPUnit_Framework_MockObject_Invocation_Static' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Invocation/Static.php',
'PHPUnit_Framework_MockObject_Invokable' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Invokable.php',
'PHPUnit_Framework_MockObject_Matcher' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher.php',
'PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/AnyInvokedCount.php',
'PHPUnit_Framework_MockObject_Matcher_AnyParameters' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/AnyParameters.php',
'PHPUnit_Framework_MockObject_Matcher_Invocation' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/Invocation.php',
'PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/InvokedAtIndex.php',
'PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/InvokedAtLeastOnce.php',
'PHPUnit_Framework_MockObject_Matcher_InvokedCount' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/InvokedCount.php',
'PHPUnit_Framework_MockObject_Matcher_InvokedRecorder' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/InvokedRecorder.php',
'PHPUnit_Framework_MockObject_Matcher_MethodName' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/MethodName.php',
'PHPUnit_Framework_MockObject_Matcher_Parameters' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/Parameters.php',
'PHPUnit_Framework_MockObject_Matcher_StatelessInvocation' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Matcher/StatelessInvocation.php',
'PHPUnit_Framework_MockObject_MockBuilder' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/MockBuilder.php',
'PHPUnit_Framework_MockObject_MockObject' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/MockObject.php',
'PHPUnit_Framework_MockObject_Stub' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub.php',
'PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/ConsecutiveCalls.php',
'PHPUnit_Framework_MockObject_Stub_Exception' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/Exception.php',
'PHPUnit_Framework_MockObject_Stub_MatcherCollection' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/MatcherCollection.php',
'PHPUnit_Framework_MockObject_Stub_Return' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/Return.php',
'PHPUnit_Framework_MockObject_Stub_ReturnArgument' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/ReturnArgument.php',
'PHPUnit_Framework_MockObject_Stub_ReturnCallback' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/ReturnCallback.php',
'PHPUnit_Framework_MockObject_Stub_ReturnSelf' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/ReturnSelf.php',
'PHPUnit_Framework_MockObject_Stub_ReturnValueMap' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Stub/ReturnValueMap.php',
'PHPUnit_Framework_MockObject_Verifiable' => __DIR__ . '/..' . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Verifiable.php',
'PHPUnit_Framework_OutputError' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/OutputError.php',
'PHPUnit_Framework_SelfDescribing' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/SelfDescribing.php',
'PHPUnit_Framework_SkippedTest' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/SkippedTest.php',
'PHPUnit_Framework_SkippedTestError' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/SkippedTestError.php',
'PHPUnit_Framework_SkippedTestSuiteError' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/SkippedTestSuiteError.php',
'PHPUnit_Framework_SyntheticError' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/SyntheticError.php',
'PHPUnit_Framework_Test' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Test.php',
'PHPUnit_Framework_TestCase' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/TestCase.php',
'PHPUnit_Framework_TestFailure' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/TestFailure.php',
'PHPUnit_Framework_TestListener' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/TestListener.php',
'PHPUnit_Framework_TestResult' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/TestResult.php',
'PHPUnit_Framework_TestSuite' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/TestSuite.php',
'PHPUnit_Framework_TestSuite_DataProvider' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/TestSuite/DataProvider.php',
'PHPUnit_Framework_Warning' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Framework/Warning.php',
'PHPUnit_Runner_BaseTestRunner' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Runner/BaseTestRunner.php',
'PHPUnit_Runner_StandardTestSuiteLoader' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Runner/StandardTestSuiteLoader.php',
'PHPUnit_Runner_TestSuiteLoader' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Runner/TestSuiteLoader.php',
'PHPUnit_Runner_Version' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Runner/Version.php',
'PHPUnit_TextUI_Command' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/TextUI/Command.php',
'PHPUnit_TextUI_ResultPrinter' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/TextUI/ResultPrinter.php',
'PHPUnit_TextUI_TestRunner' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/TextUI/TestRunner.php',
'PHPUnit_Util_Class' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/Class.php',
'PHPUnit_Util_Configuration' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/Configuration.php',
'PHPUnit_Util_DeprecatedFeature' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/DeprecatedFeature.php',
'PHPUnit_Util_DeprecatedFeature_Logger' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/DeprecatedFeature/Logger.php',
'PHPUnit_Util_Diff' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/Diff.php',
'PHPUnit_Util_ErrorHandler' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/ErrorHandler.php',
'PHPUnit_Util_Fileloader' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/Fileloader.php',
'PHPUnit_Util_Filesystem' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/Filesystem.php',
'PHPUnit_Util_Filter' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/Filter.php',
'PHPUnit_Util_Getopt' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/Getopt.php',
'PHPUnit_Util_GlobalState' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/GlobalState.php',
'PHPUnit_Util_InvalidArgumentHelper' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/InvalidArgumentHelper.php',
'PHPUnit_Util_Log_JSON' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/Log/JSON.php',
'PHPUnit_Util_Log_JUnit' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/Log/JUnit.php',
'PHPUnit_Util_Log_TAP' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/Log/TAP.php',
'PHPUnit_Util_PHP' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/PHP.php',
'PHPUnit_Util_PHP_Default' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/PHP/Default.php',
'PHPUnit_Util_PHP_Windows' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/PHP/Windows.php',
'PHPUnit_Util_Printer' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/Printer.php',
'PHPUnit_Util_String' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/String.php',
'PHPUnit_Util_Test' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/Test.php',
'PHPUnit_Util_TestDox_NamePrettifier' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/TestDox/NamePrettifier.php',
'PHPUnit_Util_TestDox_ResultPrinter' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/TestDox/ResultPrinter.php',
'PHPUnit_Util_TestDox_ResultPrinter_HTML' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/TestDox/ResultPrinter/HTML.php',
'PHPUnit_Util_TestDox_ResultPrinter_Text' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/TestDox/ResultPrinter/Text.php',
'PHPUnit_Util_TestSuiteIterator' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/TestSuiteIterator.php',
'PHPUnit_Util_Type' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/Type.php',
'PHPUnit_Util_XML' => __DIR__ . '/..' . '/phpunit/phpunit/PHPUnit/Util/XML.php',
'PHP_CodeCoverage' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage.php',
'PHP_CodeCoverage_Driver' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Driver.php',
'PHP_CodeCoverage_Driver_Xdebug' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Driver/Xdebug.php',
'PHP_CodeCoverage_Exception' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Exception.php',
'PHP_CodeCoverage_Filter' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Filter.php',
'PHP_CodeCoverage_Report_Clover' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/Clover.php',
'PHP_CodeCoverage_Report_Factory' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/Factory.php',
'PHP_CodeCoverage_Report_HTML' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/HTML.php',
'PHP_CodeCoverage_Report_HTML_Renderer' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/HTML/Renderer.php',
'PHP_CodeCoverage_Report_HTML_Renderer_Dashboard' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/HTML/Renderer/Dashboard.php',
'PHP_CodeCoverage_Report_HTML_Renderer_Directory' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/HTML/Renderer/Directory.php',
'PHP_CodeCoverage_Report_HTML_Renderer_File' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/HTML/Renderer/File.php',
'PHP_CodeCoverage_Report_Node' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/Node.php',
'PHP_CodeCoverage_Report_Node_Directory' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/Node/Directory.php',
'PHP_CodeCoverage_Report_Node_File' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/Node/File.php',
'PHP_CodeCoverage_Report_Node_Iterator' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/Node/Iterator.php',
'PHP_CodeCoverage_Report_PHP' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/PHP.php',
'PHP_CodeCoverage_Report_Text' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Report/Text.php',
'PHP_CodeCoverage_Util' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Util.php',
'PHP_CodeCoverage_Util_InvalidArgumentHelper' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Util/InvalidArgumentHelper.php',
'PHP_CodeCoverage_Version' => __DIR__ . '/..' . '/phpunit/php-code-coverage/PHP/CodeCoverage/Version.php',
'PHP_Timer' => __DIR__ . '/..' . '/phpunit/php-timer/src/Timer.php',
'PHP_Token' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_TokenWithScope' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_TokenWithScopeAndVisibility' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ABSTRACT' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_AMPERSAND' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_AND_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ARRAY' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ARRAY_CAST' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_AS' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_AT' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_BACKTICK' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_BAD_CHARACTER' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_BOOLEAN_AND' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_BOOLEAN_OR' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_BOOL_CAST' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_BREAK' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CALLABLE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CARET' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CASE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CATCH' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CHARACTER' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLASS' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLASS_C' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLASS_NAME_CONSTANT' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLONE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLOSE_BRACKET' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLOSE_CURLY' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLOSE_SQUARE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CLOSE_TAG' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_COLON' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_COMMA' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_COMMENT' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CONCAT_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CONST' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CONSTANT_ENCAPSED_STRING' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CONTINUE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_CURLY_OPEN' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DEC' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DECLARE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DEFAULT' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DIR' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DIV' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DIV_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DNUMBER' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DO' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOC_COMMENT' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOLLAR' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOLLAR_OPEN_CURLY_BRACES' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOT' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOUBLE_ARROW' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOUBLE_CAST' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOUBLE_COLON' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_DOUBLE_QUOTES' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ECHO' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ELSE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ELSEIF' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_EMPTY' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ENCAPSED_AND_WHITESPACE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ENDDECLARE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ENDFOR' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ENDFOREACH' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ENDIF' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ENDSWITCH' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ENDWHILE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_END_HEREDOC' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_EVAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_EXCLAMATION_MARK' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_EXIT' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_EXTENDS' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_FILE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_FINAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_FINALLY' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_FOR' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_FOREACH' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_FUNCTION' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_FUNC_C' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_GLOBAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_GOTO' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_GT' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_HALT_COMPILER' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IF' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IMPLEMENTS' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INC' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INCLUDE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INCLUDE_ONCE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INLINE_HTML' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INSTANCEOF' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INSTEADOF' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INTERFACE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_INT_CAST' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_ISSET' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IS_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IS_GREATER_OR_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IS_IDENTICAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IS_NOT_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IS_NOT_IDENTICAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_IS_SMALLER_OR_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_Includes' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_LINE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_LIST' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_LNUMBER' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_LOGICAL_AND' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_LOGICAL_OR' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_LOGICAL_XOR' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_LT' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_METHOD_C' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_MINUS' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_MINUS_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_MOD_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_MULT' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_MUL_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_NAMESPACE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_NEW' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_NS_C' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_NS_SEPARATOR' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_NUM_STRING' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OBJECT_CAST' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OBJECT_OPERATOR' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OPEN_BRACKET' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OPEN_CURLY' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OPEN_SQUARE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OPEN_TAG' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OPEN_TAG_WITH_ECHO' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_OR_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PAAMAYIM_NEKUDOTAYIM' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PERCENT' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PIPE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PLUS' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PLUS_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PRINT' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PRIVATE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PROTECTED' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_PUBLIC' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_QUESTION_MARK' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_REQUIRE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_REQUIRE_ONCE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_RETURN' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_SEMICOLON' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_SL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_SL_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_SR' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_SR_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_START_HEREDOC' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_STATIC' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_STRING' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_STRING_CAST' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_STRING_VARNAME' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_SWITCH' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_Stream' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token/Stream.php',
'PHP_Token_Stream_CachingFactory' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token/Stream/CachingFactory.php',
'PHP_Token_THROW' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_TILDE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_TRAIT' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_TRAIT_C' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_TRY' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_UNSET' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_UNSET_CAST' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_USE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_VAR' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_VARIABLE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_WHILE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_WHITESPACE' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_XOR_EQUAL' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'PHP_Token_YIELD' => __DIR__ . '/..' . '/phpunit/php-token-stream/PHP/Token.php',
'Text_Template' => __DIR__ . '/..' . '/phpunit/php-text-template/src/Template.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit4ddb0bfe747486746b07c9365ebf26f5::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit4ddb0bfe747486746b07c9365ebf26f5::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInit4ddb0bfe747486746b07c9365ebf26f5::$prefixesPsr0;
$loader->classMap = ComposerStaticInit4ddb0bfe747486746b07c9365ebf26f5::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInit312a1f75dce9c5adc27329538beefb51::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit312a1f75dce9c5adc27329538beefb51::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInit312a1f75dce9c5adc27329538beefb51::$prefixesPsr0;
}, null, ClassLoader::class);
}

View File

@ -1,14 +0,0 @@
<?php
// include_paths.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
$vendorDir . '/phpunit/phpunit-mock-objects',
$vendorDir . '/phpunit/php-token-stream',
$vendorDir . '/phpunit/php-code-coverage',
$vendorDir . '/phpunit/phpunit',
$vendorDir . '/symfony/yaml',
);

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +0,0 @@
# Ingore common cruft
.DS_STORE
coverage
.idea
# Ignore binary files
guzzle.phar
guzzle-min.phar
# Ignore potentially sensitive phpunit file
phpunit.xml
# Ignore composer generated files
composer.phar
composer.lock
composer-test.lock
vendor/
# Ignore build files
build/
phing/build.properties
# Ignore subsplit working directory
.subsplit
docs/_build
docs/*.pyc

View File

@ -1,17 +0,0 @@
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
- hhvm
before_script:
- curl --version
- pecl install uri_template-beta || echo "pecl uri_template not available"
- composer self-update
- composer install --no-interaction --prefer-source --dev
- ~/.nvm/nvm.sh install v0.6.14
script: composer test

View File

@ -1,751 +0,0 @@
# CHANGELOG
## 3.9.3 - 2015-03-18
* Ensuring Content-Length is not stripped from a request when it is `0`.
* Added more information to stream wrapper exceptions.
* Message parser will no longer throw warnings for malformed messages.
* Giving a valid cache TTL when max-age is 0.
## 3.9.2 - 2014-09-10
* Retrying "Connection died, retrying a fresh connect" curl errors.
* Automatically extracting the cacert from the phar in client constructor.
* Added EntityBody support for OPTIONS requests.
## 3.9.1 - 2014-05-07
* Added a fix to ReadLimitEntityBody to ensure it doesn't infinitely loop.
* Added a fix to the stream checksum function so that when the first read
returns a falsey value, it still continues to consume the stream until EOF.
## 3.9.0 - 2014-04-23
* `null`, `false`, and `"_guzzle_blank_"` all now serialize as an empty value
with no trailing "=". See dc1d824277.
* No longer performing an MD5 check on the cacert each time the phar is used,
but rather copying the cacert to the temp directory.
* `"0"` can now be added as a URL path
* Deleting cookies that are set to empty
* If-Modified-Since is no longer unnecessarily added to the CachePlugin
* Cookie path matching now follows RFC 6265 s5.1.4
* Updated service descriptions are now added to a service client's composite
factory.
* MockPlugin now throws an exception if the queue is empty.
* Properly parsing URLs that start with "http" but are not absolute
* Added the ability to configure the curl_multi_select timeout setting
* OAuth parameters are now sorted using lexicographical byte value ordering
* Fixing invalid usage of an out of range PHP feature in the ErrorResponsePlugin
## 3.8.1 -2014-01-28
* Bug: Always using GET requests when redirecting from a 303 response
* Bug: CURLOPT_SSL_VERIFYHOST is now correctly set to false when setting `$certificateAuthority` to false in
`Guzzle\Http\ClientInterface::setSslVerification()`
* Bug: RedirectPlugin now uses strict RFC 3986 compliance when combining a base URL with a relative URL
* Bug: The body of a request can now be set to `"0"`
* Sending PHP stream requests no longer forces `HTTP/1.0`
* Adding more information to ExceptionCollection exceptions so that users have more context, including a stack trace of
each sub-exception
* Updated the `$ref` attribute in service descriptions to merge over any existing parameters of a schema (rather than
clobbering everything).
* Merging URLs will now use the query string object from the relative URL (thus allowing custom query aggregators)
* Query strings are now parsed in a way that they do no convert empty keys with no value to have a dangling `=`.
For example `foo&bar=baz` is now correctly parsed and recognized as `foo&bar=baz` rather than `foo=&bar=baz`.
* Now properly escaping the regular expression delimiter when matching Cookie domains.
* Network access is now disabled when loading XML documents
## 3.8.0 - 2013-12-05
* Added the ability to define a POST name for a file
* JSON response parsing now properly walks additionalProperties
* cURL error code 18 is now retried automatically in the BackoffPlugin
* Fixed a cURL error when URLs contain fragments
* Fixed an issue in the BackoffPlugin retry event where it was trying to access all exceptions as if they were
CurlExceptions
* CURLOPT_PROGRESS function fix for PHP 5.5 (69fcc1e)
* Added the ability for Guzzle to work with older versions of cURL that do not support `CURLOPT_TIMEOUT_MS`
* Fixed a bug that was encountered when parsing empty header parameters
* UriTemplate now has a `setRegex()` method to match the docs
* The `debug` request parameter now checks if it is truthy rather than if it exists
* Setting the `debug` request parameter to true shows verbose cURL output instead of using the LogPlugin
* Added the ability to combine URLs using strict RFC 3986 compliance
* Command objects can now return the validation errors encountered by the command
* Various fixes to cache revalidation (#437 and 29797e5)
* Various fixes to the AsyncPlugin
* Cleaned up build scripts
## 3.7.4 - 2013-10-02
* Bug fix: 0 is now an allowed value in a description parameter that has a default value (#430)
* Bug fix: SchemaFormatter now returns an integer when formatting to a Unix timestamp
(see https://github.com/aws/aws-sdk-php/issues/147)
* Bug fix: Cleaned up and fixed URL dot segment removal to properly resolve internal dots
* Minimum PHP version is now properly specified as 5.3.3 (up from 5.3.2) (#420)
* Updated the bundled cacert.pem (#419)
* OauthPlugin now supports adding authentication to headers or query string (#425)
## 3.7.3 - 2013-09-08
* Added the ability to get the exception associated with a request/command when using `MultiTransferException` and
`CommandTransferException`.
* Setting `additionalParameters` of a response to false is now honored when parsing responses with a service description
* Schemas are only injected into response models when explicitly configured.
* No longer guessing Content-Type based on the path of a request. Content-Type is now only guessed based on the path of
an EntityBody.
* Bug fix: ChunkedIterator can now properly chunk a \Traversable as well as an \Iterator.
* Bug fix: FilterIterator now relies on `\Iterator` instead of `\Traversable`.
* Bug fix: Gracefully handling malformed responses in RequestMediator::writeResponseBody()
* Bug fix: Replaced call to canCache with canCacheRequest in the CallbackCanCacheStrategy of the CachePlugin
* Bug fix: Visiting XML attributes first before visting XML children when serializing requests
* Bug fix: Properly parsing headers that contain commas contained in quotes
* Bug fix: mimetype guessing based on a filename is now case-insensitive
## 3.7.2 - 2013-08-02
* Bug fix: Properly URL encoding paths when using the PHP-only version of the UriTemplate expander
See https://github.com/guzzle/guzzle/issues/371
* Bug fix: Cookie domains are now matched correctly according to RFC 6265
See https://github.com/guzzle/guzzle/issues/377
* Bug fix: GET parameters are now used when calculating an OAuth signature
* Bug fix: Fixed an issue with cache revalidation where the If-None-Match header was being double quoted
* `Guzzle\Common\AbstractHasDispatcher::dispatch()` now returns the event that was dispatched
* `Guzzle\Http\QueryString::factory()` now guesses the most appropriate query aggregator to used based on the input.
See https://github.com/guzzle/guzzle/issues/379
* Added a way to add custom domain objects to service description parsing using the `operation.parse_class` event. See
https://github.com/guzzle/guzzle/pull/380
* cURL multi cleanup and optimizations
## 3.7.1 - 2013-07-05
* Bug fix: Setting default options on a client now works
* Bug fix: Setting options on HEAD requests now works. See #352
* Bug fix: Moving stream factory before send event to before building the stream. See #353
* Bug fix: Cookies no longer match on IP addresses per RFC 6265
* Bug fix: Correctly parsing header parameters that are in `<>` and quotes
* Added `cert` and `ssl_key` as request options
* `Host` header can now diverge from the host part of a URL if the header is set manually
* `Guzzle\Service\Command\LocationVisitor\Request\XmlVisitor` was rewritten to change from using SimpleXML to XMLWriter
* OAuth parameters are only added via the plugin if they aren't already set
* Exceptions are now thrown when a URL cannot be parsed
* Returning `false` if `Guzzle\Http\EntityBody::getContentMd5()` fails
* Not setting a `Content-MD5` on a command if calculating the Content-MD5 fails via the CommandContentMd5Plugin
## 3.7.0 - 2013-06-10
* See UPGRADING.md for more information on how to upgrade.
* Requests now support the ability to specify an array of $options when creating a request to more easily modify a
request. You can pass a 'request.options' configuration setting to a client to apply default request options to
every request created by a client (e.g. default query string variables, headers, curl options, etc).
* Added a static facade class that allows you to use Guzzle with static methods and mount the class to `\Guzzle`.
See `Guzzle\Http\StaticClient::mount`.
* Added `command.request_options` to `Guzzle\Service\Command\AbstractCommand` to pass request options to requests
created by a command (e.g. custom headers, query string variables, timeout settings, etc).
* Stream size in `Guzzle\Stream\PhpStreamRequestFactory` will now be set if Content-Length is returned in the
headers of a response
* Added `Guzzle\Common\Collection::setPath($path, $value)` to set a value into an array using a nested key
(e.g. `$collection->setPath('foo/baz/bar', 'test'); echo $collection['foo']['bar']['bar'];`)
* ServiceBuilders now support storing and retrieving arbitrary data
* CachePlugin can now purge all resources for a given URI
* CachePlugin can automatically purge matching cached items when a non-idempotent request is sent to a resource
* CachePlugin now uses the Vary header to determine if a resource is a cache hit
* `Guzzle\Http\Message\Response` now implements `\Serializable`
* Added `Guzzle\Cache\CacheAdapterFactory::fromCache()` to more easily create cache adapters
* `Guzzle\Service\ClientInterface::execute()` now accepts an array, single command, or Traversable
* Fixed a bug in `Guzzle\Http\Message\Header\Link::addLink()`
* Better handling of calculating the size of a stream in `Guzzle\Stream\Stream` using fstat() and caching the size
* `Guzzle\Common\Exception\ExceptionCollection` now creates a more readable exception message
* Fixing BC break: Added back the MonologLogAdapter implementation rather than extending from PsrLog so that older
Symfony users can still use the old version of Monolog.
* Fixing BC break: Added the implementation back in for `Guzzle\Http\Message\AbstractMessage::getTokenizedHeader()`.
Now triggering an E_USER_DEPRECATED warning when used. Use `$message->getHeader()->parseParams()`.
* Several performance improvements to `Guzzle\Common\Collection`
* Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`:
createRequest, head, delete, put, patch, post, options, prepareRequest
* Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()`
* Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface`
* Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to
`Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a
resource, string, or EntityBody into the $options parameter to specify the download location of the response.
* Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a
default `array()`
* Added `Guzzle\Stream\StreamInterface::isRepeatable`
* Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use
$client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or
$client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))`.
* Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use $client->getConfig()->getPath('request.options/headers')`.
* Removed `Guzzle\Http\ClientInterface::expandTemplate()`
* Removed `Guzzle\Http\ClientInterface::setRequestFactory()`
* Removed `Guzzle\Http\ClientInterface::getCurlMulti()`
* Removed `Guzzle\Http\Message\RequestInterface::canCache`
* Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`
* Removed `Guzzle\Http\Message\RequestInterface::isRedirect`
* Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods.
* You can now enable E_USER_DEPRECATED warnings to see if you are using a deprecated method by setting
`Guzzle\Common\Version::$emitWarnings` to true.
* Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use
`$request->getResponseBody()->isRepeatable()` instead.
* Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use
`Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
* Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use
`Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
* Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead.
* Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead.
* Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated
* Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand.
These will work through Guzzle 4.0
* Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use [request.options][params].
* Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client.
* Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use $client->getConfig()->getPath('request.options/headers')`.
* Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`.
* Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8.
* Marked `Guzzle\Common\Collection::inject()` as deprecated.
* Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest');`
* CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a
CacheStorageInterface. These two objects and interface will be removed in a future version.
* Always setting X-cache headers on cached responses
* Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin
* `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface
$request, Response $response);`
* `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);`
* `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);`
* Added `CacheStorageInterface::purge($url)`
* `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin
$plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache,
CanCacheStrategyInterface $canCache = null)`
* Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)`
## 3.6.0 - 2013-05-29
* ServiceDescription now implements ToArrayInterface
* Added command.hidden_params to blacklist certain headers from being treated as additionalParameters
* Guzzle can now correctly parse incomplete URLs
* Mixed casing of headers are now forced to be a single consistent casing across all values for that header.
* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution
* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader().
* Specific header implementations can be created for complex headers. When a message creates a header, it uses a
HeaderFactory which can map specific headers to specific header classes. There is now a Link header and
CacheControl header implementation.
* Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate
* Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti()
* Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in
Guzzle\Http\Curl\RequestMediator
* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string.
* Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface
* Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders()
* Removed Guzzle\Parser\ParserRegister::get(). Use getParser()
* Removed Guzzle\Parser\ParserRegister::set(). Use registerParser().
* All response header helper functions return a string rather than mixing Header objects and strings inconsistently
* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc are managed by Guzzle
directly via interfaces
* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist
but are a no-op until removed.
* Most classes that used to require a ``Guzzle\Service\Command\CommandInterface` typehint now request a
`Guzzle\Service\Command\ArrayCommandInterface`.
* Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response
on a request while the request is still being transferred
* The ability to case-insensitively search for header values
* Guzzle\Http\Message\Header::hasExactHeader
* Guzzle\Http\Message\Header::raw. Use getAll()
* Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object
instead.
* `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess
* Added the ability to cast Model objects to a string to view debug information.
## 3.5.0 - 2013-05-13
* Bug: Fixed a regression so that request responses are parsed only once per oncomplete event rather than multiple times
* Bug: Better cleanup of one-time events accross the board (when an event is meant to fire once, it will now remove
itself from the EventDispatcher)
* Bug: `Guzzle\Log\MessageFormatter` now properly writes "total_time" and "connect_time" values
* Bug: Cloning an EntityEnclosingRequest now clones the EntityBody too
* Bug: Fixed an undefined index error when parsing nested JSON responses with a sentAs parameter that reference a
non-existent key
* Bug: All __call() method arguments are now required (helps with mocking frameworks)
* Deprecating Response::getRequest() and now using a shallow clone of a request object to remove a circular reference
to help with refcount based garbage collection of resources created by sending a request
* Deprecating ZF1 cache and log adapters. These will be removed in the next major version.
* Deprecating `Response::getPreviousResponse()` (method signature still exists, but it'sdeprecated). Use the
HistoryPlugin for a history.
* Added a `responseBody` alias for the `response_body` location
* Refactored internals to no longer rely on Response::getRequest()
* HistoryPlugin can now be cast to a string
* HistoryPlugin now logs transactions rather than requests and responses to more accurately keep track of the requests
and responses that are sent over the wire
* Added `getEffectiveUrl()` and `getRedirectCount()` to Response objects
## 3.4.3 - 2013-04-30
* Bug fix: Fixing bug introduced in 3.4.2 where redirect responses are duplicated on the final redirected response
* Added a check to re-extract the temp cacert bundle from the phar before sending each request
## 3.4.2 - 2013-04-29
* Bug fix: Stream objects now work correctly with "a" and "a+" modes
* Bug fix: Removing `Transfer-Encoding: chunked` header when a Content-Length is present
* Bug fix: AsyncPlugin no longer forces HEAD requests
* Bug fix: DateTime timezones are now properly handled when using the service description schema formatter
* Bug fix: CachePlugin now properly handles stale-if-error directives when a request to the origin server fails
* Setting a response on a request will write to the custom request body from the response body if one is specified
* LogPlugin now writes to php://output when STDERR is undefined
* Added the ability to set multiple POST files for the same key in a single call
* application/x-www-form-urlencoded POSTs now use the utf-8 charset by default
* Added the ability to queue CurlExceptions to the MockPlugin
* Cleaned up how manual responses are queued on requests (removed "queued_response" and now using request.before_send)
* Configuration loading now allows remote files
## 3.4.1 - 2013-04-16
* Large refactoring to how CurlMulti handles work. There is now a proxy that sits in front of a pool of CurlMulti
handles. This greatly simplifies the implementation, fixes a couple bugs, and provides a small performance boost.
* Exceptions are now properly grouped when sending requests in parallel
* Redirects are now properly aggregated when a multi transaction fails
* Redirects now set the response on the original object even in the event of a failure
* Bug fix: Model names are now properly set even when using $refs
* Added support for PHP 5.5's CurlFile to prevent warnings with the deprecated @ syntax
* Added support for oauth_callback in OAuth signatures
* Added support for oauth_verifier in OAuth signatures
* Added support to attempt to retrieve a command first literally, then ucfirst, the with inflection
## 3.4.0 - 2013-04-11
* Bug fix: URLs are now resolved correctly based on http://tools.ietf.org/html/rfc3986#section-5.2. #289
* Bug fix: Absolute URLs with a path in a service description will now properly override the base URL. #289
* Bug fix: Parsing a query string with a single PHP array value will now result in an array. #263
* Bug fix: Better normalization of the User-Agent header to prevent duplicate headers. #264.
* Bug fix: Added `number` type to service descriptions.
* Bug fix: empty parameters are removed from an OAuth signature
* Bug fix: Revalidating a cache entry prefers the Last-Modified over the Date header
* Bug fix: Fixed "array to string" error when validating a union of types in a service description
* Bug fix: Removed code that attempted to determine the size of a stream when data is written to the stream
* Bug fix: Not including an `oauth_token` if the value is null in the OauthPlugin.
* Bug fix: Now correctly aggregating successful requests and failed requests in CurlMulti when a redirect occurs.
* The new default CURLOPT_TIMEOUT setting has been increased to 150 seconds so that Guzzle works on poor connections.
* Added a feature to EntityEnclosingRequest::setBody() that will automatically set the Content-Type of the request if
the Content-Type can be determined based on the entity body or the path of the request.
* Added the ability to overwrite configuration settings in a client when grabbing a throwaway client from a builder.
* Added support for a PSR-3 LogAdapter.
* Added a `command.after_prepare` event
* Added `oauth_callback` parameter to the OauthPlugin
* Added the ability to create a custom stream class when using a stream factory
* Added a CachingEntityBody decorator
* Added support for `additionalParameters` in service descriptions to define how custom parameters are serialized.
* The bundled SSL certificate is now provided in the phar file and extracted when running Guzzle from a phar.
* You can now send any EntityEnclosingRequest with POST fields or POST files and cURL will handle creating bodies
* POST requests using a custom entity body are now treated exactly like PUT requests but with a custom cURL method. This
means that the redirect behavior of POST requests with custom bodies will not be the same as POST requests that use
POST fields or files (the latter is only used when emulating a form POST in the browser).
* Lots of cleanup to CurlHandle::factory and RequestFactory::createRequest
## 3.3.1 - 2013-03-10
* Added the ability to create PHP streaming responses from HTTP requests
* Bug fix: Running any filters when parsing response headers with service descriptions
* Bug fix: OauthPlugin fixes to allow for multi-dimensional array signing, and sorting parameters before signing
* Bug fix: Removed the adding of default empty arrays and false Booleans to responses in order to be consistent across
response location visitors.
* Bug fix: Removed the possibility of creating configuration files with circular dependencies
* RequestFactory::create() now uses the key of a POST file when setting the POST file name
* Added xmlAllowEmpty to serialize an XML body even if no XML specific parameters are set
## 3.3.0 - 2013-03-03
* A large number of performance optimizations have been made
* Bug fix: Added 'wb' as a valid write mode for streams
* Bug fix: `Guzzle\Http\Message\Response::json()` now allows scalar values to be returned
* Bug fix: Fixed bug in `Guzzle\Http\Message\Response` where wrapping quotes were stripped from `getEtag()`
* BC: Removed `Guzzle\Http\Utils` class
* BC: Setting a service description on a client will no longer modify the client's command factories.
* BC: Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using
the 'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'
* BC: `Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getSteamType()` are no longer converted to
lowercase
* Operation parameter objects are now lazy loaded internally
* Added ErrorResponsePlugin that can throw errors for responses defined in service description operations' errorResponses
* Added support for instantiating responseType=class responseClass classes. Classes must implement
`Guzzle\Service\Command\ResponseClassInterface`
* Added support for additionalProperties for top-level parameters in responseType=model responseClasses. These
additional properties also support locations and can be used to parse JSON responses where the outermost part of the
JSON is an array
* Added support for nested renaming of JSON models (rename sentAs to name)
* CachePlugin
* Added support for stale-if-error so that the CachePlugin can now serve stale content from the cache on error
* Debug headers can now added to cached response in the CachePlugin
## 3.2.0 - 2013-02-14
* CurlMulti is no longer reused globally. A new multi object is created per-client. This helps to isolate clients.
* URLs with no path no longer contain a "/" by default
* Guzzle\Http\QueryString does no longer manages the leading "?". This is now handled in Guzzle\Http\Url.
* BadResponseException no longer includes the full request and response message
* Adding setData() to Guzzle\Service\Description\ServiceDescriptionInterface
* Adding getResponseBody() to Guzzle\Http\Message\RequestInterface
* Various updates to classes to use ServiceDescriptionInterface type hints rather than ServiceDescription
* Header values can now be normalized into distinct values when multiple headers are combined with a comma separated list
* xmlEncoding can now be customized for the XML declaration of a XML service description operation
* Guzzle\Http\QueryString now uses Guzzle\Http\QueryAggregator\QueryAggregatorInterface objects to add custom value
aggregation and no longer uses callbacks
* The URL encoding implementation of Guzzle\Http\QueryString can now be customized
* Bug fix: Filters were not always invoked for array service description parameters
* Bug fix: Redirects now use a target response body rather than a temporary response body
* Bug fix: The default exponential backoff BackoffPlugin was not giving when the request threshold was exceeded
* Bug fix: Guzzle now takes the first found value when grabbing Cache-Control directives
## 3.1.2 - 2013-01-27
* Refactored how operation responses are parsed. Visitors now include a before() method responsible for parsing the
response body. For example, the XmlVisitor now parses the XML response into an array in the before() method.
* Fixed an issue where cURL would not automatically decompress responses when the Accept-Encoding header was sent
* CURLOPT_SSL_VERIFYHOST is never set to 1 because it is deprecated (see 5e0ff2ef20f839e19d1eeb298f90ba3598784444)
* Fixed a bug where redirect responses were not chained correctly using getPreviousResponse()
* Setting default headers on a client after setting the user-agent will not erase the user-agent setting
## 3.1.1 - 2013-01-20
* Adding wildcard support to Guzzle\Common\Collection::getPath()
* Adding alias support to ServiceBuilder configs
* Adding Guzzle\Service\Resource\CompositeResourceIteratorFactory and cleaning up factory interface
## 3.1.0 - 2013-01-12
* BC: CurlException now extends from RequestException rather than BadResponseException
* BC: Renamed Guzzle\Plugin\Cache\CanCacheStrategyInterface::canCache() to canCacheRequest() and added CanCacheResponse()
* Added getData to ServiceDescriptionInterface
* Added context array to RequestInterface::setState()
* Bug: Removing hard dependency on the BackoffPlugin from Guzzle\Http
* Bug: Adding required content-type when JSON request visitor adds JSON to a command
* Bug: Fixing the serialization of a service description with custom data
* Made it easier to deal with exceptions thrown when transferring commands or requests in parallel by providing
an array of successful and failed responses
* Moved getPath from Guzzle\Service\Resource\Model to Guzzle\Common\Collection
* Added Guzzle\Http\IoEmittingEntityBody
* Moved command filtration from validators to location visitors
* Added `extends` attributes to service description parameters
* Added getModels to ServiceDescriptionInterface
## 3.0.7 - 2012-12-19
* Fixing phar detection when forcing a cacert to system if null or true
* Allowing filename to be passed to `Guzzle\Http\Message\Request::setResponseBody()`
* Cleaning up `Guzzle\Common\Collection::inject` method
* Adding a response_body location to service descriptions
## 3.0.6 - 2012-12-09
* CurlMulti performance improvements
* Adding setErrorResponses() to Operation
* composer.json tweaks
## 3.0.5 - 2012-11-18
* Bug: Fixing an infinite recursion bug caused from revalidating with the CachePlugin
* Bug: Response body can now be a string containing "0"
* Bug: Using Guzzle inside of a phar uses system by default but now allows for a custom cacert
* Bug: QueryString::fromString now properly parses query string parameters that contain equal signs
* Added support for XML attributes in service description responses
* DefaultRequestSerializer now supports array URI parameter values for URI template expansion
* Added better mimetype guessing to requests and post files
## 3.0.4 - 2012-11-11
* Bug: Fixed a bug when adding multiple cookies to a request to use the correct glue value
* Bug: Cookies can now be added that have a name, domain, or value set to "0"
* Bug: Using the system cacert bundle when using the Phar
* Added json and xml methods to Response to make it easier to parse JSON and XML response data into data structures
* Enhanced cookie jar de-duplication
* Added the ability to enable strict cookie jars that throw exceptions when invalid cookies are added
* Added setStream to StreamInterface to actually make it possible to implement custom rewind behavior for entity bodies
* Added the ability to create any sort of hash for a stream rather than just an MD5 hash
## 3.0.3 - 2012-11-04
* Implementing redirects in PHP rather than cURL
* Added PECL URI template extension and using as default parser if available
* Bug: Fixed Content-Length parsing of Response factory
* Adding rewind() method to entity bodies and streams. Allows for custom rewinding of non-repeatable streams.
* Adding ToArrayInterface throughout library
* Fixing OauthPlugin to create unique nonce values per request
## 3.0.2 - 2012-10-25
* Magic methods are enabled by default on clients
* Magic methods return the result of a command
* Service clients no longer require a base_url option in the factory
* Bug: Fixed an issue with URI templates where null template variables were being expanded
## 3.0.1 - 2012-10-22
* Models can now be used like regular collection objects by calling filter, map, etc
* Models no longer require a Parameter structure or initial data in the constructor
* Added a custom AppendIterator to get around a PHP bug with the `\AppendIterator`
## 3.0.0 - 2012-10-15
* Rewrote service description format to be based on Swagger
* Now based on JSON schema
* Added nested input structures and nested response models
* Support for JSON and XML input and output models
* Renamed `commands` to `operations`
* Removed dot class notation
* Removed custom types
* Broke the project into smaller top-level namespaces to be more component friendly
* Removed support for XML configs and descriptions. Use arrays or JSON files.
* Removed the Validation component and Inspector
* Moved all cookie code to Guzzle\Plugin\Cookie
* Magic methods on a Guzzle\Service\Client now return the command un-executed.
* Calling getResult() or getResponse() on a command will lazily execute the command if needed.
* Now shipping with cURL's CA certs and using it by default
* Added previousResponse() method to response objects
* No longer sending Accept and Accept-Encoding headers on every request
* Only sending an Expect header by default when a payload is greater than 1MB
* Added/moved client options:
* curl.blacklist to curl.option.blacklist
* Added ssl.certificate_authority
* Added a Guzzle\Iterator component
* Moved plugins from Guzzle\Http\Plugin to Guzzle\Plugin
* Added a more robust backoff retry strategy (replaced the ExponentialBackoffPlugin)
* Added a more robust caching plugin
* Added setBody to response objects
* Updating LogPlugin to use a more flexible MessageFormatter
* Added a completely revamped build process
* Cleaning up Collection class and removing default values from the get method
* Fixed ZF2 cache adapters
## 2.8.8 - 2012-10-15
* Bug: Fixed a cookie issue that caused dot prefixed domains to not match where popular browsers did
## 2.8.7 - 2012-09-30
* Bug: Fixed config file aliases for JSON includes
* Bug: Fixed cookie bug on a request object by using CookieParser to parse cookies on requests
* Bug: Removing the path to a file when sending a Content-Disposition header on a POST upload
* Bug: Hardening request and response parsing to account for missing parts
* Bug: Fixed PEAR packaging
* Bug: Fixed Request::getInfo
* Bug: Fixed cases where CURLM_CALL_MULTI_PERFORM return codes were causing curl transactions to fail
* Adding the ability for the namespace Iterator factory to look in multiple directories
* Added more getters/setters/removers from service descriptions
* Added the ability to remove POST fields from OAuth signatures
* OAuth plugin now supports 2-legged OAuth
## 2.8.6 - 2012-09-05
* Added the ability to modify and build service descriptions
* Added the use of visitors to apply parameters to locations in service descriptions using the dynamic command
* Added a `json` parameter location
* Now allowing dot notation for classes in the CacheAdapterFactory
* Using the union of two arrays rather than an array_merge when extending service builder services and service params
* Ensuring that a service is a string before doing strpos() checks on it when substituting services for references
in service builder config files.
* Services defined in two different config files that include one another will by default replace the previously
defined service, but you can now create services that extend themselves and merge their settings over the previous
* The JsonLoader now supports aliasing filenames with different filenames. This allows you to alias something like
'_default' with a default JSON configuration file.
## 2.8.5 - 2012-08-29
* Bug: Suppressed empty arrays from URI templates
* Bug: Added the missing $options argument from ServiceDescription::factory to enable caching
* Added support for HTTP responses that do not contain a reason phrase in the start-line
* AbstractCommand commands are now invokable
* Added a way to get the data used when signing an Oauth request before a request is sent
## 2.8.4 - 2012-08-15
* Bug: Custom delay time calculations are no longer ignored in the ExponentialBackoffPlugin
* Added the ability to transfer entity bodies as a string rather than streamed. This gets around curl error 65. Set `body_as_string` in a request's curl options to enable.
* Added a StreamInterface, EntityBodyInterface, and added ftell() to Guzzle\Common\Stream
* Added an AbstractEntityBodyDecorator and a ReadLimitEntityBody decorator to transfer only a subset of a decorated stream
* Stream and EntityBody objects will now return the file position to the previous position after a read required operation (e.g. getContentMd5())
* Added additional response status codes
* Removed SSL information from the default User-Agent header
* DELETE requests can now send an entity body
* Added an EventDispatcher to the ExponentialBackoffPlugin and added an ExponentialBackoffLogger to log backoff retries
* Added the ability of the MockPlugin to consume mocked request bodies
* LogPlugin now exposes request and response objects in the extras array
## 2.8.3 - 2012-07-30
* Bug: Fixed a case where empty POST requests were sent as GET requests
* Bug: Fixed a bug in ExponentialBackoffPlugin that caused fatal errors when retrying an EntityEnclosingRequest that does not have a body
* Bug: Setting the response body of a request to null after completing a request, not when setting the state of a request to new
* Added multiple inheritance to service description commands
* Added an ApiCommandInterface and added ``getParamNames()`` and ``hasParam()``
* Removed the default 2mb size cutoff from the Md5ValidatorPlugin so that it now defaults to validating everything
* Changed CurlMulti::perform to pass a smaller timeout to CurlMulti::executeHandles
## 2.8.2 - 2012-07-24
* Bug: Query string values set to 0 are no longer dropped from the query string
* Bug: A Collection object is no longer created each time a call is made to ``Guzzle\Service\Command\AbstractCommand::getRequestHeaders()``
* Bug: ``+`` is now treated as an encoded space when parsing query strings
* QueryString and Collection performance improvements
* Allowing dot notation for class paths in filters attribute of a service descriptions
## 2.8.1 - 2012-07-16
* Loosening Event Dispatcher dependency
* POST redirects can now be customized using CURLOPT_POSTREDIR
## 2.8.0 - 2012-07-15
* BC: Guzzle\Http\Query
* Query strings with empty variables will always show an equal sign unless the variable is set to QueryString::BLANK (e.g. ?acl= vs ?acl)
* Changed isEncodingValues() and isEncodingFields() to isUrlEncoding()
* Changed setEncodeValues(bool) and setEncodeFields(bool) to useUrlEncoding(bool)
* Changed the aggregation functions of QueryString to be static methods
* Can now use fromString() with querystrings that have a leading ?
* cURL configuration values can be specified in service descriptions using ``curl.`` prefixed parameters
* Content-Length is set to 0 before emitting the request.before_send event when sending an empty request body
* Cookies are no longer URL decoded by default
* Bug: URI template variables set to null are no longer expanded
## 2.7.2 - 2012-07-02
* BC: Moving things to get ready for subtree splits. Moving Inflection into Common. Moving Guzzle\Http\Parser to Guzzle\Parser.
* BC: Removing Guzzle\Common\Batch\Batch::count() and replacing it with isEmpty()
* CachePlugin now allows for a custom request parameter function to check if a request can be cached
* Bug fix: CachePlugin now only caches GET and HEAD requests by default
* Bug fix: Using header glue when transferring headers over the wire
* Allowing deeply nested arrays for composite variables in URI templates
* Batch divisors can now return iterators or arrays
## 2.7.1 - 2012-06-26
* Minor patch to update version number in UA string
* Updating build process
## 2.7.0 - 2012-06-25
* BC: Inflection classes moved to Guzzle\Inflection. No longer static methods. Can now inject custom inflectors into classes.
* BC: Removed magic setX methods from commands
* BC: Magic methods mapped to service description commands are now inflected in the command factory rather than the client __call() method
* Verbose cURL options are no longer enabled by default. Set curl.debug to true on a client to enable.
* Bug: Now allowing colons in a response start-line (e.g. HTTP/1.1 503 Service Unavailable: Back-end server is at capacity)
* Guzzle\Service\Resource\ResourceIteratorApplyBatched now internally uses the Guzzle\Common\Batch namespace
* Added Guzzle\Service\Plugin namespace and a PluginCollectionPlugin
* Added the ability to set POST fields and files in a service description
* Guzzle\Http\EntityBody::factory() now accepts objects with a __toString() method
* Adding a command.before_prepare event to clients
* Added BatchClosureTransfer and BatchClosureDivisor
* BatchTransferException now includes references to the batch divisor and transfer strategies
* Fixed some tests so that they pass more reliably
* Added Guzzle\Common\Log\ArrayLogAdapter
## 2.6.6 - 2012-06-10
* BC: Removing Guzzle\Http\Plugin\BatchQueuePlugin
* BC: Removing Guzzle\Service\Command\CommandSet
* Adding generic batching system (replaces the batch queue plugin and command set)
* Updating ZF cache and log adapters and now using ZF's composer repository
* Bug: Setting the name of each ApiParam when creating through an ApiCommand
* Adding result_type, result_doc, deprecated, and doc_url to service descriptions
* Bug: Changed the default cookie header casing back to 'Cookie'
## 2.6.5 - 2012-06-03
* BC: Renaming Guzzle\Http\Message\RequestInterface::getResourceUri() to getResource()
* BC: Removing unused AUTH_BASIC and AUTH_DIGEST constants from
* BC: Guzzle\Http\Cookie is now used to manage Set-Cookie data, not Cookie data
* BC: Renaming methods in the CookieJarInterface
* Moving almost all cookie logic out of the CookiePlugin and into the Cookie or CookieJar implementations
* Making the default glue for HTTP headers ';' instead of ','
* Adding a removeValue to Guzzle\Http\Message\Header
* Adding getCookies() to request interface.
* Making it easier to add event subscribers to HasDispatcherInterface classes. Can now directly call addSubscriber()
## 2.6.4 - 2012-05-30
* BC: Cleaning up how POST files are stored in EntityEnclosingRequest objects. Adding PostFile class.
* BC: Moving ApiCommand specific functionality from the Inspector and on to the ApiCommand
* Bug: Fixing magic method command calls on clients
* Bug: Email constraint only validates strings
* Bug: Aggregate POST fields when POST files are present in curl handle
* Bug: Fixing default User-Agent header
* Bug: Only appending or prepending parameters in commands if they are specified
* Bug: Not requiring response reason phrases or status codes to match a predefined list of codes
* Allowing the use of dot notation for class namespaces when using instance_of constraint
* Added any_match validation constraint
* Added an AsyncPlugin
* Passing request object to the calculateWait method of the ExponentialBackoffPlugin
* Allowing the result of a command object to be changed
* Parsing location and type sub values when instantiating a service description rather than over and over at runtime
## 2.6.3 - 2012-05-23
* [BC] Guzzle\Common\FromConfigInterface no longer requires any config options.
* [BC] Refactoring how POST files are stored on an EntityEnclosingRequest. They are now separate from POST fields.
* You can now use an array of data when creating PUT request bodies in the request factory.
* Removing the requirement that HTTPS requests needed a Cache-Control: public directive to be cacheable.
* [Http] Adding support for Content-Type in multipart POST uploads per upload
* [Http] Added support for uploading multiple files using the same name (foo[0], foo[1])
* Adding more POST data operations for easier manipulation of POST data.
* You can now set empty POST fields.
* The body of a request is only shown on EntityEnclosingRequest objects that do not use POST files.
* Split the Guzzle\Service\Inspector::validateConfig method into two methods. One to initialize when a command is created, and one to validate.
* CS updates
## 2.6.2 - 2012-05-19
* [Http] Better handling of nested scope requests in CurlMulti. Requests are now always prepares in the send() method rather than the addRequest() method.
## 2.6.1 - 2012-05-19
* [BC] Removing 'path' support in service descriptions. Use 'uri'.
* [BC] Guzzle\Service\Inspector::parseDocBlock is now protected. Adding getApiParamsForClass() with cache.
* [BC] Removing Guzzle\Common\NullObject. Use https://github.com/mtdowling/NullObject if you need it.
* [BC] Removing Guzzle\Common\XmlElement.
* All commands, both dynamic and concrete, have ApiCommand objects.
* Adding a fix for CurlMulti so that if all of the connections encounter some sort of curl error, then the loop exits.
* Adding checks to EntityEnclosingRequest so that empty POST files and fields are ignored.
* Making the method signature of Guzzle\Service\Builder\ServiceBuilder::factory more flexible.
## 2.6.0 - 2012-05-15
* [BC] Moving Guzzle\Service\Builder to Guzzle\Service\Builder\ServiceBuilder
* [BC] Executing a Command returns the result of the command rather than the command
* [BC] Moving all HTTP parsing logic to Guzzle\Http\Parsers. Allows for faster C implementations if needed.
* [BC] Changing the Guzzle\Http\Message\Response::setProtocol() method to accept a protocol and version in separate args.
* [BC] Moving ResourceIterator* to Guzzle\Service\Resource
* [BC] Completely refactored ResourceIterators to iterate over a cloned command object
* [BC] Moved Guzzle\Http\UriTemplate to Guzzle\Http\Parser\UriTemplate\UriTemplate
* [BC] Guzzle\Guzzle is now deprecated
* Moving Guzzle\Common\Guzzle::inject to Guzzle\Common\Collection::inject
* Adding Guzzle\Version class to give version information about Guzzle
* Adding Guzzle\Http\Utils class to provide getDefaultUserAgent() and getHttpDate()
* Adding Guzzle\Curl\CurlVersion to manage caching curl_version() data
* ServiceDescription and ServiceBuilder are now cacheable using similar configs
* Changing the format of XML and JSON service builder configs. Backwards compatible.
* Cleaned up Cookie parsing
* Trimming the default Guzzle User-Agent header
* Adding a setOnComplete() method to Commands that is called when a command completes
* Keeping track of requests that were mocked in the MockPlugin
* Fixed a caching bug in the CacheAdapterFactory
* Inspector objects can be injected into a Command object
* Refactoring a lot of code and tests to be case insensitive when dealing with headers
* Adding Guzzle\Http\Message\HeaderComparison for easy comparison of HTTP headers using a DSL
* Adding the ability to set global option overrides to service builder configs
* Adding the ability to include other service builder config files from within XML and JSON files
* Moving the parseQuery method out of Url and on to QueryString::fromString() as a static factory method.
## 2.5.0 - 2012-05-08
* Major performance improvements
* [BC] Simplifying Guzzle\Common\Collection. Please check to see if you are using features that are now deprecated.
* [BC] Using a custom validation system that allows a flyweight implementation for much faster validation. No longer using Symfony2 Validation component.
* [BC] No longer supporting "{{ }}" for injecting into command or UriTemplates. Use "{}"
* Added the ability to passed parameters to all requests created by a client
* Added callback functionality to the ExponentialBackoffPlugin
* Using microtime in ExponentialBackoffPlugin to allow more granular backoff strategies.
* Rewinding request stream bodies when retrying requests
* Exception is thrown when JSON response body cannot be decoded
* Added configurable magic method calls to clients and commands. This is off by default.
* Fixed a defect that added a hash to every parsed URL part
* Fixed duplicate none generation for OauthPlugin.
* Emitting an event each time a client is generated by a ServiceBuilder
* Using an ApiParams object instead of a Collection for parameters of an ApiCommand
* cache.* request parameters should be renamed to params.cache.*
* Added the ability to set arbitrary curl options on requests (disable_wire, progress, etc). See CurlHandle.
* Added the ability to disable type validation of service descriptions
* ServiceDescriptions and ServiceBuilders are now Serializable

View File

@ -1,19 +0,0 @@
Copyright (c) 2011 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,57 +0,0 @@
Guzzle, PHP HTTP client and webservice framework
================================================
# This is an old version of Guzzle
This repository is for Guzzle 3.x. Guzzle 5.x, the new version of Guzzle, has
been released and is available at
[https://github.com/guzzle/guzzle](https://github.com/guzzle/guzzle). The
documentation for Guzzle version 5+ can be found at
[http://guzzlephp.org](http://guzzlephp.org).
Guzzle 3 is only maintained for bug and security fixes. Guzzle 3 will be EOL
at some point in late 2015.
### About Guzzle 3
[![Composer Downloads](https://poser.pugx.org/guzzle/guzzle/d/total.png)](https://packagist.org/packages/guzzle/guzzle)
[![Build Status](https://secure.travis-ci.org/guzzle/guzzle3.png?branch=master)](http://travis-ci.org/guzzle/guzzle3)
- Extremely powerful API provides all the power of cURL with a simple interface.
- Truly take advantage of HTTP/1.1 with persistent connections, connection pooling, and parallel requests.
- Service description DSL allows you build awesome web service clients faster.
- Symfony2 event-based plugin system allows you to completely modify the behavior of a request.
Get answers with: [Documentation](http://guzzle3.readthedocs.org/en/latest/), [Forums](https://groups.google.com/forum/?hl=en#!forum/guzzle), IRC ([#guzzlephp](irc://irc.freenode.net/#guzzlephp) @ irc.freenode.net)
### Installing via Composer
The recommended way to install Guzzle is through [Composer](http://getcomposer.org).
```bash
# Install Composer
curl -sS https://getcomposer.org/installer | php
# Add Guzzle as a dependency
php composer.phar require guzzle/guzzle:~3.9
```
After installing, you need to require Composer's autoloader:
```php
require 'vendor/autoload.php';
```
## Known Issues
1. Problem following a specific redirect: https://github.com/guzzle/guzzle/issues/385.
This has been fixed in Guzzle 4/5.
2. Root XML attributes not serialized in a service description: https://github.com/guzzle/guzzle3/issues/5.
This has been fixed in Guzzle 4/5.
3. Accept-Encoding not preserved when following redirect: https://github.com/guzzle/guzzle3/issues/9
Fixed in Guzzle 4/5.
4. String "Array" Transmitted w/ PostFiles and Duplicate Aggregator: https://github.com/guzzle/guzzle3/issues/10
Fixed in Guzzle 4/5.
5. Recursive model references with array items: https://github.com/guzzle/guzzle3/issues/13
Fixed in Guzzle 4/5
6. String "Array" Transmitted w/ PostFiles and Duplicate Aggregator: https://github.com/guzzle/guzzle3/issues/10
Fixed in Guzzle 4/5.

View File

@ -1,537 +0,0 @@
Guzzle Upgrade Guide
====================
3.6 to 3.7
----------
### Deprecations
- You can now enable E_USER_DEPRECATED warnings to see if you are using any deprecated methods.:
```php
\Guzzle\Common\Version::$emitWarnings = true;
```
The following APIs and options have been marked as deprecated:
- Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use `$request->getResponseBody()->isRepeatable()` instead.
- Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
- Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
- Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead.
- Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead.
- Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated
- Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client.
- Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8.
- Marked `Guzzle\Common\Collection::inject()` as deprecated.
- Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use
`$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` or
`$client->setDefaultOption('auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));`
3.7 introduces `request.options` as a parameter for a client configuration and as an optional argument to all creational
request methods. When paired with a client's configuration settings, these options allow you to specify default settings
for various aspects of a request. Because these options make other previous configuration options redundant, several
configuration options and methods of a client and AbstractCommand have been deprecated.
- Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use `$client->getDefaultOption('headers')`.
- Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use `$client->setDefaultOption('headers/{header_name}', 'value')`.
- Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use `$client->setDefaultOption('params/{param_name}', 'value')`
- Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand. These will work through Guzzle 4.0
$command = $client->getCommand('foo', array(
'command.headers' => array('Test' => '123'),
'command.response_body' => '/path/to/file'
));
// Should be changed to:
$command = $client->getCommand('foo', array(
'command.request_options' => array(
'headers' => array('Test' => '123'),
'save_as' => '/path/to/file'
)
));
### Interface changes
Additions and changes (you will need to update any implementations or subclasses you may have created):
- Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`:
createRequest, head, delete, put, patch, post, options, prepareRequest
- Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()`
- Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface`
- Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to
`Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a
resource, string, or EntityBody into the $options parameter to specify the download location of the response.
- Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a
default `array()`
- Added `Guzzle\Stream\StreamInterface::isRepeatable`
- Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods.
The following methods were removed from interfaces. All of these methods are still available in the concrete classes
that implement them, but you should update your code to use alternative methods:
- Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use
`$client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or
`$client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))` or
`$client->setDefaultOption('headers/{header_name}', 'value')`. or
`$client->setDefaultOption('headers', array('header_name' => 'value'))`.
- Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use `$client->getConfig()->getPath('request.options/headers')`.
- Removed `Guzzle\Http\ClientInterface::expandTemplate()`. This is an implementation detail.
- Removed `Guzzle\Http\ClientInterface::setRequestFactory()`. This is an implementation detail.
- Removed `Guzzle\Http\ClientInterface::getCurlMulti()`. This is a very specific implementation detail.
- Removed `Guzzle\Http\Message\RequestInterface::canCache`. Use the CachePlugin.
- Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`. Use the HistoryPlugin.
- Removed `Guzzle\Http\Message\RequestInterface::isRedirect`. Use the HistoryPlugin.
### Cache plugin breaking changes
- CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a
CacheStorageInterface. These two objects and interface will be removed in a future version.
- Always setting X-cache headers on cached responses
- Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin
- `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface
$request, Response $response);`
- `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);`
- `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);`
- Added `CacheStorageInterface::purge($url)`
- `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin
$plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache,
CanCacheStrategyInterface $canCache = null)`
- Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)`
3.5 to 3.6
----------
* Mixed casing of headers are now forced to be a single consistent casing across all values for that header.
* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution
* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader().
For example, setHeader() first removes the header using unset on a HeaderCollection and then calls addHeader().
Keeping the Host header and URL host in sync is now handled by overriding the addHeader method in Request.
* Specific header implementations can be created for complex headers. When a message creates a header, it uses a
HeaderFactory which can map specific headers to specific header classes. There is now a Link header and
CacheControl header implementation.
* Moved getLinks() from Response to just be used on a Link header object.
If you previously relied on Guzzle\Http\Message\Header::raw(), then you will need to update your code to use the
HeaderInterface (e.g. toArray(), getAll(), etc).
### Interface changes
* Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate
* Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti()
* Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in
Guzzle\Http\Curl\RequestMediator
* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string.
* Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface
* Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders()
### Removed deprecated functions
* Removed Guzzle\Parser\ParserRegister::get(). Use getParser()
* Removed Guzzle\Parser\ParserRegister::set(). Use registerParser().
### Deprecations
* The ability to case-insensitively search for header values
* Guzzle\Http\Message\Header::hasExactHeader
* Guzzle\Http\Message\Header::raw. Use getAll()
* Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object
instead.
### Other changes
* All response header helper functions return a string rather than mixing Header objects and strings inconsistently
* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc are managed by Guzzle
directly via interfaces
* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist
but are a no-op until removed.
* Most classes that used to require a ``Guzzle\Service\Command\CommandInterface` typehint now request a
`Guzzle\Service\Command\ArrayCommandInterface`.
* Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response
on a request while the request is still being transferred
* `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess
3.3 to 3.4
----------
Base URLs of a client now follow the rules of http://tools.ietf.org/html/rfc3986#section-5.2.2 when merging URLs.
3.2 to 3.3
----------
### Response::getEtag() quote stripping removed
`Guzzle\Http\Message\Response::getEtag()` no longer strips quotes around the ETag response header
### Removed `Guzzle\Http\Utils`
The `Guzzle\Http\Utils` class was removed. This class was only used for testing.
### Stream wrapper and type
`Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getSteamType()` are no longer converted to lowercase.
### curl.emit_io became emit_io
Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using the
'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'
3.1 to 3.2
----------
### CurlMulti is no longer reused globally
Before 3.2, the same CurlMulti object was reused globally for each client. This can cause issue where plugins added
to a single client can pollute requests dispatched from other clients.
If you still wish to reuse the same CurlMulti object with each client, then you can add a listener to the
ServiceBuilder's `service_builder.create_client` event to inject a custom CurlMulti object into each client as it is
created.
```php
$multi = new Guzzle\Http\Curl\CurlMulti();
$builder = Guzzle\Service\Builder\ServiceBuilder::factory('/path/to/config.json');
$builder->addListener('service_builder.create_client', function ($event) use ($multi) {
$event['client']->setCurlMulti($multi);
}
});
```
### No default path
URLs no longer have a default path value of '/' if no path was specified.
Before:
```php
$request = $client->get('http://www.foo.com');
echo $request->getUrl();
// >> http://www.foo.com/
```
After:
```php
$request = $client->get('http://www.foo.com');
echo $request->getUrl();
// >> http://www.foo.com
```
### Less verbose BadResponseException
The exception message for `Guzzle\Http\Exception\BadResponseException` no longer contains the full HTTP request and
response information. You can, however, get access to the request and response object by calling `getRequest()` or
`getResponse()` on the exception object.
### Query parameter aggregation
Multi-valued query parameters are no longer aggregated using a callback function. `Guzzle\Http\Query` now has a
setAggregator() method that accepts a `Guzzle\Http\QueryAggregator\QueryAggregatorInterface` object. This object is
responsible for handling the aggregation of multi-valued query string variables into a flattened hash.
2.8 to 3.x
----------
### Guzzle\Service\Inspector
Change `\Guzzle\Service\Inspector::fromConfig` to `\Guzzle\Common\Collection::fromConfig`
**Before**
```php
use Guzzle\Service\Inspector;
class YourClient extends \Guzzle\Service\Client
{
public static function factory($config = array())
{
$default = array();
$required = array('base_url', 'username', 'api_key');
$config = Inspector::fromConfig($config, $default, $required);
$client = new self(
$config->get('base_url'),
$config->get('username'),
$config->get('api_key')
);
$client->setConfig($config);
$client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));
return $client;
}
```
**After**
```php
use Guzzle\Common\Collection;
class YourClient extends \Guzzle\Service\Client
{
public static function factory($config = array())
{
$default = array();
$required = array('base_url', 'username', 'api_key');
$config = Collection::fromConfig($config, $default, $required);
$client = new self(
$config->get('base_url'),
$config->get('username'),
$config->get('api_key')
);
$client->setConfig($config);
$client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));
return $client;
}
```
### Convert XML Service Descriptions to JSON
**Before**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<client>
<commands>
<!-- Groups -->
<command name="list_groups" method="GET" uri="groups.json">
<doc>Get a list of groups</doc>
</command>
<command name="search_groups" method="GET" uri='search.json?query="{{query}} type:group"'>
<doc>Uses a search query to get a list of groups</doc>
<param name="query" type="string" required="true" />
</command>
<command name="create_group" method="POST" uri="groups.json">
<doc>Create a group</doc>
<param name="data" type="array" location="body" filters="json_encode" doc="Group JSON"/>
<param name="Content-Type" location="header" static="application/json"/>
</command>
<command name="delete_group" method="DELETE" uri="groups/{{id}}.json">
<doc>Delete a group by ID</doc>
<param name="id" type="integer" required="true"/>
</command>
<command name="get_group" method="GET" uri="groups/{{id}}.json">
<param name="id" type="integer" required="true"/>
</command>
<command name="update_group" method="PUT" uri="groups/{{id}}.json">
<doc>Update a group</doc>
<param name="id" type="integer" required="true"/>
<param name="data" type="array" location="body" filters="json_encode" doc="Group JSON"/>
<param name="Content-Type" location="header" static="application/json"/>
</command>
</commands>
</client>
```
**After**
```json
{
"name": "Zendesk REST API v2",
"apiVersion": "2012-12-31",
"description":"Provides access to Zendesk views, groups, tickets, ticket fields, and users",
"operations": {
"list_groups": {
"httpMethod":"GET",
"uri": "groups.json",
"summary": "Get a list of groups"
},
"search_groups":{
"httpMethod":"GET",
"uri": "search.json?query=\"{query} type:group\"",
"summary": "Uses a search query to get a list of groups",
"parameters":{
"query":{
"location": "uri",
"description":"Zendesk Search Query",
"type": "string",
"required": true
}
}
},
"create_group": {
"httpMethod":"POST",
"uri": "groups.json",
"summary": "Create a group",
"parameters":{
"data": {
"type": "array",
"location": "body",
"description":"Group JSON",
"filters": "json_encode",
"required": true
},
"Content-Type":{
"type": "string",
"location":"header",
"static": "application/json"
}
}
},
"delete_group": {
"httpMethod":"DELETE",
"uri": "groups/{id}.json",
"summary": "Delete a group",
"parameters":{
"id":{
"location": "uri",
"description":"Group to delete by ID",
"type": "integer",
"required": true
}
}
},
"get_group": {
"httpMethod":"GET",
"uri": "groups/{id}.json",
"summary": "Get a ticket",
"parameters":{
"id":{
"location": "uri",
"description":"Group to get by ID",
"type": "integer",
"required": true
}
}
},
"update_group": {
"httpMethod":"PUT",
"uri": "groups/{id}.json",
"summary": "Update a group",
"parameters":{
"id": {
"location": "uri",
"description":"Group to update by ID",
"type": "integer",
"required": true
},
"data": {
"type": "array",
"location": "body",
"description":"Group JSON",
"filters": "json_encode",
"required": true
},
"Content-Type":{
"type": "string",
"location":"header",
"static": "application/json"
}
}
}
}
```
### Guzzle\Service\Description\ServiceDescription
Commands are now called Operations
**Before**
```php
use Guzzle\Service\Description\ServiceDescription;
$sd = new ServiceDescription();
$sd->getCommands(); // @returns ApiCommandInterface[]
$sd->hasCommand($name);
$sd->getCommand($name); // @returns ApiCommandInterface|null
$sd->addCommand($command); // @param ApiCommandInterface $command
```
**After**
```php
use Guzzle\Service\Description\ServiceDescription;
$sd = new ServiceDescription();
$sd->getOperations(); // @returns OperationInterface[]
$sd->hasOperation($name);
$sd->getOperation($name); // @returns OperationInterface|null
$sd->addOperation($operation); // @param OperationInterface $operation
```
### Guzzle\Common\Inflection\Inflector
Namespace is now `Guzzle\Inflection\Inflector`
### Guzzle\Http\Plugin
Namespace is now `Guzzle\Plugin`. Many other changes occur within this namespace and are detailed in their own sections below.
### Guzzle\Http\Plugin\LogPlugin and Guzzle\Common\Log
Now `Guzzle\Plugin\Log\LogPlugin` and `Guzzle\Log` respectively.
**Before**
```php
use Guzzle\Common\Log\ClosureLogAdapter;
use Guzzle\Http\Plugin\LogPlugin;
/** @var \Guzzle\Http\Client */
$client;
// $verbosity is an integer indicating desired message verbosity level
$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $verbosity = LogPlugin::LOG_VERBOSE);
```
**After**
```php
use Guzzle\Log\ClosureLogAdapter;
use Guzzle\Log\MessageFormatter;
use Guzzle\Plugin\Log\LogPlugin;
/** @var \Guzzle\Http\Client */
$client;
// $format is a string indicating desired message format -- @see MessageFormatter
$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $format = MessageFormatter::DEBUG_FORMAT);
```
### Guzzle\Http\Plugin\CurlAuthPlugin
Now `Guzzle\Plugin\CurlAuth\CurlAuthPlugin`.
### Guzzle\Http\Plugin\ExponentialBackoffPlugin
Now `Guzzle\Plugin\Backoff\BackoffPlugin`, and other changes.
**Before**
```php
use Guzzle\Http\Plugin\ExponentialBackoffPlugin;
$backoffPlugin = new ExponentialBackoffPlugin($maxRetries, array_merge(
ExponentialBackoffPlugin::getDefaultFailureCodes(), array(429)
));
$client->addSubscriber($backoffPlugin);
```
**After**
```php
use Guzzle\Plugin\Backoff\BackoffPlugin;
use Guzzle\Plugin\Backoff\HttpBackoffStrategy;
// Use convenient factory method instead -- see implementation for ideas of what
// you can do with chaining backoff strategies
$backoffPlugin = BackoffPlugin::getExponentialBackoff($maxRetries, array_merge(
HttpBackoffStrategy::getDefaultFailureCodes(), array(429)
));
$client->addSubscriber($backoffPlugin);
```
### Known Issues
#### [BUG] Accept-Encoding header behavior changed unintentionally.
(See #217) (Fixed in 09daeb8c666fb44499a0646d655a8ae36456575e)
In version 2.8 setting the `Accept-Encoding` header would set the CURLOPT_ENCODING option, which permitted cURL to
properly handle gzip/deflate compressed responses from the server. In versions affected by this bug this does not happen.
See issue #217 for a workaround, or use a version containing the fix.

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="guzzle" default="test">
<!-- set local values, like git location -->
<property file="phing/build.properties.dist" override="true" />
<property file="phing/build.properties" override="true" />
<property name="dir.output" value="${project.basedir}/build/artifacts" />
<property name="dir.imports" value="${project.basedir}/phing/imports" />
<property name="dir.bin" value="${project.basedir}/bin" />
<property name="repo.dir" value="${project.basedir}" />
<import file="${dir.imports}/dependencies.xml"/>
<import file="${dir.imports}/deploy.xml"/>
<target name="composer-lint" description="lint-check composer.json only">
<composerlint dir="${project.basedir}/src" file="{$project.basedir}/composer.json" />
</target>
<target name="test" description="Run unit tests">
<exec passthru="true" command="vendor/bin/phpunit" checkReturn="true" />
</target>
<target name="build-init" description="Initialize local phing properties">
<copy file="phing/build.properties.dist" tofile="phing/build.properties" overwrite="false" />
</target>
<target name="clean">
<delete dir="${dir.output}"/>
<delete dir="${project.basedir}/build/pearwork"/>
</target>
<target name="prepare" depends="clean,build-init">
<mkdir dir="${dir.output}"/>
<mkdir dir="${dir.output}/logs" />
</target>
<target name="coverage" depends="prepare">
<exec passthru="true" command="vendor/bin/phpunit --coverage-html=${dir.output}/coverage" />
</target>
<target name="view-coverage">
<exec passthru="true" command="open ${dir.output}/coverage/index.html" />
</target>
</project>

View File

@ -1,82 +0,0 @@
{
"name": "guzzle/guzzle",
"type": "library",
"description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle",
"keywords": ["framework", "http", "rest", "web service", "curl", "client", "HTTP client"],
"homepage": "http://guzzlephp.org/",
"license": "MIT",
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Guzzle Community",
"homepage": "https://github.com/guzzle/guzzle/contributors"
}
],
"replace": {
"guzzle/batch": "self.version",
"guzzle/cache": "self.version",
"guzzle/common": "self.version",
"guzzle/http": "self.version",
"guzzle/inflection": "self.version",
"guzzle/iterator": "self.version",
"guzzle/log": "self.version",
"guzzle/parser": "self.version",
"guzzle/plugin": "self.version",
"guzzle/plugin-async": "self.version",
"guzzle/plugin-backoff": "self.version",
"guzzle/plugin-cache": "self.version",
"guzzle/plugin-cookie": "self.version",
"guzzle/plugin-curlauth": "self.version",
"guzzle/plugin-error-response": "self.version",
"guzzle/plugin-history": "self.version",
"guzzle/plugin-log": "self.version",
"guzzle/plugin-md5": "self.version",
"guzzle/plugin-mock": "self.version",
"guzzle/plugin-oauth": "self.version",
"guzzle/service": "self.version",
"guzzle/stream": "self.version"
},
"require": {
"php": ">=5.3.3",
"ext-curl": "*",
"symfony/event-dispatcher": "~2.1"
},
"autoload": {
"psr-0": {
"Guzzle": "src/",
"Guzzle\\Tests": "tests/"
}
},
"suggest": {
"guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated."
},
"scripts": {
"test": "phpunit"
},
"require-dev": {
"doctrine/cache": "~1.3",
"symfony/class-loader": "~2.1",
"monolog/monolog": "~1.0",
"psr/log": "~1.0",
"zendframework/zend-cache": "2.*,<2.3",
"zendframework/zend-log": "2.*,<2.3",
"phpunit/phpunit": "3.7.*"
},
"extra": {
"branch-alias": {
"dev-master": "3.9-dev"
}
}
}

View File

@ -1,153 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Guzzle.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Guzzle.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Guzzle"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Guzzle"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

View File

@ -1,176 +0,0 @@
{
"additionalProperties": true,
"name": {
"type": "string",
"description": "Name of the web service"
},
"apiVersion": {
"type": ["string", "number"],
"description": "Version identifier that the service description is compatible with"
},
"baseUrl": {
"type": "string",
"description": "Base URL of the web service. Any relative URI specified in an operation will be merged with the baseUrl using the process defined in RFC 2396"
},
"basePath": {
"type": "string",
"description": "Alias of baseUrl"
},
"_description": {
"type": "string",
"description": "Short summary of the web service. This is actually called 'description' but this JSON schema wont validate using just description."
},
"operations": {
"description": "Operations of the web service",
"type": "object",
"properties": {
"extends": {
"type": "string",
"description": "Extend from another operation by name. The parent operation must be defined before the child."
},
"httpMethod": {
"type": "string",
"description": "HTTP method used with the operation (e.g. GET, POST, PUT, DELETE, PATCH, etc)"
},
"uri": {
"type": "string",
"description": "URI of the operation. The uri attribute can contain URI templates. The variables of the URI template are parameters of the operation with a location value of uri"
},
"summary": {
"type": "string",
"description": "Short summary of what the operation does"
},
"class": {
"type": "string",
"description": "Custom class to instantiate instead of the default Guzzle\\Service\\Command\\OperationCommand"
},
"responseClass": {
"type": "string",
"description": "This is what is returned from the method. Can be a primitive, class name, or model name."
},
"responseNotes": {
"type": "string",
"description": "A description of the response returned by the operation"
},
"responseType": {
"type": "string",
"description": "The type of response that the operation creates. If not specified, this value will be automatically inferred based on whether or not there is a model matching the name, if a matching class name is found, or set to 'primitive' by default.",
"enum": [ "primitive", "class", "model", "documentation" ]
},
"deprecated": {
"type": "boolean",
"description": "Whether or not the operation is deprecated"
},
"errorResponses": {
"description": "Errors that could occur while executing the operation",
"type": "array",
"items": {
"type": "object",
"properties": {
"code": {
"type": "number",
"description": "HTTP response status code of the error"
},
"reason": {
"type": "string",
"description": "Response reason phrase or description of the error"
},
"class": {
"type": "string",
"description": "A custom exception class that would be thrown if the error is encountered"
}
}
}
},
"data": {
"type": "object",
"additionalProperties": "true"
},
"parameters": {
"$ref": "parameters",
"description": "Parameters of the operation. Parameters are used to define how input data is serialized into a HTTP request."
},
"additionalParameters": {
"$ref": "parameters",
"description": "Validation and serialization rules for any parameter supplied to the operation that was not explicitly defined."
}
}
},
"models": {
"description": "Schema models that can be referenced throughout the service description. Models can be used to define how an HTTP response is parsed into a Guzzle\\Service\\Resource\\Model object.",
"type": "object",
"properties": {
"$ref": "parameters",
"description": "Parameters of the model. When a model is referenced in a responseClass attribute of an operation, parameters define how a HTTP response message is parsed into a Guzzle\\Service\\Resource\\Model."
}
},
"includes": {
"description": "Service description files to include and extend from (can be a .json, .js, or .php file)",
"type": "array",
"items": {
"type": "string",
"pattern": ".+\\.(js|json|php)$"
}
},
"definitions": {
"parameters": {
"extends": "http://json-schema.org/schema",
"id": "parameters",
"name": {
"type": "string",
"description": "Unique name of the parameter"
},
"type": {
"type": ["string", "array"],
"description": "Type of variable (string, number, integer, boolean, object, array, numeric, null, any). Types are using for validation and determining the structure of a parameter. You can use a union type by providing an array of simple types. If one of the union types matches the provided value, then the value is valid."
},
"instanceOf": {
"type": "string",
"description": "When the type is an object, you can specify the class that the object must implement"
},
"required": {
"type": "boolean",
"description": "Whether or not the parameter is required"
},
"default": {
"description": "Default value to use if no value is supplied"
},
"static": {
"type": "bool",
"description": "Set to true to specify that the parameter value cannot be changed from the default setting"
},
"description": {
"type": "string",
"description": "Documentation of the parameter"
},
"location": {
"type": "string",
"description": "The location of a request used to apply a parameter. Custom locations can be registered with a command, but the defaults are uri, query, statusCode, reasonPhrase, header, body, json, xml, postField, postFile, responseBody"
},
"sentAs": {
"type": "string",
"description": "Specifies how the data being modeled is sent over the wire. For example, you may wish to include certain headers in a response model that have a normalized casing of FooBar, but the actual header is x-foo-bar. In this case, sentAs would be set to x-foo-bar."
},
"filters": {
"type": "array",
"description": "Array of static method names to to run a parameter value through. Each value in the array must be a string containing the full class path to a static method or an array of complex filter information. You can specify static methods of classes using the full namespace class name followed by :: (e.g. FooBar::baz()). Some filters require arguments in order to properly filter a value. For complex filters, use a hash containing a method key pointing to a static method, and an args key containing an array of positional arguments to pass to the method. Arguments can contain keywords that are replaced when filtering a value: '@value is replaced with the value being validated, '@api is replaced with the Parameter object.",
"items": {
"type": ["string", {
"object": {
"properties": {
"method": {
"type": "string",
"description": "PHP function to call",
"required": true
},
"args": {
"type": "array"
}
}
}
}]
}
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 803 B

View File

@ -1,122 +0,0 @@
/* Hero unit on homepage */
.hero-unit h1 {
font-size: 49px;
margin-bottom: 12px;
}
.hero-unit {
padding: 40px;
}
.hero-unit p {
font-size: 17px;
}
.masthead img {
float: left;
margin-right: 17px;
}
.hero-unit ul li {
margin-left: 220px;
}
.hero-unit .buttons {
text-align: center;
}
.jumbotron {
position: relative;
padding: 40px 0;
color: #fff;
text-shadow: 0 1px 3px rgba(0,0,0,.4), 0 0 30px rgba(0,0,0,.075);
background: #00312F;
background: -moz-linear-gradient(45deg, #002F31 0%, #335A6D 100%);
background: -webkit-gradient(linear, left bottom, right top, color-stop(0%,#00312D), color-stop(100%,#33566D));
background: -webkit-linear-gradient(45deg, #020031 0%,#334F6D 100%);
background: -o-linear-gradient(45deg, #002D31 0%,#334D6D 100%);
background: -ms-linear-gradient(45deg, #002F31 0%,#33516D 100%);
background: linear-gradient(45deg, #020031 0%,#33516D 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#020031', endColorstr='#6d3353',GradientType=1 );
-webkit-box-shadow: inset 0 3px 7px rgba(0, 0, 0, .2), inset 0 -3px 7px rgba(0, 0, 0, .2);
-moz-box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2);
box-shadow: inset 0 3px 7px rgba(0, 0, 0, .2), inset 0 -3px 7px rgba(0, 0, 0, .2);
}
.jumbotron h1 {
font-size: 80px;
font-weight: bold;
letter-spacing: -1px;
line-height: 1;
}
.jumbotron p {
font-size: 24px;
font-weight: 300;
line-height: 1.25;
margin-bottom: 30px;
}
.masthead {
padding: 40px 0 30px;
margin-bottom: 0;
color: #fff;
margin-top: -19px;
}
.masthead h1 {
display: none;
}
.masthead p {
font-size: 40px;
font-weight: 200;
line-height: 1.25;
margin: 12px 0 0 0;
}
.masthead .btn {
padding: 19px 24px;
font-size: 24px;
font-weight: 200;
border: 0;
}
/* Social bar on homepage */
.social {
padding: 2px 0;
text-align: center;
background-color: #f5f5f5;
border-top: 1px solid #fff;
border-bottom: 1px solid #ddd;
margin: 0 0 20px 0;
}
.social ul {
margin-top: 0;
}
.social-buttons {
margin-left: 0;
margin-bottom: 0;
padding-left: 0;
list-style: none;
}
.social-buttons li {
display: inline-block;
padding: 5px 8px;
line-height: 1;
*display: inline;
*zoom: 1;
}
.center-announcement {
padding: 10px;
background-color: rgb(238, 243, 255);
border-radius: 8px;
text-align: center;
margin: 24px 0;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

View File

@ -1,41 +0,0 @@
.com {
color: #93A1A1;
}
.lit {
color: #195F91;
}
.pun, .opn, .clo {
color: #93A1A1;
}
.fun {
color: #DC322F;
}
.str, .atv {
color: #DD1144;
}
.kwd, .linenums .tag {
color: #1E347B;
}
.typ, .atn, .dec, .var {
color: teal;
}
.pln {
color: #48484C;
}
.prettyprint {
background-color: #F7F7F9;
border: 1px solid #E1E1E8;
padding: 8px;
}
.prettyprint.linenums {
box-shadow: 40px 0 0 #FBFBFC inset, 41px 0 0 #ECECF0 inset;
}
ol.linenums {
margin: 0 0 0 33px;
}
ol.linenums li {
color: #BEBEC5;
line-height: 18px;
padding-left: 12px;
text-shadow: 0 1px 0 #FFFFFF;
}

View File

@ -1,28 +0,0 @@
var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();

View File

@ -1,106 +0,0 @@
<script type="text/javascript" src="{{ pathto('_static/prettify.js', 1) }}"></script>
<link rel="stylesheet" type="text/css" href="{{ pathto('_static/prettify.css', 1) }}" />
<link rel="stylesheet" type="text/css" href="{{ pathto('_static/homepage.css', 1) }}" />
<div class="jumbotron masthead">
<div class="container">
<img src="{{ pathto('_static/logo.png', 1) }}" alt="guzzle" width="199" height="260" />
<h1>Guzzle</h1>
<p>Guzzle is a PHP HTTP client<br />&amp; framework for building RESTful web service clients.</p>
<p>
<a class="btn btn-primary btn-lg" href="https://github.com/guzzle/guzzle">View Guzzle on GitHub</a>
<a class="btn btn-default btn-lg" href="{{ pathto('docs') }}">Read the docs</a>
</p>
</div>
</div>
<div class="social">
<ul class="social-buttons">
<li>
<iframe src="http://ghbtns.com/github-btn.html?user=guzzle&repo=guzzle&type=watch&count=true"
allowtransparency="true" frameborder="0" scrolling="0" width="110" height="20"></iframe>
</li>
<li>
<a href="https://twitter.com/share" class="twitter-share-button" data-url="http://guzzlephp.org" data-text="Guzzle, PHP HTTP client &amp; framework for building RESTful web service clients" data-via="mtdowling">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="http://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
</li>
<li>
<a href="https://twitter.com/mtdowling" class="twitter-follow-button" data-show-count="false">Follow @mtdowling</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="http://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
</li>
</ul>
</div>
<div class="container">
<h1>Introducing Guzzle</h1>
<p>Guzzle takes the pain out of sending HTTP requests and the redundancy out of creating web service clients. It's
a framework that includes the tools needed to create a robust web service client, including:
Service descriptions for defining the inputs and outputs of an API, resource iterators for traversing
paginated resources, batching for sending a large number of requests as efficiently as possible.</p>
<ul>
<li>All the power of cURL with a simple interface.</li>
<li>Persistent connections and parallel requests.</li>
<li>Streams request and response bodies</li>
<li><a href="{{ pathto('webservice-client/guzzle-service-descriptions') }}">Service descriptions</a> for quickly building clients.</li>
<li>Powered by the Symfony2 EventDispatcher.</li>
<li>Use all of the code or only <a href="https://packagist.org/packages/guzzle/">specific components</a>.</li>
<li><a href="{{ pathto('plugins/plugins-overview') }}">Plugins</a> for caching, logging, OAuth, mocks, and more</li>
<li>Includes a custom node.js webserver to <a href="{{ pathto('testing/unit-testing') }}">test your clients</a>.</li>
</ul>
<div class="center-announcement">
Guzzle is now part of Drupal 8 core and powers the official <a href="https://github.com/aws/aws-sdk-php">AWS SDK for PHP</a>
</div>
<h2>GitHub Example</h2>
<pre class="prettyprint">&lt;?php
require_once 'vendor/autoload.php';
use Guzzle\Http\Client;
// Create a client and provide a base URL
$client = new Client('https://api.github.com');
// Create a request with basic Auth
$request = $client->get('/user')->setAuth('user', 'pass');
// Send the request and get the response
$response = $request->send();
echo $response->getBody();
// >>> {"type":"User", ...
echo $response->getHeader('Content-Length');
// >>> 792
</pre>
<h2>Twitter Example</h2>
<pre class="prettyprint">&lt;?php
// Create a client to work with the Twitter API
$client = new Client('https://api.twitter.com/{version}', array(
'version' => '1.1'
));
// Sign all requests with the OauthPlugin
$client->addSubscriber(new Guzzle\Plugin\Oauth\OauthPlugin(array(
'consumer_key' => '***',
'consumer_secret' => '***',
'token' => '***',
'token_secret' => '***'
)));
echo $client->get('statuses/user_timeline.json')->send()->getBody();
// >>> {"public_gists":6,"type":"User" ...
// Create a tweet using POST
$request = $client->post('statuses/update.json', null, array(
'status' => 'Tweeted with Guzzle, http://guzzlephp.org'
));
// Send the request and parse the JSON response into an array
$data = $request->send()->json();
echo $data['text'];
// >>> Tweeted with Guzzle, http://t.co/kngJMfRk
</pre>
</div>
<script type="text/javascript">prettyPrint();</script>

View File

@ -1,5 +0,0 @@
<li><a href="{{ pathto('docs') }}">Docs</a></li>
<li><a href="http://guzzlephp.org/api/index.html">API</a></li>
<li><a href="https://github.com/guzzle/guzzle">GitHub</a></li>
<li><a href="https://groups.google.com/forum/?hl=en#!forum/guzzle">Forum</a></li>
<li><a href="irc:irc.freenode.com/#guzzlephp">IRC</a></li>

View File

@ -1,183 +0,0 @@
========
Batching
========
Guzzle provides a fairly generic and very customizable batching framework that allows developers to efficiently
transfer requests in parallel.
Sending requests and commands in parallel
-----------------------------------------
You can send HTTP requests in parallel by passing an array of ``Guzzle\Http\Message\RequestInterface`` objects to
``Guzzle\Http\Client::send()``:
.. code-block:: php
$responses = $client->send(array(
$client->get('http://www.example.com/foo'),
$client->get('http://www.example.com/baz')
$client->get('http://www.example.com/bar')
));
You can send commands in parallel by passing an array of ``Guzzle\Service\Command\CommandInterface`` objects
``Guzzle\Service\Client::execute()``:
.. code-block:: php
$commands = $client->execute(array(
$client->getCommand('foo'),
$client->getCommand('baz'),
$client->getCommand('bar')
));
These approaches work well for most use-cases. When you need more control over the requests that are sent in
parallel or you need to send a large number of requests, you need to use the functionality provided in the
``Guzzle\Batch`` namespace.
Batching overview
-----------------
The batch object, ``Guzzle\Batch\Batch``, is a queue. You add requests to the queue until you are ready to transfer
all of the requests. In order to efficiently transfer the items in the queue, the batch object delegates the
responsibility of dividing the queue into manageable parts to a divisor (``Guzzle\Batch\BatchDivisorInterface``).
The batch object then iterates over each array of items created by the divisor and sends them to the batch object's
``Guzzle\Batch\BatchTransferInterface``.
.. code-block:: php
use Guzzle\Batch\Batch;
use Guzzle\Http\BatchRequestTransfer;
// BatchRequestTransfer acts as both the divisor and transfer strategy
$transferStrategy = new BatchRequestTransfer(10);
$divisorStrategy = $transferStrategy;
$batch = new Batch($transferStrategy, $divisorStrategy);
// Add some requests to the batch queue
$batch->add($request1)
->add($request2)
->add($request3);
// Flush the queue and retrieve the flushed items
$arrayOfTransferredRequests = $batch->flush();
.. note::
You might find that your transfer strategy will need to act as both the divisor and transfer strategy.
Using the BatchBuilder
----------------------
The ``Guzzle\Batch\BatchBuilder`` makes it easier to create batch objects. The batch builder also provides an easier
way to add additional behaviors to your batch object.
Transferring requests
~~~~~~~~~~~~~~~~~~~~~
The ``Guzzle\Http\BatchRequestTransfer`` class efficiently transfers HTTP requests in parallel by grouping batches of
requests by the curl_multi handle that is used to transfer the requests.
.. code-block:: php
use Guzzle\Batch\BatchBuilder;
$batch = BatchBuilder::factory()
->transferRequests(10)
->build();
Transferring commands
~~~~~~~~~~~~~~~~~~~~~
The ``Guzzle\Service\Command\BatchCommandTransfer`` class efficiently transfers service commands by grouping commands
by the client that is used to transfer them. You can add commands to a batch object that are transferred by different
clients, and the batch will handle the rest.
.. code-block:: php
use Guzzle\Batch\BatchBuilder;
$batch = BatchBuilder::factory()
->transferCommands(10)
->build();
$batch->add($client->getCommand('foo'))
->add($client->getCommand('baz'))
->add($client->getCommand('bar'));
$commands = $batch->flush();
Batch behaviors
---------------
You can add various behaviors to your batch that allow for more customizable transfers.
Automatically flushing a queue
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use the ``Guzzle\Batch\FlushingBatch`` decorator when you want to pump a large number of items into a batch queue and
have the queue automatically flush when the size of the queue reaches a certain threshold.
.. code-block:: php
use Guzzle\Batch\BatchBuilder;
$batch = BatchBuilder::factory()
->transferRequests(10)
->autoFlushAt(10)
->build();
Batch builder method: ``autoFlushAt($threshold)``
Notifying on flush
~~~~~~~~~~~~~~~~~~
Use the ``Guzzle\Batch\NotifyingBatch`` decorator if you want a function to be notified each time the batch queue is
flushed. This is useful when paired with the flushing batch decorator. Pass a callable to the ``notify()`` method of
a batch builder to use this decorator with the builder.
.. code-block:: php
use Guzzle\Batch\BatchBuilder;
$batch = BatchBuilder::factory()
->transferRequests(10)
->autoFlushAt(10)
->notify(function (array $transferredItems) {
echo 'Transferred ' . count($transferredItems) . "items\n";
})
->build();
Batch builder method:: ``notify(callable $callback)``
Keeping a history
~~~~~~~~~~~~~~~~~
Use the ``Guzzle\Batch\HistoryBatch`` decorator if you want to maintain a history of all the items transferred with
the batch queue.
.. code-block:: php
use Guzzle\Batch\BatchBuilder;
$batch = BatchBuilder::factory()
->transferRequests(10)
->keepHistory()
->build();
After transferring items, you can use the ``getHistory()`` of a batch to retrieve an array of transferred items. Be
sure to periodically clear the history using ``clearHistory()``.
Batch builder method: ``keepHistory()``
Exception buffering
~~~~~~~~~~~~~~~~~~~
Use the ``Guzzle\Batch\ExceptionBufferingBatch`` decorator to buffer exceptions during a transfer so that you can
transfer as many items as possible then deal with the errored batches after the transfer completes. After transfer,
use the ``getExceptions()`` method of a batch to retrieve an array of
``Guzzle\Batch\Exception\BatchTransferException`` objects. You can use these exceptions to attempt to retry the
failed batches. Be sure to clear the buffered exceptions when you are done with them by using the
``clearExceptions()`` method.
Batch builder method: ``bufferExceptions()``

View File

@ -1,94 +0,0 @@
import sys, os
from sphinx.highlighting import lexers
from pygments.lexers.web import PhpLexer
lexers['php'] = PhpLexer(startinline=True, linenos=1)
lexers['php-annotations'] = PhpLexer(startinline=True, linenos=1)
primary_domain = 'php'
# -- General configuration -----------------------------------------------------
extensions = []
templates_path = ['_templates']
source_suffix = '.rst'
master_doc = 'index'
project = u'Guzzle'
copyright = u'2012, Michael Dowling'
version = '3.0.0'
release = '3.0.0'
exclude_patterns = ['_build']
# -- Options for HTML output ---------------------------------------------------
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
html_title = "Guzzle documentation"
html_short_title = "Guzzle"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, maps document names to template names.
html_sidebars = {
'**': ['localtoc.html', 'leftbar.html', 'searchbox.html']
}
# Output file base name for HTML help builder.
htmlhelp_basename = 'Guzzledoc'
# -- Guzzle Sphinx theme setup ------------------------------------------------
sys.path.insert(0, '/Users/dowling/projects/guzzle_sphinx_theme')
import guzzle_sphinx_theme
html_translator_class = 'guzzle_sphinx_theme.HTMLTranslator'
html_theme_path = guzzle_sphinx_theme.html_theme_path()
html_theme = 'guzzle_sphinx_theme'
# Guzzle theme options (see theme.conf for more information)
html_theme_options = {
"index_template": "index.html",
"project_nav_name": "Guzzle",
"github_user": "guzzle",
"github_repo": "guzzle",
"disqus_comments_shortname": "guzzle",
"google_analytics_account": "UA-22752917-1"
}
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'Guzzle.tex', u'Guzzle Documentation',
u'Michael Dowling', 'manual'),
]
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'guzzle', u'Guzzle Documentation',
[u'Michael Dowling'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'Guzzle', u'Guzzle Documentation',
u'Michael Dowling', 'Guzzle', 'One line description of project.',
'Miscellaneous'),
]

View File

@ -1,73 +0,0 @@
.. title:: Guzzle | PHP HTTP client and framework for consuming RESTful web services
====================
Guzzle Documentation
====================
Getting started
---------------
.. toctree::
:maxdepth: 1
getting-started/overview
getting-started/installation
getting-started/faq
The HTTP client
---------------
.. toctree::
:maxdepth: 2
http-client/client
http-client/request
http-client/response
http-client/entity-bodies
http-client/http-redirects
http-client/uri-templates
Plugins
-------
.. toctree::
:maxdepth: 1
plugins/plugins-overview
plugins/creating-plugins
plugins/async-plugin
plugins/backoff-plugin
plugins/cache-plugin
plugins/cookie-plugin
plugins/curl-auth-plugin
plugins/history-plugin
plugins/log-plugin
plugins/md5-validator-plugin
plugins/mock-plugin
plugins/oauth-plugin
The web service client
----------------------
.. toctree::
:maxdepth: 1
webservice-client/webservice-client
webservice-client/using-the-service-builder
webservice-client/guzzle-service-descriptions
batching/batching
iterators/resource-iterators
iterators/guzzle-iterators
Testing
-------
.. toctree::
:maxdepth: 2
testing/unit-testing
API Docs
--------
`Read the API docs <http://guzzlephp.org/api/index.html>`_

View File

@ -1,29 +0,0 @@
===
FAQ
===
What should I do if I get this error: Fatal error: Maximum function nesting level of '100' reached, aborting!
-------------------------------------------------------------------------------------------------------------
You could run into this error if you have the XDebug extension installed and you execute a lot of requests in
callbacks. This error message comes specifically from the XDebug extension. PHP itself does not have a function
nesting limit. Change this setting in your php.ini to increase the limit::
xdebug.max_nesting_level = 1000
[`source <http://stackoverflow.com/a/4293870/151504>`_]
How can I speed up my client?
-----------------------------
There are several things you can do to speed up your client:
1. Utilize a C based HTTP message parser (e.g. ``Guzzle\Parser\Message\PeclHttpMessageParser``)
2. Disable operation validation by setting the ``command.disable_validation`` option to true on a command
Why am I getting a 417 error response?
--------------------------------------
This can occur for a number of reasons, but if you are sending PUT, POST, or PATCH requests with an
``Expect: 100-Continue`` header, a server that does not support this header will return a 417 response. You can work
around this by calling ``$request->removeHeader('Expect');`` after setting the entity body of a request.

View File

@ -1,154 +0,0 @@
============
Installation
============
Requirements
------------
#. PHP 5.3.3+ compiled with the cURL extension
#. A recent version of cURL 7.16.2+ compiled with OpenSSL and zlib
Installing Guzzle
-----------------
Composer
~~~~~~~~
The recommended way to install Guzzle is with `Composer <http://getcomposer.org>`_. Composer is a dependency
management tool for PHP that allows you to declare the dependencies your project needs and installs them into your
project.
.. code-block:: bash
# Install Composer
curl -sS https://getcomposer.org/installer | php
# Add Guzzle as a dependency
php composer.phar require guzzle/guzzle:~3.9
After installing, you need to require Composer's autoloader:
.. code-block:: php
require 'vendor/autoload.php';
You can find out more on how to install Composer, configure autoloading, and other best-practices for defining
dependencies at `getcomposer.org <http://getcomposer.org>`_.
Using only specific parts of Guzzle
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
While you can always just rely on ``guzzle/guzzle``, Guzzle provides several smaller parts of Guzzle as individual
packages available through Composer.
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| Package name | Description |
+===============================================================================================+==========================================+
| `guzzle/common <https://packagist.org/packages/guzzle/common>`_ | Provides ``Guzzle\Common`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/http <https://packagist.org/packages/guzzle/http>`_ | Provides ``Guzzle\Http`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/parser <https://packagist.org/packages/guzzle/parser>`_ | Provides ``Guzzle\Parser`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/batch <https://packagist.org/packages/guzzle/batch>`_ | Provides ``Guzzle\Batch`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/cache <https://packagist.org/packages/guzzle/cache>`_ | Provides ``Guzzle\Cache`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/inflection <https://packagist.org/packages/guzzle/inflection>`_ | Provides ``Guzzle\Inflection`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/iterator <https://packagist.org/packages/guzzle/iterator>`_ | Provides ``Guzzle\Iterator`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/log <https://packagist.org/packages/guzzle/log>`_ | Provides ``Guzzle\Log`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/plugin <https://packagist.org/packages/guzzle/plugin>`_ | Provides ``Guzzle\Plugin`` (all plugins) |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/plugin-async <https://packagist.org/packages/guzzle/plugin-async>`_ | Provides ``Guzzle\Plugin\Async`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/plugin-backoff <https://packagist.org/packages/guzzle/plugin-backoff>`_ | Provides ``Guzzle\Plugin\BackoffPlugin`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/plugin-cache <https://packagist.org/packages/guzzle/plugin-cache>`_ | Provides ``Guzzle\Plugin\Cache`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/plugin-cookie <https://packagist.org/packages/guzzle/plugin-cookie>`_ | Provides ``Guzzle\Plugin\Cookie`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/plugin-error-response <https://packagist.org/packages/guzzle/plugin-error-response>`_ | Provides ``Guzzle\Plugin\ErrorResponse`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/plugin-history <https://packagist.org/packages/guzzle/plugin-history>`_ | Provides ``Guzzle\Plugin\History`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/plugin-log <https://packagist.org/packages/guzzle/plugin-log>`_ | Provides ``Guzzle\Plugin\Log`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/plugin-md5 <https://packagist.org/packages/guzzle/plugin-md5>`_ | Provides ``Guzzle\Plugin\Md5`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/plugin-mock <https://packagist.org/packages/guzzle/plugin-mock>`_ | Provides ``Guzzle\Plugin\Mock`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/plugin-oauth <https://packagist.org/packages/guzzle/plugin-oauth>`_ | Provides ``Guzzle\Plugin\Oauth`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/service <https://packagist.org/packages/guzzle/service>`_ | Provides ``Guzzle\Service`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
| `guzzle/stream <https://packagist.org/packages/guzzle/stream>`_ | Provides ``Guzzle\Stream`` |
+-----------------------------------------------------------------------------------------------+------------------------------------------+
Bleeding edge
^^^^^^^^^^^^^
During your development, you can keep up with the latest changes on the master branch by setting the version
requirement for Guzzle to ``dev-master``.
.. code-block:: js
{
"require": {
"guzzle/guzzle": "dev-master"
}
}
PEAR
~~~~
Guzzle can be installed through PEAR:
.. code-block:: bash
pear channel-discover guzzlephp.org/pear
pear install guzzle/guzzle
You can install a specific version of Guzzle by providing a version number suffix:
.. code-block:: bash
pear install guzzle/guzzle-3.9.0
Contributing to Guzzle
----------------------
In order to contribute, you'll need to checkout the source from GitHub and install Guzzle's dependencies using
Composer:
.. code-block:: bash
git clone https://github.com/guzzle/guzzle.git
cd guzzle && curl -s http://getcomposer.org/installer | php && ./composer.phar install --dev
Guzzle is unit tested with PHPUnit. You will need to create your own phpunit.xml file in order to run the unit tests
(or just copy phpunit.xml.dist to phpunit.xml). Run the tests using the vendored PHPUnit binary:
.. code-block:: bash
vendor/bin/phpunit
You'll need to install node.js v0.5.0 or newer in order to test the cURL implementation.
Framework integrations
----------------------
Using Guzzle with Symfony
~~~~~~~~~~~~~~~~~~~~~~~~~
Bundles are available on GitHub:
- `DdeboerGuzzleBundle <https://github.com/ddeboer/GuzzleBundle>`_ for Guzzle 2
- `MisdGuzzleBundle <https://github.com/misd-service-development/guzzle-bundle>`_ for Guzzle 3
Using Guzzle with Silex
~~~~~~~~~~~~~~~~~~~~~~~
A `Guzzle Silex service provider <https://github.com/guzzle/guzzle-silex-extension>`_ is available on GitHub.

View File

@ -1,85 +0,0 @@
=================
Welcome to Guzzle
=================
What is Guzzle?
~~~~~~~~~~~~~~~
Guzzle is a PHP HTTP client and framework for building web service clients. Guzzle takes the pain out of sending HTTP
requests and the redundancy out of creating web service clients.
Features at a glance
--------------------
- All the power of cURL with a simple interface.
- Persistent connections and parallel requests.
- Streams request and response bodies
- Service descriptions for quickly building clients.
- Powered by the Symfony2 EventDispatcher.
- Use all of the code or only specific components.
- Plugins for caching, logging, OAuth, mocks, and more
- Includes a custom node.js webserver to test your clients.
- Service descriptions for defining the inputs and outputs of an API
- Resource iterators for traversing paginated resources
- Batching for sending a large number of requests as efficiently as possible
.. code-block:: php
// Really simple using a static facade
Guzzle\Http\StaticClient::mount();
$response = Guzzle::get('http://guzzlephp.org');
// More control using a client class
$client = new \Guzzle\Http\Client('http://guzzlephp.org');
$request = $client->get('/');
$response = $request->send();
License
-------
Licensed using the `MIT license <http://opensource.org/licenses/MIT>`_.
Copyright (c) 2013 Michael Dowling <https://github.com/mtdowling>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Contributing
------------
Guidelines
~~~~~~~~~~
This is still a work in progress, but there are only a few rules:
1. Guzzle follows PSR-0, PSR-1, and PSR-2
2. All pull requests must include unit tests to ensure the change works as expected and to prevent future regressions
Reporting a security vulnerability
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We want to ensure that Guzzle is a secure HTTP client library for everyone. If you've discovered a security
vulnerability in Guzzle, we appreciate your help in disclosing it to us in a
`responsible manner <http://en.wikipedia.org/wiki/Responsible_disclosure>`_.
Publicly disclosing a vulnerability can put the entire community at risk. If you've discovered a security concern,
please email us at security@guzzlephp.org. We'll work with you to make sure that we understand the scope of the issue,
and that we fully address your concern. We consider correspondence sent to security@guzzlephp.org our highest priority,
and work to address any issues that arise as quickly as possible.
After a security vulnerability has been corrected, a security hotfix release will be deployed as soon as possible.

View File

@ -1,569 +0,0 @@
======================
The Guzzle HTTP client
======================
Guzzle gives PHP developers complete control over HTTP requests while utilizing HTTP/1.1 best practices. Guzzle's HTTP
functionality is a robust framework built on top of the `PHP libcurl bindings <http://www.php.net/curl>`_.
The three main parts of the Guzzle HTTP client are:
+--------------+-------------------------------------------------------------------------------------------------------+
| Clients | ``Guzzle\Http\Client`` (creates and sends requests, associates a response with a request) |
+--------------+-------------------------------------------------------------------------------------------------------+
| Requests | ``Guzzle\Http\Message\Request`` (requests with no body), |
| | ``Guzzle\Http\Message\EntityEnclosingRequest`` (requests with a body) |
+--------------+-------------------------------------------------------------------------------------------------------+
| Responses | ``Guzzle\Http\Message\Response`` |
+--------------+-------------------------------------------------------------------------------------------------------+
Creating a Client
-----------------
Clients create requests, send requests, and set responses on a request object. When instantiating a client object,
you can pass an optional "base URL" and optional array of configuration options. A base URL is a
:doc:`URI template <uri-templates>` that contains the URL of a remote server. When creating requests with a relative
URL, the base URL of a client will be merged into the request's URL.
.. code-block:: php
use Guzzle\Http\Client;
// Create a client and provide a base URL
$client = new Client('https://api.github.com');
$request = $client->get('/user');
$request->setAuth('user', 'pass');
echo $request->getUrl();
// >>> https://api.github.com/user
// You must send a request in order for the transfer to occur
$response = $request->send();
echo $response->getBody();
// >>> {"type":"User", ...
echo $response->getHeader('Content-Length');
// >>> 792
$data = $response->json();
echo $data['type'];
// >>> User
Base URLs
~~~~~~~~~
Notice that the URL provided to the client's ``get()`` method is relative. Relative URLs will always merge into the
base URL of the client. There are a few rules that control how the URLs are merged.
.. tip::
Guzzle follows `RFC 3986 <http://tools.ietf.org/html/rfc3986#section-5.2>`_ when merging base URLs and
relative URLs.
In the above example, we passed ``/user`` to the ``get()`` method of the client. This is a relative URL, so it will
merge into the base URL of the client-- resulting in the derived URL of ``https://api.github.com/users``.
``/user`` is a relative URL but uses an absolute path because it contains the leading slash. Absolute paths will
overwrite any existing path of the base URL. If an absolute path is provided (e.g. ``/path/to/something``), then the
path specified in the base URL of the client will be replaced with the absolute path, and the query string provided
by the relative URL will replace the query string of the base URL.
Omitting the leading slash and using relative paths will add to the path of the base URL of the client. So using a
client base URL of ``https://api.twitter.com/v1.1`` and creating a GET request with ``statuses/user_timeline.json``
will result in a URL of ``https://api.twitter.com/v1.1/statuses/user_timeline.json``. If a relative path and a query
string are provided, then the relative path will be appended to the base URL path, and the query string provided will
be merged into the query string of the base URL.
If an absolute URL is provided (e.g. ``http://httpbin.org/ip``), then the request will completely use the absolute URL
as-is without merging in any of the URL parts specified in the base URL.
Configuration options
~~~~~~~~~~~~~~~~~~~~~
The second argument of the client's constructor is an array of configuration data. This can include URI template data
or special options that alter the client's behavior:
+-------------------------------+-------------------------------------------------------------------------------------+
| ``request.options`` | Associative array of :ref:`Request options <request-options>` to apply to every |
| | request created by the client. |
+-------------------------------+-------------------------------------------------------------------------------------+
| ``redirect.disable`` | Disable HTTP redirects for every request created by the client. |
+-------------------------------+-------------------------------------------------------------------------------------+
| ``curl.options`` | Associative array of cURL options to apply to every request created by the client. |
| | if either the key or value of an entry in the array is a string, Guzzle will |
| | attempt to find a matching defined cURL constant automatically (e.g. |
| | "CURLOPT_PROXY" will be converted to the constant ``CURLOPT_PROXY``). |
+-------------------------------+-------------------------------------------------------------------------------------+
| ``ssl.certificate_authority`` | Set to true to use the Guzzle bundled SSL certificate bundle (this is used by |
| | default, 'system' to use the bundle on your system, a string pointing to a file to |
| | use a specific certificate file, a string pointing to a directory to use multiple |
| | certificates, or ``false`` to disable SSL validation (not recommended). |
| | |
| | When using Guzzle inside of a phar file, the bundled SSL certificate will be |
| | extracted to your system's temp folder, and each time a client is created an MD5 |
| | check will be performed to ensure the integrity of the certificate. |
+-------------------------------+-------------------------------------------------------------------------------------+
| ``command.params`` | When using a ``Guzzle\Service\Client`` object, this is an associative array of |
| | default options to set on each command created by the client. |
+-------------------------------+-------------------------------------------------------------------------------------+
Here's an example showing how to set various configuration options, including default headers to send with each request,
default query string parameters to add to each request, a default auth scheme for each request, and a proxy to use for
each request. Values can be injected into the client's base URL using variables from the configuration array.
.. code-block:: php
use Guzzle\Http\Client;
$client = new Client('https://api.twitter.com/{version}', array(
'version' => 'v1.1',
'request.options' => array(
'headers' => array('Foo' => 'Bar'),
'query' => array('testing' => '123'),
'auth' => array('username', 'password', 'Basic|Digest|NTLM|Any'),
'proxy' => 'tcp://localhost:80'
)
));
Setting a custom User-Agent
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The default Guzzle User-Agent header is ``Guzzle/<Guzzle_Version> curl/<curl_version> PHP/<PHP_VERSION>``. You can
customize the User-Agent header of a client by calling the ``setUserAgent()`` method of a Client object.
.. code-block:: php
// Completely override the default User-Agent
$client->setUserAgent('Test/123');
// Prepend a string to the default User-Agent
$client->setUserAgent('Test/123', true);
Creating requests with a client
-------------------------------
A Client object exposes several methods used to create Request objects:
* Create a custom HTTP request: ``$client->createRequest($method, $uri, array $headers, $body, $options)``
* Create a GET request: ``$client->get($uri, array $headers, $options)``
* Create a HEAD request: ``$client->head($uri, array $headers, $options)``
* Create a DELETE request: ``$client->delete($uri, array $headers, $body, $options)``
* Create a POST request: ``$client->post($uri, array $headers, $postBody, $options)``
* Create a PUT request: ``$client->put($uri, array $headers, $body, $options)``
* Create a PATCH request: ``$client->patch($uri, array $headers, $body, $options)``
.. code-block:: php
use Guzzle\Http\Client;
$client = new Client('http://baseurl.com/api/v1');
// Create a GET request using Relative to base URL
// URL of the request: http://baseurl.com/api/v1/path?query=123&value=abc)
$request = $client->get('path?query=123&value=abc');
$response = $request->send();
// Create HEAD request using a relative URL with an absolute path
// URL of the request: http://baseurl.com/path?query=123&value=abc
$request = $client->head('/path?query=123&value=abc');
$response = $request->send();
// Create a DELETE request using an absolute URL
$request = $client->delete('http://www.example.com/path?query=123&value=abc');
$response = $request->send();
// Create a PUT request using the contents of a PHP stream as the body
// Specify custom HTTP headers
$request = $client->put('http://www.example.com/upload', array(
'X-Header' => 'My Header'
), fopen('http://www.test.com/', 'r'));
$response = $request->send();
// Create a POST request and add the POST files manually
$request = $client->post('http://localhost:8983/solr/update')
->addPostFiles(array('file' => '/path/to/documents.xml'));
$response = $request->send();
// Check if a resource supports the DELETE method
$supportsDelete = $client->options('/path')->send()->isMethodAllowed('DELETE');
$response = $request->send();
Client objects create Request objects using a request factory (``Guzzle\Http\Message\RequestFactoryInterface``).
You can inject a custom request factory into the Client using ``$client->setRequestFactory()``, but you can typically
rely on a Client's default request factory.
Static clients
--------------
You can use Guzzle's static client facade to more easily send simple HTTP requests.
.. code-block:: php
// Mount the client so that you can access it at \Guzzle
Guzzle\Http\StaticClient::mount();
$response = Guzzle::get('http://guzzlephp.org');
Each request method of the static client (e.g. ``get()``, ``post()`, ``put()``, etc) accepts an associative array of request
options to apply to the request.
.. code-block:: php
$response = Guzzle::post('http://test.com', array(
'headers' => array('X-Foo' => 'Bar'),
'body' => array('Test' => '123'),
'timeout' => 10
));
.. _request-options:
Request options
---------------
Request options can be specified when creating a request or in the ``request.options`` parameter of a client. These
options can control various aspects of a request including: headers to send, query string data, where the response
should be downloaded, proxies, auth, etc.
headers
~~~~~~~
Associative array of headers to apply to the request. When specified in the ``$options`` argument of a client creational
method (e.g. ``get()``, ``post()``, etc), the headers in the ``$options`` array will overwrite headers specified in the
``$headers`` array.
.. code-block:: php
$request = $client->get($url, array(), array(
'headers' => array('X-Foo' => 'Bar')
));
Headers can be specified on a client to add default headers to every request sent by a client.
.. code-block:: php
$client = new Guzzle\Http\Client();
// Set a single header using path syntax
$client->setDefaultOption('headers/X-Foo', 'Bar');
// Set all headers
$client->setDefaultOption('headers', array('X-Foo' => 'Bar'));
.. note::
In addition to setting request options when creating requests or using the ``setDefaultOption()`` method, any
default client request option can be set using a client's config object:
.. code-block:: php
$client->getConfig()->setPath('request.options/headers/X-Foo', 'Bar');
query
~~~~~
Associative array of query string parameters to the request. When specified in the ``$options`` argument of a client
creational method, the query string parameters in the ``$options`` array will overwrite query string parameters
specified in the `$url`.
.. code-block:: php
$request = $client->get($url, array(), array(
'query' => array('abc' => '123')
));
Query string parameters can be specified on a client to add default query string parameters to every request sent by a
client.
.. code-block:: php
$client = new Guzzle\Http\Client();
// Set a single query string parameter using path syntax
$client->setDefaultOption('query/abc', '123');
// Set an array of default query string parameters
$client->setDefaultOption('query', array('abc' => '123'));
body
~~~~
Sets the body of a request. The value supplied to the body option can be a ``Guzzle\Http\EntityBodyInterface``, string,
fopen resource, or array when sending POST requests. When a ``body`` request option is supplied, the option value will
overwrite the ``$body`` argument of a client creational method.
auth
~~~~
Specifies and array of HTTP authorization parameters parameters to use with the request. The array must contain the
username in index [0], the password in index [1], and can optionally contain the authentication type in index [2].
The available authentication types are: "Basic" (default), "Digest", "NTLM", or "Any".
.. code-block:: php
$request = $client->get($url, array(), array(
'auth' => array('username', 'password', 'Digest')
));
// You can add auth headers to every request of a client
$client->setDefaultOption('auth', array('username', 'password', 'Digest'));
cookies
~~~~~~~
Specifies an associative array of cookies to add to the request.
allow_redirects
~~~~~~~~~~~~~~~
Specifies whether or not the request should follow redirects. Requests will follow redirects by default. Set
``allow_redirects`` to ``false`` to disable redirects.
save_to
~~~~~~~
The ``save_to`` option specifies where the body of a response is downloaded. You can pass the path to a file, an fopen
resource, or a ``Guzzle\Http\EntityBodyInterface`` object.
See :ref:`Changing where a response is downloaded <request-set-response-body>` for more information on setting the
`save_to` option.
events
~~~~~~
The `events` option makes it easy to attach listeners to the various events emitted by a request object. The `events`
options must be an associative array mapping an event name to a Closure or array the contains a Closure and the
priority of the event.
.. code-block:: php
$request = $client->get($url, array(), array(
'events' => array(
'request.before_send' => function (\Guzzle\Common\Event $e) {
echo 'About to send ' . $e['request'];
}
)
));
// Using the static client:
Guzzle::get($url, array(
'events' => array(
'request.before_send' => function (\Guzzle\Common\Event $e) {
echo 'About to send ' . $e['request'];
}
)
));
plugins
~~~~~~~
The `plugins` options makes it easy to attach an array of plugins to a request.
.. code-block:: php
// Using the static client:
Guzzle::get($url, array(
'plugins' => array(
new Guzzle\Plugin\Cache\CachePlugin(),
new Guzzle\Plugin\Cookie\CookiePlugin()
)
));
exceptions
~~~~~~~~~~
The `exceptions` option can be used to disable throwing exceptions for unsuccessful HTTP response codes
(e.g. 404, 500, etc). Set `exceptions` to false to not throw exceptions.
params
~~~~~~
The `params` options can be used to specify an associative array of data parameters to add to a request. Note that
these are not query string parameters.
timeout / connect_timeout
~~~~~~~~~~~~~~~~~~~~~~~~~
You can specify the maximum number of seconds to allow for an entire transfer to take place before timing out using
the `timeout` request option. You can specify the maximum number of seconds to wait while trying to connect using the
`connect_timeout` request option. Set either of these options to 0 to wait indefinitely.
.. code-block:: php
$request = $client->get('http://www.example.com', array(), array(
'timeout' => 20,
'connect_timeout' => 1.5
));
verify
~~~~~~
Set to true to enable SSL certificate validation (the default), false to disable SSL certificate validation, or supply
the path to a CA bundle to enable verification using a custom certificate.
cert
~~~~
The `cert` option lets you specify a PEM formatted SSL client certificate to use with servers that require one. If the
certificate requires a password, provide an array with the password as the second item.
This would typically be used in conjunction with the `ssl_key` option.
.. code-block:: php
$request = $client->get('https://www.example.com', array(), array(
'cert' => '/etc/pki/client_certificate.pem'
)
$request = $client->get('https://www.example.com', array(), array(
'cert' => array('/etc/pki/client_certificate.pem', 's3cr3tp455w0rd')
)
ssl_key
~~~~~~~
The `ssl_key` option lets you specify a file containing your PEM formatted private key, optionally protected by a password.
Note: your password is sensitive, keep the PHP script containing it safe.
This would typically be used in conjunction with the `cert` option.
.. code-block:: php
$request = $client->get('https://www.example.com', array(), array(
'ssl_key' => '/etc/pki/private_key.pem'
)
$request = $client->get('https://www.example.com', array(), array(
'ssl_key' => array('/etc/pki/private_key.pem', 's3cr3tp455w0rd')
)
proxy
~~~~~
The `proxy` option is used to specify an HTTP proxy (e.g. `http://username:password@192.168.16.1:10`).
debug
~~~~~
The `debug` option is used to show verbose cURL output for a transfer.
stream
~~~~~~
When using a static client, you can set the `stream` option to true to return a `Guzzle\Stream\Stream` object that can
be used to pull data from a stream as needed (rather than have cURL download the entire contents of a response to a
stream all at once).
.. code-block:: php
$stream = Guzzle::get('http://guzzlephp.org', array('stream' => true));
while (!$stream->feof()) {
echo $stream->readLine();
}
Sending requests
----------------
Requests can be sent by calling the ``send()`` method of a Request object, but you can also send requests using the
``send()`` method of a Client.
.. code-block:: php
$request = $client->get('http://www.amazon.com');
$response = $client->send($request);
Sending requests in parallel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Client's ``send()`` method accept a single ``Guzzle\Http\Message\RequestInterface`` object or an array of
RequestInterface objects. When an array is specified, the requests will be sent in parallel.
Sending many HTTP requests serially (one at a time) can cause an unnecessary delay in a script's execution. Each
request must complete before a subsequent request can be sent. By sending requests in parallel, a pool of HTTP
requests can complete at the speed of the slowest request in the pool, significantly reducing the amount of time
needed to execute multiple HTTP requests. Guzzle provides a wrapper for the curl_multi functions in PHP.
Here's an example of sending three requests in parallel using a client object:
.. code-block:: php
use Guzzle\Common\Exception\MultiTransferException;
try {
$responses = $client->send(array(
$client->get('http://www.google.com/'),
$client->head('http://www.google.com/'),
$client->get('https://www.github.com/')
));
} catch (MultiTransferException $e) {
echo "The following exceptions were encountered:\n";
foreach ($e as $exception) {
echo $exception->getMessage() . "\n";
}
echo "The following requests failed:\n";
foreach ($e->getFailedRequests() as $request) {
echo $request . "\n\n";
}
echo "The following requests succeeded:\n";
foreach ($e->getSuccessfulRequests() as $request) {
echo $request . "\n\n";
}
}
If the requests succeed, an array of ``Guzzle\Http\Message\Response`` objects are returned. A single request failure
will not cause the entire pool of requests to fail. Any exceptions thrown while transferring a pool of requests will
be aggregated into a ``Guzzle\Common\Exception\MultiTransferException`` exception.
Plugins and events
------------------
Guzzle provides easy to use request plugins that add behavior to requests based on signal slot event notifications
powered by the
`Symfony2 Event Dispatcher component <http://symfony.com/doc/2.0/components/event_dispatcher/introduction.html>`_. Any
event listener or subscriber attached to a Client object will automatically be attached to each request created by the
client.
Using the same cookie session for each request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Attach a ``Guzzle\Plugin\Cookie\CookiePlugin`` to a client which will in turn add support for cookies to every request
created by a client, and each request will use the same cookie session:
.. code-block:: php
use Guzzle\Plugin\Cookie\CookiePlugin;
use Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar;
// Create a new cookie plugin
$cookiePlugin = new CookiePlugin(new ArrayCookieJar());
// Add the cookie plugin to the client
$client->addSubscriber($cookiePlugin);
.. _client-events:
Events emitted from a client
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A ``Guzzle\Http\Client`` object emits the following events:
+------------------------------+--------------------------------------------+------------------------------------------+
| Event name | Description | Event data |
+==============================+============================================+==========================================+
| client.create_request | Called when a client creates a request | * client: The client |
| | | * request: The created request |
+------------------------------+--------------------------------------------+------------------------------------------+
.. code-block:: php
use Guzzle\Common\Event;
use Guzzle\Http\Client;
$client = new Client();
// Add a listener that will echo out requests as they are created
$client->getEventDispatcher()->addListener('client.create_request', function (Event $e) {
echo 'Client object: ' . spl_object_hash($e['client']) . "\n";
echo "Request object: {$e['request']}\n";
});

View File

@ -1,151 +0,0 @@
===========================
Request and response bodies
===========================
`Entity body <http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html>`_ is the term used for the body of an HTTP
message. The entity body of requests and responses is inherently a
`PHP stream <http://php.net/manual/en/book.stream.php>`_ in Guzzle. The body of the request can be either a string or
a PHP stream which are converted into a ``Guzzle\Http\EntityBody`` object using its factory method. When using a
string, the entity body is stored in a `temp PHP stream <http://www.php.net/manual/en/wrappers.php.php>`_. The use of
temp PHP streams helps to protect your application from running out of memory when sending or receiving large entity
bodies in your messages. When more than 2MB of data is stored in a temp stream, it automatically stores the data on
disk rather than in memory.
EntityBody objects provide a great deal of functionality: compression, decompression, calculate the Content-MD5,
calculate the Content-Length (when the resource is repeatable), guessing the Content-Type, and more. Guzzle doesn't
need to load an entire entity body into a string when sending or retrieving data; entity bodies are streamed when
being uploaded and downloaded.
Here's an example of gzip compressing a text file then sending the file to a URL:
.. code-block:: php
use Guzzle\Http\EntityBody;
$body = EntityBody::factory(fopen('/path/to/file.txt', 'r+'));
echo $body->read(1024);
$body->seek(0, SEEK_END);
$body->write('foo');
echo $body->ftell();
$body->rewind();
// Send a request using the body
$response = $client->put('http://localhost:8080/uploads', null, $body)->send();
The body of the request can be specified in the ``Client::put()`` or ``Client::post()`` method, or, you can specify
the body of the request by calling the ``setBody()`` method of any
``Guzzle\Http\Message\EntityEnclosingRequestInterface`` object.
Compression
-----------
You can compress the contents of an EntityBody object using the ``compress()`` method. The compress method accepts a
filter that must match to one of the supported
`PHP stream filters <http://www.php.net/manual/en/filters.compression.php>`_ on your system (e.g. `zlib.deflate`,
``bzip2.compress``, etc). Compressing an entity body will stream the entire entity body through a stream compression
filter into a temporary PHP stream. You can uncompress an entity body using the ``uncompress()`` method and passing
the PHP stream filter to use when decompressing the stream (e.g. ``zlib.inflate``).
.. code-block:: php
use Guzzle\Http\EntityBody;
$body = EntityBody::factory(fopen('/tmp/test.txt', 'r+'));
echo $body->getSize();
// >>> 1048576
// Compress using the default zlib.deflate filter
$body->compress();
echo $body->getSize();
// >>> 314572
// Decompress the stream
$body->uncompress();
echo $body->getSize();
// >>> 1048576
Decorators
----------
Guzzle provides several EntityBody decorators that can be used to add functionality to an EntityBody at runtime.
IoEmittingEntityBody
~~~~~~~~~~~~~~~~~~~~
This decorator will emit events when data is read from a stream or written to a stream. Add an event subscriber to the
entity body's ``body.read`` or ``body.write`` methods to receive notifications when data data is transferred.
.. code-block:: php
use Guzzle\Common\Event;
use Guzzle\Http\EntityBody;
use Guzzle\Http\IoEmittingEntityBody;
$original = EntityBody::factory(fopen('/tmp/test.txt', 'r+'));
$body = new IoEmittingEntityBody($original);
// Listen for read events
$body->getEventDispatcher()->addListener('body.read', function (Event $e) {
// Grab data from the event
$entityBody = $e['body'];
// Amount of data retrieved from the body
$lengthOfData = $e['length'];
// The actual data that was read
$data = $e['read'];
});
// Listen for write events
$body->getEventDispatcher()->addListener('body.write', function (Event $e) {
// Grab data from the event
$entityBody = $e['body'];
// The data that was written
$data = $e['write'];
// The actual amount of data that was written
$data = $e['read'];
});
ReadLimitEntityBody
~~~~~~~~~~~~~~~~~~~
The ReadLimitEntityBody decorator can be used to transfer a subset or slice of an existing EntityBody object. This can
be useful for breaking a large file into smaller pieces to be sent in chunks (e.g. Amazon S3's multipart upload API).
.. code-block:: php
use Guzzle\Http\EntityBody;
use Guzzle\Http\ReadLimitEntityBody;
$original = EntityBody::factory(fopen('/tmp/test.txt', 'r+'));
echo $original->getSize();
// >>> 1048576
// Limit the size of the body to 1024 bytes and start reading from byte 2048
$body = new ReadLimitEntityBody($original, 1024, 2048);
echo $body->getSize();
// >>> 1024
echo $body->ftell();
// >>> 0
CachingEntityBody
~~~~~~~~~~~~~~~~~
The CachingEntityBody decorator is used to allow seeking over previously read bytes on non-seekable read streams. This
can be useful when transferring a non-seekable entity body fails due to needing to rewind the stream (for example,
resulting from a redirect). Data that is read from the remote stream will be buffered in a PHP temp stream so that
previously read bytes are cached first in memory, then on disk.
.. code-block:: php
use Guzzle\Http\EntityBody;
use Guzzle\Http\CachingEntityBody;
$original = EntityBody::factory(fopen('http://www.google.com', 'r'));
$body = new CachingEntityBody($original);
$body->read(1024);
echo $body->ftell();
// >>> 1024
$body->seek(0);
echo $body->ftell();
// >>> 0

View File

@ -1,99 +0,0 @@
==============
HTTP redirects
==============
By default, Guzzle will automatically follow redirects using the non-RFC compliant implementation used by most web
browsers. This means that redirects for POST requests are followed by a GET request. You can force RFC compliance by
enabling the strict mode on a request's parameter object:
.. code-block:: php
// Set per request
$request = $client->post();
$request->getParams()->set('redirect.strict', true);
// You can set globally on a client so all requests use strict redirects
$client->getConfig()->set('request.params', array(
'redirect.strict' => true
));
By default, Guzzle will redirect up to 5 times before throwing a ``Guzzle\Http\Exception\TooManyRedirectsException``.
You can raise or lower this value using the ``redirect.max`` parameter of a request object:
.. code-block:: php
$request->getParams()->set('redirect.max', 2);
Redirect history
----------------
You can get the number of redirects of a request using the resulting response object's ``getRedirectCount()`` method.
Similar to cURL's ``effective_url`` property, Guzzle provides the effective URL, or the last redirect URL that returned
the request, in a response's ``getEffectiveUrl()`` method.
When testing or debugging, it is often useful to see a history of redirects for a particular request. This can be
achieved using the HistoryPlugin.
.. code-block:: php
$request = $client->get('/');
$history = new Guzzle\Plugin\History\HistoryPlugin();
$request->addSubscriber($history);
$response = $request->send();
// Get the last redirect URL or the URL of the request that received
// this response
echo $response->getEffectiveUrl();
// Get the number of redirects
echo $response->getRedirectCount();
// Iterate over each sent request and response
foreach ($history->getAll() as $transaction) {
// Request object
echo $transaction['request']->getUrl() . "\n";
// Response object
echo $transaction['response']->getEffectiveUrl() . "\n";
}
// Or, simply cast the HistoryPlugin to a string to view each request and response
echo $history;
Disabling redirects
-------------------
You can disable redirects on a client by passing a configuration option in the client's constructor:
.. code-block:: php
$client = new Client(null, array('redirect.disable' => true));
You can also disable redirects per request:
.. code-block:: php
$request = $client->get($url, array(), array('allow_redirects' => false));
Redirects and non-repeatable streams
------------------------------------
If you are redirected when sending data from a non-repeatable stream and some of the data has been read off of the
stream, then you will get a ``Guzzle\Http\Exception\CouldNotRewindStreamException``. You can get around this error by
adding a custom rewind method to the entity body object being sent in the request.
.. code-block:: php
$request = $client->post(
'http://httpbin.com/redirect/2',
null,
fopen('http://httpbin.com/get', 'r')
);
// Add a custom function that can be used to rewind the stream
// (reopen in this example)
$request->getBody()->setRewindFunction(function ($body) {
$body->setStream(fopen('http://httpbin.com/get', 'r'));
return true;
);
$response = $client->send();

View File

@ -1,667 +0,0 @@
=====================
Using Request objects
=====================
HTTP request messages
---------------------
Request objects are all about building an HTTP message. Each part of an HTTP request message can be set individually
using methods on the request object or set in bulk using the ``setUrl()`` method. Here's the format of an HTTP request
with each part of the request referencing the method used to change it::
PUT(a) /path(b)?query=123(c) HTTP/1.1(d)
X-Header(e): header
Content-Length(e): 4
data(f)
+-------------------------+---------------------------------------------------------------------------------+
| a. **Method** | The request method can only be set when instantiating a request |
+-------------------------+---------------------------------------------------------------------------------+
| b. **Path** | ``$request->setPath('/path');`` |
+-------------------------+---------------------------------------------------------------------------------+
| c. **Query** | ``$request->getQuery()->set('query', '123');`` |
+-------------------------+---------------------------------------------------------------------------------+
| d. **Protocol version** | ``$request->setProtocolVersion('1.1');`` |
+-------------------------+---------------------------------------------------------------------------------+
| e. **Header** | ``$request->setHeader('X-Header', 'header');`` |
+-------------------------+---------------------------------------------------------------------------------+
| f. **Entity Body** | ``$request->setBody('data'); // Only available with PUT, POST, PATCH, DELETE`` |
+-------------------------+---------------------------------------------------------------------------------+
Creating requests with a client
-------------------------------
Client objects are responsible for creating HTTP request objects.
GET requests
~~~~~~~~~~~~
`GET requests <http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3>`_ are the most common form of HTTP
requests. When you visit a website in your browser, the HTML of the website is downloaded using a GET request. GET
requests are idempotent requests that are typically used to download content (an entity) identified by a request URL.
.. code-block:: php
use Guzzle\Http\Client;
$client = new Client();
// Create a request that has a query string and an X-Foo header
$request = $client->get('http://www.amazon.com?a=1', array('X-Foo' => 'Bar'));
// Send the request and get the response
$response = $request->send();
You can change where the body of a response is downloaded on any request using the
``$request->setResponseBody(string|EntityBodyInterface|resource)`` method of a request. You can also set the ``save_to``
option of a request:
.. code-block:: php
// Send the response body to a file
$request = $client->get('http://test.com', array(), array('save_to' => '/path/to/file'));
// Send the response body to an fopen resource
$request = $client->get('http://test.com', array(), array('save_to' => fopen('/path/to/file', 'w')));
HEAD requests
~~~~~~~~~~~~~
`HEAD requests <http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4>`_ work exactly like GET requests except
that they do not actually download the response body (entity) of the response message. HEAD requests are useful for
retrieving meta information about an entity identified by a Request-URI.
.. code-block:: php
$client = new Guzzle\Http\Client();
$request = $client->head('http://www.amazon.com');
$response = $request->send();
echo $response->getContentLength();
// >>> Will output the Content-Length header value
DELETE requests
~~~~~~~~~~~~~~~
A `DELETE method <http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.7>`_ requests that the origin server
delete the resource identified by the Request-URI.
.. code-block:: php
$client = new Guzzle\Http\Client();
$request = $client->delete('http://example.com');
$response = $request->send();
POST requests
~~~~~~~~~~~~~
While `POST requests <http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5>`_ can be used for a number of
reasons, POST requests are often used when submitting HTML form data to a website. POST requests can include an entity
body in the HTTP request.
POST requests in Guzzle are sent with an ``application/x-www-form-urlencoded`` Content-Type header if POST fields are
present but no files are being sent in the POST. If files are specified in the POST request, then the Content-Type
header will become ``multipart/form-data``.
The ``post()`` method of a client object accepts four arguments: the URL, optional headers, post fields, and an array of
request options. To send files in the POST request, prepend the ``@`` symbol to the array value (just like you would if
you were using the PHP ``curl_setopt`` function).
Here's how to create a multipart/form-data POST request containing files and fields:
.. code-block:: php
$request = $client->post('http://httpbin.org/post', array(), array(
'custom_field' => 'my custom value',
'file_field' => '@/path/to/file.xml'
));
$response = $request->send();
.. note::
Remember to **always** sanitize user input when sending POST requests:
.. code-block:: php
// Prevent users from accessing sensitive files by sanitizing input
$_POST = array('firstname' => '@/etc/passwd');
$request = $client->post('http://www.example.com', array(), array (
'firstname' => str_replace('@', '', $_POST['firstname'])
));
You can alternatively build up the contents of a POST request.
.. code-block:: php
$request = $client->post('http://httpbin.org/post')
->setPostField('custom_field', 'my custom value')
->addPostFile('file', '/path/to/file.xml');
$response = $request->send();
Raw POST data
^^^^^^^^^^^^^
POST requests can also contain raw POST data that is not related to HTML forms.
.. code-block:: php
$request = $client->post('http://httpbin.org/post', array(), 'this is the body');
$response = $request->send();
You can set the body of POST request using the ``setBody()`` method of the
``Guzzle\Http\Message\EntityEnclosingRequest`` object. This method accepts a string, a resource returned from
``fopen``, or a ``Guzzle\Http\EntityBodyInterface`` object.
.. code-block:: php
$request = $client->post('http://httpbin.org/post');
// Set the body of the POST to stream the contents of /path/to/large_body.txt
$request->setBody(fopen('/path/to/large_body.txt', 'r'));
$response = $request->send();
PUT requests
~~~~~~~~~~~~
The `PUT method <http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6>`_ requests that the enclosed entity be
stored under the supplied Request-URI. PUT requests are similar to POST requests in that they both can send an entity
body in the request message.
The body of a PUT request (any any ``Guzzle\Http\Message\EntityEnclosingRequestInterface`` object) is always stored as
a ``Guzzle\Http\Message\EntityBodyInterface`` object. This allows a great deal of flexibility when sending data to a
remote server. For example, you can stream the contents of a stream returned by fopen, stream the contents of a
callback function, or simply send a string of data.
.. code-block:: php
$request = $client->put('http://httpbin.org/put', array(), 'this is the body');
$response = $request->send();
Just like with POST, PATH, and DELETE requests, you can set the body of a PUT request using the ``setBody()`` method.
.. code-block:: php
$request = $client->put('http://httpbin.org/put');
$request->setBody(fopen('/path/to/large_body.txt', 'r'));
$response = $request->send();
PATCH requests
~~~~~~~~~~~~~~
`PATCH requests <http://tools.ietf.org/html/rfc5789>`_ are used to modify a resource.
.. code-block:: php
$request = $client->patch('http://httpbin.org', array(), 'this is the body');
$response = $request->send();
OPTIONS requests
~~~~~~~~~~~~~~~~
The `OPTIONS method <http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.2>`_ represents a request for
information about the communication options available on the request/response chain identified by the Request-URI.
.. code-block:: php
$request = $client->options('http://httpbin.org');
$response = $request->send();
// Check if the PUT method is supported by this resource
var_export($response->isMethodAllows('PUT'));
Custom requests
~~~~~~~~~~~~~~~
You can create custom HTTP requests that use non-standard HTTP methods using the ``createRequest()`` method of a
client object.
.. code-block:: php
$request = $client->createRequest('COPY', 'http://example.com/foo', array(
'Destination' => 'http://example.com/bar',
'Overwrite' => 'T'
));
$response = $request->send();
Query string parameters
-----------------------
Query string parameters of a request are owned by a request's ``Guzzle\Http\Query`` object that is accessible by
calling ``$request->getQuery()``. The Query class extends from ``Guzzle\Common\Collection`` and allows you to set one
or more query string parameters as key value pairs. You can set a parameter on a Query object using the
``set($key, $value)`` method or access the query string object like an associative array. Any previously specified
value for a key will be overwritten when using ``set()``. Use ``add($key, $value)`` to add a value to query string
object, and in the event of a collision with an existing value at a specific key, the value will be converted to an
array that contains all of the previously set values.
.. code-block:: php
$request = new Guzzle\Http\Message\Request('GET', 'http://www.example.com?foo=bar&abc=123');
$query = $request->getQuery();
echo "{$query}\n";
// >>> foo=bar&abc=123
$query->remove('abc');
echo "{$query}\n";
// >>> foo=bar
$query->set('foo', 'baz');
echo "{$query}\n";
// >>> foo=baz
$query->add('foo', 'bar');
echo "{$query}\n";
// >>> foo%5B0%5D=baz&foo%5B1%5D=bar
Whoah! What happened there? When ``foo=bar`` was added to the existing ``foo=baz`` query string parameter, the
aggregator associated with the Query object was used to help convert multi-value query string parameters into a string.
Let's disable URL-encoding to better see what's happening.
.. code-block:: php
$query->useUrlEncoding(false);
echo "{$query}\n";
// >>> foo[0]=baz&foo[1]=bar
.. note::
URL encoding can be disabled by passing false, enabled by passing true, set to use RFC 1738 by passing
``Query::FORM_URLENCODED`` (internally uses PHP's ``urlencode`` function), or set to RFC 3986 by passing
``Query::RFC_3986`` (this is the default and internally uses PHP's ``rawurlencode`` function).
As you can see, the multiple values were converted into query string parameters following the default PHP convention of
adding numerically indexed square bracket suffixes to each key (``foo[0]=baz&foo[1]=bar``). The strategy used to convert
multi-value parameters into a string can be customized using the ``setAggregator()`` method of the Query class. Guzzle
ships with the following query string aggregators by default:
1. ``Guzzle\Http\QueryAggregator\PhpAggregator``: Aggregates using PHP style brackets (e.g. ``foo[0]=baz&foo[1]=bar``)
2. ``Guzzle\Http\QueryAggregator\DuplicateAggregator``: Performs no aggregation and allows for key value pairs to be
repeated in a URL (e.g. ``foo=baz&foo=bar``)
3. ``Guzzle\Http\QueryAggregator\CommaAggregator``: Aggregates using commas (e.g. ``foo=baz,bar``)
.. _http-message-headers:
HTTP Message Headers
--------------------
HTTP message headers are case insensitive, multiple occurrences of any header can be present in an HTTP message
(whether it's valid or not), and some servers require specific casing of particular headers. Because of this, request
and response headers are stored in ``Guzzle\Http\Message\Header`` objects. The Header object can be cast as a string,
counted, or iterated to retrieve each value from the header. Casting a Header object to a string will return all of
the header values concatenated together using a glue string (typically ", ").
A request (and response) object have several methods that allow you to retrieve and modify headers.
* ``getHeaders()``: Get all of the headers of a message as a ``Guzzle\Http\Message\Header\HeaderCollection`` object.
* ``getHeader($header)``: Get a specific header from a message. If the header exists, you'll get a
``Guzzle\Http\Message\Header`` object. If the header does not exist, this methods returns ``null``.
* ``hasHeader($header)``: Returns true or false based on if the message has a particular header.
* ``setHeader($header, $value)``: Set a header value and overwrite any previously set value for this header.
* ``addHeader($header, $value)``: Add a header with a particular name. If a previous value was already set by the same,
then the header will contain multiple values.
* ``removeHeader($header)``: Remove a header by name from the message.
.. code-block:: php
$request = new Request('GET', 'http://httpbin.com/cookies');
// addHeader will set and append to any existing header values
$request->addHeader('Foo', 'bar');
$request->addHeader('foo', 'baz');
// setHeader overwrites any existing values
$request->setHeader('Test', '123');
// Request headers can be cast as a string
echo $request->getHeader('Foo');
// >>> bar, baz
echo $request->getHeader('Test');
// >>> 123
// You can count the number of headers of a particular case insensitive name
echo count($request->getHeader('foO'));
// >>> 2
// You can iterate over Header objects
foreach ($request->getHeader('foo') as $header) {
echo $header . "\n";
}
// You can get all of the request headers as a Guzzle\Http\Message\Header\HeaderCollection object
$headers = $request->getHeaders();
// Missing headers return NULL
var_export($request->getHeader('Missing'));
// >>> null
// You can see all of the different variations of a header by calling raw() on the Header
var_export($request->getHeader('foo')->raw());
Setting the body of a request
-----------------------------
Requests that can send a body (e.g. PUT, POST, DELETE, PATCH) are instances of
``Guzzle\Http\Message\EntityEnclosingRequestInterface``. Entity enclosing requests contain several methods that allow
you to specify the body to send with a request.
Use the ``setBody()`` method of a request to set the body that will be sent with a request. This method accepts a
string, a resource returned by ``fopen()``, an array, or an instance of ``Guzzle\Http\EntityBodyInterface``. The body
will then be streamed from the underlying ``EntityBodyInterface`` object owned by the request. When setting the body
of the request, you can optionally specify a Content-Type header and whether or not to force the request to use
chunked Transfer-Encoding.
.. code-block:: php
$request = $client->put('/user.json');
$request->setBody('{"foo":"baz"}', 'application/json');
Content-Type header
~~~~~~~~~~~~~~~~~~~
Guzzle will automatically add a Content-Type header to a request if the Content-Type can be guessed based on the file
extension of the payload being sent or the file extension present in the path of a request.
.. code-block:: php
$request = $client->put('/user.json', array(), '{"foo":"bar"}');
// The Content-Type was guessed based on the path of the request
echo $request->getHeader('Content-Type');
// >>> application/json
$request = $client->put('/user.json');
$request->setBody(fopen('/tmp/user_data.json', 'r'));
// The Content-Type was guessed based on the path of the entity body
echo $request->getHeader('Content-Type');
// >>> application/json
Transfer-Encoding: chunked header
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When sending HTTP requests that contain a payload, you must let the remote server know how to determine when the entire
message has been sent. This usually is done by supplying a ``Content-Length`` header that tells the origin server the
size of the body that is to be sent. In some cases, the size of the payload being sent in a request cannot be known
before initiating the transfer. In these cases (when using HTTP/1.1), you can use the ``Transfer-Encoding: chunked``
header.
If the Content-Length cannot be determined (i.e. using a PHP ``http://`` stream), then Guzzle will automatically add
the ``Transfer-Encoding: chunked`` header to the request.
.. code-block:: php
$request = $client->put('/user.json');
$request->setBody(fopen('http://httpbin.org/get', 'r'));
// The Content-Length could not be determined
echo $request->getHeader('Transfer-Encoding');
// >>> chunked
See :doc:`/http-client/entity-bodies` for more information on entity bodies.
Expect: 100-Continue header
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``Expect: 100-Continue`` header is used to help a client prevent sending a large payload to a server that will
reject the request. This allows clients to fail fast rather than waste bandwidth sending an erroneous payload. Guzzle
will automatically add the ``Expect: 100-Continue`` header to a request when the size of the payload exceeds 1MB or if
the body of the request is not seekable (this helps to prevent errors when a non-seekable body request is redirected).
.. note::
If you find that your larger requests are taking too long to complete, you should first check if the
``Expect: 100-Continue`` header is being sent with the request. Some servers do not respond well to this header,
which causes cURL to sleep for `1 second <http://curl.haxx.se/mail/lib-2010-01/0182.html>`_.
POST fields and files
~~~~~~~~~~~~~~~~~~~~~
Any entity enclosing request can send POST style fields and files. This includes POST, PUT, PATCH, and DELETE requests.
Any request that has set POST fields or files will use cURL's POST message functionality.
.. code-block:: php
$request = $client->post('/post');
// Set an overwrite any previously specified value
$request->setPostField('foo', 'bar');
// Append a value to any existing values
$request->getPostFields()->add('foo', 'baz');
// Remove a POST field by name
$request->removePostField('fizz');
// Add a file to upload (forces multipart/form-data)
$request->addPostFile('my_file', '/path/to/file', 'plain/text');
// Remove a POST file by POST key name
$request->removePostFile('my_other_file');
.. tip::
Adding a large number of POST fields to a POST request is faster if you use the ``addPostFields()`` method so that
you can add and process multiple fields with a single call. Adding multiple POST files is also faster using
``addPostFiles()``.
Working with cookies
--------------------
Cookies can be modified and retrieved from a request using the following methods:
.. code-block:: php
$request->addCookie($name, $value);
$request->removeCookie($name);
$value = $request->getCookie($name);
$valueArray = $request->getCookies();
Use the :doc:`cookie plugin </plugins/cookie-plugin>` if you need to reuse cookies between requests.
.. _request-set-response-body:
Changing where a response is downloaded
----------------------------------------
When a request is sent, the body of the response will be stored in a PHP temp stream by default. You can change the
location in which the response will be downloaded using ``$request->setResponseBody($body)`` or the ``save_to`` request
option. This can be useful for downloading the contents of a URL to a specific file.
Here's an example of using request options:
.. code-block:: php
$request = $this->client->get('http://example.com/large.mov', array(), array(
'save_to' => '/tmp/large_file.mov'
));
$request->send();
var_export(file_exists('/tmp/large_file.mov'));
// >>> true
Here's an example of using ``setResponseBody()``:
.. code-block:: php
$body = fopen('/tmp/large_file.mov', 'w');
$request = $this->client->get('http://example.com/large.mov');
$request->setResponseBody($body);
// You can more easily specify the name of a file to save the contents
// of the response to by passing a string to ``setResponseBody()``.
$request = $this->client->get('http://example.com/large.mov');
$request->setResponseBody('/tmp/large_file.mov');
Custom cURL options
-------------------
Most of the functionality implemented in the libcurl bindings has been simplified and abstracted by Guzzle. Developers
who need access to `cURL specific functionality <http://www.php.net/curl_setopt>`_ can still add cURL handle
specific behavior to Guzzle HTTP requests by modifying the cURL options collection of a request:
.. code-block:: php
$request->getCurlOptions()->set(CURLOPT_LOW_SPEED_LIMIT, 200);
Other special options that can be set in the ``curl.options`` array include:
+-------------------------+---------------------------------------------------------------------------------+
| debug | Adds verbose cURL output to a temp stream owned by the cURL handle object |
+-------------------------+---------------------------------------------------------------------------------+
| progress | Instructs cURL to emit events when IO events occur. This allows you to be |
| | notified when bytes are transferred over the wire by subscribing to a request's |
| | ``curl.callback.read``, ``curl.callback.write``, and ``curl.callback.progress`` |
| | events. |
+-------------------------+---------------------------------------------------------------------------------+
Request options
---------------
Requests options can be specified when creating a request or in the ``request.options`` parameter of a client. These
options can control various aspects of a request including: headers to send, query string data, where the response
should be downloaded, proxies, auth, etc.
.. code-block:: php
$request = $client->get($url, $headers, array('proxy' => 'http://proxy.com'));
See :ref:`Request options <request-options>` for more information.
Working with errors
-------------------
HTTP errors
~~~~~~~~~~~
Requests that receive a 4xx or 5xx response will throw a ``Guzzle\Http\Exception\BadResponseException``. More
specifically, 4xx errors throw a ``Guzzle\Http\Exception\ClientErrorResponseException``, and 5xx errors throw a
``Guzzle\Http\Exception\ServerErrorResponseException``. You can catch the specific exceptions or just catch the
BadResponseException to deal with either type of error. Here's an example of catching a generic BadResponseException:
.. code-block:: php
try {
$response = $client->get('/not_found.xml')->send();
} catch (Guzzle\Http\Exception\BadResponseException $e) {
echo 'Uh oh! ' . $e->getMessage();
echo 'HTTP request URL: ' . $e->getRequest()->getUrl() . "\n";
echo 'HTTP request: ' . $e->getRequest() . "\n";
echo 'HTTP response status: ' . $e->getResponse()->getStatusCode() . "\n";
echo 'HTTP response: ' . $e->getResponse() . "\n";
}
Throwing an exception when a 4xx or 5xx response is encountered is the default behavior of Guzzle requests. This
behavior can be overridden by adding an event listener with a higher priority than -255 that stops event propagation.
You can subscribe to ``request.error`` to receive notifications any time an unsuccessful response is received.
You can change the response that will be associated with the request by calling ``setResponse()`` on the
``$event['request']`` object passed into your listener, or by changing the ``$event['response']`` value of the
``Guzzle\Common\Event`` object that is passed to your listener. Transparently changing the response associated with a
request by modifying the event allows you to retry failed requests without complicating the code that uses the client.
This might be useful for sending requests to a web service that has expiring auth tokens. When a response shows that
your token has expired, you can get a new token, retry the request with the new token, and return the successful
response to the user.
Here's an example of retrying a request using updated authorization credentials when a 401 response is received,
overriding the response of the original request with the new response, and still allowing the default exception
behavior to be called when other non-200 response status codes are encountered:
.. code-block:: php
// Add custom error handling to any request created by this client
$client->getEventDispatcher()->addListener('request.error', function(Event $event) {
if ($event['response']->getStatusCode() == 401) {
$newRequest = $event['request']->clone();
$newRequest->setHeader('X-Auth-Header', MyApplication::getNewAuthToken());
$newResponse = $newRequest->send();
// Set the response object of the request without firing more events
$event['response'] = $newResponse;
// You can also change the response and fire the normal chain of
// events by calling $event['request']->setResponse($newResponse);
// Stop other events from firing when you override 401 responses
$event->stopPropagation();
}
});
cURL errors
~~~~~~~~~~~
Connection problems and cURL specific errors can also occur when transferring requests using Guzzle. When Guzzle
encounters cURL specific errors while transferring a single request, a ``Guzzle\Http\Exception\CurlException`` is
thrown with an informative error message and access to the cURL error message.
A ``Guzzle\Http\Exception\MultiTransferException`` exception is thrown when a cURL specific error occurs while
transferring multiple requests in parallel. You can then iterate over all of the exceptions encountered during the
transfer.
Plugins and events
------------------
Guzzle request objects expose various events that allow you to hook in custom logic. A request object owns a
``Symfony\Component\EventDispatcher\EventDispatcher`` object that can be accessed by calling
``$request->getEventDispatcher()``. You can use the event dispatcher to add listeners (a simple callback function) or
event subscribers (classes that listen to specific events of a dispatcher). You can add event subscribers to a request
directly by just calling ``$request->addSubscriber($mySubscriber);``.
.. _request-events:
Events emitted from a request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A ``Guzzle\Http\Message\Request`` and ``Guzzle\Http\Message\EntityEnclosingRequest`` object emit the following events:
+------------------------------+--------------------------------------------+------------------------------------------+
| Event name | Description | Event data |
+==============================+============================================+==========================================+
| request.before_send | About to send request | * request: Request to be sent |
+------------------------------+--------------------------------------------+------------------------------------------+
| request.sent | Sent the request | * request: Request that was sent |
| | | * response: Received response |
+------------------------------+--------------------------------------------+------------------------------------------+
| request.complete | Completed a full HTTP transaction | * request: Request that was sent |
| | | * response: Received response |
+------------------------------+--------------------------------------------+------------------------------------------+
| request.success | Completed a successful request | * request: Request that was sent |
| | | * response: Received response |
+------------------------------+--------------------------------------------+------------------------------------------+
| request.error | Completed an unsuccessful request | * request: Request that was sent |
| | | * response: Received response |
+------------------------------+--------------------------------------------+------------------------------------------+
| request.exception | An unsuccessful response was | * request: Request |
| | received. | * response: Received response |
| | | * exception: BadResponseException |
+------------------------------+--------------------------------------------+------------------------------------------+
| request.receive.status_line | Received the start of a response | * line: Full response start line |
| | | * status_code: Status code |
| | | * reason_phrase: Reason phrase |
| | | * previous_response: (e.g. redirect) |
+------------------------------+--------------------------------------------+------------------------------------------+
| curl.callback.progress | cURL progress event (only dispatched when | * handle: CurlHandle |
| | ``emit_io`` is set on a request's curl | * download_size: Total download size |
| | options) | * downloaded: Bytes downloaded |
| | | * upload_size: Total upload bytes |
| | | * uploaded: Bytes uploaded |
+------------------------------+--------------------------------------------+------------------------------------------+
| curl.callback.write | cURL event called when data is written to | * request: Request |
| | an outgoing stream | * write: Data being written |
+------------------------------+--------------------------------------------+------------------------------------------+
| curl.callback.read | cURL event called when data is written to | * request: Request |
| | an incoming stream | * read: Data being read |
+------------------------------+--------------------------------------------+------------------------------------------+
Creating a request event listener
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here's an example that listens to the ``request.complete`` event of a request and prints the request and response.
.. code-block:: php
use Guzzle\Common\Event;
$request = $client->get('http://www.google.com');
// Echo out the response that was received
$request->getEventDispatcher()->addListener('request.complete', function (Event $e) {
echo $e['request'] . "\n\n";
echo $e['response'];
});

View File

@ -1,141 +0,0 @@
======================
Using Response objects
======================
Sending a request will return a ``Guzzle\Http\Message\Response`` object. You can view the raw HTTP response message by
casting the Response object to a string. Casting the response to a string will return the entity body of the response
as a string too, so this might be an expensive operation if the entity body is stored in a file or network stream. If
you only want to see the response headers, you can call ``getRawHeaders()``.
Response status line
--------------------
The different parts of a response's `status line <http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1>`_
(the first line of the response HTTP message) are easily retrievable.
.. code-block:: php
$response = $client->get('http://www.amazon.com')->send();
echo $response->getStatusCode(); // >>> 200
echo $response->getReasonPhrase(); // >>> OK
echo $response->getProtocol(); // >>> HTTP
echo $response->getProtocolVersion(); // >>> 1.1
You can determine the type of the response using several helper methods:
.. code-block:: php
$response->isSuccessful(); // true
$response->isInformational();
$response->isRedirect();
$response->isClientError();
$response->isServerError();
Response headers
----------------
The Response object contains helper methods for retrieving common response headers. These helper methods normalize the
variations of HTTP response headers.
.. code-block:: php
$response->getCacheControl();
$response->getContentType();
$response->getContentLength();
$response->getContentEncoding();
$response->getContentMd5();
$response->getEtag();
// etc... There are methods for every known response header
You can interact with the Response headers using the same exact methods used to interact with Request headers. See
:ref:`http-message-headers` for more information.
.. code-block:: php
echo $response->getHeader('Content-Type');
echo $response->getHeader('Content-Length');
echo $response->getHeaders()['Content-Type']; // PHP 5.4
Response body
-------------
The entity body object of a response can be retrieved by calling ``$response->getBody()``. The response EntityBody can
be cast to a string, or you can pass ``true`` to this method to retrieve the body as a string.
.. code-block:: php
$request = $client->get('http://www.amazon.com');
$response = $request->send();
echo $response->getBody();
See :doc:`/http-client/entity-bodies` for more information on entity bodies.
JSON Responses
~~~~~~~~~~~~~~
You can easily parse and use a JSON response as an array using the ``json()`` method of a response. This method will
always return an array if the response is valid JSON or if the response body is empty. You will get an exception if you
call this method and the response is not valid JSON.
.. code-block:: php
$data = $response->json();
echo gettype($data);
// >>> array
XML Responses
~~~~~~~~~~~~~
You can easily parse and use a XML response as SimpleXMLElement object using the ``xml()`` method of a response. This
method will always return a SimpleXMLElement object if the response is valid XML or if the response body is empty. You
will get an exception if you call this method and the response is not valid XML.
.. code-block:: php
$xml = $response->xml();
echo $xml->foo;
// >>> Bar!
Streaming responses
-------------------
Some web services provide streaming APIs that allow a client to keep a HTTP request open for an extended period of
time while polling and reading. Guzzle provides a simple way to convert HTTP request messages into
``Guzzle\Stream\Stream`` objects so that you can send the initial headers of a request, read the response headers, and
pull in the response body manually as needed.
Here's an example using the Twitter Streaming API to track the keyword "bieber":
.. code-block:: php
use Guzzle\Http\Client;
use Guzzle\Stream\PhpStreamRequestFactory;
$client = new Client('https://stream.twitter.com/1');
$request = $client->post('statuses/filter.json', null, array(
'track' => 'bieber'
));
$request->setAuth('myusername', 'mypassword');
$factory = new PhpStreamRequestFactory();
$stream = $factory->fromRequest($request);
// Read until the stream is closed
while (!$stream->feof()) {
// Read a line from the stream
$line = $stream->readLine();
// JSON decode the line of data
$data = json_decode($line, true);
}
You can use the ``stream`` request option when using a static client to more easily create a streaming response.
.. code-block:: php
$stream = Guzzle::get('http://guzzlephp.org', array('stream' => true));
while (!$stream->feof()) {
echo $stream->readLine();
}

View File

@ -1,52 +0,0 @@
=============
URI templates
=============
The ``$uri`` passed to one of the client's request creational methods or the base URL of a client can utilize URI
templates. Guzzle supports the entire `URI templates RFC <http://tools.ietf.org/html/rfc6570>`_. URI templates add a
special syntax to URIs that replace template place holders with user defined variables.
Every request created by a Guzzle HTTP client passes through a URI template so that URI template expressions are
automatically expanded:
.. code-block:: php
$client = new Guzzle\Http\Client('https://example.com/', array('a' => 'hi'));
$request = $client->get('/{a}');
Because of URI template expansion, the URL of the above request will become ``https://example.com/hi``. Notice that
the template was expanded using configuration variables of the client. You can pass in custom URI template variables
by passing the URI of your request as an array where the first index of the array is the URI template and the second
index of the array are template variables that are merged into the client's configuration variables.
.. code-block:: php
$request = $client->get(array('/test{?a,b}', array('b' => 'there')));
The URL for this request will become ``https://test.com?a=hi&b=there``. URI templates aren't limited to just simple
variable replacements; URI templates can provide an enormous amount of flexibility when creating request URIs.
.. code-block:: php
$request = $client->get(array('http://example.com{+path}{/segments*}{?query,data*}', array(
'path' => '/foo/bar',
'segments' => array('one', 'two'),
'query' => 'test',
'data' => array(
'more' => 'value'
)
)));
The resulting URL would become ``http://example.com/foo/bar/one/two?query=test&more=value``.
By default, URI template expressions are enclosed in an opening and closing brace (e.g. ``{var}``). If you are working
with a web service that actually uses braces (e.g. Solr), then you can specify a custom regular expression to use to
match URI template expressions.
.. code-block:: php
$client->getUriTemplate()->setRegex('/\<\$(.+)\>/');
$client->get('/<$a>');
You can learn about all of the different features of URI templates by reading the
`URI templates RFC <http://tools.ietf.org/html/rfc6570>`_.

View File

@ -1,5 +0,0 @@
.. title:: Guzzle | PHP HTTP client and framework for consuming RESTful web services
.. toctree::
:hidden:
docs.rst

View File

@ -1,97 +0,0 @@
================
Guzzle iterators
================
Guzzle provides several SPL iterators that can be used with other SPL iterators, including Guzzle resource iterators.
Guzzle's ``guzzle/iterator`` component can also be used independently of the rest of Guzzle through Packagist and
Composer: https://packagist.org/packages/guzzle/iterator
ChunkedIterator
---------------
Pulls out multiple values from an inner iterator and yields and array of values for each outer iteration -- essentially
pulling out chunks of values from the inner iterator.
.. code-block:: php
use Guzzle\Iterator\ChunkedIterator;
$inner = new ArrayIterator(range(0, 8));
$chunkedIterator = new ChunkedIterator($inner, 2);
foreach ($chunkedIterator as $chunk) {
echo implode(', ', $chunk) . "\n";
}
// >>> 0, 1
// >>> 2, 3
// >>> 4, 5
// >>> 6, 7
// >>> 8
FilterIterator
--------------
This iterator is used to filter values out of the inner iterator. This iterator can be used when PHP 5.4's
CallbackFilterIterator is not available.
.. code-block:: php
use Guzzle\Iterator\FilterIterator;
$inner = new ArrayIterator(range(1, 10));
$filterIterator = new FilterIterator($inner, function ($value) {
return $value % 2;
});
foreach ($filterIterator as $value) {
echo $value . "\n";
}
// >>> 2
// >>> 4
// >>> 6
// >>> 8
// >>> 10
MapIterator
-----------
This iterator modifies the values of the inner iterator before yielding.
.. code-block:: php
use Guzzle\Iterator\MapIterator;
$inner = new ArrayIterator(range(0, 3));
$mapIterator = new MapIterator($inner, function ($value) {
return $value * 10;
});
foreach ($mapIterator as $value) {
echo $value . "\n";
}
// >>> 0
// >>> 10
// >>> 20
// >>> 30
MethodProxyIterator
-------------------
This decorator is useful when you need to expose a specific method from an inner iterator that might be wrapper
by one or more iterator decorators. This decorator proxies missing method calls to each inner iterator until one
of the inner iterators can fulfill the call.
.. code-block:: php
use Guzzle\Iterator\MethodProxyIterator;
$inner = new \ArrayIterator();
$proxy = new MethodProxyIterator($inner);
// Proxy method calls to the ArrayIterator
$proxy->append('a');
$proxy->append('b');

View File

@ -1,149 +0,0 @@
==================
Resource iterators
==================
Web services often implement pagination in their responses which requires the end-user to issue a series of consecutive
requests in order to fetch all of the data they asked for. Users of your web service client should not be responsible
for implementing the logic involved in iterating through pages of results. Guzzle provides a simple resource iterator
foundation to make it easier on web service client developers to offer a useful abstraction layer.
Getting an iterator from a client
---------------------------------
ResourceIteratorInterface Guzzle\Service\Client::getIterator($command [, array $commandOptions, array $iteratorOptions ])
The ``getIterator`` method of a ``Guzzle\Service\ClientInterface`` object provides a convenient interface for
instantiating a resource iterator for a specific command. This method implicitly uses a
``Guzzle\Service\Resource\ResourceIteratorFactoryInterface`` object to create resource iterators. Pass an
instantiated command object or the name of a command in the first argument. When passing the name of a command, the
command factory of the client will create the command by name using the ``$commandOptions`` array. The third argument
may be used to pass an array of options to the constructor of the instantiated ``ResourceIteratorInterface`` object.
.. code-block:: php
$iterator = $client->getIterator('get_users');
foreach ($iterator as $user) {
echo $user['name'] . ' age ' . $user['age'] . PHP_EOL;
}
The above code sample might execute a single request or a thousand requests. As a consumer of a web service, I don't
care. I just want to iterate over all of the users.
Iterator options
~~~~~~~~~~~~~~~~
The two universal options that iterators should support are ``limit`` and ``page_size``. Using the ``limit`` option
tells the resource iterator to attempt to limit the total number of iterated resources to a specific amount. Keep in
mind that this is not always possible due to limitations that may be inherent to a web service. The ``page_size``
option is used to tell a resource iterator how many resources to request per page of results. Much like the ``limit``
option, you can not rely on getting back exactly the number of resources your specify in the ``page_size`` option.
.. note::
The ``limit`` and ``page_size`` options can also be specified on an iterator using the ``setLimit($limit)`` and
``setPageSize($pageSize)`` methods.
Resolving iterator class names
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The default resource iterator factory of a client object expects that your iterators are stored under the ``Model``
folder of your client and that an iterator is names after the CamelCase name of a command followed by the word
"Iterator". For example, if you wanted to create an iterator for the ``get_users`` command, then your iterator class
would be ``Model\GetUsersIterator`` and would be stored in ``Model/GetUsersIterator.php``.
Creating an iterator
--------------------
While not required, resource iterators in Guzzle typically iterate using a ``Guzzle\Service\Command\CommandInterface``
object. ``Guzzle\Service\Resource\ResourceIterator``, the default iterator implementation that you should extend,
accepts a command object and array of iterator options in its constructor. The command object passed to the resource
iterator is expected to be ready to execute and not previously executed. The resource iterator keeps a reference of
this command and clones the original command each time a subsequent request needs to be made to fetch more data.
Implement the sendRequest method
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The most important thing (and usually the only thing) you need to do when creating a resource iterator is to implement
the ``sendRequest()`` method of the resource iterator. The ``sendRequest()`` method is called when you begin
iterating or if there are no resources left to iterate and it you expect to retrieve more resources by making a
subsequent request. The ``$this->command`` property of the resource iterator is updated with a cloned copy of the
original command object passed into the constructor of the iterator. Use this command object to issue your subsequent
requests.
The ``sendRequest()`` method must return an array of the resources you retrieved from making the subsequent call.
Returning an empty array will stop the iteration. If you suspect that your web service client will occasionally return
an empty result set but still requires further iteration, then you must implement a sort of loop in your
``sendRequest()`` method that will continue to issue subsequent requests until your reach the end of the paginated
result set or until additional resources are retrieved from the web service.
Update the nextToken property
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Beyond fetching more results, the ``sendRequest()`` method is responsible for updating the ``$this->nextToken``
property of the iterator. Setting this property to anything other than null tells the iterator that issuing a
subsequent request using the nextToken value will probably return more results. You must continually update this
value in your ``sendRequest()`` method as each response is received from the web service.
Example iterator
----------------
Let's say you want to implement a resource iterator for the ``get_users`` command of your web service. The
``get_users`` command receives a response that contains a list of users, and if there are more pages of results to
retrieve, returns a value called ``next_user``. This return value is known as the **next token** and should be used to
issue subsequent requests.
Assume the response to a ``get_users`` command returns JSON data that looks like this:
.. code-block:: javascript
{
"users": [
{ "name": "Craig Johnson", "age": 10 },
{ "name": "Tom Barker", "age": 20 },
{ "name": "Bob Mitchell", "age": 74 }
],
"next_user": "Michael Dowling"
}
Assume that because there is a ``next_user`` value, there will be more users if a subsequent request is issued. If the
``next_user`` value is missing or null, then we know there are no more results to fetch. Let's implement a resource
iterator for this command.
.. code-block:: php
namespace MyService\Model;
use Guzzle\Service\Resource\ResourceIterator;
/**
* Iterate over a get_users command
*/
class GetUsersIterator extends ResourceIterator
{
protected function sendRequest()
{
// If a next token is set, then add it to the command
if ($this->nextToken) {
$this->command->set('next_user', $this->nextToken);
}
// Execute the command and parse the result
$result = $this->command->execute();
// Parse the next token
$this->nextToken = isset($result['next_user']) ? $result['next_user'] : false;
return $result['users'];
}
}
As you can see, it's pretty simple to implement an iterator. There are a few things that you should notice from this
example:
1. You do not need to create a new command in the ``sendRequest()`` method. A new command object is cloned from the
original command passed into the constructor of the iterator before the ``sendRequest()`` method is called.
Remember that the resource iterator expects a command that has not been executed.
2. When the ``sendRequest()`` method is first called, you will not have a ``$this->nextToken`` value, so always check
before setting it on a command. Notice that the next token is being updated each time a request is sent.
3. After fetching more resources from the service, always return an array of resources.

View File

@ -1,18 +0,0 @@
============
Async plugin
============
The AsyncPlugin allows you to send requests that do not wait on a response. This is handled through cURL by utilizing
the progress event. When a request has sent all of its data to the remote server, Guzzle adds a 1ms timeout on the
request and instructs cURL to not download the body of the response. The async plugin then catches the exception and
adds a mock response to the request, along with an X-Guzzle-Async header to let you know that the response was not
fully downloaded.
.. code-block:: php
use Guzzle\Http\Client;
use Guzzle\Plugin\Async\AsyncPlugin;
$client = new Client('http://www.example.com');
$client->addSubscriber(new AsyncPlugin());
$response = $client->get()->send();

View File

@ -1,22 +0,0 @@
====================
Backoff retry plugin
====================
The ``Guzzle\Plugin\Backoff\BackoffPlugin`` automatically retries failed HTTP requests using custom backoff strategies:
.. code-block:: php
use Guzzle\Http\Client;
use Guzzle\Plugin\Backoff\BackoffPlugin;
$client = new Client('http://www.test.com/');
// Use a static factory method to get a backoff plugin using the exponential backoff strategy
$backoffPlugin = BackoffPlugin::getExponentialBackoff();
// Add the backoff plugin to the client object
$client->addSubscriber($backoffPlugin);
The BackoffPlugin's constructor accepts a ``Guzzle\Plugin\Backoff\BackoffStrategyInterface`` object that is used to
determine when a retry should be issued and how long to delay between retries. The above code example shows how to
attach a BackoffPlugin to a client that is pre-configured to retry failed 500 and 503 responses using truncated
exponential backoff (emulating the behavior of Guzzle 2's ExponentialBackoffPlugin).

View File

@ -1,169 +0,0 @@
=================
HTTP Cache plugin
=================
Guzzle can leverage HTTP's caching specifications using the ``Guzzle\Plugin\Cache\CachePlugin``. The CachePlugin
provides a private transparent proxy cache that caches HTTP responses. The caching logic, based on
`RFC 2616 <http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html>`_, uses HTTP headers to control caching behavior,
cache lifetime, and supports Vary, ETag, and Last-Modified based revalidation:
.. code-block:: php
use Guzzle\Http\Client;
use Doctrine\Common\Cache\FilesystemCache;
use Guzzle\Cache\DoctrineCacheAdapter;
use Guzzle\Plugin\Cache\CachePlugin;
use Guzzle\Plugin\Cache\DefaultCacheStorage;
$client = new Client('http://www.test.com/');
$cachePlugin = new CachePlugin(array(
'storage' => new DefaultCacheStorage(
new DoctrineCacheAdapter(
new FilesystemCache('/path/to/cache/files')
)
)
));
// Add the cache plugin to the client object
$client->addSubscriber($cachePlugin);
$client->get('http://www.wikipedia.org/')->send();
// The next request will revalidate against the origin server to see if it
// has been modified. If a 304 response is received the response will be
// served from cache
$client->get('http://www.wikipedia.org/')->send();
The cache plugin intercepts GET and HEAD requests before they are actually transferred to the origin server. The cache
plugin then generates a hash key based on the request method and URL, and checks to see if a response exists in the cache. If
a response exists in the cache, the cache adapter then checks to make sure that the caching rules associated with the response
satisfy the request, and ensures that response still fresh. If the response is acceptable for the request any required
revalidation, then the cached response is served instead of contacting the origin server.
Vary
----
Cache keys are derived from a request method and a request URL. Multiple responses can map to the same cache key and
stored in Guzzle's underlying cache storage object. You should use the ``Vary`` HTTP header to tell the cache storage
object that the cache response must have been cached for a request that matches the headers specified in the Vary header
of the request. This allows you to have specific cache entries for the same request URL but variations in a request's
headers determine which cache entry is served. Please see the http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44
for more information.
Cache options
-------------
There are several options you can add to requests or clients to modify the behavior of the cache plugin.
Override cache TTL
~~~~~~~~~~~~~~~~~~
You can override the number of seconds a cacheable response is stored in the cache by setting the
``cache.override_ttl`` parameter on the params object of a request:
.. code-block:: php
// If the response to the request is cacheable, then the response will be cached for 100 seconds
$request->getParams()->set('cache.override_ttl', 100);
If a response doesn't specify any freshness policy, it will be kept in cache for 3600 seconds by default.
Custom caching decision
~~~~~~~~~~~~~~~~~~~~~~~
If the service you are interacting with does not return caching headers or returns responses that are normally
something that would not be cached, you can set a custom ``can_cache`` object on the constructor of the CachePlugin
and provide a ``Guzzle\Plugin\Cache\CanCacheInterface`` object. You can use the
``Guzzle\Plugin\Cache\CallbackCanCacheStrategy`` to easily make a caching decision based on an HTTP request and
response.
Revalidation options
~~~~~~~~~~~~~~~~~~~~
You can change the revalidation behavior of a request using the ``cache.revalidate`` parameter. Setting this
parameter to ``never`` will ensure that a revalidation request is never sent, and the response is always served from
the origin server. Setting this parameter to ``skip`` will never revalidate and uses the response stored in the cache.
Normalizing requests for caching
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use the ``cache.key_filter`` parameter if you wish to strip certain query string parameters from your
request before creating a unique hash for the request. This parameter can be useful if your requests have query
string values that cause each request URL to be unique (thus preventing a cache hit). The ``cache.key_filter``
format is simply a comma separated list of query string values to remove from the URL when creating a cache key.
For example, here we are saying that the ``a`` and ``q`` query string variables should be ignored when generating a
cache key for the request:
.. code-block:: php
$request->getParams()->set('cache.key_filter', 'a, q');
Other options
~~~~~~~~~~~~~
There are many other options available to the CachePlugin that can meet almost any caching requirement, including
custom revalidation implementations, custom cache key generators, custom caching decision strategies, and custom
cache storage objects. Take a look the constructor of ``Guzzle\Plugin\Cache\CachePlugin`` for more information.
Setting Client-wide cache settings
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can specify cache settings for every request created by a client by adding cache settings to the configuration
options of a client.
.. code-block:: php
$client = new Guzzle\Http\Client('http://www.test.com', array(
'request.params' => array(
'cache.override_ttl' => 3600,
'params.cache.revalidate' => 'never'
)
));
echo $client->get('/')->getParams()->get('cache.override_ttl');
// >>> 3600
echo $client->get('/')->getParams()->get('cache.revalidate');
// >>> never
Cache revalidation
------------------
If the cache plugin determines that a response to a GET request needs revalidation, a conditional GET is transferred
to the origin server. If the origin server returns a 304 response, then a response containing the merged headers of
the cached response with the new response and the entity body of the cached response is returned. Custom revalidation
strategies can be injected into a CachePlugin if needed.
Cache adapters
--------------
Guzzle doesn't try to reinvent the wheel when it comes to caching or logging. Plenty of other frameworks have
excellent solutions in place that you are probably already using in your applications. Guzzle uses adapters for
caching and logging. The cache plugin requires a cache adapter so that is can store responses in a cache. Guzzle
currently supports cache adapters for `Doctrine 2.0 <http://www.doctrine-project.org/>`_ and the
`Zend Framework <http://framework.zend.com>`_.
Doctrine cache adapter
~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: php
use Doctrine\Common\Cache\ArrayCache;
use Guzzle\Cache\DoctrineCacheAdapter;
use Guzzle\Plugin\Cache\CachePlugin;
$backend = new ArrayCache();
$adapter = new DoctrineCacheAdapter($backend);
$cache = new CachePlugin($adapter);
Zend Framework cache adapter
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: php
use Guzzle\Cache\ZendCacheAdapter;
use Zend\Cache\Backend\TestBackend;
$backend = new TestBackend();
$adapter = new ZendCacheAdapter($backend);
$cache = new CachePlugin($adapter);

View File

@ -1,33 +0,0 @@
=============
Cookie plugin
=============
Some web services require a Cookie in order to maintain a session. The ``Guzzle\Plugin\Cookie\CookiePlugin`` will add
cookies to requests and parse cookies from responses using a CookieJar object:
.. code-block:: php
use Guzzle\Http\Client;
use Guzzle\Plugin\Cookie\CookiePlugin;
use Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar;
$cookiePlugin = new CookiePlugin(new ArrayCookieJar());
// Add the cookie plugin to a client
$client = new Client('http://www.test.com/');
$client->addSubscriber($cookiePlugin);
// Send the request with no cookies and parse the returned cookies
$client->get('http://www.yahoo.com/')->send();
// Send the request again, noticing that cookies are being sent
$request = $client->get('http://www.yahoo.com/');
$request->send();
echo $request;
You can disable cookies per-request by setting the ``cookies.disable`` value to true on a request's params object.
.. code-block:: php
$request->getParams()->set('cookies.disable', true);

View File

@ -1,93 +0,0 @@
================
Creating plugins
================
.. highlight:: php
Guzzle is extremely extensible because of the behavioral modifications that can be added to requests, clients, and
commands using an event system. Before and after the majority of actions are taken in the library, an event is emitted
with the name of the event and context surrounding the event. Observers can subscribe to a subject and modify the
subject based on the events received. Guzzle's event system utilizes the Symfony2 EventDispatcher and is the backbone
of its plugin architecture.
Overview
--------
Plugins must implement the ``Symfony\Component\EventDispatcher\EventSubscriberInterface`` interface. The
``EventSubscriberInterface`` requires that your class implements a static method, ``getSubscribedEvents()``, that
returns an associative array mapping events to methods on the object. See the
`Symfony2 documentation <http://symfony.com/doc/2.0/book/internals.html#the-event-dispatcher>`_ for more information.
Plugins can be attached to any subject, or object in Guzzle that implements that
``Guzzle\Common\HasDispatcherInterface``.
Subscribing to a subject
~~~~~~~~~~~~~~~~~~~~~~~~
You can subscribe an instantiated observer to an event by calling ``addSubscriber`` on a subject.
.. code-block:: php
$testPlugin = new TestPlugin();
$client->addSubscriber($testPlugin);
You can also subscribe to only specific events using a closure::
$client->getEventDispatcher()->addListener('request.create', function(Event $event) {
echo $event->getName();
echo $event['request'];
});
``Guzzle\Common\Event`` objects are passed to notified functions. The Event object has a ``getName()`` method which
return the name of the emitted event and may contain contextual information that can be accessed like an array.
Knowing what events to listen to
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Any class that implements the ``Guzzle\Common\HasDispatcherInterface`` must implement a static method,
``getAllEvents()``, that returns an array of the events that are emitted from the object. You can browse the source
to see each event, or you can call the static method directly in your code to get a list of available events.
Event hooks
-----------
* :ref:`client-events`
* :ref:`service-client-events`
* :ref:`request-events`
* ``Guzzle\Http\Curl\CurlMulti``:
* :ref:`service-builder-events`
Examples of the event system
----------------------------
Simple Echo plugin
~~~~~~~~~~~~~~~~~~
This simple plugin prints a string containing the request that is about to be sent by listening to the
``request.before_send`` event::
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class EchoPlugin implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array('request.before_send' => 'onBeforeSend');
}
public function onBeforeSend(Guzzle\Common\Event $event)
{
echo 'About to send a request: ' . $event['request'] . "\n";
}
}
$client = new Guzzle\Service\Client('http://www.test.com/');
// Create the plugin and add it as an event subscriber
$plugin = new EchoPlugin();
$client->addSubscriber($plugin);
// Send a request and notice that the request is printed to the screen
$client->get('/')->send();
Running the above code will print a string containing the HTTP request that is about to be sent.

View File

@ -1,32 +0,0 @@
==========================
cURL authentication plugin
==========================
.. warning::
The CurlAuthPlugin is deprecated. You should use the `auth` parameter of a client to add authorization headers to
every request created by a client.
.. code-block:: php
$client->setDefaultOption('auth', array('username', 'password', 'Basic|Digest|NTLM|Any'));
If your web service client requires basic authorization, then you can use the CurlAuthPlugin to easily add an
Authorization header to each request sent by the client.
.. code-block:: php
use Guzzle\Http\Client;
use Guzzle\Plugin\CurlAuth\CurlAuthPlugin;
$client = new Client('http://www.test.com/');
// Add the auth plugin to the client object
$authPlugin = new CurlAuthPlugin('username', 'password');
$client->addSubscriber($authPlugin);
$response = $client->get('projects/1/people')->send();
$xml = new SimpleXMLElement($response->getBody(true));
foreach ($xml->person as $person) {
echo $person->email . "\n";
}

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