mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-25 10:09:20 +03:00
Remove unused GuzzleHttp library.
This commit is contained in:
parent
841c4d59e3
commit
142272b522
74 changed files with 0 additions and 14006 deletions
|
|
@ -1,23 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Adapter;
|
|
||||||
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter interface used to transfer HTTP requests.
|
|
||||||
*
|
|
||||||
* @link http://docs.guzzlephp.org/en/guzzle4/adapters.html for a full
|
|
||||||
* explanation of adapters and their responsibilities.
|
|
||||||
*/
|
|
||||||
interface AdapterInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Transfers an HTTP request and populates a response
|
|
||||||
*
|
|
||||||
* @param TransactionInterface $transaction Transaction abject to populate
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function send(TransactionInterface $transaction);
|
|
||||||
}
|
|
||||||
|
|
@ -1,158 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Adapter\Curl;
|
|
||||||
|
|
||||||
use GuzzleHttp\Adapter\TransactionInterface;
|
|
||||||
use GuzzleHttp\Exception\AdapterException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides context for a Curl transaction, including active handles,
|
|
||||||
* pending transactions, and whether or not this is a batch or single
|
|
||||||
* transaction.
|
|
||||||
*/
|
|
||||||
class BatchContext
|
|
||||||
{
|
|
||||||
/** @var resource Curl multi resource */
|
|
||||||
private $multi;
|
|
||||||
|
|
||||||
/** @var \SplObjectStorage Map of transactions to curl resources */
|
|
||||||
private $handles;
|
|
||||||
|
|
||||||
/** @var \Iterator Yields pending transactions */
|
|
||||||
private $pending;
|
|
||||||
|
|
||||||
/** @var bool Whether or not to throw transactions */
|
|
||||||
private $throwsExceptions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param resource $multiHandle Initialized curl_multi resource
|
|
||||||
* @param bool $throwsExceptions Whether or not exceptions are thrown
|
|
||||||
* @param \Iterator $pending Iterator yielding pending transactions
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
$multiHandle,
|
|
||||||
$throwsExceptions,
|
|
||||||
\Iterator $pending = null
|
|
||||||
) {
|
|
||||||
$this->multi = $multiHandle;
|
|
||||||
$this->handles = new \SplObjectStorage();
|
|
||||||
$this->throwsExceptions = $throwsExceptions;
|
|
||||||
$this->pending = $pending;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a transaction for a given curl handle
|
|
||||||
*
|
|
||||||
* @param resource $handle Curl handle
|
|
||||||
*
|
|
||||||
* @return TransactionInterface
|
|
||||||
* @throws AdapterException if a transaction is not found
|
|
||||||
*/
|
|
||||||
public function findTransaction($handle)
|
|
||||||
{
|
|
||||||
foreach ($this->handles as $transaction) {
|
|
||||||
if ($this->handles[$transaction] === $handle) {
|
|
||||||
return $transaction;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new AdapterException('No curl handle was found');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if there are any remaining pending transactions
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function hasPending()
|
|
||||||
{
|
|
||||||
return $this->pending && $this->pending->valid();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pop the next transaction from the transaction queue
|
|
||||||
*
|
|
||||||
* @return TransactionInterface|null
|
|
||||||
*/
|
|
||||||
public function nextPending()
|
|
||||||
{
|
|
||||||
if (!$this->hasPending()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$current = $this->pending->current();
|
|
||||||
$this->pending->next();
|
|
||||||
|
|
||||||
return $current;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the batch is to throw exceptions on error
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function throwsExceptions()
|
|
||||||
{
|
|
||||||
return $this->throwsExceptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the curl_multi handle
|
|
||||||
*
|
|
||||||
* @return resource
|
|
||||||
*/
|
|
||||||
public function getMultiHandle()
|
|
||||||
{
|
|
||||||
return $this->multi;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a transaction to the multi handle
|
|
||||||
*
|
|
||||||
* @param TransactionInterface $transaction Transaction to add
|
|
||||||
* @param resource $handle Resource to use with the handle
|
|
||||||
*
|
|
||||||
* @throws AdapterException If the handle is already registered
|
|
||||||
*/
|
|
||||||
public function addTransaction(TransactionInterface $transaction, $handle)
|
|
||||||
{
|
|
||||||
if (isset($this->handles[$transaction])) {
|
|
||||||
throw new AdapterException('Transaction already registered');
|
|
||||||
}
|
|
||||||
|
|
||||||
$code = curl_multi_add_handle($this->multi, $handle);
|
|
||||||
if ($code != CURLM_OK) {
|
|
||||||
MultiAdapter::throwMultiError($code);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->handles[$transaction] = $handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a transaction and associated handle from the context
|
|
||||||
*
|
|
||||||
* @param TransactionInterface $transaction Transaction to remove
|
|
||||||
*
|
|
||||||
* @return array Returns the curl_getinfo array
|
|
||||||
* @throws AdapterException if the transaction is not found
|
|
||||||
*/
|
|
||||||
public function removeTransaction(TransactionInterface $transaction)
|
|
||||||
{
|
|
||||||
if (!isset($this->handles[$transaction])) {
|
|
||||||
throw new AdapterException('Transaction not registered');
|
|
||||||
}
|
|
||||||
|
|
||||||
$handle = $this->handles[$transaction];
|
|
||||||
|
|
||||||
$code = curl_multi_remove_handle($this->multi, $handle);
|
|
||||||
if ($code != CURLM_OK) {
|
|
||||||
MultiAdapter::throwMultiError($code);
|
|
||||||
}
|
|
||||||
|
|
||||||
$info = curl_getinfo($handle);
|
|
||||||
curl_close($handle);
|
|
||||||
unset($this->handles[$transaction]);
|
|
||||||
|
|
||||||
return $info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Adapter\Curl;
|
|
||||||
|
|
||||||
use GuzzleHttp\Adapter\AdapterInterface;
|
|
||||||
use GuzzleHttp\Adapter\TransactionInterface;
|
|
||||||
use GuzzleHttp\Event\RequestEvents;
|
|
||||||
use GuzzleHttp\Exception\AdapterException;
|
|
||||||
use GuzzleHttp\Message\MessageFactoryInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTTP adapter that uses cURL easy handles as a transport layer.
|
|
||||||
*
|
|
||||||
* Requires PHP 5.5+
|
|
||||||
*
|
|
||||||
* When using the CurlAdapter, custom curl options can be specified as an
|
|
||||||
* associative array of curl option constants mapping to values in the
|
|
||||||
* **curl** key of a request's configuration options.
|
|
||||||
*/
|
|
||||||
class CurlAdapter implements AdapterInterface
|
|
||||||
{
|
|
||||||
/** @var CurlFactory */
|
|
||||||
private $curlFactory;
|
|
||||||
|
|
||||||
/** @var MessageFactoryInterface */
|
|
||||||
private $messageFactory;
|
|
||||||
|
|
||||||
/** @var array Array of curl easy handles */
|
|
||||||
private $handles = [];
|
|
||||||
|
|
||||||
/** @var array Array of owned curl easy handles */
|
|
||||||
private $ownedHandles = [];
|
|
||||||
|
|
||||||
/** @var int Total number of idle handles to keep in cache */
|
|
||||||
private $maxHandles;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accepts an associative array of options:
|
|
||||||
*
|
|
||||||
* - handle_factory: Optional callable factory used to create cURL handles.
|
|
||||||
* The callable is invoked with the following arguments:
|
|
||||||
* TransactionInterface, MessageFactoryInterface, and an optional cURL
|
|
||||||
* handle to modify. The factory method must then return a cURL resource.
|
|
||||||
* - max_handles: Maximum number of idle handles (defaults to 5).
|
|
||||||
*
|
|
||||||
* @param MessageFactoryInterface $messageFactory
|
|
||||||
* @param array $options Array of options to use with the adapter
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
MessageFactoryInterface $messageFactory,
|
|
||||||
array $options = []
|
|
||||||
) {
|
|
||||||
$this->handles = $this->ownedHandles = [];
|
|
||||||
$this->messageFactory = $messageFactory;
|
|
||||||
$this->curlFactory = isset($options['handle_factory'])
|
|
||||||
? $options['handle_factory']
|
|
||||||
: new CurlFactory();
|
|
||||||
$this->maxHandles = isset($options['max_handles'])
|
|
||||||
? $options['max_handles']
|
|
||||||
: 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __destruct()
|
|
||||||
{
|
|
||||||
foreach ($this->handles as $handle) {
|
|
||||||
if (is_resource($handle)) {
|
|
||||||
curl_close($handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function send(TransactionInterface $transaction)
|
|
||||||
{
|
|
||||||
RequestEvents::emitBefore($transaction);
|
|
||||||
if ($response = $transaction->getResponse()) {
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
$factory = $this->curlFactory;
|
|
||||||
$handle = $factory(
|
|
||||||
$transaction,
|
|
||||||
$this->messageFactory,
|
|
||||||
$this->checkoutEasyHandle()
|
|
||||||
);
|
|
||||||
|
|
||||||
curl_exec($handle);
|
|
||||||
$info = curl_getinfo($handle);
|
|
||||||
$info['curl_result'] = curl_errno($handle);
|
|
||||||
|
|
||||||
if ($info['curl_result']) {
|
|
||||||
$this->handleError($transaction, $info, $handle);
|
|
||||||
} else {
|
|
||||||
$this->releaseEasyHandle($handle);
|
|
||||||
RequestEvents::emitComplete($transaction, $info);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $transaction->getResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function handleError(
|
|
||||||
TransactionInterface $transaction,
|
|
||||||
$info,
|
|
||||||
$handle
|
|
||||||
) {
|
|
||||||
$error = curl_error($handle);
|
|
||||||
$this->releaseEasyHandle($handle);
|
|
||||||
RequestEvents::emitError(
|
|
||||||
$transaction,
|
|
||||||
new AdapterException("cURL error {$info['curl_result']}: {$error}"),
|
|
||||||
$info
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function checkoutEasyHandle()
|
|
||||||
{
|
|
||||||
// Find an unused handle in the cache
|
|
||||||
if (false !== ($key = array_search(false, $this->ownedHandles, true))) {
|
|
||||||
$this->ownedHandles[$key] = true;
|
|
||||||
return $this->handles[$key];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a new handle
|
|
||||||
$handle = curl_init();
|
|
||||||
$id = (int) $handle;
|
|
||||||
$this->handles[$id] = $handle;
|
|
||||||
$this->ownedHandles[$id] = true;
|
|
||||||
|
|
||||||
return $handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function releaseEasyHandle($handle)
|
|
||||||
{
|
|
||||||
$id = (int) $handle;
|
|
||||||
if (count($this->ownedHandles) > $this->maxHandles) {
|
|
||||||
curl_close($this->handles[$id]);
|
|
||||||
unset($this->handles[$id], $this->ownedHandles[$id]);
|
|
||||||
} else {
|
|
||||||
curl_reset($handle);
|
|
||||||
$this->ownedHandles[$id] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,331 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Adapter\Curl;
|
|
||||||
|
|
||||||
use GuzzleHttp\Adapter\TransactionInterface;
|
|
||||||
use GuzzleHttp\Message\MessageFactoryInterface;
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
use GuzzleHttp\Stream;
|
|
||||||
use GuzzleHttp\Exception\AdapterException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates curl resources from a request and response object
|
|
||||||
*/
|
|
||||||
class CurlFactory
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Creates a cURL handle based on a transaction.
|
|
||||||
*
|
|
||||||
* @param TransactionInterface $transaction Holds a request and response
|
|
||||||
* @param MessageFactoryInterface $messageFactory Used to create responses
|
|
||||||
* @param null|resource $handle Optionally provide a curl handle to modify
|
|
||||||
*
|
|
||||||
* @return resource Returns a prepared cURL handle
|
|
||||||
* @throws AdapterException when an option cannot be applied
|
|
||||||
*/
|
|
||||||
public function __invoke(
|
|
||||||
TransactionInterface $transaction,
|
|
||||||
MessageFactoryInterface $messageFactory,
|
|
||||||
$handle = null
|
|
||||||
) {
|
|
||||||
$request = $transaction->getRequest();
|
|
||||||
$mediator = new RequestMediator($transaction, $messageFactory);
|
|
||||||
$options = $this->getDefaultOptions($request, $mediator);
|
|
||||||
$this->applyMethod($request, $options);
|
|
||||||
$this->applyTransferOptions($request, $mediator, $options);
|
|
||||||
$this->applyHeaders($request, $options);
|
|
||||||
unset($options['_headers']);
|
|
||||||
|
|
||||||
// Add adapter options from the request's configuration options
|
|
||||||
if ($config = $request->getConfig()['curl']) {
|
|
||||||
$options = $this->applyCustomCurlOptions($config, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$handle) {
|
|
||||||
$handle = curl_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_setopt_array($handle, $options);
|
|
||||||
|
|
||||||
return $handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getDefaultOptions(
|
|
||||||
RequestInterface $request,
|
|
||||||
RequestMediator $mediator
|
|
||||||
) {
|
|
||||||
$url = $request->getUrl();
|
|
||||||
|
|
||||||
// Strip fragment from URL. See:
|
|
||||||
// https://github.com/guzzle/guzzle/issues/453
|
|
||||||
if (($pos = strpos($url, '#')) !== false) {
|
|
||||||
$url = substr($url, 0, $pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
$config = $request->getConfig();
|
|
||||||
$options = array(
|
|
||||||
CURLOPT_URL => $url,
|
|
||||||
CURLOPT_CONNECTTIMEOUT => $config['connect_timeout'] ?: 150,
|
|
||||||
CURLOPT_RETURNTRANSFER => false,
|
|
||||||
CURLOPT_HEADER => false,
|
|
||||||
CURLOPT_WRITEFUNCTION => array($mediator, 'writeResponseBody'),
|
|
||||||
CURLOPT_HEADERFUNCTION => array($mediator, 'receiveResponseHeader'),
|
|
||||||
CURLOPT_READFUNCTION => array($mediator, 'readRequestBody'),
|
|
||||||
CURLOPT_HTTP_VERSION => $request->getProtocolVersion() === '1.0'
|
|
||||||
? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1,
|
|
||||||
CURLOPT_SSL_VERIFYPEER => 1,
|
|
||||||
CURLOPT_SSL_VERIFYHOST => 2,
|
|
||||||
'_headers' => $request->getHeaders()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (defined('CURLOPT_PROTOCOLS')) {
|
|
||||||
// Allow only HTTP and HTTPS protocols
|
|
||||||
$options[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add CURLOPT_ENCODING if Accept-Encoding header is provided
|
|
||||||
if ($request->hasHeader('Accept-Encoding')) {
|
|
||||||
$options[CURLOPT_ENCODING] = $request->getHeader('Accept-Encoding');
|
|
||||||
// Let cURL set the Accept-Encoding header. Without this change
|
|
||||||
// curl could add a duplicate value.
|
|
||||||
$this->removeHeader('Accept-Encoding', $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $options;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function applyMethod(RequestInterface $request, array &$options)
|
|
||||||
{
|
|
||||||
$method = $request->getMethod();
|
|
||||||
if ($method == 'HEAD') {
|
|
||||||
$options[CURLOPT_NOBODY] = true;
|
|
||||||
unset($options[CURLOPT_WRITEFUNCTION], $options[CURLOPT_READFUNCTION]);
|
|
||||||
} else {
|
|
||||||
$options[CURLOPT_CUSTOMREQUEST] = $method;
|
|
||||||
if (!$request->getBody()) {
|
|
||||||
unset($options[CURLOPT_READFUNCTION]);
|
|
||||||
} else {
|
|
||||||
$this->applyBody($request, $options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function applyBody(RequestInterface $request, array &$options)
|
|
||||||
{
|
|
||||||
if ($request->hasHeader('Content-Length')) {
|
|
||||||
$size = (int) $request->getHeader('Content-Length');
|
|
||||||
} else {
|
|
||||||
$size = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$request->getBody()->seek(0);
|
|
||||||
|
|
||||||
// You can send the body as a string using curl's CURLOPT_POSTFIELDS
|
|
||||||
if (($size !== null && $size < 32768) ||
|
|
||||||
isset($request->getConfig()['curl']['body_as_string'])
|
|
||||||
) {
|
|
||||||
$options[CURLOPT_POSTFIELDS] = $request->getBody()->getContents();
|
|
||||||
// Don't duplicate the Content-Length header
|
|
||||||
$this->removeHeader('Content-Length', $options);
|
|
||||||
$this->removeHeader('Transfer-Encoding', $options);
|
|
||||||
} else {
|
|
||||||
$options[CURLOPT_UPLOAD] = true;
|
|
||||||
// Let cURL handle setting the Content-Length header
|
|
||||||
if ($size !== null) {
|
|
||||||
$options[CURLOPT_INFILESIZE] = $size;
|
|
||||||
$this->removeHeader('Content-Length', $options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the Expect header is not present, prevent curl from adding it
|
|
||||||
if (!$request->hasHeader('Expect')) {
|
|
||||||
$options[CURLOPT_HTTPHEADER][] = 'Expect:';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function applyHeaders(RequestInterface $request, array &$options)
|
|
||||||
{
|
|
||||||
foreach ($options['_headers'] as $name => $values) {
|
|
||||||
$options[CURLOPT_HTTPHEADER][] = $name . ': ' . implode(', ', $values);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the Expect header if one was not set
|
|
||||||
if (!$request->hasHeader('Accept')) {
|
|
||||||
$options[CURLOPT_HTTPHEADER][] = 'Accept:';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function applyTransferOptions(
|
|
||||||
RequestInterface $request,
|
|
||||||
RequestMediator $mediator,
|
|
||||||
array &$options
|
|
||||||
) {
|
|
||||||
static $methods;
|
|
||||||
if (!$methods) {
|
|
||||||
$methods = array_flip(get_class_methods(__CLASS__));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($request->getConfig()->toArray() as $key => $value) {
|
|
||||||
$method = "add_{$key}";
|
|
||||||
if (isset($methods[$method])) {
|
|
||||||
$this->{$method}($request, $mediator, $options, $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_debug(
|
|
||||||
RequestInterface $request,
|
|
||||||
RequestMediator $mediator,
|
|
||||||
&$options,
|
|
||||||
$value
|
|
||||||
) {
|
|
||||||
if ($value) {
|
|
||||||
$options[CURLOPT_STDERR] = is_resource($value) ? $value : STDOUT;
|
|
||||||
$options[CURLOPT_VERBOSE] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_proxy(
|
|
||||||
RequestInterface $request,
|
|
||||||
RequestMediator $mediator,
|
|
||||||
&$options,
|
|
||||||
$value
|
|
||||||
) {
|
|
||||||
if (!is_array($value)) {
|
|
||||||
$options[CURLOPT_PROXY] = $value;
|
|
||||||
} else {
|
|
||||||
$scheme = $request->getScheme();
|
|
||||||
if (isset($value[$scheme])) {
|
|
||||||
$options[CURLOPT_PROXY] = $value[$scheme];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_timeout(
|
|
||||||
RequestInterface $request,
|
|
||||||
RequestMediator $mediator,
|
|
||||||
&$options,
|
|
||||||
$value
|
|
||||||
) {
|
|
||||||
$options[CURLOPT_TIMEOUT_MS] = $value * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_connect_timeout(
|
|
||||||
RequestInterface $request,
|
|
||||||
RequestMediator $mediator,
|
|
||||||
&$options,
|
|
||||||
$value
|
|
||||||
) {
|
|
||||||
$options[CURLOPT_CONNECTTIMEOUT_MS] = $value * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_verify(
|
|
||||||
RequestInterface $request,
|
|
||||||
RequestMediator $mediator,
|
|
||||||
&$options,
|
|
||||||
$value
|
|
||||||
) {
|
|
||||||
if ($value === false) {
|
|
||||||
unset($options[CURLOPT_CAINFO]);
|
|
||||||
$options[CURLOPT_SSL_VERIFYHOST] = 0;
|
|
||||||
$options[CURLOPT_SSL_VERIFYPEER] = false;
|
|
||||||
} elseif ($value === true || is_string($value)) {
|
|
||||||
$options[CURLOPT_SSL_VERIFYHOST] = 2;
|
|
||||||
$options[CURLOPT_SSL_VERIFYPEER] = true;
|
|
||||||
if ($value !== true) {
|
|
||||||
if (!file_exists($value)) {
|
|
||||||
throw new AdapterException('SSL certificate authority file'
|
|
||||||
. " not found: {$value}");
|
|
||||||
}
|
|
||||||
$options[CURLOPT_CAINFO] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_cert(
|
|
||||||
RequestInterface $request,
|
|
||||||
RequestMediator $mediator,
|
|
||||||
&$options,
|
|
||||||
$value
|
|
||||||
) {
|
|
||||||
if (!file_exists($value)) {
|
|
||||||
throw new AdapterException("SSL certificate not found: {$value}");
|
|
||||||
}
|
|
||||||
|
|
||||||
$options[CURLOPT_SSLCERT] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_ssl_key(
|
|
||||||
RequestInterface $request,
|
|
||||||
RequestMediator $mediator,
|
|
||||||
&$options,
|
|
||||||
$value
|
|
||||||
) {
|
|
||||||
if (is_array($value)) {
|
|
||||||
$options[CURLOPT_SSLKEYPASSWD] = $value[1];
|
|
||||||
$value = $value[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!file_exists($value)) {
|
|
||||||
throw new AdapterException("SSL private key not found: {$value}");
|
|
||||||
}
|
|
||||||
|
|
||||||
$options[CURLOPT_SSLKEY] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_save_to(
|
|
||||||
RequestInterface $request,
|
|
||||||
RequestMediator $mediator,
|
|
||||||
&$options,
|
|
||||||
$value
|
|
||||||
) {
|
|
||||||
$mediator->setResponseBody(is_string($value)
|
|
||||||
? Stream\create(fopen($value, 'w'))
|
|
||||||
: Stream\create($value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes an array of curl options specified in the 'curl' option of a
|
|
||||||
* request's configuration array and maps them to CURLOPT_* options.
|
|
||||||
*
|
|
||||||
* This method is only called when a request has a 'curl' config setting.
|
|
||||||
* Array key strings that start with CURL that have a matching constant
|
|
||||||
* value will be automatically converted to the matching constant.
|
|
||||||
*
|
|
||||||
* @param array $config Configuration array of custom curl option
|
|
||||||
* @param array $options Array of existing curl options
|
|
||||||
*
|
|
||||||
* @return array Returns a new array of curl options
|
|
||||||
*/
|
|
||||||
private function applyCustomCurlOptions(array $config, array $options)
|
|
||||||
{
|
|
||||||
unset($config['body_as_string']);
|
|
||||||
$curlOptions = [];
|
|
||||||
|
|
||||||
// Map curl constant strings to defined values
|
|
||||||
foreach ($config as $key => $value) {
|
|
||||||
if (defined($key) && substr($key, 0, 4) === 'CURL') {
|
|
||||||
$key = constant($key);
|
|
||||||
}
|
|
||||||
$curlOptions[$key] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $curlOptions + $options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a header from the options array
|
|
||||||
*
|
|
||||||
* @param string $name Case-insensitive header to remove
|
|
||||||
* @param array $options Array of options to modify
|
|
||||||
*/
|
|
||||||
private function removeHeader($name, array &$options)
|
|
||||||
{
|
|
||||||
foreach (array_keys($options['_headers']) as $key) {
|
|
||||||
if (!strcasecmp($key, $name)) {
|
|
||||||
unset($options['_headers'][$key]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,284 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Adapter\Curl;
|
|
||||||
|
|
||||||
use GuzzleHttp\Adapter\AdapterInterface;
|
|
||||||
use GuzzleHttp\Adapter\ParallelAdapterInterface;
|
|
||||||
use GuzzleHttp\Adapter\TransactionInterface;
|
|
||||||
use GuzzleHttp\Event\RequestEvents;
|
|
||||||
use GuzzleHttp\Exception\AdapterException;
|
|
||||||
use GuzzleHttp\Exception\RequestException;
|
|
||||||
use GuzzleHttp\Message\MessageFactoryInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTTP adapter that uses cURL multi as a transport layer
|
|
||||||
*
|
|
||||||
* When using the CurlAdapter, custom curl options can be specified as an
|
|
||||||
* associative array of curl option constants mapping to values in the
|
|
||||||
* **curl** key of a request's configuration options.
|
|
||||||
*
|
|
||||||
* In addition to being able to supply configuration options via the curl
|
|
||||||
* request config, you can also specify the select_timeout variable using the
|
|
||||||
* `GUZZLE_CURL_SELECT_TIMEOUT` environment variable.
|
|
||||||
*/
|
|
||||||
class MultiAdapter implements AdapterInterface, ParallelAdapterInterface
|
|
||||||
{
|
|
||||||
const ERROR_STR = 'See http://curl.haxx.se/libcurl/c/libcurl-errors.html for an explanation of cURL errors';
|
|
||||||
const ENV_SELECT_TIMEOUT = 'GUZZLE_CURL_SELECT_TIMEOUT';
|
|
||||||
|
|
||||||
/** @var CurlFactory */
|
|
||||||
private $curlFactory;
|
|
||||||
|
|
||||||
/** @var MessageFactoryInterface */
|
|
||||||
private $messageFactory;
|
|
||||||
|
|
||||||
/** @var array Array of curl multi handles */
|
|
||||||
private $multiHandles = [];
|
|
||||||
|
|
||||||
/** @var array Array of curl multi handles */
|
|
||||||
private $multiOwned = [];
|
|
||||||
|
|
||||||
/** @var double */
|
|
||||||
private $selectTimeout;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accepts an associative array of options:
|
|
||||||
*
|
|
||||||
* - handle_factory: Optional callable factory used to create cURL handles.
|
|
||||||
* The callable is invoked with the following arguments:
|
|
||||||
* TransactionInterface, MessageFactoryInterface, and an optional cURL
|
|
||||||
* handle to modify. The factory method must then return a cURL resource.
|
|
||||||
* - select_timeout: Specify a float in seconds to use for a
|
|
||||||
* curl_multi_select timeout.
|
|
||||||
*
|
|
||||||
* @param MessageFactoryInterface $messageFactory
|
|
||||||
* @param array $options Array of options to use with the adapter:
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
MessageFactoryInterface $messageFactory,
|
|
||||||
array $options = []
|
|
||||||
) {
|
|
||||||
$this->messageFactory = $messageFactory;
|
|
||||||
$this->curlFactory = isset($options['handle_factory'])
|
|
||||||
? $options['handle_factory']
|
|
||||||
: new CurlFactory();
|
|
||||||
|
|
||||||
if (isset($options['select_timeout'])) {
|
|
||||||
$this->selectTimeout = $options['select_timeout'];
|
|
||||||
} elseif (isset($_SERVER[self::ENV_SELECT_TIMEOUT])) {
|
|
||||||
$this->selectTimeout = $_SERVER[self::ENV_SELECT_TIMEOUT];
|
|
||||||
} else {
|
|
||||||
$this->selectTimeout = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __destruct()
|
|
||||||
{
|
|
||||||
foreach ($this->multiHandles as $handle) {
|
|
||||||
if (is_resource($handle)) {
|
|
||||||
curl_multi_close($handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Throw an exception for a cURL multi response
|
|
||||||
*
|
|
||||||
* @param int $code Curl response code
|
|
||||||
* @throws AdapterException
|
|
||||||
*/
|
|
||||||
public static function throwMultiError($code)
|
|
||||||
{
|
|
||||||
$buffer = function_exists('curl_multi_strerror')
|
|
||||||
? curl_multi_strerror($code)
|
|
||||||
: self::ERROR_STR;
|
|
||||||
|
|
||||||
throw new AdapterException(sprintf('cURL error %s: %s', $code, $buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function send(TransactionInterface $transaction)
|
|
||||||
{
|
|
||||||
$context = new BatchContext($this->checkoutMultiHandle(), true);
|
|
||||||
$this->addHandle($transaction, $context);
|
|
||||||
$this->perform($context);
|
|
||||||
|
|
||||||
return $transaction->getResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function sendAll(\Iterator $transactions, $parallel)
|
|
||||||
{
|
|
||||||
$context = new BatchContext(
|
|
||||||
$this->checkoutMultiHandle(),
|
|
||||||
false,
|
|
||||||
$transactions
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach (new \LimitIterator($transactions, 0, $parallel) as $trans) {
|
|
||||||
$this->addHandle($trans, $context);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->perform($context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function perform(BatchContext $context)
|
|
||||||
{
|
|
||||||
// The first curl_multi_select often times out no matter what, but is
|
|
||||||
// usually required for fast transfers.
|
|
||||||
$active = false;
|
|
||||||
$multi = $context->getMultiHandle();
|
|
||||||
|
|
||||||
do {
|
|
||||||
while (($mrc = curl_multi_exec($multi, $active)) == CURLM_CALL_MULTI_PERFORM);
|
|
||||||
if ($mrc != CURLM_OK && $mrc != CURLM_CALL_MULTI_PERFORM) {
|
|
||||||
self::throwMultiError($mrc);
|
|
||||||
}
|
|
||||||
// Need to check if there are pending transactions before processing
|
|
||||||
// them so that we don't bail from the loop too early.
|
|
||||||
$pending = $context->hasPending();
|
|
||||||
$this->processMessages($context);
|
|
||||||
if ($active && curl_multi_select($multi, $this->selectTimeout) === -1) {
|
|
||||||
// Perform a usleep if a select returns -1.
|
|
||||||
// See: https://bugs.php.net/bug.php?id=61141
|
|
||||||
usleep(250);
|
|
||||||
}
|
|
||||||
} while ($active || $pending);
|
|
||||||
|
|
||||||
$this->releaseMultiHandle($multi);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function processMessages(BatchContext $context)
|
|
||||||
{
|
|
||||||
$multi = $context->getMultiHandle();
|
|
||||||
|
|
||||||
while ($done = curl_multi_info_read($multi)) {
|
|
||||||
$transaction = $context->findTransaction($done['handle']);
|
|
||||||
$this->processResponse($transaction, $done, $context);
|
|
||||||
// Add the next transaction if there are more in the queue
|
|
||||||
if ($next = $context->nextPending()) {
|
|
||||||
$this->addHandle($next, $context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function processResponse(
|
|
||||||
TransactionInterface $transaction,
|
|
||||||
array $curl,
|
|
||||||
BatchContext $context
|
|
||||||
) {
|
|
||||||
$info = $context->removeTransaction($transaction);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!$this->isCurlException($transaction, $curl, $context, $info)) {
|
|
||||||
RequestEvents::emitComplete($transaction, $info);
|
|
||||||
}
|
|
||||||
} catch (RequestException $e) {
|
|
||||||
$this->throwException($e, $context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function addHandle(
|
|
||||||
TransactionInterface $transaction,
|
|
||||||
BatchContext $context
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
RequestEvents::emitBefore($transaction);
|
|
||||||
// Only transfer if the request was not intercepted
|
|
||||||
if (!$transaction->getResponse()) {
|
|
||||||
$factory = $this->curlFactory;
|
|
||||||
$context->addTransaction(
|
|
||||||
$transaction,
|
|
||||||
$factory($transaction, $this->messageFactory)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (RequestException $e) {
|
|
||||||
$this->throwException($e, $context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function isCurlException(
|
|
||||||
TransactionInterface $transaction,
|
|
||||||
array $curl,
|
|
||||||
BatchContext $context,
|
|
||||||
array $info
|
|
||||||
) {
|
|
||||||
if (CURLM_OK == $curl['result'] ||
|
|
||||||
CURLM_CALL_MULTI_PERFORM == $curl['result']
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$request = $transaction->getRequest();
|
|
||||||
try {
|
|
||||||
// Send curl stats along if they are available
|
|
||||||
$stats = ['curl_result' => $curl['result']] + $info;
|
|
||||||
RequestEvents::emitError(
|
|
||||||
$transaction,
|
|
||||||
new RequestException(
|
|
||||||
sprintf(
|
|
||||||
'[curl] (#%s) %s [url] %s',
|
|
||||||
$curl['result'],
|
|
||||||
function_exists('curl_strerror')
|
|
||||||
? curl_strerror($curl['result'])
|
|
||||||
: self::ERROR_STR,
|
|
||||||
$request->getUrl()
|
|
||||||
),
|
|
||||||
$request
|
|
||||||
),
|
|
||||||
$stats
|
|
||||||
);
|
|
||||||
} catch (RequestException $e) {
|
|
||||||
$this->throwException($e, $context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function throwException(RequestException $e, BatchContext $context)
|
|
||||||
{
|
|
||||||
if ($context->throwsExceptions()) {
|
|
||||||
$this->releaseMultiHandle($context->getMultiHandle());
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a curl_multi handle from the cache or creates a new one
|
|
||||||
*
|
|
||||||
* @return resource
|
|
||||||
*/
|
|
||||||
private function checkoutMultiHandle()
|
|
||||||
{
|
|
||||||
// Find an unused handle in the cache
|
|
||||||
$key = array_search(false, $this->multiOwned, true);
|
|
||||||
if (false !== $key) {
|
|
||||||
$this->multiOwned[$key] = true;
|
|
||||||
return $this->multiHandles[$key];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a new handle
|
|
||||||
$handle = curl_multi_init();
|
|
||||||
$id = (int) $handle;
|
|
||||||
$this->multiHandles[$id] = $handle;
|
|
||||||
$this->multiOwned[$id] = true;
|
|
||||||
|
|
||||||
return $handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Releases a curl_multi handle back into the cache and removes excess cache
|
|
||||||
*
|
|
||||||
* @param resource $handle Curl multi handle to remove
|
|
||||||
*/
|
|
||||||
private function releaseMultiHandle($handle)
|
|
||||||
{
|
|
||||||
$id = (int) $handle;
|
|
||||||
|
|
||||||
if (count($this->multiHandles) <= 3) {
|
|
||||||
$this->multiOwned[$id] = false;
|
|
||||||
} else {
|
|
||||||
// Prune excessive handles
|
|
||||||
curl_multi_close($this->multiHandles[$id]);
|
|
||||||
unset($this->multiHandles[$id], $this->multiOwned[$id]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,130 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Adapter\Curl;
|
|
||||||
|
|
||||||
use GuzzleHttp\Adapter\TransactionInterface;
|
|
||||||
use GuzzleHttp\Event\RequestEvents;
|
|
||||||
use GuzzleHttp\Message\MessageFactoryInterface;
|
|
||||||
use GuzzleHttp\Stream\Stream;
|
|
||||||
use GuzzleHttp\Stream\StreamInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mediator between curl handles and request objects
|
|
||||||
*/
|
|
||||||
class RequestMediator
|
|
||||||
{
|
|
||||||
/** @var TransactionInterface */
|
|
||||||
private $transaction;
|
|
||||||
/** @var MessageFactoryInterface */
|
|
||||||
private $messageFactory;
|
|
||||||
private $statusCode;
|
|
||||||
private $reasonPhrase;
|
|
||||||
private $body;
|
|
||||||
private $protocolVersion;
|
|
||||||
private $headers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param TransactionInterface $transaction Transaction to populate
|
|
||||||
* @param MessageFactoryInterface $messageFactory Creates responses
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
TransactionInterface $transaction,
|
|
||||||
MessageFactoryInterface $messageFactory
|
|
||||||
) {
|
|
||||||
$this->transaction = $transaction;
|
|
||||||
$this->messageFactory = $messageFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the body that will hold the response body
|
|
||||||
*
|
|
||||||
* @param StreamInterface $body Response body
|
|
||||||
*/
|
|
||||||
public function setResponseBody(StreamInterface $body = null)
|
|
||||||
{
|
|
||||||
$this->body = $body;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receive a response header from curl
|
|
||||||
*
|
|
||||||
* @param resource $curl Curl handle
|
|
||||||
* @param string $header Received header
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function receiveResponseHeader($curl, $header)
|
|
||||||
{
|
|
||||||
static $normalize = ["\r", "\n"];
|
|
||||||
$length = strlen($header);
|
|
||||||
$header = str_replace($normalize, '', $header);
|
|
||||||
|
|
||||||
if (strpos($header, 'HTTP/') === 0) {
|
|
||||||
$startLine = explode(' ', $header, 3);
|
|
||||||
// Only download the body to a target body when a successful
|
|
||||||
// response is received.
|
|
||||||
if ($startLine[1][0] != '2') {
|
|
||||||
$this->body = null;
|
|
||||||
}
|
|
||||||
$this->statusCode = $startLine[1];
|
|
||||||
$this->reasonPhrase = isset($startLine[2]) ? $startLine[2] : null;
|
|
||||||
$this->protocolVersion = substr($startLine[0], -3);
|
|
||||||
$this->headers = [];
|
|
||||||
} elseif ($pos = strpos($header, ':')) {
|
|
||||||
$this->headers[substr($header, 0, $pos)][] = substr($header, $pos + 1);
|
|
||||||
} elseif ($header == '' && $this->statusCode >= 200) {
|
|
||||||
$response = $this->messageFactory->createResponse(
|
|
||||||
$this->statusCode,
|
|
||||||
$this->headers,
|
|
||||||
$this->body,
|
|
||||||
[
|
|
||||||
'protocol_version' => $this->protocolVersion,
|
|
||||||
'reason_phrase' => $this->reasonPhrase
|
|
||||||
]
|
|
||||||
);
|
|
||||||
$this->headers = $this->body = null;
|
|
||||||
$this->transaction->setResponse($response);
|
|
||||||
// Allows events to react before downloading any of the body
|
|
||||||
RequestEvents::emitHeaders($this->transaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write data to the response body of a request
|
|
||||||
*
|
|
||||||
* @param resource $curl
|
|
||||||
* @param string $write
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function writeResponseBody($curl, $write)
|
|
||||||
{
|
|
||||||
if (!($response = $this->transaction->getResponse())) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a default body on the response if one was not found
|
|
||||||
if (!($body = $response->getBody())) {
|
|
||||||
$body = new Stream(fopen('php://temp', 'r+'));
|
|
||||||
$response->setBody($body);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $body->write($write);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read data from the request body and send it to curl
|
|
||||||
*
|
|
||||||
* @param resource $ch Curl handle
|
|
||||||
* @param resource $fd File descriptor
|
|
||||||
* @param int $length Amount of data to read
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function readRequestBody($ch, $fd, $length)
|
|
||||||
{
|
|
||||||
return (string) $this->transaction->getRequest()->getBody()->read($length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Adapter;
|
|
||||||
|
|
||||||
use GuzzleHttp\Exception\RequestException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorates a regular AdapterInterface object and creates a
|
|
||||||
* ParallelAdapterInterface object that sends multiple HTTP requests serially.
|
|
||||||
*/
|
|
||||||
class FakeParallelAdapter implements ParallelAdapterInterface
|
|
||||||
{
|
|
||||||
/** @var AdapterInterface */
|
|
||||||
private $adapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param AdapterInterface $adapter Adapter used to send requests
|
|
||||||
*/
|
|
||||||
public function __construct(AdapterInterface $adapter)
|
|
||||||
{
|
|
||||||
$this->adapter = $adapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function sendAll(\Iterator $transactions, $parallel)
|
|
||||||
{
|
|
||||||
foreach ($transactions as $transaction) {
|
|
||||||
try {
|
|
||||||
$this->adapter->send($transaction);
|
|
||||||
} catch (RequestException $e) {
|
|
||||||
// no op for batch transaction
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Adapter;
|
|
||||||
|
|
||||||
use GuzzleHttp\Event\RequestEvents;
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter that can be used to associate mock responses with a transaction
|
|
||||||
* while still emulating the event workflow of real adapters.
|
|
||||||
*/
|
|
||||||
class MockAdapter implements AdapterInterface
|
|
||||||
{
|
|
||||||
private $response;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param ResponseInterface|callable $response Response to serve or function
|
|
||||||
* to invoke that handles a transaction
|
|
||||||
*/
|
|
||||||
public function __construct($response = null)
|
|
||||||
{
|
|
||||||
$this->setResponse($response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the response that will be served by the adapter
|
|
||||||
*
|
|
||||||
* @param ResponseInterface|callable $response Response to serve or
|
|
||||||
* function to invoke that handles a transaction
|
|
||||||
*/
|
|
||||||
public function setResponse($response)
|
|
||||||
{
|
|
||||||
$this->response = $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function send(TransactionInterface $transaction)
|
|
||||||
{
|
|
||||||
RequestEvents::emitBefore($transaction);
|
|
||||||
if (!$transaction->getResponse()) {
|
|
||||||
|
|
||||||
// Read the request body if it is present
|
|
||||||
if ($transaction->getRequest()->getBody()) {
|
|
||||||
$transaction->getRequest()->getBody()->__toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = is_callable($this->response)
|
|
||||||
? call_user_func($this->response, $transaction)
|
|
||||||
: $this->response;
|
|
||||||
if (!$response instanceof ResponseInterface) {
|
|
||||||
throw new \RuntimeException('Invalid mocked response');
|
|
||||||
}
|
|
||||||
|
|
||||||
$transaction->setResponse($response);
|
|
||||||
RequestEvents::emitHeaders($transaction);
|
|
||||||
RequestEvents::emitComplete($transaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $transaction->getResponse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Adapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter interface used to transfer multiple HTTP requests in parallel.
|
|
||||||
*
|
|
||||||
* Parallel adapters follow the same rules as AdapterInterface except that
|
|
||||||
* RequestExceptions are never thrown in a parallel transfer and parallel
|
|
||||||
* adapters do not return responses.
|
|
||||||
*/
|
|
||||||
interface ParallelAdapterInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Transfers multiple HTTP requests in parallel.
|
|
||||||
*
|
|
||||||
* RequestExceptions MUST not be thrown from a parallel transfer.
|
|
||||||
*
|
|
||||||
* @param \Iterator $transactions Iterator that yields TransactionInterface
|
|
||||||
* @param int $parallel Max number of requests to send in parallel
|
|
||||||
*/
|
|
||||||
public function sendAll(\Iterator $transactions, $parallel);
|
|
||||||
}
|
|
||||||
|
|
@ -1,347 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Adapter;
|
|
||||||
|
|
||||||
use GuzzleHttp\Event\RequestEvents;
|
|
||||||
use GuzzleHttp\Exception\AdapterException;
|
|
||||||
use GuzzleHttp\Exception\RequestException;
|
|
||||||
use GuzzleHttp\Message\MessageFactoryInterface;
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
use GuzzleHttp\Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTTP adapter that uses PHP's HTTP stream wrapper.
|
|
||||||
*
|
|
||||||
* When using the StreamAdapter, custom stream context options can be specified
|
|
||||||
* using the **stream_context** option in a request's **config** option. The
|
|
||||||
* structure of the "stream_context" option is an associative array where each
|
|
||||||
* key is a transport name and each option is an associative array of options.
|
|
||||||
*/
|
|
||||||
class StreamAdapter implements AdapterInterface
|
|
||||||
{
|
|
||||||
/** @var MessageFactoryInterface */
|
|
||||||
private $messageFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param MessageFactoryInterface $messageFactory
|
|
||||||
*/
|
|
||||||
public function __construct(MessageFactoryInterface $messageFactory)
|
|
||||||
{
|
|
||||||
$this->messageFactory = $messageFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function send(TransactionInterface $transaction)
|
|
||||||
{
|
|
||||||
// HTTP/1.1 streams using the PHP stream wrapper require a
|
|
||||||
// Connection: close header. Setting here so that it is added before
|
|
||||||
// emitting the request.before_send event.
|
|
||||||
$request = $transaction->getRequest();
|
|
||||||
if ($request->getProtocolVersion() == '1.1' &&
|
|
||||||
!$request->hasHeader('Connection')
|
|
||||||
) {
|
|
||||||
$transaction->getRequest()->setHeader('Connection', 'close');
|
|
||||||
}
|
|
||||||
|
|
||||||
RequestEvents::emitBefore($transaction);
|
|
||||||
if (!$transaction->getResponse()) {
|
|
||||||
$this->createResponse($transaction);
|
|
||||||
RequestEvents::emitComplete($transaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $transaction->getResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function createResponse(TransactionInterface $transaction)
|
|
||||||
{
|
|
||||||
$request = $transaction->getRequest();
|
|
||||||
$stream = $this->createStream($request, $http_response_header);
|
|
||||||
|
|
||||||
if (!$request->getConfig()['stream']) {
|
|
||||||
$stream = $this->getSaveToBody($request, $stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Track the response headers of the request
|
|
||||||
$this->createResponseObject($http_response_header, $transaction, $stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Drain the steam into the destination stream
|
|
||||||
*/
|
|
||||||
private function getSaveToBody(RequestInterface $request, $stream)
|
|
||||||
{
|
|
||||||
if ($saveTo = $request->getConfig()['save_to']) {
|
|
||||||
// Stream the response into the destination stream
|
|
||||||
$saveTo = is_string($saveTo)
|
|
||||||
? Stream\create(fopen($saveTo, 'r+'))
|
|
||||||
: Stream\create($saveTo);
|
|
||||||
} else {
|
|
||||||
// Stream into the default temp stream
|
|
||||||
$saveTo = Stream\create();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!feof($stream)) {
|
|
||||||
$saveTo->write(fread($stream, 8096));
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose($stream);
|
|
||||||
$saveTo->seek(0);
|
|
||||||
|
|
||||||
return $saveTo;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function createResponseObject(
|
|
||||||
array $headers,
|
|
||||||
TransactionInterface $transaction,
|
|
||||||
$stream
|
|
||||||
) {
|
|
||||||
$parts = explode(' ', array_shift($headers), 3);
|
|
||||||
$options = ['protocol_version' => substr($parts[0], -3)];
|
|
||||||
if (isset($parts[2])) {
|
|
||||||
$options['reason_phrase'] = $parts[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the size on the stream if it was returned in the response
|
|
||||||
$responseHeaders = [];
|
|
||||||
foreach ($headers as $header) {
|
|
||||||
$headerParts = explode(':', $header, 2);
|
|
||||||
$responseHeaders[$headerParts[0]] = isset($headerParts[1])
|
|
||||||
? $headerParts[1]
|
|
||||||
: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = $this->messageFactory->createResponse(
|
|
||||||
$parts[1],
|
|
||||||
$responseHeaders,
|
|
||||||
$stream,
|
|
||||||
$options
|
|
||||||
);
|
|
||||||
|
|
||||||
$transaction->setResponse($response);
|
|
||||||
RequestEvents::emitHeaders($transaction);
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a resource and check to ensure it was created successfully
|
|
||||||
*
|
|
||||||
* @param callable $callback Callable that returns stream resource
|
|
||||||
* @param RequestInterface $request Request used when throwing exceptions
|
|
||||||
* @param array $options Options used when throwing exceptions
|
|
||||||
*
|
|
||||||
* @return resource
|
|
||||||
* @throws RequestException on error
|
|
||||||
*/
|
|
||||||
private function createResource(callable $callback, RequestInterface $request, $options)
|
|
||||||
{
|
|
||||||
// Turn off error reporting while we try to initiate the request
|
|
||||||
$level = error_reporting(0);
|
|
||||||
$resource = call_user_func($callback);
|
|
||||||
error_reporting($level);
|
|
||||||
|
|
||||||
// If the resource could not be created, then grab the last error and
|
|
||||||
// throw an exception.
|
|
||||||
if (!is_resource($resource)) {
|
|
||||||
$message = 'Error creating resource. [url] ' . $request->getUrl() . ' ';
|
|
||||||
if (isset($options['http']['proxy'])) {
|
|
||||||
$message .= "[proxy] {$options['http']['proxy']} ";
|
|
||||||
}
|
|
||||||
foreach (error_get_last() as $key => $value) {
|
|
||||||
$message .= "[{$key}] {$value} ";
|
|
||||||
}
|
|
||||||
throw new RequestException(trim($message), $request);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the stream for the request with the context options.
|
|
||||||
*
|
|
||||||
* @param RequestInterface $request Request being sent
|
|
||||||
* @param mixed $http_response_header Populated by stream wrapper
|
|
||||||
*
|
|
||||||
* @return resource
|
|
||||||
*/
|
|
||||||
private function createStream(
|
|
||||||
RequestInterface $request,
|
|
||||||
&$http_response_header
|
|
||||||
) {
|
|
||||||
static $methods;
|
|
||||||
if (!$methods) {
|
|
||||||
$methods = array_flip(get_class_methods(__CLASS__));
|
|
||||||
}
|
|
||||||
|
|
||||||
$params = [];
|
|
||||||
$options = $this->getDefaultOptions($request);
|
|
||||||
foreach ($request->getConfig()->toArray() as $key => $value) {
|
|
||||||
$method = "add_{$key}";
|
|
||||||
if (isset($methods[$method])) {
|
|
||||||
$this->{$method}($request, $options, $value, $params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->applyCustomOptions($request, $options);
|
|
||||||
$context = $this->createStreamContext($request, $options, $params);
|
|
||||||
|
|
||||||
return $this->createStreamResource(
|
|
||||||
$request,
|
|
||||||
$options,
|
|
||||||
$context,
|
|
||||||
$http_response_header
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getDefaultOptions(RequestInterface $request)
|
|
||||||
{
|
|
||||||
$headers = '';
|
|
||||||
foreach ($request->getHeaders() as $name => $values) {
|
|
||||||
$headers .= $name . ': ' . implode(', ', $values) . "\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'http' => [
|
|
||||||
'method' => $request->getMethod(),
|
|
||||||
'header' => trim($headers),
|
|
||||||
'protocol_version' => $request->getProtocolVersion(),
|
|
||||||
'ignore_errors' => true,
|
|
||||||
'follow_location' => 0,
|
|
||||||
'content' => (string) $request->getBody()
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_proxy(RequestInterface $request, &$options, $value, &$params)
|
|
||||||
{
|
|
||||||
if (!is_array($value)) {
|
|
||||||
$options['http']['proxy'] = $value;
|
|
||||||
$options['http']['request_fulluri'] = true;
|
|
||||||
} else {
|
|
||||||
$scheme = $request->getScheme();
|
|
||||||
if (isset($value[$scheme])) {
|
|
||||||
$options['http']['proxy'] = $value[$scheme];
|
|
||||||
$options['http']['request_fulluri'] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_timeout(RequestInterface $request, &$options, $value, &$params)
|
|
||||||
{
|
|
||||||
$options['http']['timeout'] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_verify(RequestInterface $request, &$options, $value, &$params)
|
|
||||||
{
|
|
||||||
if ($value === true || is_string($value)) {
|
|
||||||
$options['http']['verify_peer'] = true;
|
|
||||||
if ($value !== true) {
|
|
||||||
if (!file_exists($value)) {
|
|
||||||
throw new \RuntimeException("SSL certificate authority file not found: {$value}");
|
|
||||||
}
|
|
||||||
$options['http']['allow_self_signed'] = true;
|
|
||||||
$options['http']['cafile'] = $value;
|
|
||||||
}
|
|
||||||
} elseif ($value === false) {
|
|
||||||
$options['http']['verify_peer'] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_cert(RequestInterface $request, &$options, $value, &$params)
|
|
||||||
{
|
|
||||||
if (is_array($value)) {
|
|
||||||
$options['http']['passphrase'] = $value[1];
|
|
||||||
$value = $value[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!file_exists($value)) {
|
|
||||||
throw new \RuntimeException("SSL certificate not found: {$value}");
|
|
||||||
}
|
|
||||||
|
|
||||||
$options['http']['local_cert'] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_debug(RequestInterface $request, &$options, $value, &$params)
|
|
||||||
{
|
|
||||||
static $map = [
|
|
||||||
STREAM_NOTIFY_CONNECT => 'CONNECT',
|
|
||||||
STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
|
|
||||||
STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
|
|
||||||
STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
|
|
||||||
STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
|
|
||||||
STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
|
|
||||||
STREAM_NOTIFY_PROGRESS => 'PROGRESS',
|
|
||||||
STREAM_NOTIFY_FAILURE => 'FAILURE',
|
|
||||||
STREAM_NOTIFY_COMPLETED => 'COMPLETED',
|
|
||||||
STREAM_NOTIFY_RESOLVE => 'RESOLVE'
|
|
||||||
];
|
|
||||||
|
|
||||||
static $args = ['severity', 'message', 'message_code',
|
|
||||||
'bytes_transferred', 'bytes_max'];
|
|
||||||
|
|
||||||
if (!is_resource($value)) {
|
|
||||||
$value = fopen('php://output', 'w');
|
|
||||||
}
|
|
||||||
|
|
||||||
$params['notification'] = function () use ($request, $value, $map, $args) {
|
|
||||||
$passed = func_get_args();
|
|
||||||
$code = array_shift($passed);
|
|
||||||
fprintf($value, '<%s> [%s] ', $request->getUrl(), $map[$code]);
|
|
||||||
foreach (array_filter($passed) as $i => $v) {
|
|
||||||
fwrite($value, $args[$i] . ': "' . $v . '" ');
|
|
||||||
}
|
|
||||||
fwrite($value, "\n");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private function applyCustomOptions(
|
|
||||||
RequestInterface $request,
|
|
||||||
array &$options
|
|
||||||
) {
|
|
||||||
// Overwrite any generated options with custom options
|
|
||||||
if ($custom = $request->getConfig()['stream_context']) {
|
|
||||||
if (!is_array($custom)) {
|
|
||||||
throw new AdapterException('stream_context must be an array');
|
|
||||||
}
|
|
||||||
$options = array_replace_recursive($options, $custom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function createStreamContext(
|
|
||||||
RequestInterface $request,
|
|
||||||
array $options,
|
|
||||||
array $params
|
|
||||||
) {
|
|
||||||
return $this->createResource(function () use (
|
|
||||||
$request,
|
|
||||||
$options,
|
|
||||||
$params
|
|
||||||
) {
|
|
||||||
return stream_context_create($options, $params);
|
|
||||||
}, $request, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function createStreamResource(
|
|
||||||
RequestInterface $request,
|
|
||||||
array $options,
|
|
||||||
$context,
|
|
||||||
&$http_response_header
|
|
||||||
) {
|
|
||||||
$url = $request->getUrl();
|
|
||||||
// Add automatic gzip decompression
|
|
||||||
if (strpos($request->getHeader('Accept-Encoding'), 'gzip') !== false) {
|
|
||||||
$url = 'compress.zlib://' . $url;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->createResource(function () use (
|
|
||||||
$url,
|
|
||||||
&$http_response_header,
|
|
||||||
$context
|
|
||||||
) {
|
|
||||||
if (false === strpos($url, 'http')) {
|
|
||||||
trigger_error("URL is invalid: {$url}", E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return fopen($url, 'r', null, $context);
|
|
||||||
}, $request, $options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Adapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends streaming requests to a streaming compatible adapter while sending all
|
|
||||||
* other requests to a default adapter.
|
|
||||||
*
|
|
||||||
* This, for example, could be useful for taking advantage of the performance
|
|
||||||
* benefits of the CurlAdapter while still supporting true streaming through
|
|
||||||
* the StreamAdapter.
|
|
||||||
*/
|
|
||||||
class StreamingProxyAdapter implements AdapterInterface
|
|
||||||
{
|
|
||||||
private $defaultAdapter;
|
|
||||||
private $streamingAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param AdapterInterface $defaultAdapter Adapter used for non-streaming responses
|
|
||||||
* @param AdapterInterface $streamingAdapter Adapter used for streaming responses
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
AdapterInterface $defaultAdapter,
|
|
||||||
AdapterInterface $streamingAdapter
|
|
||||||
) {
|
|
||||||
$this->defaultAdapter = $defaultAdapter;
|
|
||||||
$this->streamingAdapter = $streamingAdapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function send(TransactionInterface $transaction)
|
|
||||||
{
|
|
||||||
return $transaction->getRequest()->getConfig()['stream']
|
|
||||||
? $this->streamingAdapter->send($transaction)
|
|
||||||
: $this->defaultAdapter->send($transaction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Adapter;
|
|
||||||
|
|
||||||
use GuzzleHttp\ClientInterface;
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
|
|
||||||
class Transaction implements TransactionInterface
|
|
||||||
{
|
|
||||||
/** @var ClientInterface */
|
|
||||||
private $client;
|
|
||||||
/** @var RequestInterface */
|
|
||||||
private $request;
|
|
||||||
/** @var ResponseInterface */
|
|
||||||
private $response;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param ClientInterface $client Client that is used to send the requests
|
|
||||||
* @param RequestInterface $request
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
ClientInterface $client,
|
|
||||||
RequestInterface $request
|
|
||||||
) {
|
|
||||||
$this->client = $client;
|
|
||||||
$this->request = $request;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRequest()
|
|
||||||
{
|
|
||||||
return $this->request;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getResponse()
|
|
||||||
{
|
|
||||||
return $this->response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setResponse(ResponseInterface $response)
|
|
||||||
{
|
|
||||||
$this->response = $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getClient()
|
|
||||||
{
|
|
||||||
return $this->client;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Adapter;
|
|
||||||
|
|
||||||
use GuzzleHttp\ClientInterface;
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a transactions that consists of a request, response, and client
|
|
||||||
*/
|
|
||||||
interface TransactionInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @return RequestInterface
|
|
||||||
*/
|
|
||||||
public function getRequest();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return ResponseInterface|null
|
|
||||||
*/
|
|
||||||
public function getResponse();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a response on the transaction
|
|
||||||
*
|
|
||||||
* @param ResponseInterface $response Response to set
|
|
||||||
*/
|
|
||||||
public function setResponse(ResponseInterface $response);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return ClientInterface
|
|
||||||
*/
|
|
||||||
public function getClient();
|
|
||||||
}
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Adapter;
|
|
||||||
|
|
||||||
use GuzzleHttp\ClientInterface;
|
|
||||||
use GuzzleHttp\Event\ListenerAttacherTrait;
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a sequence of request objects into a transaction.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
class TransactionIterator implements \Iterator
|
|
||||||
{
|
|
||||||
use ListenerAttacherTrait;
|
|
||||||
|
|
||||||
/** @var \Iterator */
|
|
||||||
private $source;
|
|
||||||
|
|
||||||
/** @var ClientInterface */
|
|
||||||
private $client;
|
|
||||||
|
|
||||||
/** @var array Listeners to attach to each request */
|
|
||||||
private $eventListeners = [];
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
$source,
|
|
||||||
ClientInterface $client,
|
|
||||||
array $options
|
|
||||||
) {
|
|
||||||
$this->client = $client;
|
|
||||||
$this->eventListeners = $this->prepareListeners(
|
|
||||||
$options,
|
|
||||||
['before', 'complete', 'error']
|
|
||||||
);
|
|
||||||
if ($source instanceof \Iterator) {
|
|
||||||
$this->source = $source;
|
|
||||||
} elseif (is_array($source)) {
|
|
||||||
$this->source = new \ArrayIterator($source);
|
|
||||||
} else {
|
|
||||||
throw new \InvalidArgumentException('Expected an Iterator or array');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function current()
|
|
||||||
{
|
|
||||||
$request = $this->source->current();
|
|
||||||
if (!$request instanceof RequestInterface) {
|
|
||||||
throw new \RuntimeException('All must implement RequestInterface');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->attachListeners($request, $this->eventListeners);
|
|
||||||
|
|
||||||
return new Transaction($this->client, $request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function next()
|
|
||||||
{
|
|
||||||
$this->source->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function key()
|
|
||||||
{
|
|
||||||
return $this->source->key();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function valid()
|
|
||||||
{
|
|
||||||
return $this->source->valid();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function rewind() {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,364 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp;
|
|
||||||
|
|
||||||
use GuzzleHttp\Adapter\Curl\MultiAdapter;
|
|
||||||
use GuzzleHttp\Event\HasEmitterTrait;
|
|
||||||
use GuzzleHttp\Adapter\FakeParallelAdapter;
|
|
||||||
use GuzzleHttp\Adapter\ParallelAdapterInterface;
|
|
||||||
use GuzzleHttp\Adapter\AdapterInterface;
|
|
||||||
use GuzzleHttp\Adapter\StreamAdapter;
|
|
||||||
use GuzzleHttp\Adapter\StreamingProxyAdapter;
|
|
||||||
use GuzzleHttp\Adapter\Curl\CurlAdapter;
|
|
||||||
use GuzzleHttp\Adapter\Transaction;
|
|
||||||
use GuzzleHttp\Adapter\TransactionIterator;
|
|
||||||
use GuzzleHttp\Exception\RequestException;
|
|
||||||
use GuzzleHttp\Message\MessageFactory;
|
|
||||||
use GuzzleHttp\Message\MessageFactoryInterface;
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTTP client
|
|
||||||
*/
|
|
||||||
class Client implements ClientInterface
|
|
||||||
{
|
|
||||||
use HasEmitterTrait;
|
|
||||||
|
|
||||||
const DEFAULT_CONCURRENCY = 25;
|
|
||||||
|
|
||||||
/** @var MessageFactoryInterface Request factory used by the client */
|
|
||||||
private $messageFactory;
|
|
||||||
|
|
||||||
/** @var AdapterInterface */
|
|
||||||
private $adapter;
|
|
||||||
|
|
||||||
/** @var ParallelAdapterInterface */
|
|
||||||
private $parallelAdapter;
|
|
||||||
|
|
||||||
/** @var Url Base URL of the client */
|
|
||||||
private $baseUrl;
|
|
||||||
|
|
||||||
/** @var array Default request options */
|
|
||||||
private $defaults;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clients accept an array of constructor parameters.
|
|
||||||
*
|
|
||||||
* Here's an example of creating a client using an URI template for the
|
|
||||||
* client's base_url and an array of default request options to apply
|
|
||||||
* to each request:
|
|
||||||
*
|
|
||||||
* $client = new Client([
|
|
||||||
* 'base_url' => [
|
|
||||||
* 'http://www.foo.com/{version}/',
|
|
||||||
* ['version' => '123']
|
|
||||||
* ],
|
|
||||||
* 'defaults' => [
|
|
||||||
* 'timeout' => 10,
|
|
||||||
* 'allow_redirects' => false,
|
|
||||||
* 'proxy' => '192.168.16.1:10'
|
|
||||||
* ]
|
|
||||||
* ]);
|
|
||||||
*
|
|
||||||
* @param array $config Client configuration settings
|
|
||||||
* - base_url: Base URL of the client that is merged into relative URLs.
|
|
||||||
* Can be a string or an array that contains a URI template followed
|
|
||||||
* by an associative array of expansion variables to inject into the
|
|
||||||
* URI template.
|
|
||||||
* - adapter: Adapter used to transfer requests
|
|
||||||
* - parallel_adapter: Adapter used to transfer requests in parallel
|
|
||||||
* - message_factory: Factory used to create request and response object
|
|
||||||
* - defaults: Default request options to apply to each request
|
|
||||||
* - emitter: Event emitter used for request events
|
|
||||||
*/
|
|
||||||
public function __construct(array $config = [])
|
|
||||||
{
|
|
||||||
$this->configureBaseUrl($config);
|
|
||||||
$this->configureDefaults($config);
|
|
||||||
$this->configureAdapter($config);
|
|
||||||
if (isset($config['emitter'])) {
|
|
||||||
$this->emitter = $config['emitter'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the default User-Agent string to use with Guzzle
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function getDefaultUserAgent()
|
|
||||||
{
|
|
||||||
static $defaultAgent = '';
|
|
||||||
if (!$defaultAgent) {
|
|
||||||
$defaultAgent = 'Guzzle/' . self::VERSION;
|
|
||||||
if (extension_loaded('curl')) {
|
|
||||||
$defaultAgent .= ' curl/' . curl_version()['version'];
|
|
||||||
}
|
|
||||||
$defaultAgent .= ' PHP/' . PHP_VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $defaultAgent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __call($name, $arguments)
|
|
||||||
{
|
|
||||||
return \GuzzleHttp\deprecation_proxy(
|
|
||||||
$this,
|
|
||||||
$name,
|
|
||||||
$arguments,
|
|
||||||
['getEventDispatcher' => 'getEmitter']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDefaultOption($keyOrPath = null)
|
|
||||||
{
|
|
||||||
return $keyOrPath === null
|
|
||||||
? $this->defaults
|
|
||||||
: \GuzzleHttp\get_path($this->defaults, $keyOrPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setDefaultOption($keyOrPath, $value)
|
|
||||||
{
|
|
||||||
\GuzzleHttp\set_path($this->defaults, $keyOrPath, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBaseUrl()
|
|
||||||
{
|
|
||||||
return (string) $this->baseUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createRequest($method, $url = null, array $options = [])
|
|
||||||
{
|
|
||||||
// Merge in default options
|
|
||||||
$options = array_replace_recursive($this->defaults, $options);
|
|
||||||
|
|
||||||
// Use a clone of the client's emitter
|
|
||||||
$options['config']['emitter'] = clone $this->getEmitter();
|
|
||||||
|
|
||||||
$request = $this->messageFactory->createRequest(
|
|
||||||
$method,
|
|
||||||
$url ? (string) $this->buildUrl($url) : (string) $this->baseUrl,
|
|
||||||
$options
|
|
||||||
);
|
|
||||||
|
|
||||||
return $request;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function get($url = null, $options = [])
|
|
||||||
{
|
|
||||||
return $this->send($this->createRequest('GET', $url, $options));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function head($url = null, array $options = [])
|
|
||||||
{
|
|
||||||
return $this->send($this->createRequest('HEAD', $url, $options));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function delete($url = null, array $options = [])
|
|
||||||
{
|
|
||||||
return $this->send($this->createRequest('DELETE', $url, $options));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function put($url = null, array $options = [])
|
|
||||||
{
|
|
||||||
return $this->send($this->createRequest('PUT', $url, $options));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function patch($url = null, array $options = [])
|
|
||||||
{
|
|
||||||
return $this->send($this->createRequest('PATCH', $url, $options));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function post($url = null, array $options = [])
|
|
||||||
{
|
|
||||||
return $this->send($this->createRequest('POST', $url, $options));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function options($url = null, array $options = [])
|
|
||||||
{
|
|
||||||
return $this->send($this->createRequest('OPTIONS', $url, $options));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function send(RequestInterface $request)
|
|
||||||
{
|
|
||||||
$transaction = new Transaction($this, $request);
|
|
||||||
try {
|
|
||||||
if ($response = $this->adapter->send($transaction)) {
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
throw new \LogicException('No response was associated with the transaction');
|
|
||||||
} catch (RequestException $e) {
|
|
||||||
throw $e;
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
// Wrap exceptions in a RequestException to adhere to the interface
|
|
||||||
throw new RequestException($e->getMessage(), $request, null, $e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function sendAll($requests, array $options = [])
|
|
||||||
{
|
|
||||||
if (!($requests instanceof TransactionIterator)) {
|
|
||||||
$requests = new TransactionIterator($requests, $this, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->parallelAdapter->sendAll(
|
|
||||||
$requests,
|
|
||||||
isset($options['parallel'])
|
|
||||||
? $options['parallel']
|
|
||||||
: self::DEFAULT_CONCURRENCY
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an array of default options to apply to the client
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function getDefaultOptions()
|
|
||||||
{
|
|
||||||
$settings = [
|
|
||||||
'allow_redirects' => true,
|
|
||||||
'exceptions' => true,
|
|
||||||
'verify' => __DIR__ . '/cacert.pem'
|
|
||||||
];
|
|
||||||
|
|
||||||
// Use the bundled cacert if it is a regular file, or set to true if
|
|
||||||
// using a phar file (because curL and the stream wrapper can't read
|
|
||||||
// cacerts from the phar stream wrapper). Favor the ini setting over
|
|
||||||
// the system's cacert.
|
|
||||||
if (substr(__FILE__, 0, 7) == 'phar://') {
|
|
||||||
$settings['verify'] = ini_get('openssl.cafile') ?: true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set
|
|
||||||
if (isset($_SERVER['HTTP_PROXY'])) {
|
|
||||||
$settings['proxy']['http'] = $_SERVER['HTTP_PROXY'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_SERVER['HTTPS_PROXY'])) {
|
|
||||||
$settings['proxy']['https'] = $_SERVER['HTTPS_PROXY'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expand a URI template and inherit from the base URL if it's relative
|
|
||||||
*
|
|
||||||
* @param string|array $url URL or URI template to expand
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function buildUrl($url)
|
|
||||||
{
|
|
||||||
if (!is_array($url)) {
|
|
||||||
if (strpos($url, '://')) {
|
|
||||||
return (string) $url;
|
|
||||||
}
|
|
||||||
return (string) $this->baseUrl->combine($url);
|
|
||||||
} elseif (strpos($url[0], '://')) {
|
|
||||||
return \GuzzleHttp\uri_template($url[0], $url[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (string) $this->baseUrl->combine(
|
|
||||||
\GuzzleHttp\uri_template($url[0], $url[1])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a default parallel adapter to use based on the environment
|
|
||||||
*
|
|
||||||
* @return ParallelAdapterInterface
|
|
||||||
*/
|
|
||||||
private function getDefaultParallelAdapter()
|
|
||||||
{
|
|
||||||
return extension_loaded('curl')
|
|
||||||
? new MultiAdapter($this->messageFactory)
|
|
||||||
: new FakeParallelAdapter($this->adapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a default adapter to use based on the environment
|
|
||||||
* @throws \RuntimeException
|
|
||||||
*/
|
|
||||||
private function getDefaultAdapter()
|
|
||||||
{
|
|
||||||
if (extension_loaded('curl')) {
|
|
||||||
$this->parallelAdapter = new MultiAdapter($this->messageFactory);
|
|
||||||
$this->adapter = function_exists('curl_reset')
|
|
||||||
? new CurlAdapter($this->messageFactory)
|
|
||||||
: $this->parallelAdapter;
|
|
||||||
if (ini_get('allow_url_fopen')) {
|
|
||||||
$this->adapter = new StreamingProxyAdapter(
|
|
||||||
$this->adapter,
|
|
||||||
new StreamAdapter($this->messageFactory)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} elseif (ini_get('allow_url_fopen')) {
|
|
||||||
$this->adapter = new StreamAdapter($this->messageFactory);
|
|
||||||
} else {
|
|
||||||
throw new \RuntimeException('Guzzle requires cURL, the '
|
|
||||||
. 'allow_url_fopen ini setting, or a custom HTTP adapter.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function configureBaseUrl(&$config)
|
|
||||||
{
|
|
||||||
if (!isset($config['base_url'])) {
|
|
||||||
$this->baseUrl = new Url('', '');
|
|
||||||
} elseif (is_array($config['base_url'])) {
|
|
||||||
$this->baseUrl = Url::fromString(
|
|
||||||
\GuzzleHttp\uri_template(
|
|
||||||
$config['base_url'][0],
|
|
||||||
$config['base_url'][1]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$config['base_url'] = (string) $this->baseUrl;
|
|
||||||
} else {
|
|
||||||
$this->baseUrl = Url::fromString($config['base_url']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function configureDefaults($config)
|
|
||||||
{
|
|
||||||
if (!isset($config['defaults'])) {
|
|
||||||
$this->defaults = $this->getDefaultOptions();
|
|
||||||
} else {
|
|
||||||
$this->defaults = array_replace(
|
|
||||||
$this->getDefaultOptions(),
|
|
||||||
$config['defaults']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the default user-agent header
|
|
||||||
if (!isset($this->defaults['headers'])) {
|
|
||||||
$this->defaults['headers'] = [
|
|
||||||
'User-Agent' => static::getDefaultUserAgent()
|
|
||||||
];
|
|
||||||
} elseif (!isset(array_change_key_case($this->defaults['headers'])['user-agent'])) {
|
|
||||||
// Add the User-Agent header if one was not already set
|
|
||||||
$this->defaults['headers']['User-Agent'] = static::getDefaultUserAgent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function configureAdapter(&$config)
|
|
||||||
{
|
|
||||||
if (isset($config['message_factory'])) {
|
|
||||||
$this->messageFactory = $config['message_factory'];
|
|
||||||
} else {
|
|
||||||
$this->messageFactory = new MessageFactory();
|
|
||||||
}
|
|
||||||
if (isset($config['adapter'])) {
|
|
||||||
$this->adapter = $config['adapter'];
|
|
||||||
} else {
|
|
||||||
$this->getDefaultAdapter();
|
|
||||||
}
|
|
||||||
// If no parallel adapter was explicitly provided and one was not
|
|
||||||
// defaulted when creating the default adapter, then create one now.
|
|
||||||
if (isset($config['parallel_adapter'])) {
|
|
||||||
$this->parallelAdapter = $config['parallel_adapter'];
|
|
||||||
} elseif (!$this->parallelAdapter) {
|
|
||||||
$this->parallelAdapter = $this->getDefaultParallelAdapter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,179 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp;
|
|
||||||
|
|
||||||
use GuzzleHttp\Event\HasEmitterInterface;
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
use GuzzleHttp\Exception\RequestException;
|
|
||||||
use GuzzleHttp\Exception\AdapterException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Client interface for sending HTTP requests
|
|
||||||
*/
|
|
||||||
interface ClientInterface extends HasEmitterInterface
|
|
||||||
{
|
|
||||||
const VERSION = '4.1.2';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create and return a new {@see RequestInterface} object.
|
|
||||||
*
|
|
||||||
* Use an absolute path to override the base path of the client, or a
|
|
||||||
* relative path to append to the base path of the client. The URL can
|
|
||||||
* contain the query string as well. Use an array to provide a URL
|
|
||||||
* template and additional variables to use in the URL template expansion.
|
|
||||||
*
|
|
||||||
* @param string $method HTTP method
|
|
||||||
* @param string|array|Url $url URL or URI template
|
|
||||||
* @param array $options Array of request options to apply.
|
|
||||||
*
|
|
||||||
* @return RequestInterface
|
|
||||||
*/
|
|
||||||
public function createRequest($method, $url = null, array $options = []);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a GET request
|
|
||||||
*
|
|
||||||
* @param string|array|Url $url URL or URI template
|
|
||||||
* @param array $options Array of request options to apply.
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
* @throws RequestException When an error is encountered
|
|
||||||
*/
|
|
||||||
public function get($url = null, $options = []);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a HEAD request
|
|
||||||
*
|
|
||||||
* @param string|array|Url $url URL or URI template
|
|
||||||
* @param array $options Array of request options to apply.
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
* @throws RequestException When an error is encountered
|
|
||||||
*/
|
|
||||||
public function head($url = null, array $options = []);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a DELETE request
|
|
||||||
*
|
|
||||||
* @param string|array|Url $url URL or URI template
|
|
||||||
* @param array $options Array of request options to apply.
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
* @throws RequestException When an error is encountered
|
|
||||||
*/
|
|
||||||
public function delete($url = null, array $options = []);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a PUT request
|
|
||||||
*
|
|
||||||
* @param string|array|Url $url URL or URI template
|
|
||||||
* @param array $options Array of request options to apply.
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
* @throws RequestException When an error is encountered
|
|
||||||
*/
|
|
||||||
public function put($url = null, array $options = []);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a PATCH request
|
|
||||||
*
|
|
||||||
* @param string|array|Url $url URL or URI template
|
|
||||||
* @param array $options Array of request options to apply.
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
* @throws RequestException When an error is encountered
|
|
||||||
*/
|
|
||||||
public function patch($url = null, array $options = []);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a POST request
|
|
||||||
*
|
|
||||||
* @param string|array|Url $url URL or URI template
|
|
||||||
* @param array $options Array of request options to apply.
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
* @throws RequestException When an error is encountered
|
|
||||||
*/
|
|
||||||
public function post($url = null, array $options = []);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send an OPTIONS request
|
|
||||||
*
|
|
||||||
* @param string|array|Url $url URL or URI template
|
|
||||||
* @param array $options Array of request options to apply.
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
* @throws RequestException When an error is encountered
|
|
||||||
*/
|
|
||||||
public function options($url = null, array $options = []);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a single request
|
|
||||||
*
|
|
||||||
* @param RequestInterface $request Request to send
|
|
||||||
*
|
|
||||||
* @return \GuzzleHttp\Message\ResponseInterface
|
|
||||||
* @throws \LogicException When the adapter does not populate a response
|
|
||||||
* @throws RequestException When an error is encountered
|
|
||||||
*/
|
|
||||||
public function send(RequestInterface $request);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends multiple requests in parallel.
|
|
||||||
*
|
|
||||||
* Exceptions are not thrown for failed requests. Callers are expected to
|
|
||||||
* register an "error" option to handle request errors OR directly register
|
|
||||||
* an event handler for the "error" event of a request's
|
|
||||||
* event emitter.
|
|
||||||
*
|
|
||||||
* The option values for 'before', 'after', and 'error' can be a callable,
|
|
||||||
* an associative array containing event data, or an array of event data
|
|
||||||
* arrays. Event data arrays contain the following keys:
|
|
||||||
*
|
|
||||||
* - fn: callable to invoke that receives the event
|
|
||||||
* - priority: Optional event priority (defaults to 0)
|
|
||||||
* - once: Set to true so that the event is removed after it is triggered
|
|
||||||
*
|
|
||||||
* @param array|\Iterator $requests Requests to send in parallel
|
|
||||||
* @param array $options Associative array of options
|
|
||||||
* - parallel: (int) Maximum number of requests to send in parallel
|
|
||||||
* - before: (callable|array) Receives a BeforeEvent
|
|
||||||
* - after: (callable|array) Receives a CompleteEvent
|
|
||||||
* - error: (callable|array) Receives a ErrorEvent
|
|
||||||
*
|
|
||||||
* @throws AdapterException When an error occurs in the HTTP adapter.
|
|
||||||
*/
|
|
||||||
public function sendAll($requests, array $options = []);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get default request options of the client.
|
|
||||||
*
|
|
||||||
* @param string|null $keyOrPath The Path to a particular default request
|
|
||||||
* option to retrieve or pass null to retrieve all default request
|
|
||||||
* options. The syntax uses "/" to denote a path through nested PHP
|
|
||||||
* arrays. For example, "headers/content-type".
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getDefaultOption($keyOrPath = null);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a default request option on the client so that any request created
|
|
||||||
* by the client will use the provided default value unless overridden
|
|
||||||
* explicitly when creating a request.
|
|
||||||
*
|
|
||||||
* @param string|null $keyOrPath The Path to a particular configuration
|
|
||||||
* value to set. The syntax uses a path notation that allows you to
|
|
||||||
* specify nested configuration values (e.g., 'headers/content-type').
|
|
||||||
* @param mixed $value Default request option value to set
|
|
||||||
*/
|
|
||||||
public function setDefaultOption($keyOrPath, $value);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the base URL of the client.
|
|
||||||
*
|
|
||||||
* @return string Returns the base URL if present
|
|
||||||
*/
|
|
||||||
public function getBaseUrl();
|
|
||||||
}
|
|
||||||
|
|
@ -1,265 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Key value pair collection object
|
|
||||||
*/
|
|
||||||
class Collection implements
|
|
||||||
\ArrayAccess,
|
|
||||||
\IteratorAggregate,
|
|
||||||
\Countable,
|
|
||||||
ToArrayInterface
|
|
||||||
{
|
|
||||||
use HasDataTrait;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $data Associative array of data to set
|
|
||||||
*/
|
|
||||||
public function __construct(array $data = [])
|
|
||||||
{
|
|
||||||
$this->data = $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new collection from an array, validate the keys, and add default
|
|
||||||
* values where missing
|
|
||||||
*
|
|
||||||
* @param array $config Configuration values to apply.
|
|
||||||
* @param array $defaults Default parameters
|
|
||||||
* @param array $required Required parameter names
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
* @throws \InvalidArgumentException if a parameter is missing
|
|
||||||
*/
|
|
||||||
public static function fromConfig(
|
|
||||||
array $config = [],
|
|
||||||
array $defaults = [],
|
|
||||||
array $required = []
|
|
||||||
) {
|
|
||||||
$data = $config + $defaults;
|
|
||||||
|
|
||||||
if ($missing = array_diff($required, array_keys($data))) {
|
|
||||||
throw new \InvalidArgumentException(
|
|
||||||
'Config is missing the following keys: ' .
|
|
||||||
implode(', ', $missing));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new self($data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes all key value pairs
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function clear()
|
|
||||||
{
|
|
||||||
$this->data = [];
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a specific key value.
|
|
||||||
*
|
|
||||||
* @param string $key Key to retrieve.
|
|
||||||
*
|
|
||||||
* @return mixed|null Value of the key or NULL
|
|
||||||
*/
|
|
||||||
public function get($key)
|
|
||||||
{
|
|
||||||
return isset($this->data[$key]) ? $this->data[$key] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a key value pair
|
|
||||||
*
|
|
||||||
* @param string $key Key to set
|
|
||||||
* @param mixed $value Value to set
|
|
||||||
*
|
|
||||||
* @return Collection Returns a reference to the object
|
|
||||||
*/
|
|
||||||
public function set($key, $value)
|
|
||||||
{
|
|
||||||
$this->data[$key] = $value;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a value to a key. If a key of the same name has already been added,
|
|
||||||
* the key value will be converted into an array and the new value will be
|
|
||||||
* pushed to the end of the array.
|
|
||||||
*
|
|
||||||
* @param string $key Key to add
|
|
||||||
* @param mixed $value Value to add to the key
|
|
||||||
*
|
|
||||||
* @return Collection Returns a reference to the object.
|
|
||||||
*/
|
|
||||||
public function add($key, $value)
|
|
||||||
{
|
|
||||||
if (!array_key_exists($key, $this->data)) {
|
|
||||||
$this->data[$key] = $value;
|
|
||||||
} elseif (is_array($this->data[$key])) {
|
|
||||||
$this->data[$key][] = $value;
|
|
||||||
} else {
|
|
||||||
$this->data[$key] = array($this->data[$key], $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a specific key value pair
|
|
||||||
*
|
|
||||||
* @param string $key A key to remove
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function remove($key)
|
|
||||||
{
|
|
||||||
unset($this->data[$key]);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all keys in the collection
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getKeys()
|
|
||||||
{
|
|
||||||
return array_keys($this->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether or not the specified key is present.
|
|
||||||
*
|
|
||||||
* @param string $key The key for which to check the existence.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function hasKey($key)
|
|
||||||
{
|
|
||||||
return array_key_exists($key, $this->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if any keys contains a certain value
|
|
||||||
*
|
|
||||||
* @param string $value Value to search for
|
|
||||||
*
|
|
||||||
* @return mixed Returns the key if the value was found FALSE if the value
|
|
||||||
* was not found.
|
|
||||||
*/
|
|
||||||
public function hasValue($value)
|
|
||||||
{
|
|
||||||
return array_search($value, $this->data, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace the data of the object with the value of an array
|
|
||||||
*
|
|
||||||
* @param array $data Associative array of data
|
|
||||||
*
|
|
||||||
* @return Collection Returns a reference to the object
|
|
||||||
*/
|
|
||||||
public function replace(array $data)
|
|
||||||
{
|
|
||||||
$this->data = $data;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add and merge in a Collection or array of key value pair data.
|
|
||||||
*
|
|
||||||
* @param Collection|array $data Associative array of key value pair data
|
|
||||||
*
|
|
||||||
* @return Collection Returns a reference to the object.
|
|
||||||
*/
|
|
||||||
public function merge($data)
|
|
||||||
{
|
|
||||||
foreach ($data as $key => $value) {
|
|
||||||
$this->add($key, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Over write key value pairs in this collection with all of the data from
|
|
||||||
* an array or collection.
|
|
||||||
*
|
|
||||||
* @param array|\Traversable $data Values to override over this config
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function overwriteWith($data)
|
|
||||||
{
|
|
||||||
if (is_array($data)) {
|
|
||||||
$this->data = $data + $this->data;
|
|
||||||
} elseif ($data instanceof Collection) {
|
|
||||||
$this->data = $data->toArray() + $this->data;
|
|
||||||
} else {
|
|
||||||
foreach ($data as $key => $value) {
|
|
||||||
$this->data[$key] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a Collection containing all the elements of the collection after
|
|
||||||
* applying the callback function to each one.
|
|
||||||
*
|
|
||||||
* The callable should accept three arguments:
|
|
||||||
* - (string) $key
|
|
||||||
* - (string) $value
|
|
||||||
* - (array) $context
|
|
||||||
*
|
|
||||||
* The callable must return a the altered or unaltered value.
|
|
||||||
*
|
|
||||||
* @param callable $closure Map function to apply
|
|
||||||
* @param array $context Context to pass to the callable
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function map(callable $closure, array $context = [])
|
|
||||||
{
|
|
||||||
$collection = new static();
|
|
||||||
foreach ($this as $key => $value) {
|
|
||||||
$collection[$key] = $closure($key, $value, $context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $collection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates over each key value pair in the collection passing them to the
|
|
||||||
* callable. If the callable returns true, the current value from input is
|
|
||||||
* returned into the result Collection.
|
|
||||||
*
|
|
||||||
* The callable must accept two arguments:
|
|
||||||
* - (string) $key
|
|
||||||
* - (string) $value
|
|
||||||
*
|
|
||||||
* @param callable $closure Evaluation function
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function filter(callable $closure)
|
|
||||||
{
|
|
||||||
$collection = new static();
|
|
||||||
foreach ($this->data as $key => $value) {
|
|
||||||
if ($closure($key, $value)) {
|
|
||||||
$collection[$key] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $collection;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,249 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Cookie;
|
|
||||||
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
use GuzzleHttp\ToArrayInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cookie jar that stores cookies an an array
|
|
||||||
*/
|
|
||||||
class CookieJar implements CookieJarInterface, ToArrayInterface
|
|
||||||
{
|
|
||||||
/** @var SetCookie[] Loaded cookie data */
|
|
||||||
private $cookies = [];
|
|
||||||
|
|
||||||
/** @var bool */
|
|
||||||
private $strictMode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param bool $strictMode Set to true to throw exceptions when invalid
|
|
||||||
* cookies are added to the cookie jar.
|
|
||||||
* @param array $cookieArray Array of SetCookie objects or a hash of arrays
|
|
||||||
* that can be used with the SetCookie constructor
|
|
||||||
*/
|
|
||||||
public function __construct($strictMode = false, $cookieArray = [])
|
|
||||||
{
|
|
||||||
$this->strictMode = $strictMode;
|
|
||||||
|
|
||||||
foreach ($cookieArray as $cookie) {
|
|
||||||
if (!($cookieArray instanceof SetCookie)) {
|
|
||||||
$cookie = new SetCookie($cookie);
|
|
||||||
}
|
|
||||||
$this->setCookie($cookie);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new Cookie jar from an associative array and domain.
|
|
||||||
*
|
|
||||||
* @param array $cookies Cookies to create the jar from
|
|
||||||
* @param string $domain Domain to set the cookies to
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public static function fromArray(array $cookies, $domain)
|
|
||||||
{
|
|
||||||
$cookieJar = new self();
|
|
||||||
foreach ($cookies as $name => $value) {
|
|
||||||
$cookieJar->setCookie(new SetCookie([
|
|
||||||
'Domain' => $domain,
|
|
||||||
'Name' => $name,
|
|
||||||
'Value' => $value,
|
|
||||||
'Discard' => true
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $cookieJar;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Quote the cookie value if it is not already quoted and it contains
|
|
||||||
* problematic characters.
|
|
||||||
*
|
|
||||||
* @param string $value Value that may or may not need to be quoted
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function getCookieValue($value)
|
|
||||||
{
|
|
||||||
if (substr($value, 0, 1) !== '"' &&
|
|
||||||
substr($value, -1, 1) !== '"' &&
|
|
||||||
strpbrk($value, ';,')
|
|
||||||
) {
|
|
||||||
$value = '"' . $value . '"';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toArray()
|
|
||||||
{
|
|
||||||
return array_map(function (SetCookie $cookie) {
|
|
||||||
return $cookie->toArray();
|
|
||||||
}, $this->getIterator()->getArrayCopy());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function clear($domain = null, $path = null, $name = null)
|
|
||||||
{
|
|
||||||
if (!$domain) {
|
|
||||||
$this->cookies = [];
|
|
||||||
return;
|
|
||||||
} elseif (!$path) {
|
|
||||||
$this->cookies = array_filter(
|
|
||||||
$this->cookies,
|
|
||||||
function (SetCookie $cookie) use ($path, $domain) {
|
|
||||||
return !$cookie->matchesDomain($domain);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} elseif (!$name) {
|
|
||||||
$this->cookies = array_filter(
|
|
||||||
$this->cookies,
|
|
||||||
function (SetCookie $cookie) use ($path, $domain) {
|
|
||||||
return !($cookie->matchesPath($path) &&
|
|
||||||
$cookie->matchesDomain($domain));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$this->cookies = array_filter(
|
|
||||||
$this->cookies,
|
|
||||||
function (SetCookie $cookie) use ($path, $domain, $name) {
|
|
||||||
return !($cookie->getName() == $name &&
|
|
||||||
$cookie->matchesPath($path) &&
|
|
||||||
$cookie->matchesDomain($domain));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function clearSessionCookies()
|
|
||||||
{
|
|
||||||
$this->cookies = array_filter(
|
|
||||||
$this->cookies,
|
|
||||||
function (SetCookie $cookie) {
|
|
||||||
return !$cookie->getDiscard() && $cookie->getExpires();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setCookie(SetCookie $cookie)
|
|
||||||
{
|
|
||||||
// Only allow cookies with set and valid domain, name, value
|
|
||||||
$result = $cookie->validate();
|
|
||||||
if ($result !== true) {
|
|
||||||
if ($this->strictMode) {
|
|
||||||
throw new \RuntimeException('Invalid cookie: ' . $result);
|
|
||||||
} else {
|
|
||||||
$this->removeCookieIfEmpty($cookie);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve conflicts with previously set cookies
|
|
||||||
foreach ($this->cookies as $i => $c) {
|
|
||||||
|
|
||||||
// Two cookies are identical, when their path, and domain are
|
|
||||||
// identical.
|
|
||||||
if ($c->getPath() != $cookie->getPath() ||
|
|
||||||
$c->getDomain() != $cookie->getDomain() ||
|
|
||||||
$c->getName() != $cookie->getName()
|
|
||||||
) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The previously set cookie is a discard cookie and this one is
|
|
||||||
// not so allow the new cookie to be set
|
|
||||||
if (!$cookie->getDiscard() && $c->getDiscard()) {
|
|
||||||
unset($this->cookies[$i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the new cookie's expiration is further into the future, then
|
|
||||||
// replace the old cookie
|
|
||||||
if ($cookie->getExpires() > $c->getExpires()) {
|
|
||||||
unset($this->cookies[$i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the value has changed, we better change it
|
|
||||||
if ($cookie->getValue() !== $c->getValue()) {
|
|
||||||
unset($this->cookies[$i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The cookie exists, so no need to continue
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->cookies[] = $cookie;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function count()
|
|
||||||
{
|
|
||||||
return count($this->cookies);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getIterator()
|
|
||||||
{
|
|
||||||
return new \ArrayIterator(array_values($this->cookies));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function extractCookies(
|
|
||||||
RequestInterface $request,
|
|
||||||
ResponseInterface $response
|
|
||||||
) {
|
|
||||||
if ($cookieHeader = $response->getHeader('Set-Cookie', true)) {
|
|
||||||
foreach ($cookieHeader as $cookie) {
|
|
||||||
$sc = SetCookie::fromString($cookie);
|
|
||||||
if (!$sc->getDomain()) {
|
|
||||||
$sc->setDomain($request->getHost());
|
|
||||||
}
|
|
||||||
$this->setCookie($sc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addCookieHeader(RequestInterface $request)
|
|
||||||
{
|
|
||||||
$values = [];
|
|
||||||
$scheme = $request->getScheme();
|
|
||||||
$host = $request->getHost();
|
|
||||||
$path = $request->getPath();
|
|
||||||
|
|
||||||
foreach ($this->cookies as $cookie) {
|
|
||||||
if ($cookie->matchesPath($path) &&
|
|
||||||
$cookie->matchesDomain($host) &&
|
|
||||||
!$cookie->isExpired() &&
|
|
||||||
(!$cookie->getSecure() || $scheme == 'https')
|
|
||||||
) {
|
|
||||||
$values[] = $cookie->getName() . '='
|
|
||||||
. self::getCookieValue($cookie->getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($values) {
|
|
||||||
$request->setHeader('Cookie', implode(';', $values));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If a cookie already exists and the server asks to set it again with a
|
|
||||||
* null value, the cookie must be deleted.
|
|
||||||
*
|
|
||||||
* @param SetCookie $cookie
|
|
||||||
*/
|
|
||||||
private function removeCookieIfEmpty(SetCookie $cookie)
|
|
||||||
{
|
|
||||||
$cookieValue = $cookie->getValue();
|
|
||||||
if ($cookieValue === null || $cookieValue === '') {
|
|
||||||
$this->clear(
|
|
||||||
$cookie->getDomain(),
|
|
||||||
$cookie->getPath(),
|
|
||||||
$cookie->getName()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Cookie;
|
|
||||||
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores HTTP cookies.
|
|
||||||
*
|
|
||||||
* It extracts cookies from HTTP requests, and returns them in HTTP responses.
|
|
||||||
* CookieJarInterface instances automatically expire contained cookies when
|
|
||||||
* necessary. Subclasses are also responsible for storing and retrieving
|
|
||||||
* cookies from a file, database, etc.
|
|
||||||
*
|
|
||||||
* @link http://docs.python.org/2/library/cookielib.html Inspiration
|
|
||||||
*/
|
|
||||||
interface CookieJarInterface extends \Countable, \IteratorAggregate
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Add a Cookie header to a request.
|
|
||||||
*
|
|
||||||
* If no matching cookies are found in the cookie jar, then no Cookie
|
|
||||||
* header is added to the request.
|
|
||||||
*
|
|
||||||
* @param RequestInterface $request Request object to update
|
|
||||||
*/
|
|
||||||
public function addCookieHeader(RequestInterface $request);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract cookies from an HTTP response and store them in the CookieJar.
|
|
||||||
*
|
|
||||||
* @param RequestInterface $request Request that was sent
|
|
||||||
* @param ResponseInterface $response Response that was received
|
|
||||||
*/
|
|
||||||
public function extractCookies(
|
|
||||||
RequestInterface $request,
|
|
||||||
ResponseInterface $response
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a cookie in the cookie jar.
|
|
||||||
*
|
|
||||||
* @param SetCookie $cookie Cookie to set.
|
|
||||||
*
|
|
||||||
* @return bool Returns true on success or false on failure
|
|
||||||
*/
|
|
||||||
public function setCookie(SetCookie $cookie);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove cookies currently held in the cookie jar.
|
|
||||||
*
|
|
||||||
* Invoking this method without arguments will empty the whole cookie jar.
|
|
||||||
* If given a $domain argument only cookies belonging to that domain will
|
|
||||||
* be removed. If given a $domain and $path argument, cookies belonging to
|
|
||||||
* the specified path within that domain are removed. If given all three
|
|
||||||
* arguments, then the cookie with the specified name, path and domain is
|
|
||||||
* removed.
|
|
||||||
*
|
|
||||||
* @param string $domain Clears cookies matching a domain
|
|
||||||
* @param string $path Clears cookies matching a domain and path
|
|
||||||
* @param string $name Clears cookies matching a domain, path, and name
|
|
||||||
*
|
|
||||||
* @return CookieJarInterface
|
|
||||||
*/
|
|
||||||
public function clear($domain = null, $path = null, $name = null);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discard all sessions cookies.
|
|
||||||
*
|
|
||||||
* Removes cookies that don't have an expire field or a have a discard
|
|
||||||
* field set to true. To be called when the user agent shuts down according
|
|
||||||
* to RFC 2965.
|
|
||||||
*/
|
|
||||||
public function clearSessionCookies();
|
|
||||||
}
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Cookie;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persists non-session cookies using a JSON formatted file
|
|
||||||
*/
|
|
||||||
class FileCookieJar extends CookieJar
|
|
||||||
{
|
|
||||||
/** @var string filename */
|
|
||||||
private $filename;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new FileCookieJar object
|
|
||||||
*
|
|
||||||
* @param string $cookieFile File to store the cookie data
|
|
||||||
*
|
|
||||||
* @throws \RuntimeException if the file cannot be found or created
|
|
||||||
*/
|
|
||||||
public function __construct($cookieFile)
|
|
||||||
{
|
|
||||||
$this->filename = $cookieFile;
|
|
||||||
|
|
||||||
if (file_exists($cookieFile)) {
|
|
||||||
$this->load($cookieFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the file when shutting down
|
|
||||||
*/
|
|
||||||
public function __destruct()
|
|
||||||
{
|
|
||||||
$this->save($this->filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the cookies to a file.
|
|
||||||
*
|
|
||||||
* @param string $filename File to save
|
|
||||||
* @throws \RuntimeException if the file cannot be found or created
|
|
||||||
*/
|
|
||||||
public function save($filename)
|
|
||||||
{
|
|
||||||
$json = [];
|
|
||||||
foreach ($this as $cookie) {
|
|
||||||
if ($cookie->getExpires() && !$cookie->getDiscard()) {
|
|
||||||
$json[] = $cookie->toArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false === file_put_contents($filename, json_encode($json))) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new \RuntimeException("Unable to save file {$filename}");
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load cookies from a JSON formatted file.
|
|
||||||
*
|
|
||||||
* Old cookies are kept unless overwritten by newly loaded ones.
|
|
||||||
*
|
|
||||||
* @param string $filename Cookie file to load.
|
|
||||||
* @throws \RuntimeException if the file cannot be loaded.
|
|
||||||
*/
|
|
||||||
public function load($filename)
|
|
||||||
{
|
|
||||||
$json = file_get_contents($filename);
|
|
||||||
if (false === $json) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new \RuntimeException("Unable to load file {$filename}");
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = \GuzzleHttp\json_decode($json, true);
|
|
||||||
if (is_array($data)) {
|
|
||||||
foreach (\GuzzleHttp\json_decode($json, true) as $cookie) {
|
|
||||||
$this->setCookie(new SetCookie($cookie));
|
|
||||||
}
|
|
||||||
} elseif (strlen($data)) {
|
|
||||||
throw new \RuntimeException("Invalid cookie file: {$filename}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Cookie;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persists cookies in the client session
|
|
||||||
*/
|
|
||||||
class SessionCookieJar extends CookieJar
|
|
||||||
{
|
|
||||||
/** @var string session key */
|
|
||||||
private $sessionKey;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new SessionCookieJar object
|
|
||||||
*
|
|
||||||
* @param string $sessionKey Session key name to store the cookie data in session
|
|
||||||
*/
|
|
||||||
public function __construct($sessionKey)
|
|
||||||
{
|
|
||||||
$this->sessionKey = $sessionKey;
|
|
||||||
$this->load();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves cookies to session when shutting down
|
|
||||||
*/
|
|
||||||
public function __destruct()
|
|
||||||
{
|
|
||||||
$this->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save cookies to the client session
|
|
||||||
*/
|
|
||||||
public function save()
|
|
||||||
{
|
|
||||||
$json = [];
|
|
||||||
foreach ($this as $cookie) {
|
|
||||||
if ($cookie->getExpires() && !$cookie->getDiscard()) {
|
|
||||||
$json[] = $cookie->toArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$_SESSION[$this->sessionKey] = json_encode($json);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the contents of the client session into the data array
|
|
||||||
*/
|
|
||||||
protected function load()
|
|
||||||
{
|
|
||||||
$cookieJar = isset($_SESSION[$this->sessionKey])
|
|
||||||
? $_SESSION[$this->sessionKey]
|
|
||||||
: null;
|
|
||||||
|
|
||||||
$data = \GuzzleHttp\json_decode($cookieJar, true);
|
|
||||||
if (is_array($data)) {
|
|
||||||
foreach ($data as $cookie) {
|
|
||||||
$this->setCookie(new SetCookie($cookie));
|
|
||||||
}
|
|
||||||
} elseif (strlen($data)) {
|
|
||||||
throw new \RuntimeException("Invalid cookie data");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,410 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Cookie;
|
|
||||||
|
|
||||||
use GuzzleHttp\ToArrayInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set-Cookie object
|
|
||||||
*/
|
|
||||||
class SetCookie implements ToArrayInterface
|
|
||||||
{
|
|
||||||
/** @var array */
|
|
||||||
private static $defaults = [
|
|
||||||
'Name' => null,
|
|
||||||
'Value' => null,
|
|
||||||
'Domain' => null,
|
|
||||||
'Path' => '/',
|
|
||||||
'Max-Age' => null,
|
|
||||||
'Expires' => null,
|
|
||||||
'Secure' => false,
|
|
||||||
'Discard' => false,
|
|
||||||
'HttpOnly' => false
|
|
||||||
];
|
|
||||||
|
|
||||||
/** @var array Cookie data */
|
|
||||||
private $data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new SetCookie object from a string
|
|
||||||
*
|
|
||||||
* @param string $cookie Set-Cookie header string
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public static function fromString($cookie)
|
|
||||||
{
|
|
||||||
// Create the default return array
|
|
||||||
$data = self::$defaults;
|
|
||||||
// Explode the cookie string using a series of semicolons
|
|
||||||
$pieces = array_filter(array_map('trim', explode(';', $cookie)));
|
|
||||||
// The name of the cookie (first kvp) must include an equal sign.
|
|
||||||
if (empty($pieces) || !strpos($pieces[0], '=')) {
|
|
||||||
return new self($data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the cookie pieces into the parsed data array
|
|
||||||
foreach ($pieces as $part) {
|
|
||||||
|
|
||||||
$cookieParts = explode('=', $part, 2);
|
|
||||||
$key = trim($cookieParts[0]);
|
|
||||||
$value = isset($cookieParts[1])
|
|
||||||
? trim($cookieParts[1], " \n\r\t\0\x0B\"")
|
|
||||||
: true;
|
|
||||||
|
|
||||||
// Only check for non-cookies when cookies have been found
|
|
||||||
if (empty($data['Name'])) {
|
|
||||||
$data['Name'] = $key;
|
|
||||||
$data['Value'] = $value;
|
|
||||||
} else {
|
|
||||||
foreach (array_keys(self::$defaults) as $search) {
|
|
||||||
if (!strcasecmp($search, $key)) {
|
|
||||||
$data[$search] = $value;
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$data[$key] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new self($data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $data Array of cookie data provided by a Cookie parser
|
|
||||||
*/
|
|
||||||
public function __construct(array $data = [])
|
|
||||||
{
|
|
||||||
$this->data = array_replace(self::$defaults, $data);
|
|
||||||
// Extract the Expires value and turn it into a UNIX timestamp if needed
|
|
||||||
if (!$this->getExpires() && $this->getMaxAge()) {
|
|
||||||
// Calculate the Expires date
|
|
||||||
$this->setExpires(time() + $this->getMaxAge());
|
|
||||||
} elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
|
|
||||||
$this->setExpires($this->getExpires());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
$str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
|
|
||||||
foreach ($this->data as $k => $v) {
|
|
||||||
if ($k != 'Name' && $k != 'Value'&& $v !== null && $v !== false) {
|
|
||||||
if ($k == 'Expires') {
|
|
||||||
$str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
|
|
||||||
} else {
|
|
||||||
$str .= ($v === true ? $k : "{$k}={$v}") . '; ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rtrim($str, '; ');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toArray()
|
|
||||||
{
|
|
||||||
return $this->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the cookie name
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return $this->data['Name'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the cookie name
|
|
||||||
*
|
|
||||||
* @param string $name Cookie name
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setName($name)
|
|
||||||
{
|
|
||||||
$this->data['Name'] = $name;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the cookie value
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getValue()
|
|
||||||
{
|
|
||||||
return $this->data['Value'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the cookie value
|
|
||||||
*
|
|
||||||
* @param string $value Cookie value
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setValue($value)
|
|
||||||
{
|
|
||||||
$this->data['Value'] = $value;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the domain
|
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
public function getDomain()
|
|
||||||
{
|
|
||||||
return $this->data['Domain'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the domain of the cookie
|
|
||||||
*
|
|
||||||
* @param string $domain
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setDomain($domain)
|
|
||||||
{
|
|
||||||
$this->data['Domain'] = $domain;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the path
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getPath()
|
|
||||||
{
|
|
||||||
return $this->data['Path'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the path of the cookie
|
|
||||||
*
|
|
||||||
* @param string $path Path of the cookie
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setPath($path)
|
|
||||||
{
|
|
||||||
$this->data['Path'] = $path;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum lifetime of the cookie in seconds
|
|
||||||
*
|
|
||||||
* @return int|null
|
|
||||||
*/
|
|
||||||
public function getMaxAge()
|
|
||||||
{
|
|
||||||
return $this->data['Max-Age'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the max-age of the cookie
|
|
||||||
*
|
|
||||||
* @param int $maxAge Max age of the cookie in seconds
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setMaxAge($maxAge)
|
|
||||||
{
|
|
||||||
$this->data['Max-Age'] = $maxAge;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The UNIX timestamp when the cookie Expires
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getExpires()
|
|
||||||
{
|
|
||||||
return $this->data['Expires'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the unix timestamp for which the cookie will expire
|
|
||||||
*
|
|
||||||
* @param int $timestamp Unix timestamp
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setExpires($timestamp)
|
|
||||||
{
|
|
||||||
$this->data['Expires'] = is_numeric($timestamp)
|
|
||||||
? (int) $timestamp
|
|
||||||
: strtotime($timestamp);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get whether or not this is a secure cookie
|
|
||||||
*
|
|
||||||
* @return null|bool
|
|
||||||
*/
|
|
||||||
public function getSecure()
|
|
||||||
{
|
|
||||||
return $this->data['Secure'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether or not the cookie is secure
|
|
||||||
*
|
|
||||||
* @param bool $secure Set to true or false if secure
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setSecure($secure)
|
|
||||||
{
|
|
||||||
$this->data['Secure'] = $secure;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get whether or not this is a session cookie
|
|
||||||
*
|
|
||||||
* @return null|bool
|
|
||||||
*/
|
|
||||||
public function getDiscard()
|
|
||||||
{
|
|
||||||
return $this->data['Discard'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether or not this is a session cookie
|
|
||||||
*
|
|
||||||
* @param bool $discard Set to true or false if this is a session cookie
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setDiscard($discard)
|
|
||||||
{
|
|
||||||
$this->data['Discard'] = $discard;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get whether or not this is an HTTP only cookie
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function getHttpOnly()
|
|
||||||
{
|
|
||||||
return $this->data['HttpOnly'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether or not this is an HTTP only cookie
|
|
||||||
*
|
|
||||||
* @param bool $httpOnly Set to true or false if this is HTTP only
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setHttpOnly($httpOnly)
|
|
||||||
{
|
|
||||||
$this->data['HttpOnly'] = $httpOnly;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the cookie matches a path value
|
|
||||||
*
|
|
||||||
* @param string $path Path to check against
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function matchesPath($path)
|
|
||||||
{
|
|
||||||
return !$this->getPath() || 0 === stripos($path, $this->getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the cookie matches a domain value
|
|
||||||
*
|
|
||||||
* @param string $domain Domain to check against
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function matchesDomain($domain)
|
|
||||||
{
|
|
||||||
// Remove the leading '.' as per spec in RFC 6265.
|
|
||||||
// http://tools.ietf.org/html/rfc6265#section-5.2.3
|
|
||||||
$cookieDomain = ltrim($this->getDomain(), '.');
|
|
||||||
|
|
||||||
// Domain not set or exact match.
|
|
||||||
if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Matching the subdomain according to RFC 6265.
|
|
||||||
// http://tools.ietf.org/html/rfc6265#section-5.1.3
|
|
||||||
if (filter_var($domain, FILTER_VALIDATE_IP)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (bool) preg_match('/\.' . preg_quote($cookieDomain) . '$/i', $domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the cookie is expired
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isExpired()
|
|
||||||
{
|
|
||||||
return $this->getExpires() && time() > $this->getExpires();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the cookie is valid according to RFC 6265
|
|
||||||
*
|
|
||||||
* @return bool|string Returns true if valid or an error message if invalid
|
|
||||||
*/
|
|
||||||
public function validate()
|
|
||||||
{
|
|
||||||
// Names must not be empty, but can be 0
|
|
||||||
$name = $this->getName();
|
|
||||||
if (empty($name) && !is_numeric($name)) {
|
|
||||||
return 'The cookie name must not be empty';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if any of the invalid characters are present in the cookie name
|
|
||||||
if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
|
|
||||||
return "Cookie name must not cannot invalid characters: =,; \\t\\r\\n\\013\\014";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value must not be empty, but can be 0
|
|
||||||
$value = $this->getValue();
|
|
||||||
if (empty($value) && !is_numeric($value)) {
|
|
||||||
return 'The cookie value must not be empty';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Domains must not be empty, but can be 0
|
|
||||||
// A "0" is not a valid internet domain, but may be used as server name
|
|
||||||
// in a private network.
|
|
||||||
$domain = $this->getDomain();
|
|
||||||
if (empty($domain) && !is_numeric($domain)) {
|
|
||||||
return 'The cookie domain must not be empty';
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic event class that can be extended.
|
|
||||||
*/
|
|
||||||
abstract class AbstractEvent implements EventInterface
|
|
||||||
{
|
|
||||||
private $propagationStopped = false;
|
|
||||||
|
|
||||||
public function isPropagationStopped()
|
|
||||||
{
|
|
||||||
return $this->propagationStopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stopPropagation()
|
|
||||||
{
|
|
||||||
$this->propagationStopped = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
use GuzzleHttp\Adapter\TransactionInterface;
|
|
||||||
use GuzzleHttp\ClientInterface;
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
|
|
||||||
abstract class AbstractRequestEvent extends AbstractEvent
|
|
||||||
{
|
|
||||||
/** @var TransactionInterface */
|
|
||||||
private $transaction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param TransactionInterface $transaction
|
|
||||||
*/
|
|
||||||
public function __construct(TransactionInterface $transaction)
|
|
||||||
{
|
|
||||||
$this->transaction = $transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the client associated with the event
|
|
||||||
*
|
|
||||||
* @return ClientInterface
|
|
||||||
*/
|
|
||||||
public function getClient()
|
|
||||||
{
|
|
||||||
return $this->transaction->getClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the request object
|
|
||||||
*
|
|
||||||
* @return RequestInterface
|
|
||||||
*/
|
|
||||||
public function getRequest()
|
|
||||||
{
|
|
||||||
return $this->transaction->getRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return TransactionInterface
|
|
||||||
*/
|
|
||||||
protected function getTransaction()
|
|
||||||
{
|
|
||||||
return $this->transaction;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
use GuzzleHttp\Adapter\TransactionInterface;
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event that contains transaction statistics (time over the wire, lookup time,
|
|
||||||
* etc.).
|
|
||||||
*
|
|
||||||
* Adapters that create this event SHOULD add, at a minimum, the 'total_time'
|
|
||||||
* transfer statistic that measures the amount of time, in seconds, taken to
|
|
||||||
* complete a transfer for the current request/response cycle. Each event
|
|
||||||
* pertains to a single request/response transaction, NOT the entire
|
|
||||||
* transaction (e.g. redirects).
|
|
||||||
*
|
|
||||||
* Adapters that add transaction statistics SHOULD follow the same string
|
|
||||||
* attribute names that are provided by cURL listed at
|
|
||||||
* http://php.net/manual/en/function.curl-getinfo.php. However, not all
|
|
||||||
* adapters will have access to the advanced statistics provided by cURL. The
|
|
||||||
* most useful transfer statistics are as follows:
|
|
||||||
*
|
|
||||||
* - total_time: Total transaction time in seconds for last transfer
|
|
||||||
* - namelookup_time: Time in seconds until name resolving was complete
|
|
||||||
* - connect_time: Time in seconds it took to establish the connection
|
|
||||||
* - pretransfer_time: Time in seconds from start until just before file
|
|
||||||
* transfer begins.
|
|
||||||
* - starttransfer_time: Time in seconds until the first byte is about to be
|
|
||||||
* transferred.
|
|
||||||
* - speed_download: Average download speed
|
|
||||||
* - speed_upload: Average upload speed
|
|
||||||
*/
|
|
||||||
abstract class AbstractTransferEvent extends AbstractRequestEvent
|
|
||||||
{
|
|
||||||
private $transferInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param TransactionInterface $transaction Transaction
|
|
||||||
* @param array $transferInfo Transfer statistics
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
TransactionInterface $transaction,
|
|
||||||
$transferInfo = []
|
|
||||||
) {
|
|
||||||
parent::__construct($transaction);
|
|
||||||
$this->transferInfo = $transferInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all transfer information as an associative array if no $name
|
|
||||||
* argument is supplied, or gets a specific transfer statistic if
|
|
||||||
* a $name attribute is supplied (e.g., 'total_time').
|
|
||||||
*
|
|
||||||
* @param string $name Name of the transfer stat to retrieve
|
|
||||||
*
|
|
||||||
* @return mixed|null|array
|
|
||||||
*/
|
|
||||||
public function getTransferInfo($name = null)
|
|
||||||
{
|
|
||||||
if (!$name) {
|
|
||||||
return $this->transferInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isset($this->transferInfo[$name])
|
|
||||||
? $this->transferInfo[$name]
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the response
|
|
||||||
*
|
|
||||||
* @return ResponseInterface|null
|
|
||||||
*/
|
|
||||||
abstract public function getResponse();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Intercept the request and associate a response
|
|
||||||
*
|
|
||||||
* @param ResponseInterface $response Response to set
|
|
||||||
*/
|
|
||||||
abstract public function intercept(ResponseInterface $response);
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event object emitted before a request is sent.
|
|
||||||
*
|
|
||||||
* You may change the Response associated with the request using the
|
|
||||||
* intercept() method of the event.
|
|
||||||
*/
|
|
||||||
class BeforeEvent extends AbstractRequestEvent
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Intercept the request and associate a response
|
|
||||||
*
|
|
||||||
* @param ResponseInterface $response Response to set
|
|
||||||
*/
|
|
||||||
public function intercept(ResponseInterface $response)
|
|
||||||
{
|
|
||||||
$this->getTransaction()->setResponse($response);
|
|
||||||
$this->stopPropagation();
|
|
||||||
RequestEvents::emitComplete($this->getTransaction());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event object emitted after a request has been completed.
|
|
||||||
*
|
|
||||||
* You may change the Response associated with the request using the
|
|
||||||
* intercept() method of the event.
|
|
||||||
*/
|
|
||||||
class CompleteEvent extends AbstractTransferEvent
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Intercept the request and associate a response
|
|
||||||
*
|
|
||||||
* @param ResponseInterface $response Response to set
|
|
||||||
*/
|
|
||||||
public function intercept(ResponseInterface $response)
|
|
||||||
{
|
|
||||||
$this->stopPropagation();
|
|
||||||
$this->getTransaction()->setResponse($response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the response of the request
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function getResponse()
|
|
||||||
{
|
|
||||||
return $this->getTransaction()->getResponse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,147 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Guzzle event emitter.
|
|
||||||
*
|
|
||||||
* Some of this class is based on the Symfony EventDispatcher component, which
|
|
||||||
* ships with the following license:
|
|
||||||
*
|
|
||||||
* This file is part of the Symfony package.
|
|
||||||
*
|
|
||||||
* (c) Fabien Potencier <fabien@symfony.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*
|
|
||||||
* @link https://github.com/symfony/symfony/tree/master/src/Symfony/Component/EventDispatcher
|
|
||||||
*/
|
|
||||||
class Emitter implements EmitterInterface
|
|
||||||
{
|
|
||||||
/** @var array */
|
|
||||||
private $listeners = [];
|
|
||||||
|
|
||||||
/** @var array */
|
|
||||||
private $sorted = [];
|
|
||||||
|
|
||||||
public function on($eventName, callable $listener, $priority = 0)
|
|
||||||
{
|
|
||||||
if ($priority === 'first') {
|
|
||||||
$priority = isset($this->listeners[$eventName])
|
|
||||||
? max(array_keys($this->listeners[$eventName])) + 1
|
|
||||||
: 1;
|
|
||||||
} elseif ($priority === 'last') {
|
|
||||||
$priority = isset($this->listeners[$eventName])
|
|
||||||
? min(array_keys($this->listeners[$eventName])) - 1
|
|
||||||
: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->listeners[$eventName][$priority][] = $listener;
|
|
||||||
unset($this->sorted[$eventName]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function once($eventName, callable $listener, $priority = 0)
|
|
||||||
{
|
|
||||||
$onceListener = function (
|
|
||||||
EventInterface $event,
|
|
||||||
$eventName
|
|
||||||
) use (&$onceListener, $eventName, $listener, $priority) {
|
|
||||||
$this->removeListener($eventName, $onceListener);
|
|
||||||
$listener($event, $eventName, $this);
|
|
||||||
};
|
|
||||||
|
|
||||||
$this->on($eventName, $onceListener, $priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function removeListener($eventName, callable $listener)
|
|
||||||
{
|
|
||||||
if (!isset($this->listeners[$eventName])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->listeners[$eventName] as $priority => $listeners) {
|
|
||||||
if (false !== ($key = array_search($listener, $listeners, true))) {
|
|
||||||
unset(
|
|
||||||
$this->listeners[$eventName][$priority][$key],
|
|
||||||
$this->sorted[$eventName]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function listeners($eventName = null)
|
|
||||||
{
|
|
||||||
// Return all events in a sorted priority order
|
|
||||||
if ($eventName === null) {
|
|
||||||
foreach (array_keys($this->listeners) as $eventName) {
|
|
||||||
if (!isset($this->sorted[$eventName])) {
|
|
||||||
$this->listeners($eventName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $this->sorted;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the listeners for a specific event, sorted in priority order
|
|
||||||
if (!isset($this->sorted[$eventName])) {
|
|
||||||
if (!isset($this->listeners[$eventName])) {
|
|
||||||
return [];
|
|
||||||
} else {
|
|
||||||
krsort($this->listeners[$eventName]);
|
|
||||||
$this->sorted[$eventName] = call_user_func_array(
|
|
||||||
'array_merge',
|
|
||||||
$this->listeners[$eventName]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->sorted[$eventName];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function emit($eventName, EventInterface $event)
|
|
||||||
{
|
|
||||||
if (isset($this->listeners[$eventName])) {
|
|
||||||
foreach ($this->listeners($eventName) as $listener) {
|
|
||||||
$listener($event, $eventName);
|
|
||||||
if ($event->isPropagationStopped()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $event;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function attach(SubscriberInterface $subscriber)
|
|
||||||
{
|
|
||||||
foreach ($subscriber->getEvents() as $eventName => $listener) {
|
|
||||||
$this->on(
|
|
||||||
$eventName,
|
|
||||||
array($subscriber, $listener[0]),
|
|
||||||
isset($listener[1]) ? $listener[1] : 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function detach(SubscriberInterface $subscriber)
|
|
||||||
{
|
|
||||||
foreach ($subscriber->getEvents() as $eventName => $listener) {
|
|
||||||
$this->removeListener($eventName, array($subscriber, $listener[0]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __call($name, $arguments)
|
|
||||||
{
|
|
||||||
return \GuzzleHttp\deprecation_proxy(
|
|
||||||
$this,
|
|
||||||
$name,
|
|
||||||
$arguments,
|
|
||||||
[
|
|
||||||
'addSubscriber' => 'attach',
|
|
||||||
'removeSubscriber' => 'detach',
|
|
||||||
'addListener' => 'on',
|
|
||||||
'dispatch' => 'emit'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Guzzle event emitter.
|
|
||||||
*/
|
|
||||||
interface EmitterInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Binds a listener to a specific event.
|
|
||||||
*
|
|
||||||
* @param string $eventName Name of the event to bind to.
|
|
||||||
* @param callable $listener Listener to invoke when triggered.
|
|
||||||
* @param int|string $priority The higher this value, the earlier an event
|
|
||||||
* listener will be triggered in the chain (defaults to 0). You can
|
|
||||||
* pass "first" or "last" to dynamically specify the event priority
|
|
||||||
* based on the current event priorities associated with the given
|
|
||||||
* event name in the emitter. Use "first" to set the priority to the
|
|
||||||
* current highest priority plus one. Use "last" to set the priority to
|
|
||||||
* the current lowest event priority minus one.
|
|
||||||
*/
|
|
||||||
public function on($eventName, callable $listener, $priority = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds a listener to a specific event. After the listener is triggered
|
|
||||||
* once, it is removed as a listener.
|
|
||||||
*
|
|
||||||
* @param string $eventName Name of the event to bind to.
|
|
||||||
* @param callable $listener Listener to invoke when triggered.
|
|
||||||
* @param int $priority The higher this value, the earlier an event
|
|
||||||
* listener will be triggered in the chain (defaults to 0)
|
|
||||||
*/
|
|
||||||
public function once($eventName, callable $listener, $priority = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes an event listener from the specified event.
|
|
||||||
*
|
|
||||||
* @param string $eventName The event to remove a listener from
|
|
||||||
* @param callable $listener The listener to remove
|
|
||||||
*/
|
|
||||||
public function removeListener($eventName, callable $listener);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the listeners of a specific event or all listeners if no event is
|
|
||||||
* specified.
|
|
||||||
*
|
|
||||||
* @param string $eventName The name of the event. Pass null (the default)
|
|
||||||
* to retrieve all listeners.
|
|
||||||
*
|
|
||||||
* @return array The event listeners for the specified event, or all event
|
|
||||||
* listeners by event name. The format of the array when retrieving a
|
|
||||||
* specific event list is an array of callables. The format of the array
|
|
||||||
* when retrieving all listeners is an associative array of arrays of
|
|
||||||
* callables.
|
|
||||||
*/
|
|
||||||
public function listeners($eventName = null);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits an event to all registered listeners.
|
|
||||||
*
|
|
||||||
* Each event that is bound to the emitted eventName receives a
|
|
||||||
* EventInterface, the name of the event, and the event emitter.
|
|
||||||
*
|
|
||||||
* @param string $eventName The name of the event to dispatch.
|
|
||||||
* @param EventInterface $event The event to pass to the event handlers/listeners.
|
|
||||||
*
|
|
||||||
* @return EventInterface Returns the provided event object
|
|
||||||
*/
|
|
||||||
public function emit($eventName, EventInterface $event);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attaches an event subscriber.
|
|
||||||
*
|
|
||||||
* The subscriber is asked for all the events it is interested in and added
|
|
||||||
* as an event listener for each event.
|
|
||||||
*
|
|
||||||
* @param SubscriberInterface $subscriber Subscriber to attach.
|
|
||||||
*/
|
|
||||||
public function attach(SubscriberInterface $subscriber);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detaches an event subscriber.
|
|
||||||
*
|
|
||||||
* @param SubscriberInterface $subscriber Subscriber to detach.
|
|
||||||
*/
|
|
||||||
public function detach(SubscriberInterface $subscriber);
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
use GuzzleHttp\Exception\RequestException;
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
use GuzzleHttp\Adapter\TransactionInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event object emitted after a request has been sent and an error was
|
|
||||||
* encountered.
|
|
||||||
*
|
|
||||||
* You may intercept the exception and inject a response into the event to
|
|
||||||
* rescue the request.
|
|
||||||
*/
|
|
||||||
class ErrorEvent extends AbstractTransferEvent
|
|
||||||
{
|
|
||||||
private $exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param TransactionInterface $transaction Transaction that contains the request
|
|
||||||
* @param RequestException $e Exception encountered
|
|
||||||
* @param array $transferStats Array of transfer statistics
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
TransactionInterface $transaction,
|
|
||||||
RequestException $e,
|
|
||||||
$transferStats = []
|
|
||||||
) {
|
|
||||||
parent::__construct($transaction, $transferStats);
|
|
||||||
$this->exception = $e;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Intercept the exception and inject a response
|
|
||||||
*
|
|
||||||
* @param ResponseInterface $response Response to set
|
|
||||||
*/
|
|
||||||
public function intercept(ResponseInterface $response)
|
|
||||||
{
|
|
||||||
$this->stopPropagation();
|
|
||||||
$this->getTransaction()->setResponse($response);
|
|
||||||
RequestEvents::emitComplete($this->getTransaction());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the exception that was encountered
|
|
||||||
*
|
|
||||||
* @return RequestException
|
|
||||||
*/
|
|
||||||
public function getException()
|
|
||||||
{
|
|
||||||
return $this->exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the response the was received (if any)
|
|
||||||
*
|
|
||||||
* @return ResponseInterface|null
|
|
||||||
*/
|
|
||||||
public function getResponse()
|
|
||||||
{
|
|
||||||
return $this->getException()->getResponse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base event interface used when dispatching events to listeners using an
|
|
||||||
* event emitter.
|
|
||||||
*/
|
|
||||||
interface EventInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns whether or not stopPropagation was called on the event.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
* @see Event::stopPropagation
|
|
||||||
*/
|
|
||||||
public function isPropagationStopped();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops the propagation of the event, preventing subsequent listeners
|
|
||||||
* registered to the same event from being invoked.
|
|
||||||
*/
|
|
||||||
public function stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds an event emitter
|
|
||||||
*/
|
|
||||||
interface HasEmitterInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get the event emitter of the object
|
|
||||||
*
|
|
||||||
* @return EmitterInterface
|
|
||||||
*/
|
|
||||||
public function getEmitter();
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trait that implements the methods of HasEmitterInterface
|
|
||||||
*/
|
|
||||||
trait HasEmitterTrait
|
|
||||||
{
|
|
||||||
/** @var EmitterInterface */
|
|
||||||
private $emitter;
|
|
||||||
|
|
||||||
public function getEmitter()
|
|
||||||
{
|
|
||||||
if (!$this->emitter) {
|
|
||||||
$this->emitter = new Emitter();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->emitter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
use GuzzleHttp\Adapter\TransactionInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event object emitted after the response headers of a request have been
|
|
||||||
* received.
|
|
||||||
*
|
|
||||||
* You may intercept the exception and inject a response into the event to
|
|
||||||
* rescue the request.
|
|
||||||
*/
|
|
||||||
class HeadersEvent extends AbstractRequestEvent
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @param TransactionInterface $transaction Transaction that contains the
|
|
||||||
* request and response.
|
|
||||||
* @throws \RuntimeException
|
|
||||||
*/
|
|
||||||
public function __construct(TransactionInterface $transaction)
|
|
||||||
{
|
|
||||||
parent::__construct($transaction);
|
|
||||||
if (!$transaction->getResponse()) {
|
|
||||||
throw new \RuntimeException('A response must be present');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the response the was received
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function getResponse()
|
|
||||||
{
|
|
||||||
return $this->getTransaction()->getResponse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,89 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trait that provides methods for extract event listeners specified in an array
|
|
||||||
* and attaching them to an emitter owned by the object or one of its direct
|
|
||||||
* dependencies.
|
|
||||||
*/
|
|
||||||
trait ListenerAttacherTrait
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Attaches event listeners and properly sets their priorities and whether
|
|
||||||
* or not they are are only executed once.
|
|
||||||
*
|
|
||||||
* @param HasEmitterInterface $object Object that has the event emitter.
|
|
||||||
* @param array $listeners Array of hashes representing event
|
|
||||||
* event listeners. Each item contains
|
|
||||||
* "name", "fn", "priority", & "once".
|
|
||||||
*/
|
|
||||||
private function attachListeners(HasEmitterInterface $object, array $listeners)
|
|
||||||
{
|
|
||||||
$emitter = $object->getEmitter();
|
|
||||||
foreach ($listeners as $el) {
|
|
||||||
if ($el['once']) {
|
|
||||||
$emitter->once($el['name'], $el['fn'], $el['priority']);
|
|
||||||
} else {
|
|
||||||
$emitter->on($el['name'], $el['fn'], $el['priority']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the allowed events from the provided array, and ignores anything
|
|
||||||
* else in the array. The event listener must be specified as a callable or
|
|
||||||
* as an array of event listener data ("name", "fn", "priority", "once").
|
|
||||||
*
|
|
||||||
* @param array $source Array containing callables or hashes of data to be
|
|
||||||
* prepared as event listeners.
|
|
||||||
* @param array $events Names of events to look for in the provided $source
|
|
||||||
* array. Other keys are ignored.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function prepareListeners(array $source, array $events)
|
|
||||||
{
|
|
||||||
$listeners = [];
|
|
||||||
foreach ($events as $name) {
|
|
||||||
if (isset($source[$name])) {
|
|
||||||
$this->buildListener($name, $source[$name], $listeners);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $listeners;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a complete event listener definition from the provided array of
|
|
||||||
* listener data. Also works recursively if more than one listeners are
|
|
||||||
* contained in the provided array.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the event the listener is for.
|
|
||||||
* @param array|callable $data Event listener data to prepare.
|
|
||||||
* @param array $listeners Array of listeners, passed by reference.
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException if the event data is malformed.
|
|
||||||
*/
|
|
||||||
private function buildListener($name, $data, &$listeners)
|
|
||||||
{
|
|
||||||
static $defaults = ['priority' => 0, 'once' => false];
|
|
||||||
|
|
||||||
// If a callable is provided, normalize it to the array format.
|
|
||||||
if (is_callable($data)) {
|
|
||||||
$data = ['fn' => $data];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare the listener and add it to the array, recursively.
|
|
||||||
if (isset($data['fn'])) {
|
|
||||||
$data['name'] = $name;
|
|
||||||
$listeners[] = $data + $defaults;
|
|
||||||
} elseif (is_array($data)) {
|
|
||||||
foreach ($data as $listenerData) {
|
|
||||||
$this->buildListener($name, $listenerData, $listeners);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new \InvalidArgumentException('Each event listener must be a '
|
|
||||||
. 'callable or an associative array containing a "fn" key.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,162 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
use GuzzleHttp\Adapter\TransactionInterface;
|
|
||||||
use GuzzleHttp\Exception\RequestException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains methods used to manage the request event lifecycle.
|
|
||||||
*/
|
|
||||||
final class RequestEvents
|
|
||||||
{
|
|
||||||
// Generic event priorities
|
|
||||||
const EARLY = 10000;
|
|
||||||
const LATE = -10000;
|
|
||||||
|
|
||||||
// "before" priorities
|
|
||||||
const PREPARE_REQUEST = -100;
|
|
||||||
const SIGN_REQUEST = -10000;
|
|
||||||
|
|
||||||
// "complete" and "error" response priorities
|
|
||||||
const VERIFY_RESPONSE = 100;
|
|
||||||
const REDIRECT_RESPONSE = 200;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits the before send event for a request and emits an error
|
|
||||||
* event if an error is encountered during the before send.
|
|
||||||
*
|
|
||||||
* @param TransactionInterface $transaction
|
|
||||||
*
|
|
||||||
* @throws RequestException
|
|
||||||
*/
|
|
||||||
public static function emitBefore(TransactionInterface $transaction) {
|
|
||||||
$request = $transaction->getRequest();
|
|
||||||
try {
|
|
||||||
$request->getEmitter()->emit(
|
|
||||||
'before',
|
|
||||||
new BeforeEvent($transaction)
|
|
||||||
);
|
|
||||||
} catch (RequestException $e) {
|
|
||||||
// When a RequestException has been emitted through emitError, the
|
|
||||||
// exception is marked as "emitted". This means that the exception
|
|
||||||
// had a chance to be rescued but was not. In this case, this method
|
|
||||||
// must not emit the error again, but rather throw the exception.
|
|
||||||
// This prevents RequestExceptions encountered during the before
|
|
||||||
// event from being emitted to listeners twice.
|
|
||||||
if ($e->emittedError()) {
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
self::emitError($transaction, $e);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
self::emitError($transaction, $e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits the complete event for a request and emits an error
|
|
||||||
* event if an error is encountered during the after send.
|
|
||||||
*
|
|
||||||
* @param TransactionInterface $transaction Transaction to emit for
|
|
||||||
* @param array $stats Transfer stats
|
|
||||||
*
|
|
||||||
* @throws RequestException
|
|
||||||
*/
|
|
||||||
public static function emitComplete(
|
|
||||||
TransactionInterface $transaction,
|
|
||||||
array $stats = []
|
|
||||||
) {
|
|
||||||
$request = $transaction->getRequest();
|
|
||||||
$transaction->getResponse()->setEffectiveUrl($request->getUrl());
|
|
||||||
try {
|
|
||||||
$request->getEmitter()->emit(
|
|
||||||
'complete',
|
|
||||||
new CompleteEvent($transaction, $stats)
|
|
||||||
);
|
|
||||||
} catch (RequestException $e) {
|
|
||||||
self::emitError($transaction, $e, $stats);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits the headers event for a request.
|
|
||||||
*
|
|
||||||
* @param TransactionInterface $transaction Transaction to emit for
|
|
||||||
*/
|
|
||||||
public static function emitHeaders(TransactionInterface $transaction)
|
|
||||||
{
|
|
||||||
$transaction->getRequest()->getEmitter()->emit(
|
|
||||||
'headers',
|
|
||||||
new HeadersEvent($transaction)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits an error event for a request and accounts for the propagation
|
|
||||||
* of an error event being stopped to prevent the exception from being
|
|
||||||
* thrown.
|
|
||||||
*
|
|
||||||
* @param TransactionInterface $transaction
|
|
||||||
* @param \Exception $e
|
|
||||||
* @param array $stats
|
|
||||||
*
|
|
||||||
* @throws \GuzzleHttp\Exception\RequestException
|
|
||||||
*/
|
|
||||||
public static function emitError(
|
|
||||||
TransactionInterface $transaction,
|
|
||||||
\Exception $e,
|
|
||||||
array $stats = []
|
|
||||||
) {
|
|
||||||
$request = $transaction->getRequest();
|
|
||||||
|
|
||||||
// Convert non-request exception to a wrapped exception
|
|
||||||
if (!($e instanceof RequestException)) {
|
|
||||||
$e = new RequestException($e->getMessage(), $request, null, $e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark the exception as having been emitted for an error event. This
|
|
||||||
// works in tandem with the emitBefore method to prevent the error
|
|
||||||
// event from being triggered twice for the same exception.
|
|
||||||
$e->emittedError(true);
|
|
||||||
|
|
||||||
// Dispatch an event and allow interception
|
|
||||||
if (!$request->getEmitter()->emit(
|
|
||||||
'error',
|
|
||||||
new ErrorEvent($transaction, $e, $stats)
|
|
||||||
)->isPropagationStopped()) {
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an array of event options into a formatted array of valid event
|
|
||||||
* configuration.
|
|
||||||
*
|
|
||||||
* @param array $options Event array to convert
|
|
||||||
* @param array $events Event names to convert in the options array.
|
|
||||||
* @param mixed $handler Event handler to utilize
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
* @throws \InvalidArgumentException if the event config is invalid
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
public static function convertEventArray(
|
|
||||||
array $options,
|
|
||||||
array $events,
|
|
||||||
$handler
|
|
||||||
) {
|
|
||||||
foreach ($events as $name) {
|
|
||||||
if (!isset($options[$name])) {
|
|
||||||
$options[$name] = $handler;
|
|
||||||
} elseif (is_callable($options[$name])) {
|
|
||||||
$options[$name] = [['fn' => $options[$name]], $handler];
|
|
||||||
} elseif (is_array($options[$name])) {
|
|
||||||
$options[$name][] = $handler;
|
|
||||||
} else {
|
|
||||||
throw new \InvalidArgumentException('Invalid event format');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $options;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Event;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SubscriberInterface provides an array of events to an
|
|
||||||
* EventEmitterInterface when it is registered. The emitter then binds the
|
|
||||||
* listeners specified by the EventSubscriber.
|
|
||||||
*
|
|
||||||
* This interface is based on the SubscriberInterface of the Symfony.
|
|
||||||
* @link https://github.com/symfony/symfony/tree/master/src/Symfony/Component/EventDispatcher
|
|
||||||
*/
|
|
||||||
interface SubscriberInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns an array of event names this subscriber wants to listen to.
|
|
||||||
*
|
|
||||||
* The returned array keys MUST map to an event name. Each array value
|
|
||||||
* MUST be an array in which the first element is the name of a function
|
|
||||||
* on the EventSubscriber. The second element in the array is optional, and
|
|
||||||
* if specified, designates the event priority.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
*
|
|
||||||
* - ['eventName' => ['methodName']]
|
|
||||||
* - ['eventName' => ['methodName', $priority]]
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getEvents();
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Exception;
|
|
||||||
|
|
||||||
class AdapterException extends TransferException {}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception when an HTTP error occurs (4xx or 5xx error)
|
|
||||||
*/
|
|
||||||
class BadResponseException extends RequestException {}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception when a client error is encountered (4xx codes)
|
|
||||||
*/
|
|
||||||
class ClientException extends BadResponseException {}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Exception;
|
|
||||||
|
|
||||||
class CouldNotRewindStreamException extends RequestException {}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Exception;
|
|
||||||
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception when a client is unable to parse the response body as XML or JSON
|
|
||||||
*/
|
|
||||||
class ParseException extends TransferException
|
|
||||||
{
|
|
||||||
/** @var ResponseInterface */
|
|
||||||
private $response;
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
$message = '',
|
|
||||||
ResponseInterface $response = null,
|
|
||||||
\Exception $previous = null
|
|
||||||
) {
|
|
||||||
parent::__construct($message, 0, $previous);
|
|
||||||
$this->response = $response;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Get the associated response
|
|
||||||
*
|
|
||||||
* @return ResponseInterface|null
|
|
||||||
*/
|
|
||||||
public function getResponse()
|
|
||||||
{
|
|
||||||
return $this->response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,124 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Exception;
|
|
||||||
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTTP Request exception
|
|
||||||
*/
|
|
||||||
class RequestException extends TransferException
|
|
||||||
{
|
|
||||||
/** @var bool */
|
|
||||||
private $emittedErrorEvent = false;
|
|
||||||
|
|
||||||
/** @var RequestInterface */
|
|
||||||
private $request;
|
|
||||||
|
|
||||||
/** @var ResponseInterface */
|
|
||||||
private $response;
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
$message = '',
|
|
||||||
RequestInterface $request,
|
|
||||||
ResponseInterface $response = null,
|
|
||||||
\Exception $previous = null
|
|
||||||
) {
|
|
||||||
$code = $response ? $response->getStatusCode() : 0;
|
|
||||||
parent::__construct($message, $code, $previous);
|
|
||||||
$this->request = $request;
|
|
||||||
$this->response = $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method to create a new exception with a normalized error message
|
|
||||||
*
|
|
||||||
* @param RequestInterface $request Request
|
|
||||||
* @param ResponseInterface $response Response received
|
|
||||||
* @param \Exception $previous Previous exception
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public static function create(
|
|
||||||
RequestInterface $request,
|
|
||||||
ResponseInterface $response = null,
|
|
||||||
\Exception $previous = null
|
|
||||||
) {
|
|
||||||
if (!$response) {
|
|
||||||
return new self('Error completing request', $request, null, $previous);
|
|
||||||
}
|
|
||||||
|
|
||||||
$level = $response->getStatusCode()[0];
|
|
||||||
if ($level == '4') {
|
|
||||||
$label = 'Client error response';
|
|
||||||
$className = __NAMESPACE__ . '\\ClientException';
|
|
||||||
} elseif ($level == '5') {
|
|
||||||
$label = 'Server error response';
|
|
||||||
$className = __NAMESPACE__ . '\\ServerException';
|
|
||||||
} else {
|
|
||||||
$label = 'Unsuccessful response';
|
|
||||||
$className = __CLASS__;
|
|
||||||
}
|
|
||||||
|
|
||||||
$message = $label . ' [url] ' . $request->getUrl()
|
|
||||||
. ' [status code] ' . $response->getStatusCode()
|
|
||||||
. ' [reason phrase] ' . $response->getReasonPhrase();
|
|
||||||
|
|
||||||
return new $className($message, $request, $response, $previous);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the request that caused the exception
|
|
||||||
*
|
|
||||||
* @return RequestInterface
|
|
||||||
*/
|
|
||||||
public function getRequest()
|
|
||||||
{
|
|
||||||
return $this->request;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the associated response
|
|
||||||
*
|
|
||||||
* @return ResponseInterface|null
|
|
||||||
*/
|
|
||||||
public function getResponse()
|
|
||||||
{
|
|
||||||
return $this->response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a response was received
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function hasResponse()
|
|
||||||
{
|
|
||||||
return $this->response !== null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check or set if the exception was emitted in an error event.
|
|
||||||
*
|
|
||||||
* This value is used in the RequestEvents::emitBefore() method to check
|
|
||||||
* to see if an exception has already been emitted in an error event.
|
|
||||||
*
|
|
||||||
* @param bool|null Set to true to set the exception as having emitted an
|
|
||||||
* error. Leave null to retrieve the current setting.
|
|
||||||
*
|
|
||||||
* @return null|bool
|
|
||||||
* @throws \InvalidArgumentException if you attempt to set the value to false
|
|
||||||
*/
|
|
||||||
public function emittedError($value = null)
|
|
||||||
{
|
|
||||||
if ($value === null) {
|
|
||||||
return $this->emittedErrorEvent;
|
|
||||||
} elseif ($value === true) {
|
|
||||||
return $this->emittedErrorEvent = true;
|
|
||||||
} else {
|
|
||||||
throw new \InvalidArgumentException('You cannot set the emitted '
|
|
||||||
. 'error value to false.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception when a server error is encountered (5xx codes)
|
|
||||||
*/
|
|
||||||
class ServerException extends BadResponseException {}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Exception;
|
|
||||||
|
|
||||||
class TooManyRedirectsException extends RequestException {}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Exception;
|
|
||||||
|
|
||||||
class TransferException extends \RuntimeException {}
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trait implementing ToArrayInterface, \ArrayAccess, \Countable,
|
|
||||||
* \IteratorAggregate, and some path style methods.
|
|
||||||
*/
|
|
||||||
trait HasDataTrait
|
|
||||||
{
|
|
||||||
/** @var array */
|
|
||||||
protected $data = [];
|
|
||||||
|
|
||||||
public function getIterator()
|
|
||||||
{
|
|
||||||
return new \ArrayIterator($this->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function offsetGet($offset)
|
|
||||||
{
|
|
||||||
return isset($this->data[$offset]) ? $this->data[$offset] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function offsetSet($offset, $value)
|
|
||||||
{
|
|
||||||
$this->data[$offset] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function offsetExists($offset)
|
|
||||||
{
|
|
||||||
return isset($this->data[$offset]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function offsetUnset($offset)
|
|
||||||
{
|
|
||||||
unset($this->data[$offset]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toArray()
|
|
||||||
{
|
|
||||||
return $this->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function count()
|
|
||||||
{
|
|
||||||
return count($this->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a value from the collection using a path syntax to retrieve nested
|
|
||||||
* data.
|
|
||||||
*
|
|
||||||
* @param string $path Path to traverse and retrieve a value from
|
|
||||||
*
|
|
||||||
* @return mixed|null
|
|
||||||
*/
|
|
||||||
public function getPath($path)
|
|
||||||
{
|
|
||||||
return \GuzzleHttp\get_path($this->data, $path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a value into a nested array key. Keys will be created as needed to
|
|
||||||
* set the value.
|
|
||||||
*
|
|
||||||
* @param string $path Path to set
|
|
||||||
* @param mixed $value Value to set at the key
|
|
||||||
*
|
|
||||||
* @throws \RuntimeException when trying to setPath using a nested path
|
|
||||||
* that travels through a scalar value
|
|
||||||
*/
|
|
||||||
public function setPath($path, $value)
|
|
||||||
{
|
|
||||||
\GuzzleHttp\set_path($this->data, $path, $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,237 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Message;
|
|
||||||
|
|
||||||
use GuzzleHttp\Stream\StreamInterface;
|
|
||||||
|
|
||||||
abstract class AbstractMessage implements MessageInterface
|
|
||||||
{
|
|
||||||
/** @var array HTTP header collection */
|
|
||||||
private $headers = [];
|
|
||||||
|
|
||||||
/** @var array mapping a lowercase header name to its name over the wire */
|
|
||||||
private $headerNames = [];
|
|
||||||
|
|
||||||
/** @var StreamInterface Message body */
|
|
||||||
private $body;
|
|
||||||
|
|
||||||
/** @var string HTTP protocol version of the message */
|
|
||||||
private $protocolVersion = '1.1';
|
|
||||||
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
$result = $this->getStartLine();
|
|
||||||
foreach ($this->getHeaders() as $name => $values) {
|
|
||||||
$result .= "\r\n{$name}: " . implode(', ', $values);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result . "\r\n\r\n" . $this->body;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getProtocolVersion()
|
|
||||||
{
|
|
||||||
return $this->protocolVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBody()
|
|
||||||
{
|
|
||||||
return $this->body;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setBody(StreamInterface $body = null)
|
|
||||||
{
|
|
||||||
if ($body === null) {
|
|
||||||
// Setting a null body will remove the body of the request
|
|
||||||
$this->removeHeader('Content-Length')
|
|
||||||
->removeHeader('Transfer-Encoding');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->body = $body;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addHeader($header, $value)
|
|
||||||
{
|
|
||||||
static $valid = ['string' => true, 'integer' => true,
|
|
||||||
'double' => true, 'array' => true];
|
|
||||||
|
|
||||||
$type = gettype($value);
|
|
||||||
if (!isset($valid[$type])) {
|
|
||||||
throw new \InvalidArgumentException('Invalid header value');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($type == 'array') {
|
|
||||||
$current = array_merge($this->getHeader($header, true), $value);
|
|
||||||
} else {
|
|
||||||
$current = $this->getHeader($header, true);
|
|
||||||
$current[] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->setHeader($header, $current);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addHeaders(array $headers)
|
|
||||||
{
|
|
||||||
foreach ($headers as $name => $header) {
|
|
||||||
$this->addHeader($name, $header);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHeader($header, $asArray = false)
|
|
||||||
{
|
|
||||||
$name = strtolower($header);
|
|
||||||
|
|
||||||
if (!isset($this->headers[$name])) {
|
|
||||||
return $asArray ? [] : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $asArray
|
|
||||||
? $this->headers[$name]
|
|
||||||
: implode(', ', $this->headers[$name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHeaders()
|
|
||||||
{
|
|
||||||
$headers = [];
|
|
||||||
foreach ($this->headers as $name => $values) {
|
|
||||||
$headers[$this->headerNames[$name]] = $values;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setHeader($header, $value)
|
|
||||||
{
|
|
||||||
$header = trim($header);
|
|
||||||
$name = strtolower($header);
|
|
||||||
$this->headerNames[$name] = $header;
|
|
||||||
|
|
||||||
switch (gettype($value)) {
|
|
||||||
case 'string':
|
|
||||||
$this->headers[$name] = [trim($value)];
|
|
||||||
break;
|
|
||||||
case 'integer':
|
|
||||||
case 'double':
|
|
||||||
$this->headers[$name] = [(string) $value];
|
|
||||||
break;
|
|
||||||
case 'array':
|
|
||||||
foreach ($value as &$v) {
|
|
||||||
$v = trim($v);
|
|
||||||
}
|
|
||||||
$this->headers[$name] = $value;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new \InvalidArgumentException('Invalid header value '
|
|
||||||
. 'provided: ' . var_export($value, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setHeaders(array $headers)
|
|
||||||
{
|
|
||||||
$this->headers = $this->headerNames = [];
|
|
||||||
foreach ($headers as $key => $value) {
|
|
||||||
$this->setHeader($key, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hasHeader($header)
|
|
||||||
{
|
|
||||||
return isset($this->headers[strtolower($header)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function removeHeader($header)
|
|
||||||
{
|
|
||||||
$name = strtolower($header);
|
|
||||||
unset($this->headers[$name], $this->headerNames[$name]);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse an array of header values containing ";" separated data into an
|
|
||||||
* array of associative arrays representing the header key value pair
|
|
||||||
* data of the header. When a parameter does not contain a value, but just
|
|
||||||
* contains a key, this function will inject a key with a '' string value.
|
|
||||||
*
|
|
||||||
* @param MessageInterface $message That contains the header
|
|
||||||
* @param string $header Header to retrieve from the message
|
|
||||||
*
|
|
||||||
* @return array Returns the parsed header values.
|
|
||||||
*/
|
|
||||||
public static function parseHeader(MessageInterface $message, $header)
|
|
||||||
{
|
|
||||||
static $trimmed = "\"' \n\t\r";
|
|
||||||
$params = $matches = [];
|
|
||||||
|
|
||||||
foreach (self::normalizeHeader($message, $header) as $val) {
|
|
||||||
$part = [];
|
|
||||||
foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
|
|
||||||
if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
|
|
||||||
$m = $matches[0];
|
|
||||||
if (isset($m[1])) {
|
|
||||||
$part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
|
|
||||||
} else {
|
|
||||||
$part[] = trim($m[0], $trimmed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($part) {
|
|
||||||
$params[] = $part;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $params;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an array of header values that may contain comma separated
|
|
||||||
* headers into an array of headers with no comma separated values.
|
|
||||||
*
|
|
||||||
* @param MessageInterface $message That contains the header
|
|
||||||
* @param string $header Header to retrieve from the message
|
|
||||||
*
|
|
||||||
* @return array Returns the normalized header field values.
|
|
||||||
*/
|
|
||||||
public static function normalizeHeader(MessageInterface $message, $header)
|
|
||||||
{
|
|
||||||
$h = $message->getHeader($header, true);
|
|
||||||
for ($i = 0, $total = count($h); $i < $total; $i++) {
|
|
||||||
if (strpos($h[$i], ',') === false) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $h[$i]) as $v) {
|
|
||||||
$h[] = trim($v);
|
|
||||||
}
|
|
||||||
unset($h[$i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $h;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the start line of a message.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
abstract protected function getStartLine();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accepts and modifies the options provided to the message in the
|
|
||||||
* constructor.
|
|
||||||
*
|
|
||||||
* Can be overridden in subclasses as necessary.
|
|
||||||
*
|
|
||||||
* @param array $options Options array passed by reference.
|
|
||||||
*/
|
|
||||||
protected function handleOptions(array &$options)
|
|
||||||
{
|
|
||||||
if (isset($options['protocol_version'])) {
|
|
||||||
$this->protocolVersion = $options['protocol_version'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,345 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Message;
|
|
||||||
|
|
||||||
use GuzzleHttp\Event\ListenerAttacherTrait;
|
|
||||||
use GuzzleHttp\Post\PostFileInterface;
|
|
||||||
use GuzzleHttp\Subscriber\Cookie;
|
|
||||||
use GuzzleHttp\Cookie\CookieJar;
|
|
||||||
use GuzzleHttp\Cookie\CookieJarInterface;
|
|
||||||
use GuzzleHttp\Subscriber\HttpError;
|
|
||||||
use GuzzleHttp\Post\PostBody;
|
|
||||||
use GuzzleHttp\Post\PostFile;
|
|
||||||
use GuzzleHttp\Subscriber\Redirect;
|
|
||||||
use GuzzleHttp\Stream;
|
|
||||||
use GuzzleHttp\Query;
|
|
||||||
use GuzzleHttp\Url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default HTTP request factory used to create Request and Response objects.
|
|
||||||
*/
|
|
||||||
class MessageFactory implements MessageFactoryInterface
|
|
||||||
{
|
|
||||||
use ListenerAttacherTrait;
|
|
||||||
|
|
||||||
/** @var HttpError */
|
|
||||||
private $errorPlugin;
|
|
||||||
|
|
||||||
/** @var Redirect */
|
|
||||||
private $redirectPlugin;
|
|
||||||
|
|
||||||
/** @var array */
|
|
||||||
protected static $classMethods = [];
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->errorPlugin = new HttpError();
|
|
||||||
$this->redirectPlugin = new Redirect();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createResponse(
|
|
||||||
$statusCode,
|
|
||||||
array $headers = [],
|
|
||||||
$body = null,
|
|
||||||
array $options = []
|
|
||||||
) {
|
|
||||||
if (null !== $body) {
|
|
||||||
$body = Stream\create($body);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Response($statusCode, $headers, $body, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createRequest($method, $url, array $options = [])
|
|
||||||
{
|
|
||||||
// Handle the request protocol version option that needs to be
|
|
||||||
// specified in the request constructor.
|
|
||||||
if (isset($options['version'])) {
|
|
||||||
$options['config']['protocol_version'] = $options['version'];
|
|
||||||
unset($options['version']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$request = new Request($method, $url, [], null,
|
|
||||||
isset($options['config']) ? $options['config'] : []);
|
|
||||||
|
|
||||||
unset($options['config']);
|
|
||||||
|
|
||||||
// Use a POST body by default
|
|
||||||
if ($method == 'POST' &&
|
|
||||||
!isset($options['body']) &&
|
|
||||||
!isset($options['json'])
|
|
||||||
) {
|
|
||||||
$options['body'] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($options) {
|
|
||||||
$this->applyOptions($request, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $request;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a request or response object from an HTTP message string
|
|
||||||
*
|
|
||||||
* @param string $message Message to parse
|
|
||||||
*
|
|
||||||
* @return RequestInterface|ResponseInterface
|
|
||||||
* @throws \InvalidArgumentException if unable to parse a message
|
|
||||||
*/
|
|
||||||
public function fromMessage($message)
|
|
||||||
{
|
|
||||||
static $parser;
|
|
||||||
if (!$parser) {
|
|
||||||
$parser = new MessageParser();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse a response
|
|
||||||
if (strtoupper(substr($message, 0, 4)) == 'HTTP') {
|
|
||||||
$data = $parser->parseResponse($message);
|
|
||||||
return $this->createResponse(
|
|
||||||
$data['code'],
|
|
||||||
$data['headers'],
|
|
||||||
$data['body'] === '' ? null : $data['body'],
|
|
||||||
$data
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse a request
|
|
||||||
if (!($data = ($parser->parseRequest($message)))) {
|
|
||||||
throw new \InvalidArgumentException('Unable to parse request');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->createRequest(
|
|
||||||
$data['method'],
|
|
||||||
Url::buildUrl($data['request_url']),
|
|
||||||
[
|
|
||||||
'headers' => $data['headers'],
|
|
||||||
'body' => $data['body'] === '' ? null : $data['body'],
|
|
||||||
'config' => [
|
|
||||||
'protocol_version' => $data['protocol_version']
|
|
||||||
]
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply POST fields and files to a request to attempt to give an accurate
|
|
||||||
* representation.
|
|
||||||
*
|
|
||||||
* @param RequestInterface $request Request to update
|
|
||||||
* @param array $body Body to apply
|
|
||||||
*/
|
|
||||||
protected function addPostData(RequestInterface $request, array $body)
|
|
||||||
{
|
|
||||||
static $fields = ['string' => true, 'array' => true, 'NULL' => true,
|
|
||||||
'boolean' => true, 'double' => true, 'integer' => true];
|
|
||||||
|
|
||||||
$post = new PostBody();
|
|
||||||
foreach ($body as $key => $value) {
|
|
||||||
if (isset($fields[gettype($value)])) {
|
|
||||||
$post->setField($key, $value);
|
|
||||||
} elseif ($value instanceof PostFileInterface) {
|
|
||||||
$post->addFile($value);
|
|
||||||
} else {
|
|
||||||
$post->addFile(new PostFile($key, $value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$request->setBody($post);
|
|
||||||
$post->applyRequestHeaders($request);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function applyOptions(
|
|
||||||
RequestInterface $request,
|
|
||||||
array $options = []
|
|
||||||
) {
|
|
||||||
// Values specified in the config map are passed to request options
|
|
||||||
static $configMap = ['connect_timeout' => 1, 'timeout' => 1,
|
|
||||||
'verify' => 1, 'ssl_key' => 1, 'cert' => 1, 'proxy' => 1,
|
|
||||||
'debug' => 1, 'save_to' => 1, 'stream' => 1, 'expect' => 1];
|
|
||||||
|
|
||||||
// Take the class of the instance, not the parent
|
|
||||||
$selfClass = get_class($this);
|
|
||||||
|
|
||||||
// Check if we already took it's class methods and had them saved
|
|
||||||
if (!isset(self::$classMethods[$selfClass])) {
|
|
||||||
self::$classMethods[$selfClass] = array_flip(get_class_methods($this));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Take class methods of this particular instance
|
|
||||||
$methods = self::$classMethods[$selfClass];
|
|
||||||
|
|
||||||
// Iterate over each key value pair and attempt to apply a config using
|
|
||||||
// double dispatch.
|
|
||||||
$config = $request->getConfig();
|
|
||||||
foreach ($options as $key => $value) {
|
|
||||||
$method = "add_{$key}";
|
|
||||||
if (isset($methods[$method])) {
|
|
||||||
$this->{$method}($request, $value);
|
|
||||||
} elseif (isset($configMap[$key])) {
|
|
||||||
$config[$key] = $value;
|
|
||||||
} else {
|
|
||||||
throw new \InvalidArgumentException("No method is configured "
|
|
||||||
. "to handle the {$key} config key");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_body(RequestInterface $request, $value)
|
|
||||||
{
|
|
||||||
if ($value !== null) {
|
|
||||||
if (is_array($value)) {
|
|
||||||
$this->addPostData($request, $value);
|
|
||||||
} else {
|
|
||||||
$request->setBody(Stream\create($value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_allow_redirects(RequestInterface $request, $value)
|
|
||||||
{
|
|
||||||
static $defaultRedirect = [
|
|
||||||
'max' => 5,
|
|
||||||
'strict' => false,
|
|
||||||
'referer' => false
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($value === false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($value === true) {
|
|
||||||
$value = $defaultRedirect;
|
|
||||||
} elseif (!isset($value['max'])) {
|
|
||||||
throw new \InvalidArgumentException('allow_redirects must be '
|
|
||||||
. 'true, false, or an array that contains the \'max\' key');
|
|
||||||
} else {
|
|
||||||
// Merge the default settings with the provided settings
|
|
||||||
$value += $defaultRedirect;
|
|
||||||
}
|
|
||||||
|
|
||||||
$request->getConfig()['redirect'] = $value;
|
|
||||||
$request->getEmitter()->attach($this->redirectPlugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_exceptions(RequestInterface $request, $value)
|
|
||||||
{
|
|
||||||
if ($value === true) {
|
|
||||||
$request->getEmitter()->attach($this->errorPlugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_auth(RequestInterface $request, $value)
|
|
||||||
{
|
|
||||||
if (!$value) {
|
|
||||||
return;
|
|
||||||
} elseif (is_array($value)) {
|
|
||||||
$authType = isset($value[2]) ? strtolower($value[2]) : 'basic';
|
|
||||||
} else {
|
|
||||||
$authType = strtolower($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
$request->getConfig()->set('auth', $value);
|
|
||||||
|
|
||||||
if ($authType == 'basic') {
|
|
||||||
$request->setHeader(
|
|
||||||
'Authorization',
|
|
||||||
'Basic ' . base64_encode("$value[0]:$value[1]")
|
|
||||||
);
|
|
||||||
} elseif ($authType == 'digest') {
|
|
||||||
// Currently only implemented by the cURL adapter.
|
|
||||||
// @todo: Need an event listener solution that does not rely on cURL
|
|
||||||
$config = $request->getConfig();
|
|
||||||
$config->setPath('curl/' . CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
|
|
||||||
$config->setPath('curl/' . CURLOPT_USERPWD, "$value[0]:$value[1]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_query(RequestInterface $request, $value)
|
|
||||||
{
|
|
||||||
if ($value instanceof Query) {
|
|
||||||
$original = $request->getQuery();
|
|
||||||
// Do not overwrite existing query string variables by overwriting
|
|
||||||
// the object with the query string data passed in the URL
|
|
||||||
$request->setQuery($value->overwriteWith($original->toArray()));
|
|
||||||
} elseif (is_array($value)) {
|
|
||||||
// Do not overwrite existing query string variables
|
|
||||||
$query = $request->getQuery();
|
|
||||||
foreach ($value as $k => $v) {
|
|
||||||
if (!isset($query[$k])) {
|
|
||||||
$query[$k] = $v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new \InvalidArgumentException('query value must be an array '
|
|
||||||
. 'or Query object');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_headers(RequestInterface $request, $value)
|
|
||||||
{
|
|
||||||
if (!is_array($value)) {
|
|
||||||
throw new \InvalidArgumentException('header value must be an array');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not overwrite existing headers
|
|
||||||
foreach ($value as $k => $v) {
|
|
||||||
if (!$request->hasHeader($k)) {
|
|
||||||
$request->setHeader($k, $v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_cookies(RequestInterface $request, $value)
|
|
||||||
{
|
|
||||||
if ($value === true) {
|
|
||||||
static $cookie = null;
|
|
||||||
if (!$cookie) {
|
|
||||||
$cookie = new Cookie();
|
|
||||||
}
|
|
||||||
$request->getEmitter()->attach($cookie);
|
|
||||||
} elseif (is_array($value)) {
|
|
||||||
$request->getEmitter()->attach(
|
|
||||||
new Cookie(CookieJar::fromArray($value, $request->getHost()))
|
|
||||||
);
|
|
||||||
} elseif ($value instanceof CookieJarInterface) {
|
|
||||||
$request->getEmitter()->attach(new Cookie($value));
|
|
||||||
} elseif ($value !== false) {
|
|
||||||
throw new \InvalidArgumentException('cookies must be an array, '
|
|
||||||
. 'true, or a CookieJarInterface object');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_events(RequestInterface $request, $value)
|
|
||||||
{
|
|
||||||
if (!is_array($value)) {
|
|
||||||
throw new \InvalidArgumentException('events value must be an array');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->attachListeners($request, $this->prepareListeners($value,
|
|
||||||
['before', 'complete', 'error', 'headers']
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_subscribers(RequestInterface $request, $value)
|
|
||||||
{
|
|
||||||
if (!is_array($value)) {
|
|
||||||
throw new \InvalidArgumentException('subscribers must be an array');
|
|
||||||
}
|
|
||||||
|
|
||||||
$emitter = $request->getEmitter();
|
|
||||||
foreach ($value as $subscribers) {
|
|
||||||
$emitter->attach($subscribers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function add_json(RequestInterface $request, $value)
|
|
||||||
{
|
|
||||||
if (!$request->hasHeader('Content-Type')) {
|
|
||||||
$request->setHeader('Content-Type', 'application/json');
|
|
||||||
}
|
|
||||||
|
|
||||||
$request->setBody(Stream\create(json_encode($value)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Message;
|
|
||||||
|
|
||||||
use GuzzleHttp\Url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request and response factory
|
|
||||||
*/
|
|
||||||
interface MessageFactoryInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Creates a response
|
|
||||||
*
|
|
||||||
* @param string $statusCode HTTP status code
|
|
||||||
* @param array $headers Response headers
|
|
||||||
* @param mixed $body Response body
|
|
||||||
* @param array $options Response options
|
|
||||||
* - protocol_version: HTTP protocol version
|
|
||||||
* - header_factory: Factory used to create headers
|
|
||||||
* - And any other options used by a concrete message implementation
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function createResponse(
|
|
||||||
$statusCode,
|
|
||||||
array $headers = [],
|
|
||||||
$body = null,
|
|
||||||
array $options = []
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new request based on the HTTP method.
|
|
||||||
*
|
|
||||||
* This method accepts an associative array of request options. Below is a
|
|
||||||
* brief description of each parameter. See
|
|
||||||
* http://docs.guzzlephp.org/clients.html#request-options for a much more
|
|
||||||
* in-depth description of each parameter.
|
|
||||||
*
|
|
||||||
* - headers: Associative array of headers to add to the request
|
|
||||||
* - body: string|resource|array|StreamInterface request body to send
|
|
||||||
* - json: mixed Uploads JSON encoded data using an application/json Content-Type header.
|
|
||||||
* - query: Associative array of query string values to add to the request
|
|
||||||
* - auth: array|string HTTP auth settings (user, pass[, type="basic"])
|
|
||||||
* - version: The HTTP protocol version to use with the request
|
|
||||||
* - cookies: true|false|CookieJarInterface To enable or disable cookies
|
|
||||||
* - allow_redirects: true|false|array Controls HTTP redirects
|
|
||||||
* - save_to: string|resource|StreamInterface Where the response is saved
|
|
||||||
* - events: Associative array of event names to callables or arrays
|
|
||||||
* - subscribers: Array of event subscribers to add to the request
|
|
||||||
* - exceptions: Specifies whether or not exceptions are thrown for HTTP protocol errors
|
|
||||||
* - timeout: Timeout of the request in seconds. Use 0 to wait indefinitely
|
|
||||||
* - connect_timeout: Number of seconds to wait while trying to connect. (0 to wait indefinitely)
|
|
||||||
* - verify: SSL validation. True/False or the path to a PEM file
|
|
||||||
* - cert: Path a SSL cert or array of (path, pwd)
|
|
||||||
* - ssl_key: Path to a private SSL key or array of (path, pwd)
|
|
||||||
* - proxy: Specify an HTTP proxy or hash of protocols to proxies
|
|
||||||
* - debug: Set to true or a resource to view adapter specific debug info
|
|
||||||
* - stream: Set to true to stream a response body rather than download it all up front
|
|
||||||
* - expect: true/false/integer Controls the "Expect: 100-Continue" header
|
|
||||||
* - config: Associative array of request config collection options
|
|
||||||
*
|
|
||||||
* @param string $method HTTP method (GET, POST, PUT, etc.)
|
|
||||||
* @param string|Url $url HTTP URL to connect to
|
|
||||||
* @param array $options Array of options to apply to the request
|
|
||||||
*
|
|
||||||
* @return RequestInterface
|
|
||||||
* @link http://docs.guzzlephp.org/clients.html#request-options
|
|
||||||
*/
|
|
||||||
public function createRequest($method, $url, array $options = []);
|
|
||||||
}
|
|
||||||
|
|
@ -1,148 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Message;
|
|
||||||
|
|
||||||
use GuzzleHttp\Stream\StreamInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request and response message interface
|
|
||||||
*/
|
|
||||||
interface MessageInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get a string representation of the message
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the HTTP protocol version of the message
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getProtocolVersion();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the body of the message.
|
|
||||||
*
|
|
||||||
* The body MUST be a StreamInterface object. Setting the body to null MUST
|
|
||||||
* remove the existing body.
|
|
||||||
*
|
|
||||||
* @param StreamInterface|null $body Body.
|
|
||||||
*
|
|
||||||
* @return self Returns the message.
|
|
||||||
*/
|
|
||||||
public function setBody(StreamInterface $body = null);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the body of the message
|
|
||||||
*
|
|
||||||
* @return StreamInterface|null
|
|
||||||
*/
|
|
||||||
public function getBody();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets all message headers.
|
|
||||||
*
|
|
||||||
* The keys represent the header name as it will be sent over the wire, and
|
|
||||||
* each value is an array of strings associated with the header.
|
|
||||||
*
|
|
||||||
* // Represent the headers as a string
|
|
||||||
* foreach ($message->getHeaders() as $name => $values) {
|
|
||||||
* echo $name . ": " . implode(", ", $values);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @return array Returns an associative array of the message's headers.
|
|
||||||
*/
|
|
||||||
public function getHeaders();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve a header by the given case-insensitive name.
|
|
||||||
*
|
|
||||||
* By default, this method returns all of the header values of the given
|
|
||||||
* case-insensitive header name as a string concatenated together using
|
|
||||||
* a comma. Because some header should not be concatenated together using a
|
|
||||||
* comma, this method provides a Boolean argument that can be used to
|
|
||||||
* retrieve the associated header values as an array of strings.
|
|
||||||
*
|
|
||||||
* @param string $header Case-insensitive header name.
|
|
||||||
* @param bool $asArray Set to true to retrieve the header value as an
|
|
||||||
* array of strings.
|
|
||||||
*
|
|
||||||
* @return array|string
|
|
||||||
*/
|
|
||||||
public function getHeader($header, $asArray = false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a header exists by the given case-insensitive name.
|
|
||||||
*
|
|
||||||
* @param string $header Case-insensitive header name.
|
|
||||||
*
|
|
||||||
* @return bool Returns true if any header names match the given header
|
|
||||||
* name using a case-insensitive string comparison. Returns false if
|
|
||||||
* no matching header name is found in the message.
|
|
||||||
*/
|
|
||||||
public function hasHeader($header);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a specific header by case-insensitive name.
|
|
||||||
*
|
|
||||||
* @param string $header Case-insensitive header name.
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function removeHeader($header);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Appends a header value to any existing values associated with the
|
|
||||||
* given header name.
|
|
||||||
*
|
|
||||||
* @param string $header Header name to add
|
|
||||||
* @param string $value Value of the header
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function addHeader($header, $value);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Merges in an associative array of headers.
|
|
||||||
*
|
|
||||||
* Each array key MUST be a string representing the case-insensitive name
|
|
||||||
* of a header. Each value MUST be either a string or an array of strings.
|
|
||||||
* For each value, the value is appended to any existing header of the same
|
|
||||||
* name, or, if a header does not already exist by the given name, then the
|
|
||||||
* header is added.
|
|
||||||
*
|
|
||||||
* @param array $headers Associative array of headers to add to the message
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function addHeaders(array $headers);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a header, replacing any existing values of any headers with the
|
|
||||||
* same case-insensitive name.
|
|
||||||
*
|
|
||||||
* The header values MUST be a string or an array of strings.
|
|
||||||
*
|
|
||||||
* @param string $header Header name
|
|
||||||
* @param string|array $value Header value(s)
|
|
||||||
*
|
|
||||||
* @return self Returns the message.
|
|
||||||
*/
|
|
||||||
public function setHeader($header, $value);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets headers, replacing any headers that have already been set on the
|
|
||||||
* message.
|
|
||||||
*
|
|
||||||
* The array keys MUST be a string. The array values must be either a
|
|
||||||
* string or an array of strings.
|
|
||||||
*
|
|
||||||
* @param array $headers Headers to set.
|
|
||||||
*
|
|
||||||
* @return self Returns the message.
|
|
||||||
*/
|
|
||||||
public function setHeaders(array $headers);
|
|
||||||
}
|
|
||||||
|
|
@ -1,172 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Message;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request and response parser used by Guzzle
|
|
||||||
*/
|
|
||||||
class MessageParser
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Parse an HTTP request message into an associative array of parts.
|
|
||||||
*
|
|
||||||
* @param string $message HTTP request to parse
|
|
||||||
*
|
|
||||||
* @return array|bool Returns false if the message is invalid
|
|
||||||
*/
|
|
||||||
public function parseRequest($message)
|
|
||||||
{
|
|
||||||
if (!($parts = $this->parseMessage($message))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the protocol and protocol version
|
|
||||||
if (isset($parts['start_line'][2])) {
|
|
||||||
$startParts = explode('/', $parts['start_line'][2]);
|
|
||||||
$protocol = strtoupper($startParts[0]);
|
|
||||||
$version = isset($startParts[1]) ? $startParts[1] : '1.1';
|
|
||||||
} else {
|
|
||||||
$protocol = 'HTTP';
|
|
||||||
$version = '1.1';
|
|
||||||
}
|
|
||||||
|
|
||||||
$parsed = [
|
|
||||||
'method' => strtoupper($parts['start_line'][0]),
|
|
||||||
'protocol' => $protocol,
|
|
||||||
'protocol_version' => $version,
|
|
||||||
'headers' => $parts['headers'],
|
|
||||||
'body' => $parts['body']
|
|
||||||
];
|
|
||||||
|
|
||||||
$parsed['request_url'] = $this->getUrlPartsFromMessage(
|
|
||||||
(isset($parts['start_line'][1]) ? $parts['start_line'][1] : ''), $parsed);
|
|
||||||
|
|
||||||
return $parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse an HTTP response message into an associative array of parts.
|
|
||||||
*
|
|
||||||
* @param string $message HTTP response to parse
|
|
||||||
*
|
|
||||||
* @return array|bool Returns false if the message is invalid
|
|
||||||
*/
|
|
||||||
public function parseResponse($message)
|
|
||||||
{
|
|
||||||
if (!($parts = $this->parseMessage($message))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
list($protocol, $version) = explode('/', trim($parts['start_line'][0]));
|
|
||||||
|
|
||||||
return [
|
|
||||||
'protocol' => $protocol,
|
|
||||||
'protocol_version' => $version,
|
|
||||||
'code' => $parts['start_line'][1],
|
|
||||||
'reason_phrase' => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '',
|
|
||||||
'headers' => $parts['headers'],
|
|
||||||
'body' => $parts['body']
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse a message into parts
|
|
||||||
*
|
|
||||||
* @param string $message Message to parse
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
private function parseMessage($message)
|
|
||||||
{
|
|
||||||
if (!$message) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$startLine = null;
|
|
||||||
$headers = [];
|
|
||||||
$body = '';
|
|
||||||
|
|
||||||
// Iterate over each line in the message, accounting for line endings
|
|
||||||
$lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
|
|
||||||
for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) {
|
|
||||||
|
|
||||||
$line = $lines[$i];
|
|
||||||
|
|
||||||
// If two line breaks were encountered, then this is the end of body
|
|
||||||
if (empty($line)) {
|
|
||||||
if ($i < $totalLines - 1) {
|
|
||||||
$body = implode('', array_slice($lines, $i + 2));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse message headers
|
|
||||||
if (!$startLine) {
|
|
||||||
$startLine = explode(' ', $line, 3);
|
|
||||||
} elseif (strpos($line, ':')) {
|
|
||||||
$parts = explode(':', $line, 2);
|
|
||||||
$key = trim($parts[0]);
|
|
||||||
$value = isset($parts[1]) ? trim($parts[1]) : '';
|
|
||||||
if (!isset($headers[$key])) {
|
|
||||||
$headers[$key] = $value;
|
|
||||||
} elseif (!is_array($headers[$key])) {
|
|
||||||
$headers[$key] = [$headers[$key], $value];
|
|
||||||
} else {
|
|
||||||
$headers[$key][] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'start_line' => $startLine,
|
|
||||||
'headers' => $headers,
|
|
||||||
'body' => $body
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create URL parts from HTTP message parts
|
|
||||||
*
|
|
||||||
* @param string $requestUrl Associated URL
|
|
||||||
* @param array $parts HTTP message parts
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function getUrlPartsFromMessage($requestUrl, array $parts)
|
|
||||||
{
|
|
||||||
// Parse the URL information from the message
|
|
||||||
$urlParts = ['path' => $requestUrl, 'scheme' => 'http'];
|
|
||||||
|
|
||||||
// Check for the Host header
|
|
||||||
if (isset($parts['headers']['Host'])) {
|
|
||||||
$urlParts['host'] = $parts['headers']['Host'];
|
|
||||||
} elseif (isset($parts['headers']['host'])) {
|
|
||||||
$urlParts['host'] = $parts['headers']['host'];
|
|
||||||
} else {
|
|
||||||
$urlParts['host'] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false === strpos($urlParts['host'], ':')) {
|
|
||||||
$urlParts['port'] = '';
|
|
||||||
} else {
|
|
||||||
$hostParts = explode(':', $urlParts['host']);
|
|
||||||
$urlParts['host'] = trim($hostParts[0]);
|
|
||||||
$urlParts['port'] = (int) trim($hostParts[1]);
|
|
||||||
if ($urlParts['port'] == 443) {
|
|
||||||
$urlParts['scheme'] = 'https';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if a query is present
|
|
||||||
$path = $urlParts['path'];
|
|
||||||
$qpos = strpos($path, '?');
|
|
||||||
if ($qpos) {
|
|
||||||
$urlParts['query'] = substr($path, $qpos + 1);
|
|
||||||
$urlParts['path'] = substr($path, 0, $qpos);
|
|
||||||
} else {
|
|
||||||
$urlParts['query'] = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $urlParts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,216 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Message;
|
|
||||||
|
|
||||||
use GuzzleHttp\Event\HasEmitterTrait;
|
|
||||||
use GuzzleHttp\Collection;
|
|
||||||
use GuzzleHttp\Subscriber\Prepare;
|
|
||||||
use GuzzleHttp\Url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTTP request class to send requests
|
|
||||||
*/
|
|
||||||
class Request extends AbstractMessage implements RequestInterface
|
|
||||||
{
|
|
||||||
use HasEmitterTrait;
|
|
||||||
|
|
||||||
/** @var Url HTTP Url */
|
|
||||||
private $url;
|
|
||||||
|
|
||||||
/** @var string HTTP method */
|
|
||||||
private $method;
|
|
||||||
|
|
||||||
/** @var Collection Transfer options */
|
|
||||||
private $transferOptions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $method HTTP method
|
|
||||||
* @param string|Url $url HTTP URL to connect to. The URI scheme,
|
|
||||||
* host header, and URI are parsed from the full URL. If query string
|
|
||||||
* parameters are present they will be parsed as well.
|
|
||||||
* @param array|Collection $headers HTTP headers
|
|
||||||
* @param mixed $body Body to send with the request
|
|
||||||
* @param array $options Array of options to use with the request
|
|
||||||
* - emitter: Event emitter to use with the request
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
$method,
|
|
||||||
$url,
|
|
||||||
$headers = [],
|
|
||||||
$body = null,
|
|
||||||
array $options = []
|
|
||||||
) {
|
|
||||||
$this->setUrl($url);
|
|
||||||
$this->method = strtoupper($method);
|
|
||||||
$this->handleOptions($options);
|
|
||||||
$this->transferOptions = new Collection($options);
|
|
||||||
$this->addPrepareEvent();
|
|
||||||
|
|
||||||
if ($body !== null) {
|
|
||||||
$this->setBody($body);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($headers) {
|
|
||||||
foreach ($headers as $key => $value) {
|
|
||||||
$this->setHeader($key, $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __clone()
|
|
||||||
{
|
|
||||||
if ($this->emitter) {
|
|
||||||
$this->emitter = clone $this->emitter;
|
|
||||||
}
|
|
||||||
$this->transferOptions = clone $this->transferOptions;
|
|
||||||
$this->url = clone $this->url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setUrl($url)
|
|
||||||
{
|
|
||||||
$this->url = $url instanceof Url ? $url : Url::fromString($url);
|
|
||||||
$this->updateHostHeaderFromUrl();
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUrl()
|
|
||||||
{
|
|
||||||
return (string) $this->url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setQuery($query)
|
|
||||||
{
|
|
||||||
$this->url->setQuery($query);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getQuery()
|
|
||||||
{
|
|
||||||
return $this->url->getQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setMethod($method)
|
|
||||||
{
|
|
||||||
$this->method = strtoupper($method);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMethod()
|
|
||||||
{
|
|
||||||
return $this->method;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getScheme()
|
|
||||||
{
|
|
||||||
return $this->url->getScheme();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setScheme($scheme)
|
|
||||||
{
|
|
||||||
$this->url->setScheme($scheme);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPort()
|
|
||||||
{
|
|
||||||
return $this->url->getPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setPort($port)
|
|
||||||
{
|
|
||||||
$this->url->setPort($port);
|
|
||||||
$this->updateHostHeaderFromUrl();
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHost()
|
|
||||||
{
|
|
||||||
return $this->url->getHost();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setHost($host)
|
|
||||||
{
|
|
||||||
$this->url->setHost($host);
|
|
||||||
$this->updateHostHeaderFromUrl();
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPath()
|
|
||||||
{
|
|
||||||
return '/' . ltrim($this->url->getPath(), '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setPath($path)
|
|
||||||
{
|
|
||||||
$this->url->setPath($path);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getResource()
|
|
||||||
{
|
|
||||||
$resource = $this->getPath();
|
|
||||||
if ($query = (string) $this->url->getQuery()) {
|
|
||||||
$resource .= '?' . $query;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getConfig()
|
|
||||||
{
|
|
||||||
return $this->transferOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function handleOptions(array &$options)
|
|
||||||
{
|
|
||||||
parent::handleOptions($options);
|
|
||||||
// Use a custom emitter if one is specified, and remove it from
|
|
||||||
// options that are exposed through getConfig()
|
|
||||||
if (isset($options['emitter'])) {
|
|
||||||
$this->emitter = $options['emitter'];
|
|
||||||
unset($options['emitter']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getStartLine()
|
|
||||||
{
|
|
||||||
return trim($this->method . ' ' . $this->getResource())
|
|
||||||
. ' HTTP/' . $this->getProtocolVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a subscriber that ensures a request's body is prepared before
|
|
||||||
* sending.
|
|
||||||
*/
|
|
||||||
private function addPrepareEvent()
|
|
||||||
{
|
|
||||||
static $subscriber;
|
|
||||||
if (!$subscriber) {
|
|
||||||
$subscriber = new Prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->getEmitter()->attach($subscriber);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function updateHostHeaderFromUrl()
|
|
||||||
{
|
|
||||||
$port = $this->url->getPort();
|
|
||||||
$scheme = $this->url->getScheme();
|
|
||||||
if ($host = $this->url->getHost()) {
|
|
||||||
if (($port == 80 && $scheme == 'http') ||
|
|
||||||
($port == 443 && $scheme == 'https')
|
|
||||||
) {
|
|
||||||
$this->setHeader('Host', $host);
|
|
||||||
} else {
|
|
||||||
$this->setHeader('Host', "{$host}:{$port}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,150 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Message;
|
|
||||||
|
|
||||||
use GuzzleHttp\Event\HasEmitterInterface;
|
|
||||||
use GuzzleHttp\Query;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generic HTTP request interface
|
|
||||||
*/
|
|
||||||
interface RequestInterface extends MessageInterface, HasEmitterInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Sets the request URL.
|
|
||||||
*
|
|
||||||
* The URL MUST be a string, or an object that implements the
|
|
||||||
* `__toString()` method.
|
|
||||||
*
|
|
||||||
* @param string $url Request URL.
|
|
||||||
*
|
|
||||||
* @return self Reference to the request.
|
|
||||||
* @throws \InvalidArgumentException If the URL is invalid.
|
|
||||||
*/
|
|
||||||
public function setUrl($url);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the request URL as a string.
|
|
||||||
*
|
|
||||||
* @return string Returns the URL as a string.
|
|
||||||
*/
|
|
||||||
public function getUrl();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the resource part of the the request, including the path, query
|
|
||||||
* string, and fragment.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getResource();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the collection of key value pairs that will be used as the query
|
|
||||||
* string in the request.
|
|
||||||
*
|
|
||||||
* @return Query
|
|
||||||
*/
|
|
||||||
public function getQuery();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the query string used by the request
|
|
||||||
*
|
|
||||||
* @param array|Query $query Query to set
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setQuery($query);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the HTTP method of the request.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getMethod();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the HTTP method of the request.
|
|
||||||
*
|
|
||||||
* @param string $method HTTP method
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setMethod($method);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the URI scheme of the request (http, https, etc.).
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getScheme();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the URI scheme of the request (http, https, etc.).
|
|
||||||
*
|
|
||||||
* @param string $scheme Scheme to set
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setScheme($scheme);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the port scheme of the request (e.g., 80, 443, etc.).
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getPort();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the port of the request.
|
|
||||||
*
|
|
||||||
* Setting a port modifies the Host header of a request as necessary.
|
|
||||||
*
|
|
||||||
* @param int $port Port to set
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setPort($port);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the host of the request.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getHost();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the host of the request including an optional port.
|
|
||||||
*
|
|
||||||
* Including a port in the host argument will explicitly change the port of
|
|
||||||
* the request. If no port is found, the default port of the current
|
|
||||||
* request scheme will be utilized.
|
|
||||||
*
|
|
||||||
* @param string $host Host to set (e.g. www.yahoo.com, www.yahoo.com:80)
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setHost($host);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the path of the request (e.g. '/', '/index.html').
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getPath();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the path of the request (e.g. '/', '/index.html').
|
|
||||||
*
|
|
||||||
* @param string|array $path Path to set or array of segments to implode
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setPath($path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the request's configuration options.
|
|
||||||
*
|
|
||||||
* @return \GuzzleHttp\Collection
|
|
||||||
*/
|
|
||||||
public function getConfig();
|
|
||||||
}
|
|
||||||
|
|
@ -1,202 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Message;
|
|
||||||
|
|
||||||
use GuzzleHttp\Exception\ParseException;
|
|
||||||
use GuzzleHttp\Stream\StreamInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Guzzle HTTP response object
|
|
||||||
*/
|
|
||||||
class Response extends AbstractMessage implements ResponseInterface
|
|
||||||
{
|
|
||||||
/** @var array Mapping of status codes to reason phrases */
|
|
||||||
private static $statusTexts = array(
|
|
||||||
100 => 'Continue',
|
|
||||||
101 => 'Switching Protocols',
|
|
||||||
102 => 'Processing',
|
|
||||||
200 => 'OK',
|
|
||||||
201 => 'Created',
|
|
||||||
202 => 'Accepted',
|
|
||||||
203 => 'Non-Authoritative Information',
|
|
||||||
204 => 'No Content',
|
|
||||||
205 => 'Reset Content',
|
|
||||||
206 => 'Partial Content',
|
|
||||||
207 => 'Multi-Status',
|
|
||||||
208 => 'Already Reported',
|
|
||||||
226 => 'IM Used',
|
|
||||||
300 => 'Multiple Choices',
|
|
||||||
301 => 'Moved Permanently',
|
|
||||||
302 => 'Found',
|
|
||||||
303 => 'See Other',
|
|
||||||
304 => 'Not Modified',
|
|
||||||
305 => 'Use Proxy',
|
|
||||||
307 => 'Temporary Redirect',
|
|
||||||
308 => 'Permanent Redirect',
|
|
||||||
400 => 'Bad Request',
|
|
||||||
401 => 'Unauthorized',
|
|
||||||
402 => 'Payment Required',
|
|
||||||
403 => 'Forbidden',
|
|
||||||
404 => 'Not Found',
|
|
||||||
405 => 'Method Not Allowed',
|
|
||||||
406 => 'Not Acceptable',
|
|
||||||
407 => 'Proxy Authentication Required',
|
|
||||||
408 => 'Request Timeout',
|
|
||||||
409 => 'Conflict',
|
|
||||||
410 => 'Gone',
|
|
||||||
411 => 'Length Required',
|
|
||||||
412 => 'Precondition Failed',
|
|
||||||
413 => 'Request Entity Too Large',
|
|
||||||
414 => 'Request-URI Too Long',
|
|
||||||
415 => 'Unsupported Media Type',
|
|
||||||
416 => 'Requested Range Not Satisfiable',
|
|
||||||
417 => 'Expectation Failed',
|
|
||||||
422 => 'Unprocessable Entity',
|
|
||||||
423 => 'Locked',
|
|
||||||
424 => 'Failed Dependency',
|
|
||||||
425 => 'Reserved for WebDAV advanced collections expired proposal',
|
|
||||||
426 => 'Upgrade required',
|
|
||||||
428 => 'Precondition Required',
|
|
||||||
429 => 'Too Many Requests',
|
|
||||||
431 => 'Request Header Fields Too Large',
|
|
||||||
500 => 'Internal Server Error',
|
|
||||||
501 => 'Not Implemented',
|
|
||||||
502 => 'Bad Gateway',
|
|
||||||
503 => 'Service Unavailable',
|
|
||||||
504 => 'Gateway Timeout',
|
|
||||||
505 => 'HTTP Version Not Supported',
|
|
||||||
506 => 'Variant Also Negotiates (Experimental)',
|
|
||||||
507 => 'Insufficient Storage',
|
|
||||||
508 => 'Loop Detected',
|
|
||||||
510 => 'Not Extended',
|
|
||||||
511 => 'Network Authentication Required',
|
|
||||||
);
|
|
||||||
|
|
||||||
/** @var string The reason phrase of the response (human readable code) */
|
|
||||||
private $reasonPhrase;
|
|
||||||
|
|
||||||
/** @var string The status code of the response */
|
|
||||||
private $statusCode;
|
|
||||||
|
|
||||||
/** @var string The effective URL that returned this response */
|
|
||||||
private $effectiveUrl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $statusCode The response status code (e.g. 200)
|
|
||||||
* @param array $headers The response headers
|
|
||||||
* @param StreamInterface $body The body of the response
|
|
||||||
* @param array $options Response message options
|
|
||||||
* - reason_phrase: Set a custom reason phrase
|
|
||||||
* - protocol_version: Set a custom protocol version
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
$statusCode,
|
|
||||||
array $headers = [],
|
|
||||||
StreamInterface $body = null,
|
|
||||||
array $options = []
|
|
||||||
) {
|
|
||||||
$this->statusCode = (string) $statusCode;
|
|
||||||
$this->handleOptions($options);
|
|
||||||
|
|
||||||
// Assume a reason phrase if one was not applied as an option
|
|
||||||
if (!$this->reasonPhrase &&
|
|
||||||
isset(self::$statusTexts[$this->statusCode])
|
|
||||||
) {
|
|
||||||
$this->reasonPhrase = self::$statusTexts[$this->statusCode];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($headers) {
|
|
||||||
$this->setHeaders($headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($body) {
|
|
||||||
$this->setBody($body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getStatusCode()
|
|
||||||
{
|
|
||||||
return $this->statusCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getReasonPhrase()
|
|
||||||
{
|
|
||||||
return $this->reasonPhrase;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function json(array $config = [])
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
return \GuzzleHttp\json_decode(
|
|
||||||
(string) $this->getBody(),
|
|
||||||
isset($config['object']) ? !$config['object'] : true,
|
|
||||||
512,
|
|
||||||
isset($config['big_int_strings']) ? JSON_BIGINT_AS_STRING : 0
|
|
||||||
);
|
|
||||||
} catch (\InvalidArgumentException $e) {
|
|
||||||
throw new ParseException(
|
|
||||||
$e->getMessage(),
|
|
||||||
$this
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function xml(array $config = [])
|
|
||||||
{
|
|
||||||
$disableEntities = libxml_disable_entity_loader(true);
|
|
||||||
$internalErrors = libxml_use_internal_errors(true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Allow XML to be retrieved even if there is no response body
|
|
||||||
$xml = new \SimpleXMLElement(
|
|
||||||
(string) $this->getBody() ?: '<root />',
|
|
||||||
LIBXML_NONET,
|
|
||||||
isset($config['ns']) ? $config['ns'] : '',
|
|
||||||
isset($config['ns_is_prefix']) ? $config['ns_is_prefix'] : false
|
|
||||||
);
|
|
||||||
libxml_disable_entity_loader($disableEntities);
|
|
||||||
libxml_use_internal_errors($internalErrors);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
libxml_disable_entity_loader($disableEntities);
|
|
||||||
libxml_use_internal_errors($internalErrors);
|
|
||||||
throw new ParseException(
|
|
||||||
'Unable to parse response body into XML: ' . $e->getMessage(),
|
|
||||||
$this
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $xml;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEffectiveUrl()
|
|
||||||
{
|
|
||||||
return $this->effectiveUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setEffectiveUrl($url)
|
|
||||||
{
|
|
||||||
$this->effectiveUrl = $url;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accepts and modifies the options provided to the response in the
|
|
||||||
* constructor.
|
|
||||||
*
|
|
||||||
* @param array $options Options array passed by reference.
|
|
||||||
*/
|
|
||||||
protected function handleOptions(array &$options = [])
|
|
||||||
{
|
|
||||||
parent::handleOptions($options);
|
|
||||||
if (isset($options['reason_phrase'])) {
|
|
||||||
$this->reasonPhrase = $options['reason_phrase'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getStartLine()
|
|
||||||
{
|
|
||||||
return 'HTTP/' . $this->getProtocolVersion()
|
|
||||||
. " {$this->statusCode} {$this->reasonPhrase}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Message;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents an HTTP response message.
|
|
||||||
*/
|
|
||||||
interface ResponseInterface extends MessageInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get the response status code (e.g. "200", "404", etc.)
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getStatusCode();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the response reason phrase- a human readable version of the numeric
|
|
||||||
* status code
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getReasonPhrase();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the effective URL that resulted in this response (e.g. the last
|
|
||||||
* redirect URL).
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getEffectiveUrl();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the effective URL that resulted in this response (e.g. the last
|
|
||||||
* redirect URL).
|
|
||||||
*
|
|
||||||
* @param string $url Effective URL
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setEffectiveUrl($url);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the JSON response body and return the JSON decoded data.
|
|
||||||
*
|
|
||||||
* @param array $config Associative array of configuration settings used
|
|
||||||
* to control how the JSON data is parsed. Concrete implementations MAY
|
|
||||||
* add further configuration settings as needed, but they MUST implement
|
|
||||||
* functionality for the following options:
|
|
||||||
*
|
|
||||||
* - object: Set to true to parse JSON objects as PHP objects rather
|
|
||||||
* than associative arrays. Defaults to false.
|
|
||||||
* - big_int_strings: When set to true, large integers are converted to
|
|
||||||
* strings rather than floats. Defaults to false.
|
|
||||||
*
|
|
||||||
* Implementations are free to add further configuration settings as
|
|
||||||
* needed.
|
|
||||||
*
|
|
||||||
* @return mixed Returns the JSON decoded data based on the provided
|
|
||||||
* parse settings.
|
|
||||||
* @throws \RuntimeException if the response body is not in JSON format
|
|
||||||
*/
|
|
||||||
public function json(array $config = []);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the XML response body and return a \SimpleXMLElement.
|
|
||||||
*
|
|
||||||
* In order to prevent XXE attacks, this method disables loading external
|
|
||||||
* entities. If you rely on external entities, then you must parse the
|
|
||||||
* XML response manually by accessing the response body directly.
|
|
||||||
*
|
|
||||||
* @param array $config Associative array of configuration settings used
|
|
||||||
* to control how the XML is parsed. Concrete implementations MAY add
|
|
||||||
* further configuration settings as needed, but they MUST implement
|
|
||||||
* functionality for the following options:
|
|
||||||
*
|
|
||||||
* - ns: Set to a string to represent the namespace prefix or URI
|
|
||||||
* - ns_is_prefix: Set to true to specify that the NS is a prefix rather
|
|
||||||
* than a URI (defaults to false).
|
|
||||||
*
|
|
||||||
* @return \SimpleXMLElement
|
|
||||||
* @throws \RuntimeException if the response body is not in XML format
|
|
||||||
* @link http://websec.io/2012/08/27/Preventing-XXE-in-PHP.html
|
|
||||||
*/
|
|
||||||
public function xml(array $config = []);
|
|
||||||
}
|
|
||||||
|
|
@ -1,964 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides mappings of file extensions to mimetypes
|
|
||||||
* @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
|
|
||||||
*/
|
|
||||||
class Mimetypes
|
|
||||||
{
|
|
||||||
/** @var self */
|
|
||||||
protected static $instance;
|
|
||||||
|
|
||||||
/** @var array Mapping of extension to mimetype */
|
|
||||||
protected $mimetypes = array(
|
|
||||||
'3dml' => 'text/vnd.in3d.3dml',
|
|
||||||
'3g2' => 'video/3gpp2',
|
|
||||||
'3gp' => 'video/3gpp',
|
|
||||||
'7z' => 'application/x-7z-compressed',
|
|
||||||
'aab' => 'application/x-authorware-bin',
|
|
||||||
'aac' => 'audio/x-aac',
|
|
||||||
'aam' => 'application/x-authorware-map',
|
|
||||||
'aas' => 'application/x-authorware-seg',
|
|
||||||
'abw' => 'application/x-abiword',
|
|
||||||
'ac' => 'application/pkix-attr-cert',
|
|
||||||
'acc' => 'application/vnd.americandynamics.acc',
|
|
||||||
'ace' => 'application/x-ace-compressed',
|
|
||||||
'acu' => 'application/vnd.acucobol',
|
|
||||||
'acutc' => 'application/vnd.acucorp',
|
|
||||||
'adp' => 'audio/adpcm',
|
|
||||||
'aep' => 'application/vnd.audiograph',
|
|
||||||
'afm' => 'application/x-font-type1',
|
|
||||||
'afp' => 'application/vnd.ibm.modcap',
|
|
||||||
'ahead' => 'application/vnd.ahead.space',
|
|
||||||
'ai' => 'application/postscript',
|
|
||||||
'aif' => 'audio/x-aiff',
|
|
||||||
'aifc' => 'audio/x-aiff',
|
|
||||||
'aiff' => 'audio/x-aiff',
|
|
||||||
'air' => 'application/vnd.adobe.air-application-installer-package+zip',
|
|
||||||
'ait' => 'application/vnd.dvb.ait',
|
|
||||||
'ami' => 'application/vnd.amiga.ami',
|
|
||||||
'apk' => 'application/vnd.android.package-archive',
|
|
||||||
'application' => 'application/x-ms-application',
|
|
||||||
'apr' => 'application/vnd.lotus-approach',
|
|
||||||
'asa' => 'text/plain',
|
|
||||||
'asax' => 'application/octet-stream',
|
|
||||||
'asc' => 'application/pgp-signature',
|
|
||||||
'ascx' => 'text/plain',
|
|
||||||
'asf' => 'video/x-ms-asf',
|
|
||||||
'ashx' => 'text/plain',
|
|
||||||
'asm' => 'text/x-asm',
|
|
||||||
'asmx' => 'text/plain',
|
|
||||||
'aso' => 'application/vnd.accpac.simply.aso',
|
|
||||||
'asp' => 'text/plain',
|
|
||||||
'aspx' => 'text/plain',
|
|
||||||
'asx' => 'video/x-ms-asf',
|
|
||||||
'atc' => 'application/vnd.acucorp',
|
|
||||||
'atom' => 'application/atom+xml',
|
|
||||||
'atomcat' => 'application/atomcat+xml',
|
|
||||||
'atomsvc' => 'application/atomsvc+xml',
|
|
||||||
'atx' => 'application/vnd.antix.game-component',
|
|
||||||
'au' => 'audio/basic',
|
|
||||||
'avi' => 'video/x-msvideo',
|
|
||||||
'aw' => 'application/applixware',
|
|
||||||
'axd' => 'text/plain',
|
|
||||||
'azf' => 'application/vnd.airzip.filesecure.azf',
|
|
||||||
'azs' => 'application/vnd.airzip.filesecure.azs',
|
|
||||||
'azw' => 'application/vnd.amazon.ebook',
|
|
||||||
'bat' => 'application/x-msdownload',
|
|
||||||
'bcpio' => 'application/x-bcpio',
|
|
||||||
'bdf' => 'application/x-font-bdf',
|
|
||||||
'bdm' => 'application/vnd.syncml.dm+wbxml',
|
|
||||||
'bed' => 'application/vnd.realvnc.bed',
|
|
||||||
'bh2' => 'application/vnd.fujitsu.oasysprs',
|
|
||||||
'bin' => 'application/octet-stream',
|
|
||||||
'bmi' => 'application/vnd.bmi',
|
|
||||||
'bmp' => 'image/bmp',
|
|
||||||
'book' => 'application/vnd.framemaker',
|
|
||||||
'box' => 'application/vnd.previewsystems.box',
|
|
||||||
'boz' => 'application/x-bzip2',
|
|
||||||
'bpk' => 'application/octet-stream',
|
|
||||||
'btif' => 'image/prs.btif',
|
|
||||||
'bz' => 'application/x-bzip',
|
|
||||||
'bz2' => 'application/x-bzip2',
|
|
||||||
'c' => 'text/x-c',
|
|
||||||
'c11amc' => 'application/vnd.cluetrust.cartomobile-config',
|
|
||||||
'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg',
|
|
||||||
'c4d' => 'application/vnd.clonk.c4group',
|
|
||||||
'c4f' => 'application/vnd.clonk.c4group',
|
|
||||||
'c4g' => 'application/vnd.clonk.c4group',
|
|
||||||
'c4p' => 'application/vnd.clonk.c4group',
|
|
||||||
'c4u' => 'application/vnd.clonk.c4group',
|
|
||||||
'cab' => 'application/vnd.ms-cab-compressed',
|
|
||||||
'car' => 'application/vnd.curl.car',
|
|
||||||
'cat' => 'application/vnd.ms-pki.seccat',
|
|
||||||
'cc' => 'text/x-c',
|
|
||||||
'cct' => 'application/x-director',
|
|
||||||
'ccxml' => 'application/ccxml+xml',
|
|
||||||
'cdbcmsg' => 'application/vnd.contact.cmsg',
|
|
||||||
'cdf' => 'application/x-netcdf',
|
|
||||||
'cdkey' => 'application/vnd.mediastation.cdkey',
|
|
||||||
'cdmia' => 'application/cdmi-capability',
|
|
||||||
'cdmic' => 'application/cdmi-container',
|
|
||||||
'cdmid' => 'application/cdmi-domain',
|
|
||||||
'cdmio' => 'application/cdmi-object',
|
|
||||||
'cdmiq' => 'application/cdmi-queue',
|
|
||||||
'cdx' => 'chemical/x-cdx',
|
|
||||||
'cdxml' => 'application/vnd.chemdraw+xml',
|
|
||||||
'cdy' => 'application/vnd.cinderella',
|
|
||||||
'cer' => 'application/pkix-cert',
|
|
||||||
'cfc' => 'application/x-coldfusion',
|
|
||||||
'cfm' => 'application/x-coldfusion',
|
|
||||||
'cgm' => 'image/cgm',
|
|
||||||
'chat' => 'application/x-chat',
|
|
||||||
'chm' => 'application/vnd.ms-htmlhelp',
|
|
||||||
'chrt' => 'application/vnd.kde.kchart',
|
|
||||||
'cif' => 'chemical/x-cif',
|
|
||||||
'cii' => 'application/vnd.anser-web-certificate-issue-initiation',
|
|
||||||
'cil' => 'application/vnd.ms-artgalry',
|
|
||||||
'cla' => 'application/vnd.claymore',
|
|
||||||
'class' => 'application/java-vm',
|
|
||||||
'clkk' => 'application/vnd.crick.clicker.keyboard',
|
|
||||||
'clkp' => 'application/vnd.crick.clicker.palette',
|
|
||||||
'clkt' => 'application/vnd.crick.clicker.template',
|
|
||||||
'clkw' => 'application/vnd.crick.clicker.wordbank',
|
|
||||||
'clkx' => 'application/vnd.crick.clicker',
|
|
||||||
'clp' => 'application/x-msclip',
|
|
||||||
'cmc' => 'application/vnd.cosmocaller',
|
|
||||||
'cmdf' => 'chemical/x-cmdf',
|
|
||||||
'cml' => 'chemical/x-cml',
|
|
||||||
'cmp' => 'application/vnd.yellowriver-custom-menu',
|
|
||||||
'cmx' => 'image/x-cmx',
|
|
||||||
'cod' => 'application/vnd.rim.cod',
|
|
||||||
'com' => 'application/x-msdownload',
|
|
||||||
'conf' => 'text/plain',
|
|
||||||
'cpio' => 'application/x-cpio',
|
|
||||||
'cpp' => 'text/x-c',
|
|
||||||
'cpt' => 'application/mac-compactpro',
|
|
||||||
'crd' => 'application/x-mscardfile',
|
|
||||||
'crl' => 'application/pkix-crl',
|
|
||||||
'crt' => 'application/x-x509-ca-cert',
|
|
||||||
'cryptonote' => 'application/vnd.rig.cryptonote',
|
|
||||||
'cs' => 'text/plain',
|
|
||||||
'csh' => 'application/x-csh',
|
|
||||||
'csml' => 'chemical/x-csml',
|
|
||||||
'csp' => 'application/vnd.commonspace',
|
|
||||||
'css' => 'text/css',
|
|
||||||
'cst' => 'application/x-director',
|
|
||||||
'csv' => 'text/csv',
|
|
||||||
'cu' => 'application/cu-seeme',
|
|
||||||
'curl' => 'text/vnd.curl',
|
|
||||||
'cww' => 'application/prs.cww',
|
|
||||||
'cxt' => 'application/x-director',
|
|
||||||
'cxx' => 'text/x-c',
|
|
||||||
'dae' => 'model/vnd.collada+xml',
|
|
||||||
'daf' => 'application/vnd.mobius.daf',
|
|
||||||
'dataless' => 'application/vnd.fdsn.seed',
|
|
||||||
'davmount' => 'application/davmount+xml',
|
|
||||||
'dcr' => 'application/x-director',
|
|
||||||
'dcurl' => 'text/vnd.curl.dcurl',
|
|
||||||
'dd2' => 'application/vnd.oma.dd2+xml',
|
|
||||||
'ddd' => 'application/vnd.fujixerox.ddd',
|
|
||||||
'deb' => 'application/x-debian-package',
|
|
||||||
'def' => 'text/plain',
|
|
||||||
'deploy' => 'application/octet-stream',
|
|
||||||
'der' => 'application/x-x509-ca-cert',
|
|
||||||
'dfac' => 'application/vnd.dreamfactory',
|
|
||||||
'dic' => 'text/x-c',
|
|
||||||
'dir' => 'application/x-director',
|
|
||||||
'dis' => 'application/vnd.mobius.dis',
|
|
||||||
'dist' => 'application/octet-stream',
|
|
||||||
'distz' => 'application/octet-stream',
|
|
||||||
'djv' => 'image/vnd.djvu',
|
|
||||||
'djvu' => 'image/vnd.djvu',
|
|
||||||
'dll' => 'application/x-msdownload',
|
|
||||||
'dmg' => 'application/octet-stream',
|
|
||||||
'dms' => 'application/octet-stream',
|
|
||||||
'dna' => 'application/vnd.dna',
|
|
||||||
'doc' => 'application/msword',
|
|
||||||
'docm' => 'application/vnd.ms-word.document.macroenabled.12',
|
|
||||||
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
||||||
'dot' => 'application/msword',
|
|
||||||
'dotm' => 'application/vnd.ms-word.template.macroenabled.12',
|
|
||||||
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
|
|
||||||
'dp' => 'application/vnd.osgi.dp',
|
|
||||||
'dpg' => 'application/vnd.dpgraph',
|
|
||||||
'dra' => 'audio/vnd.dra',
|
|
||||||
'dsc' => 'text/prs.lines.tag',
|
|
||||||
'dssc' => 'application/dssc+der',
|
|
||||||
'dtb' => 'application/x-dtbook+xml',
|
|
||||||
'dtd' => 'application/xml-dtd',
|
|
||||||
'dts' => 'audio/vnd.dts',
|
|
||||||
'dtshd' => 'audio/vnd.dts.hd',
|
|
||||||
'dump' => 'application/octet-stream',
|
|
||||||
'dvi' => 'application/x-dvi',
|
|
||||||
'dwf' => 'model/vnd.dwf',
|
|
||||||
'dwg' => 'image/vnd.dwg',
|
|
||||||
'dxf' => 'image/vnd.dxf',
|
|
||||||
'dxp' => 'application/vnd.spotfire.dxp',
|
|
||||||
'dxr' => 'application/x-director',
|
|
||||||
'ecelp4800' => 'audio/vnd.nuera.ecelp4800',
|
|
||||||
'ecelp7470' => 'audio/vnd.nuera.ecelp7470',
|
|
||||||
'ecelp9600' => 'audio/vnd.nuera.ecelp9600',
|
|
||||||
'ecma' => 'application/ecmascript',
|
|
||||||
'edm' => 'application/vnd.novadigm.edm',
|
|
||||||
'edx' => 'application/vnd.novadigm.edx',
|
|
||||||
'efif' => 'application/vnd.picsel',
|
|
||||||
'ei6' => 'application/vnd.pg.osasli',
|
|
||||||
'elc' => 'application/octet-stream',
|
|
||||||
'eml' => 'message/rfc822',
|
|
||||||
'emma' => 'application/emma+xml',
|
|
||||||
'eol' => 'audio/vnd.digital-winds',
|
|
||||||
'eot' => 'application/vnd.ms-fontobject',
|
|
||||||
'eps' => 'application/postscript',
|
|
||||||
'epub' => 'application/epub+zip',
|
|
||||||
'es3' => 'application/vnd.eszigno3+xml',
|
|
||||||
'esf' => 'application/vnd.epson.esf',
|
|
||||||
'et3' => 'application/vnd.eszigno3+xml',
|
|
||||||
'etx' => 'text/x-setext',
|
|
||||||
'exe' => 'application/x-msdownload',
|
|
||||||
'exi' => 'application/exi',
|
|
||||||
'ext' => 'application/vnd.novadigm.ext',
|
|
||||||
'ez' => 'application/andrew-inset',
|
|
||||||
'ez2' => 'application/vnd.ezpix-album',
|
|
||||||
'ez3' => 'application/vnd.ezpix-package',
|
|
||||||
'f' => 'text/x-fortran',
|
|
||||||
'f4v' => 'video/x-f4v',
|
|
||||||
'f77' => 'text/x-fortran',
|
|
||||||
'f90' => 'text/x-fortran',
|
|
||||||
'fbs' => 'image/vnd.fastbidsheet',
|
|
||||||
'fcs' => 'application/vnd.isac.fcs',
|
|
||||||
'fdf' => 'application/vnd.fdf',
|
|
||||||
'fe_launch' => 'application/vnd.denovo.fcselayout-link',
|
|
||||||
'fg5' => 'application/vnd.fujitsu.oasysgp',
|
|
||||||
'fgd' => 'application/x-director',
|
|
||||||
'fh' => 'image/x-freehand',
|
|
||||||
'fh4' => 'image/x-freehand',
|
|
||||||
'fh5' => 'image/x-freehand',
|
|
||||||
'fh7' => 'image/x-freehand',
|
|
||||||
'fhc' => 'image/x-freehand',
|
|
||||||
'fig' => 'application/x-xfig',
|
|
||||||
'fli' => 'video/x-fli',
|
|
||||||
'flo' => 'application/vnd.micrografx.flo',
|
|
||||||
'flv' => 'video/x-flv',
|
|
||||||
'flw' => 'application/vnd.kde.kivio',
|
|
||||||
'flx' => 'text/vnd.fmi.flexstor',
|
|
||||||
'fly' => 'text/vnd.fly',
|
|
||||||
'fm' => 'application/vnd.framemaker',
|
|
||||||
'fnc' => 'application/vnd.frogans.fnc',
|
|
||||||
'for' => 'text/x-fortran',
|
|
||||||
'fpx' => 'image/vnd.fpx',
|
|
||||||
'frame' => 'application/vnd.framemaker',
|
|
||||||
'fsc' => 'application/vnd.fsc.weblaunch',
|
|
||||||
'fst' => 'image/vnd.fst',
|
|
||||||
'ftc' => 'application/vnd.fluxtime.clip',
|
|
||||||
'fti' => 'application/vnd.anser-web-funds-transfer-initiation',
|
|
||||||
'fvt' => 'video/vnd.fvt',
|
|
||||||
'fxp' => 'application/vnd.adobe.fxp',
|
|
||||||
'fxpl' => 'application/vnd.adobe.fxp',
|
|
||||||
'fzs' => 'application/vnd.fuzzysheet',
|
|
||||||
'g2w' => 'application/vnd.geoplan',
|
|
||||||
'g3' => 'image/g3fax',
|
|
||||||
'g3w' => 'application/vnd.geospace',
|
|
||||||
'gac' => 'application/vnd.groove-account',
|
|
||||||
'gdl' => 'model/vnd.gdl',
|
|
||||||
'geo' => 'application/vnd.dynageo',
|
|
||||||
'gex' => 'application/vnd.geometry-explorer',
|
|
||||||
'ggb' => 'application/vnd.geogebra.file',
|
|
||||||
'ggt' => 'application/vnd.geogebra.tool',
|
|
||||||
'ghf' => 'application/vnd.groove-help',
|
|
||||||
'gif' => 'image/gif',
|
|
||||||
'gim' => 'application/vnd.groove-identity-message',
|
|
||||||
'gmx' => 'application/vnd.gmx',
|
|
||||||
'gnumeric' => 'application/x-gnumeric',
|
|
||||||
'gph' => 'application/vnd.flographit',
|
|
||||||
'gqf' => 'application/vnd.grafeq',
|
|
||||||
'gqs' => 'application/vnd.grafeq',
|
|
||||||
'gram' => 'application/srgs',
|
|
||||||
'gre' => 'application/vnd.geometry-explorer',
|
|
||||||
'grv' => 'application/vnd.groove-injector',
|
|
||||||
'grxml' => 'application/srgs+xml',
|
|
||||||
'gsf' => 'application/x-font-ghostscript',
|
|
||||||
'gtar' => 'application/x-gtar',
|
|
||||||
'gtm' => 'application/vnd.groove-tool-message',
|
|
||||||
'gtw' => 'model/vnd.gtw',
|
|
||||||
'gv' => 'text/vnd.graphviz',
|
|
||||||
'gxt' => 'application/vnd.geonext',
|
|
||||||
'h' => 'text/x-c',
|
|
||||||
'h261' => 'video/h261',
|
|
||||||
'h263' => 'video/h263',
|
|
||||||
'h264' => 'video/h264',
|
|
||||||
'hal' => 'application/vnd.hal+xml',
|
|
||||||
'hbci' => 'application/vnd.hbci',
|
|
||||||
'hdf' => 'application/x-hdf',
|
|
||||||
'hh' => 'text/x-c',
|
|
||||||
'hlp' => 'application/winhlp',
|
|
||||||
'hpgl' => 'application/vnd.hp-hpgl',
|
|
||||||
'hpid' => 'application/vnd.hp-hpid',
|
|
||||||
'hps' => 'application/vnd.hp-hps',
|
|
||||||
'hqx' => 'application/mac-binhex40',
|
|
||||||
'hta' => 'application/octet-stream',
|
|
||||||
'htc' => 'text/html',
|
|
||||||
'htke' => 'application/vnd.kenameaapp',
|
|
||||||
'htm' => 'text/html',
|
|
||||||
'html' => 'text/html',
|
|
||||||
'hvd' => 'application/vnd.yamaha.hv-dic',
|
|
||||||
'hvp' => 'application/vnd.yamaha.hv-voice',
|
|
||||||
'hvs' => 'application/vnd.yamaha.hv-script',
|
|
||||||
'i2g' => 'application/vnd.intergeo',
|
|
||||||
'icc' => 'application/vnd.iccprofile',
|
|
||||||
'ice' => 'x-conference/x-cooltalk',
|
|
||||||
'icm' => 'application/vnd.iccprofile',
|
|
||||||
'ico' => 'image/x-icon',
|
|
||||||
'ics' => 'text/calendar',
|
|
||||||
'ief' => 'image/ief',
|
|
||||||
'ifb' => 'text/calendar',
|
|
||||||
'ifm' => 'application/vnd.shana.informed.formdata',
|
|
||||||
'iges' => 'model/iges',
|
|
||||||
'igl' => 'application/vnd.igloader',
|
|
||||||
'igm' => 'application/vnd.insors.igm',
|
|
||||||
'igs' => 'model/iges',
|
|
||||||
'igx' => 'application/vnd.micrografx.igx',
|
|
||||||
'iif' => 'application/vnd.shana.informed.interchange',
|
|
||||||
'imp' => 'application/vnd.accpac.simply.imp',
|
|
||||||
'ims' => 'application/vnd.ms-ims',
|
|
||||||
'in' => 'text/plain',
|
|
||||||
'ini' => 'text/plain',
|
|
||||||
'ipfix' => 'application/ipfix',
|
|
||||||
'ipk' => 'application/vnd.shana.informed.package',
|
|
||||||
'irm' => 'application/vnd.ibm.rights-management',
|
|
||||||
'irp' => 'application/vnd.irepository.package+xml',
|
|
||||||
'iso' => 'application/octet-stream',
|
|
||||||
'itp' => 'application/vnd.shana.informed.formtemplate',
|
|
||||||
'ivp' => 'application/vnd.immervision-ivp',
|
|
||||||
'ivu' => 'application/vnd.immervision-ivu',
|
|
||||||
'jad' => 'text/vnd.sun.j2me.app-descriptor',
|
|
||||||
'jam' => 'application/vnd.jam',
|
|
||||||
'jar' => 'application/java-archive',
|
|
||||||
'java' => 'text/x-java-source',
|
|
||||||
'jisp' => 'application/vnd.jisp',
|
|
||||||
'jlt' => 'application/vnd.hp-jlyt',
|
|
||||||
'jnlp' => 'application/x-java-jnlp-file',
|
|
||||||
'joda' => 'application/vnd.joost.joda-archive',
|
|
||||||
'jpe' => 'image/jpeg',
|
|
||||||
'jpeg' => 'image/jpeg',
|
|
||||||
'jpg' => 'image/jpeg',
|
|
||||||
'jpgm' => 'video/jpm',
|
|
||||||
'jpgv' => 'video/jpeg',
|
|
||||||
'jpm' => 'video/jpm',
|
|
||||||
'js' => 'text/javascript',
|
|
||||||
'json' => 'application/json',
|
|
||||||
'kar' => 'audio/midi',
|
|
||||||
'karbon' => 'application/vnd.kde.karbon',
|
|
||||||
'kfo' => 'application/vnd.kde.kformula',
|
|
||||||
'kia' => 'application/vnd.kidspiration',
|
|
||||||
'kml' => 'application/vnd.google-earth.kml+xml',
|
|
||||||
'kmz' => 'application/vnd.google-earth.kmz',
|
|
||||||
'kne' => 'application/vnd.kinar',
|
|
||||||
'knp' => 'application/vnd.kinar',
|
|
||||||
'kon' => 'application/vnd.kde.kontour',
|
|
||||||
'kpr' => 'application/vnd.kde.kpresenter',
|
|
||||||
'kpt' => 'application/vnd.kde.kpresenter',
|
|
||||||
'ksp' => 'application/vnd.kde.kspread',
|
|
||||||
'ktr' => 'application/vnd.kahootz',
|
|
||||||
'ktx' => 'image/ktx',
|
|
||||||
'ktz' => 'application/vnd.kahootz',
|
|
||||||
'kwd' => 'application/vnd.kde.kword',
|
|
||||||
'kwt' => 'application/vnd.kde.kword',
|
|
||||||
'lasxml' => 'application/vnd.las.las+xml',
|
|
||||||
'latex' => 'application/x-latex',
|
|
||||||
'lbd' => 'application/vnd.llamagraphics.life-balance.desktop',
|
|
||||||
'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml',
|
|
||||||
'les' => 'application/vnd.hhe.lesson-player',
|
|
||||||
'lha' => 'application/octet-stream',
|
|
||||||
'link66' => 'application/vnd.route66.link66+xml',
|
|
||||||
'list' => 'text/plain',
|
|
||||||
'list3820' => 'application/vnd.ibm.modcap',
|
|
||||||
'listafp' => 'application/vnd.ibm.modcap',
|
|
||||||
'log' => 'text/plain',
|
|
||||||
'lostxml' => 'application/lost+xml',
|
|
||||||
'lrf' => 'application/octet-stream',
|
|
||||||
'lrm' => 'application/vnd.ms-lrm',
|
|
||||||
'ltf' => 'application/vnd.frogans.ltf',
|
|
||||||
'lvp' => 'audio/vnd.lucent.voice',
|
|
||||||
'lwp' => 'application/vnd.lotus-wordpro',
|
|
||||||
'lzh' => 'application/octet-stream',
|
|
||||||
'm13' => 'application/x-msmediaview',
|
|
||||||
'm14' => 'application/x-msmediaview',
|
|
||||||
'm1v' => 'video/mpeg',
|
|
||||||
'm21' => 'application/mp21',
|
|
||||||
'm2a' => 'audio/mpeg',
|
|
||||||
'm2v' => 'video/mpeg',
|
|
||||||
'm3a' => 'audio/mpeg',
|
|
||||||
'm3u' => 'audio/x-mpegurl',
|
|
||||||
'm3u8' => 'application/vnd.apple.mpegurl',
|
|
||||||
'm4a' => 'audio/mp4',
|
|
||||||
'm4u' => 'video/vnd.mpegurl',
|
|
||||||
'm4v' => 'video/mp4',
|
|
||||||
'ma' => 'application/mathematica',
|
|
||||||
'mads' => 'application/mads+xml',
|
|
||||||
'mag' => 'application/vnd.ecowin.chart',
|
|
||||||
'maker' => 'application/vnd.framemaker',
|
|
||||||
'man' => 'text/troff',
|
|
||||||
'mathml' => 'application/mathml+xml',
|
|
||||||
'mb' => 'application/mathematica',
|
|
||||||
'mbk' => 'application/vnd.mobius.mbk',
|
|
||||||
'mbox' => 'application/mbox',
|
|
||||||
'mc1' => 'application/vnd.medcalcdata',
|
|
||||||
'mcd' => 'application/vnd.mcd',
|
|
||||||
'mcurl' => 'text/vnd.curl.mcurl',
|
|
||||||
'mdb' => 'application/x-msaccess',
|
|
||||||
'mdi' => 'image/vnd.ms-modi',
|
|
||||||
'me' => 'text/troff',
|
|
||||||
'mesh' => 'model/mesh',
|
|
||||||
'meta4' => 'application/metalink4+xml',
|
|
||||||
'mets' => 'application/mets+xml',
|
|
||||||
'mfm' => 'application/vnd.mfmp',
|
|
||||||
'mgp' => 'application/vnd.osgeo.mapguide.package',
|
|
||||||
'mgz' => 'application/vnd.proteus.magazine',
|
|
||||||
'mid' => 'audio/midi',
|
|
||||||
'midi' => 'audio/midi',
|
|
||||||
'mif' => 'application/vnd.mif',
|
|
||||||
'mime' => 'message/rfc822',
|
|
||||||
'mj2' => 'video/mj2',
|
|
||||||
'mjp2' => 'video/mj2',
|
|
||||||
'mlp' => 'application/vnd.dolby.mlp',
|
|
||||||
'mmd' => 'application/vnd.chipnuts.karaoke-mmd',
|
|
||||||
'mmf' => 'application/vnd.smaf',
|
|
||||||
'mmr' => 'image/vnd.fujixerox.edmics-mmr',
|
|
||||||
'mny' => 'application/x-msmoney',
|
|
||||||
'mobi' => 'application/x-mobipocket-ebook',
|
|
||||||
'mods' => 'application/mods+xml',
|
|
||||||
'mov' => 'video/quicktime',
|
|
||||||
'movie' => 'video/x-sgi-movie',
|
|
||||||
'mp2' => 'audio/mpeg',
|
|
||||||
'mp21' => 'application/mp21',
|
|
||||||
'mp2a' => 'audio/mpeg',
|
|
||||||
'mp3' => 'audio/mpeg',
|
|
||||||
'mp4' => 'video/mp4',
|
|
||||||
'mp4a' => 'audio/mp4',
|
|
||||||
'mp4s' => 'application/mp4',
|
|
||||||
'mp4v' => 'video/mp4',
|
|
||||||
'mpc' => 'application/vnd.mophun.certificate',
|
|
||||||
'mpe' => 'video/mpeg',
|
|
||||||
'mpeg' => 'video/mpeg',
|
|
||||||
'mpg' => 'video/mpeg',
|
|
||||||
'mpg4' => 'video/mp4',
|
|
||||||
'mpga' => 'audio/mpeg',
|
|
||||||
'mpkg' => 'application/vnd.apple.installer+xml',
|
|
||||||
'mpm' => 'application/vnd.blueice.multipass',
|
|
||||||
'mpn' => 'application/vnd.mophun.application',
|
|
||||||
'mpp' => 'application/vnd.ms-project',
|
|
||||||
'mpt' => 'application/vnd.ms-project',
|
|
||||||
'mpy' => 'application/vnd.ibm.minipay',
|
|
||||||
'mqy' => 'application/vnd.mobius.mqy',
|
|
||||||
'mrc' => 'application/marc',
|
|
||||||
'mrcx' => 'application/marcxml+xml',
|
|
||||||
'ms' => 'text/troff',
|
|
||||||
'mscml' => 'application/mediaservercontrol+xml',
|
|
||||||
'mseed' => 'application/vnd.fdsn.mseed',
|
|
||||||
'mseq' => 'application/vnd.mseq',
|
|
||||||
'msf' => 'application/vnd.epson.msf',
|
|
||||||
'msh' => 'model/mesh',
|
|
||||||
'msi' => 'application/x-msdownload',
|
|
||||||
'msl' => 'application/vnd.mobius.msl',
|
|
||||||
'msty' => 'application/vnd.muvee.style',
|
|
||||||
'mts' => 'model/vnd.mts',
|
|
||||||
'mus' => 'application/vnd.musician',
|
|
||||||
'musicxml' => 'application/vnd.recordare.musicxml+xml',
|
|
||||||
'mvb' => 'application/x-msmediaview',
|
|
||||||
'mwf' => 'application/vnd.mfer',
|
|
||||||
'mxf' => 'application/mxf',
|
|
||||||
'mxl' => 'application/vnd.recordare.musicxml',
|
|
||||||
'mxml' => 'application/xv+xml',
|
|
||||||
'mxs' => 'application/vnd.triscape.mxs',
|
|
||||||
'mxu' => 'video/vnd.mpegurl',
|
|
||||||
'n-gage' => 'application/vnd.nokia.n-gage.symbian.install',
|
|
||||||
'n3' => 'text/n3',
|
|
||||||
'nb' => 'application/mathematica',
|
|
||||||
'nbp' => 'application/vnd.wolfram.player',
|
|
||||||
'nc' => 'application/x-netcdf',
|
|
||||||
'ncx' => 'application/x-dtbncx+xml',
|
|
||||||
'ngdat' => 'application/vnd.nokia.n-gage.data',
|
|
||||||
'nlu' => 'application/vnd.neurolanguage.nlu',
|
|
||||||
'nml' => 'application/vnd.enliven',
|
|
||||||
'nnd' => 'application/vnd.noblenet-directory',
|
|
||||||
'nns' => 'application/vnd.noblenet-sealer',
|
|
||||||
'nnw' => 'application/vnd.noblenet-web',
|
|
||||||
'npx' => 'image/vnd.net-fpx',
|
|
||||||
'nsf' => 'application/vnd.lotus-notes',
|
|
||||||
'oa2' => 'application/vnd.fujitsu.oasys2',
|
|
||||||
'oa3' => 'application/vnd.fujitsu.oasys3',
|
|
||||||
'oas' => 'application/vnd.fujitsu.oasys',
|
|
||||||
'obd' => 'application/x-msbinder',
|
|
||||||
'oda' => 'application/oda',
|
|
||||||
'odb' => 'application/vnd.oasis.opendocument.database',
|
|
||||||
'odc' => 'application/vnd.oasis.opendocument.chart',
|
|
||||||
'odf' => 'application/vnd.oasis.opendocument.formula',
|
|
||||||
'odft' => 'application/vnd.oasis.opendocument.formula-template',
|
|
||||||
'odg' => 'application/vnd.oasis.opendocument.graphics',
|
|
||||||
'odi' => 'application/vnd.oasis.opendocument.image',
|
|
||||||
'odm' => 'application/vnd.oasis.opendocument.text-master',
|
|
||||||
'odp' => 'application/vnd.oasis.opendocument.presentation',
|
|
||||||
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
|
|
||||||
'odt' => 'application/vnd.oasis.opendocument.text',
|
|
||||||
'oga' => 'audio/ogg',
|
|
||||||
'ogg' => 'audio/ogg',
|
|
||||||
'ogv' => 'video/ogg',
|
|
||||||
'ogx' => 'application/ogg',
|
|
||||||
'onepkg' => 'application/onenote',
|
|
||||||
'onetmp' => 'application/onenote',
|
|
||||||
'onetoc' => 'application/onenote',
|
|
||||||
'onetoc2' => 'application/onenote',
|
|
||||||
'opf' => 'application/oebps-package+xml',
|
|
||||||
'oprc' => 'application/vnd.palm',
|
|
||||||
'org' => 'application/vnd.lotus-organizer',
|
|
||||||
'osf' => 'application/vnd.yamaha.openscoreformat',
|
|
||||||
'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml',
|
|
||||||
'otc' => 'application/vnd.oasis.opendocument.chart-template',
|
|
||||||
'otf' => 'application/x-font-otf',
|
|
||||||
'otg' => 'application/vnd.oasis.opendocument.graphics-template',
|
|
||||||
'oth' => 'application/vnd.oasis.opendocument.text-web',
|
|
||||||
'oti' => 'application/vnd.oasis.opendocument.image-template',
|
|
||||||
'otp' => 'application/vnd.oasis.opendocument.presentation-template',
|
|
||||||
'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
|
|
||||||
'ott' => 'application/vnd.oasis.opendocument.text-template',
|
|
||||||
'oxt' => 'application/vnd.openofficeorg.extension',
|
|
||||||
'p' => 'text/x-pascal',
|
|
||||||
'p10' => 'application/pkcs10',
|
|
||||||
'p12' => 'application/x-pkcs12',
|
|
||||||
'p7b' => 'application/x-pkcs7-certificates',
|
|
||||||
'p7c' => 'application/pkcs7-mime',
|
|
||||||
'p7m' => 'application/pkcs7-mime',
|
|
||||||
'p7r' => 'application/x-pkcs7-certreqresp',
|
|
||||||
'p7s' => 'application/pkcs7-signature',
|
|
||||||
'p8' => 'application/pkcs8',
|
|
||||||
'pas' => 'text/x-pascal',
|
|
||||||
'paw' => 'application/vnd.pawaafile',
|
|
||||||
'pbd' => 'application/vnd.powerbuilder6',
|
|
||||||
'pbm' => 'image/x-portable-bitmap',
|
|
||||||
'pcf' => 'application/x-font-pcf',
|
|
||||||
'pcl' => 'application/vnd.hp-pcl',
|
|
||||||
'pclxl' => 'application/vnd.hp-pclxl',
|
|
||||||
'pct' => 'image/x-pict',
|
|
||||||
'pcurl' => 'application/vnd.curl.pcurl',
|
|
||||||
'pcx' => 'image/x-pcx',
|
|
||||||
'pdb' => 'application/vnd.palm',
|
|
||||||
'pdf' => 'application/pdf',
|
|
||||||
'pfa' => 'application/x-font-type1',
|
|
||||||
'pfb' => 'application/x-font-type1',
|
|
||||||
'pfm' => 'application/x-font-type1',
|
|
||||||
'pfr' => 'application/font-tdpfr',
|
|
||||||
'pfx' => 'application/x-pkcs12',
|
|
||||||
'pgm' => 'image/x-portable-graymap',
|
|
||||||
'pgn' => 'application/x-chess-pgn',
|
|
||||||
'pgp' => 'application/pgp-encrypted',
|
|
||||||
'php' => 'text/x-php',
|
|
||||||
'phps' => 'application/x-httpd-phps',
|
|
||||||
'pic' => 'image/x-pict',
|
|
||||||
'pkg' => 'application/octet-stream',
|
|
||||||
'pki' => 'application/pkixcmp',
|
|
||||||
'pkipath' => 'application/pkix-pkipath',
|
|
||||||
'plb' => 'application/vnd.3gpp.pic-bw-large',
|
|
||||||
'plc' => 'application/vnd.mobius.plc',
|
|
||||||
'plf' => 'application/vnd.pocketlearn',
|
|
||||||
'pls' => 'application/pls+xml',
|
|
||||||
'pml' => 'application/vnd.ctc-posml',
|
|
||||||
'png' => 'image/png',
|
|
||||||
'pnm' => 'image/x-portable-anymap',
|
|
||||||
'portpkg' => 'application/vnd.macports.portpkg',
|
|
||||||
'pot' => 'application/vnd.ms-powerpoint',
|
|
||||||
'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12',
|
|
||||||
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
|
|
||||||
'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12',
|
|
||||||
'ppd' => 'application/vnd.cups-ppd',
|
|
||||||
'ppm' => 'image/x-portable-pixmap',
|
|
||||||
'pps' => 'application/vnd.ms-powerpoint',
|
|
||||||
'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
|
|
||||||
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
|
|
||||||
'ppt' => 'application/vnd.ms-powerpoint',
|
|
||||||
'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12',
|
|
||||||
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
||||||
'pqa' => 'application/vnd.palm',
|
|
||||||
'prc' => 'application/x-mobipocket-ebook',
|
|
||||||
'pre' => 'application/vnd.lotus-freelance',
|
|
||||||
'prf' => 'application/pics-rules',
|
|
||||||
'ps' => 'application/postscript',
|
|
||||||
'psb' => 'application/vnd.3gpp.pic-bw-small',
|
|
||||||
'psd' => 'image/vnd.adobe.photoshop',
|
|
||||||
'psf' => 'application/x-font-linux-psf',
|
|
||||||
'pskcxml' => 'application/pskc+xml',
|
|
||||||
'ptid' => 'application/vnd.pvi.ptid1',
|
|
||||||
'pub' => 'application/x-mspublisher',
|
|
||||||
'pvb' => 'application/vnd.3gpp.pic-bw-var',
|
|
||||||
'pwn' => 'application/vnd.3m.post-it-notes',
|
|
||||||
'pya' => 'audio/vnd.ms-playready.media.pya',
|
|
||||||
'pyv' => 'video/vnd.ms-playready.media.pyv',
|
|
||||||
'qam' => 'application/vnd.epson.quickanime',
|
|
||||||
'qbo' => 'application/vnd.intu.qbo',
|
|
||||||
'qfx' => 'application/vnd.intu.qfx',
|
|
||||||
'qps' => 'application/vnd.publishare-delta-tree',
|
|
||||||
'qt' => 'video/quicktime',
|
|
||||||
'qwd' => 'application/vnd.quark.quarkxpress',
|
|
||||||
'qwt' => 'application/vnd.quark.quarkxpress',
|
|
||||||
'qxb' => 'application/vnd.quark.quarkxpress',
|
|
||||||
'qxd' => 'application/vnd.quark.quarkxpress',
|
|
||||||
'qxl' => 'application/vnd.quark.quarkxpress',
|
|
||||||
'qxt' => 'application/vnd.quark.quarkxpress',
|
|
||||||
'ra' => 'audio/x-pn-realaudio',
|
|
||||||
'ram' => 'audio/x-pn-realaudio',
|
|
||||||
'rar' => 'application/x-rar-compressed',
|
|
||||||
'ras' => 'image/x-cmu-raster',
|
|
||||||
'rb' => 'text/plain',
|
|
||||||
'rcprofile' => 'application/vnd.ipunplugged.rcprofile',
|
|
||||||
'rdf' => 'application/rdf+xml',
|
|
||||||
'rdz' => 'application/vnd.data-vision.rdz',
|
|
||||||
'rep' => 'application/vnd.businessobjects',
|
|
||||||
'res' => 'application/x-dtbresource+xml',
|
|
||||||
'resx' => 'text/xml',
|
|
||||||
'rgb' => 'image/x-rgb',
|
|
||||||
'rif' => 'application/reginfo+xml',
|
|
||||||
'rip' => 'audio/vnd.rip',
|
|
||||||
'rl' => 'application/resource-lists+xml',
|
|
||||||
'rlc' => 'image/vnd.fujixerox.edmics-rlc',
|
|
||||||
'rld' => 'application/resource-lists-diff+xml',
|
|
||||||
'rm' => 'application/vnd.rn-realmedia',
|
|
||||||
'rmi' => 'audio/midi',
|
|
||||||
'rmp' => 'audio/x-pn-realaudio-plugin',
|
|
||||||
'rms' => 'application/vnd.jcp.javame.midlet-rms',
|
|
||||||
'rnc' => 'application/relax-ng-compact-syntax',
|
|
||||||
'roff' => 'text/troff',
|
|
||||||
'rp9' => 'application/vnd.cloanto.rp9',
|
|
||||||
'rpss' => 'application/vnd.nokia.radio-presets',
|
|
||||||
'rpst' => 'application/vnd.nokia.radio-preset',
|
|
||||||
'rq' => 'application/sparql-query',
|
|
||||||
'rs' => 'application/rls-services+xml',
|
|
||||||
'rsd' => 'application/rsd+xml',
|
|
||||||
'rss' => 'application/rss+xml',
|
|
||||||
'rtf' => 'application/rtf',
|
|
||||||
'rtx' => 'text/richtext',
|
|
||||||
's' => 'text/x-asm',
|
|
||||||
'saf' => 'application/vnd.yamaha.smaf-audio',
|
|
||||||
'sbml' => 'application/sbml+xml',
|
|
||||||
'sc' => 'application/vnd.ibm.secure-container',
|
|
||||||
'scd' => 'application/x-msschedule',
|
|
||||||
'scm' => 'application/vnd.lotus-screencam',
|
|
||||||
'scq' => 'application/scvp-cv-request',
|
|
||||||
'scs' => 'application/scvp-cv-response',
|
|
||||||
'scurl' => 'text/vnd.curl.scurl',
|
|
||||||
'sda' => 'application/vnd.stardivision.draw',
|
|
||||||
'sdc' => 'application/vnd.stardivision.calc',
|
|
||||||
'sdd' => 'application/vnd.stardivision.impress',
|
|
||||||
'sdkd' => 'application/vnd.solent.sdkm+xml',
|
|
||||||
'sdkm' => 'application/vnd.solent.sdkm+xml',
|
|
||||||
'sdp' => 'application/sdp',
|
|
||||||
'sdw' => 'application/vnd.stardivision.writer',
|
|
||||||
'see' => 'application/vnd.seemail',
|
|
||||||
'seed' => 'application/vnd.fdsn.seed',
|
|
||||||
'sema' => 'application/vnd.sema',
|
|
||||||
'semd' => 'application/vnd.semd',
|
|
||||||
'semf' => 'application/vnd.semf',
|
|
||||||
'ser' => 'application/java-serialized-object',
|
|
||||||
'setpay' => 'application/set-payment-initiation',
|
|
||||||
'setreg' => 'application/set-registration-initiation',
|
|
||||||
'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data',
|
|
||||||
'sfs' => 'application/vnd.spotfire.sfs',
|
|
||||||
'sgl' => 'application/vnd.stardivision.writer-global',
|
|
||||||
'sgm' => 'text/sgml',
|
|
||||||
'sgml' => 'text/sgml',
|
|
||||||
'sh' => 'application/x-sh',
|
|
||||||
'shar' => 'application/x-shar',
|
|
||||||
'shf' => 'application/shf+xml',
|
|
||||||
'sig' => 'application/pgp-signature',
|
|
||||||
'silo' => 'model/mesh',
|
|
||||||
'sis' => 'application/vnd.symbian.install',
|
|
||||||
'sisx' => 'application/vnd.symbian.install',
|
|
||||||
'sit' => 'application/x-stuffit',
|
|
||||||
'sitx' => 'application/x-stuffitx',
|
|
||||||
'skd' => 'application/vnd.koan',
|
|
||||||
'skm' => 'application/vnd.koan',
|
|
||||||
'skp' => 'application/vnd.koan',
|
|
||||||
'skt' => 'application/vnd.koan',
|
|
||||||
'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12',
|
|
||||||
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
|
|
||||||
'slt' => 'application/vnd.epson.salt',
|
|
||||||
'sm' => 'application/vnd.stepmania.stepchart',
|
|
||||||
'smf' => 'application/vnd.stardivision.math',
|
|
||||||
'smi' => 'application/smil+xml',
|
|
||||||
'smil' => 'application/smil+xml',
|
|
||||||
'snd' => 'audio/basic',
|
|
||||||
'snf' => 'application/x-font-snf',
|
|
||||||
'so' => 'application/octet-stream',
|
|
||||||
'spc' => 'application/x-pkcs7-certificates',
|
|
||||||
'spf' => 'application/vnd.yamaha.smaf-phrase',
|
|
||||||
'spl' => 'application/x-futuresplash',
|
|
||||||
'spot' => 'text/vnd.in3d.spot',
|
|
||||||
'spp' => 'application/scvp-vp-response',
|
|
||||||
'spq' => 'application/scvp-vp-request',
|
|
||||||
'spx' => 'audio/ogg',
|
|
||||||
'src' => 'application/x-wais-source',
|
|
||||||
'sru' => 'application/sru+xml',
|
|
||||||
'srx' => 'application/sparql-results+xml',
|
|
||||||
'sse' => 'application/vnd.kodak-descriptor',
|
|
||||||
'ssf' => 'application/vnd.epson.ssf',
|
|
||||||
'ssml' => 'application/ssml+xml',
|
|
||||||
'st' => 'application/vnd.sailingtracker.track',
|
|
||||||
'stc' => 'application/vnd.sun.xml.calc.template',
|
|
||||||
'std' => 'application/vnd.sun.xml.draw.template',
|
|
||||||
'stf' => 'application/vnd.wt.stf',
|
|
||||||
'sti' => 'application/vnd.sun.xml.impress.template',
|
|
||||||
'stk' => 'application/hyperstudio',
|
|
||||||
'stl' => 'application/vnd.ms-pki.stl',
|
|
||||||
'str' => 'application/vnd.pg.format',
|
|
||||||
'stw' => 'application/vnd.sun.xml.writer.template',
|
|
||||||
'sub' => 'image/vnd.dvb.subtitle',
|
|
||||||
'sus' => 'application/vnd.sus-calendar',
|
|
||||||
'susp' => 'application/vnd.sus-calendar',
|
|
||||||
'sv4cpio' => 'application/x-sv4cpio',
|
|
||||||
'sv4crc' => 'application/x-sv4crc',
|
|
||||||
'svc' => 'application/vnd.dvb.service',
|
|
||||||
'svd' => 'application/vnd.svd',
|
|
||||||
'svg' => 'image/svg+xml',
|
|
||||||
'svgz' => 'image/svg+xml',
|
|
||||||
'swa' => 'application/x-director',
|
|
||||||
'swf' => 'application/x-shockwave-flash',
|
|
||||||
'swi' => 'application/vnd.aristanetworks.swi',
|
|
||||||
'sxc' => 'application/vnd.sun.xml.calc',
|
|
||||||
'sxd' => 'application/vnd.sun.xml.draw',
|
|
||||||
'sxg' => 'application/vnd.sun.xml.writer.global',
|
|
||||||
'sxi' => 'application/vnd.sun.xml.impress',
|
|
||||||
'sxm' => 'application/vnd.sun.xml.math',
|
|
||||||
'sxw' => 'application/vnd.sun.xml.writer',
|
|
||||||
't' => 'text/troff',
|
|
||||||
'tao' => 'application/vnd.tao.intent-module-archive',
|
|
||||||
'tar' => 'application/x-tar',
|
|
||||||
'tcap' => 'application/vnd.3gpp2.tcap',
|
|
||||||
'tcl' => 'application/x-tcl',
|
|
||||||
'teacher' => 'application/vnd.smart.teacher',
|
|
||||||
'tei' => 'application/tei+xml',
|
|
||||||
'teicorpus' => 'application/tei+xml',
|
|
||||||
'tex' => 'application/x-tex',
|
|
||||||
'texi' => 'application/x-texinfo',
|
|
||||||
'texinfo' => 'application/x-texinfo',
|
|
||||||
'text' => 'text/plain',
|
|
||||||
'tfi' => 'application/thraud+xml',
|
|
||||||
'tfm' => 'application/x-tex-tfm',
|
|
||||||
'thmx' => 'application/vnd.ms-officetheme',
|
|
||||||
'tif' => 'image/tiff',
|
|
||||||
'tiff' => 'image/tiff',
|
|
||||||
'tmo' => 'application/vnd.tmobile-livetv',
|
|
||||||
'torrent' => 'application/x-bittorrent',
|
|
||||||
'tpl' => 'application/vnd.groove-tool-template',
|
|
||||||
'tpt' => 'application/vnd.trid.tpt',
|
|
||||||
'tr' => 'text/troff',
|
|
||||||
'tra' => 'application/vnd.trueapp',
|
|
||||||
'trm' => 'application/x-msterminal',
|
|
||||||
'tsd' => 'application/timestamped-data',
|
|
||||||
'tsv' => 'text/tab-separated-values',
|
|
||||||
'ttc' => 'application/x-font-ttf',
|
|
||||||
'ttf' => 'application/x-font-ttf',
|
|
||||||
'ttl' => 'text/turtle',
|
|
||||||
'twd' => 'application/vnd.simtech-mindmapper',
|
|
||||||
'twds' => 'application/vnd.simtech-mindmapper',
|
|
||||||
'txd' => 'application/vnd.genomatix.tuxedo',
|
|
||||||
'txf' => 'application/vnd.mobius.txf',
|
|
||||||
'txt' => 'text/plain',
|
|
||||||
'u32' => 'application/x-authorware-bin',
|
|
||||||
'udeb' => 'application/x-debian-package',
|
|
||||||
'ufd' => 'application/vnd.ufdl',
|
|
||||||
'ufdl' => 'application/vnd.ufdl',
|
|
||||||
'umj' => 'application/vnd.umajin',
|
|
||||||
'unityweb' => 'application/vnd.unity',
|
|
||||||
'uoml' => 'application/vnd.uoml+xml',
|
|
||||||
'uri' => 'text/uri-list',
|
|
||||||
'uris' => 'text/uri-list',
|
|
||||||
'urls' => 'text/uri-list',
|
|
||||||
'ustar' => 'application/x-ustar',
|
|
||||||
'utz' => 'application/vnd.uiq.theme',
|
|
||||||
'uu' => 'text/x-uuencode',
|
|
||||||
'uva' => 'audio/vnd.dece.audio',
|
|
||||||
'uvd' => 'application/vnd.dece.data',
|
|
||||||
'uvf' => 'application/vnd.dece.data',
|
|
||||||
'uvg' => 'image/vnd.dece.graphic',
|
|
||||||
'uvh' => 'video/vnd.dece.hd',
|
|
||||||
'uvi' => 'image/vnd.dece.graphic',
|
|
||||||
'uvm' => 'video/vnd.dece.mobile',
|
|
||||||
'uvp' => 'video/vnd.dece.pd',
|
|
||||||
'uvs' => 'video/vnd.dece.sd',
|
|
||||||
'uvt' => 'application/vnd.dece.ttml+xml',
|
|
||||||
'uvu' => 'video/vnd.uvvu.mp4',
|
|
||||||
'uvv' => 'video/vnd.dece.video',
|
|
||||||
'uvva' => 'audio/vnd.dece.audio',
|
|
||||||
'uvvd' => 'application/vnd.dece.data',
|
|
||||||
'uvvf' => 'application/vnd.dece.data',
|
|
||||||
'uvvg' => 'image/vnd.dece.graphic',
|
|
||||||
'uvvh' => 'video/vnd.dece.hd',
|
|
||||||
'uvvi' => 'image/vnd.dece.graphic',
|
|
||||||
'uvvm' => 'video/vnd.dece.mobile',
|
|
||||||
'uvvp' => 'video/vnd.dece.pd',
|
|
||||||
'uvvs' => 'video/vnd.dece.sd',
|
|
||||||
'uvvt' => 'application/vnd.dece.ttml+xml',
|
|
||||||
'uvvu' => 'video/vnd.uvvu.mp4',
|
|
||||||
'uvvv' => 'video/vnd.dece.video',
|
|
||||||
'uvvx' => 'application/vnd.dece.unspecified',
|
|
||||||
'uvx' => 'application/vnd.dece.unspecified',
|
|
||||||
'vcd' => 'application/x-cdlink',
|
|
||||||
'vcf' => 'text/x-vcard',
|
|
||||||
'vcg' => 'application/vnd.groove-vcard',
|
|
||||||
'vcs' => 'text/x-vcalendar',
|
|
||||||
'vcx' => 'application/vnd.vcx',
|
|
||||||
'vis' => 'application/vnd.visionary',
|
|
||||||
'viv' => 'video/vnd.vivo',
|
|
||||||
'vor' => 'application/vnd.stardivision.writer',
|
|
||||||
'vox' => 'application/x-authorware-bin',
|
|
||||||
'vrml' => 'model/vrml',
|
|
||||||
'vsd' => 'application/vnd.visio',
|
|
||||||
'vsf' => 'application/vnd.vsf',
|
|
||||||
'vss' => 'application/vnd.visio',
|
|
||||||
'vst' => 'application/vnd.visio',
|
|
||||||
'vsw' => 'application/vnd.visio',
|
|
||||||
'vtu' => 'model/vnd.vtu',
|
|
||||||
'vxml' => 'application/voicexml+xml',
|
|
||||||
'w3d' => 'application/x-director',
|
|
||||||
'wad' => 'application/x-doom',
|
|
||||||
'wav' => 'audio/x-wav',
|
|
||||||
'wax' => 'audio/x-ms-wax',
|
|
||||||
'wbmp' => 'image/vnd.wap.wbmp',
|
|
||||||
'wbs' => 'application/vnd.criticaltools.wbs+xml',
|
|
||||||
'wbxml' => 'application/vnd.wap.wbxml',
|
|
||||||
'wcm' => 'application/vnd.ms-works',
|
|
||||||
'wdb' => 'application/vnd.ms-works',
|
|
||||||
'weba' => 'audio/webm',
|
|
||||||
'webm' => 'video/webm',
|
|
||||||
'webp' => 'image/webp',
|
|
||||||
'wg' => 'application/vnd.pmi.widget',
|
|
||||||
'wgt' => 'application/widget',
|
|
||||||
'wks' => 'application/vnd.ms-works',
|
|
||||||
'wm' => 'video/x-ms-wm',
|
|
||||||
'wma' => 'audio/x-ms-wma',
|
|
||||||
'wmd' => 'application/x-ms-wmd',
|
|
||||||
'wmf' => 'application/x-msmetafile',
|
|
||||||
'wml' => 'text/vnd.wap.wml',
|
|
||||||
'wmlc' => 'application/vnd.wap.wmlc',
|
|
||||||
'wmls' => 'text/vnd.wap.wmlscript',
|
|
||||||
'wmlsc' => 'application/vnd.wap.wmlscriptc',
|
|
||||||
'wmv' => 'video/x-ms-wmv',
|
|
||||||
'wmx' => 'video/x-ms-wmx',
|
|
||||||
'wmz' => 'application/x-ms-wmz',
|
|
||||||
'woff' => 'application/x-font-woff',
|
|
||||||
'wpd' => 'application/vnd.wordperfect',
|
|
||||||
'wpl' => 'application/vnd.ms-wpl',
|
|
||||||
'wps' => 'application/vnd.ms-works',
|
|
||||||
'wqd' => 'application/vnd.wqd',
|
|
||||||
'wri' => 'application/x-mswrite',
|
|
||||||
'wrl' => 'model/vrml',
|
|
||||||
'wsdl' => 'application/wsdl+xml',
|
|
||||||
'wspolicy' => 'application/wspolicy+xml',
|
|
||||||
'wtb' => 'application/vnd.webturbo',
|
|
||||||
'wvx' => 'video/x-ms-wvx',
|
|
||||||
'x32' => 'application/x-authorware-bin',
|
|
||||||
'x3d' => 'application/vnd.hzn-3d-crossword',
|
|
||||||
'xap' => 'application/x-silverlight-app',
|
|
||||||
'xar' => 'application/vnd.xara',
|
|
||||||
'xbap' => 'application/x-ms-xbap',
|
|
||||||
'xbd' => 'application/vnd.fujixerox.docuworks.binder',
|
|
||||||
'xbm' => 'image/x-xbitmap',
|
|
||||||
'xdf' => 'application/xcap-diff+xml',
|
|
||||||
'xdm' => 'application/vnd.syncml.dm+xml',
|
|
||||||
'xdp' => 'application/vnd.adobe.xdp+xml',
|
|
||||||
'xdssc' => 'application/dssc+xml',
|
|
||||||
'xdw' => 'application/vnd.fujixerox.docuworks',
|
|
||||||
'xenc' => 'application/xenc+xml',
|
|
||||||
'xer' => 'application/patch-ops-error+xml',
|
|
||||||
'xfdf' => 'application/vnd.adobe.xfdf',
|
|
||||||
'xfdl' => 'application/vnd.xfdl',
|
|
||||||
'xht' => 'application/xhtml+xml',
|
|
||||||
'xhtml' => 'application/xhtml+xml',
|
|
||||||
'xhvml' => 'application/xv+xml',
|
|
||||||
'xif' => 'image/vnd.xiff',
|
|
||||||
'xla' => 'application/vnd.ms-excel',
|
|
||||||
'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12',
|
|
||||||
'xlc' => 'application/vnd.ms-excel',
|
|
||||||
'xlm' => 'application/vnd.ms-excel',
|
|
||||||
'xls' => 'application/vnd.ms-excel',
|
|
||||||
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12',
|
|
||||||
'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12',
|
|
||||||
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
||||||
'xlt' => 'application/vnd.ms-excel',
|
|
||||||
'xltm' => 'application/vnd.ms-excel.template.macroenabled.12',
|
|
||||||
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
|
|
||||||
'xlw' => 'application/vnd.ms-excel',
|
|
||||||
'xml' => 'application/xml',
|
|
||||||
'xo' => 'application/vnd.olpc-sugar',
|
|
||||||
'xop' => 'application/xop+xml',
|
|
||||||
'xpi' => 'application/x-xpinstall',
|
|
||||||
'xpm' => 'image/x-xpixmap',
|
|
||||||
'xpr' => 'application/vnd.is-xpr',
|
|
||||||
'xps' => 'application/vnd.ms-xpsdocument',
|
|
||||||
'xpw' => 'application/vnd.intercon.formnet',
|
|
||||||
'xpx' => 'application/vnd.intercon.formnet',
|
|
||||||
'xsl' => 'application/xml',
|
|
||||||
'xslt' => 'application/xslt+xml',
|
|
||||||
'xsm' => 'application/vnd.syncml+xml',
|
|
||||||
'xspf' => 'application/xspf+xml',
|
|
||||||
'xul' => 'application/vnd.mozilla.xul+xml',
|
|
||||||
'xvm' => 'application/xv+xml',
|
|
||||||
'xvml' => 'application/xv+xml',
|
|
||||||
'xwd' => 'image/x-xwindowdump',
|
|
||||||
'xyz' => 'chemical/x-xyz',
|
|
||||||
'yaml' => 'text/yaml',
|
|
||||||
'yang' => 'application/yang',
|
|
||||||
'yin' => 'application/yin+xml',
|
|
||||||
'yml' => 'text/yaml',
|
|
||||||
'zaz' => 'application/vnd.zzazz.deck+xml',
|
|
||||||
'zip' => 'application/zip',
|
|
||||||
'zir' => 'application/vnd.zul',
|
|
||||||
'zirz' => 'application/vnd.zul',
|
|
||||||
'zmm' => 'application/vnd.handheld-entertainment+xml'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a singleton instance of the class
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
* @codeCoverageIgnore
|
|
||||||
*/
|
|
||||||
public static function getInstance()
|
|
||||||
{
|
|
||||||
if (!self::$instance) {
|
|
||||||
self::$instance = new self();
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::$instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a mimetype value from a file extension
|
|
||||||
*
|
|
||||||
* @param string $extension File extension
|
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function fromExtension($extension)
|
|
||||||
{
|
|
||||||
$extension = strtolower($extension);
|
|
||||||
|
|
||||||
return isset($this->mimetypes[$extension])
|
|
||||||
? $this->mimetypes[$extension]
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a mimetype from a filename
|
|
||||||
*
|
|
||||||
* @param string $filename Filename to generate a mimetype from
|
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
public function fromFilename($filename)
|
|
||||||
{
|
|
||||||
return $this->fromExtension(pathinfo($filename, PATHINFO_EXTENSION));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,292 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Post;
|
|
||||||
|
|
||||||
use GuzzleHttp\Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stream that when read returns bytes for a streaming multipart/form-data body
|
|
||||||
*/
|
|
||||||
class MultipartBody implements Stream\StreamInterface
|
|
||||||
{
|
|
||||||
/** @var Stream\StreamInterface */
|
|
||||||
private $files;
|
|
||||||
private $fields;
|
|
||||||
private $size;
|
|
||||||
private $buffer;
|
|
||||||
private $bufferedHeaders = [];
|
|
||||||
private $pos = 0;
|
|
||||||
private $currentFile = 0;
|
|
||||||
private $currentField = 0;
|
|
||||||
private $sentLast;
|
|
||||||
private $boundary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $fields Associative array of field names to values where
|
|
||||||
* each value is a string.
|
|
||||||
* @param array $files Associative array of PostFileInterface objects
|
|
||||||
* @param string $boundary You can optionally provide a specific boundary
|
|
||||||
* @throws \InvalidArgumentException
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
array $fields = [],
|
|
||||||
array $files = [],
|
|
||||||
$boundary = null
|
|
||||||
) {
|
|
||||||
$this->boundary = $boundary ?: uniqid();
|
|
||||||
$this->fields = $fields;
|
|
||||||
$this->files = $files;
|
|
||||||
|
|
||||||
// Ensure each file is a PostFileInterface
|
|
||||||
foreach ($this->files as $file) {
|
|
||||||
if (!$file instanceof PostFileInterface) {
|
|
||||||
throw new \InvalidArgumentException('All POST fields must '
|
|
||||||
. 'implement PostFieldInterface');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
$this->seek(0);
|
|
||||||
|
|
||||||
return $this->getContents();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getContents($maxLength = -1)
|
|
||||||
{
|
|
||||||
$buffer = '';
|
|
||||||
|
|
||||||
while (!$this->eof()) {
|
|
||||||
if ($maxLength === -1) {
|
|
||||||
$read = 1048576;
|
|
||||||
} else {
|
|
||||||
$len = strlen($buffer);
|
|
||||||
if ($len == $maxLength) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$read = min(1048576, $maxLength - $len);
|
|
||||||
}
|
|
||||||
$buffer .= $this->read($read);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the boundary
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getBoundary()
|
|
||||||
{
|
|
||||||
return $this->boundary;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function close()
|
|
||||||
{
|
|
||||||
$this->detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function detach()
|
|
||||||
{
|
|
||||||
$this->fields = $this->files = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The stream has reached an EOF when all of the fields and files have been
|
|
||||||
* read.
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function eof()
|
|
||||||
{
|
|
||||||
return $this->currentField == count($this->fields) &&
|
|
||||||
$this->currentFile == count($this->files);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function tell()
|
|
||||||
{
|
|
||||||
return $this->pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isReadable()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isWritable()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The steam is seekable by default, but all attached files must be
|
|
||||||
* seekable too.
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function isSeekable()
|
|
||||||
{
|
|
||||||
foreach ($this->files as $file) {
|
|
||||||
if (!$file->getContent()->isSeekable()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSize()
|
|
||||||
{
|
|
||||||
if ($this->size === null) {
|
|
||||||
foreach ($this->files as $file) {
|
|
||||||
// We must be able to ascertain the size of each attached file
|
|
||||||
if (null === ($size = $file->getContent()->getSize())) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$this->size += strlen($this->getFileHeaders($file)) + $size;
|
|
||||||
}
|
|
||||||
foreach (array_keys($this->fields) as $key) {
|
|
||||||
$this->size += strlen($this->getFieldString($key));
|
|
||||||
}
|
|
||||||
$this->size += strlen("\r\n--{$this->boundary}--");
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function read($length)
|
|
||||||
{
|
|
||||||
$content = '';
|
|
||||||
if ($this->buffer && !$this->buffer->eof()) {
|
|
||||||
$content .= $this->buffer->read($length);
|
|
||||||
}
|
|
||||||
if ($delta = $length - strlen($content)) {
|
|
||||||
$content .= $this->readData($delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($content === '' && !$this->sentLast) {
|
|
||||||
$this->sentLast = true;
|
|
||||||
$content = "\r\n--{$this->boundary}--";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function seek($offset, $whence = SEEK_SET)
|
|
||||||
{
|
|
||||||
if ($offset != 0 || $whence != SEEK_SET || !$this->isSeekable()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->files as $file) {
|
|
||||||
if (!$file->getContent()->seek(0)) {
|
|
||||||
throw new \RuntimeException('Rewind on multipart file failed '
|
|
||||||
. 'even though it shouldn\'t have');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->buffer = $this->sentLast = null;
|
|
||||||
$this->pos = $this->currentField = $this->currentFile = 0;
|
|
||||||
$this->bufferedHeaders = [];
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function write($string)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* No data is in the read buffer, so more needs to be pulled in from fields
|
|
||||||
* and files.
|
|
||||||
*
|
|
||||||
* @param int $length Amount of data to read
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function readData($length)
|
|
||||||
{
|
|
||||||
$result = '';
|
|
||||||
|
|
||||||
if ($this->currentField < count($this->fields)) {
|
|
||||||
$result = $this->readField($length);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($result === '' && $this->currentFile < count($this->files)) {
|
|
||||||
$result = $this->readFile($length);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new stream buffer and inject form-data
|
|
||||||
*
|
|
||||||
* @param int $length Amount of data to read from the stream buffer
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function readField($length)
|
|
||||||
{
|
|
||||||
$name = array_keys($this->fields)[++$this->currentField - 1];
|
|
||||||
$this->buffer = Stream\create($this->getFieldString($name));
|
|
||||||
|
|
||||||
return $this->buffer->read($length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read data from a POST file, fill the read buffer with any overflow
|
|
||||||
*
|
|
||||||
* @param int $length Amount of data to read from the file
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function readFile($length)
|
|
||||||
{
|
|
||||||
$current = $this->files[$this->currentFile];
|
|
||||||
|
|
||||||
// Got to the next file and recursively return the read value, or bail
|
|
||||||
// if no more data can be read.
|
|
||||||
if ($current->getContent()->eof()) {
|
|
||||||
return ++$this->currentFile == count($this->files)
|
|
||||||
? ''
|
|
||||||
: $this->readFile($length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is the start of a file, then send the headers to the read
|
|
||||||
// buffer.
|
|
||||||
if (!isset($this->bufferedHeaders[$this->currentFile])) {
|
|
||||||
$this->buffer = Stream\create($this->getFileHeaders($current));
|
|
||||||
$this->bufferedHeaders[$this->currentFile] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// More data needs to be read to meet the limit, so pull from the file
|
|
||||||
$content = $this->buffer ? $this->buffer->read($length) : '';
|
|
||||||
if (($remaining = $length - strlen($content)) > 0) {
|
|
||||||
$content .= $current->getContent()->read($remaining);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getFieldString($key)
|
|
||||||
{
|
|
||||||
return sprintf(
|
|
||||||
"--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n",
|
|
||||||
$this->boundary,
|
|
||||||
$key,
|
|
||||||
$this->fields[$key]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getFileHeaders(PostFileInterface $file)
|
|
||||||
{
|
|
||||||
$headers = '';
|
|
||||||
foreach ($file->getHeaders() as $key => $value) {
|
|
||||||
$headers .= "{$key}: {$value}\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "--{$this->boundary}\r\n" . trim($headers) . "\r\n\r\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,282 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Post;
|
|
||||||
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
use GuzzleHttp\Stream;
|
|
||||||
use GuzzleHttp\Query;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds POST fields and files and creates a streaming body when read methods
|
|
||||||
* are called on the object.
|
|
||||||
*/
|
|
||||||
class PostBody implements PostBodyInterface
|
|
||||||
{
|
|
||||||
/** @var Stream\StreamInterface */
|
|
||||||
private $body;
|
|
||||||
|
|
||||||
/** @var callable */
|
|
||||||
private $aggregator;
|
|
||||||
|
|
||||||
private $fields = [];
|
|
||||||
|
|
||||||
/** @var PostFileInterface[] */
|
|
||||||
private $files = [];
|
|
||||||
private $forceMultipart = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies request headers to a request based on the POST state
|
|
||||||
*
|
|
||||||
* @param RequestInterface $request Request to update
|
|
||||||
*/
|
|
||||||
public function applyRequestHeaders(RequestInterface $request)
|
|
||||||
{
|
|
||||||
if ($this->files || $this->forceMultipart) {
|
|
||||||
$request->setHeader(
|
|
||||||
'Content-Type',
|
|
||||||
'multipart/form-data; boundary=' . $this->getBody()->getBoundary()
|
|
||||||
);
|
|
||||||
} elseif ($this->fields) {
|
|
||||||
$request->setHeader('Content-Type', 'application/x-www-form-urlencoded');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($size = $this->getSize()) {
|
|
||||||
$request->setHeader('Content-Length', $size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function forceMultipartUpload($force)
|
|
||||||
{
|
|
||||||
$this->forceMultipart = $force;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setAggregator(callable $aggregator)
|
|
||||||
{
|
|
||||||
$this->aggregator = $aggregator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setField($name, $value)
|
|
||||||
{
|
|
||||||
$this->fields[$name] = $value;
|
|
||||||
$this->mutate();
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function replaceFields(array $fields)
|
|
||||||
{
|
|
||||||
$this->fields = $fields;
|
|
||||||
$this->mutate();
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getField($name)
|
|
||||||
{
|
|
||||||
return isset($this->fields[$name]) ? $this->fields[$name] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function removeField($name)
|
|
||||||
{
|
|
||||||
unset($this->fields[$name]);
|
|
||||||
$this->mutate();
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFields($asString = false)
|
|
||||||
{
|
|
||||||
if (!$asString) {
|
|
||||||
return $this->fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (string) (new Query($this->fields))
|
|
||||||
->setEncodingType(Query::RFC1738)
|
|
||||||
->setAggregator($this->getAggregator());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hasField($name)
|
|
||||||
{
|
|
||||||
return isset($this->fields[$name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFile($name)
|
|
||||||
{
|
|
||||||
foreach ($this->files as $file) {
|
|
||||||
if ($file->getName() == $name) {
|
|
||||||
return $file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFiles()
|
|
||||||
{
|
|
||||||
return $this->files;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addFile(PostFileInterface $file)
|
|
||||||
{
|
|
||||||
$this->files[] = $file;
|
|
||||||
$this->mutate();
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function clearFiles()
|
|
||||||
{
|
|
||||||
$this->files = [];
|
|
||||||
$this->mutate();
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the numbers of fields + files
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function count()
|
|
||||||
{
|
|
||||||
return count($this->files) + count($this->fields);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
return (string) $this->getBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getContents($maxLength = -1)
|
|
||||||
{
|
|
||||||
return $this->getBody()->getContents();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function close()
|
|
||||||
{
|
|
||||||
return $this->body ? $this->body->close() : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function detach()
|
|
||||||
{
|
|
||||||
$this->body = null;
|
|
||||||
$this->fields = $this->files = [];
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function eof()
|
|
||||||
{
|
|
||||||
return $this->getBody()->eof();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function tell()
|
|
||||||
{
|
|
||||||
return $this->body ? $this->body->tell() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isSeekable()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isReadable()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isWritable()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSize()
|
|
||||||
{
|
|
||||||
return $this->getBody()->getSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function seek($offset, $whence = SEEK_SET)
|
|
||||||
{
|
|
||||||
return $this->getBody()->seek($offset, $whence);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function read($length)
|
|
||||||
{
|
|
||||||
return $this->getBody()->read($length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function write($string)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a stream object that is built from the POST fields and files.
|
|
||||||
*
|
|
||||||
* If one has already been created, the previously created stream will be
|
|
||||||
* returned.
|
|
||||||
*/
|
|
||||||
private function getBody()
|
|
||||||
{
|
|
||||||
if ($this->body) {
|
|
||||||
return $this->body;
|
|
||||||
} elseif ($this->files || $this->forceMultipart) {
|
|
||||||
return $this->body = $this->createMultipart();
|
|
||||||
} elseif ($this->fields) {
|
|
||||||
return $this->body = $this->createUrlEncoded();
|
|
||||||
} else {
|
|
||||||
return $this->body = Stream\create();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the aggregator used to join multi-valued field parameters
|
|
||||||
*
|
|
||||||
* @return callable
|
|
||||||
*/
|
|
||||||
final protected function getAggregator()
|
|
||||||
{
|
|
||||||
if (!$this->aggregator) {
|
|
||||||
$this->aggregator = Query::phpAggregator();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->aggregator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a multipart/form-data body stream
|
|
||||||
*
|
|
||||||
* @return MultipartBody
|
|
||||||
*/
|
|
||||||
private function createMultipart()
|
|
||||||
{
|
|
||||||
// Flatten the nested query string values using the correct aggregator
|
|
||||||
$query = (string) (new Query($this->fields))
|
|
||||||
->setEncodingType(false)
|
|
||||||
->setAggregator($this->getAggregator());
|
|
||||||
// Convert the flattened query string back into an array
|
|
||||||
$fields = Query::fromString($query)->toArray();
|
|
||||||
|
|
||||||
return new MultipartBody($fields, $this->files);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an application/x-www-form-urlencoded stream body
|
|
||||||
*
|
|
||||||
* @return Stream\StreamInterface
|
|
||||||
*/
|
|
||||||
private function createUrlEncoded()
|
|
||||||
{
|
|
||||||
return Stream\create($this->getFields(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get rid of any cached data
|
|
||||||
*/
|
|
||||||
private function mutate()
|
|
||||||
{
|
|
||||||
$this->body = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Post;
|
|
||||||
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
use GuzzleHttp\Stream\StreamInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a POST body that is sent as either a multipart/form-data stream
|
|
||||||
* or application/x-www-urlencoded stream.
|
|
||||||
*/
|
|
||||||
interface PostBodyInterface extends StreamInterface, \Countable
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Apply headers to the request appropriate for the current state of the object
|
|
||||||
*
|
|
||||||
* @param RequestInterface $request Request
|
|
||||||
*/
|
|
||||||
public function applyRequestHeaders(RequestInterface $request);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a specific field
|
|
||||||
*
|
|
||||||
* @param string $name Name of the field to set
|
|
||||||
* @param string|array $value Value to set
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setField($name, $value);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the aggregation strategy that will be used to turn multi-valued
|
|
||||||
* fields into a string.
|
|
||||||
*
|
|
||||||
* The aggregation function accepts a deeply nested array of query string
|
|
||||||
* values and returns a flattened associative array of key value pairs.
|
|
||||||
*
|
|
||||||
* @param callable $aggregator
|
|
||||||
*/
|
|
||||||
public function setAggregator(callable $aggregator);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set to true to force a multipart upload even if there are no files.
|
|
||||||
*
|
|
||||||
* @param bool $force Set to true to force multipart uploads or false to
|
|
||||||
* remove this flag.
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function forceMultipartUpload($force);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace all existing form fields with an array of fields
|
|
||||||
*
|
|
||||||
* @param array $fields Associative array of fields to set
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function replaceFields(array $fields);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a specific field by name
|
|
||||||
*
|
|
||||||
* @param string $name Name of the POST field to retrieve
|
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
public function getField($name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a field by name
|
|
||||||
*
|
|
||||||
* @param string $name Name of the field to remove
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function removeField($name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an associative array of names to values or a query string.
|
|
||||||
*
|
|
||||||
* @param bool $asString Set to true to retrieve the fields as a query
|
|
||||||
* string.
|
|
||||||
*
|
|
||||||
* @return array|string
|
|
||||||
*/
|
|
||||||
public function getFields($asString = false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if a field is set
|
|
||||||
*
|
|
||||||
* @param string $name Name of the field to set
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function hasField($name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all of the files
|
|
||||||
*
|
|
||||||
* @return array Returns an array of PostFileInterface objects
|
|
||||||
*/
|
|
||||||
public function getFiles();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a POST file by name.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the POST file to retrieve
|
|
||||||
*
|
|
||||||
* @return PostFileInterface|null
|
|
||||||
*/
|
|
||||||
public function getFile($name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a file to the POST
|
|
||||||
*
|
|
||||||
* @param PostFileInterface $file File to add
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function addFile(PostFileInterface $file);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all files from the collection
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function clearFiles();
|
|
||||||
}
|
|
||||||
|
|
@ -1,138 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Post;
|
|
||||||
|
|
||||||
use GuzzleHttp\Mimetypes;
|
|
||||||
use GuzzleHttp\Stream\MetadataStreamInterface;
|
|
||||||
use GuzzleHttp\Stream\StreamInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Post file upload
|
|
||||||
*/
|
|
||||||
class PostFile implements PostFileInterface
|
|
||||||
{
|
|
||||||
private $name;
|
|
||||||
private $filename;
|
|
||||||
private $content;
|
|
||||||
private $headers = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param null $name Name of the form field
|
|
||||||
* @param mixed $content Data to send
|
|
||||||
* @param null $filename Filename content-disposition attribute
|
|
||||||
* @param array $headers Array of headers to set on the file
|
|
||||||
* (can override any default headers)
|
|
||||||
* @throws \RuntimeException when filename is not passed or can't be determined
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
$name,
|
|
||||||
$content,
|
|
||||||
$filename = null,
|
|
||||||
array $headers = []
|
|
||||||
) {
|
|
||||||
$this->headers = $headers;
|
|
||||||
$this->name = $name;
|
|
||||||
$this->prepareContent($content);
|
|
||||||
$this->prepareFilename($filename);
|
|
||||||
$this->prepareDefaultHeaders();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return $this->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFilename()
|
|
||||||
{
|
|
||||||
return $this->filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getContent()
|
|
||||||
{
|
|
||||||
return $this->content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHeaders()
|
|
||||||
{
|
|
||||||
return $this->headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepares the contents of a POST file.
|
|
||||||
*
|
|
||||||
* @param mixed $content Content of the POST file
|
|
||||||
*/
|
|
||||||
private function prepareContent($content)
|
|
||||||
{
|
|
||||||
$this->content = $content;
|
|
||||||
|
|
||||||
if (!($this->content instanceof StreamInterface)) {
|
|
||||||
$this->content = \GuzzleHttp\Stream\create($this->content);
|
|
||||||
} elseif ($this->content instanceof MultipartBody) {
|
|
||||||
if (!$this->hasHeader('Content-Disposition')) {
|
|
||||||
$disposition = 'form-data; name="' . $this->name .'"';
|
|
||||||
$this->headers['Content-Disposition'] = $disposition;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->hasHeader('Content-Type')) {
|
|
||||||
$this->headers['Content-Type'] = sprintf(
|
|
||||||
"multipart/form-data; boundary=%s",
|
|
||||||
$this->content->getBoundary()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies a file name to the POST file based on various checks.
|
|
||||||
*
|
|
||||||
* @param string|null $filename Filename to apply (or null to guess)
|
|
||||||
*/
|
|
||||||
private function prepareFilename($filename)
|
|
||||||
{
|
|
||||||
$this->filename = $filename;
|
|
||||||
|
|
||||||
if (!$this->filename &&
|
|
||||||
$this->content instanceof MetadataStreamInterface
|
|
||||||
) {
|
|
||||||
$this->filename = $this->content->getMetadata('uri');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->filename || substr($this->filename, 0, 6) === 'php://') {
|
|
||||||
$this->filename = $this->name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies default Content-Disposition and Content-Type headers if needed.
|
|
||||||
*/
|
|
||||||
private function prepareDefaultHeaders()
|
|
||||||
{
|
|
||||||
// Set a default content-disposition header if one was no provided
|
|
||||||
if (!$this->hasHeader('Content-Disposition')) {
|
|
||||||
$this->headers['Content-Disposition'] = sprintf(
|
|
||||||
'form-data; filename="%s"; name="%s"',
|
|
||||||
basename($this->filename),
|
|
||||||
$this->name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a default Content-Type if one was not supplied
|
|
||||||
if (!$this->hasHeader('Content-Type')) {
|
|
||||||
$this->headers['Content-Type'] = Mimetypes::getInstance()
|
|
||||||
->fromFilename($this->filename) ?: 'text/plain';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a specific header exists on the POST file by name.
|
|
||||||
*
|
|
||||||
* @param string $name Case-insensitive header to check
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private function hasHeader($name)
|
|
||||||
{
|
|
||||||
return isset(array_change_key_case($this->headers)[strtolower($name)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Post;
|
|
||||||
|
|
||||||
use GuzzleHttp\Stream\StreamInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Post file upload interface
|
|
||||||
*/
|
|
||||||
interface PostFileInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get the name of the form field
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the full path to the file
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getFilename();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the content
|
|
||||||
*
|
|
||||||
* @return StreamInterface
|
|
||||||
*/
|
|
||||||
public function getContent();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets all POST file headers.
|
|
||||||
*
|
|
||||||
* The keys represent the header name as it will be sent over the wire, and
|
|
||||||
* each value is a string.
|
|
||||||
*
|
|
||||||
* @return array Returns an associative array of the file's headers.
|
|
||||||
*/
|
|
||||||
public function getHeaders();
|
|
||||||
}
|
|
||||||
|
|
@ -1,226 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages query string variables and can aggregate them into a string
|
|
||||||
*/
|
|
||||||
class Query extends Collection
|
|
||||||
{
|
|
||||||
const RFC3986 = 'RFC3986';
|
|
||||||
const RFC1738 = 'RFC1738';
|
|
||||||
|
|
||||||
/** @var bool URL encode fields and values */
|
|
||||||
private $encoding = self::RFC3986;
|
|
||||||
|
|
||||||
/** @var callable */
|
|
||||||
private $aggregator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse a query string into a Query object
|
|
||||||
*
|
|
||||||
* @param string $query Query string to parse
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public static function fromString($query)
|
|
||||||
{
|
|
||||||
$q = new static();
|
|
||||||
if ($query === '') {
|
|
||||||
return $q;
|
|
||||||
}
|
|
||||||
|
|
||||||
$foundDuplicates = $foundPhpStyle = false;
|
|
||||||
|
|
||||||
foreach (explode('&', $query) as $kvp) {
|
|
||||||
$parts = explode('=', $kvp, 2);
|
|
||||||
$key = rawurldecode($parts[0]);
|
|
||||||
if ($paramIsPhpStyleArray = substr($key, -2) == '[]') {
|
|
||||||
$foundPhpStyle = true;
|
|
||||||
$key = substr($key, 0, -2);
|
|
||||||
}
|
|
||||||
if (isset($parts[1])) {
|
|
||||||
$value = rawurldecode(str_replace('+', '%20', $parts[1]));
|
|
||||||
if (isset($q[$key])) {
|
|
||||||
$q->add($key, $value);
|
|
||||||
$foundDuplicates = true;
|
|
||||||
} elseif ($paramIsPhpStyleArray) {
|
|
||||||
$q[$key] = array($value);
|
|
||||||
} else {
|
|
||||||
$q[$key] = $value;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$q->add($key, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the duplicate aggregator if duplicates were found and not using
|
|
||||||
// PHP style arrays.
|
|
||||||
if ($foundDuplicates && !$foundPhpStyle) {
|
|
||||||
$q->setAggregator(self::duplicateAggregator());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $q;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the query string parameters to a query string string
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
if (!$this->data) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// The default aggregator is statically cached
|
|
||||||
static $defaultAggregator;
|
|
||||||
|
|
||||||
if (!$this->aggregator) {
|
|
||||||
if (!$defaultAggregator) {
|
|
||||||
$defaultAggregator = self::phpAggregator();
|
|
||||||
}
|
|
||||||
$this->aggregator = $defaultAggregator;
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = '';
|
|
||||||
$aggregator = $this->aggregator;
|
|
||||||
|
|
||||||
foreach ($aggregator($this->data) as $key => $values) {
|
|
||||||
foreach ($values as $value) {
|
|
||||||
if ($result) {
|
|
||||||
$result .= '&';
|
|
||||||
}
|
|
||||||
if ($this->encoding == self::RFC1738) {
|
|
||||||
$result .= urlencode($key);
|
|
||||||
if ($value !== null) {
|
|
||||||
$result .= '=' . urlencode($value);
|
|
||||||
}
|
|
||||||
} elseif ($this->encoding == self::RFC3986) {
|
|
||||||
$result .= rawurlencode($key);
|
|
||||||
if ($value !== null) {
|
|
||||||
$result .= '=' . rawurlencode($value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$result .= $key;
|
|
||||||
if ($value !== null) {
|
|
||||||
$result .= '=' . $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controls how multi-valued query string parameters are aggregated into a
|
|
||||||
* string.
|
|
||||||
*
|
|
||||||
* $query->setAggregator($query::duplicateAggregator());
|
|
||||||
*
|
|
||||||
* @param callable $aggregator Callable used to convert a deeply nested
|
|
||||||
* array of query string variables into a flattened array of key value
|
|
||||||
* pairs. The callable accepts an array of query data and returns a
|
|
||||||
* flattened array of key value pairs where each value is an array of
|
|
||||||
* strings.
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setAggregator(callable $aggregator)
|
|
||||||
{
|
|
||||||
$this->aggregator = $aggregator;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify how values are URL encoded
|
|
||||||
*
|
|
||||||
* @param string|bool $type One of 'RFC1738', 'RFC3986', or false to disable encoding
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
* @throws \InvalidArgumentException
|
|
||||||
*/
|
|
||||||
public function setEncodingType($type)
|
|
||||||
{
|
|
||||||
if ($type === false || $type === self::RFC1738 || $type === self::RFC3986) {
|
|
||||||
$this->encoding = $type;
|
|
||||||
} else {
|
|
||||||
throw new \InvalidArgumentException('Invalid URL encoding type');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Query string aggregator that does not aggregate nested query string
|
|
||||||
* values and allows duplicates in the resulting array.
|
|
||||||
*
|
|
||||||
* Example: http://test.com?q=1&q=2
|
|
||||||
*
|
|
||||||
* @return callable
|
|
||||||
*/
|
|
||||||
public static function duplicateAggregator()
|
|
||||||
{
|
|
||||||
return function (array $data) {
|
|
||||||
return self::walkQuery($data, '', function ($key, $prefix) {
|
|
||||||
return is_int($key) ? $prefix : "{$prefix}[{$key}]";
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aggregates nested query string variables using the same technique as
|
|
||||||
* ``http_build_query()``.
|
|
||||||
*
|
|
||||||
* @param bool $numericIndices Pass false to not include numeric indices
|
|
||||||
* when multi-values query string parameters are present.
|
|
||||||
*
|
|
||||||
* @return callable
|
|
||||||
*/
|
|
||||||
public static function phpAggregator($numericIndices = true)
|
|
||||||
{
|
|
||||||
return function (array $data) use ($numericIndices) {
|
|
||||||
return self::walkQuery(
|
|
||||||
$data,
|
|
||||||
'',
|
|
||||||
function ($key, $prefix) use ($numericIndices) {
|
|
||||||
return !$numericIndices && is_int($key)
|
|
||||||
? "{$prefix}[]"
|
|
||||||
: "{$prefix}[{$key}]";
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Easily create query aggregation functions by providing a key prefix
|
|
||||||
* function to this query string array walker.
|
|
||||||
*
|
|
||||||
* @param array $query Query string to walk
|
|
||||||
* @param string $keyPrefix Key prefix (start with '')
|
|
||||||
* @param callable $prefixer Function used to create a key prefix
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function walkQuery(array $query, $keyPrefix, callable $prefixer)
|
|
||||||
{
|
|
||||||
$result = [];
|
|
||||||
foreach ($query as $key => $value) {
|
|
||||||
if ($keyPrefix) {
|
|
||||||
$key = $prefixer($key, $keyPrefix);
|
|
||||||
}
|
|
||||||
if (is_array($value)) {
|
|
||||||
$result += self::walkQuery($value, $key, $prefixer);
|
|
||||||
} elseif (isset($result[$key])) {
|
|
||||||
$result[$key][] = $value;
|
|
||||||
} else {
|
|
||||||
$result[$key] = array($value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Subscriber;
|
|
||||||
|
|
||||||
use GuzzleHttp\Event\RequestEvents;
|
|
||||||
use GuzzleHttp\Event\SubscriberInterface;
|
|
||||||
use GuzzleHttp\Event\CompleteEvent;
|
|
||||||
use GuzzleHttp\Event\BeforeEvent;
|
|
||||||
use GuzzleHttp\Cookie\CookieJar;
|
|
||||||
use GuzzleHttp\Cookie\CookieJarInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds, extracts, and persists cookies between HTTP requests
|
|
||||||
*/
|
|
||||||
class Cookie implements SubscriberInterface
|
|
||||||
{
|
|
||||||
/** @var CookieJarInterface */
|
|
||||||
private $cookieJar;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param CookieJarInterface $cookieJar Cookie jar used to hold cookies
|
|
||||||
*/
|
|
||||||
public function __construct(CookieJarInterface $cookieJar = null)
|
|
||||||
{
|
|
||||||
$this->cookieJar = $cookieJar ?: new CookieJar();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEvents()
|
|
||||||
{
|
|
||||||
// Fire the cookie plugin complete event before redirecting
|
|
||||||
return [
|
|
||||||
'before' => ['onBefore'],
|
|
||||||
'complete' => ['onComplete', RequestEvents::REDIRECT_RESPONSE + 10]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the cookie cookieJar
|
|
||||||
*
|
|
||||||
* @return CookieJarInterface
|
|
||||||
*/
|
|
||||||
public function getCookieJar()
|
|
||||||
{
|
|
||||||
return $this->cookieJar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onBefore(BeforeEvent $event)
|
|
||||||
{
|
|
||||||
$this->cookieJar->addCookieHeader($event->getRequest());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onComplete(CompleteEvent $event)
|
|
||||||
{
|
|
||||||
$this->cookieJar->extractCookies(
|
|
||||||
$event->getRequest(),
|
|
||||||
$event->getResponse()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,138 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Subscriber;
|
|
||||||
|
|
||||||
use GuzzleHttp\Event\RequestEvents;
|
|
||||||
use GuzzleHttp\Event\SubscriberInterface;
|
|
||||||
use GuzzleHttp\Event\CompleteEvent;
|
|
||||||
use GuzzleHttp\Event\ErrorEvent;
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maintains a list of requests and responses sent using a request or client
|
|
||||||
*/
|
|
||||||
class History implements SubscriberInterface, \IteratorAggregate, \Countable
|
|
||||||
{
|
|
||||||
/** @var int The maximum number of requests to maintain in the history */
|
|
||||||
private $limit;
|
|
||||||
|
|
||||||
/** @var array Requests and responses that have passed through the plugin */
|
|
||||||
private $transactions = [];
|
|
||||||
|
|
||||||
public function __construct($limit = 10)
|
|
||||||
{
|
|
||||||
$this->limit = $limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEvents()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'complete' => ['onComplete', RequestEvents::EARLY],
|
|
||||||
'error' => ['onError', RequestEvents::EARLY],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert to a string that contains all request and response headers
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
$lines = array();
|
|
||||||
foreach ($this->transactions as $entry) {
|
|
||||||
$response = isset($entry['response']) ? $entry['response'] : '';
|
|
||||||
$lines[] = '> ' . trim($entry['request']) . "\n\n< " . trim($response) . "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return implode("\n", $lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onComplete(CompleteEvent $event)
|
|
||||||
{
|
|
||||||
$this->add($event->getRequest(), $event->getResponse());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onError(ErrorEvent $event)
|
|
||||||
{
|
|
||||||
$this->add($event->getRequest(), $event->getResponse());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an Iterator that yields associative array values where each
|
|
||||||
* associative array contains a 'request' and 'response' key.
|
|
||||||
*
|
|
||||||
* @return \Iterator
|
|
||||||
*/
|
|
||||||
public function getIterator()
|
|
||||||
{
|
|
||||||
return new \ArrayIterator($this->transactions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all of the requests sent through the plugin
|
|
||||||
*
|
|
||||||
* @return RequestInterface[]
|
|
||||||
*/
|
|
||||||
public function getRequests()
|
|
||||||
{
|
|
||||||
return array_map(function ($t) {
|
|
||||||
return $t['request'];
|
|
||||||
}, $this->transactions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the number of requests in the history
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function count()
|
|
||||||
{
|
|
||||||
return count($this->transactions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the last request sent
|
|
||||||
*
|
|
||||||
* @return RequestInterface
|
|
||||||
*/
|
|
||||||
public function getLastRequest()
|
|
||||||
{
|
|
||||||
return end($this->transactions)['request'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the last response in the history
|
|
||||||
*
|
|
||||||
* @return ResponseInterface|null
|
|
||||||
*/
|
|
||||||
public function getLastResponse()
|
|
||||||
{
|
|
||||||
return end($this->transactions)['response'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the history
|
|
||||||
*/
|
|
||||||
public function clear()
|
|
||||||
{
|
|
||||||
$this->transactions = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a request to the history
|
|
||||||
*
|
|
||||||
* @param RequestInterface $request Request to add
|
|
||||||
* @param ResponseInterface $response Response of the request
|
|
||||||
*/
|
|
||||||
private function add(
|
|
||||||
RequestInterface $request,
|
|
||||||
ResponseInterface $response = null
|
|
||||||
) {
|
|
||||||
$this->transactions[] = ['request' => $request, 'response' => $response];
|
|
||||||
if (count($this->transactions) > $this->limit) {
|
|
||||||
array_shift($this->transactions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Subscriber;
|
|
||||||
|
|
||||||
use GuzzleHttp\Event\RequestEvents;
|
|
||||||
use GuzzleHttp\Event\SubscriberInterface;
|
|
||||||
use GuzzleHttp\Event\CompleteEvent;
|
|
||||||
use GuzzleHttp\Exception\RequestException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Throws exceptions when a 4xx or 5xx response is received
|
|
||||||
*/
|
|
||||||
class HttpError implements SubscriberInterface
|
|
||||||
{
|
|
||||||
public function getEvents()
|
|
||||||
{
|
|
||||||
return ['complete' => ['onComplete', RequestEvents::VERIFY_RESPONSE]];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Throw a RequestException on an HTTP protocol error
|
|
||||||
*
|
|
||||||
* @param CompleteEvent $event Emitted event
|
|
||||||
* @throws RequestException
|
|
||||||
*/
|
|
||||||
public function onComplete(CompleteEvent $event)
|
|
||||||
{
|
|
||||||
$code = (string) $event->getResponse()->getStatusCode();
|
|
||||||
// Throw an exception for an unsuccessful response
|
|
||||||
if ($code[0] === '4' || $code[0] === '5') {
|
|
||||||
throw RequestException::create($event->getRequest(), $event->getResponse());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,143 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Subscriber;
|
|
||||||
|
|
||||||
use GuzzleHttp\Event\RequestEvents;
|
|
||||||
use GuzzleHttp\Event\SubscriberInterface;
|
|
||||||
use GuzzleHttp\Adapter\Transaction;
|
|
||||||
use GuzzleHttp\Event\BeforeEvent;
|
|
||||||
use GuzzleHttp\Event\HeadersEvent;
|
|
||||||
use GuzzleHttp\Exception\RequestException;
|
|
||||||
use GuzzleHttp\Message\MessageFactory;
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queues mock responses or exceptions and delivers mock responses or
|
|
||||||
* exceptions in a fifo order.
|
|
||||||
*/
|
|
||||||
class Mock implements SubscriberInterface, \Countable
|
|
||||||
{
|
|
||||||
/** @var array Array of mock responses / exceptions */
|
|
||||||
private $queue = [];
|
|
||||||
|
|
||||||
/** @var bool Whether or not to consume an entity body when mocking */
|
|
||||||
private $readBodies;
|
|
||||||
|
|
||||||
/** @var MessageFactory */
|
|
||||||
private $factory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $items Array of responses or exceptions to queue
|
|
||||||
* @param bool $readBodies Set to false to not consume the entity body of
|
|
||||||
* a request when a mock is served.
|
|
||||||
*/
|
|
||||||
public function __construct(array $items = [], $readBodies = true)
|
|
||||||
{
|
|
||||||
$this->factory = new MessageFactory();
|
|
||||||
$this->readBodies = $readBodies;
|
|
||||||
$this->addMultiple($items);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEvents()
|
|
||||||
{
|
|
||||||
// Fire the event last, after signing
|
|
||||||
return ['before' => ['onBefore', RequestEvents::SIGN_REQUEST - 10]];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws \OutOfBoundsException|\Exception
|
|
||||||
*/
|
|
||||||
public function onBefore(BeforeEvent $event)
|
|
||||||
{
|
|
||||||
if (!$item = array_shift($this->queue)) {
|
|
||||||
throw new \OutOfBoundsException('Mock queue is empty');
|
|
||||||
} elseif ($item instanceof RequestException) {
|
|
||||||
throw $item;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emulate the receiving of the response headers
|
|
||||||
$request = $event->getRequest();
|
|
||||||
$transaction = new Transaction($event->getClient(), $request);
|
|
||||||
$transaction->setResponse($item);
|
|
||||||
$request->getEmitter()->emit(
|
|
||||||
'headers',
|
|
||||||
new HeadersEvent($transaction)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Emulate reading a response body
|
|
||||||
if ($this->readBodies && $request->getBody()) {
|
|
||||||
while (!$request->getBody()->eof()) {
|
|
||||||
$request->getBody()->read(8096);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$event->intercept($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function count()
|
|
||||||
{
|
|
||||||
return count($this->queue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a response to the end of the queue
|
|
||||||
*
|
|
||||||
* @param string|ResponseInterface $response Response or path to response file
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
* @throws \InvalidArgumentException if a string or Response is not passed
|
|
||||||
*/
|
|
||||||
public function addResponse($response)
|
|
||||||
{
|
|
||||||
if (is_string($response)) {
|
|
||||||
$response = file_exists($response)
|
|
||||||
? $this->factory->fromMessage(file_get_contents($response))
|
|
||||||
: $this->factory->fromMessage($response);
|
|
||||||
} elseif (!($response instanceof ResponseInterface)) {
|
|
||||||
throw new \InvalidArgumentException('Response must a message '
|
|
||||||
. 'string, response object, or path to a file');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->queue[] = $response;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an exception to the end of the queue
|
|
||||||
*
|
|
||||||
* @param RequestException $e Exception to throw when the request is executed
|
|
||||||
*
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function addException(RequestException $e)
|
|
||||||
{
|
|
||||||
$this->queue[] = $e;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add multiple items to the queue
|
|
||||||
*
|
|
||||||
* @param array $items Items to add
|
|
||||||
*/
|
|
||||||
public function addMultiple(array $items)
|
|
||||||
{
|
|
||||||
foreach ($items as $item) {
|
|
||||||
if ($item instanceof RequestException) {
|
|
||||||
$this->addException($item);
|
|
||||||
} else {
|
|
||||||
$this->addResponse($item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear the queue
|
|
||||||
*/
|
|
||||||
public function clearQueue()
|
|
||||||
{
|
|
||||||
$this->queue = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Subscriber;
|
|
||||||
|
|
||||||
use GuzzleHttp\Event\RequestEvents;
|
|
||||||
use GuzzleHttp\Event\SubscriberInterface;
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
use GuzzleHttp\Event\BeforeEvent;
|
|
||||||
use GuzzleHttp\Post\PostBodyInterface;
|
|
||||||
use GuzzleHttp\Stream\StreamInterface;
|
|
||||||
use GuzzleHttp\Stream\MetadataStreamInterface;
|
|
||||||
use GuzzleHttp\Mimetypes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepares requests with a body before sending
|
|
||||||
*
|
|
||||||
* **Request Options**
|
|
||||||
*
|
|
||||||
* - expect: Set to true to enable the "Expect: 100-Continue" header for a
|
|
||||||
* request that send a body. Set to false to disable "Expect: 100-Continue".
|
|
||||||
* Set to a number so that the size of the payload must be greater than the
|
|
||||||
* number in order to send the Expect header. Setting to a number will send
|
|
||||||
* the Expect header for all requests in which the size of the payload cannot
|
|
||||||
* be determined or where the body is not rewindable.
|
|
||||||
*/
|
|
||||||
class Prepare implements SubscriberInterface
|
|
||||||
{
|
|
||||||
public function getEvents()
|
|
||||||
{
|
|
||||||
return ['before' => ['onBefore', RequestEvents::PREPARE_REQUEST]];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onBefore(BeforeEvent $event)
|
|
||||||
{
|
|
||||||
$request = $event->getRequest();
|
|
||||||
|
|
||||||
// Set the appropriate Content-Type for a request if one is not set and
|
|
||||||
// there are form fields
|
|
||||||
if (!($body = $request->getBody())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->addContentLength($request, $body);
|
|
||||||
|
|
||||||
if ($body instanceof PostBodyInterface) {
|
|
||||||
// Synchronize the POST body with the request's headers
|
|
||||||
$body->applyRequestHeaders($request);
|
|
||||||
} elseif (!$request->hasHeader('Content-Type')) {
|
|
||||||
$this->addContentType($request, $body);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->addExpectHeader($request, $body);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function addContentType(
|
|
||||||
RequestInterface $request,
|
|
||||||
StreamInterface $body
|
|
||||||
) {
|
|
||||||
if (!($body instanceof MetadataStreamInterface)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!($uri = $body->getMetadata('uri'))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Guess the content-type based on the stream's "uri" metadata value.
|
|
||||||
// The file extension is used to determine the appropriate mime-type.
|
|
||||||
if ($contentType = Mimetypes::getInstance()->fromFilename($uri)) {
|
|
||||||
$request->setHeader('Content-Type', $contentType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function addContentLength(
|
|
||||||
RequestInterface $request,
|
|
||||||
StreamInterface $body
|
|
||||||
) {
|
|
||||||
// Set the Content-Length header if it can be determined, and never
|
|
||||||
// send a Transfer-Encoding: chunked and Content-Length header in
|
|
||||||
// the same request.
|
|
||||||
if ($request->hasHeader('Content-Length')) {
|
|
||||||
// Remove transfer-encoding if content-length is set.
|
|
||||||
$request->removeHeader('Transfer-Encoding');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->hasHeader('Transfer-Encoding')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null !== ($size = $body->getSize())) {
|
|
||||||
$request->setHeader('Content-Length', $size)
|
|
||||||
->removeHeader('Transfer-Encoding');
|
|
||||||
} elseif ('1.1' == $request->getProtocolVersion()) {
|
|
||||||
// Use chunked Transfer-Encoding if there is no determinable
|
|
||||||
// content-length header and we're using HTTP/1.1.
|
|
||||||
$request->setHeader('Transfer-Encoding', 'chunked')
|
|
||||||
->removeHeader('Content-Length');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function addExpectHeader(
|
|
||||||
RequestInterface $request,
|
|
||||||
StreamInterface $body
|
|
||||||
) {
|
|
||||||
// Determine if the Expect header should be used
|
|
||||||
if ($request->hasHeader('Expect')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$expect = $request->getConfig()['expect'];
|
|
||||||
|
|
||||||
// Return if disabled or if you're not using HTTP/1.1
|
|
||||||
if ($expect === false || $request->getProtocolVersion() !== '1.1') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The expect header is unconditionally enabled
|
|
||||||
if ($expect === true) {
|
|
||||||
$request->setHeader('Expect', '100-Continue');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// By default, send the expect header when the payload is > 1mb
|
|
||||||
if ($expect === null) {
|
|
||||||
$expect = 1048576;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always add if the body cannot be rewound, the size cannot be
|
|
||||||
// determined, or the size is greater than the cutoff threshold
|
|
||||||
$size = $body->getSize();
|
|
||||||
if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
|
|
||||||
$request->setHeader('Expect', '100-Continue');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,172 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp\Subscriber;
|
|
||||||
|
|
||||||
use GuzzleHttp\Event\RequestEvents;
|
|
||||||
use GuzzleHttp\Event\SubscriberInterface;
|
|
||||||
use GuzzleHttp\Event\CompleteEvent;
|
|
||||||
use GuzzleHttp\Exception\TooManyRedirectsException;
|
|
||||||
use GuzzleHttp\Exception\CouldNotRewindStreamException;
|
|
||||||
use GuzzleHttp\Message\RequestInterface;
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
use GuzzleHttp\Url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscriber used to implement HTTP redirects.
|
|
||||||
*
|
|
||||||
* **Request options**
|
|
||||||
*
|
|
||||||
* - redirect: Associative array containing the 'max', 'strict', and 'referer'
|
|
||||||
* keys.
|
|
||||||
*
|
|
||||||
* - max: Maximum number of redirects allowed per-request
|
|
||||||
* - strict: You can use strict redirects by setting this value to ``true``.
|
|
||||||
* Strict redirects adhere to strict RFC compliant redirection (e.g.,
|
|
||||||
* redirect POST with POST) vs doing what most clients do (e.g., redirect
|
|
||||||
* POST request with a GET request).
|
|
||||||
* - referer: Set to true to automatically add the "Referer" header when a
|
|
||||||
* redirect request is sent.
|
|
||||||
*/
|
|
||||||
class Redirect implements SubscriberInterface
|
|
||||||
{
|
|
||||||
public function getEvents()
|
|
||||||
{
|
|
||||||
return ['complete' => ['onComplete', RequestEvents::REDIRECT_RESPONSE]];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rewind the entity body of the request if needed
|
|
||||||
*
|
|
||||||
* @param RequestInterface $redirectRequest
|
|
||||||
* @throws CouldNotRewindStreamException
|
|
||||||
*/
|
|
||||||
public static function rewindEntityBody(RequestInterface $redirectRequest)
|
|
||||||
{
|
|
||||||
// Rewind the entity body of the request if needed
|
|
||||||
if ($redirectRequest->getBody()) {
|
|
||||||
$body = $redirectRequest->getBody();
|
|
||||||
// Only rewind the body if some of it has been read already, and
|
|
||||||
// throw an exception if the rewind fails
|
|
||||||
if ($body->tell() && !$body->seek(0)) {
|
|
||||||
throw new CouldNotRewindStreamException(
|
|
||||||
'Unable to rewind the non-seekable request body after redirecting',
|
|
||||||
$redirectRequest
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a request receives a redirect response
|
|
||||||
*
|
|
||||||
* @param CompleteEvent $event Event emitted
|
|
||||||
* @throws TooManyRedirectsException
|
|
||||||
*/
|
|
||||||
public function onComplete(CompleteEvent $event)
|
|
||||||
{
|
|
||||||
$response = $event->getResponse();
|
|
||||||
|
|
||||||
if (substr($response->getStatusCode(), 0, 1) != '3' ||
|
|
||||||
!$response->hasHeader('Location')
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$redirectCount = 0;
|
|
||||||
$request = $event->getRequest();
|
|
||||||
$redirectResponse = $response;
|
|
||||||
$max = $request->getConfig()->getPath('redirect/max') ?: 5;
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (++$redirectCount > $max) {
|
|
||||||
throw new TooManyRedirectsException(
|
|
||||||
"Will not follow more than {$redirectCount} redirects",
|
|
||||||
$request
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$redirectRequest = $this->createRedirectRequest($request, $redirectResponse);
|
|
||||||
$redirectResponse = $event->getClient()->send($redirectRequest);
|
|
||||||
} while (substr($redirectResponse->getStatusCode(), 0, 1) == '3' &&
|
|
||||||
$redirectResponse->hasHeader('Location')
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($redirectResponse !== $response) {
|
|
||||||
$event->intercept($redirectResponse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a redirect request for a specific request object
|
|
||||||
*
|
|
||||||
* Takes into account strict RFC compliant redirection (e.g. redirect POST
|
|
||||||
* with POST) vs doing what most clients do (e.g. redirect POST with GET).
|
|
||||||
*
|
|
||||||
* @param RequestInterface $request
|
|
||||||
* @param ResponseInterface $response
|
|
||||||
*
|
|
||||||
* @return RequestInterface Returns a new redirect request
|
|
||||||
* @throws CouldNotRewindStreamException If the body cannot be rewound.
|
|
||||||
*/
|
|
||||||
private function createRedirectRequest(
|
|
||||||
RequestInterface $request,
|
|
||||||
ResponseInterface $response
|
|
||||||
) {
|
|
||||||
$config = $request->getConfig();
|
|
||||||
|
|
||||||
// Use a GET request if this is an entity enclosing request and we are
|
|
||||||
// not forcing RFC compliance, but rather emulating what all browsers
|
|
||||||
// would do. Be sure to disable redirects on the clone.
|
|
||||||
$redirectRequest = clone $request;
|
|
||||||
$redirectRequest->getEmitter()->detach($this);
|
|
||||||
$statusCode = $response->getStatusCode();
|
|
||||||
|
|
||||||
if ($statusCode == 303 ||
|
|
||||||
($statusCode <= 302 && $request->getBody() &&
|
|
||||||
!$config->getPath('redirect/strict'))
|
|
||||||
) {
|
|
||||||
$redirectRequest->setMethod('GET');
|
|
||||||
$redirectRequest->setBody(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->setRedirectUrl($redirectRequest, $response);
|
|
||||||
$this->rewindEntityBody($redirectRequest);
|
|
||||||
|
|
||||||
// Add the Referer header if it is told to do so and only
|
|
||||||
// add the header if we are not redirecting from https to http.
|
|
||||||
if ($config->getPath('redirect/referer') && (
|
|
||||||
$redirectRequest->getScheme() == 'https' ||
|
|
||||||
$redirectRequest->getScheme() == $request->getScheme()
|
|
||||||
)) {
|
|
||||||
$url = Url::fromString($request->getUrl());
|
|
||||||
$url->setUsername(null)->setPassword(null);
|
|
||||||
$redirectRequest->setHeader('Referer', (string) $url);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $redirectRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the appropriate URL on the request based on the location header
|
|
||||||
*
|
|
||||||
* @param RequestInterface $redirectRequest
|
|
||||||
* @param ResponseInterface $response
|
|
||||||
*/
|
|
||||||
private function setRedirectUrl(
|
|
||||||
RequestInterface $redirectRequest,
|
|
||||||
ResponseInterface $response
|
|
||||||
) {
|
|
||||||
$location = $response->getHeader('Location');
|
|
||||||
$location = Url::fromString($location);
|
|
||||||
|
|
||||||
// Combine location with the original URL if it is not absolute.
|
|
||||||
if (!$location->isAbsolute()) {
|
|
||||||
$originalUrl = Url::fromString($redirectRequest->getUrl());
|
|
||||||
// Remove query string parameters and just take what is present on
|
|
||||||
// the redirect Location header
|
|
||||||
$originalUrl->getQuery()->clear();
|
|
||||||
$location = $originalUrl->combine($location);
|
|
||||||
}
|
|
||||||
|
|
||||||
$redirectRequest->setUrl($location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An object that can be represented as an array
|
|
||||||
*/
|
|
||||||
interface ToArrayInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get the array representation of an object
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function toArray();
|
|
||||||
}
|
|
||||||
|
|
@ -1,242 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expands URI templates. Userland implementation of PECL uri_template.
|
|
||||||
*
|
|
||||||
* @link http://tools.ietf.org/html/rfc6570
|
|
||||||
*/
|
|
||||||
class UriTemplate
|
|
||||||
{
|
|
||||||
/** @var string URI template */
|
|
||||||
private $template;
|
|
||||||
|
|
||||||
/** @var array Variables to use in the template expansion */
|
|
||||||
private $variables;
|
|
||||||
|
|
||||||
/** @var array Hash for quick operator lookups */
|
|
||||||
private static $operatorHash = array(
|
|
||||||
'' => array('prefix' => '', 'joiner' => ',', 'query' => false),
|
|
||||||
'+' => array('prefix' => '', 'joiner' => ',', 'query' => false),
|
|
||||||
'#' => array('prefix' => '#', 'joiner' => ',', 'query' => false),
|
|
||||||
'.' => array('prefix' => '.', 'joiner' => '.', 'query' => false),
|
|
||||||
'/' => array('prefix' => '/', 'joiner' => '/', 'query' => false),
|
|
||||||
';' => array('prefix' => ';', 'joiner' => ';', 'query' => true),
|
|
||||||
'?' => array('prefix' => '?', 'joiner' => '&', 'query' => true),
|
|
||||||
'&' => array('prefix' => '&', 'joiner' => '&', 'query' => true)
|
|
||||||
);
|
|
||||||
|
|
||||||
/** @var array Delimiters */
|
|
||||||
private static $delims = array(':', '/', '?', '#', '[', ']', '@', '!', '$',
|
|
||||||
'&', '\'', '(', ')', '*', '+', ',', ';', '=');
|
|
||||||
|
|
||||||
/** @var array Percent encoded delimiters */
|
|
||||||
private static $delimsPct = array('%3A', '%2F', '%3F', '%23', '%5B', '%5D',
|
|
||||||
'%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C',
|
|
||||||
'%3B', '%3D');
|
|
||||||
|
|
||||||
public function expand($template, array $variables)
|
|
||||||
{
|
|
||||||
if (false === strpos($template, '{')) {
|
|
||||||
return $template;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->template = $template;
|
|
||||||
$this->variables = $variables;
|
|
||||||
|
|
||||||
return preg_replace_callback(
|
|
||||||
'/\{([^\}]+)\}/',
|
|
||||||
[$this, 'expandMatch'],
|
|
||||||
$this->template
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse an expression into parts
|
|
||||||
*
|
|
||||||
* @param string $expression Expression to parse
|
|
||||||
*
|
|
||||||
* @return array Returns an associative array of parts
|
|
||||||
*/
|
|
||||||
private function parseExpression($expression)
|
|
||||||
{
|
|
||||||
$result = array();
|
|
||||||
|
|
||||||
if (isset(self::$operatorHash[$expression[0]])) {
|
|
||||||
$result['operator'] = $expression[0];
|
|
||||||
$expression = substr($expression, 1);
|
|
||||||
} else {
|
|
||||||
$result['operator'] = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (explode(',', $expression) as $value) {
|
|
||||||
$value = trim($value);
|
|
||||||
$varspec = array();
|
|
||||||
if ($colonPos = strpos($value, ':')) {
|
|
||||||
$varspec['value'] = substr($value, 0, $colonPos);
|
|
||||||
$varspec['modifier'] = ':';
|
|
||||||
$varspec['position'] = (int) substr($value, $colonPos + 1);
|
|
||||||
} elseif (substr($value, -1) == '*') {
|
|
||||||
$varspec['modifier'] = '*';
|
|
||||||
$varspec['value'] = substr($value, 0, -1);
|
|
||||||
} else {
|
|
||||||
$varspec['value'] = (string) $value;
|
|
||||||
$varspec['modifier'] = '';
|
|
||||||
}
|
|
||||||
$result['values'][] = $varspec;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process an expansion
|
|
||||||
*
|
|
||||||
* @param array $matches Matches met in the preg_replace_callback
|
|
||||||
*
|
|
||||||
* @return string Returns the replacement string
|
|
||||||
*/
|
|
||||||
private function expandMatch(array $matches)
|
|
||||||
{
|
|
||||||
static $rfc1738to3986 = array('+' => '%20', '%7e' => '~');
|
|
||||||
|
|
||||||
$replacements = array();
|
|
||||||
$parsed = self::parseExpression($matches[1]);
|
|
||||||
$prefix = self::$operatorHash[$parsed['operator']]['prefix'];
|
|
||||||
$joiner = self::$operatorHash[$parsed['operator']]['joiner'];
|
|
||||||
$useQuery = self::$operatorHash[$parsed['operator']]['query'];
|
|
||||||
|
|
||||||
foreach ($parsed['values'] as $value) {
|
|
||||||
|
|
||||||
if (!isset($this->variables[$value['value']])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$variable = $this->variables[$value['value']];
|
|
||||||
$actuallyUseQuery = $useQuery;
|
|
||||||
$expanded = '';
|
|
||||||
|
|
||||||
if (is_array($variable)) {
|
|
||||||
|
|
||||||
$isAssoc = $this->isAssoc($variable);
|
|
||||||
$kvp = array();
|
|
||||||
foreach ($variable as $key => $var) {
|
|
||||||
|
|
||||||
if ($isAssoc) {
|
|
||||||
$key = rawurlencode($key);
|
|
||||||
$isNestedArray = is_array($var);
|
|
||||||
} else {
|
|
||||||
$isNestedArray = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$isNestedArray) {
|
|
||||||
$var = rawurlencode($var);
|
|
||||||
if ($parsed['operator'] == '+' ||
|
|
||||||
$parsed['operator'] == '#'
|
|
||||||
) {
|
|
||||||
$var = $this->decodeReserved($var);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($value['modifier'] == '*') {
|
|
||||||
if ($isAssoc) {
|
|
||||||
if ($isNestedArray) {
|
|
||||||
// Nested arrays must allow for deeply nested
|
|
||||||
// structures.
|
|
||||||
$var = strtr(
|
|
||||||
http_build_query([$key => $var]),
|
|
||||||
$rfc1738to3986
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$var = $key . '=' . $var;
|
|
||||||
}
|
|
||||||
} elseif ($key > 0 && $actuallyUseQuery) {
|
|
||||||
$var = $value['value'] . '=' . $var;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$kvp[$key] = $var;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($variable)) {
|
|
||||||
$actuallyUseQuery = false;
|
|
||||||
} elseif ($value['modifier'] == '*') {
|
|
||||||
$expanded = implode($joiner, $kvp);
|
|
||||||
if ($isAssoc) {
|
|
||||||
// Don't prepend the value name when using the explode
|
|
||||||
// modifier with an associative array.
|
|
||||||
$actuallyUseQuery = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($isAssoc) {
|
|
||||||
// When an associative array is encountered and the
|
|
||||||
// explode modifier is not set, then the result must be
|
|
||||||
// a comma separated list of keys followed by their
|
|
||||||
// respective values.
|
|
||||||
foreach ($kvp as $k => &$v) {
|
|
||||||
$v = $k . ',' . $v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$expanded = implode(',', $kvp);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if ($value['modifier'] == ':') {
|
|
||||||
$variable = substr($variable, 0, $value['position']);
|
|
||||||
}
|
|
||||||
$expanded = rawurlencode($variable);
|
|
||||||
if ($parsed['operator'] == '+' || $parsed['operator'] == '#') {
|
|
||||||
$expanded = $this->decodeReserved($expanded);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($actuallyUseQuery) {
|
|
||||||
if (!$expanded && $joiner != '&') {
|
|
||||||
$expanded = $value['value'];
|
|
||||||
} else {
|
|
||||||
$expanded = $value['value'] . '=' . $expanded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$replacements[] = $expanded;
|
|
||||||
}
|
|
||||||
|
|
||||||
$ret = implode($joiner, $replacements);
|
|
||||||
if ($ret && $prefix) {
|
|
||||||
return $prefix . $ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if an array is associative.
|
|
||||||
*
|
|
||||||
* This makes the assumption that input arrays are sequences or hashes.
|
|
||||||
* This assumption is a tradeoff for accuracy in favor of speed, but it
|
|
||||||
* should work in almost every case where input is supplied for a URI
|
|
||||||
* template.
|
|
||||||
*
|
|
||||||
* @param array $array Array to check
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private function isAssoc(array $array)
|
|
||||||
{
|
|
||||||
return $array && array_keys($array)[0] !== 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes percent encoding on reserved characters (used with + and #
|
|
||||||
* modifiers).
|
|
||||||
*
|
|
||||||
* @param string $string String to fix
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function decodeReserved($string)
|
|
||||||
{
|
|
||||||
return str_replace(self::$delimsPct, self::$delims, $string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,585 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses and generates URLs based on URL parts
|
|
||||||
*/
|
|
||||||
class Url
|
|
||||||
{
|
|
||||||
private $scheme;
|
|
||||||
private $host;
|
|
||||||
private $port;
|
|
||||||
private $username;
|
|
||||||
private $password;
|
|
||||||
private $path = '';
|
|
||||||
private $fragment;
|
|
||||||
private static $defaultPorts = ['http' => 80, 'https' => 443, 'ftp' => 21];
|
|
||||||
|
|
||||||
/** @var Query Query part of the URL */
|
|
||||||
private $query;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method to create a new URL from a URL string
|
|
||||||
*
|
|
||||||
* @param string $url Full URL used to create a Url object
|
|
||||||
*
|
|
||||||
* @return Url
|
|
||||||
* @throws \InvalidArgumentException
|
|
||||||
*/
|
|
||||||
public static function fromString($url)
|
|
||||||
{
|
|
||||||
static $defaults = array('scheme' => null, 'host' => null,
|
|
||||||
'path' => null, 'port' => null, 'query' => null,
|
|
||||||
'user' => null, 'pass' => null, 'fragment' => null);
|
|
||||||
|
|
||||||
if (false === ($parts = parse_url($url))) {
|
|
||||||
throw new \InvalidArgumentException('Unable to parse malformed '
|
|
||||||
. 'url: ' . $url);
|
|
||||||
}
|
|
||||||
|
|
||||||
$parts += $defaults;
|
|
||||||
|
|
||||||
// Convert the query string into a Query object
|
|
||||||
if ($parts['query'] || 0 !== strlen($parts['query'])) {
|
|
||||||
$parts['query'] = Query::fromString($parts['query']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new static($parts['scheme'], $parts['host'], $parts['user'],
|
|
||||||
$parts['pass'], $parts['port'], $parts['path'], $parts['query'],
|
|
||||||
$parts['fragment']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a URL from parse_url parts. The generated URL will be a relative
|
|
||||||
* URL if a scheme or host are not provided.
|
|
||||||
*
|
|
||||||
* @param array $parts Array of parse_url parts
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function buildUrl(array $parts)
|
|
||||||
{
|
|
||||||
$url = $scheme = '';
|
|
||||||
|
|
||||||
if (!empty($parts['scheme'])) {
|
|
||||||
$scheme = $parts['scheme'];
|
|
||||||
$url .= $scheme . ':';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($parts['host'])) {
|
|
||||||
$url .= '//';
|
|
||||||
if (isset($parts['user'])) {
|
|
||||||
$url .= $parts['user'];
|
|
||||||
if (isset($parts['pass'])) {
|
|
||||||
$url .= ':' . $parts['pass'];
|
|
||||||
}
|
|
||||||
$url .= '@';
|
|
||||||
}
|
|
||||||
|
|
||||||
$url .= $parts['host'];
|
|
||||||
|
|
||||||
// Only include the port if it is not the default port of the scheme
|
|
||||||
if (isset($parts['port']) &&
|
|
||||||
(!isset(self::$defaultPorts[$scheme]) ||
|
|
||||||
$parts['port'] != self::$defaultPorts[$scheme])
|
|
||||||
) {
|
|
||||||
$url .= ':' . $parts['port'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the path component if present
|
|
||||||
if (isset($parts['path']) && strlen($parts['path'])) {
|
|
||||||
// Always ensure that the path begins with '/' if set and something
|
|
||||||
// is before the path
|
|
||||||
if (isset($parts['host']) && $parts['path'][0] != '/') {
|
|
||||||
$url .= '/';
|
|
||||||
}
|
|
||||||
$url .= $parts['path'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the query string if present
|
|
||||||
if (isset($parts['query'])) {
|
|
||||||
$queryStr = (string) $parts['query'];
|
|
||||||
if ($queryStr || $queryStr === '0') {
|
|
||||||
$url .= '?' . $queryStr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that # is only added to the url if fragment contains anything.
|
|
||||||
if (isset($parts['fragment'])) {
|
|
||||||
$url .= '#' . $parts['fragment'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new URL from URL parts
|
|
||||||
*
|
|
||||||
* @param string $scheme Scheme of the URL
|
|
||||||
* @param string $host Host of the URL
|
|
||||||
* @param string $username Username of the URL
|
|
||||||
* @param string $password Password of the URL
|
|
||||||
* @param int $port Port of the URL
|
|
||||||
* @param string $path Path of the URL
|
|
||||||
* @param Query|array|string $query Query string of the URL
|
|
||||||
* @param string $fragment Fragment of the URL
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
$scheme,
|
|
||||||
$host,
|
|
||||||
$username = null,
|
|
||||||
$password = null,
|
|
||||||
$port = null,
|
|
||||||
$path = null,
|
|
||||||
Query $query = null,
|
|
||||||
$fragment = null
|
|
||||||
) {
|
|
||||||
$this->scheme = $scheme;
|
|
||||||
$this->host = $host;
|
|
||||||
$this->port = $port;
|
|
||||||
$this->username = $username;
|
|
||||||
$this->password = $password;
|
|
||||||
$this->fragment = $fragment;
|
|
||||||
if (!$query) {
|
|
||||||
$this->query = new Query();
|
|
||||||
} else {
|
|
||||||
$this->setQuery($query);
|
|
||||||
}
|
|
||||||
$this->setPath($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clone the URL
|
|
||||||
*/
|
|
||||||
public function __clone()
|
|
||||||
{
|
|
||||||
$this->query = clone $this->query;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the URL as a URL string
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
return static::buildUrl($this->getParts());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the parts of the URL as an array
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getParts()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
'scheme' => $this->scheme,
|
|
||||||
'user' => $this->username,
|
|
||||||
'pass' => $this->password,
|
|
||||||
'host' => $this->host,
|
|
||||||
'port' => $this->port,
|
|
||||||
'path' => $this->path,
|
|
||||||
'query' => $this->query,
|
|
||||||
'fragment' => $this->fragment,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the host of the request.
|
|
||||||
*
|
|
||||||
* @param string $host Host to set (e.g. www.yahoo.com, yahoo.com)
|
|
||||||
*
|
|
||||||
* @return Url
|
|
||||||
*/
|
|
||||||
public function setHost($host)
|
|
||||||
{
|
|
||||||
if (strpos($host, ':') === false) {
|
|
||||||
$this->host = $host;
|
|
||||||
} else {
|
|
||||||
list($host, $port) = explode(':', $host);
|
|
||||||
$this->host = $host;
|
|
||||||
$this->setPort($port);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the host part of the URL
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getHost()
|
|
||||||
{
|
|
||||||
return $this->host;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the scheme part of the URL (http, https, ftp, etc.)
|
|
||||||
*
|
|
||||||
* @param string $scheme Scheme to set
|
|
||||||
*
|
|
||||||
* @return Url
|
|
||||||
*/
|
|
||||||
public function setScheme($scheme)
|
|
||||||
{
|
|
||||||
// Remove the default port if one is specified
|
|
||||||
if ($this->port && isset(self::$defaultPorts[$this->scheme]) &&
|
|
||||||
self::$defaultPorts[$this->scheme] == $this->port
|
|
||||||
) {
|
|
||||||
$this->port = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->scheme = $scheme;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the scheme part of the URL
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getScheme()
|
|
||||||
{
|
|
||||||
return $this->scheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the port part of the URL
|
|
||||||
*
|
|
||||||
* @param int $port Port to set
|
|
||||||
*
|
|
||||||
* @return Url
|
|
||||||
*/
|
|
||||||
public function setPort($port)
|
|
||||||
{
|
|
||||||
$this->port = $port;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the port part of the URl.
|
|
||||||
*
|
|
||||||
* If no port was set, this method will return the default port for the
|
|
||||||
* scheme of the URI.
|
|
||||||
*
|
|
||||||
* @return int|null
|
|
||||||
*/
|
|
||||||
public function getPort()
|
|
||||||
{
|
|
||||||
if ($this->port) {
|
|
||||||
return $this->port;
|
|
||||||
} elseif (isset(self::$defaultPorts[$this->scheme])) {
|
|
||||||
return self::$defaultPorts[$this->scheme];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the path part of the URL
|
|
||||||
*
|
|
||||||
* @param string $path Path string to set
|
|
||||||
*
|
|
||||||
* @return Url
|
|
||||||
*/
|
|
||||||
public function setPath($path)
|
|
||||||
{
|
|
||||||
static $search = [' ', '?'];
|
|
||||||
static $replace = ['%20', '%3F'];
|
|
||||||
$this->path = str_replace($search, $replace, $path);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes dot segments from a URL
|
|
||||||
*
|
|
||||||
* @return Url
|
|
||||||
* @link http://tools.ietf.org/html/rfc3986#section-5.2.4
|
|
||||||
*/
|
|
||||||
public function removeDotSegments()
|
|
||||||
{
|
|
||||||
static $noopPaths = ['' => true, '/' => true, '*' => true];
|
|
||||||
static $ignoreSegments = ['' => true, '.' => true, '..' => true];
|
|
||||||
|
|
||||||
if (isset($noopPaths[$this->path])) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
$results = [];
|
|
||||||
$segments = $this->getPathSegments();
|
|
||||||
foreach ($segments as $segment) {
|
|
||||||
if ($segment == '..') {
|
|
||||||
array_pop($results);
|
|
||||||
} elseif (!isset($ignoreSegments[$segment])) {
|
|
||||||
$results[] = $segment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Combine the normalized parts and add the leading slash if needed
|
|
||||||
if ($this->path[0] == '/') {
|
|
||||||
$this->path = '/' . implode('/', $results);
|
|
||||||
} else {
|
|
||||||
$this->path = implode('/', $results);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the trailing slash if necessary
|
|
||||||
if ($this->path != '/' && isset($ignoreSegments[end($segments)])) {
|
|
||||||
$this->path .= '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a relative path to the currently set path.
|
|
||||||
*
|
|
||||||
* @param string $relativePath Relative path to add
|
|
||||||
*
|
|
||||||
* @return Url
|
|
||||||
*/
|
|
||||||
public function addPath($relativePath)
|
|
||||||
{
|
|
||||||
if ($relativePath != '/' &&
|
|
||||||
is_string($relativePath) &&
|
|
||||||
strlen($relativePath) > 0
|
|
||||||
) {
|
|
||||||
// Add a leading slash if needed
|
|
||||||
if ($relativePath[0] != '/') {
|
|
||||||
$relativePath = '/' . $relativePath;
|
|
||||||
}
|
|
||||||
$this->setPath(str_replace('//', '/', $this->path . $relativePath));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the path part of the URL
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getPath()
|
|
||||||
{
|
|
||||||
return $this->path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the path segments of the URL as an array
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getPathSegments()
|
|
||||||
{
|
|
||||||
return explode('/', $this->path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the password part of the URL
|
|
||||||
*
|
|
||||||
* @param string $password Password to set
|
|
||||||
*
|
|
||||||
* @return Url
|
|
||||||
*/
|
|
||||||
public function setPassword($password)
|
|
||||||
{
|
|
||||||
$this->password = $password;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the password part of the URL
|
|
||||||
*
|
|
||||||
* @return null|string
|
|
||||||
*/
|
|
||||||
public function getPassword()
|
|
||||||
{
|
|
||||||
return $this->password;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the username part of the URL
|
|
||||||
*
|
|
||||||
* @param string $username Username to set
|
|
||||||
*
|
|
||||||
* @return Url
|
|
||||||
*/
|
|
||||||
public function setUsername($username)
|
|
||||||
{
|
|
||||||
$this->username = $username;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the username part of the URl
|
|
||||||
*
|
|
||||||
* @return null|string
|
|
||||||
*/
|
|
||||||
public function getUsername()
|
|
||||||
{
|
|
||||||
return $this->username;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the query part of the URL as a Query object
|
|
||||||
*
|
|
||||||
* @return Query
|
|
||||||
*/
|
|
||||||
public function getQuery()
|
|
||||||
{
|
|
||||||
return $this->query;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the query part of the URL
|
|
||||||
*
|
|
||||||
* @param Query|string|array $query Query string value to set. Can
|
|
||||||
* be a string that will be parsed into a Query object, an array
|
|
||||||
* of key value pairs, or a Query object.
|
|
||||||
*
|
|
||||||
* @return Url
|
|
||||||
* @throws \InvalidArgumentException
|
|
||||||
*/
|
|
||||||
public function setQuery($query)
|
|
||||||
{
|
|
||||||
if ($query instanceof Query) {
|
|
||||||
$this->query = $query;
|
|
||||||
} elseif (is_string($query)) {
|
|
||||||
$this->query = Query::fromString($query);
|
|
||||||
} elseif (is_array($query)) {
|
|
||||||
$this->query = new Query($query);
|
|
||||||
} else {
|
|
||||||
throw new \InvalidArgumentException('Query must be a '
|
|
||||||
. 'QueryInterface, array, or string');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the fragment part of the URL
|
|
||||||
*
|
|
||||||
* @return null|string
|
|
||||||
*/
|
|
||||||
public function getFragment()
|
|
||||||
{
|
|
||||||
return $this->fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the fragment part of the URL
|
|
||||||
*
|
|
||||||
* @param string $fragment Fragment to set
|
|
||||||
*
|
|
||||||
* @return Url
|
|
||||||
*/
|
|
||||||
public function setFragment($fragment)
|
|
||||||
{
|
|
||||||
$this->fragment = $fragment;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if this is an absolute URL
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isAbsolute()
|
|
||||||
{
|
|
||||||
return $this->scheme && $this->host;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Combine the URL with another URL and return a new URL instance.
|
|
||||||
*
|
|
||||||
* Follows the rules specific in RFC 3986 section 5.4.
|
|
||||||
*
|
|
||||||
* @param string $url Relative URL to combine with
|
|
||||||
*
|
|
||||||
* @return Url
|
|
||||||
* @throws \InvalidArgumentException
|
|
||||||
* @link http://tools.ietf.org/html/rfc3986#section-5.4
|
|
||||||
*/
|
|
||||||
public function combine($url)
|
|
||||||
{
|
|
||||||
$url = static::fromString($url);
|
|
||||||
|
|
||||||
// Use the more absolute URL as the base URL
|
|
||||||
if (!$this->isAbsolute() && $url->isAbsolute()) {
|
|
||||||
$url = $url->combine($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
$parts = $url->getParts();
|
|
||||||
|
|
||||||
// Passing a URL with a scheme overrides everything
|
|
||||||
if ($parts['scheme']) {
|
|
||||||
return new static(
|
|
||||||
$parts['scheme'],
|
|
||||||
$parts['host'],
|
|
||||||
$parts['user'],
|
|
||||||
$parts['pass'],
|
|
||||||
$parts['port'],
|
|
||||||
$parts['path'],
|
|
||||||
clone $parts['query'],
|
|
||||||
$parts['fragment']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setting a host overrides the entire rest of the URL
|
|
||||||
if ($parts['host']) {
|
|
||||||
return new static(
|
|
||||||
$this->scheme,
|
|
||||||
$parts['host'],
|
|
||||||
$parts['user'],
|
|
||||||
$parts['pass'],
|
|
||||||
$parts['port'],
|
|
||||||
$parts['path'],
|
|
||||||
clone $parts['query'],
|
|
||||||
$parts['fragment']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$parts['path']) {
|
|
||||||
// The relative URL has no path, so check if it is just a query
|
|
||||||
$path = $this->path ?: '';
|
|
||||||
$query = count($parts['query']) ? $parts['query'] : $this->query;
|
|
||||||
} else {
|
|
||||||
$query = $parts['query'];
|
|
||||||
if ($parts['path'][0] == '/' || !$this->path) {
|
|
||||||
// Overwrite the existing path if the rel path starts with "/"
|
|
||||||
$path = $parts['path'];
|
|
||||||
} else {
|
|
||||||
// If the relative URL does not have a path or the base URL
|
|
||||||
// path does not end in a "/" then overwrite the existing path
|
|
||||||
// up to the last "/"
|
|
||||||
$path = substr($this->path, 0, strrpos($this->path, '/') + 1) . $parts['path'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = new self(
|
|
||||||
$this->scheme,
|
|
||||||
$this->host,
|
|
||||||
$this->username,
|
|
||||||
$this->password,
|
|
||||||
$this->port,
|
|
||||||
$path,
|
|
||||||
clone $query,
|
|
||||||
$parts['fragment']
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($path) {
|
|
||||||
$result->removeDotSegments();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,325 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GuzzleHttp;
|
|
||||||
|
|
||||||
use GuzzleHttp\Event\CompleteEvent;
|
|
||||||
use GuzzleHttp\Event\ErrorEvent;
|
|
||||||
use GuzzleHttp\Event\RequestEvents;
|
|
||||||
use GuzzleHttp\Message\ResponseInterface;
|
|
||||||
use GuzzleHttp\UriTemplate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a custom request
|
|
||||||
*
|
|
||||||
* @param string $method HTTP request method
|
|
||||||
* @param string $url URL of the request
|
|
||||||
* @param array $options Options to use with the request.
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
function request($method, $url, array $options = [])
|
|
||||||
{
|
|
||||||
static $client;
|
|
||||||
if (!$client) {
|
|
||||||
$client = new Client();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $client->send($client->createRequest($method, $url, $options));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a GET request
|
|
||||||
*
|
|
||||||
* @param string $url URL of the request
|
|
||||||
* @param array $options Array of request options
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
function get($url, array $options = [])
|
|
||||||
{
|
|
||||||
return request('GET', $url, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a HEAD request
|
|
||||||
*
|
|
||||||
* @param string $url URL of the request
|
|
||||||
* @param array $options Array of request options
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
function head($url, array $options = [])
|
|
||||||
{
|
|
||||||
return request('HEAD', $url, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a DELETE request
|
|
||||||
*
|
|
||||||
* @param string $url URL of the request
|
|
||||||
* @param array $options Array of request options
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
function delete($url, array $options = [])
|
|
||||||
{
|
|
||||||
return request('DELETE', $url, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a POST request
|
|
||||||
*
|
|
||||||
* @param string $url URL of the request
|
|
||||||
* @param array $options Array of request options
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
function post($url, array $options = [])
|
|
||||||
{
|
|
||||||
return request('POST', $url, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a PUT request
|
|
||||||
*
|
|
||||||
* @param string $url URL of the request
|
|
||||||
* @param array $options Array of request options
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
function put($url, array $options = [])
|
|
||||||
{
|
|
||||||
return request('PUT', $url, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a PATCH request
|
|
||||||
*
|
|
||||||
* @param string $url URL of the request
|
|
||||||
* @param array $options Array of request options
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
function patch($url, array $options = [])
|
|
||||||
{
|
|
||||||
return request('PATCH', $url, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send an OPTIONS request
|
|
||||||
*
|
|
||||||
* @param string $url URL of the request
|
|
||||||
* @param array $options Array of request options
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
function options($url, array $options = [])
|
|
||||||
{
|
|
||||||
return request('OPTIONS', $url, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method for sending multiple requests in parallel and retrieving
|
|
||||||
* a hash map of requests to response objects or RequestException objects.
|
|
||||||
*
|
|
||||||
* Note: This method keeps every request and response in memory, and as such is
|
|
||||||
* NOT recommended when sending a large number or an indeterminable number of
|
|
||||||
* requests in parallel.
|
|
||||||
*
|
|
||||||
* @param ClientInterface $client Client used to send the requests
|
|
||||||
* @param array|\Iterator $requests Requests to send in parallel
|
|
||||||
* @param array $options Passes through the options available in
|
|
||||||
* {@see GuzzleHttp\ClientInterface::sendAll()}
|
|
||||||
* @return \SplObjectStorage Requests are the key and each value is a
|
|
||||||
* {@see GuzzleHttp\Message\ResponseInterface} if the request succeeded or
|
|
||||||
* a {@see GuzzleHttp\Exception\RequestException} if it failed.
|
|
||||||
* @throws \InvalidArgumentException if the event format is incorrect.
|
|
||||||
*/
|
|
||||||
function batch(ClientInterface $client, $requests, array $options = [])
|
|
||||||
{
|
|
||||||
$hash = new \SplObjectStorage();
|
|
||||||
foreach ($requests as $request) {
|
|
||||||
$hash->attach($request);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge the necessary complete and error events to the event listeners so
|
|
||||||
// that as each request succeeds or fails, it is added to the result hash.
|
|
||||||
$options = RequestEvents::convertEventArray(
|
|
||||||
$options,
|
|
||||||
['complete', 'error'],
|
|
||||||
[
|
|
||||||
'priority' => RequestEvents::EARLY,
|
|
||||||
'once' => true,
|
|
||||||
'fn' => function ($e) use ($hash) { $hash[$e->getRequest()] = $e; }
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Send the requests in parallel and aggregate the results.
|
|
||||||
$client->sendAll($requests, $options);
|
|
||||||
|
|
||||||
// Update the received value for any of the intercepted requests.
|
|
||||||
foreach ($hash as $request) {
|
|
||||||
if ($hash[$request] instanceof CompleteEvent) {
|
|
||||||
$hash[$request] = $hash[$request]->getResponse();
|
|
||||||
} elseif ($hash[$request] instanceof ErrorEvent) {
|
|
||||||
$hash[$request] = $hash[$request]->getException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a value from an array using a path syntax to retrieve nested data.
|
|
||||||
*
|
|
||||||
* This method does not allow for keys that contain "/". You must traverse
|
|
||||||
* the array manually or using something more advanced like JMESPath to
|
|
||||||
* work with keys that contain "/".
|
|
||||||
*
|
|
||||||
* // Get the bar key of a set of nested arrays.
|
|
||||||
* // This is equivalent to $collection['foo']['baz']['bar'] but won't
|
|
||||||
* // throw warnings for missing keys.
|
|
||||||
* GuzzleHttp\get_path($data, 'foo/baz/bar');
|
|
||||||
*
|
|
||||||
* @param array $data Data to retrieve values from
|
|
||||||
* @param string $path Path to traverse and retrieve a value from
|
|
||||||
*
|
|
||||||
* @return mixed|null
|
|
||||||
*/
|
|
||||||
function get_path($data, $path)
|
|
||||||
{
|
|
||||||
$path = explode('/', $path);
|
|
||||||
|
|
||||||
while (null !== ($part = array_shift($path))) {
|
|
||||||
if (!is_array($data) || !isset($data[$part])) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$data = $data[$part];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a value in a nested array key. Keys will be created as needed to set the
|
|
||||||
* value.
|
|
||||||
*
|
|
||||||
* This function does not support keys that contain "/" or "[]" characters
|
|
||||||
* because these are special tokens used when traversing the data structure.
|
|
||||||
* A value may be prepended to an existing array by using "[]" as the final
|
|
||||||
* key of a path.
|
|
||||||
*
|
|
||||||
* GuzzleHttp\get_path($data, 'foo/baz'); // null
|
|
||||||
* GuzzleHttp\set_path($data, 'foo/baz/[]', 'a');
|
|
||||||
* GuzzleHttp\set_path($data, 'foo/baz/[]', 'b');
|
|
||||||
* GuzzleHttp\get_path($data, 'foo/baz');
|
|
||||||
* // Returns ['a', 'b']
|
|
||||||
*
|
|
||||||
* @param array $data Data to modify by reference
|
|
||||||
* @param string $path Path to set
|
|
||||||
* @param mixed $value Value to set at the key
|
|
||||||
* @throws \RuntimeException when trying to setPath using a nested path that
|
|
||||||
* travels through a scalar value.
|
|
||||||
*/
|
|
||||||
function set_path(&$data, $path, $value)
|
|
||||||
{
|
|
||||||
$current =& $data;
|
|
||||||
$queue = explode('/', $path);
|
|
||||||
while (null !== ($key = array_shift($queue))) {
|
|
||||||
if (!is_array($current)) {
|
|
||||||
throw new \RuntimeException("Trying to setPath {$path}, but "
|
|
||||||
. "{$key} is set and is not an array");
|
|
||||||
} elseif (!$queue) {
|
|
||||||
if ($key == '[]') {
|
|
||||||
$current[] = $value;
|
|
||||||
} else {
|
|
||||||
$current[$key] = $value;
|
|
||||||
}
|
|
||||||
} elseif (isset($current[$key])) {
|
|
||||||
$current =& $current[$key];
|
|
||||||
} else {
|
|
||||||
$current[$key] = [];
|
|
||||||
$current =& $current[$key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expands a URI template
|
|
||||||
*
|
|
||||||
* @param string $template URI template
|
|
||||||
* @param array $variables Template variables
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function uri_template($template, array $variables)
|
|
||||||
{
|
|
||||||
if (function_exists('\\uri_template')) {
|
|
||||||
return \uri_template($template, $variables);
|
|
||||||
}
|
|
||||||
|
|
||||||
static $uriTemplate;
|
|
||||||
if (!$uriTemplate) {
|
|
||||||
$uriTemplate = new UriTemplate();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $uriTemplate->expand($template, $variables);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper for JSON decode that implements error detection with helpful error
|
|
||||||
* messages.
|
|
||||||
*
|
|
||||||
* @param string $json JSON data to parse
|
|
||||||
* @param bool $assoc When true, returned objects will be converted into
|
|
||||||
* associative arrays.
|
|
||||||
* @param int $depth User specified recursion depth.
|
|
||||||
* @param int $options Bitmask of JSON decode options.
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
* @throws \InvalidArgumentException if the JSON cannot be parsed.
|
|
||||||
* @link http://www.php.net/manual/en/function.json-decode.php
|
|
||||||
*/
|
|
||||||
function json_decode($json, $assoc = false, $depth = 512, $options = 0)
|
|
||||||
{
|
|
||||||
static $jsonErrors = [
|
|
||||||
JSON_ERROR_DEPTH => 'JSON_ERROR_DEPTH - Maximum stack depth exceeded',
|
|
||||||
JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch',
|
|
||||||
JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found',
|
|
||||||
JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON',
|
|
||||||
JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded'
|
|
||||||
];
|
|
||||||
|
|
||||||
$data = \json_decode($json, $assoc, $depth, $options);
|
|
||||||
|
|
||||||
if (JSON_ERROR_NONE !== json_last_error()) {
|
|
||||||
$last = json_last_error();
|
|
||||||
throw new \InvalidArgumentException(
|
|
||||||
'Unable to parse JSON data: '
|
|
||||||
. (isset($jsonErrors[$last]) ? $jsonErrors[$last] : 'Unknown error')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
function deprecation_proxy($object, $name, $arguments, $map)
|
|
||||||
{
|
|
||||||
if (!isset($map[$name])) {
|
|
||||||
throw new \BadMethodCallException('Unknown method, ' . $name);
|
|
||||||
}
|
|
||||||
|
|
||||||
$message = sprintf('%s is deprecated and will be removed in a future '
|
|
||||||
. 'version. Update your code to use the equivalent %s method '
|
|
||||||
. 'instead to avoid breaking changes when this shim is removed.',
|
|
||||||
get_class($object) . '::' . $name . '()',
|
|
||||||
get_class($object) . '::' . $map[$name] . '()'
|
|
||||||
);
|
|
||||||
|
|
||||||
trigger_error($message, E_USER_DEPRECATED);
|
|
||||||
|
|
||||||
return call_user_func_array([$object, $map[$name]], $arguments);
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue