mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-25 10:09:20 +03:00
Merge branch 'master' into master
This commit is contained in:
commit
628f8077a3
393 changed files with 74330 additions and 64616 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);
|
||||
}
|
||||
|
|
@ -67,7 +67,10 @@ class SubStreams
|
|||
|
||||
$sHashName = \MailSo\Base\Utils::Md5Rand();
|
||||
|
||||
self::$aStreams[$sHashName] = $aSubStreams;
|
||||
self::$aStreams[$sHashName] = array_map(function($mItem) {
|
||||
return \is_resource($mItem) ? $mItem :
|
||||
\MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString($mItem);
|
||||
}, $aSubStreams);
|
||||
|
||||
\MailSo\Base\Loader::IncStatistic('CreateStream/SubStreams');
|
||||
|
||||
|
|
@ -181,26 +184,6 @@ class SubStreams
|
|||
$this->iIndex++;
|
||||
}
|
||||
}
|
||||
else if (\is_string($mCurrentPart))
|
||||
{
|
||||
$sReadResult = \substr($mCurrentPart, 0, $iCount);
|
||||
|
||||
$sReturn .= $sReadResult;
|
||||
|
||||
$iLen = \strlen($sReadResult);
|
||||
if ($iCount < $iLen)
|
||||
{
|
||||
$this->sBuffer = \substr($sReturn, $iCount);
|
||||
$sReturn = \substr($sReturn, 0, $iCount);
|
||||
$iCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iCount -= $iLen;
|
||||
}
|
||||
|
||||
$this->iIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -668,7 +668,8 @@ END;
|
|||
|
||||
$aEncodeArray = array('');
|
||||
$aMatch = array();
|
||||
\preg_match_all('/=\?[^\?]+\?[q|b|Q|B]\?[^\?]*(\?=)/', $sValue, $aMatch);
|
||||
// \preg_match_all('/=\?[^\?]+\?[q|b|Q|B]\?[^\?]*?\?=/', $sValue, $aMatch);
|
||||
\preg_match_all('/=\?[^\?]+\?[q|b|Q|B]\?.*?\?=/', $sValue, $aMatch);
|
||||
|
||||
if (isset($aMatch[0]) && \is_array($aMatch[0]))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class Header
|
|||
const DISPOSITION_NOTIFICATION_TO = 'Disposition-Notification-To';
|
||||
const X_CONFIRM_READING_TO = 'X-Confirm-Reading-To';
|
||||
|
||||
const MIME_VERSION = 'Mime-Version';
|
||||
const MIME_VERSION = 'MIME-Version';
|
||||
const X_MAILER = 'X-Mailer';
|
||||
|
||||
const X_MSMAIL_PRIORITY = 'X-MSMail-Priority';
|
||||
|
|
|
|||
|
|
@ -413,7 +413,10 @@ class SmtpClient extends \MailSo\Net\NetClient
|
|||
$sCmd .= ' NOTIFY=SUCCESS,FAILURE';
|
||||
}
|
||||
|
||||
$this->sendRequestWithCheck('RCPT', array(250, 251), $sCmd);
|
||||
$this->sendRequestWithCheck(
|
||||
'RCPT', array(250, 251), $sCmd, false,
|
||||
'Failed to add recipient "'.$sTo.'"'
|
||||
);
|
||||
|
||||
$this->bRcpt = true;
|
||||
|
||||
|
|
@ -657,6 +660,7 @@ class SmtpClient extends \MailSo\Net\NetClient
|
|||
* @param int|array $mExpectCode
|
||||
* @param string $sAddToCommand = ''
|
||||
* @param bool $bSecureLog = false
|
||||
* @param string $sErrorPrefix = ''
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
|
|
@ -664,10 +668,10 @@ class SmtpClient extends \MailSo\Net\NetClient
|
|||
* @throws \MailSo\Net\Exceptions\Exception
|
||||
* @throws \MailSo\Smtp\Exceptions\Exception
|
||||
*/
|
||||
private function sendRequestWithCheck($sCommand, $mExpectCode, $sAddToCommand = '', $bSecureLog = false)
|
||||
private function sendRequestWithCheck($sCommand, $mExpectCode, $sAddToCommand = '', $bSecureLog = false, $sErrorPrefix = '')
|
||||
{
|
||||
$this->sendRequest($sCommand, $sAddToCommand, $bSecureLog);
|
||||
$this->validateResponse($mExpectCode);
|
||||
$this->validateResponse($mExpectCode, $sErrorPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -758,12 +762,13 @@ class SmtpClient extends \MailSo\Net\NetClient
|
|||
|
||||
/**
|
||||
* @param int|array $mExpectCode
|
||||
* @param string $sErrorPrefix = ''
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \MailSo\Smtp\Exceptions\ResponseException
|
||||
*/
|
||||
private function validateResponse($mExpectCode)
|
||||
private function validateResponse($mExpectCode, $sErrorPrefix = '')
|
||||
{
|
||||
if (!\is_array($mExpectCode))
|
||||
{
|
||||
|
|
@ -786,7 +791,8 @@ class SmtpClient extends \MailSo\Net\NetClient
|
|||
if ('-' !== \substr($aParts[1], 0, 1) && !\in_array((int) $aParts[0], $mExpectCode))
|
||||
{
|
||||
$this->writeLogException(
|
||||
new Exceptions\NegativeResponseException($this->aResults, \trim(
|
||||
new Exceptions\NegativeResponseException($this->aResults,
|
||||
('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim(
|
||||
(0 < \count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : '').
|
||||
$this->sResponseBuffer)), \MailSo\Log\Enumerations\Type::ERROR, true);
|
||||
}
|
||||
|
|
@ -794,7 +800,8 @@ class SmtpClient extends \MailSo\Net\NetClient
|
|||
else
|
||||
{
|
||||
$this->writeLogException(
|
||||
new Exceptions\ResponseException($this->aResults, \trim(
|
||||
new Exceptions\ResponseException($this->aResults,
|
||||
('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim(
|
||||
(0 < \count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : '').
|
||||
$this->sResponseBuffer)), \MailSo\Log\Enumerations\Type::ERROR, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
vendor/
|
||||
nbproject/
|
||||
/*.buildpath
|
||||
/*.project
|
||||
/.settings
|
||||
/error.log
|
||||
/export/nicejson
|
||||
.idea/
|
||||
*.iml
|
||||
/coverage
|
||||
/phpunit.phar
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
[submodule "export/nicejson"]
|
||||
path = export/nicejson
|
||||
url = https://github.com/GerHobbelt/nicejson-php.git
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Symfony\CS\FixerInterface;
|
||||
|
||||
$finder = Symfony\CS\Finder\DefaultFinder::create()
|
||||
->notName('LICENSE')
|
||||
->notName('README.md')
|
||||
->notName('.php_cs')
|
||||
->notName('composer.*')
|
||||
->notName('phpunit.xml*')
|
||||
->notName('*.phar')
|
||||
->exclude('vendor')
|
||||
->exclude('examples')
|
||||
->exclude('Symfony/CS/Tests/Fixer')
|
||||
->notName('ElseifFixer.php')
|
||||
->exclude('data')
|
||||
->in(__DIR__)
|
||||
;
|
||||
|
||||
return Symfony\CS\Config\Config::create()
|
||||
->finder($finder)
|
||||
;
|
||||
|
||||
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
language: php
|
||||
php:
|
||||
- "5.3"
|
||||
- "5.4"
|
||||
- "5.5"
|
||||
- "5.6"
|
||||
|
||||
branches:
|
||||
only:
|
||||
- devel
|
||||
- master
|
||||
|
||||
script:
|
||||
- phpunit -v -c tests/phpunit.xml
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
irc:
|
||||
channels:
|
||||
- "asimov.freenode.net#mobiledetect"
|
||||
template:
|
||||
- "%{repository} (%{commit}): %{message}. Build details: %{build_url}"
|
||||
- "%{author} said %{commit_subject}. See %{compare_url}"
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,10 +1,13 @@
|
|||
[](https://travis-ci.org/serbanghita/Mobile-Detect) [](https://packagist.org/packages/mobiledetect/mobiledetectlib) [](https://packagist.org/packages/mobiledetect/mobiledetectlib) [](https://packagist.org/packages/mobiledetect/mobiledetectlib) [](https://packagist.org/packages/mobiledetect/mobiledetectlib)
|
||||
[](https://gitter.im/serbanghita/Mobile-Detect?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||

|
||||
|
||||
> Motto: "Every business should have a mobile detection script to detect mobile readers."
|
||||
|
||||
[](https://travis-ci.org/serbanghita/Mobile-Detect)
|
||||
[](https://packagist.org/packages/mobiledetect/mobiledetectlib)
|
||||
[](https://packagist.org/packages/mobiledetect/mobiledetectlib)
|
||||
[](https://packagist.org/packages/mobiledetect/mobiledetectlib)
|
||||
[](https://packagist.org/packages/mobiledetect/mobiledetectlib)
|
||||
|
||||
*Mobile_Detect is a lightweight PHP class for detecting mobile devices (including tablets).
|
||||
It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.*
|
||||
|
||||
|
|
@ -67,212 +70,214 @@ Special thanks to the community :+1: for donations, [BrowserStack](https://www.b
|
|||
:point_right: Keep `Mobile_Detect.php` class in a separate `module` and do NOT include it in your script core because of the high frequency of updates.
|
||||
:point_right: When including the class into you `web application` or `module` always use `include_once '../path/to/Mobile_Detect.php` to prevent conflicts.
|
||||
|
||||
<table>
|
||||
**JavaScript**
|
||||
|
||||
<tr>
|
||||
<td>mobile-detect.js</td>
|
||||
<td><p>A <a href="https://github.com/hgoebl/mobile-detect.js">JavaScript port</a> of Mobile-Detect class. Made by <a href="https://github.com/hgoebl">Heinrich Goebl</a>.</p></td>
|
||||
</tr>
|
||||
* mobile-detect.js - A [JavaScript port](https://github.com/hgoebl/mobile-detect.js) of Mobile-Detect class. Made by [Heinrich Goebl](https://github.com/hgoebl).
|
||||
|
||||
<tr>
|
||||
<td>Varnish Cache</td>
|
||||
<td>
|
||||
<p><a href="https://github.com/willemk/varnish-mobiletranslate">Varnish Mobile Detect</a> - Drop-in varnish solution to mobile user detection based on the Mobile-Detect library. Made by <a href="https://github.com/willemk">willemk</a>.</p>
|
||||
<p><a href="https://github.com/carlosabalde/mobiledetect2vcl">mobiledetect2vcl</a> - Python script to transform the Mobile Detect JSON database into an UA-based mobile detection VCL subroutine easily integrable in any Varnish Cache configuration. Made by <a href="https://github.com/carlosabalde">Carlos Abalde</a>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
**Varnish Cache**
|
||||
|
||||
<tr>
|
||||
<td>LUA</td>
|
||||
<td>
|
||||
<p><a href="https://github.com/yourpalmark/mobile-detect.lua">mobile-detect.lua</a> is a port of Mobile-Detect to Lua for NGINX HTTP servers. Follows closely to mobile-detect.js. Supports all methods that server-side mobile-detect.js supports. Fully unit-tested and synced with Travis CI (Build Passing badge included). Made by <a href="https://github.com/yourpalmark">Mark Walters</a>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
* [Varnish Mobile Detect](https://github.com/willemk/varnish-mobiletranslate) - Drop-in varnish solution to mobile user
|
||||
detection based on the Mobile-Detect library. Made by [willemk](https://github.com/willemk).
|
||||
* [mobiledetect2vcl](https://github.com/carlosabalde/mobiledetect2vcl) - Python script to transform the Mobile
|
||||
Detect JSON database into an UA-based mobile detection VCL subroutine easily integrable in any Varnish Cache
|
||||
configuration. Made by [Carlos Abalde](https://github.com/carlosabalde).
|
||||
|
||||
<tr>
|
||||
<td>WordPress</td>
|
||||
<td>
|
||||
<p><a href="https://wordpress.org/plugins/wp-mobile-detect/">WordPress Mobile Detect</a> - Gives you the ability to wrap that infographic in a <code>[notdevice][/notdevice]</code> shortcode so at the server level <code>WordPress</code> will decide to show that content only if the user is NOT on a phone or tablet. Made by <a href="https://profiles.wordpress.org/professor44/">Jesse Friedman</a>.</p>
|
||||
**LUA**
|
||||
|
||||
<p><a href="https://wordpress.org/plugins/mobble/">mobble</a> - provides mobile related conditional functions for your site. e.g. is_iphone(), is_mobile() and is_tablet(). Made by Scott Evans.</p>
|
||||
* [mobile-detect.lua](https://github.com/yourpalmark/mobile-detect.lua) is a port of Mobile-Detect to Lua for
|
||||
NGINX HTTP servers. Follows closely to mobile-detect.js. Supports all methods that server-side
|
||||
mobile-detect.js supports. Fully unit-tested and synced with Travis CI (Build Passing badge included).
|
||||
Made by [Mark Walters](https://github.com/yourpalmark).
|
||||
|
||||
<p><a href="https://github.com/iamspacehead/responsage">WordPress Responsage</a> - A small <code>WordPress</code> theme plugin that allows you to make your images responsive. Made by <a href="https://github.com/iamspacehead">Adrian Ciaschetti</a>.</p>
|
||||
**PHP**
|
||||
|
||||
**WordPress**
|
||||
|
||||
* [WordPress Mobile Detect](https://wordpress.org/plugins/wp-mobile-detect/) - Gives you the ability to wrap that
|
||||
infographic in a `[notdevice][/notdevice]` shortcode so at the server level WordPress will
|
||||
decide to show that content only if the user is NOT on a phone or tablet.
|
||||
Made by [Jesse Friedman](https://profiles.wordpress.org/professor44/).
|
||||
|
||||
* [mobble](https://wordpress.org/plugins/mobble/) - provides mobile related conditional functions for your site.
|
||||
e.g. `is_iphone()`, `is_mobile()` and `is_tablet()`. Made by Scott Evans.
|
||||
|
||||
* [WordPress Responsage](https://github.com/iamspacehead/responsage) - A small WordPress theme plugin that allows
|
||||
you to make your images responsive. Made by [Adrian Ciaschetti](https://github.com/iamspacehead).
|
||||
|
||||
<p><a href="https://wordpress.org/plugins/wp247-body-classes/">WP247 Body Classes</a> - Add unique classes to the <code>body</code> tag for easy styling based on various attributes (archive, user, post, mobile) and various WordPress "is" functions. Mobile attributes include type of device, Operating System, Browser, etc. Examples: .is-mobile, .is-not-mobile, .is-tablet, .is-ios, .is-not-ios, .is-androidos, .is-chromebrowser. Made by <a href="https://github.com/wescleveland56">wescleveland56</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
* [WP247 Body Classes](https://wordpress.org/plugins/wp247-body-classes/) - Add unique classes to the `body` tag for
|
||||
easy styling based on various attributes (archive, user, post, mobile) and various WordPress "is" functions.
|
||||
Mobile attributes include type of device, Operating System, Browser, etc. Examples: .is-mobile, .is-not-mobile,
|
||||
.is-tablet, .is-ios, .is-not-ios, .is-androidos, .is-chromebrowser.
|
||||
Made by [wescleveland56](https://github.com/wescleveland56).
|
||||
|
||||
<tr>
|
||||
<td>Drupal</td>
|
||||
<td>
|
||||
<p><a href="https://www.drupal.org/project/mobile_switch">Drupal Mobile Switch</a> - The Mobile Switch <code>Drupal</code> module provides a automatic theme switch functionality for mobile devices,
|
||||
detected by Browscap or Mobile Detect. Made by <a href="https://www.drupal.org/user/45267">Siegfried Neumann</a>.</p>
|
||||
**Drupal**
|
||||
|
||||
<p><a href="https://www.drupal.org/project/context_mobile_detect">Drupal Context Mobile Detect</a> - This is a <code>Drupal context</code> module which integrates Context and PHP Mobile Detect library.
|
||||
Created by <a href="https://www.drupal.org/user/432492">Artem Shymko</a>.</p>
|
||||
* [Drupal Mobile Switch](https://www.drupal.org/project/mobile_switch) - The Mobile Switch Drupal module provides a
|
||||
automatic theme switch functionality for mobile devices, detected by Browscap or Mobile Detect.
|
||||
Made by [Siegfried Neumann](https://www.drupal.org/user/45267).
|
||||
|
||||
<p><a href="https://www.drupal.org/project/mobile_detect">Drupal Mobile Detect</a> - Lightweight mobile detect module for <code>Drupal</code> created by <a href="https://www.drupal.org/user/325244">Matthew Donadio</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
* [Drupal Context Mobile Detect](https://www.drupal.org/project/context_mobile_detect) - This is a Drupal context module
|
||||
which integrates Context and PHP Mobile Detect library.
|
||||
Created by [Artem Shymko](https://www.drupal.org/user/432492).
|
||||
|
||||
<tr>
|
||||
<td>Joomla</td>
|
||||
<td>
|
||||
<p><a href="http://www.yagendoo.com/en/blog/free-mobile-detection-plugin-for-joomla.html">yagendoo Joomla! Mobile Detection Plugin</a> - Lightweight PHP plugin for Joomla!
|
||||
that detects a mobile browser using the Mobile Detect class. Made by <a href="http://www.yagendoo.com/">yagendoo media</a>.</p>
|
||||
|
||||
<p><a href="https://github.com/renekreijveld/UserAgentDetector">User Agent Detector plugin</a> by @ReneKreijveld. This system plugin detects the user agent of your
|
||||
website visitor and sets a session variable accordingly. Based on the user agent, the plugin detects if the site is running on a desktop pc, tablet or smartphone.
|
||||
It can also detect if the visitor is a spider bot (search engine). Session variable that is set: ualayout. Possible values: desktop, tablet, mobile, bot..</p>
|
||||
</td>
|
||||
</tr>
|
||||
* [Drupal Mobile Detect](https://www.drupal.org/project/mobile_detect) - Lightweight mobile detect module for Drupal
|
||||
created by [Matthew Donadio](https://www.drupal.org/user/325244).
|
||||
|
||||
<tr>
|
||||
<td>Magento</td>
|
||||
<td><p><a href="http://www.magentocommerce.com/magento-connect/catalog/product/view/id/16835/">Magento</a> - This <code>Magento helper</code> from Optimise Web enables the use of all functions provided by MobileDetect.net.
|
||||
Made by <a href="http://www.kathirvel.com">Kathir Vel</a>.</p></td>
|
||||
</tr>
|
||||
**Joomla**
|
||||
|
||||
<tr>
|
||||
<td>PrestaShop</td>
|
||||
<td><p><a href="https://www.prestashop.com/">PrestaShop</a> is a free, secure and open source shopping cart platform. Mobile_Detect is included in the default package since 1.5.x.</p></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Zend Framework</td>
|
||||
<td>
|
||||
<p><a href="https://github.com/neilime/zf2-mobile-detect.git">ZF2 Mobile-Detect</a> - Zend Framework 2 module that provides Mobile-Detect features (Mobile_Detect class as a service, helper for views and plugin controllers). Made by <a href="https://github.com/neilime">neilime</a></p>
|
||||
|
||||
<p><a href="https://github.com/nikolaposa/MobileDetectModule">ZF2 MobileDetectModule</a> - Facilitates integration of a PHP MobileDetect class with some ZF2-based application. Has similar idea like the existing ZF2 Mobile-Detect module, but differs in initialization and provision routine of the actual Mobile_Detect class. Appropriate view helper and controller plugin also have different conceptions. Made by <a href="https://github.com/nikolaposa">Nikola Posa</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Symfony</td>
|
||||
<td><p><a href="https://github.com/suncat2000/MobileDetectBundle">Symfony2 Mobile Detect Bundle</a> - The bundle for detecting mobile devices, manage mobile view and redirect to the mobile and tablet version.
|
||||
Made by <a href="https://github.com/suncat2000">Nikolay Ivlev</a>.</p>
|
||||
<p><a href="https://github.com/jbinfo/MobileDetectServiceProvider">Silex Mobile Detect Service Provider</a> - <code>Silex</code> service provider to interact with Mobile detect class methods. Made by <a href="https://github.com/jbinfo">Lhassan Baazzi</a>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Laravel</td>
|
||||
<td>
|
||||
<p><a href="https://github.com/jenssegers/agent">Agent</a> a user agent class for Laravel, based on Mobile Detect with some additional functionality. Made by <a href="https://github.com/jenssegers">Jens Segers</a>.</p>
|
||||
<p><a href="https://github.com/hisorange/browser-detect">BrowserDetect</a> is a browser & mobile detection package, collects and wrap together the best user-agent identifiers for Laravel. Created by <a href="https://github.com/hisorange">Varga Zsolt</a>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Slim Framework</td>
|
||||
<td>
|
||||
<p><a href="https://github.com/zguillez/slim_mobile_detect">Slim_Mobile_Detect</a> implements Mobile_Detect lib for differents response's write on Slim Framework App</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>ExpressionEngine</td>
|
||||
<td><p><a href="https://github.com/garethtdavies/detect-mobile">EE2 Detect Mobile</a> - Lightweight PHP plugin for <code>EE2</code> that detects a mobile browser using the Mobile Detect class. Made by <a href="https://github.com/garethtdavies">Gareth Davies</a>.</p></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Yii Framework</td>
|
||||
<td>
|
||||
<p><a href="https://github.com/iamsalnikov/MobileDetect">Yii Extension</a> - Mobile detect plugin for Yii framework.
|
||||
Made by <a href="https://github.com/iamsalnikov">Alexey Salnikov</a>.</p>
|
||||
|
||||
<p><a href="https://github.com/alexandernst/yii2-device-detect/">Yii2 Device Detect</a> - Yii2 extension for Mobile-Detect library. Made by <a href="https://github.com/alexandernst">Alexander Nestorov</a></p>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>CakePHP</td>
|
||||
<td><p><a href="https://github.com/chronon/CakePHP-MobileDetectComponent-Plugin">CakePHP MobileDetect</a> - <code>plugin</code> component for <code>CakePHP</code> 2.x. Made by <a href="https://github.com/chronon">Gregory Gaskill</a></p></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>FuelPHP</td>
|
||||
<td><a href="https://github.com/rob-bar/special_agent">Special Agent</a> is a FuelPHP package which uses php-mobile-detect to determine whether a device is mobile or not.
|
||||
It overrides the Fuelphp Agent class its methods. Made by <a href="https://github.com/rob-bar">Robbie Bardjin</a>.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>TYPO3</td>
|
||||
<td><a href="https://typo3.org/extensions/repository/view/px_mobiledetect">px_mobiledetect</a> is an extension that helps to detect visitor's mobile device class (if that’s tablet or mobile device like smartphone). Made by Alexander Tretyak.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>PHP</td>
|
||||
<td>
|
||||
<p><a href="https://github.com/mmamedov/page-cache">PageCache</a> is a lightweight PHP library for full page cache, with built-in Mobile-Detect support. Made by <a href="https://github.com/mmamedov">Muhammed Mamedov</a>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Statamic</td>
|
||||
<td><p><a href="https://github.com/haikulab/statamic-mobile-detect">Statamic CMS Mobile Detect</a> - <code>plugin</code>. Made by <a href="https://github.com/haikulab/statamic-mobile-detect">Sergei Filippov of Haiku Lab</a>.</p></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Kohana</td>
|
||||
<td><p><a href="https://github.com/madeinnordeste/kohana-mobile-detect">Kohana Mobile Detect</a> - an example of implementation of <code>Mobile_Detect</code> class with Kohana framework. Written by <a href="https://github.com/madeinnordeste">Luiz Alberto S. Ribeiro</a>.</p></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Perl</td>
|
||||
<td><p><a href="https://www.buzzerstar.com/development/">MobileDetect.pm</a> - <code>Perl module</code> for Mobile Detect. Made by <a href="https://www.buzzerstar.com/">Sebastian Enger</a>.</p></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>python</td>
|
||||
<td><p><a href="https://pypi.python.org/pypi/pymobiledetect">pymobiledetect</a> - Mobile detect <code>python package</code>. Made by Bas van Oostveen.</p></td>
|
||||
</tr>
|
||||
* [yagendoo Joomla! Mobile Detection Plugin](http://www.yagendoo.com/en/blog/free-mobile-detection-plugin-for-joomla.html) - Lightweight PHP plugin for Joomla!
|
||||
that detects a mobile browser using the Mobile Detect class.
|
||||
Made by yagendoo media.
|
||||
|
||||
<tr>
|
||||
<td>Ruby</td>
|
||||
<td><p><a href="https://github.com/ktaragorn/mobile_detect">mobile_detect.rb</a> - A <code>Ruby gem</code> using the JSON data exposed by the php project and implementing a basic subset of the API (as much as can be done by the exposed data). Made by <a href="https://github.com/ktaragorn">Karthik T</a>.</p></td>
|
||||
</tr>
|
||||
* [User Agent Detector plugin](https://github.com/renekreijveld/UserAgentDetector) - This system plugin detects the user
|
||||
agent of your website visitor and sets a session variable accordingly. Based on the user agent, the plugin detects if the
|
||||
site is running on a desktop pc, tablet or smartphone. It can also detect if the visitor is a spider bot (search engine).
|
||||
Session variable that is set: `ualayout`. Possible values: desktop, tablet, mobile, bot.
|
||||
Made by @ReneKreijveld.
|
||||
|
||||
<tr>
|
||||
<td>GoMobileDetect</td>
|
||||
<td><p><a href="https://github.com/Shaked/gomobiledetect">GoMobileDetect</a> - <code>Go</code> port of Mobile Detect class. Made by <a href="https://github.com/Shaked">Shaked</a>.</p></td>
|
||||
</tr>
|
||||
**Magento**
|
||||
|
||||
<tr>
|
||||
<td>LUA</td>
|
||||
<td><p><a href="https://github.com/robinef/ua-lua">ua-lua</a> is a small lib written in <code>LUA</code> providing device type detection. ua-lua is detecting mobile or tablet devices based on user-agent inside nginx daemon. Made by <a href="https://github.com/robinef">Frédéric Robinet</a>.</p></td>
|
||||
</tr>
|
||||
* [Magento helper](http://www.magentocommerce.com/magento-connect/catalog/product/view/id/16835/) from Optimise Web enables
|
||||
the use of all functions provided by Mobile Detect. Made by [Kathir Vel](http://www.kathirvel.com).
|
||||
|
||||
<tr>
|
||||
<td>MemHT</td>
|
||||
<td><p><a href="https://www.memht.com/">MemHT</a> is a Free PHP CMS and Blog that permit the creation and the management online of websites with few and easy steps. Has the class included in the core.</p></td>
|
||||
</tr>
|
||||
* [Magento 2 Mobile Detect Theme Change](https://github.com/EaDesgin/magento2-mobiledetect) is an extension for Magento 2
|
||||
that will change the theme or redirect to a different URL. Also containing a helper to check for the device type.
|
||||
|
||||
<tr>
|
||||
<td>concrete5</td>
|
||||
<td><p><a href="https://www.concrete5.org/">concrete5</a> is a CMS that is free and open source. The library is included in the core.</p></td>
|
||||
</tr>
|
||||
**PrestaShop**
|
||||
|
||||
<tr>
|
||||
<td>engine7</td>
|
||||
<td><p><a href="https://github.com/QOXCorp/exengine">ExEngine 7</a> PHP Open Source Framework. The Mobile_Detect class is included in the engine.</p></td>
|
||||
</tr>
|
||||
* [PrestaShop](https://www.prestashop.com) is a free, secure and open source shopping cart platform. Mobile_Detect
|
||||
is included in the default package since 1.5.x.
|
||||
|
||||
<tr>
|
||||
<td>Zikula</td>
|
||||
<td><p><a href="http://zikula.org/">Zikula</a> is a free and open-source Content Management Framework, which allows you to run impressive websites and build powerful online applications. The core uses Mobile-Detect to switch to a special Mobile theme, using jQueryMobile</p></td>
|
||||
</tr>
|
||||
**Laravel**
|
||||
|
||||
<tr>
|
||||
<td>UserAgentInfo</td>
|
||||
<td><p><a href="https://github.com/quentin389/UserAgentInfo">UserAgentInfo</a> is a PHP class for parsing user agent strings (HTTP_USER_AGENT). Includes mobile checks, bot checks, browser types/versions and more.
|
||||
Based on browscap, Mobile_Detect and ua-parser. Created for high traffic websites and fast batch processing. Made by <a href="https://github.com/quentin389">quentin389</a></p></td>
|
||||
</tr>
|
||||
* [Agent](https://github.com/jenssegers/agent) is a user agent class for Laravel based on Mobile Detect with some
|
||||
additional functionality.
|
||||
Made by [Jens Segers](https://github.com/jenssegers).
|
||||
|
||||
<tr>
|
||||
<td>Craft CMS</td>
|
||||
<td><p><a href="https://github.com/lewisjenkins/craft-lj-mobiledetect">LJ Mobile Detect</a> is a simple implementation of Mobile Detect for Craft CMS. Made by <a href="https://github.com/lewisjenkins">Lewis Jenkins</a></p></td>
|
||||
</tr>
|
||||
* [BrowserDetect](https://github.com/hisorange/browser-detect) is a browser and mobile detection package, collects
|
||||
and wrap together the best user-agent identifiers for Laravel.
|
||||
Created by [Varga Zsolt](https://github.com/hisorange).
|
||||
|
||||
</table>
|
||||
**Zend Framework**
|
||||
|
||||
* [ZF2 Mobile-Detect](https://github.com/neilime/zf2-mobile-detect.git) is a Zend Framework 2 module that provides
|
||||
Mobile-Detect features (Mobile_Detect class as a service, helper for views and plugin controllers).
|
||||
Made by [neilime](https://github.com/neilime).
|
||||
|
||||
* [ZF2 MobileDetectModule](https://github.com/nikolaposa/MobileDetectModule) facilitates integration of a PHP MobileDetect
|
||||
class with some ZF2-based application. Has similar idea like the existing ZF2 Mobile-Detect module,
|
||||
but differs in initialization and provision routine of the actual Mobile_Detect class.
|
||||
Appropriate view helper and controller plugin also have different conceptions.
|
||||
Made by [Nikola Posa](https://github.com/nikolaposa).
|
||||
|
||||
**Symfony**
|
||||
|
||||
* [Symfony2 Mobile Detect Bundle](https://github.com/suncat2000/MobileDetectBundle) is a bundle for detecting mobile devices,
|
||||
manage mobile view and redirect to the mobile and tablet version.
|
||||
Made by [Nikolay Ivlev](https://github.com/suncat2000).
|
||||
|
||||
* [Silex Mobile Detect Service Provider](https://github.com/jbinfo/MobileDetectServiceProvider) is a service provider to
|
||||
interact with Mobile detect class methods.
|
||||
Made by [Lhassan Baazzi](https://github.com/jbinfo).
|
||||
|
||||
**Slim Framework**
|
||||
|
||||
* [Slim_Mobile_Detect](https://github.com/zguillez/slim_mobile_detect) implements Mobile_Detect lib for different
|
||||
responses write on Slim Framework App.
|
||||
|
||||
**ExpressionEngine**
|
||||
|
||||
* [EE2 Detect Mobile](https://github.com/garethtdavies/detect-mobile) is a lightweight PHP plugin for EE2 that detects
|
||||
a mobile browser using the Mobile Detect class. Made by [Gareth Davies](https://github.com/garethtdavies).
|
||||
|
||||
**Yii Framework**
|
||||
|
||||
* [Yii Extension](https://github.com/iamsalnikov/MobileDetect) - Mobile detect plugin for Yii framework.
|
||||
Made by [Alexey Salnikov](https://github.com/iamsalnikov).
|
||||
|
||||
* [Yii Extension](https://github.com/candasm/yii1-mobile-detect-component) - Mobile detect component for Yii framework
|
||||
1.x version which supports composer package manager. Made by [Candas Minareci](https://github.com/candasm).
|
||||
|
||||
* [Yii2 Device Detect](https://github.com/alexandernst/yii2-device-detect/) - Yii2 extension for Mobile-Detect library.
|
||||
Made by [Alexander Nestorov](https://github.com/alexandernst).
|
||||
|
||||
**CakePHP**
|
||||
|
||||
* [CakePHP MobileDetect](https://github.com/chronon/CakePHP-MobileDetectComponent-Plugin) is a plugin component for
|
||||
CakePHP 2.x. Made by [Gregory Gaskill](https://github.com/chronon).
|
||||
|
||||
**FuelPHP**
|
||||
|
||||
* [Special Agent](https://github.com/rob-bar/special_agent) is a FuelPHP package which uses php-mobile-detect to
|
||||
determine whether a device is mobile or not. It overrides the Fuelphp Agent class its methods.
|
||||
Made by [Robbie Bardjin](https://github.com/rob-bar).
|
||||
|
||||
|
||||
**TYPO3**
|
||||
|
||||
* [px_mobiledetect](https://typo3.org/extensions/repository/view/px_mobiledetect) is an extension that helps to detect
|
||||
visitor's mobile device class (if that’s tablet or mobile device like smartphone). Made by Alexander Tretyak.
|
||||
|
||||
**Other**
|
||||
|
||||
* [PageCache](https://github.com/mmamedov/page-cache) is a lightweight PHP library for full page cache,
|
||||
with built-in Mobile-Detect support. Made by [Muhammed Mamedov](https://github.com/mmamedov).
|
||||
|
||||
* [Statamic CMS Mobile Detect](https://github.com/haikulab/statamic-mobile-detect) is a plugin.
|
||||
Made by [Sergei Filippov](https://github.com/haikulab/statamic-mobile-detect) of Haiku Lab.
|
||||
|
||||
* [Kohana Mobile Detect](https://github.com/madeinnordeste/kohana-mobile-detect) is an example of implementation of
|
||||
Mobile_Detect class with Kohana framework.
|
||||
Written by [Luiz Alberto S. Ribeiro](https://github.com/madeinnordeste).
|
||||
|
||||
* [MemHT](https://www.memht.com) is a Free PHP CMS and Blog that permit the creation and the management online
|
||||
of websites with few and easy steps. Has the class included in the core.
|
||||
|
||||
* [concrete5](https://www.concrete5.org) is a CMS that is free and open source. The library is included in the core.
|
||||
|
||||
* [engine7](https://github.com/QOXCorp/exengine) is PHP Open Source Framework. The Mobile_Detect class is included in
|
||||
the engine.
|
||||
|
||||
* [Zikula](http://zikula.org) is a free and open-source Content Management Framework, which allows you to run
|
||||
impressive websites and build powerful online applications. The core uses Mobile-Detect to switch to a special
|
||||
Mobile theme, using jQueryMobile.
|
||||
|
||||
* [UserAgentInfo](https://github.com/quentin389/UserAgentInfo) is a PHP class for parsing user agent strings
|
||||
(HTTP_USER_AGENT). Includes mobile checks, bot checks, browser types/versions and more.
|
||||
Based on browscap, Mobile_Detect and ua-parser. Created for high traffic websites and fast batch processing.
|
||||
Made by [quentin389](https://github.com/quentin389).
|
||||
|
||||
* [LJ Mobile Detect](https://github.com/lewisjenkins/craft-lj-mobiledetect) is a simple implementation of Mobile Detect
|
||||
for Craft CMS. Made by [Lewis Jenkins](https://github.com/lewisjenkins).
|
||||
|
||||
* [Grav Plugin Mobile Detect](https://github.com/dimitrilongo/grav-plugin-mobile-detect/) is a simple implementation
|
||||
of Mobile Detect for Grav CMS. Made by [Dimitri Longo](https://github.com/dimitrilongo).
|
||||
|
||||
|
||||
**Perl**
|
||||
|
||||
* [MobileDetect.pm](https://www.buzzerstar.com/development/) is a Perl module for Mobile Detect.
|
||||
Made by [Sebastian Enger](https://devop.tools/).
|
||||
|
||||
**Python**
|
||||
|
||||
* [pymobiledetect](https://pypi.python.org/pypi/pymobiledetect) - Mobile detect python package.
|
||||
Made by Bas van Oostveen.
|
||||
|
||||
**Ruby**
|
||||
|
||||
* [mobile_detect.rb](https://github.com/ktaragorn/mobile_detect) is a Ruby gem using the JSON data exposed by the
|
||||
php project and implementing a basic subset of the API (as much as can be done by the exposed data).
|
||||
Made by [Karthik T](https://github.com/ktaragorn).
|
||||
|
||||
**Go**
|
||||
|
||||
* [GoMobileDetect](https://github.com/Shaked/gomobiledetect) is a Go port of Mobile Detect class.
|
||||
Made by [https://github.com/Shaked](Shaked).
|
||||
|
||||
|
||||
**LUA**
|
||||
|
||||
* [ua-lua](https://github.com/robinef/ua-lua) is a small lib written in LUA providing device type detection.
|
||||
ua-lua is detecting mobile or tablet devices based on user-agent inside nginx daemon.
|
||||
Made by [Frédéric Robinet](https://github.com/robinef).
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@
|
|||
"php": ">=5.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*",
|
||||
"johnkary/phpunit-speedtrap": "~1.0@dev",
|
||||
"codeclimate/php-test-reporter": "dev-master"
|
||||
"phpunit/phpunit": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": ["Mobile_Detect.php"],
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ class Client
|
|||
public function __construct($client_id, $client_secret, $client_auth = self::AUTH_TYPE_URI, $certificate_file = null)
|
||||
{
|
||||
if (!extension_loaded('curl')) {
|
||||
throw new Exception('The PHP exention curl must be installed to use this library.', Exception::CURL_NOT_FOUND);
|
||||
throw new Exception('The PHP extension curl must be installed to use this library.', Exception::CURL_NOT_FOUND);
|
||||
}
|
||||
|
||||
$this->client_id = $client_id;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -183,7 +183,6 @@ class Application extends \RainLoop\Config\AbstractConfig
|
|||
|
||||
'contacts' => array(
|
||||
'enable' => array(false, 'Enable contacts'),
|
||||
'allow_sharing' => array(true),
|
||||
'allow_sync' => array(false),
|
||||
'sync_interval' => array(20),
|
||||
'type' => array('sqlite', ''),
|
||||
|
|
@ -257,6 +256,8 @@ class Application extends \RainLoop\Config\AbstractConfig
|
|||
'forgot_password_link_url' => array('', ''),
|
||||
'registration_link_url' => array('', ''),
|
||||
|
||||
'login_lowercase' => array(true, ''),
|
||||
|
||||
'sign_me_auto' => array(\RainLoop\Enumerations\SignMeType::DEFAILT_OFF,
|
||||
'This option allows webmail to remember the logged in user
|
||||
once they closed the browser window.
|
||||
|
|
@ -385,7 +386,7 @@ Enables caching in the system'),
|
|||
'allow_prefetch' => array(true),
|
||||
'allow_smart_html_links' => array(true),
|
||||
'cache_system_data' => array(true),
|
||||
'date_from_headers' => array(false),
|
||||
'date_from_headers' => array(true),
|
||||
'autocreate_system_folders' => array(true),
|
||||
'allow_message_append' => array(false),
|
||||
'disable_iconv_if_mbstring_supported' => array(false),
|
||||
|
|
@ -393,10 +394,11 @@ Enables caching in the system'),
|
|||
'log_ajax_response_write_limit' => array(300),
|
||||
'allow_html_editor_source_button' => array(false),
|
||||
'allow_html_editor_biti_buttons' => array(false),
|
||||
'allow_ctrl_enter_on_compose' => array(false),
|
||||
'allow_ctrl_enter_on_compose' => array(true),
|
||||
'try_to_detect_hidden_images' => array(false),
|
||||
'hide_dangerous_actions' => array(false),
|
||||
'use_app_debug_js' => array(false),
|
||||
'use_mobile_version_for_tablets' => array(false),
|
||||
'use_app_debug_css' => array(false),
|
||||
'use_imap_sort' => array(true),
|
||||
'use_imap_force_selection' => array(false),
|
||||
|
|
@ -423,6 +425,7 @@ Enables caching in the system'),
|
|||
'sieve_allow_raw_script' => array(false),
|
||||
'sieve_utf8_folder_name' => array(true),
|
||||
'sieve_auth_plain_initial' => array(true),
|
||||
'sieve_allow_fileinto_inbox' => array(false),
|
||||
'imap_timeout' => array(300),
|
||||
'smtp_timeout' => array(60),
|
||||
'sieve_timeout' => array(10),
|
||||
|
|
|
|||
|
|
@ -1787,7 +1787,8 @@ CREATE TABLE IF NOT EXISTS rainloop_ab_properties (
|
|||
|
||||
PRIMARY KEY(id_prop),
|
||||
INDEX id_user_rainloop_ab_properties_index (id_user),
|
||||
INDEX id_user_id_contact_rainloop_ab_properties_index (id_user, id_contact)
|
||||
INDEX id_user_id_contact_rainloop_ab_properties_index (id_user, id_contact),
|
||||
INDEX id_contact_prop_type_rainloop_ab_properties_index (id_contact, prop_type)
|
||||
|
||||
)/*!40000 ENGINE=INNODB *//*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
|
|
|
|||
|
|
@ -150,8 +150,8 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage
|
|||
$sEmail = $mAccount;
|
||||
}
|
||||
|
||||
$sEmail = \preg_replace('/[^a-z0-9\-\.@]+/', '_', $sEmail);
|
||||
$sSubEmail = \preg_replace('/[^a-z0-9\-\.@]+/', '_', $sSubEmail);
|
||||
$sEmail = \preg_replace('/[^a-z0-9\-\.@]+/i', '_', $sEmail);
|
||||
$sSubEmail = \preg_replace('/[^a-z0-9\-\.@]+/i', '_', $sSubEmail);
|
||||
|
||||
$sTypePath = $sKeyPath = '';
|
||||
switch ($iStorageType)
|
||||
|
|
|
|||
|
|
@ -156,21 +156,26 @@ class Service
|
|||
|
||||
if ($this->oActions->Config()->Get('labs', 'allow_mobile_version', false))
|
||||
{
|
||||
$bUseMobileVersionForTablets = $this->oActions->Config()->Get('labs', 'use_mobile_version_for_tablets', false);
|
||||
|
||||
$oMobileDetect = new \Detection\MobileDetect();
|
||||
$bMobileDevice = $oMobileDetect->isMobile() && !$oMobileDetect->isTablet();
|
||||
$bMobileDevice = $oMobileDetect->isMobile() &&
|
||||
($bUseMobileVersionForTablets ? true : !$oMobileDetect->isTablet());
|
||||
|
||||
$bMobile = (0 < \count($aPaths) && !empty($aPaths[0]) && 'mobile' === \strtolower($aPaths[0]));
|
||||
}
|
||||
|
||||
if ($bIndex && !$bMobile)
|
||||
{
|
||||
$iMobileKey = (int) \RainLoop\Utils::GetCookie(\RainLoop\Actions::RL_SKIP_MOBILE_KEY, 0);
|
||||
if (1 !== $iMobileKey)
|
||||
if ($bIndex)
|
||||
{
|
||||
if ($bMobileDevice)
|
||||
{
|
||||
$this->oActions->Location('./?/Mobile/');
|
||||
return $this;
|
||||
$sMobileType = (string) \RainLoop\Utils::GetCookie(\RainLoop\Actions::RL_MOBILE_TYPE, '');
|
||||
switch ($sMobileType) {
|
||||
default:
|
||||
$sMobileType = '';
|
||||
$bMobile = $bMobileDevice;
|
||||
break;
|
||||
case 'mobile':
|
||||
$bMobile = true;
|
||||
break;
|
||||
case 'desktop':
|
||||
$bMobile = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -829,9 +829,9 @@ class ServiceActions
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function ServiceSkipMobile()
|
||||
public function ServiceMobileVersion()
|
||||
{
|
||||
\RainLoop\Utils::SetCookie(\RainLoop\Actions::RL_SKIP_MOBILE_KEY, 1);
|
||||
\RainLoop\Utils::SetCookie(\RainLoop\Actions::RL_MOBILE_TYPE, 'mobile');
|
||||
$this->oActions->Location('./');
|
||||
return '';
|
||||
}
|
||||
|
|
@ -839,9 +839,9 @@ class ServiceActions
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function ServiceClearSkipMobile()
|
||||
public function ServiceDesktopVersion()
|
||||
{
|
||||
\RainLoop\Utils::ClearCookie(\RainLoop\Actions::RL_SKIP_MOBILE_KEY);
|
||||
\RainLoop\Utils::SetCookie(\RainLoop\Actions::RL_MOBILE_TYPE, 'desktop');
|
||||
$this->oActions->Location('./');
|
||||
return '';
|
||||
}
|
||||
|
|
@ -1183,16 +1183,6 @@ class ServiceActions
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function ServiceChangeMobile()
|
||||
{
|
||||
$this->changeAction();
|
||||
$this->oActions->Location('./?/Mobile/');
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -61,7 +61,10 @@ class Utils
|
|||
if (!\class_exists('Crypt_RSA', false))
|
||||
{
|
||||
include_once 'Crypt/RSA.php';
|
||||
\defined('CRYPT_RSA_MODE') || \define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
|
||||
if (!\defined('CRYPT_RSA_MODE') && \defined('CRYPT_RSA_MODE_INTERNAL'))
|
||||
{
|
||||
\define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
|
||||
}
|
||||
}
|
||||
|
||||
if (\class_exists('Crypt_RSA'))
|
||||
|
|
|
|||
404
rainloop/v/0.0.0/app/libraries/phpseclib/Crypt/AES.php
Normal file → Executable file
404
rainloop/v/0.0.0/app/libraries/phpseclib/Crypt/AES.php
Normal file → Executable file
|
|
@ -1,207 +1,197 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of AES.
|
||||
*
|
||||
* Uses mcrypt, if available/possible, and an internal implementation, otherwise.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
|
||||
* {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
|
||||
* it'll be null-padded to 192-bits and 192 bits will be the key length until {@link Crypt_AES::setKey() setKey()}
|
||||
* is called, again, at which point, it'll be recalculated.
|
||||
*
|
||||
* Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't
|
||||
* make a whole lot of sense. {@link Crypt_AES::setBlockLength() setBlockLength()}, for instance. Calling that function,
|
||||
* however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
|
||||
*
|
||||
* Here's a short example of how to use this library:
|
||||
* <code>
|
||||
* <?php
|
||||
* include 'Crypt/AES.php';
|
||||
*
|
||||
* $aes = new Crypt_AES();
|
||||
*
|
||||
* $aes->setKey('abcdefghijklmnop');
|
||||
*
|
||||
* $size = 10 * 1024;
|
||||
* $plaintext = '';
|
||||
* for ($i = 0; $i < $size; $i++) {
|
||||
* $plaintext.= 'a';
|
||||
* }
|
||||
*
|
||||
* echo $aes->decrypt($aes->encrypt($plaintext));
|
||||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Crypt_AES
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2008 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
/**
|
||||
* Include Crypt_Rijndael
|
||||
*/
|
||||
if (!class_exists('Crypt_Rijndael')) {
|
||||
include_once 'Rijndael.php';
|
||||
}
|
||||
|
||||
/**#@+
|
||||
* @access public
|
||||
* @see Crypt_AES::encrypt()
|
||||
* @see Crypt_AES::decrypt()
|
||||
*/
|
||||
/**
|
||||
* Encrypt / decrypt using the Counter mode.
|
||||
*
|
||||
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR);
|
||||
/**
|
||||
* Encrypt / decrypt using the Electronic Code Book mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB);
|
||||
/**
|
||||
* Encrypt / decrypt using the Code Book Chaining mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC);
|
||||
/**
|
||||
* Encrypt / decrypt using the Cipher Feedback mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB);
|
||||
/**
|
||||
* Encrypt / decrypt using the Cipher Feedback mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
*/
|
||||
/**
|
||||
* Toggles the internal implementation
|
||||
*/
|
||||
define('CRYPT_AES_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
|
||||
/**
|
||||
* Toggles the mcrypt implementation
|
||||
*/
|
||||
define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of AES.
|
||||
*
|
||||
* @package Crypt_AES
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class Crypt_AES extends Crypt_Rijndael
|
||||
{
|
||||
/**
|
||||
* The namespace used by the cipher for its constants.
|
||||
*
|
||||
* @see Crypt_Base::const_namespace
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $const_namespace = 'AES';
|
||||
|
||||
/**
|
||||
* Dummy function
|
||||
*
|
||||
* Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
|
||||
*
|
||||
* @see Crypt_Rijndael::setBlockLength()
|
||||
* @access public
|
||||
* @param Integer $length
|
||||
*/
|
||||
function setBlockLength($length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key length
|
||||
*
|
||||
* Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
|
||||
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
|
||||
*
|
||||
* @see Crypt_Rijndael:setKeyLength()
|
||||
* @access public
|
||||
* @param Integer $length
|
||||
*/
|
||||
function setKeyLength($length)
|
||||
{
|
||||
switch ($length) {
|
||||
case 160:
|
||||
$length = 192;
|
||||
break;
|
||||
case 224:
|
||||
$length = 256;
|
||||
}
|
||||
parent::setKeyLength($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key.
|
||||
*
|
||||
* Rijndael supports five different key lengths, AES only supports three.
|
||||
*
|
||||
* @see Crypt_Rijndael:setKey()
|
||||
* @see setKeyLength()
|
||||
* @access public
|
||||
* @param String $key
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
parent::setKey($key);
|
||||
|
||||
if (!$this->explicit_key_length) {
|
||||
$length = strlen($key);
|
||||
switch (true) {
|
||||
case $length <= 16:
|
||||
$this->key_size = 16;
|
||||
break;
|
||||
case $length <= 24:
|
||||
$this->key_size = 24;
|
||||
break;
|
||||
default:
|
||||
$this->key_size = 32;
|
||||
}
|
||||
$this->_setupEngine();
|
||||
}
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of AES.
|
||||
*
|
||||
* Uses mcrypt, if available/possible, and an internal implementation, otherwise.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* NOTE: Since AES.php is (for compatibility and phpseclib-historical reasons) virtually
|
||||
* just a wrapper to Rijndael.php you may consider using Rijndael.php instead of
|
||||
* to save one include_once().
|
||||
*
|
||||
* If {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
|
||||
* {@link self::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
|
||||
* it'll be null-padded to 192-bits and 192 bits will be the key length until {@link self::setKey() setKey()}
|
||||
* is called, again, at which point, it'll be recalculated.
|
||||
*
|
||||
* Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't
|
||||
* make a whole lot of sense. {@link self::setBlockLength() setBlockLength()}, for instance. Calling that function,
|
||||
* however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
|
||||
*
|
||||
* Here's a short example of how to use this library:
|
||||
* <code>
|
||||
* <?php
|
||||
* include 'Crypt/AES.php';
|
||||
*
|
||||
* $aes = new Crypt_AES();
|
||||
*
|
||||
* $aes->setKey('abcdefghijklmnop');
|
||||
*
|
||||
* $size = 10 * 1024;
|
||||
* $plaintext = '';
|
||||
* for ($i = 0; $i < $size; $i++) {
|
||||
* $plaintext.= 'a';
|
||||
* }
|
||||
*
|
||||
* echo $aes->decrypt($aes->encrypt($plaintext));
|
||||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Crypt_AES
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2008 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
/**
|
||||
* Include Crypt_Rijndael
|
||||
*/
|
||||
if (!class_exists('Crypt_Rijndael')) {
|
||||
include_once 'Rijndael.php';
|
||||
}
|
||||
|
||||
/**#@+
|
||||
* @access public
|
||||
* @see self::encrypt()
|
||||
* @see self::decrypt()
|
||||
*/
|
||||
/**
|
||||
* Encrypt / decrypt using the Counter mode.
|
||||
*
|
||||
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR);
|
||||
/**
|
||||
* Encrypt / decrypt using the Electronic Code Book mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB);
|
||||
/**
|
||||
* Encrypt / decrypt using the Code Book Chaining mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC);
|
||||
/**
|
||||
* Encrypt / decrypt using the Cipher Feedback mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB);
|
||||
/**
|
||||
* Encrypt / decrypt using the Cipher Feedback mode.
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
|
||||
*/
|
||||
define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of AES.
|
||||
*
|
||||
* @package Crypt_AES
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class Crypt_AES extends Crypt_Rijndael
|
||||
{
|
||||
/**
|
||||
* The namespace used by the cipher for its constants.
|
||||
*
|
||||
* @see Crypt_Base::const_namespace
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $const_namespace = 'AES';
|
||||
|
||||
/**
|
||||
* Dummy function
|
||||
*
|
||||
* Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
|
||||
*
|
||||
* @see Crypt_Rijndael::setBlockLength()
|
||||
* @access public
|
||||
* @param int $length
|
||||
*/
|
||||
function setBlockLength($length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key length
|
||||
*
|
||||
* Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
|
||||
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
|
||||
*
|
||||
* @see Crypt_Rijndael:setKeyLength()
|
||||
* @access public
|
||||
* @param int $length
|
||||
*/
|
||||
function setKeyLength($length)
|
||||
{
|
||||
switch ($length) {
|
||||
case 160:
|
||||
$length = 192;
|
||||
break;
|
||||
case 224:
|
||||
$length = 256;
|
||||
}
|
||||
parent::setKeyLength($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key.
|
||||
*
|
||||
* Rijndael supports five different key lengths, AES only supports three.
|
||||
*
|
||||
* @see Crypt_Rijndael:setKey()
|
||||
* @see setKeyLength()
|
||||
* @access public
|
||||
* @param string $key
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
parent::setKey($key);
|
||||
|
||||
if (!$this->explicit_key_length) {
|
||||
$length = strlen($key);
|
||||
switch (true) {
|
||||
case $length <= 16:
|
||||
$this->key_length = 16;
|
||||
break;
|
||||
case $length <= 24:
|
||||
$this->key_length = 24;
|
||||
break;
|
||||
default:
|
||||
$this->key_length = 32;
|
||||
}
|
||||
$this->_setEngine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4671
rainloop/v/0.0.0/app/libraries/phpseclib/Crypt/Base.php
Normal file → Executable file
4671
rainloop/v/0.0.0/app/libraries/phpseclib/Crypt/Base.php
Normal file → Executable file
File diff suppressed because it is too large
Load diff
1288
rainloop/v/0.0.0/app/libraries/phpseclib/Crypt/Blowfish.php
Normal file → Executable file
1288
rainloop/v/0.0.0/app/libraries/phpseclib/Crypt/Blowfish.php
Normal file → Executable file
File diff suppressed because it is too large
Load diff
3022
rainloop/v/0.0.0/app/libraries/phpseclib/Crypt/DES.php
Normal file → Executable file
3022
rainloop/v/0.0.0/app/libraries/phpseclib/Crypt/DES.php
Normal file → Executable file
File diff suppressed because it is too large
Load diff
1770
rainloop/v/0.0.0/app/libraries/phpseclib/Crypt/Hash.php
Normal file → Executable file
1770
rainloop/v/0.0.0/app/libraries/phpseclib/Crypt/Hash.php
Normal file → Executable file
File diff suppressed because it is too large
Load diff
1413
rainloop/v/0.0.0/app/libraries/phpseclib/Crypt/RC2.php
Normal file → Executable file
1413
rainloop/v/0.0.0/app/libraries/phpseclib/Crypt/RC2.php
Normal file → Executable file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue