Augmentation vers version 3.3.0

This commit is contained in:
Gauvain Boiché
2020-03-31 15:31:03 +02:00
parent d926806907
commit a1864c0414
2618 changed files with 406015 additions and 31377 deletions

View File

@@ -1,24 +1,38 @@
<?php
/*
/**
* @package s9e\TextFormatter
* @copyright Copyright (c) 2010-2019 The s9e Authors
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
namespace s9e\TextFormatter\Utils;
use s9e\TextFormatter\Utils\Http\Clients\Cached;
use s9e\TextFormatter\Utils\Http\Clients\Curl;
use s9e\TextFormatter\Utils\Http\Clients\Native;
abstract class Http
{
/**
* Instantiate and return an HTTP client
*
* @return Http\Client
*/
public static function getClient()
{
return (\extension_loaded('curl')) ? new Curl : new Native;
return (extension_loaded('curl')) ? new Curl : new Native;
}
public static function getCachingClient($cacheDir = \null)
/**
* Instantiate and return a caching HTTP client
*
* @param string $cacheDir
* @return Cached
*/
public static function getCachingClient($cacheDir = null)
{
$client = new Cached(self::getClient());
$client->cacheDir = (isset($cacheDir)) ? $cacheDir : \sys_get_temp_dir();
$client->cacheDir = (isset($cacheDir)) ? $cacheDir : sys_get_temp_dir();
return $client;
}
}

View File

@@ -1,15 +1,40 @@
<?php
/*
/**
* @package s9e\TextFormatter
* @copyright Copyright (c) 2010-2019 The s9e Authors
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
namespace s9e\TextFormatter\Utils\Http;
abstract class Client
{
public $sslVerifyPeer = \false;
/**
* @var bool Whether to verify the peer's SSL certificate
*/
public $sslVerifyPeer = false;
/**
* @var integer Request timeout
*/
public $timeout = 10;
abstract public function get($url, $headers = []);
abstract public function post($url, $headers = [], $body = '');
/**
* Execute a GET request and return the response's body
*
* @param string $url Request URL
* @param array $options Request options
* @return string|bool Response content or FALSE
*/
abstract public function get($url, array $options = []);
/**
* Execute a POST request and return the response's body
*
* @param string $url Request URL
* @param array $options Request options
* @param string $body Request body
* @return string|bool Response content or FALSE
*/
abstract public function post($url, array $options = [], $body = '');
}

View File

@@ -1,54 +1,108 @@
<?php
/*
/**
* @package s9e\TextFormatter
* @copyright Copyright (c) 2010-2019 The s9e Authors
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
namespace s9e\TextFormatter\Utils\Http\Clients;
use s9e\TextFormatter\Utils\Http\Client;
class Cached extends Client
{
/**
* @var Client
*/
public $client;
/**
* @var string
*/
public $cacheDir;
/**
* @param Client $client
*/
public function __construct(Client $client)
{
$this->client = $client;
$this->timeout = $client->timeout;
$this->sslVerifyPeer = $client->sslVerifyPeer;
}
public function get($url, $headers = [])
/**
* {@inheritdoc}
*/
public function get($url, array $options = [])
{
$filepath = $this->getCachedFilepath([$url, $headers]);
if (isset($filepath) && \file_exists(\preg_replace('(^compress\\.zlib://)', '', $filepath)))
return \file_get_contents($filepath);
$content = $this->getClient()->get($url, $headers);
if (isset($filepath) && $content !== \false)
\file_put_contents($filepath, $content);
$filepath = $this->getCachedFilepath([$url, $options]);
if (isset($filepath) && file_exists(preg_replace('(^compress\\.zlib://)', '', $filepath)))
{
return file_get_contents($filepath);
}
$content = $this->getClient()->get($url, $options);
if (isset($filepath) && $content !== false)
{
file_put_contents($filepath, $content);
}
return $content;
}
public function post($url, $headers = [], $body = '')
/**
* {@inheritdoc}
*/
public function post($url, array $options = [], $body = '')
{
return $this->getClient()->post($url, $headers, $body);
return $this->getClient()->post($url, $options, $body);
}
/**
* Generate and return a filepath that matches given vars
*
* @param array $vars
* @return string
*/
protected function getCachedFilepath(array $vars)
{
if (!isset($this->cacheDir))
return \null;
{
return null;
}
$filepath = $this->cacheDir . '/http.' . $this->getCacheKey($vars);
if (\extension_loaded('zlib'))
if (extension_loaded('zlib'))
{
$filepath = 'compress.zlib://' . $filepath . '.gz';
}
return $filepath;
}
/**
* Generate a key for a given set of values
*
* @param string[] $vars
* @return string
*/
protected function getCacheKey(array $vars)
{
return \strtr(\base64_encode(\sha1(\serialize($vars), \true)), '/', '_');
return strtr(base64_encode(sha1(serialize($vars), true)), '/', '_');
}
/**
* Return cached client configured with this client's options
*
* @return Client
*/
protected function getClient()
{
$this->client->timeout = $this->timeout;
$this->client->sslVerifyPeer = $this->sslVerifyPeer;
return $this->client;
}
}

View File

@@ -1,48 +1,86 @@
<?php
/*
/**
* @package s9e\TextFormatter
* @copyright Copyright (c) 2010-2019 The s9e Authors
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
namespace s9e\TextFormatter\Utils\Http\Clients;
use s9e\TextFormatter\Utils\Http\Client;
class Curl extends Client
{
/**
* @var resource cURL handle, shared across instances
*/
protected static $handle;
public function get($url, $headers = [])
/**
* {@inheritdoc}
*/
public function get($url, array $options = [])
{
$options += ['headers' => []];
$handle = $this->getHandle();
\curl_setopt($handle, \CURLOPT_HTTPGET, \true);
\curl_setopt($handle, \CURLOPT_HTTPHEADER, $headers);
\curl_setopt($handle, \CURLOPT_URL, $url);
return \curl_exec($handle);
curl_setopt($handle, CURLOPT_HEADER, !empty($options['returnHeaders']));
curl_setopt($handle, CURLOPT_HTTPGET, true);
curl_setopt($handle, CURLOPT_HTTPHEADER, $options['headers']);
curl_setopt($handle, CURLOPT_URL, $url);
return curl_exec($handle);
}
public function post($url, $headers = [], $body = '')
/**
* {@inheritdoc}
*/
public function post($url, array $options = [], $body = '')
{
$headers[] = 'Content-Length: ' . \strlen($body);
$options += ['headers' => []];
$options['headers'][] = 'Content-Length: ' . strlen($body);
$handle = $this->getHandle();
\curl_setopt($handle, \CURLOPT_HTTPHEADER, $headers);
\curl_setopt($handle, \CURLOPT_POST, \true);
\curl_setopt($handle, \CURLOPT_POSTFIELDS, $body);
\curl_setopt($handle, \CURLOPT_URL, $url);
return \curl_exec($handle);
curl_setopt($handle, CURLOPT_HEADER, !empty($options['returnHeaders']));
curl_setopt($handle, CURLOPT_HTTPHEADER, $options['headers']);
curl_setopt($handle, CURLOPT_POST, true);
curl_setopt($handle, CURLOPT_POSTFIELDS, $body);
curl_setopt($handle, CURLOPT_URL, $url);
return curl_exec($handle);
}
/**
* Return a globally cached cURL handle, configured for current instance
*
* @return resource
*/
protected function getHandle()
{
if (!isset(self::$handle))
{
self::$handle = $this->getNewHandle();
\curl_setopt(self::$handle, \CURLOPT_SSL_VERIFYPEER, $this->sslVerifyPeer);
\curl_setopt(self::$handle, \CURLOPT_TIMEOUT, $this->timeout);
}
curl_setopt(self::$handle, CURLOPT_SSL_VERIFYPEER, $this->sslVerifyPeer);
curl_setopt(self::$handle, CURLOPT_TIMEOUT, $this->timeout);
return self::$handle;
}
/**
* Create and return a new cURL handle
*
* @return resource
*/
protected function getNewHandle()
{
$handle = \curl_init();
\curl_setopt($handle, \CURLOPT_ENCODING, '');
\curl_setopt($handle, \CURLOPT_FAILONERROR, \true);
\curl_setopt($handle, \CURLOPT_FOLLOWLOCATION, \true);
\curl_setopt($handle, \CURLOPT_RETURNTRANSFER, \true);
$handle = curl_init();
curl_setopt($handle, CURLOPT_ENCODING, '');
curl_setopt($handle, CURLOPT_FAILONERROR, true);
curl_setopt($handle, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
return $handle;
}
}

View File

@@ -1,56 +1,125 @@
<?php
/*
/**
* @package s9e\TextFormatter
* @copyright Copyright (c) 2010-2019 The s9e Authors
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
namespace s9e\TextFormatter\Utils\Http\Clients;
use s9e\TextFormatter\Utils\Http\Client;
class Native extends Client
{
/**
* @var bool Whether to use gzip encoding
*/
public $gzipEnabled;
/**
* Constructor
*/
public function __construct()
{
$this->gzipEnabled = \extension_loaded('zlib');
$this->gzipEnabled = extension_loaded('zlib');
}
public function get($url, $headers = [])
/**
* {@inheritdoc}
*/
public function get($url, array $options = [])
{
return $this->request('GET', $url, $headers);
return $this->request('GET', $url, $options);
}
public function post($url, $headers = [], $body = '')
/**
* {@inheritdoc}
*/
public function post($url, array $options = [], $body = '')
{
return $this->request('POST', $url, $headers, $body);
return $this->request('POST', $url, $options, $body);
}
protected function createContext($method, array $headers, $body)
/**
* Create a stream context for given request
*
* @param string $method Request method
* @param array $options Request options
* @param string $body Request body
* @return resource
*/
protected function createContext($method, array $options, $body)
{
$contextOptions = [
'ssl' => ['verify_peer' => $this->sslVerifyPeer],
'http' => [
'method' => $method,
'timeout' => $this->timeout,
'header' => $this->generateHeaders($headers, $body),
'header' => $this->generateHeaders($options, $body),
'content' => $body
]
];
return \stream_context_create($contextOptions);
return stream_context_create($contextOptions);
}
/**
* Decompress given page if applicable
*
* @param string $content Response body, potentially compressed
* @return string Response body, uncompressed
*/
protected function decompress($content)
{
if ($this->gzipEnabled && \substr($content, 0, 2) === "\x1f\x8b")
return \gzdecode($content);
if ($this->gzipEnabled && substr($content, 0, 2) === "\x1f\x8b")
{
return gzdecode($content);
}
return $content;
}
protected function generateHeaders(array $headers, $body)
/**
* Generate a list of headers for given request
*
* @param array $options Request options
* @param string $body Request body
* @return string[]
*/
protected function generateHeaders(array $options, $body)
{
$options += ['headers' => []];
if ($this->gzipEnabled)
$headers[] = 'Accept-Encoding: gzip';
$headers[] = 'Content-Length: ' . \strlen($body);
return $headers;
{
$options['headers'][] = 'Accept-Encoding: gzip';
}
$options['headers'][] = 'Content-Length: ' . strlen($body);
return $options['headers'];
}
protected function request($method, $url, $headers, $body = '')
/**
* Execute an HTTP request
*
* @param string $method Request method
* @param string $url Request URL
* @param array $options Request options
* @return string|bool Response body or FALSE
*/
protected function request($method, $url, array $options, $body = '')
{
$response = @\file_get_contents($url, \false, $this->createContext($method, $headers, $body));
return (\is_string($response)) ? $this->decompress($response) : $response;
$response = @file_get_contents($url, false, $this->createContext($method, $options, $body));
if ($response === false)
{
return false;
}
$response = $this->decompress($response);
if (!empty($options['returnHeaders']))
{
$response = implode("\r\n", $http_response_header) . "\r\n\r\n" . $response;
}
return $response;
}
}

View File

@@ -1,43 +1,109 @@
<?php
/*
/**
* @package s9e\TextFormatter
* @copyright Copyright (c) 2010-2019 The s9e Authors
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
namespace s9e\TextFormatter\Utils;
use InvalidArgumentException;
abstract class XPath
{
/**
* Export a literal as an XPath expression
*
* @param mixed $value Literal, e.g. "foo"
* @return string XPath expression, e.g. "'foo'"
*/
public static function export($value)
{
if (!\is_scalar($value))
$callback = get_called_class() . '::export' . ucfirst(gettype($value));
if (!is_callable($callback))
{
throw new InvalidArgumentException(__METHOD__ . '() cannot export non-scalar values');
if (\is_int($value))
return (string) $value;
if (\is_float($value))
return \preg_replace('(\\.?0+$)', '', \sprintf('%F', $value));
return self::exportString((string) $value);
}
return $callback($value);
}
protected static function exportString($str)
/**
* Export given boolean value
*
* @param bool $value
* @return string
*/
protected static function exportBoolean(bool $value): string
{
if (\strpos($str, "'") === \false)
return ($value) ? 'true()' : 'false()';
}
/**
* Export given float value
*
* @param float $value
* @return string
*/
protected static function exportDouble(float $value): string
{
if (!is_finite($value))
{
throw new InvalidArgumentException(__METHOD__ . '() cannot export irrational numbers');
}
// Avoid locale issues by using sprintf()
return preg_replace('(\\.?0+$)', '', sprintf('%F', $value));
}
/**
* Export given integer value
*
* @param integer $value
* @return string
*/
protected static function exportInteger(int $value): string
{
return (string) $value;
}
/**
* Export a string as an XPath expression
*
* @param string $str Literal, e.g. "foo"
* @return string XPath expression, e.g. "'foo'"
*/
protected static function exportString(string $str): string
{
// foo becomes 'foo'
if (strpos($str, "'") === false)
{
return "'" . $str . "'";
if (\strpos($str, '"') === \false)
}
// d'oh becomes "d'oh"
if (strpos($str, '"') === false)
{
return '"' . $str . '"';
}
// This string contains both ' and ". XPath 1.0 doesn't have a mechanism to escape quotes,
// so we have to get creative and use concat() to join chunks in single quotes and chunks
// in double quotes
$toks = [];
$c = '"';
$pos = 0;
while ($pos < \strlen($str))
while ($pos < strlen($str))
{
$spn = \strcspn($str, $c, $pos);
$spn = strcspn($str, $c, $pos);
if ($spn)
{
$toks[] = $c . \substr($str, $pos, $spn) . $c;
$toks[] = $c . substr($str, $pos, $spn) . $c;
$pos += $spn;
}
$c = ($c === '"') ? "'" : '"';
}
return 'concat(' . \implode(',', $toks) . ')';
return 'concat(' . implode(',', $toks) . ')';
}
}