One Hat Cyber Team
Your IP:
216.73.216.176
Server IP:
198.54.114.155
Server:
Linux server71.web-hosting.com 4.18.0-513.18.1.lve.el8.x86_64 #1 SMP Thu Feb 22 12:55:50 UTC 2024 x86_64
Server Software:
LiteSpeed
PHP Version:
5.6.40
Create File
|
Create Folder
Execute
Dir :
~
/
proc
/
thread-self
/
root
/
proc
/
self
/
cwd
/
Edit File:
php-http.tar
guzzle7-adapter/src/Client.php 0000644 00000003407 15111300111 0012273 0 ustar 00 <?php declare(strict_types=1); namespace Http\Adapter\Guzzle7; use GuzzleHttp\Client as GuzzleClient; use GuzzleHttp\ClientInterface; use GuzzleHttp\HandlerStack; use GuzzleHttp\Middleware; use GuzzleHttp\Utils; use Http\Client\HttpAsyncClient; use Http\Client\HttpClient; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; /** * HTTP Adapter for Guzzle 7. * * @author Tobias Nyholm <tobias.nyholm@gmail.com> */ final class Client implements HttpClient, HttpAsyncClient { /** * @var ClientInterface */ private $guzzle; public function __construct(?ClientInterface $guzzle = null) { if (!$guzzle) { $guzzle = self::buildClient(); } $this->guzzle = $guzzle; } /** * Factory method to create the Guzzle 7 adapter with custom Guzzle configuration. */ public static function createWithConfig(array $config): Client { return new self(self::buildClient($config)); } /** * {@inheritdoc} */ public function sendRequest(RequestInterface $request): ResponseInterface { return $this->sendAsyncRequest($request)->wait(); } /** * {@inheritdoc} */ public function sendAsyncRequest(RequestInterface $request) { $promise = $this->guzzle->sendAsync($request); return new Promise($promise, $request); } /** * Build the Guzzle client instance. */ private static function buildClient(array $config = []): GuzzleClient { $handlerStack = new HandlerStack(Utils::chooseHandler()); $handlerStack->push(Middleware::prepareBody(), 'prepare_body'); $config = array_merge(['handler' => $handlerStack], $config); return new GuzzleClient($config); } } guzzle7-adapter/src/Exception/UnexpectedValueException.php 0000644 00000000256 15111300111 0017772 0 ustar 00 <?php namespace Http\Adapter\Guzzle7\Exception; use Http\Client\Exception; final class UnexpectedValueException extends \UnexpectedValueException implements Exception { } guzzle7-adapter/src/error_log 0000644 00000002410 15111300111 0012252 0 ustar 00 [19-Nov-2025 09:37:38 UTC] PHP Fatal error: Uncaught Error: Interface "Http\Client\HttpClient" not found in /home/fluxyjvi/public_html/project/vendor/php-http/guzzle7-adapter/src/Client.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/guzzle7-adapter/src/Client.php on line 22 [19-Nov-2025 16:10:20 UTC] PHP Fatal error: Uncaught Error: Interface "Http\Client\HttpClient" not found in /home/fluxyjvi/public_html/project/vendor/php-http/guzzle7-adapter/src/Client.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/guzzle7-adapter/src/Client.php on line 22 [25-Nov-2025 03:01:57 UTC] PHP Fatal error: Uncaught Error: Interface "Http\Promise\Promise" not found in /home/fluxyjvi/public_html/project/vendor/php-http/guzzle7-adapter/src/Promise.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/guzzle7-adapter/src/Promise.php on line 20 [25-Nov-2025 03:24:32 UTC] PHP Fatal error: Uncaught Error: Interface "Http\Client\HttpClient" not found in /home/fluxyjvi/public_html/project/vendor/php-http/guzzle7-adapter/src/Client.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/guzzle7-adapter/src/Client.php on line 22 guzzle7-adapter/src/Promise.php 0000644 00000007204 15111300111 0012472 0 ustar 00 <?php declare(strict_types=1); namespace Http\Adapter\Guzzle7; use GuzzleHttp\Exception as GuzzleExceptions; use GuzzleHttp\Promise\PromiseInterface; use Http\Adapter\Guzzle7\Exception\UnexpectedValueException; use Http\Client\Exception as HttplugException; use Http\Promise\Promise as HttpPromise; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; /** * Wrapper around Guzzle promises. * * @author Joel Wurtz <joel.wurtz@gmail.com> */ final class Promise implements HttpPromise { /** * @var PromiseInterface */ private $promise; /** * @var string State of the promise */ private $state; /** * @var ResponseInterface */ private $response; /** * @var HttplugException */ private $exception; /** * @var RequestInterface */ private $request; public function __construct(PromiseInterface $promise, RequestInterface $request) { $this->request = $request; $this->state = self::PENDING; $this->promise = $promise->then(function ($response) { $this->response = $response; $this->state = self::FULFILLED; return $response; }, function ($reason) use ($request) { $this->state = self::REJECTED; if ($reason instanceof HttplugException) { $this->exception = $reason; } elseif ($reason instanceof GuzzleExceptions\GuzzleException) { $this->exception = $this->handleException($reason, $request); } elseif ($reason instanceof \Throwable) { $this->exception = new HttplugException\TransferException('Invalid exception returned from Guzzle7', 0, $reason); } else { $this->exception = new UnexpectedValueException('Reason returned from Guzzle7 must be an Exception'); } throw $this->exception; }); } /** * {@inheritdoc} */ public function then(callable $onFulfilled = null, callable $onRejected = null) { return new static($this->promise->then($onFulfilled, $onRejected), $this->request); } /** * {@inheritdoc} */ public function getState() { return $this->state; } /** * {@inheritdoc} */ public function wait($unwrap = true) { $this->promise->wait(false); if ($unwrap) { if (self::REJECTED == $this->getState()) { throw $this->exception; } return $this->response; } } /** * Converts a Guzzle exception into an Httplug exception. * * @return HttplugException */ private function handleException(GuzzleExceptions\GuzzleException $exception, RequestInterface $request) { if ($exception instanceof GuzzleExceptions\ConnectException) { return new HttplugException\NetworkException($exception->getMessage(), $exception->getRequest(), $exception); } if ($exception instanceof GuzzleExceptions\RequestException) { // Make sure we have a response for the HttpException if ($exception->hasResponse()) { return new HttplugException\HttpException( $exception->getMessage(), $exception->getRequest(), $exception->getResponse(), $exception ); } return new HttplugException\RequestException($exception->getMessage(), $exception->getRequest(), $exception); } return new HttplugException\TransferException($exception->getMessage(), 0, $exception); } } guzzle7-adapter/README.md 0000644 00000002257 15111300111 0011036 0 ustar 00 # Guzzle 7 HTTP Adapter [](https://github.com/php-http/guzzle7-adapter/releases) [](LICENSE) [](https://packagist.org/packages/php-http/guzzle7-adapter) **Guzzle 7 HTTP Adapter.** ## Install Via Composer ``` bash $ composer require php-http/guzzle7-adapter ``` ## Documentation Please see the [official documentation](http://docs.php-http.org/en/latest/clients/guzzle7-adapter.html). ## Testing First launch the http server: ```bash $ ./vendor/bin/http_test_server > /dev/null 2>&1 & ``` Then the test suite: ``` bash $ composer test ``` ## Contributing Please see our [contributing guide](http://docs.php-http.org/en/latest/development/contributing.html). ## Security If you discover any security related issues, please contact us at [security@php-http.org](mailto:security@php-http.org). ## License The MIT License (MIT). Please see [License File](LICENSE) for more information. guzzle7-adapter/LICENSE 0000644 00000002065 15111300111 0010561 0 ustar 00 Copyright (c) 2020 PHP HTTP Team <team@php-http.org> 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. guzzle7-adapter/composer.json 0000644 00000002066 15111300111 0012277 0 ustar 00 { "name": "php-http/guzzle7-adapter", "description": "Guzzle 7 HTTP Adapter", "license": "MIT", "keywords": ["guzzle", "http"], "homepage": "http://httplug.io", "authors": [ { "name": "Tobias Nyholm", "email": "tobias.nyholm@gmail.com" } ], "require": { "php": "^7.2 | ^8.0", "php-http/httplug": "^2.0", "psr/http-client": "^1.0", "guzzlehttp/guzzle": "^7.0" }, "require-dev": { "phpunit/phpunit": "^8.0|^9.3", "php-http/client-integration-tests": "^3.0" }, "provide": { "php-http/client-implementation": "1.0", "php-http/async-client-implementation": "1.0", "psr/http-client-implementation": "1.0" }, "autoload": { "psr-4": { "Http\\Adapter\\Guzzle7\\": "src/" } }, "autoload-dev": { "psr-4": { "Http\\Adapter\\Guzzle7\\Tests\\": "tests/" } }, "extra": { "branch-alias": { "dev-master": "0.2.x-dev" } } } guzzle7-adapter/phpstan.neon.dist 0000644 00000000132 15111300111 0013045 0 ustar 00 parameters: level: 5 reportUnmatchedIgnoredErrors: false paths: - src guzzle7-adapter/psalm.baseline.xml 0000644 00000000430 15111300111 0013165 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <files psalm-version="3.14.2@3538fe1955d47f6ee926c0769d71af6db08aa488"> <file src="src/Promise.php"> <PossiblyNullArgument occurrences="1"> <code>$exception->getResponse()</code> </PossiblyNullArgument> </file> </files> guzzle7-adapter/psalm.xml 0000644 00000000743 15111300111 0011413 0 ustar 00 <?xml version="1.0"?> <psalm errorLevel="3" resolveFromConfigFile="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" errorBaseline="psalm.baseline.xml" > <projectFiles> <directory name="src" /> <ignoreFiles> <directory name="vendor" /> </ignoreFiles> </projectFiles> </psalm> guzzle7-adapter/CHANGELOG.md 0000644 00000000640 15111300111 0011362 0 ustar 00 # Change Log All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [1.0.0] - 2021-03-09 - Stable release - no changes since 0.1.1 ## [0.1.1] - 2020-10-21 * Allow installation with PHP 8 ## [0.1.0] - 2020-08-16 First release discovery/src/StreamFactoryDiscovery.php 0000644 00000001700 15111300111 0014504 0 ustar 00 <?php namespace Http\Discovery; use Http\Discovery\Exception\DiscoveryFailedException; use Http\Message\StreamFactory; /** * Finds a Stream Factory. * * @author Михаил Красильников <m.krasilnikov@yandex.ru> * * @deprecated This will be removed in 2.0. Consider using Psr17FactoryDiscovery. */ final class StreamFactoryDiscovery extends ClassDiscovery { /** * Finds a Stream Factory. * * @return StreamFactory * * @throws Exception\NotFoundException */ public static function find() { try { $streamFactory = static::findOneByType(StreamFactory::class); } catch (DiscoveryFailedException $e) { throw new NotFoundException('No stream factories found. To use Guzzle, Diactoros or Slim Framework factories install php-http/message and the chosen message implementation.', 0, $e); } return static::instantiateClass($streamFactory); } } discovery/src/HttpClientDiscovery.php 0000644 00000001610 15111300111 0013777 0 ustar 00 <?php namespace Http\Discovery; use Http\Client\HttpClient; use Http\Discovery\Exception\DiscoveryFailedException; /** * Finds an HTTP Client. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> * * @deprecated This will be removed in 2.0. Consider using Psr18ClientDiscovery. */ final class HttpClientDiscovery extends ClassDiscovery { /** * Finds an HTTP Client. * * @return HttpClient * * @throws Exception\NotFoundException */ public static function find() { try { $client = static::findOneByType(HttpClient::class); } catch (DiscoveryFailedException $e) { throw new NotFoundException('No HTTPlug clients found. Make sure to install a package providing "php-http/client-implementation". Example: "php-http/guzzle6-adapter".', 0, $e); } return static::instantiateClass($client); } } discovery/src/NotFoundException.php 0000644 00000000572 15111300111 0013452 0 ustar 00 <?php namespace Http\Discovery; /** * Thrown when a discovery does not find any matches. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> * * @deprecated since since version 1.0, and will be removed in 2.0. Use {@link \Http\Discovery\Exception\NotFoundException} instead. */ final class NotFoundException extends \Http\Discovery\Exception\NotFoundException { } discovery/src/Composer/Plugin.php 0000644 00000044573 15111300111 0013075 0 ustar 00 <?php namespace Http\Discovery\Composer; use Composer\Composer; use Composer\DependencyResolver\Pool; use Composer\EventDispatcher\EventSubscriberInterface; use Composer\Factory; use Composer\Installer; use Composer\IO\IOInterface; use Composer\Json\JsonFile; use Composer\Json\JsonManipulator; use Composer\Package\Locker; use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionSelector; use Composer\Plugin\PluginInterface; use Composer\Repository\InstalledRepositoryInterface; use Composer\Repository\RepositorySet; use Composer\Script\Event; use Composer\Script\ScriptEvents; use Composer\Util\Filesystem; use Http\Discovery\ClassDiscovery; /** * Auto-installs missing implementations. * * When a dependency requires both this package and one of the supported `*-implementation` * virtual packages, this plugin will auto-install a well-known implementation if none is * found. The plugin will first look at already installed packages and figure out the * preferred implementation to install based on the below stickyness rules (or on the first * listed implementation if no rules match.) * * Don't miss updating src/Strategy/Common*Strategy.php when adding a new supported package. * * @author Nicolas Grekas <p@tchwork.com> * * @internal */ class Plugin implements PluginInterface, EventSubscriberInterface { /** * Describes, for every supported virtual implementation, which packages * provide said implementation and which extra dependencies each package * requires to provide the implementation. */ private const PROVIDE_RULES = [ 'php-http/async-client-implementation' => [ 'symfony/http-client:>=6.3' => ['guzzlehttp/promises', 'psr/http-factory-implementation', 'php-http/httplug'], 'symfony/http-client' => ['guzzlehttp/promises', 'php-http/message-factory', 'psr/http-factory-implementation', 'php-http/httplug'], 'php-http/guzzle7-adapter' => [], 'php-http/guzzle6-adapter' => [], 'php-http/curl-client' => [], 'php-http/react-adapter' => [], ], 'php-http/client-implementation' => [ 'symfony/http-client:>=6.3' => ['psr/http-factory-implementation', 'php-http/httplug'], 'symfony/http-client' => ['php-http/message-factory', 'psr/http-factory-implementation', 'php-http/httplug'], 'php-http/guzzle7-adapter' => [], 'php-http/guzzle6-adapter' => [], 'php-http/cakephp-adapter' => [], 'php-http/curl-client' => [], 'php-http/react-adapter' => [], 'php-http/buzz-adapter' => [], 'php-http/artax-adapter' => [], 'kriswallsmith/buzz:^1' => [], ], 'psr/http-client-implementation' => [ 'symfony/http-client' => ['psr/http-factory-implementation', 'psr/http-client'], 'guzzlehttp/guzzle' => [], 'kriswallsmith/buzz:^1' => [], ], 'psr/http-message-implementation' => [ 'php-http/discovery' => ['psr/http-factory-implementation'], ], 'psr/http-factory-implementation' => [ 'nyholm/psr7' => [], 'guzzlehttp/psr7:>=2' => [], 'slim/psr7' => [], 'laminas/laminas-diactoros' => [], 'phalcon/cphalcon:^4' => [], 'http-interop/http-factory-guzzle' => [], 'http-interop/http-factory-diactoros' => [], 'http-interop/http-factory-slim' => [], 'httpsoft/http-message' => [], ], ]; /** * Describes which package should be preferred on the left side * depending on which one is already installed on the right side. */ private const STICKYNESS_RULES = [ 'symfony/http-client' => 'symfony/framework-bundle', 'php-http/guzzle7-adapter' => 'guzzlehttp/guzzle:^7', 'php-http/guzzle6-adapter' => 'guzzlehttp/guzzle:^6', 'php-http/guzzle5-adapter' => 'guzzlehttp/guzzle:^5', 'php-http/cakephp-adapter' => 'cakephp/cakephp', 'php-http/react-adapter' => 'react/event-loop', 'php-http/buzz-adapter' => 'kriswallsmith/buzz:^0.15.1', 'php-http/artax-adapter' => 'amphp/artax:^3', 'http-interop/http-factory-guzzle' => 'guzzlehttp/psr7:^1', 'http-interop/http-factory-slim' => 'slim/slim:^3', ]; private const INTERFACE_MAP = [ 'php-http/async-client-implementation' => [ 'Http\Client\HttpAsyncClient', ], 'php-http/client-implementation' => [ 'Http\Client\HttpClient', ], 'psr/http-client-implementation' => [ 'Psr\Http\Client\ClientInterface', ], 'psr/http-factory-implementation' => [ 'Psr\Http\Message\RequestFactoryInterface', 'Psr\Http\Message\ResponseFactoryInterface', 'Psr\Http\Message\ServerRequestFactoryInterface', 'Psr\Http\Message\StreamFactoryInterface', 'Psr\Http\Message\UploadedFileFactoryInterface', 'Psr\Http\Message\UriFactoryInterface', ], ]; public static function getSubscribedEvents(): array { return [ ScriptEvents::PRE_AUTOLOAD_DUMP => 'preAutoloadDump', ScriptEvents::POST_UPDATE_CMD => 'postUpdate', ]; } public function activate(Composer $composer, IOInterface $io): void { } public function deactivate(Composer $composer, IOInterface $io) { } public function uninstall(Composer $composer, IOInterface $io) { } public function postUpdate(Event $event) { $composer = $event->getComposer(); $repo = $composer->getRepositoryManager()->getLocalRepository(); $requires = [ $composer->getPackage()->getRequires(), $composer->getPackage()->getDevRequires(), ]; $pinnedAbstractions = []; $pinned = $composer->getPackage()->getExtra()['discovery'] ?? []; foreach (self::INTERFACE_MAP as $abstraction => $interfaces) { foreach (isset($pinned[$abstraction]) ? [] : $interfaces as $interface) { if (!isset($pinned[$interface])) { continue 2; } } $pinnedAbstractions[$abstraction] = true; } $missingRequires = $this->getMissingRequires($repo, $requires, 'project' === $composer->getPackage()->getType(), $pinnedAbstractions); $missingRequires = [ 'require' => array_fill_keys(array_merge([], ...array_values($missingRequires[0])), '*'), 'require-dev' => array_fill_keys(array_merge([], ...array_values($missingRequires[1])), '*'), 'remove' => array_fill_keys(array_merge([], ...array_values($missingRequires[2])), '*'), ]; if (!$missingRequires = array_filter($missingRequires)) { return; } $composerJsonContents = file_get_contents(Factory::getComposerFile()); $this->updateComposerJson($missingRequires, $composer->getConfig()->get('sort-packages')); $installer = null; // Find the composer installer, hack borrowed from symfony/flex foreach (debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT) as $trace) { if (isset($trace['object']) && $trace['object'] instanceof Installer) { $installer = $trace['object']; break; } } if (!$installer) { return; } $event->stopPropagation(); $dispatcher = $composer->getEventDispatcher(); $disableScripts = !method_exists($dispatcher, 'setRunScripts') || !((array) $dispatcher)["\0*\0runScripts"]; $composer = Factory::create($event->getIO(), null, false, $disableScripts); /** @var Installer $installer */ $installer = clone $installer; if (method_exists($installer, 'setAudit')) { $trace['object']->setAudit(false); } // we need a clone of the installer to preserve its configuration state but with our own service objects $installer->__construct( $event->getIO(), $composer->getConfig(), $composer->getPackage(), $composer->getDownloadManager(), $composer->getRepositoryManager(), $composer->getLocker(), $composer->getInstallationManager(), $composer->getEventDispatcher(), $composer->getAutoloadGenerator() ); if (method_exists($installer, 'setPlatformRequirementFilter')) { $installer->setPlatformRequirementFilter(((array) $trace['object'])["\0*\0platformRequirementFilter"]); } if (0 !== $installer->run()) { file_put_contents(Factory::getComposerFile(), $composerJsonContents); return; } $versionSelector = new VersionSelector(ClassDiscovery::safeClassExists(RepositorySet::class) ? new RepositorySet() : new Pool()); $updateComposerJson = false; foreach ($composer->getRepositoryManager()->getLocalRepository()->getPackages() as $package) { foreach (['require', 'require-dev'] as $key) { if (!isset($missingRequires[$key][$package->getName()])) { continue; } $updateComposerJson = true; $missingRequires[$key][$package->getName()] = $versionSelector->findRecommendedRequireVersion($package); } } if ($updateComposerJson) { $this->updateComposerJson($missingRequires, $composer->getConfig()->get('sort-packages')); $this->updateComposerLock($composer, $event->getIO()); } } public function getMissingRequires(InstalledRepositoryInterface $repo, array $requires, bool $isProject, array $pinnedAbstractions): array { $allPackages = []; $devPackages = method_exists($repo, 'getDevPackageNames') ? array_fill_keys($repo->getDevPackageNames(), true) : []; // One must require "php-http/discovery" // to opt-in for auto-installation of virtual package implementations if (!isset($requires[0]['php-http/discovery'])) { $requires = [[], []]; } foreach ($repo->getPackages() as $package) { $allPackages[$package->getName()] = true; if (1 < \count($names = $package->getNames(false))) { $allPackages += array_fill_keys($names, false); if (isset($devPackages[$package->getName()])) { $devPackages += $names; } } if (isset($package->getRequires()['php-http/discovery'])) { $requires[(int) isset($devPackages[$package->getName()])] += $package->getRequires(); } } $missingRequires = [[], [], []]; $versionParser = new VersionParser(); if (ClassDiscovery::safeClassExists(\Phalcon\Http\Message\RequestFactory::class, false)) { $missingRequires[0]['psr/http-factory-implementation'] = []; $missingRequires[1]['psr/http-factory-implementation'] = []; } foreach ($requires as $dev => $rules) { $abstractions = []; $rules = array_intersect_key(self::PROVIDE_RULES, $rules); while ($rules) { $abstraction = key($rules); if (isset($pinnedAbstractions[$abstraction])) { unset($rules[$abstraction]); continue; } $abstractions[] = $abstraction; foreach (array_shift($rules) as $candidate => $deps) { [$candidate, $version] = explode(':', $candidate, 2) + [1 => null]; if (!isset($allPackages[$candidate])) { continue; } if (null !== $version && !$repo->findPackage($candidate, $versionParser->parseConstraints($version))) { continue; } if ($isProject && !$dev && isset($devPackages[$candidate])) { $missingRequires[0][$abstraction] = [$candidate]; $missingRequires[2][$abstraction] = [$candidate]; } else { $missingRequires[$dev][$abstraction] = []; } foreach ($deps as $dep) { if (isset(self::PROVIDE_RULES[$dep])) { $rules[$dep] = self::PROVIDE_RULES[$dep]; } elseif (!isset($allPackages[$dep])) { $missingRequires[$dev][$abstraction][] = $dep; } elseif ($isProject && !$dev && isset($devPackages[$dep])) { $missingRequires[0][$abstraction][] = $dep; $missingRequires[2][$abstraction][] = $dep; } } break; } } while ($abstractions) { $abstraction = array_shift($abstractions); if (isset($missingRequires[$dev][$abstraction])) { continue; } $candidates = self::PROVIDE_RULES[$abstraction]; foreach ($candidates as $candidate => $deps) { [$candidate, $version] = explode(':', $candidate, 2) + [1 => null]; if (null !== $version && !$repo->findPackage($candidate, $versionParser->parseConstraints($version))) { continue; } if (isset($allPackages[$candidate]) && (!$isProject || $dev || !isset($devPackages[$candidate]))) { continue 2; } } foreach (array_intersect_key(self::STICKYNESS_RULES, $candidates) as $candidate => $stickyRule) { [$stickyName, $stickyVersion] = explode(':', $stickyRule, 2) + [1 => null]; if (!isset($allPackages[$stickyName]) || ($isProject && !$dev && isset($devPackages[$stickyName]))) { continue; } if (null !== $stickyVersion && !$repo->findPackage($stickyName, $versionParser->parseConstraints($stickyVersion))) { continue; } $candidates = [$candidate => $candidates[$candidate]]; break; } $dep = key($candidates); [$dep] = explode(':', $dep, 2); $missingRequires[$dev][$abstraction] = [$dep]; if ($isProject && !$dev && isset($devPackages[$dep])) { $missingRequires[2][$abstraction][] = $dep; } } } $missingRequires[1] = array_diff_key($missingRequires[1], $missingRequires[0]); return $missingRequires; } public function preAutoloadDump(Event $event) { $filesystem = new Filesystem(); // Double realpath() on purpose, see https://bugs.php.net/72738 $vendorDir = $filesystem->normalizePath(realpath(realpath($event->getComposer()->getConfig()->get('vendor-dir')))); $filesystem->ensureDirectoryExists($vendorDir.'/composer'); $pinned = $event->getComposer()->getPackage()->getExtra()['discovery'] ?? []; $candidates = []; $allInterfaces = array_merge(...array_values(self::INTERFACE_MAP)); foreach ($pinned as $abstraction => $class) { if (isset(self::INTERFACE_MAP[$abstraction])) { $interfaces = self::INTERFACE_MAP[$abstraction]; } elseif (false !== $k = array_search($abstraction, $allInterfaces, true)) { $interfaces = [$allInterfaces[$k]]; } else { throw new \UnexpectedValueException(sprintf('Invalid "extra.discovery" pinned in composer.json: "%s" is not one of ["%s"].', $abstraction, implode('", "', array_keys(self::INTERFACE_MAP)))); } foreach ($interfaces as $interface) { $candidates[] = sprintf("case %s: return [['class' => %s]];\n", var_export($interface, true), var_export($class, true)); } } $file = $vendorDir.'/composer/GeneratedDiscoveryStrategy.php'; if (!$candidates) { if (file_exists($file)) { unlink($file); } return; } $candidates = implode(' ', $candidates); $code = <<<EOPHP <?php namespace Http\Discovery\Strategy; class GeneratedDiscoveryStrategy implements DiscoveryStrategy { public static function getCandidates(\$type) { switch (\$type) { $candidates default: return []; } } } EOPHP ; if (!file_exists($file) || $code !== file_get_contents($file)) { file_put_contents($file, $code); } $rootPackage = $event->getComposer()->getPackage(); $autoload = $rootPackage->getAutoload(); $autoload['classmap'][] = $vendorDir.'/composer/GeneratedDiscoveryStrategy.php'; $rootPackage->setAutoload($autoload); } private function updateComposerJson(array $missingRequires, bool $sortPackages) { $file = Factory::getComposerFile(); $contents = file_get_contents($file); $manipulator = new JsonManipulator($contents); foreach ($missingRequires as $key => $packages) { foreach ($packages as $package => $constraint) { if ('remove' === $key) { $manipulator->removeSubNode('require-dev', $package); } else { $manipulator->addLink($key, $package, $constraint, $sortPackages); } } } file_put_contents($file, $manipulator->getContents()); } private function updateComposerLock(Composer $composer, IOInterface $io) { $lock = substr(Factory::getComposerFile(), 0, -4).'lock'; $composerJson = file_get_contents(Factory::getComposerFile()); $lockFile = new JsonFile($lock, null, $io); $locker = ClassDiscovery::safeClassExists(RepositorySet::class) ? new Locker($io, $lockFile, $composer->getInstallationManager(), $composerJson) : new Locker($io, $lockFile, $composer->getRepositoryManager(), $composer->getInstallationManager(), $composerJson); $lockData = $locker->getLockData(); $lockData['content-hash'] = Locker::getContentHash($composerJson); $lockFile->write($lockData); } } discovery/src/MessageFactoryDiscovery.php 0000644 00000002127 15111300111 0014641 0 ustar 00 <?php namespace Http\Discovery; use Http\Discovery\Exception\DiscoveryFailedException; use Http\Message\MessageFactory; /** * Finds a Message Factory. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> * * @deprecated This will be removed in 2.0. Consider using Psr17FactoryDiscovery. */ final class MessageFactoryDiscovery extends ClassDiscovery { /** * Finds a Message Factory. * * @return MessageFactory * * @throws Exception\NotFoundException */ public static function find() { try { $messageFactory = static::findOneByType(MessageFactory::class); } catch (DiscoveryFailedException $e) { throw new NotFoundException('No php-http message factories found. Note that the php-http message factories are deprecated in favor of the PSR-17 message factories. To use the legacy Guzzle, Diactoros or Slim Framework factories of php-http, install php-http/message and php-http/message-factory and the chosen message implementation.', 0, $e); } return static::instantiateClass($messageFactory); } } discovery/src/Psr17FactoryDiscovery.php 0000644 00000007411 15111300111 0014172 0 ustar 00 <?php namespace Http\Discovery; use Http\Discovery\Exception\DiscoveryFailedException; use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\ServerRequestFactoryInterface; use Psr\Http\Message\StreamFactoryInterface; use Psr\Http\Message\UploadedFileFactoryInterface; use Psr\Http\Message\UriFactoryInterface; /** * Finds PSR-17 factories. * * @author Tobias Nyholm <tobias.nyholm@gmail.com> */ final class Psr17FactoryDiscovery extends ClassDiscovery { private static function createException($type, Exception $e) { return new \Http\Discovery\Exception\NotFoundException( 'No PSR-17 '.$type.' found. Install a package from this list: https://packagist.org/providers/psr/http-factory-implementation', 0, $e ); } /** * @return RequestFactoryInterface * * @throws Exception\NotFoundException */ public static function findRequestFactory() { try { $messageFactory = static::findOneByType(RequestFactoryInterface::class); } catch (DiscoveryFailedException $e) { throw self::createException('request factory', $e); } return static::instantiateClass($messageFactory); } /** * @return ResponseFactoryInterface * * @throws Exception\NotFoundException */ public static function findResponseFactory() { try { $messageFactory = static::findOneByType(ResponseFactoryInterface::class); } catch (DiscoveryFailedException $e) { throw self::createException('response factory', $e); } return static::instantiateClass($messageFactory); } /** * @return ServerRequestFactoryInterface * * @throws Exception\NotFoundException */ public static function findServerRequestFactory() { try { $messageFactory = static::findOneByType(ServerRequestFactoryInterface::class); } catch (DiscoveryFailedException $e) { throw self::createException('server request factory', $e); } return static::instantiateClass($messageFactory); } /** * @return StreamFactoryInterface * * @throws Exception\NotFoundException */ public static function findStreamFactory() { try { $messageFactory = static::findOneByType(StreamFactoryInterface::class); } catch (DiscoveryFailedException $e) { throw self::createException('stream factory', $e); } return static::instantiateClass($messageFactory); } /** * @return UploadedFileFactoryInterface * * @throws Exception\NotFoundException */ public static function findUploadedFileFactory() { try { $messageFactory = static::findOneByType(UploadedFileFactoryInterface::class); } catch (DiscoveryFailedException $e) { throw self::createException('uploaded file factory', $e); } return static::instantiateClass($messageFactory); } /** * @return UriFactoryInterface * * @throws Exception\NotFoundException */ public static function findUriFactory() { try { $messageFactory = static::findOneByType(UriFactoryInterface::class); } catch (DiscoveryFailedException $e) { throw self::createException('url factory', $e); } return static::instantiateClass($messageFactory); } /** * @return UriFactoryInterface * * @throws Exception\NotFoundException * * @deprecated This will be removed in 2.0. Consider using the findUriFactory() method. */ public static function findUrlFactory() { return static::findUriFactory(); } } discovery/src/Strategy/DiscoveryStrategy.php 0000644 00000001145 15111300111 0015330 0 ustar 00 <?php namespace Http\Discovery\Strategy; use Http\Discovery\Exception\StrategyUnavailableException; /** * @author Tobias Nyholm <tobias.nyholm@gmail.com> */ interface DiscoveryStrategy { /** * Find a resource of a specific type. * * @param string $type * * @return array The return value is always an array with zero or more elements. Each * element is an array with two keys ['class' => string, 'condition' => mixed]. * * @throws StrategyUnavailableException if we cannot use this strategy */ public static function getCandidates($type); } discovery/src/Strategy/MockClientStrategy.php 0000644 00000001034 15111300111 0015406 0 ustar 00 <?php namespace Http\Discovery\Strategy; use Http\Client\HttpAsyncClient; use Http\Client\HttpClient; use Http\Mock\Client as Mock; /** * Find the Mock client. * * @author Sam Rapaport <me@samrapdev.com> */ final class MockClientStrategy implements DiscoveryStrategy { public static function getCandidates($type) { if (is_a(HttpClient::class, $type, true) || is_a(HttpAsyncClient::class, $type, true)) { return [['class' => Mock::class, 'condition' => Mock::class]]; } return []; } } discovery/src/Strategy/CommonClassesStrategy.php 0000644 00000017050 15111300111 0016131 0 ustar 00 <?php namespace Http\Discovery\Strategy; use GuzzleHttp\Client as GuzzleHttp; use GuzzleHttp\Promise\Promise; use GuzzleHttp\Psr7\Request as GuzzleRequest; use Http\Adapter\Artax\Client as Artax; use Http\Adapter\Buzz\Client as Buzz; use Http\Adapter\Cake\Client as Cake; use Http\Adapter\Guzzle5\Client as Guzzle5; use Http\Adapter\Guzzle6\Client as Guzzle6; use Http\Adapter\Guzzle7\Client as Guzzle7; use Http\Adapter\React\Client as React; use Http\Client\Curl\Client as Curl; use Http\Client\HttpAsyncClient; use Http\Client\HttpClient; use Http\Client\Socket\Client as Socket; use Http\Discovery\ClassDiscovery; use Http\Discovery\Exception\NotFoundException; use Http\Discovery\Psr17FactoryDiscovery; use Http\Message\MessageFactory; use Http\Message\MessageFactory\DiactorosMessageFactory; use Http\Message\MessageFactory\GuzzleMessageFactory; use Http\Message\MessageFactory\SlimMessageFactory; use Http\Message\StreamFactory; use Http\Message\StreamFactory\DiactorosStreamFactory; use Http\Message\StreamFactory\GuzzleStreamFactory; use Http\Message\StreamFactory\SlimStreamFactory; use Http\Message\UriFactory; use Http\Message\UriFactory\DiactorosUriFactory; use Http\Message\UriFactory\GuzzleUriFactory; use Http\Message\UriFactory\SlimUriFactory; use Laminas\Diactoros\Request as DiactorosRequest; use Nyholm\Psr7\Factory\HttplugFactory as NyholmHttplugFactory; use Psr\Http\Client\ClientInterface as Psr18Client; use Psr\Http\Message\RequestFactoryInterface as Psr17RequestFactory; use Slim\Http\Request as SlimRequest; use Symfony\Component\HttpClient\HttplugClient as SymfonyHttplug; use Symfony\Component\HttpClient\Psr18Client as SymfonyPsr18; /** * @internal * * @author Tobias Nyholm <tobias.nyholm@gmail.com> * * Don't miss updating src/Composer/Plugin.php when adding a new supported class. */ final class CommonClassesStrategy implements DiscoveryStrategy { /** * @var array */ private static $classes = [ MessageFactory::class => [ ['class' => NyholmHttplugFactory::class, 'condition' => [NyholmHttplugFactory::class]], ['class' => GuzzleMessageFactory::class, 'condition' => [GuzzleRequest::class, GuzzleMessageFactory::class]], ['class' => DiactorosMessageFactory::class, 'condition' => [DiactorosRequest::class, DiactorosMessageFactory::class]], ['class' => SlimMessageFactory::class, 'condition' => [SlimRequest::class, SlimMessageFactory::class]], ], StreamFactory::class => [ ['class' => NyholmHttplugFactory::class, 'condition' => [NyholmHttplugFactory::class]], ['class' => GuzzleStreamFactory::class, 'condition' => [GuzzleRequest::class, GuzzleStreamFactory::class]], ['class' => DiactorosStreamFactory::class, 'condition' => [DiactorosRequest::class, DiactorosStreamFactory::class]], ['class' => SlimStreamFactory::class, 'condition' => [SlimRequest::class, SlimStreamFactory::class]], ], UriFactory::class => [ ['class' => NyholmHttplugFactory::class, 'condition' => [NyholmHttplugFactory::class]], ['class' => GuzzleUriFactory::class, 'condition' => [GuzzleRequest::class, GuzzleUriFactory::class]], ['class' => DiactorosUriFactory::class, 'condition' => [DiactorosRequest::class, DiactorosUriFactory::class]], ['class' => SlimUriFactory::class, 'condition' => [SlimRequest::class, SlimUriFactory::class]], ], HttpAsyncClient::class => [ ['class' => SymfonyHttplug::class, 'condition' => [SymfonyHttplug::class, Promise::class, [self::class, 'isPsr17FactoryInstalled']]], ['class' => Guzzle7::class, 'condition' => Guzzle7::class], ['class' => Guzzle6::class, 'condition' => Guzzle6::class], ['class' => Curl::class, 'condition' => Curl::class], ['class' => React::class, 'condition' => React::class], ], HttpClient::class => [ ['class' => SymfonyHttplug::class, 'condition' => [SymfonyHttplug::class, [self::class, 'isPsr17FactoryInstalled']]], ['class' => Guzzle7::class, 'condition' => Guzzle7::class], ['class' => Guzzle6::class, 'condition' => Guzzle6::class], ['class' => Guzzle5::class, 'condition' => Guzzle5::class], ['class' => Curl::class, 'condition' => Curl::class], ['class' => Socket::class, 'condition' => Socket::class], ['class' => Buzz::class, 'condition' => Buzz::class], ['class' => React::class, 'condition' => React::class], ['class' => Cake::class, 'condition' => Cake::class], ['class' => Artax::class, 'condition' => Artax::class], [ 'class' => [self::class, 'buzzInstantiate'], 'condition' => [\Buzz\Client\FileGetContents::class, \Buzz\Message\ResponseBuilder::class], ], ], Psr18Client::class => [ [ 'class' => [self::class, 'symfonyPsr18Instantiate'], 'condition' => [SymfonyPsr18::class, Psr17RequestFactory::class], ], [ 'class' => GuzzleHttp::class, 'condition' => [self::class, 'isGuzzleImplementingPsr18'], ], [ 'class' => [self::class, 'buzzInstantiate'], 'condition' => [\Buzz\Client\FileGetContents::class, \Buzz\Message\ResponseBuilder::class], ], ], ]; public static function getCandidates($type) { if (Psr18Client::class === $type) { return self::getPsr18Candidates(); } return self::$classes[$type] ?? []; } /** * @return array The return value is always an array with zero or more elements. Each * element is an array with two keys ['class' => string, 'condition' => mixed]. */ private static function getPsr18Candidates() { $candidates = self::$classes[Psr18Client::class]; // HTTPlug 2.0 clients implements PSR18Client too. foreach (self::$classes[HttpClient::class] as $c) { if (!is_string($c['class'])) { continue; } try { if (ClassDiscovery::safeClassExists($c['class']) && is_subclass_of($c['class'], Psr18Client::class)) { $candidates[] = $c; } } catch (\Throwable $e) { trigger_error(sprintf('Got exception "%s (%s)" while checking if a PSR-18 Client is available', get_class($e), $e->getMessage()), E_USER_WARNING); } } return $candidates; } public static function buzzInstantiate() { return new \Buzz\Client\FileGetContents(Psr17FactoryDiscovery::findResponseFactory()); } public static function symfonyPsr18Instantiate() { return new SymfonyPsr18(null, Psr17FactoryDiscovery::findResponseFactory(), Psr17FactoryDiscovery::findStreamFactory()); } public static function isGuzzleImplementingPsr18() { return defined('GuzzleHttp\ClientInterface::MAJOR_VERSION'); } /** * Can be used as a condition. * * @return bool */ public static function isPsr17FactoryInstalled() { try { Psr17FactoryDiscovery::findResponseFactory(); } catch (NotFoundException $e) { return false; } catch (\Throwable $e) { trigger_error(sprintf('Got exception "%s (%s)" while checking if a PSR-17 ResponseFactory is available', get_class($e), $e->getMessage()), E_USER_WARNING); return false; } return true; } } discovery/src/Strategy/PuliBetaStrategy.php 0000644 00000004276 15111300111 0015076 0 ustar 00 <?php namespace Http\Discovery\Strategy; use Http\Discovery\ClassDiscovery; use Http\Discovery\Exception\PuliUnavailableException; use Puli\Discovery\Api\Discovery; use Puli\GeneratedPuliFactory; /** * Find candidates using Puli. * * @internal * * @final * * @author David de Boer <david@ddeboer.nl> * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ class PuliBetaStrategy implements DiscoveryStrategy { /** * @var GeneratedPuliFactory */ protected static $puliFactory; /** * @var Discovery */ protected static $puliDiscovery; /** * @return GeneratedPuliFactory * * @throws PuliUnavailableException */ private static function getPuliFactory() { if (null === self::$puliFactory) { if (!defined('PULI_FACTORY_CLASS')) { throw new PuliUnavailableException('Puli Factory is not available'); } $puliFactoryClass = PULI_FACTORY_CLASS; if (!ClassDiscovery::safeClassExists($puliFactoryClass)) { throw new PuliUnavailableException('Puli Factory class does not exist'); } self::$puliFactory = new $puliFactoryClass(); } return self::$puliFactory; } /** * Returns the Puli discovery layer. * * @return Discovery * * @throws PuliUnavailableException */ private static function getPuliDiscovery() { if (!isset(self::$puliDiscovery)) { $factory = self::getPuliFactory(); $repository = $factory->createRepository(); self::$puliDiscovery = $factory->createDiscovery($repository); } return self::$puliDiscovery; } public static function getCandidates($type) { $returnData = []; $bindings = self::getPuliDiscovery()->findBindings($type); foreach ($bindings as $binding) { $condition = true; if ($binding->hasParameterValue('depends')) { $condition = $binding->getParameterValue('depends'); } $returnData[] = ['class' => $binding->getClassName(), 'condition' => $condition]; } return $returnData; } } discovery/src/Strategy/CommonPsr17ClassesStrategy.php 0000644 00000007560 15111300111 0016773 0 ustar 00 <?php namespace Http\Discovery\Strategy; use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\ServerRequestFactoryInterface; use Psr\Http\Message\StreamFactoryInterface; use Psr\Http\Message\UploadedFileFactoryInterface; use Psr\Http\Message\UriFactoryInterface; /** * @internal * * @author Tobias Nyholm <tobias.nyholm@gmail.com> * * Don't miss updating src/Composer/Plugin.php when adding a new supported class. */ final class CommonPsr17ClassesStrategy implements DiscoveryStrategy { /** * @var array */ private static $classes = [ RequestFactoryInterface::class => [ 'Phalcon\Http\Message\RequestFactory', 'Nyholm\Psr7\Factory\Psr17Factory', 'GuzzleHttp\Psr7\HttpFactory', 'Http\Factory\Diactoros\RequestFactory', 'Http\Factory\Guzzle\RequestFactory', 'Http\Factory\Slim\RequestFactory', 'Laminas\Diactoros\RequestFactory', 'Slim\Psr7\Factory\RequestFactory', 'HttpSoft\Message\RequestFactory', ], ResponseFactoryInterface::class => [ 'Phalcon\Http\Message\ResponseFactory', 'Nyholm\Psr7\Factory\Psr17Factory', 'GuzzleHttp\Psr7\HttpFactory', 'Http\Factory\Diactoros\ResponseFactory', 'Http\Factory\Guzzle\ResponseFactory', 'Http\Factory\Slim\ResponseFactory', 'Laminas\Diactoros\ResponseFactory', 'Slim\Psr7\Factory\ResponseFactory', 'HttpSoft\Message\ResponseFactory', ], ServerRequestFactoryInterface::class => [ 'Phalcon\Http\Message\ServerRequestFactory', 'Nyholm\Psr7\Factory\Psr17Factory', 'GuzzleHttp\Psr7\HttpFactory', 'Http\Factory\Diactoros\ServerRequestFactory', 'Http\Factory\Guzzle\ServerRequestFactory', 'Http\Factory\Slim\ServerRequestFactory', 'Laminas\Diactoros\ServerRequestFactory', 'Slim\Psr7\Factory\ServerRequestFactory', 'HttpSoft\Message\ServerRequestFactory', ], StreamFactoryInterface::class => [ 'Phalcon\Http\Message\StreamFactory', 'Nyholm\Psr7\Factory\Psr17Factory', 'GuzzleHttp\Psr7\HttpFactory', 'Http\Factory\Diactoros\StreamFactory', 'Http\Factory\Guzzle\StreamFactory', 'Http\Factory\Slim\StreamFactory', 'Laminas\Diactoros\StreamFactory', 'Slim\Psr7\Factory\StreamFactory', 'HttpSoft\Message\StreamFactory', ], UploadedFileFactoryInterface::class => [ 'Phalcon\Http\Message\UploadedFileFactory', 'Nyholm\Psr7\Factory\Psr17Factory', 'GuzzleHttp\Psr7\HttpFactory', 'Http\Factory\Diactoros\UploadedFileFactory', 'Http\Factory\Guzzle\UploadedFileFactory', 'Http\Factory\Slim\UploadedFileFactory', 'Laminas\Diactoros\UploadedFileFactory', 'Slim\Psr7\Factory\UploadedFileFactory', 'HttpSoft\Message\UploadedFileFactory', ], UriFactoryInterface::class => [ 'Phalcon\Http\Message\UriFactory', 'Nyholm\Psr7\Factory\Psr17Factory', 'GuzzleHttp\Psr7\HttpFactory', 'Http\Factory\Diactoros\UriFactory', 'Http\Factory\Guzzle\UriFactory', 'Http\Factory\Slim\UriFactory', 'Laminas\Diactoros\UriFactory', 'Slim\Psr7\Factory\UriFactory', 'HttpSoft\Message\UriFactory', ], ]; public static function getCandidates($type) { $candidates = []; if (isset(self::$classes[$type])) { foreach (self::$classes[$type] as $class) { $candidates[] = ['class' => $class, 'condition' => [$class]]; } } return $candidates; } } discovery/src/Exception.php 0000644 00000000314 15111300111 0011767 0 ustar 00 <?php namespace Http\Discovery; /** * An interface implemented by all discovery related exceptions. * * @author Tobias Nyholm <tobias.nyholm@gmail.com> */ interface Exception extends \Throwable { } discovery/src/Psr17Factory.php 0000644 00000026551 15111300111 0012310 0 ustar 00 <?php namespace Http\Discovery; use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestFactoryInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\StreamFactoryInterface; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UploadedFileFactoryInterface; use Psr\Http\Message\UploadedFileInterface; use Psr\Http\Message\UriFactoryInterface; use Psr\Http\Message\UriInterface; /** * A generic PSR-17 implementation. * * You can create this class with concrete factory instances or let * it use discovery to find suitable implementations as needed. * * This class also provides two additional methods that are not in PSR17, * to help with creating PSR-7 objects from PHP superglobals: * - createServerRequestFromGlobals() * - createUriFromGlobals() * * The code in this class is inspired by the "nyholm/psr7", "guzzlehttp/psr7" * and "symfony/http-foundation" packages, all licenced under MIT. * * Copyright (c) 2004-2023 Fabien Potencier <fabien@symfony.com> * Copyright (c) 2015 Michael Dowling <mtdowling@gmail.com> * Copyright (c) 2015 Márk Sági-Kazár <mark.sagikazar@gmail.com> * Copyright (c) 2015 Graham Campbell <hello@gjcampbell.co.uk> * Copyright (c) 2016 Tobias Schultze <webmaster@tubo-world.de> * Copyright (c) 2016 George Mponos <gmponos@gmail.com> * Copyright (c) 2016-2018 Tobias Nyholm <tobias.nyholm@gmail.com> * * @author Nicolas Grekas <p@tchwork.com> */ class Psr17Factory implements RequestFactoryInterface, ResponseFactoryInterface, ServerRequestFactoryInterface, StreamFactoryInterface, UploadedFileFactoryInterface, UriFactoryInterface { private $requestFactory; private $responseFactory; private $serverRequestFactory; private $streamFactory; private $uploadedFileFactory; private $uriFactory; public function __construct( RequestFactoryInterface $requestFactory = null, ResponseFactoryInterface $responseFactory = null, ServerRequestFactoryInterface $serverRequestFactory = null, StreamFactoryInterface $streamFactory = null, UploadedFileFactoryInterface $uploadedFileFactory = null, UriFactoryInterface $uriFactory = null ) { $this->requestFactory = $requestFactory; $this->responseFactory = $responseFactory; $this->serverRequestFactory = $serverRequestFactory; $this->streamFactory = $streamFactory; $this->uploadedFileFactory = $uploadedFileFactory; $this->uriFactory = $uriFactory; $this->setFactory($requestFactory); $this->setFactory($responseFactory); $this->setFactory($serverRequestFactory); $this->setFactory($streamFactory); $this->setFactory($uploadedFileFactory); $this->setFactory($uriFactory); } /** * @param UriInterface|string $uri */ public function createRequest(string $method, $uri): RequestInterface { $factory = $this->requestFactory ?? $this->setFactory(Psr17FactoryDiscovery::findRequestFactory()); return $factory->createRequest(...\func_get_args()); } public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface { $factory = $this->responseFactory ?? $this->setFactory(Psr17FactoryDiscovery::findResponseFactory()); return $factory->createResponse(...\func_get_args()); } /** * @param UriInterface|string $uri */ public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface { $factory = $this->serverRequestFactory ?? $this->setFactory(Psr17FactoryDiscovery::findServerRequestFactory()); return $factory->createServerRequest(...\func_get_args()); } public function createServerRequestFromGlobals(array $server = null, array $get = null, array $post = null, array $cookie = null, array $files = null, StreamInterface $body = null): ServerRequestInterface { $server = $server ?? $_SERVER; $request = $this->createServerRequest($server['REQUEST_METHOD'] ?? 'GET', $this->createUriFromGlobals($server), $server); return $this->buildServerRequestFromGlobals($request, $server, $files ?? $_FILES) ->withQueryParams($get ?? $_GET) ->withParsedBody($post ?? $_POST) ->withCookieParams($cookie ?? $_COOKIE) ->withBody($body ?? $this->createStreamFromFile('php://input', 'r+')); } public function createStream(string $content = ''): StreamInterface { $factory = $this->streamFactory ?? $this->setFactory(Psr17FactoryDiscovery::findStreamFactory()); return $factory->createStream($content); } public function createStreamFromFile(string $filename, string $mode = 'r'): StreamInterface { $factory = $this->streamFactory ?? $this->setFactory(Psr17FactoryDiscovery::findStreamFactory()); return $factory->createStreamFromFile($filename, $mode); } /** * @param resource $resource */ public function createStreamFromResource($resource): StreamInterface { $factory = $this->streamFactory ?? $this->setFactory(Psr17FactoryDiscovery::findStreamFactory()); return $factory->createStreamFromResource($resource); } public function createUploadedFile(StreamInterface $stream, int $size = null, int $error = \UPLOAD_ERR_OK, string $clientFilename = null, string $clientMediaType = null): UploadedFileInterface { $factory = $this->uploadedFileFactory ?? $this->setFactory(Psr17FactoryDiscovery::findUploadedFileFactory()); return $factory->createUploadedFile(...\func_get_args()); } public function createUri(string $uri = ''): UriInterface { $factory = $this->uriFactory ?? $this->setFactory(Psr17FactoryDiscovery::findUriFactory()); return $factory->createUri(...\func_get_args()); } public function createUriFromGlobals(array $server = null): UriInterface { return $this->buildUriFromGlobals($this->createUri(''), $server ?? $_SERVER); } private function setFactory($factory) { if (!$this->requestFactory && $factory instanceof RequestFactoryInterface) { $this->requestFactory = $factory; } if (!$this->responseFactory && $factory instanceof ResponseFactoryInterface) { $this->responseFactory = $factory; } if (!$this->serverRequestFactory && $factory instanceof ServerRequestFactoryInterface) { $this->serverRequestFactory = $factory; } if (!$this->streamFactory && $factory instanceof StreamFactoryInterface) { $this->streamFactory = $factory; } if (!$this->uploadedFileFactory && $factory instanceof UploadedFileFactoryInterface) { $this->uploadedFileFactory = $factory; } if (!$this->uriFactory && $factory instanceof UriFactoryInterface) { $this->uriFactory = $factory; } return $factory; } private function buildServerRequestFromGlobals(ServerRequestInterface $request, array $server, array $files): ServerRequestInterface { $request = $request ->withProtocolVersion(isset($server['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $server['SERVER_PROTOCOL']) : '1.1') ->withUploadedFiles($this->normalizeFiles($files)); $headers = []; foreach ($server as $k => $v) { if (0 === strpos($k, 'HTTP_')) { $k = substr($k, 5); } elseif (!\in_array($k, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'], true)) { continue; } $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $k)))); $headers[$k] = $v; } if (!isset($headers['Authorization'])) { if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; } elseif (isset($_SERVER['PHP_AUTH_USER'])) { $headers['Authorization'] = 'Basic '.base64_encode($_SERVER['PHP_AUTH_USER'].':'.($_SERVER['PHP_AUTH_PW'] ?? '')); } elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) { $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST']; } } foreach ($headers as $k => $v) { try { $request = $request->withHeader($k, $v); } catch (\InvalidArgumentException $e) { // ignore invalid headers } } return $request; } private function buildUriFromGlobals(UriInterface $uri, array $server): UriInterface { $uri = $uri->withScheme(!empty($server['HTTPS']) && 'off' !== strtolower($server['HTTPS']) ? 'https' : 'http'); $hasPort = false; if (isset($server['HTTP_HOST'])) { $parts = parse_url('http://'.$server['HTTP_HOST']); $uri = $uri->withHost($parts['host'] ?? 'localhost'); if ($parts['port'] ?? false) { $hasPort = true; $uri = $uri->withPort($parts['port']); } } else { $uri = $uri->withHost($server['SERVER_NAME'] ?? $server['SERVER_ADDR'] ?? 'localhost'); } if (!$hasPort && isset($server['SERVER_PORT'])) { $uri = $uri->withPort($server['SERVER_PORT']); } $hasQuery = false; if (isset($server['REQUEST_URI'])) { $requestUriParts = explode('?', $server['REQUEST_URI'], 2); $uri = $uri->withPath($requestUriParts[0]); if (isset($requestUriParts[1])) { $hasQuery = true; $uri = $uri->withQuery($requestUriParts[1]); } } if (!$hasQuery && isset($server['QUERY_STRING'])) { $uri = $uri->withQuery($server['QUERY_STRING']); } return $uri; } private function normalizeFiles(array $files): array { foreach ($files as $k => $v) { if ($v instanceof UploadedFileInterface) { continue; } if (!\is_array($v)) { unset($files[$k]); } elseif (!isset($v['tmp_name'])) { $files[$k] = $this->normalizeFiles($v); } else { $files[$k] = $this->createUploadedFileFromSpec($v); } } return $files; } /** * Create and return an UploadedFile instance from a $_FILES specification. * * @param array $value $_FILES struct * * @return UploadedFileInterface|UploadedFileInterface[] */ private function createUploadedFileFromSpec(array $value) { if (!is_array($tmpName = $value['tmp_name'])) { $file = is_file($tmpName) ? $this->createStreamFromFile($tmpName, 'r') : $this->createStream(); return $this->createUploadedFile($file, $value['size'], $value['error'], $value['name'], $value['type']); } foreach ($tmpName as $k => $v) { $tmpName[$k] = $this->createUploadedFileFromSpec([ 'tmp_name' => $v, 'size' => $value['size'][$k] ?? null, 'error' => $value['error'][$k] ?? null, 'name' => $value['name'][$k] ?? null, 'type' => $value['type'][$k] ?? null, ]); } return $tmpName; } } discovery/src/ClassDiscovery.php 0000644 00000015476 15111300111 0013005 0 ustar 00 <?php namespace Http\Discovery; use Http\Discovery\Exception\ClassInstantiationFailedException; use Http\Discovery\Exception\DiscoveryFailedException; use Http\Discovery\Exception\NoCandidateFoundException; use Http\Discovery\Exception\StrategyUnavailableException; use Http\Discovery\Strategy\DiscoveryStrategy; /** * Registry that based find results on class existence. * * @author David de Boer <david@ddeboer.nl> * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> * @author Tobias Nyholm <tobias.nyholm@gmail.com> */ abstract class ClassDiscovery { /** * A list of strategies to find classes. * * @var DiscoveryStrategy[] */ private static $strategies = [ Strategy\GeneratedDiscoveryStrategy::class, Strategy\CommonClassesStrategy::class, Strategy\CommonPsr17ClassesStrategy::class, Strategy\PuliBetaStrategy::class, ]; private static $deprecatedStrategies = [ Strategy\PuliBetaStrategy::class => true, ]; /** * Discovery cache to make the second time we use discovery faster. * * @var array */ private static $cache = []; /** * Finds a class. * * @param string $type * * @return string|\Closure * * @throws DiscoveryFailedException */ protected static function findOneByType($type) { // Look in the cache if (null !== ($class = self::getFromCache($type))) { return $class; } static $skipStrategy; $skipStrategy ?? $skipStrategy = self::safeClassExists(Strategy\GeneratedDiscoveryStrategy::class) ? false : Strategy\GeneratedDiscoveryStrategy::class; $exceptions = []; foreach (self::$strategies as $strategy) { if ($skipStrategy === $strategy) { continue; } try { $candidates = $strategy::getCandidates($type); } catch (StrategyUnavailableException $e) { if (!isset(self::$deprecatedStrategies[$strategy])) { $exceptions[] = $e; } continue; } foreach ($candidates as $candidate) { if (isset($candidate['condition'])) { if (!self::evaluateCondition($candidate['condition'])) { continue; } } // save the result for later use self::storeInCache($type, $candidate); return $candidate['class']; } $exceptions[] = new NoCandidateFoundException($strategy, $candidates); } throw DiscoveryFailedException::create($exceptions); } /** * Get a value from cache. * * @param string $type * * @return string|null */ private static function getFromCache($type) { if (!isset(self::$cache[$type])) { return; } $candidate = self::$cache[$type]; if (isset($candidate['condition'])) { if (!self::evaluateCondition($candidate['condition'])) { return; } } return $candidate['class']; } /** * Store a value in cache. * * @param string $type * @param string $class */ private static function storeInCache($type, $class) { self::$cache[$type] = $class; } /** * Set new strategies and clear the cache. * * @param string[] $strategies list of fully qualified class names that implement DiscoveryStrategy */ public static function setStrategies(array $strategies) { self::$strategies = $strategies; self::clearCache(); } /** * Returns the currently configured discovery strategies as fully qualified class names. * * @return string[] */ public static function getStrategies(): iterable { return self::$strategies; } /** * Append a strategy at the end of the strategy queue. * * @param string $strategy Fully qualified class name of a DiscoveryStrategy */ public static function appendStrategy($strategy) { self::$strategies[] = $strategy; self::clearCache(); } /** * Prepend a strategy at the beginning of the strategy queue. * * @param string $strategy Fully qualified class name to a DiscoveryStrategy */ public static function prependStrategy($strategy) { array_unshift(self::$strategies, $strategy); self::clearCache(); } public static function clearCache() { self::$cache = []; } /** * Evaluates conditions to boolean. * * @return bool */ protected static function evaluateCondition($condition) { if (is_string($condition)) { // Should be extended for functions, extensions??? return self::safeClassExists($condition); } if (is_callable($condition)) { return (bool) $condition(); } if (is_bool($condition)) { return $condition; } if (is_array($condition)) { foreach ($condition as $c) { if (false === static::evaluateCondition($c)) { // Immediately stop execution if the condition is false return false; } } return true; } return false; } /** * Get an instance of the $class. * * @param string|\Closure $class a FQCN of a class or a closure that instantiate the class * * @return object * * @throws ClassInstantiationFailedException */ protected static function instantiateClass($class) { try { if (is_string($class)) { return new $class(); } if (is_callable($class)) { return $class(); } } catch (\Exception $e) { throw new ClassInstantiationFailedException('Unexpected exception when instantiating class.', 0, $e); } throw new ClassInstantiationFailedException('Could not instantiate class because parameter is neither a callable nor a string'); } /** * We need a "safe" version of PHP's "class_exists" because Magento has a bug * (or they call it a "feature"). Magento is throwing an exception if you do class_exists() * on a class that ends with "Factory" and if that file does not exits. * * This function catches all potential exceptions and makes sure to always return a boolean. * * @param string $class * * @return bool */ public static function safeClassExists($class) { try { return class_exists($class) || interface_exists($class); } catch (\Exception $e) { return false; } } } discovery/src/Exception/StrategyUnavailableException.php 0000644 00000000546 15111300111 0017623 0 ustar 00 <?php namespace Http\Discovery\Exception; use Http\Discovery\Exception; /** * This exception is thrown when we cannot use a discovery strategy. This is *not* thrown when * the discovery fails to find a class. * * @author Tobias Nyholm <tobias.nyholm@gmail.com> */ class StrategyUnavailableException extends \RuntimeException implements Exception { } discovery/src/Exception/NotFoundException.php 0000644 00000000534 15111300111 0015406 0 ustar 00 <?php namespace Http\Discovery\Exception; use Http\Discovery\Exception; /** * Thrown when a discovery does not find any matches. * * @final do NOT extend this class, not final for BC reasons * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ /* final */ class NotFoundException extends \RuntimeException implements Exception { } discovery/src/Exception/PuliUnavailableException.php 0000644 00000000350 15111300111 0016723 0 ustar 00 <?php namespace Http\Discovery\Exception; /** * Thrown when we can't use Puli for discovery. * * @author Tobias Nyholm <tobias.nyholm@gmail.com> */ final class PuliUnavailableException extends StrategyUnavailableException { } discovery/src/Exception/DiscoveryFailedException.php 0000644 00000002237 15111300111 0016730 0 ustar 00 <?php namespace Http\Discovery\Exception; use Http\Discovery\Exception; /** * Thrown when all discovery strategies fails to find a resource. * * @author Tobias Nyholm <tobias.nyholm@gmail.com> */ final class DiscoveryFailedException extends \Exception implements Exception { /** * @var \Exception[] */ private $exceptions; /** * @param string $message * @param \Exception[] $exceptions */ public function __construct($message, array $exceptions = []) { $this->exceptions = $exceptions; parent::__construct($message); } /** * @param \Exception[] $exceptions */ public static function create($exceptions) { $message = 'Could not find resource using any discovery strategy. Find more information at http://docs.php-http.org/en/latest/discovery.html#common-errors'; foreach ($exceptions as $e) { $message .= "\n - ".$e->getMessage(); } $message .= "\n\n"; return new self($message, $exceptions); } /** * @return \Exception[] */ public function getExceptions() { return $this->exceptions; } } discovery/src/Exception/NoCandidateFoundException.php 0000644 00000002243 15111300111 0017016 0 ustar 00 <?php namespace Http\Discovery\Exception; use Http\Discovery\Exception; /** * When we have used a strategy but no candidates provided by that strategy could be used. * * @author Tobias Nyholm <tobias.nyholm@gmail.com> */ final class NoCandidateFoundException extends \Exception implements Exception { /** * @param string $strategy */ public function __construct($strategy, array $candidates) { $classes = array_map( function ($a) { return $a['class']; }, $candidates ); $message = sprintf( 'No valid candidate found using strategy "%s". We tested the following candidates: %s.', $strategy, implode(', ', array_map([$this, 'stringify'], $classes)) ); parent::__construct($message); } private function stringify($mixed) { if (is_string($mixed)) { return $mixed; } if (is_array($mixed) && 2 === count($mixed)) { return sprintf('%s::%s', $this->stringify($mixed[0]), $mixed[1]); } return is_object($mixed) ? get_class($mixed) : gettype($mixed); } } discovery/src/Exception/ClassInstantiationFailedException.php 0000644 00000000427 15111300111 0020572 0 ustar 00 <?php namespace Http\Discovery\Exception; use Http\Discovery\Exception; /** * Thrown when a class fails to instantiate. * * @author Tobias Nyholm <tobias.nyholm@gmail.com> */ final class ClassInstantiationFailedException extends \RuntimeException implements Exception { } discovery/src/HttpAsyncClientDiscovery.php 0000644 00000001545 15111300111 0015004 0 ustar 00 <?php namespace Http\Discovery; use Http\Client\HttpAsyncClient; use Http\Discovery\Exception\DiscoveryFailedException; /** * Finds an HTTP Asynchronous Client. * * @author Joel Wurtz <joel.wurtz@gmail.com> */ final class HttpAsyncClientDiscovery extends ClassDiscovery { /** * Finds an HTTP Async Client. * * @return HttpAsyncClient * * @throws Exception\NotFoundException */ public static function find() { try { $asyncClient = static::findOneByType(HttpAsyncClient::class); } catch (DiscoveryFailedException $e) { throw new NotFoundException('No HTTPlug async clients found. Make sure to install a package providing "php-http/async-client-implementation". Example: "php-http/guzzle6-adapter".', 0, $e); } return static::instantiateClass($asyncClient); } } discovery/src/UriFactoryDiscovery.php 0000644 00000001606 15111300111 0014015 0 ustar 00 <?php namespace Http\Discovery; use Http\Discovery\Exception\DiscoveryFailedException; use Http\Message\UriFactory; /** * Finds a URI Factory. * * @author David de Boer <david@ddeboer.nl> * * @deprecated This will be removed in 2.0. Consider using Psr17FactoryDiscovery. */ final class UriFactoryDiscovery extends ClassDiscovery { /** * Finds a URI Factory. * * @return UriFactory * * @throws Exception\NotFoundException */ public static function find() { try { $uriFactory = static::findOneByType(UriFactory::class); } catch (DiscoveryFailedException $e) { throw new NotFoundException('No uri factories found. To use Guzzle, Diactoros or Slim Framework factories install php-http/message and the chosen message implementation.', 0, $e); } return static::instantiateClass($uriFactory); } } discovery/src/error_log 0000644 00000010475 15111300111 0011246 0 ustar 00 [19-Nov-2025 05:46:59 UTC] PHP Fatal error: Uncaught Error: Class "Http\Discovery\Psr17Factory" not found in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/Psr18Client.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/Psr18Client.php on line 23 [19-Nov-2025 08:53:12 UTC] PHP Fatal error: Uncaught Error: Interface "Psr\Http\Message\RequestFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/Psr17Factory.php:42 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/Psr17Factory.php on line 42 [19-Nov-2025 15:33:24 UTC] PHP Fatal error: Uncaught Error: Interface "Psr\Http\Message\RequestFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/Psr17Factory.php:42 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/Psr17Factory.php on line 42 [25-Nov-2025 02:30:52 UTC] PHP Fatal error: Uncaught Error: Interface "Psr\Http\Message\RequestFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/Psr17Factory.php:42 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/Psr17Factory.php on line 42 [25-Nov-2025 02:55:41 UTC] PHP Fatal error: Uncaught Error: Class "Http\Discovery\Exception\NotFoundException" not found in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/NotFoundException.php:12 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/NotFoundException.php on line 12 [25-Nov-2025 03:00:24 UTC] PHP Fatal error: Uncaught Error: Class "Http\Discovery\ClassDiscovery" not found in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/Psr18ClientDiscovery.php:13 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/Psr18ClientDiscovery.php on line 13 [25-Nov-2025 03:00:33 UTC] PHP Fatal error: Uncaught Error: Class "Http\Discovery\ClassDiscovery" not found in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/MessageFactoryDiscovery.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/MessageFactoryDiscovery.php on line 15 [25-Nov-2025 03:00:46 UTC] PHP Fatal error: Uncaught Error: Class "Http\Discovery\ClassDiscovery" not found in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/HttpAsyncClientDiscovery.php:13 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/HttpAsyncClientDiscovery.php on line 13 [25-Nov-2025 03:04:15 UTC] PHP Fatal error: Uncaught Error: Class "Http\Discovery\ClassDiscovery" not found in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/StreamFactoryDiscovery.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/StreamFactoryDiscovery.php on line 15 [25-Nov-2025 03:30:55 UTC] PHP Fatal error: Uncaught Error: Class "Http\Discovery\ClassDiscovery" not found in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/UriFactoryDiscovery.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/UriFactoryDiscovery.php on line 15 [25-Nov-2025 05:29:04 UTC] PHP Fatal error: Uncaught Error: Class "Http\Discovery\ClassDiscovery" not found in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/HttpClientDiscovery.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/HttpClientDiscovery.php on line 15 [25-Nov-2025 06:30:30 UTC] PHP Fatal error: Uncaught Error: Class "Http\Discovery\ClassDiscovery" not found in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/Psr17FactoryDiscovery.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/Psr17FactoryDiscovery.php on line 18 [25-Nov-2025 06:31:21 UTC] PHP Fatal error: Uncaught Error: Class "Http\Discovery\Psr17Factory" not found in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/Psr18Client.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/discovery/src/Psr18Client.php on line 23 discovery/src/Psr18ClientDiscovery.php 0000644 00000001547 15111300111 0014006 0 ustar 00 <?php namespace Http\Discovery; use Http\Discovery\Exception\DiscoveryFailedException; use Psr\Http\Client\ClientInterface; /** * Finds a PSR-18 HTTP Client. * * @author Tobias Nyholm <tobias.nyholm@gmail.com> */ final class Psr18ClientDiscovery extends ClassDiscovery { /** * Finds a PSR-18 HTTP Client. * * @return ClientInterface * * @throws Exception\NotFoundException */ public static function find() { try { $client = static::findOneByType(ClientInterface::class); } catch (DiscoveryFailedException $e) { throw new \Http\Discovery\Exception\NotFoundException('No PSR-18 clients found. Make sure to install a package providing "psr/http-client-implementation". Example: "php-http/guzzle7-adapter".', 0, $e); } return static::instantiateClass($client); } } discovery/src/Psr18Client.php 0000644 00000003024 15111300111 0012106 0 ustar 00 <?php namespace Http\Discovery; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestFactoryInterface; use Psr\Http\Message\StreamFactoryInterface; use Psr\Http\Message\UploadedFileFactoryInterface; use Psr\Http\Message\UriFactoryInterface; /** * A generic PSR-18 and PSR-17 implementation. * * You can create this class with concrete client and factory instances * or let it use discovery to find suitable implementations as needed. * * @author Nicolas Grekas <p@tchwork.com> */ class Psr18Client extends Psr17Factory implements ClientInterface { private $client; public function __construct( ClientInterface $client = null, RequestFactoryInterface $requestFactory = null, ResponseFactoryInterface $responseFactory = null, ServerRequestFactoryInterface $serverRequestFactory = null, StreamFactoryInterface $streamFactory = null, UploadedFileFactoryInterface $uploadedFileFactory = null, UriFactoryInterface $uriFactory = null ) { parent::__construct($requestFactory, $responseFactory, $serverRequestFactory, $streamFactory, $uploadedFileFactory, $uriFactory); $this->client = $client ?? Psr18ClientDiscovery::find(); } public function sendRequest(RequestInterface $request): ResponseInterface { return $this->client->sendRequest($request); } } discovery/README.md 0000644 00000007302 15111300111 0010014 0 ustar 00 # HTTPlug Discovery [](https://github.com/php-http/discovery/releases) [](LICENSE) [](https://github.com/php-http/discovery/actions/workflows/ci.yml?query=branch%3Amaster) [](https://scrutinizer-ci.com/g/php-http/discovery) [](https://scrutinizer-ci.com/g/php-http/discovery) [](https://packagist.org/packages/php-http/discovery) **This library provides auto-discovery and auto-installation of well-known PSR-17, PSR-18 and HTTPlug implementations.** ## Install Via Composer ``` bash composer require php-http/discovery ``` ## Usage as a library author Please see the [official documentation](http://php-http.readthedocs.org/en/latest/discovery.html). If your library/SDK needs a PSR-18 client, here is a quick example. First, you need to install a PSR-18 client and a PSR-17 factory implementations. This should be done only for dev dependencies as you don't want to force a specific implementation on your users: ```bash composer require --dev symfony/http-client composer require --dev nyholm/psr7 ``` Then, you can disable the Composer plugin embeded in `php-http/discovery` because you just installed the dev dependencies you need for testing: ```bash composer config allow-plugins.php-http/discovery false ``` Finally, you need to require `php-http/discovery` and the generic implementations that your library is going to need: ```bash composer require 'php-http/discovery:^1.17' composer require 'psr/http-client-implementation:*' composer require 'psr/http-factory-implementation:*' ``` Now, you're ready to make an HTTP request: ```php use Http\Discovery\Psr18Client; $client = new Psr18Client(); $request = $client->createRequest('GET', 'https://example.com'); $response = $client->sendRequest($request); ``` Internally, this code will use whatever PSR-7, PSR-17 and PSR-18 implementations that your users have installed. ## Usage as a library user If you use a library/SDK that requires `php-http/discovery`, you can configure the auto-discovery mechanism to use a specific implementation when many are available in your project. For example, if you have both `nyholm/psr7` and `guzzlehttp/guzzle` in your project, you can tell `php-http/discovery` to use `guzzlehttp/guzzle` instead of `nyholm/psr7` by running the following command: ```bash composer config extra.discovery.psr/http-factory-implementation GuzzleHttp\\Psr7\\HttpFactory ``` This will update your `composer.json` file to add the following configuration: ```json { "extra": { "discovery": { "psr/http-factory-implementation": "GuzzleHttp\\Psr7\\HttpFactory" } } } ``` Don't forget to run `composer install` to apply the changes, and ensure that the composer plugin is enabled: ```bash composer config allow-plugins.php-http/discovery true composer install ``` ## Testing ``` bash composer test ``` ## Contributing Please see our [contributing guide](http://docs.php-http.org/en/latest/development/contributing.html). ## Security If you discover any security related issues, please contact us at [security@php-http.org](mailto:security@php-http.org). ## License The MIT License (MIT). Please see [License File](LICENSE) for more information. discovery/LICENSE 0000644 00000002072 15111300111 0007541 0 ustar 00 Copyright (c) 2015-2016 PHP HTTP Team <team@php-http.org> 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. discovery/composer.json 0000644 00000003560 15111300111 0011261 0 ustar 00 { "name": "php-http/discovery", "description": "Finds and installs PSR-7, PSR-17, PSR-18 and HTTPlug implementations", "type": "composer-plugin", "license": "MIT", "keywords": ["http", "discovery", "client", "adapter", "message", "factory", "psr7", "psr17"], "homepage": "http://php-http.org", "authors": [ { "name": "Márk Sági-Kazár", "email": "mark.sagikazar@gmail.com" } ], "provide": { "php-http/async-client-implementation": "*", "php-http/client-implementation": "*", "psr/http-client-implementation": "*", "psr/http-factory-implementation": "*", "psr/http-message-implementation": "*" }, "require": { "php": "^7.1 || ^8.0", "composer-plugin-api": "^1.0|^2.0" }, "require-dev": { "composer/composer": "^1.0.2|^2.0", "graham-campbell/phpspec-skip-example-extension": "^5.0", "php-http/httplug": "^1.0 || ^2.0", "php-http/message-factory": "^1.0", "phpspec/phpspec": "^5.1 || ^6.1 || ^7.3", "symfony/phpunit-bridge": "^6.2" }, "autoload": { "psr-4": { "Http\\Discovery\\": "src/" }, "exclude-from-classmap": [ "src/Composer/Plugin.php" ] }, "autoload-dev": { "psr-4": { "spec\\Http\\Discovery\\": "spec/" } }, "scripts": { "test": [ "vendor/bin/phpspec run", "vendor/bin/simple-phpunit --group NothingInstalled" ], "test-ci": "vendor/bin/phpspec run -c phpspec.ci.yml" }, "extra": { "class": "Http\\Discovery\\Composer\\Plugin", "plugin-optional": true }, "conflict": { "nyholm/psr7": "<1.0", "zendframework/zend-diactoros": "*" }, "prefer-stable": true, "minimum-stability": "beta" } discovery/.php-cs-fixer.php 0000644 00000000375 15111300111 0011634 0 ustar 00 <?php $finder = PhpCsFixer\Finder::create() ->in(__DIR__.'/src') ->name('*.php') ; $config = (new PhpCsFixer\Config()) ->setRiskyAllowed(true) ->setRules([ '@Symfony' => true, ]) ->setFinder($finder) ; return $config; discovery/CHANGELOG.md 0000644 00000022272 15111300111 0010351 0 ustar 00 # Change Log ## 1.19.1 - 2023-07-11 - [#250](https://github.com/php-http/discovery/pull/250) - Fix: Buzz client instantiation using deprecated Message Factory Discovery, use PSR-17 factory discovery instead. ## 1.19.0 - 2023-06-19 - [#249](https://github.com/php-http/discovery/pull/249) - Have composer plugin correctly install Symfony http client when nothing explicitly requires psr 18 resp. httplug. - [#241](https://github.com/php-http/discovery/pull/241) - Support discovering PSR-17 factories of `httpsoft/http-message` package ## 1.18.1 - 2023-05-17 - [#242](https://github.com/php-http/discovery/pull/242) - Better exception message when no legacy php-http message factories can be built. Also needs php-http/message-factory package and they are deprecated in favor of PSR-17 anyways. ## 1.18.0 - 2023-05-03 - [#235](https://github.com/php-http/discovery/pull/235) - Deprecate HttpClientDiscovery, use Psr18ClientDiscovery instead - [#238](https://github.com/php-http/discovery/pull/238) - Skip requiring php-http/message-factory when installing symfony/http-client 6.3+ - [#239](https://github.com/php-http/discovery/pull/239) - Skip auto-installing when the root package's extra.discovery is enough ## 1.17.0 - 2023-04-26 - [#230](https://github.com/php-http/discovery/pull/230) - Add Psr18Client to make it straightforward to use PSR-18 - [#232](https://github.com/php-http/discovery/pull/232) - Allow pinning the preferred implementations in composer.json - [#233](https://github.com/php-http/discovery/pull/233) - Fix Psr17Factory::createServerRequestFromGlobals() when uploaded files have been moved ## 1.16.0 - 2023-04-26 - [#225](https://github.com/php-http/discovery/pull/225) - Remove support for the abandoned Zend Diactoros which has been replaced with Laminas Diactoros; marked the zend library as conflict in composer.json to avoid confusion - [#227](https://github.com/php-http/discovery/pull/227) - Fix handling requests with nested files ## 1.15.3 - 2023-03-31 - [#224](https://github.com/php-http/discovery/pull/224) - Fix regression with Magento classloader ## 1.15.2 - 2023-02-11 - [#219](https://github.com/php-http/discovery/pull/219) - Fix handling of replaced packages ## 1.15.1 - 2023-02-10 - [#214](https://github.com/php-http/discovery/pull/214) - Fix resolving deps for psr/http-message-implementation - [#216](https://github.com/php-http/discovery/pull/216) - Fix keeping platform requirements when rebooting composer - [#217](https://github.com/php-http/discovery/pull/217) - Set extra.plugin-optional composer flag ## 1.15.0 - 2023-02-09 - [#209](https://github.com/php-http/discovery/pull/209) - Add generic `Psr17Factory` class - [#208](https://github.com/php-http/discovery/pull/208) - Add composer plugin to auto-install missing implementations. When libraries require an http implementation but no packages providing that implementation is installed in the application, the plugin will automatically install one. This is only done for libraries that directly require php-http/discovery to avoid unexpected dependency installation. ## 1.14.3 - 2022-07-11 - [#207](https://github.com/php-http/discovery/pull/207) - Updates Exception to extend Throwable solving static analysis errors for consumers ## 1.14.2 - 2022-05-25 - [#202](https://github.com/php-http/discovery/pull/202) - Avoid error when the Symfony PSR-18 client exists but its dependencies are not installed ## 1.14.1 - 2021-09-18 - [#199](https://github.com/php-http/discovery/pull/199) - Fixes message factory discovery for `laminas-diactoros ^2.7` ## 1.14.0 - 2021-06-21 - Deprecate puli as it has been unmaintained for a long time and is not compatible with composer 2 https://github.com/php-http/discovery/pull/195 ## 1.13.0 - 2020-11-27 - Support discovering PSR-17 factories of `slim/psr7` package https://github.com/php-http/discovery/pull/192 ## 1.12.0 - 2020-09-22 - Support discovering HttpClient of `php-http/guzzle7-adapter` https://github.com/php-http/discovery/pull/189 ## 1.11.0 - 2020-09-22 - Use correct method name to find Uri Factory in PSR17 https://github.com/php-http/discovery/pull/181 ## 1.10.0 - 2020-09-04 - Discover PSR-18 implementation of phalcon ## 1.9.1 - 2020-07-13 ### Fixed - Support PHP 7.4 and 8.0 ## 1.9.0 - 2020-07-02 ### Added - Support discovering PSR-18 factories of `guzzlehttp/guzzle` 7+ ## 1.8.0 - 2020-06-14 ### Added - Support discovering PSR-17 factories of `guzzlehttp/psr7` package - Support discovering PSR-17 factories of `laminas/laminas-diactoros` package - `ClassDiscovery::getStrategies()` to retrieve the list of current strategies. ### Fixed - Ignore exception during discovery when Symfony HttplugClient checks if HTTPlug is available. ## 1.7.4 - 2020-01-03 ### Fixed - Improve conditions on Symfony's async HTTPlug client. ## 1.7.3 - 2019-12-27 ### Fixed - Enough conditions to only use Symfony HTTP client if all needed components are available. ## 1.7.2 - 2019-12-27 ### Fixed - Allow a condition to specify an interface and not just classes. ## 1.7.1 - 2019-12-26 ### Fixed - Better conditions to see if Symfony's HTTP clients are available. ## 1.7.0 - 2019-06-30 ### Added - Dropped support for PHP < 7.1 - Support for `symfony/http-client` ## 1.6.1 - 2019-02-23 ### Fixed - MockClientStrategy also provides the mock client when requesting an async client ## 1.6.0 - 2019-01-23 ### Added - Support for PSR-17 factories - Support for PSR-18 clients ## 1.5.2 - 2018-12-31 Corrected mistakes in 1.5.1. The different between 1.5.2 and 1.5.0 is that we removed some PHP 7 code. https://github.com/php-http/discovery/compare/1.5.0...1.5.2 ## 1.5.1 - 2018-12-31 This version added new features by mistake. These are reverted in 1.5.2. Do not use 1.5.1. ### Fixed - Removed PHP 7 code ## 1.5.0 - 2018-12-30 ### Added - Support for `nyholm/psr7` version 1.0. - `ClassDiscovery::safeClassExists` which will help Magento users. - Support for HTTPlug 2.0 - Support for Buzz 1.0 - Better error message when nothing found by introducing a new exception: `NoCandidateFoundException`. ### Fixed - Fixed condition evaluation, it should stop after first invalid condition. ## 1.4.0 - 2018-02-06 ### Added - Discovery support for nyholm/psr7 ## 1.3.0 - 2017-08-03 ### Added - Discovery support for CakePHP adapter - Discovery support for Zend adapter - Discovery support for Artax adapter ## 1.2.1 - 2017-03-02 ### Fixed - Fixed minor issue with `MockClientStrategy`, also added more tests. ## 1.2.0 - 2017-02-12 ### Added - MockClientStrategy class. ## 1.1.1 - 2016-11-27 ### Changed - Made exception messages clearer. `StrategyUnavailableException` is no longer the previous exception to `DiscoveryFailedException`. - `CommonClassesStrategy` is using `self` instead of `static`. Using `static` makes no sense when `CommonClassesStrategy` is final. ## 1.1.0 - 2016-10-20 ### Added - Discovery support for Slim Framework factories ## 1.0.0 - 2016-07-18 ### Added - Added back `Http\Discovery\NotFoundException` to preserve BC with 0.8 version. You may upgrade from 0.8.x and 0.9.x to 1.0.0 without any BC breaks. - Added interface `Http\Discovery\Exception` which is implemented by all our exceptions ### Changed - Puli strategy renamed to Puli Beta strategy to prevent incompatibility with a future Puli stable ### Deprecated - For BC reasons, the old `Http\Discovery\NotFoundException` (extending the new exception) will be thrown until version 2.0 ## 0.9.1 - 2016-06-28 ### Changed - Dropping PHP 5.4 support because we use the ::class constant. ## 0.9.0 - 2016-06-25 ### Added - Discovery strategies to find classes ### Changed - [Puli](http://puli.io) made optional - Improved exceptions - **[BC] `NotFoundException` moved to `Http\Discovery\Exception\NotFoundException`** ## 0.8.0 - 2016-02-11 ### Changed - Puli composer plugin must be installed separately ## 0.7.0 - 2016-01-15 ### Added - Temporary puli.phar (Beta 10) executable ### Changed - Updated HTTPlug dependencies - Updated Puli dependencies - Local configuration to make tests passing ### Removed - Puli CLI dependency ## 0.6.4 - 2016-01-07 ### Fixed - Puli [not working](https://twitter.com/PuliPHP/status/685132540588507137) with the latest json-schema ## 0.6.3 - 2016-01-04 ### Changed - Adjust Puli dependencies ## 0.6.2 - 2016-01-04 ### Changed - Make Puli CLI a requirement ## 0.6.1 - 2016-01-03 ### Changed - More flexible Puli requirement ## 0.6.0 - 2015-12-30 ### Changed - Use [Puli](http://puli.io) for discovery - Improved exception messages ## 0.5.0 - 2015-12-25 ### Changed - Updated message factory dependency (php-http/message) ## 0.4.0 - 2015-12-17 ### Added - Array condition evaluation in the Class Discovery ### Removed - Message factories (moved to php-http/utils) ## 0.3.0 - 2015-11-18 ### Added - HTTP Async Client Discovery - Stream factories ### Changed - Discoveries and Factories are final - Message and Uri factories have the type in their names - Diactoros Message factory uses Stream factory internally ### Fixed - Improved docblocks for API documentation generation ## 0.2.0 - 2015-10-31 ### Changed - Renamed AdapterDiscovery to ClientDiscovery ## 0.1.1 - 2015-06-13 ### Fixed - Bad HTTP Adapter class name for Guzzle 5 ## 0.1.0 - 2015-06-12 ### Added - Initial release promise/src/FulfilledPromise.php 0000644 00000002031 15111300111 0012743 0 ustar 00 <?php namespace Http\Promise; /** * A promise already fulfilled. * * @author Joel Wurtz <joel.wurtz@gmail.com> * * @template-covariant T * * @implements Promise<T> */ final class FulfilledPromise implements Promise { /** * @var T */ private $result; /** * @param T $result */ public function __construct($result) { $this->result = $result; } /** * {@inheritdoc} */ public function then(callable $onFulfilled = null, callable $onRejected = null) { if (null === $onFulfilled) { return $this; } try { return new self($onFulfilled($this->result)); } catch (\Exception $e) { return new RejectedPromise($e); } } /** * {@inheritdoc} */ public function getState() { return Promise::FULFILLED; } /** * {@inheritdoc} */ public function wait($unwrap = true) { if ($unwrap) { return $this->result; } } } promise/src/error_log 0000644 00000001206 15111300111 0010705 0 ustar 00 [25-Nov-2025 02:59:20 UTC] PHP Fatal error: Uncaught Error: Interface "Http\Promise\Promise" not found in /home/fluxyjvi/public_html/project/vendor/php-http/promise/src/FulfilledPromise.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/promise/src/FulfilledPromise.php on line 14 [25-Nov-2025 05:31:42 UTC] PHP Fatal error: Uncaught Error: Interface "Http\Promise\Promise" not found in /home/fluxyjvi/public_html/project/vendor/php-http/promise/src/RejectedPromise.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/promise/src/RejectedPromise.php on line 14 promise/src/RejectedPromise.php 0000644 00000002012 15111300111 0012561 0 ustar 00 <?php namespace Http\Promise; /** * A rejected promise. * * @author Joel Wurtz <joel.wurtz@gmail.com> * * @template-covariant T * * @implements Promise<T> */ final class RejectedPromise implements Promise { /** * @var \Exception */ private $exception; public function __construct(\Exception $exception) { $this->exception = $exception; } /** * {@inheritdoc} */ public function then(callable $onFulfilled = null, callable $onRejected = null) { if (null === $onRejected) { return $this; } try { return new FulfilledPromise($onRejected($this->exception)); } catch (\Exception $e) { return new self($e); } } /** * {@inheritdoc} */ public function getState() { return Promise::REJECTED; } /** * {@inheritdoc} */ public function wait($unwrap = true) { if ($unwrap) { throw $this->exception; } } } promise/src/Promise.php 0000644 00000004414 15111300111 0011123 0 ustar 00 <?php namespace Http\Promise; /** * Promise represents a value that may not be available yet, but will be resolved at some point in future. * It acts like a proxy to the actual value. * * This interface is an extension of the promises/a+ specification. * * @see https://promisesaplus.com/ * * @author Joel Wurtz <joel.wurtz@gmail.com> * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> * * @template-covariant T */ interface Promise { /** * Promise has not been fulfilled or rejected. */ const PENDING = 'pending'; /** * Promise has been fulfilled. */ const FULFILLED = 'fulfilled'; /** * Promise has been rejected. */ const REJECTED = 'rejected'; /** * Adds behavior for when the promise is resolved or rejected (response will be available, or error happens). * * If you do not care about one of the cases, you can set the corresponding callable to null * The callback will be called when the value arrived and never more than once. * * @param callable(T): V|null $onFulfilled called when a response will be available * @param callable(\Exception): V|null $onRejected called when an exception occurs * * @return Promise<V> a new resolved promise with value of the executed callback (onFulfilled / onRejected) * * @template V */ public function then(callable $onFulfilled = null, callable $onRejected = null); /** * Returns the state of the promise, one of PENDING, FULFILLED or REJECTED. * * @return string */ public function getState(); /** * Wait for the promise to be fulfilled or rejected. * * When this method returns, the request has been resolved and if callables have been * specified, the appropriate one has terminated. * * When $unwrap is true (the default), the response is returned, or the exception thrown * on failure. Otherwise, nothing is returned or thrown. * * @param bool $unwrap Whether to return resolved value / throw reason or not * * @return T Resolved value, null if $unwrap is set to false * * @throws \Exception the rejection reason if $unwrap is set to true and the request failed */ public function wait($unwrap = true); } promise/README.md 0000644 00000003115 15111300111 0007461 0 ustar 00 # Promise [](https://github.com/php-http/promise/releases) [](LICENSE) [](https://github.com/php-http/promise/actions/workflows/tests.yml) [](https://scrutinizer-ci.com/g/php-http/promise) [](https://scrutinizer-ci.com/g/php-http/promise) [](https://packagist.org/packages/php-http/promise) **Promise used for asynchronous HTTP requests.** **Note:** This will eventually be removed/deprecated and replaced with the upcoming Promise PSR. ## Install Via Composer ``` bash $ composer require php-http/promise ``` ## Documentation Please see the [official documentation](http://docs.php-http.org/en/latest/components/promise.html). ## Testing ``` bash $ composer test ``` ## Contributing Please see our [contributing guide](http://docs.php-http.org/en/latest/development/contributing.html). ## Security If you discover any security related issues, please contact us at [security@php-http.org](mailto:security@php-http.org). ## License The MIT License (MIT). Please see [License File](LICENSE) for more information. promise/LICENSE 0000644 00000002072 15111300111 0007210 0 ustar 00 Copyright (c) 2015-2016 PHP HTTP Team <team@php-http.org> 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. promise/composer.json 0000644 00000001520 15111300111 0010722 0 ustar 00 { "name": "php-http/promise", "description": "Promise used for asynchronous HTTP requests", "license": "MIT", "keywords": ["promise"], "homepage": "http://httplug.io", "authors": [ { "name": "Joel Wurtz", "email": "joel.wurtz@gmail.com" }, { "name": "Márk Sági-Kazár", "email": "mark.sagikazar@gmail.com" } ], "require": { "php" : "^7.1 || ^8.0" }, "require-dev": { "friends-of-phpspec/phpspec-code-coverage" : "^4.3.2 || ^6.3", "phpspec/phpspec": "^5.1.2 || ^6.2 || ^7.4" }, "autoload": { "psr-4": { "Http\\Promise\\": "src/" } }, "scripts": { "test": "vendor/bin/phpspec run", "test-ci": "vendor/bin/phpspec run -c phpspec.yml.ci" } } promise/CHANGELOG.md 0000644 00000001144 15111300111 0010013 0 ustar 00 # Change Log ## 1.2.0 - 2023-10-24 ### Added - Generic annotations ## 1.1.0 - 2020-07-07 ### Added - Test with PHP 7.1, 7.2, 7.3, 7.4 and 8.0 ### Removed - PHP 5 and 7.0 support ### Fixed - Fixed PHPDoc for `Promise::then` ## 1.0.0 - 2016-01-26 ### Removed - PSR-7 dependency ## 1.0.0-RC1 - 2016-01-12 ### Added - Tests for full coverage ## Changed - Updated package files - Clarified wait method behavior - Contributing guide moved to the documentation ## 0.1.1 - 2015-12-24 ## Added - Fulfilled and Rejected promise implementations ## 0.1.0 - 2015-12-13 ## Added - Promise interface httplug/src/Promise/HttpRejectedPromise.php 0000644 00000002100 15111300111 0015046 0 ustar 00 <?php namespace Http\Client\Promise; use Http\Client\Exception; use Http\Promise\Promise; final class HttpRejectedPromise implements Promise { /** * @var Exception */ private $exception; public function __construct(Exception $exception) { $this->exception = $exception; } /** * {@inheritdoc} */ public function then(callable $onFulfilled = null, callable $onRejected = null) { if (null === $onRejected) { return $this; } try { $result = $onRejected($this->exception); if ($result instanceof Promise) { return $result; } return new HttpFulfilledPromise($result); } catch (Exception $e) { return new self($e); } } /** * {@inheritdoc} */ public function getState() { return Promise::REJECTED; } /** * {@inheritdoc} */ public function wait($unwrap = true) { if ($unwrap) { throw $this->exception; } } } httplug/src/Promise/HttpFulfilledPromise.php 0000644 00000001772 15111300111 0015245 0 ustar 00 <?php namespace Http\Client\Promise; use Http\Client\Exception; use Http\Promise\Promise; use Psr\Http\Message\ResponseInterface; final class HttpFulfilledPromise implements Promise { /** * @var ResponseInterface */ private $response; public function __construct(ResponseInterface $response) { $this->response = $response; } /** * {@inheritdoc} */ public function then(callable $onFulfilled = null, callable $onRejected = null) { if (null === $onFulfilled) { return $this; } try { return new self($onFulfilled($this->response)); } catch (Exception $e) { return new HttpRejectedPromise($e); } } /** * {@inheritdoc} */ public function getState() { return Promise::FULFILLED; } /** * {@inheritdoc} */ public function wait($unwrap = true) { if ($unwrap) { return $this->response; } } } httplug/src/Exception.php 0000644 00000000441 15111300111 0011450 0 ustar 00 <?php namespace Http\Client; use Psr\Http\Client\ClientExceptionInterface as PsrClientException; /** * Every HTTP Client related Exception must implement this interface. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ interface Exception extends PsrClientException { } httplug/src/Exception/RequestException.php 0000644 00000001423 15111300111 0014760 0 ustar 00 <?php namespace Http\Client\Exception; use Psr\Http\Client\RequestExceptionInterface as PsrRequestException; use Psr\Http\Message\RequestInterface; /** * Exception for when a request failed, providing access to the failed request. * * This could be due to an invalid request, or one of the extending exceptions * for network errors or HTTP error responses. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ class RequestException extends TransferException implements PsrRequestException { use RequestAwareTrait; /** * @param string $message */ public function __construct($message, RequestInterface $request, \Exception $previous = null) { $this->setRequest($request); parent::__construct($message, 0, $previous); } } httplug/src/Exception/RequestAwareTrait.php 0000644 00000000637 15111300111 0015073 0 ustar 00 <?php namespace Http\Client\Exception; use Psr\Http\Message\RequestInterface; trait RequestAwareTrait { /** * @var RequestInterface */ private $request; private function setRequest(RequestInterface $request) { $this->request = $request; } /** * {@inheritdoc} */ public function getRequest(): RequestInterface { return $this->request; } } httplug/src/Exception/HttpException.php 0000644 00000003106 15111300111 0014247 0 ustar 00 <?php namespace Http\Client\Exception; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; /** * Thrown when a response was received but the request itself failed. * * In addition to the request, this exception always provides access to the response object. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ class HttpException extends RequestException { /** * @var ResponseInterface */ protected $response; /** * @param string $message */ public function __construct( $message, RequestInterface $request, ResponseInterface $response, \Exception $previous = null ) { parent::__construct($message, $request, $previous); $this->response = $response; $this->code = $response->getStatusCode(); } /** * Returns the response. * * @return ResponseInterface */ public function getResponse() { return $this->response; } /** * Factory method to create a new exception with a normalized error message. */ public static function create( RequestInterface $request, ResponseInterface $response, \Exception $previous = null ) { $message = sprintf( '[url] %s [http method] %s [status code] %s [reason phrase] %s', $request->getRequestTarget(), $request->getMethod(), $response->getStatusCode(), $response->getReasonPhrase() ); return new static($message, $request, $response, $previous); } } httplug/src/Exception/NetworkException.php 0000644 00000001356 15111300111 0014766 0 ustar 00 <?php namespace Http\Client\Exception; use Psr\Http\Client\NetworkExceptionInterface as PsrNetworkException; use Psr\Http\Message\RequestInterface; /** * Thrown when the request cannot be completed because of network issues. * * There is no response object as this exception is thrown when no response has been received. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ class NetworkException extends TransferException implements PsrNetworkException { use RequestAwareTrait; /** * @param string $message */ public function __construct($message, RequestInterface $request, \Exception $previous = null) { $this->setRequest($request); parent::__construct($message, 0, $previous); } } httplug/src/Exception/TransferException.php 0000644 00000000407 15111300111 0015115 0 ustar 00 <?php namespace Http\Client\Exception; use Http\Client\Exception; /** * Base exception for transfer related exceptions. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ class TransferException extends \RuntimeException implements Exception { } httplug/src/error_log 0000644 00000001215 15111300111 0010716 0 ustar 00 [25-Nov-2025 03:24:30 UTC] PHP Fatal error: Uncaught Error: Interface "Psr\Http\Client\ClientExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/php-http/httplug/src/Exception.php:12 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/httplug/src/Exception.php on line 12 [25-Nov-2025 03:31:06 UTC] PHP Fatal error: Uncaught Error: Interface "Psr\Http\Client\ClientInterface" not found in /home/fluxyjvi/public_html/project/vendor/php-http/httplug/src/HttpClient.php:15 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/httplug/src/HttpClient.php on line 15 httplug/src/HttpAsyncClient.php 0000644 00000001252 15111300111 0012567 0 ustar 00 <?php namespace Http\Client; use Http\Promise\Promise; use Psr\Http\Message\RequestInterface; /** * Sends a PSR-7 Request in an asynchronous way by returning a Promise. * * @author Joel Wurtz <joel.wurtz@gmail.com> */ interface HttpAsyncClient { /** * Sends a PSR-7 request in an asynchronous way. * * Exceptions related to processing the request are available from the returned Promise. * * @return Promise resolves a PSR-7 Response or fails with an Http\Client\Exception * * @throws \Exception If processing the request is impossible (eg. bad configuration). */ public function sendAsyncRequest(RequestInterface $request); } httplug/src/HttpClient.php 0000644 00000000603 15111300111 0011570 0 ustar 00 <?php namespace Http\Client; use Psr\Http\Client\ClientInterface; /** * {@inheritdoc} * * Provide the Httplug HttpClient interface for BC. * You should typehint Psr\Http\Client\ClientInterface in new code * * @deprecated since version 2.4, use Psr\Http\Client\ClientInterface instead; see https://www.php-fig.org/psr/psr-18/ */ interface HttpClient extends ClientInterface { } httplug/.php-cs-fixer.dist.php 0000644 00000000375 15111300111 0012256 0 ustar 00 <?php $finder = PhpCsFixer\Finder::create() ->in(__DIR__.'/src') ->name('*.php') ; $config = (new PhpCsFixer\Config()) ->setRiskyAllowed(true) ->setRules([ '@Symfony' => true, ]) ->setFinder($finder) ; return $config; httplug/README.md 0000644 00000003554 15111300111 0007501 0 ustar 00 # HTTPlug [](https://github.com/php-http/httplug/releases) [](LICENSE) [](https://github.com/php-http/httplug/actions/workflows/ci.yml) [](https://scrutinizer-ci.com/g/php-http/httplug) [](https://scrutinizer-ci.com/g/php-http/httplug) [](https://packagist.org/packages/php-http/httplug) [](mailto:team@httplug.io) **HTTPlug, the HTTP client abstraction for PHP.** ## Intro HTTP client standard built on [PSR-7](http://www.php-fig.org/psr/psr-7/) HTTP messages. The HttpAsyncClient defines an asynchronous HTTP client for PHP. This package also provides a synchronous HttpClient interface with the same method signature as the [PSR-18](http://www.php-fig.org/psr/psr-18/) client. For synchronous requests, we recommend using PSR-18 directly. ## History HTTPlug is the official successor of the [ivory http adapter](https://github.com/egeloen/ivory-http-adapter). HTTPlug is a predecessor of [PSR-18](http://www.php-fig.org/psr/psr-18/) ## Install Via Composer ``` bash $ composer require php-http/httplug ``` ## Documentation Please see the [official documentation](http://docs.php-http.org). ## Testing ``` bash $ composer test ``` ## License The MIT License (MIT). Please see [License File](LICENSE) for more information. httplug/LICENSE 0000644 00000002154 15111300111 0007222 0 ustar 00 Copyright (c) 2014 Eric GELOEN <geloen.eric@gmail.com> Copyright (c) 2015 PHP HTTP Team <team@php-http.org> 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. httplug/puli.json 0000644 00000000425 15111300111 0010060 0 ustar 00 { "version": "1.0", "name": "php-http/httplug", "binding-types": { "Http\\Client\\HttpAsyncClient": { "description": "Async HTTP Client" }, "Http\\Client\\HttpClient": { "description": "HTTP Client" } } } httplug/composer.json 0000644 00000002030 15111300111 0010730 0 ustar 00 { "name": "php-http/httplug", "description": "HTTPlug, the HTTP client abstraction for PHP", "keywords": [ "http", "client" ], "homepage": "http://httplug.io", "license": "MIT", "authors": [ { "name": "Eric GELOEN", "email": "geloen.eric@gmail.com" }, { "name": "Márk Sági-Kazár", "email": "mark.sagikazar@gmail.com", "homepage": "https://sagikazarmark.hu" } ], "require": { "php": "^7.1 || ^8.0", "php-http/promise": "^1.1", "psr/http-client": "^1.0", "psr/http-message": "^1.0 || ^2.0" }, "require-dev": { "friends-of-phpspec/phpspec-code-coverage": "^4.1 || ^5.0 || ^6.0", "phpspec/phpspec": "^5.1 || ^6.0 || ^7.0" }, "autoload": { "psr-4": { "Http\\Client\\": "src/" } }, "scripts": { "test": "vendor/bin/phpspec run", "test-ci": "vendor/bin/phpspec run -c phpspec.ci.yml" } } httplug/CHANGELOG.md 0000644 00000006417 15111300111 0010034 0 ustar 00 # Change Log All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [2.4.0] - 2023-04-14 ### Changed - Allow `psr/http-message` v2 in addition to v1 - Deprecate `Http\Client\HttpClient`, use [PSR-18](https://www.php-fig.org/psr/psr-18/) instead ## [2.3.0] - 2022-02-21 ### Changed - Enabled the `$onRejected` callback of `HttpRejectedPromise` to return a promise for implementing a retry mechanism [#168](https://github.com/php-http/httplug/pull/168) ## [2.2.0] - 2020-07-13 ### Changed - Support PHP 7.1-8.0 ## [2.1.0] - 2019-12-27 ### Changed - `Http\Client\Exception\NetworkException` no longer extends `Http\Client\Exception\RequestException`, in accordance with [PSR-18](https://www.php-fig.org/psr/psr-18/) ## [2.0.0] - 2018-10-31 This version is no BC break for consumers using HTTPlug. However, HTTP clients that implement HTTPlug need to adjust because we add return type declarations. ### Added - Support for PSR-18 (HTTP client). ### Changed - **BC Break:** `HttpClient::sendRequest(RequestInterface $request)` has a return type annotation. The new signature is `HttpClient::sendRequest(RequestInterface $request): ResponseInterface`. - **BC Break:** `RequestException::getRequest()` has a return type annotation. The new signature is `RequestException::getRequest(): RequestInterface`. ### Removed - PHP 5 support ## [1.1.0] - 2016-08-31 ### Added - HttpFulfilledPromise and HttpRejectedPromise which respect the HttpAsyncClient interface ## [1.0.0] - 2016-01-26 ### Removed - Stability configuration from composer ## [1.0.0-RC1] - 2016-01-12 ### Changed - Updated package files - Updated promise dependency to RC1 ## [1.0.0-beta] - 2015-12-17 ### Added - Puli configuration and binding types ### Changed - Exception concept ## [1.0.0-alpha3] - 2015-12-13 ### Changed - Async client does not throw exceptions ### Removed - Promise interface moved to its own repository: [php-http/promise](https://github.com/php-http/promise) ## [1.0.0-alpha2] - 2015-11-16 ### Added - Async client and Promise interface ## [1.0.0-alpha] - 2015-10-26 ### Added - Better domain exceptions. ### Changed - Purpose of the library: general HTTP CLient abstraction. ### Removed - Request options: they should be configured at construction time. - Multiple request sending: should be done asynchronously using Async Client. - `getName` method ## 0.1.0 - 2015-06-03 ### Added - Initial release [Unreleased]: https://github.com/php-http/httplug/compare/v2.0.0...HEAD [2.0.0]: https://github.com/php-http/httplug/compare/v1.1.0...HEAD [1.1.0]: https://github.com/php-http/httplug/compare/v1.0.0...v1.1.0 [1.0.0]: https://github.com/php-http/httplug/compare/v1.0.0-RC1...v1.0.0 [1.0.0-RC1]: https://github.com/php-http/httplug/compare/v1.0.0-beta...v1.0.0-RC1 [1.0.0-beta]: https://github.com/php-http/httplug/compare/v1.0.0-alpha3...v1.0.0-beta [1.0.0-alpha3]: https://github.com/php-http/httplug/compare/v1.0.0-alpha2...v1.0.0-alpha3 [1.0.0-alpha2]: https://github.com/php-http/httplug/compare/v1.0.0-alpha...v1.0.0-alpha2 [1.0.0-alpha]: https://github.com/php-http/httplug/compare/v0.1.0...v1.0.0-alpha message/src/CookieUtil.php 0000644 00000002606 15111300111 0011523 0 ustar 00 <?php namespace Http\Message; use Http\Message\Exception\UnexpectedValueException; final class CookieUtil { /** * Handles dates as defined by RFC 2616 section 3.3.1, and also some other * non-standard, but common formats. * * @var array */ private static $dateFormats = [ 'D, d M y H:i:s T', 'D, d M Y H:i:s T', 'D, d-M-y H:i:s T', 'D, d-M-Y H:i:s T', 'D, d-m-y H:i:s T', 'D, d-m-Y H:i:s T', 'D M j G:i:s Y', 'D M d H:i:s Y T', ]; /** * @see https://github.com/symfony/symfony/blob/master/src/Symfony/Component/BrowserKit/Cookie.php * * @param string $dateValue * * @return \DateTime * * @throws UnexpectedValueException if we cannot parse the cookie date string */ public static function parseDate($dateValue) { foreach (self::$dateFormats as $dateFormat) { if (false !== $date = \DateTime::createFromFormat($dateFormat, $dateValue, new \DateTimeZone('GMT'))) { return $date; } } // attempt a fallback for unusual formatting if (false !== $date = date_create($dateValue, new \DateTimeZone('GMT'))) { return $date; } throw new UnexpectedValueException(sprintf( 'Unparseable cookie date string "%s"', $dateValue )); } } message/src/Authentication.php 0000644 00000001256 15111300111 0012433 0 ustar 00 <?php namespace Http\Message; use Psr\Http\Message\RequestInterface; /** * Add authentication information to a PSR-7 Request. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ interface Authentication { /** * Alter the request to add the authentication credentials. * * To do that, the implementation might use pre-stored credentials or do * separate HTTP requests to obtain a valid token. * * @param RequestInterface $request The request without authentication information * * @return RequestInterface The request with added authentication information */ public function authenticate(RequestInterface $request); } message/src/CookieJar.php 0000644 00000010572 15111300111 0011323 0 ustar 00 <?php namespace Http\Message; /** * Cookie Jar holds a set of Cookies. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ final class CookieJar implements \Countable, \IteratorAggregate { /** * @var \SplObjectStorage<Cookie, mixed> */ private $cookies; public function __construct() { $this->cookies = new \SplObjectStorage(); } /** * Checks if there is a cookie. * * @return bool */ public function hasCookie(Cookie $cookie) { return $this->cookies->contains($cookie); } /** * Adds a cookie. */ public function addCookie(Cookie $cookie) { if (!$this->hasCookie($cookie)) { $cookies = $this->getMatchingCookies($cookie); foreach ($cookies as $matchingCookie) { if ($cookie->getValue() !== $matchingCookie->getValue() || $cookie->getMaxAge() > $matchingCookie->getMaxAge()) { $this->removeCookie($matchingCookie); continue; } } if ($cookie->hasValue()) { $this->cookies->attach($cookie); } } } /** * Removes a cookie. */ public function removeCookie(Cookie $cookie) { $this->cookies->detach($cookie); } /** * Returns the cookies. * * @return Cookie[] */ public function getCookies() { $match = function ($matchCookie) { return true; }; return $this->findMatchingCookies($match); } /** * Returns all matching cookies. * * @return Cookie[] */ public function getMatchingCookies(Cookie $cookie) { $match = function ($matchCookie) use ($cookie) { return $matchCookie->match($cookie); }; return $this->findMatchingCookies($match); } /** * Finds matching cookies based on a callable. * * @return Cookie[] */ private function findMatchingCookies(callable $match) { $cookies = []; foreach ($this->cookies as $cookie) { if ($match($cookie)) { $cookies[] = $cookie; } } return $cookies; } /** * Checks if there are cookies. * * @return bool */ public function hasCookies() { return $this->cookies->count() > 0; } /** * Sets the cookies and removes any previous one. * * @param Cookie[] $cookies */ public function setCookies(array $cookies) { $this->clear(); $this->addCookies($cookies); } /** * Adds some cookies. * * @param Cookie[] $cookies */ public function addCookies(array $cookies) { foreach ($cookies as $cookie) { $this->addCookie($cookie); } } /** * Removes some cookies. * * @param Cookie[] $cookies */ public function removeCookies(array $cookies) { foreach ($cookies as $cookie) { $this->removeCookie($cookie); } } /** * Removes cookies which match the given parameters. * * Null means that parameter should not be matched * * @param string|null $name * @param string|null $domain * @param string|null $path */ public function removeMatchingCookies($name = null, $domain = null, $path = null) { $match = function ($cookie) use ($name, $domain, $path) { $match = true; if (isset($name)) { $match = $match && ($cookie->getName() === $name); } if (isset($domain)) { $match = $match && $cookie->matchDomain($domain); } if (isset($path)) { $match = $match && $cookie->matchPath($path); } return $match; }; $cookies = $this->findMatchingCookies($match); $this->removeCookies($cookies); } /** * Removes all cookies. */ public function clear() { $this->cookies = new \SplObjectStorage(); } /** * {@inheritdoc} */ #[\ReturnTypeWillChange] public function count() { return $this->cookies->count(); } /** * {@inheritdoc} */ #[\ReturnTypeWillChange] public function getIterator() { return clone $this->cookies; } } message/src/filters.php 0000644 00000000262 15111300111 0011120 0 ustar 00 <?php // Register chunk filter if not found if (!array_key_exists('chunk', stream_get_filters())) { stream_filter_register('chunk', 'Http\Message\Encoding\Filter\Chunk'); } message/src/Exception.php 0000644 00000000204 15111300111 0011402 0 ustar 00 <?php namespace Http\Message; /** * An interface implemented by all HTTP message related exceptions. */ interface Exception { } message/src/Encoding/Filter/Chunk.php 0000644 00000001340 15111300111 0013471 0 ustar 00 <?php namespace Http\Message\Encoding\Filter; /** * Userland implementation of the chunk stream filter. * * @author Joel Wurtz <joel.wurtz@gmail.com> */ class Chunk extends \php_user_filter { public function filter($in, $out, &$consumed, $closing): int { while ($bucket = stream_bucket_make_writeable($in)) { $lenbucket = stream_bucket_new($this->stream, dechex($bucket->datalen)."\r\n"); stream_bucket_append($out, $lenbucket); $consumed += $bucket->datalen; stream_bucket_append($out, $bucket); $lenbucket = stream_bucket_new($this->stream, "\r\n"); stream_bucket_append($out, $lenbucket); } return PSFS_PASS_ON; } } message/src/Encoding/ChunkStream.php 0000644 00000001006 15111300111 0013417 0 ustar 00 <?php namespace Http\Message\Encoding; /** * Transform a regular stream into a chunked one. * * @author Joel Wurtz <joel.wurtz@gmail.com> */ class ChunkStream extends FilteredStream { protected function readFilter(): string { return 'chunk'; } protected function writeFilter(): string { return 'dechunk'; } protected function fill(): void { parent::fill(); if ($this->stream->eof()) { $this->buffer .= "0\r\n\r\n"; } } } message/src/Encoding/DeflateStream.php 0000644 00000001501 15111300111 0013713 0 ustar 00 <?php namespace Http\Message\Encoding; use Clue\StreamFilter as Filter; use Psr\Http\Message\StreamInterface; /** * Stream deflate (RFC 1951). * * @author Joel Wurtz <joel.wurtz@gmail.com> */ class DeflateStream extends FilteredStream { /** * @param int $level */ public function __construct(StreamInterface $stream, $level = -1) { parent::__construct($stream, ['window' => -15, 'level' => $level]); // @deprecated will be removed in 2.0 $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => -15]); } /** * {@inheritdoc} */ protected function readFilter(): string { return 'zlib.deflate'; } /** * {@inheritdoc} */ protected function writeFilter(): string { return 'zlib.inflate'; } } message/src/Encoding/GzipDecodeStream.php 0000644 00000001756 15111300111 0014400 0 ustar 00 <?php namespace Http\Message\Encoding; use Clue\StreamFilter as Filter; use Psr\Http\Message\StreamInterface; /** * Stream for decoding from gzip format (RFC 1952). * * @author Joel Wurtz <joel.wurtz@gmail.com> */ class GzipDecodeStream extends FilteredStream { /** * @param int $level */ public function __construct(StreamInterface $stream, $level = -1) { if (!extension_loaded('zlib')) { throw new \RuntimeException('The zlib extension must be enabled to use this stream'); } parent::__construct($stream, ['window' => 31]); // @deprecated will be removed in 2.0 $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => 31, 'level' => $level]); } /** * {@inheritdoc} */ protected function readFilter(): string { return 'zlib.inflate'; } /** * {@inheritdoc} */ protected function writeFilter(): string { return 'zlib.deflate'; } } message/src/Encoding/InflateStream.php 0000644 00000001615 15111300111 0013737 0 ustar 00 <?php namespace Http\Message\Encoding; use Clue\StreamFilter as Filter; use Psr\Http\Message\StreamInterface; /** * Stream inflate (RFC 1951). * * @author Joel Wurtz <joel.wurtz@gmail.com> */ class InflateStream extends FilteredStream { /** * @param int $level */ public function __construct(StreamInterface $stream, $level = -1) { if (!extension_loaded('zlib')) { throw new \RuntimeException('The zlib extension must be enabled to use this stream'); } parent::__construct($stream, ['window' => -15]); // @deprecated will be removed in 2.0 $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => -15, 'level' => $level]); } protected function readFilter(): string { return 'zlib.inflate'; } protected function writeFilter(): string { return 'zlib.deflate'; } } message/src/Encoding/FilteredStream.php 0000644 00000013126 15111300111 0014113 0 ustar 00 <?php namespace Http\Message\Encoding; use Clue\StreamFilter as Filter; use Http\Message\Decorator\StreamDecorator; use Psr\Http\Message\StreamInterface; /** * A filtered stream has a filter for filtering output and a filter for filtering input made to a underlying stream. * * @author Joel Wurtz <joel.wurtz@gmail.com> */ abstract class FilteredStream implements StreamInterface { use StreamDecorator { rewind as private doRewind; seek as private doSeek; } public const BUFFER_SIZE = 8192; /** * @var callable */ protected $readFilterCallback; /** * @var resource * * @deprecated since version 1.5, will be removed in 2.0 */ protected $readFilter; /** * @var callable * * @deprecated since version 1.5, will be removed in 2.0 */ protected $writeFilterCallback; /** * @var resource * * @deprecated since version 1.5, will be removed in 2.0 */ protected $writeFilter; /** * Internal buffer. * * @var string */ protected $buffer = ''; /** * @param mixed|null $readFilterOptions * @param mixed|null $writeFilterOptions deprecated since 1.5, will be removed in 2.0 */ public function __construct(StreamInterface $stream, $readFilterOptions = null, $writeFilterOptions = null) { if (null !== $readFilterOptions) { $this->readFilterCallback = Filter\fun($this->readFilter(), $readFilterOptions); } else { $this->readFilterCallback = Filter\fun($this->readFilter()); } if (null !== $writeFilterOptions) { $this->writeFilterCallback = Filter\fun($this->writeFilter(), $writeFilterOptions); @trigger_error('The $writeFilterOptions argument is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED); } else { $this->writeFilterCallback = Filter\fun($this->writeFilter()); } $this->stream = $stream; } public function read(int $length): string { if (strlen($this->buffer) >= $length) { $read = substr($this->buffer, 0, $length); $this->buffer = substr($this->buffer, $length); return $read; } if ($this->stream->eof()) { $buffer = $this->buffer; $this->buffer = ''; return $buffer; } $read = $this->buffer; $this->buffer = ''; $this->fill(); return $read.$this->read($length - strlen($read)); } public function eof(): bool { return $this->stream->eof() && '' === $this->buffer; } /** * Buffer is filled by reading underlying stream. * * Callback is reading once more even if the stream is ended. * This allow to get last data in the PHP buffer otherwise this * bug is present : https://bugs.php.net/bug.php?id=48725 */ protected function fill(): void { $readFilterCallback = $this->readFilterCallback; $this->buffer .= $readFilterCallback($this->stream->read(self::BUFFER_SIZE)); if ($this->stream->eof()) { $this->buffer .= $readFilterCallback(); } } /** * {@inheritdoc} */ public function getContents(): string { $buffer = ''; while (!$this->eof()) { $buf = $this->read(self::BUFFER_SIZE); // Using a loose equality here to match on '' and false. if (null == $buf) { break; } $buffer .= $buf; } return $buffer; } /** * Always returns null because we can't tell the size of a stream when we filter. */ public function getSize(): ?int { return null; } public function __toString(): string { return $this->getContents(); } /** * Filtered streams are not seekable. * * We would need to buffer and process everything to allow seeking. */ public function isSeekable(): bool { return false; } /** * Filtered streams are not seekable and can thus not be rewound. */ public function rewind(): void { @trigger_error('Filtered streams are not seekable. This method will start raising an exception in the next major version', E_USER_DEPRECATED); $this->doRewind(); } /** * Filtered streams are not seekable. */ public function seek(int $offset, int $whence = SEEK_SET): void { @trigger_error('Filtered streams are not seekable. This method will start raising an exception in the next major version', E_USER_DEPRECATED); $this->doSeek($offset, $whence); } /** * Returns the read filter name. * * @deprecated since version 1.5, will be removed in 2.0 */ public function getReadFilter(): string { @trigger_error('The '.__CLASS__.'::'.__METHOD__.' method is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED); return $this->readFilter(); } /** * Returns the write filter name. */ abstract protected function readFilter(): string; /** * Returns the write filter name. * * @deprecated since version 1.5, will be removed in 2.0 */ public function getWriteFilter(): string { @trigger_error('The '.__CLASS__.'::'.__METHOD__.' method is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED); return $this->writeFilter(); } /** * Returns the write filter name. */ abstract protected function writeFilter(): string; } message/src/Encoding/DecompressStream.php 0000644 00000001621 15111300111 0014456 0 ustar 00 <?php namespace Http\Message\Encoding; use Clue\StreamFilter as Filter; use Psr\Http\Message\StreamInterface; /** * Stream decompress (RFC 1950). * * @author Joel Wurtz <joel.wurtz@gmail.com> */ class DecompressStream extends FilteredStream { /** * @param int $level */ public function __construct(StreamInterface $stream, $level = -1) { if (!extension_loaded('zlib')) { throw new \RuntimeException('The zlib extension must be enabled to use this stream'); } parent::__construct($stream, ['window' => 15]); // @deprecated will be removed in 2.0 $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => 15, 'level' => $level]); } protected function readFilter(): string { return 'zlib.inflate'; } protected function writeFilter(): string { return 'zlib.deflate'; } } message/src/Encoding/GzipEncodeStream.php 0000644 00000001754 15111300111 0014410 0 ustar 00 <?php namespace Http\Message\Encoding; use Clue\StreamFilter as Filter; use Psr\Http\Message\StreamInterface; /** * Stream for encoding to gzip format (RFC 1952). * * @author Joel Wurtz <joel.wurtz@gmail.com> */ class GzipEncodeStream extends FilteredStream { /** * @param int $level */ public function __construct(StreamInterface $stream, $level = -1) { if (!extension_loaded('zlib')) { throw new \RuntimeException('The zlib extension must be enabled to use this stream'); } parent::__construct($stream, ['window' => 31, 'level' => $level]); // @deprecated will be removed in 2.0 $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => 31]); } /** * {@inheritdoc} */ protected function readFilter(): string { return 'zlib.deflate'; } /** * {@inheritdoc} */ protected function writeFilter(): string { return 'zlib.inflate'; } } message/src/Encoding/CompressStream.php 0000644 00000001615 15111300111 0014150 0 ustar 00 <?php namespace Http\Message\Encoding; use Clue\StreamFilter as Filter; use Psr\Http\Message\StreamInterface; /** * Stream compress (RFC 1950). * * @author Joel Wurtz <joel.wurtz@gmail.com> */ class CompressStream extends FilteredStream { /** * @param int $level */ public function __construct(StreamInterface $stream, $level = -1) { if (!extension_loaded('zlib')) { throw new \RuntimeException('The zlib extension must be enabled to use this stream'); } parent::__construct($stream, ['window' => 15, 'level' => $level]); // @deprecated will be removed in 2.0 $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => 15]); } protected function readFilter(): string { return 'zlib.deflate'; } protected function writeFilter(): string { return 'zlib.inflate'; } } message/src/Encoding/DechunkStream.php 0000644 00000000602 15111300111 0013731 0 ustar 00 <?php namespace Http\Message\Encoding; /** * Decorate a stream which is chunked. * * Allow to decode a chunked stream * * @author Joel Wurtz <joel.wurtz@gmail.com> */ class DechunkStream extends FilteredStream { protected function readFilter(): string { return 'dechunk'; } protected function writeFilter(): string { return 'chunk'; } } message/src/Exception/UnexpectedValueException.php 0000644 00000000247 15111300111 0016371 0 ustar 00 <?php namespace Http\Message\Exception; use Http\Message\Exception; final class UnexpectedValueException extends \UnexpectedValueException implements Exception { } message/src/Decorator/RequestDecorator.php 0000644 00000002661 15111300111 0014672 0 ustar 00 <?php namespace Http\Message\Decorator; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\UriInterface; /** * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ trait RequestDecorator { use MessageDecorator { getMessage as getRequest; } /** * Exchanges the underlying request with another. */ public function withRequest(RequestInterface $request): RequestInterface { $new = clone $this; $new->message = $request; return $new; } public function getRequestTarget(): string { return $this->message->getRequestTarget(); } public function withRequestTarget(string $requestTarget): RequestInterface { $new = clone $this; $new->message = $this->message->withRequestTarget($requestTarget); return $new; } public function getMethod(): string { return $this->message->getMethod(); } public function withMethod(string $method): RequestInterface { $new = clone $this; $new->message = $this->message->withMethod($method); return $new; } public function getUri(): UriInterface { return $this->message->getUri(); } public function withUri(UriInterface $uri, bool $preserveHost = false): RequestInterface { $new = clone $this; $new->message = $this->message->withUri($uri, $preserveHost); return $new; } } message/src/Decorator/ResponseDecorator.php 0000644 00000001642 15111300111 0015036 0 ustar 00 <?php namespace Http\Message\Decorator; use Psr\Http\Message\ResponseInterface; /** * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ trait ResponseDecorator { use MessageDecorator { getMessage as getResponse; } /** * Exchanges the underlying response with another. */ public function withResponse(ResponseInterface $response): ResponseInterface { $new = clone $this; $new->message = $response; return $new; } public function getStatusCode(): int { return $this->message->getStatusCode(); } public function withStatus(int $code, string $reasonPhrase = ''): ResponseInterface { $new = clone $this; $new->message = $this->message->withStatus($code, $reasonPhrase); return $new; } public function getReasonPhrase(): string { return $this->message->getReasonPhrase(); } } message/src/Decorator/MessageDecorator.php 0000644 00000004315 15111300111 0014624 0 ustar 00 <?php namespace Http\Message\Decorator; use Psr\Http\Message\MessageInterface; use Psr\Http\Message\StreamInterface; /** * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ trait MessageDecorator { /** * @var MessageInterface */ private $message; /** * Returns the decorated message. * * Since the underlying Message is immutable as well * exposing it is not an issue, because it's state cannot be altered */ public function getMessage(): MessageInterface { return $this->message; } public function getProtocolVersion(): string { return $this->message->getProtocolVersion(); } public function withProtocolVersion(string $version): MessageInterface { $new = clone $this; $new->message = $this->message->withProtocolVersion($version); return $new; } public function getHeaders(): array { return $this->message->getHeaders(); } public function hasHeader(string $header): bool { return $this->message->hasHeader($header); } public function getHeader(string $header): array { return $this->message->getHeader($header); } public function getHeaderLine(string $header): string { return $this->message->getHeaderLine($header); } public function withHeader(string $header, $value): MessageInterface { $new = clone $this; $new->message = $this->message->withHeader($header, $value); return $new; } public function withAddedHeader(string $header, $value): MessageInterface { $new = clone $this; $new->message = $this->message->withAddedHeader($header, $value); return $new; } public function withoutHeader(string $header): MessageInterface { $new = clone $this; $new->message = $this->message->withoutHeader($header); return $new; } public function getBody(): StreamInterface { return $this->message->getBody(); } public function withBody(StreamInterface $body): MessageInterface { $new = clone $this; $new->message = $this->message->withBody($body); return $new; } } message/src/Decorator/StreamDecorator.php 0000644 00000003244 15111300111 0014473 0 ustar 00 <?php namespace Http\Message\Decorator; use Psr\Http\Message\StreamInterface; /** * Decorates a stream. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ trait StreamDecorator { /** * @var StreamInterface */ protected $stream; public function __toString(): string { return $this->stream->__toString(); } public function close(): void { $this->stream->close(); } public function detach() { return $this->stream->detach(); } public function getSize(): ?int { return $this->stream->getSize(); } public function tell(): int { return $this->stream->tell(); } public function eof(): bool { return $this->stream->eof(); } public function isSeekable(): bool { return $this->stream->isSeekable(); } public function seek(int $offset, int $whence = SEEK_SET): void { $this->stream->seek($offset, $whence); } public function rewind(): void { $this->stream->rewind(); } public function isWritable(): bool { return $this->stream->isWritable(); } public function write(string $string): int { return $this->stream->write($string); } public function isReadable(): bool { return $this->stream->isReadable(); } public function read(int $length): string { return $this->stream->read($length); } public function getContents(): string { return $this->stream->getContents(); } public function getMetadata(string $key = null) { return $this->stream->getMetadata($key); } } message/src/RequestMatcher.php 0000644 00000001241 15111300111 0012402 0 ustar 00 <?php namespace Http\Message; use Psr\Http\Message\RequestInterface; /** * Match a request. * * PSR-7 equivalent of Symfony's RequestMatcher * * @see https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/RequestMatcherInterface.php * * @author Joel Wurtz <joel.wurtz@gmail.com> */ interface RequestMatcher { /** * Decides whether the rule(s) implemented by the strategy matches the supplied request. * * @param RequestInterface $request The PSR7 request to check for a match * * @return bool true if the request matches, false otherwise */ public function matches(RequestInterface $request); } message/src/Cookie.php 0000644 00000025757 15111300111 0010701 0 ustar 00 <?php namespace Http\Message; /** * Cookie Value Object. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> * * @see http://tools.ietf.org/search/rfc6265 */ final class Cookie { /** * @var string */ private $name; /** * @var string|null */ private $value; /** * @var int|null */ private $maxAge; /** * @var string|null */ private $domain; /** * @var string */ private $path; /** * @var bool */ private $secure; /** * @var bool */ private $httpOnly; /** * Expires attribute is HTTP 1.0 only and should be avoided. * * @var \DateTime|null */ private $expires; /** * @param string $name * @param string|null $value * @param int|null $maxAge * @param string|null $domain * @param string|null $path * @param bool $secure * @param bool $httpOnly * @param \DateTime|null $expires Expires attribute is HTTP 1.0 only and should be avoided. * * @throws \InvalidArgumentException if name, value or max age is not valid */ public function __construct( $name, $value = null, $maxAge = null, $domain = null, $path = null, $secure = false, $httpOnly = false, \DateTime $expires = null ) { $this->validateName($name); $this->validateValue($value); $this->validateMaxAge($maxAge); $this->name = $name; $this->value = $value; $this->maxAge = $maxAge; $this->expires = $expires; $this->domain = $this->normalizeDomain($domain); $this->path = $this->normalizePath($path); $this->secure = (bool) $secure; $this->httpOnly = (bool) $httpOnly; } /** * Creates a new cookie without any attribute validation. * * @param string $name * @param string|null $value * @param int $maxAge * @param string|null $domain * @param string|null $path * @param bool $secure * @param bool $httpOnly * @param \DateTime|null $expires Expires attribute is HTTP 1.0 only and should be avoided. */ public static function createWithoutValidation( $name, $value = null, $maxAge = null, $domain = null, $path = null, $secure = false, $httpOnly = false, \DateTime $expires = null ) { $cookie = new self('name', null, null, $domain, $path, $secure, $httpOnly, $expires); $cookie->name = $name; $cookie->value = $value; $cookie->maxAge = $maxAge; return $cookie; } /** * Returns the name. * * @return string */ public function getName() { return $this->name; } /** * Returns the value. * * @return string|null */ public function getValue() { return $this->value; } /** * Checks if there is a value. * * @return bool */ public function hasValue() { return isset($this->value); } /** * Sets the value. * * @param string|null $value * * @return Cookie */ public function withValue($value) { $this->validateValue($value); $new = clone $this; $new->value = $value; return $new; } /** * Returns the max age. * * @return int|null */ public function getMaxAge() { return $this->maxAge; } /** * Checks if there is a max age. * * @return bool */ public function hasMaxAge() { return isset($this->maxAge); } /** * Sets the max age. * * @param int|null $maxAge * * @return Cookie */ public function withMaxAge($maxAge) { $this->validateMaxAge($maxAge); $new = clone $this; $new->maxAge = $maxAge; return $new; } /** * Returns the expiration time. * * @return \DateTime|null */ public function getExpires() { return $this->expires; } /** * Checks if there is an expiration time. * * @return bool */ public function hasExpires() { return isset($this->expires); } /** * Sets the expires. * * @return Cookie */ public function withExpires(\DateTime $expires = null) { $new = clone $this; $new->expires = $expires; return $new; } /** * Checks if the cookie is expired. * * @return bool */ public function isExpired() { return isset($this->expires) and $this->expires < new \DateTime(); } /** * Returns the domain. * * @return string|null */ public function getDomain() { return $this->domain; } /** * Checks if there is a domain. * * @return bool */ public function hasDomain() { return isset($this->domain); } /** * Sets the domain. * * @param string|null $domain * * @return Cookie */ public function withDomain($domain) { $new = clone $this; $new->domain = $this->normalizeDomain($domain); return $new; } /** * Checks whether this cookie is meant for this domain. * * @see http://tools.ietf.org/html/rfc6265#section-5.1.3 * * @param string $domain * * @return bool */ public function matchDomain($domain) { // Domain is not set or exact match if (!$this->hasDomain() || 0 === strcasecmp($domain, $this->domain)) { return true; } // Domain is not an IP address if (filter_var($domain, FILTER_VALIDATE_IP)) { return false; } return (bool) preg_match(sprintf('/\b%s$/i', preg_quote($this->domain)), $domain); } /** * Returns the path. * * @return string */ public function getPath() { return $this->path; } /** * Sets the path. * * @param string|null $path * * @return Cookie */ public function withPath($path) { $new = clone $this; $new->path = $this->normalizePath($path); return $new; } /** * Checks whether this cookie is meant for this path. * * @see http://tools.ietf.org/html/rfc6265#section-5.1.4 * * @param string $path * * @return bool */ public function matchPath($path) { return $this->path === $path || (0 === strpos($path, rtrim($this->path, '/').'/')); } /** * Checks whether this cookie may only be sent over HTTPS. * * @return bool */ public function isSecure() { return $this->secure; } /** * Sets whether this cookie should only be sent over HTTPS. * * @param bool $secure * * @return Cookie */ public function withSecure($secure) { $new = clone $this; $new->secure = (bool) $secure; return $new; } /** * Check whether this cookie may not be accessed through Javascript. * * @return bool */ public function isHttpOnly() { return $this->httpOnly; } /** * Sets whether this cookie may not be accessed through Javascript. * * @param bool $httpOnly * * @return Cookie */ public function withHttpOnly($httpOnly) { $new = clone $this; $new->httpOnly = (bool) $httpOnly; return $new; } /** * Checks if this cookie represents the same cookie as $cookie. * * This does not compare the values, only name, domain and path. * * @return bool */ public function match(self $cookie) { return $this->name === $cookie->name && $this->domain === $cookie->domain and $this->path === $cookie->path; } /** * Validates cookie attributes. * * @return bool */ public function isValid() { try { $this->validateName($this->name); $this->validateValue($this->value); $this->validateMaxAge($this->maxAge); } catch (\InvalidArgumentException $e) { return false; } return true; } /** * Validates the name attribute. * * @see http://tools.ietf.org/search/rfc2616#section-2.2 * * @param string $name * * @throws \InvalidArgumentException if the name is empty or contains invalid characters */ private function validateName($name) { if (strlen($name) < 1) { throw new \InvalidArgumentException('The name cannot be empty'); } // Name attribute is a token as per spec in RFC 2616 if (preg_match('/[\x00-\x20\x22\x28-\x29\x2C\x2F\x3A-\x40\x5B-\x5D\x7B\x7D\x7F]/', $name)) { throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name)); } } /** * Validates a value. * * @see http://tools.ietf.org/html/rfc6265#section-4.1.1 * * @param string|null $value * * @throws \InvalidArgumentException if the value contains invalid characters */ private function validateValue($value) { if (isset($value)) { if (preg_match('/[^\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]/', $value)) { throw new \InvalidArgumentException(sprintf('The cookie value "%s" contains invalid characters.', $value)); } } } /** * Validates a Max-Age attribute. * * @param int|null $maxAge * * @throws \InvalidArgumentException if the Max-Age is not an empty or integer value */ private function validateMaxAge($maxAge) { if (isset($maxAge)) { if (!is_int($maxAge)) { throw new \InvalidArgumentException('Max-Age must be integer'); } } } /** * Remove the leading '.' and lowercase the domain as per spec in RFC 6265. * * @see http://tools.ietf.org/html/rfc6265#section-4.1.2.3 * @see http://tools.ietf.org/html/rfc6265#section-5.1.3 * @see http://tools.ietf.org/html/rfc6265#section-5.2.3 * * @param string|null $domain * * @return string */ private function normalizeDomain($domain) { if (isset($domain)) { $domain = ltrim(strtolower($domain), '.'); } return $domain; } /** * Processes path as per spec in RFC 6265. * * @see http://tools.ietf.org/html/rfc6265#section-5.1.4 * @see http://tools.ietf.org/html/rfc6265#section-5.2.4 * * @param string|null $path * * @return string */ private function normalizePath($path) { $path = rtrim($path, '/'); if (empty($path) or '/' !== substr($path, 0, 1)) { $path = '/'; } return $path; } } message/src/Formatter/SimpleFormatter.php 0000644 00000002313 15111300111 0014527 0 ustar 00 <?php namespace Http\Message\Formatter; use Http\Message\Formatter; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; /** * Normalize a request or a response into a string or an array. * * @author Joel Wurtz <joel.wurtz@gmail.com> * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ class SimpleFormatter implements Formatter { /** * {@inheritdoc} */ public function formatRequest(RequestInterface $request) { return sprintf( '%s %s %s', $request->getMethod(), $request->getUri()->__toString(), $request->getProtocolVersion() ); } /** * {@inheritdoc} */ public function formatResponse(ResponseInterface $response) { return sprintf( '%s %s %s', $response->getStatusCode(), $response->getReasonPhrase(), $response->getProtocolVersion() ); } /** * Formats a response in context of its request. * * @return string */ public function formatResponseForRequest(ResponseInterface $response, RequestInterface $request) { return $this->formatResponse($response); } } message/src/Formatter/CurlCommandFormatter.php 0000644 00000006032 15111300111 0015504 0 ustar 00 <?php namespace Http\Message\Formatter; use Http\Message\Formatter; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; /** * A formatter that prints a cURL command for HTTP requests. * * @author Tobias Nyholm <tobias.nyholm@gmail.com> */ class CurlCommandFormatter implements Formatter { /** * {@inheritdoc} */ public function formatRequest(RequestInterface $request) { $command = sprintf('curl %s', escapeshellarg((string) $request->getUri()->withFragment(''))); if ('1.0' === $request->getProtocolVersion()) { $command .= ' --http1.0'; } elseif ('2.0' === $request->getProtocolVersion()) { $command .= ' --http2'; } $method = strtoupper($request->getMethod()); if ('HEAD' === $method) { $command .= ' --head'; } elseif ('GET' !== $method) { $command .= ' --request '.$method; } $command .= $this->getHeadersAsCommandOptions($request); $body = $request->getBody(); if ($body->getSize() > 0) { // escapeshellarg argument max length on Windows, but longer body in curl command would be impractical anyways if ($body->getSize() > 8192) { $data = '[too long stream omitted]'; } elseif ($body->isSeekable()) { $data = $body->__toString(); $body->rewind(); // all non-printable ASCII characters and <DEL> except for \t, \r, \n if (preg_match('/([\x00-\x09\x0C\x0E-\x1F\x7F])/', $data)) { $data = '[binary stream omitted]'; } } else { $data = '[non-seekable stream omitted]'; } $escapedData = @escapeshellarg($data); if (empty($escapedData)) { $escapedData = 'We couldn\'t not escape the data properly'; } $command .= sprintf(' --data %s', $escapedData); } return $command; } /** * {@inheritdoc} */ public function formatResponse(ResponseInterface $response) { return ''; } /** * Formats a response in context of its request. * * @return string */ public function formatResponseForRequest(ResponseInterface $response, RequestInterface $request) { return $this->formatResponse($response); } /** * @return string */ private function getHeadersAsCommandOptions(RequestInterface $request) { $command = ''; foreach ($request->getHeaders() as $name => $values) { if ('host' === strtolower($name) && $values[0] === $request->getUri()->getHost()) { continue; } if ('user-agent' === strtolower($name)) { $command .= sprintf(' -A %s', escapeshellarg($values[0])); continue; } $command .= sprintf(' -H %s', escapeshellarg($name.': '.$request->getHeaderLine($name))); } return $command; } } message/src/Formatter/FullHttpMessageFormatter.php 0000644 00000005676 15111300111 0016364 0 ustar 00 <?php namespace Http\Message\Formatter; use Http\Message\Formatter; use Psr\Http\Message\MessageInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; /** * A formatter that prints the complete HTTP message. * * @author Tobias Nyholm <tobias.nyholm@gmail.com> */ class FullHttpMessageFormatter implements Formatter { /** * The maximum length of the body. * * @var int|null */ private $maxBodyLength; /** * @var string */ private $binaryDetectionRegex; /** * @param int|null $maxBodyLength * @param string $binaryDetectionRegex By default, this is all non-printable ASCII characters and <DEL> except for \t, \r, \n */ public function __construct($maxBodyLength = 1000, string $binaryDetectionRegex = '/([\x00-\x09\x0C\x0E-\x1F\x7F])/') { $this->maxBodyLength = $maxBodyLength; $this->binaryDetectionRegex = $binaryDetectionRegex; } /** * {@inheritdoc} */ public function formatRequest(RequestInterface $request) { $message = sprintf( "%s %s HTTP/%s\n", $request->getMethod(), $request->getRequestTarget(), $request->getProtocolVersion() ); foreach ($request->getHeaders() as $name => $values) { $message .= $name.': '.implode(', ', $values)."\n"; } return $this->addBody($request, $message); } /** * {@inheritdoc} */ public function formatResponse(ResponseInterface $response) { $message = sprintf( "HTTP/%s %s %s\n", $response->getProtocolVersion(), $response->getStatusCode(), $response->getReasonPhrase() ); foreach ($response->getHeaders() as $name => $values) { $message .= $name.': '.implode(', ', $values)."\n"; } return $this->addBody($response, $message); } /** * Formats a response in context of its request. * * @return string */ public function formatResponseForRequest(ResponseInterface $response, RequestInterface $request) { return $this->formatResponse($response); } /** * Add the message body if the stream is seekable. * * @param string $message * * @return string */ private function addBody(MessageInterface $request, $message) { $message .= "\n"; $stream = $request->getBody(); if (!$stream->isSeekable() || 0 === $this->maxBodyLength) { // Do not read the stream return $message; } $data = $stream->__toString(); $stream->rewind(); if (preg_match($this->binaryDetectionRegex, $data)) { return $message.'[binary stream omitted]'; } if (null === $this->maxBodyLength) { return $message.$data; } return $message.mb_substr($data, 0, $this->maxBodyLength); } } message/src/Authentication/AutoBasicAuth.php 0000644 00000002213 15111300111 0015121 0 ustar 00 <?php namespace Http\Message\Authentication; use Http\Message\Authentication; use Psr\Http\Message\RequestInterface; /** * Authenticate a PSR-7 Request using Basic Auth based on credentials in the URI. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ final class AutoBasicAuth implements Authentication { /** * Whether user info should be removed from the URI. * * @var bool */ private $shouldRemoveUserInfo; /** * @param bool|true $shouldRremoveUserInfo */ public function __construct($shouldRremoveUserInfo = true) { $this->shouldRemoveUserInfo = (bool) $shouldRremoveUserInfo; } /** * {@inheritdoc} */ public function authenticate(RequestInterface $request) { $uri = $request->getUri(); $userInfo = $uri->getUserInfo(); if (!empty($userInfo)) { if ($this->shouldRemoveUserInfo) { $request = $request->withUri($uri->withUserInfo('')); } $request = $request->withHeader('Authorization', sprintf('Basic %s', base64_encode($userInfo))); } return $request; } } message/src/Authentication/Matching.php 0000644 00000003453 15111300111 0014166 0 ustar 00 <?php namespace Http\Message\Authentication; use Http\Message\Authentication; use Http\Message\RequestMatcher\CallbackRequestMatcher; use Psr\Http\Message\RequestInterface; @trigger_error('The '.__NAMESPACE__.'\Matching class is deprecated since version 1.2 and will be removed in 2.0. Use Http\Message\Authentication\RequestConditional instead.', E_USER_DEPRECATED); /** * Authenticate a PSR-7 Request if the request is matching. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> * * @deprecated since since version 1.2, and will be removed in 2.0. Use {@link RequestConditional} instead. */ final class Matching implements Authentication { /** * @var Authentication */ private $authentication; /** * @var CallbackRequestMatcher */ private $matcher; public function __construct(Authentication $authentication, callable $matcher = null) { if (is_null($matcher)) { $matcher = function () { return true; }; } $this->authentication = $authentication; $this->matcher = new CallbackRequestMatcher($matcher); } /** * {@inheritdoc} */ public function authenticate(RequestInterface $request) { if ($this->matcher->matches($request)) { return $this->authentication->authenticate($request); } return $request; } /** * Creates a matching authentication for an URL. * * @param string $url * * @return self */ public static function createUrlMatcher(Authentication $authentication, $url) { $matcher = function (RequestInterface $request) use ($url) { return preg_match($url, $request->getRequestTarget()); }; return new static($authentication, $matcher); } } message/src/Authentication/Bearer.php 0000644 00000001267 15111300111 0013635 0 ustar 00 <?php namespace Http\Message\Authentication; use Http\Message\Authentication; use Psr\Http\Message\RequestInterface; /** * Authenticate a PSR-7 Request using a token. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ final class Bearer implements Authentication { /** * @var string */ private $token; /** * @param string $token */ public function __construct($token) { $this->token = $token; } /** * {@inheritdoc} */ public function authenticate(RequestInterface $request) { $header = sprintf('Bearer %s', $this->token); return $request->withHeader('Authorization', $header); } } message/src/Authentication/Wsse.php 0000644 00000003333 15111300111 0013352 0 ustar 00 <?php namespace Http\Message\Authentication; use Http\Message\Authentication; use Psr\Http\Message\RequestInterface; /** * Authenticate a PSR-7 Request using WSSE. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ final class Wsse implements Authentication { /** * @var string */ private $username; /** * @var string */ private $password; /** * @var string */ private $hashAlgorithm; /** * @param string $username * @param string $password * @param string $hashAlgorithm To use a better hashing algorithm than the weak sha1, pass the algorithm to use, e.g. "sha512" */ public function __construct($username, $password, $hashAlgorithm = 'sha1') { $this->username = $username; $this->password = $password; if (false === in_array($hashAlgorithm, hash_algos())) { throw new \InvalidArgumentException(sprintf('Unaccepted hashing algorithm: %s', $hashAlgorithm)); } $this->hashAlgorithm = $hashAlgorithm; } /** * {@inheritdoc} */ public function authenticate(RequestInterface $request) { $nonce = substr(md5(uniqid(uniqid().'_', true)), 0, 16); $created = date('c'); $digest = base64_encode(hash($this->hashAlgorithm, base64_decode($nonce).$created.$this->password, true)); $wsse = sprintf( 'UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"', $this->username, $digest, $nonce, $created ); return $request ->withHeader('Authorization', 'WSSE profile="UsernameToken"') ->withHeader('X-WSSE', $wsse) ; } } message/src/Authentication/RequestConditional.php 0000644 00000001734 15111300111 0016250 0 ustar 00 <?php namespace Http\Message\Authentication; use Http\Message\Authentication; use Http\Message\RequestMatcher; use Psr\Http\Message\RequestInterface; /** * Authenticate a PSR-7 Request if the request is matching the given request matcher. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ final class RequestConditional implements Authentication { /** * @var RequestMatcher */ private $requestMatcher; /** * @var Authentication */ private $authentication; public function __construct(RequestMatcher $requestMatcher, Authentication $authentication) { $this->requestMatcher = $requestMatcher; $this->authentication = $authentication; } /** * {@inheritdoc} */ public function authenticate(RequestInterface $request) { if ($this->requestMatcher->matches($request)) { return $this->authentication->authenticate($request); } return $request; } } message/src/Authentication/Header.php 0000644 00000001174 15111300111 0013622 0 ustar 00 <?php namespace Http\Message\Authentication; use Http\Message\Authentication; use Psr\Http\Message\RequestInterface; class Header implements Authentication { /** * @var string */ private $name; /** * @var string|string[] */ private $value; /** * @param string|string[] $value */ public function __construct(string $name, $value) { $this->name = $name; $this->value = $value; } /** * {@inheritdoc} */ public function authenticate(RequestInterface $request) { return $request->withHeader($this->name, $this->value); } } message/src/Authentication/Chain.php 0000644 00000002252 15111300111 0013452 0 ustar 00 <?php namespace Http\Message\Authentication; use Http\Message\Authentication; use Psr\Http\Message\RequestInterface; /** * Authenticate a PSR-7 Request with a multiple authentication methods. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ final class Chain implements Authentication { /** * @var Authentication[] */ private $authenticationChain = []; /** * @param Authentication[] $authenticationChain */ public function __construct(array $authenticationChain = []) { foreach ($authenticationChain as $authentication) { if (!$authentication instanceof Authentication) { throw new \InvalidArgumentException( 'Members of the authentication chain must be of type Http\Message\Authentication' ); } } $this->authenticationChain = $authenticationChain; } /** * {@inheritdoc} */ public function authenticate(RequestInterface $request) { foreach ($this->authenticationChain as $authentication) { $request = $authentication->authenticate($request); } return $request; } } message/src/Authentication/QueryParam.php 0000644 00000002116 15111300111 0014515 0 ustar 00 <?php namespace Http\Message\Authentication; use Http\Message\Authentication; use Psr\Http\Message\RequestInterface; /** * Authenticate a PSR-7 Request by adding parameters to its query. * * Note: Although in some cases it can be useful, we do not recommend using query parameters for authentication. * Credentials in the URL is generally unsafe as they are not encrypted, anyone can see them. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ final class QueryParam implements Authentication { /** * @var array */ private $params = []; public function __construct(array $params) { $this->params = $params; } /** * {@inheritdoc} */ public function authenticate(RequestInterface $request) { $uri = $request->getUri(); $query = $uri->getQuery(); $params = []; parse_str($query, $params); $params = array_merge($params, $this->params); $query = http_build_query($params, '', '&'); $uri = $uri->withQuery($query); return $request->withUri($uri); } } message/src/Authentication/BasicAuth.php 0000644 00000001612 15111300111 0014272 0 ustar 00 <?php namespace Http\Message\Authentication; use Http\Message\Authentication; use Psr\Http\Message\RequestInterface; /** * Authenticate a PSR-7 Request using Basic Auth. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ final class BasicAuth implements Authentication { /** * @var string */ private $username; /** * @var string */ private $password; /** * @param string $username * @param string $password */ public function __construct($username, $password) { $this->username = $username; $this->password = $password; } /** * {@inheritdoc} */ public function authenticate(RequestInterface $request) { $header = sprintf('Basic %s', base64_encode(sprintf('%s:%s', $this->username, $this->password))); return $request->withHeader('Authorization', $header); } } message/src/RequestMatcher/RequestMatcher.php 0000644 00000004070 15111300111 0015341 0 ustar 00 <?php namespace Http\Message\RequestMatcher; use Http\Message\RequestMatcher as RequestMatcherInterface; use Psr\Http\Message\RequestInterface; /** * A port of the Symfony RequestMatcher for PSR-7. * * @author Fabien Potencier <fabien@symfony.com> * @author Joel Wurtz <joel.wurtz@gmail.com> */ final class RequestMatcher implements RequestMatcherInterface { /** * @var string */ private $path; /** * @var string */ private $host; /** * @var array */ private $methods = []; /** * @var string[] */ private $schemes = []; /** * The regular expressions used for path or host must be specified without delimiter. * You do not need to escape the forward slash / to match it. * * @param string|null $path Regular expression for the path * @param string|null $host Regular expression for the hostname * @param string|string[]|null $methods Method or list of methods to match * @param string|string[]|null $schemes Scheme or list of schemes to match (e.g. http or https) */ public function __construct($path = null, $host = null, $methods = [], $schemes = []) { $this->path = $path; $this->host = $host; $this->methods = array_map('strtoupper', (array) $methods); $this->schemes = array_map('strtolower', (array) $schemes); } /** * {@inheritdoc} * * @api */ public function matches(RequestInterface $request) { if ($this->schemes && !in_array($request->getUri()->getScheme(), $this->schemes)) { return false; } if ($this->methods && !in_array($request->getMethod(), $this->methods)) { return false; } if (null !== $this->path && !preg_match('{'.$this->path.'}', rawurldecode($request->getUri()->getPath()))) { return false; } if (null !== $this->host && !preg_match('{'.$this->host.'}i', $request->getUri()->getHost())) { return false; } return true; } } message/src/RequestMatcher/RegexRequestMatcher.php 0000644 00000001724 15111300111 0016337 0 ustar 00 <?php namespace Http\Message\RequestMatcher; use Http\Message\RequestMatcher; use Psr\Http\Message\RequestInterface; @trigger_error('The '.__NAMESPACE__.'\RegexRequestMatcher class is deprecated since version 1.2 and will be removed in 2.0. Use Http\Message\RequestMatcher\RequestMatcher instead.', E_USER_DEPRECATED); /** * Match a request with a regex on the uri. * * @author Joel Wurtz <joel.wurtz@gmail.com> * * @deprecated since version 1.2 and will be removed in 2.0. Use {@link RequestMatcher} instead. */ final class RegexRequestMatcher implements RequestMatcher { /** * Matching regex. * * @var string */ private $regex; /** * @param string $regex */ public function __construct($regex) { $this->regex = $regex; } /** * {@inheritdoc} */ public function matches(RequestInterface $request) { return (bool) preg_match($this->regex, (string) $request->getUri()); } } message/src/RequestMatcher/CallbackRequestMatcher.php 0000644 00000001155 15111300111 0016757 0 ustar 00 <?php namespace Http\Message\RequestMatcher; use Http\Message\RequestMatcher; use Psr\Http\Message\RequestInterface; /** * Match a request with a callback. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ final class CallbackRequestMatcher implements RequestMatcher { /** * @var callable */ private $callback; public function __construct(callable $callback) { $this->callback = $callback; } /** * {@inheritdoc} */ public function matches(RequestInterface $request) { return (bool) call_user_func($this->callback, $request); } } message/src/StreamFactory/GuzzleStreamFactory.php 0000644 00000001772 15111300111 0016226 0 ustar 00 <?php namespace Http\Message\StreamFactory; use GuzzleHttp\Psr7\Utils; use Http\Message\StreamFactory; if (!interface_exists(StreamFactory::class)) { throw new \LogicException('You cannot use "Http\Message\MessageFactory\GuzzleStreamFactory" as the "php-http/message-factory" package is not installed. Try running "composer require php-http/message-factory". Note that this package is deprecated, use "psr/http-factory" instead'); } /** * Creates Guzzle streams. * * @author Михаил Красильников <m.krasilnikov@yandex.ru> * * @deprecated This will be removed in php-http/message2.0. Consider using the official Guzzle PSR-17 factory */ final class GuzzleStreamFactory implements StreamFactory { /** * {@inheritdoc} */ public function createStream($body = null) { if (class_exists(Utils::class)) { return Utils::streamFor($body); } // legacy support for guzzle/psr7 1.* return \GuzzleHttp\Psr7\stream_for($body); } } message/src/StreamFactory/DiactorosStreamFactory.php 0000644 00000003017 15111300111 0016667 0 ustar 00 <?php namespace Http\Message\StreamFactory; use Http\Message\StreamFactory; use Laminas\Diactoros\Stream as LaminasStream; use Psr\Http\Message\StreamInterface; use Zend\Diactoros\Stream as ZendStream; if (!interface_exists(StreamFactory::class)) { throw new \LogicException('You cannot use "Http\Message\MessageFactory\DiactorosStreamFactory" as the "php-http/message-factory" package is not installed. Try running "composer require php-http/message-factory". Note that this package is deprecated, use "psr/http-factory" instead'); } /** * Creates Diactoros streams. * * @author Михаил Красильников <m.krasilnikov@yandex.ru> * * @deprecated This will be removed in php-http/message2.0. Consider using the official Diactoros PSR-17 factory */ final class DiactorosStreamFactory implements StreamFactory { /** * {@inheritdoc} */ public function createStream($body = null) { if ($body instanceof StreamInterface) { return $body; } if (is_resource($body)) { if (class_exists(LaminasStream::class)) { return new LaminasStream($body); } return new ZendStream($body); } if (class_exists(LaminasStream::class)) { $stream = new LaminasStream('php://memory', 'rw'); } else { $stream = new ZendStream('php://memory', 'rw'); } if (null !== $body && '' !== $body) { $stream->write((string) $body); } return $stream; } } message/src/StreamFactory/SlimStreamFactory.php 0000644 00000002270 15111300111 0015644 0 ustar 00 <?php namespace Http\Message\StreamFactory; use Http\Message\StreamFactory; use Psr\Http\Message\StreamInterface; use Slim\Http\Stream; if (!interface_exists(StreamFactory::class)) { throw new \LogicException('You cannot use "Http\Message\MessageFactory\SlimStreamFactory" as the "php-http/message-factory" package is not installed. Try running "composer require php-http/message-factory". Note that this package is deprecated, use "psr/http-factory" instead'); } /** * Creates Slim 3 streams. * * @author Mika Tuupola <tuupola@appelsiini.net> * * @deprecated This will be removed in php-http/message2.0. Consider using the official Slim PSR-17 factory */ final class SlimStreamFactory implements StreamFactory { /** * {@inheritdoc} */ public function createStream($body = null) { if ($body instanceof StreamInterface) { return $body; } if (is_resource($body)) { return new Stream($body); } $resource = fopen('php://memory', 'r+'); $stream = new Stream($resource); if (null !== $body && '' !== $body) { $stream->write((string) $body); } return $stream; } } message/src/Stream/BufferedStream.php 0000644 00000014046 15111300111 0013606 0 ustar 00 <?php namespace Http\Message\Stream; use Psr\Http\Message\StreamInterface; /** * Decorator to make any stream seekable. * * Internally it buffers an existing StreamInterface into a php://temp resource (or memory). By default it will use * 2 megabytes of memory before writing to a temporary disk file. * * Due to this, very large stream can suffer performance issue (i/o slowdown). */ class BufferedStream implements StreamInterface { /** @var resource The buffered resource used to seek previous data */ private $resource; /** @var int|null size of the stream if available */ private $size; /** @var StreamInterface The underlying stream decorated by this class */ private $stream; /** @var int How many bytes were written */ private $written = 0; /** * @param StreamInterface $stream Decorated stream * @param bool $useFileBuffer Whether to use a file buffer (write to a file, if data exceed a certain size) * by default, set this to false to only use memory * @param int $memoryBuffer In conjunction with using file buffer, limit (in bytes) from which it begins to buffer * the data in a file */ public function __construct(StreamInterface $stream, $useFileBuffer = true, $memoryBuffer = 2097152) { $this->stream = $stream; $this->size = $stream->getSize(); if ($useFileBuffer) { $this->resource = fopen('php://temp/maxmemory:'.$memoryBuffer, 'rw+'); } else { $this->resource = fopen('php://memory', 'rw+'); } if (false === $this->resource) { throw new \RuntimeException('Cannot create a resource over temp or memory implementation'); } } public function __toString(): string { try { $this->rewind(); return $this->getContents(); } catch (\Throwable $throwable) { return ''; } } public function close(): void { if (null === $this->resource) { throw new \RuntimeException('Cannot close on a detached stream'); } $this->stream->close(); fclose($this->resource); } public function detach() { if (null === $this->resource) { return null; } // Force reading the remaining data of the stream $this->getContents(); $resource = $this->resource; $this->stream->close(); $this->stream = null; $this->resource = null; return $resource; } public function getSize(): ?int { if (null === $this->resource) { return null; } if (null === $this->size && $this->stream->eof()) { return $this->written; } return $this->size; } public function tell(): int { if (null === $this->resource) { throw new \RuntimeException('Cannot tell on a detached stream'); } $tell = ftell($this->resource); if (false === $tell) { throw new \RuntimeException('ftell failed'); } return $tell; } public function eof(): bool { if (null === $this->resource) { throw new \RuntimeException('Cannot call eof on a detached stream'); } // We are at the end only when both our resource and underlying stream are at eof return $this->stream->eof() && (ftell($this->resource) === $this->written); } public function isSeekable(): bool { return null !== $this->resource; } public function seek(int $offset, int $whence = SEEK_SET): void { if (null === $this->resource) { throw new \RuntimeException('Cannot seek on a detached stream'); } fseek($this->resource, $offset, $whence); } public function rewind(): void { if (null === $this->resource) { throw new \RuntimeException('Cannot rewind on a detached stream'); } rewind($this->resource); } public function isWritable(): bool { return false; } public function write(string $string): int { throw new \RuntimeException('Cannot write on this stream'); } public function isReadable(): bool { return null !== $this->resource; } public function read(int $length): string { if (null === $this->resource) { throw new \RuntimeException('Cannot read on a detached stream'); } if ($length < 0) { throw new \InvalidArgumentException('Can not read a negative amount of bytes'); } $read = ''; // First read from the resource if (ftell($this->resource) !== $this->written) { $read = fread($this->resource, $length); } if (false === $read) { throw new \RuntimeException('Failed to read from resource'); } $bytesRead = strlen($read); if ($bytesRead < $length) { $streamRead = $this->stream->read($length - $bytesRead); // Write on the underlying stream what we read $this->written += fwrite($this->resource, $streamRead); $read .= $streamRead; } return $read; } public function getContents(): string { if (null === $this->resource) { throw new \RuntimeException('Cannot read on a detached stream'); } $read = ''; while (!$this->eof()) { $read .= $this->read(8192); } return $read; } public function getMetadata(?string $key = null) { if (null === $this->resource) { if (null === $key) { return []; } return null; } $metadata = stream_get_meta_data($this->resource); if (null === $key) { return $metadata; } if (!array_key_exists($key, $metadata)) { return null; } return $metadata[$key]; } } message/src/Builder/ResponseBuilder.php 0000644 00000007461 15111300111 0014153 0 ustar 00 <?php namespace Http\Message\Builder; use Psr\Http\Message\ResponseInterface; /** * Fills response object with values. */ class ResponseBuilder { /** * The response to be built. * * @var ResponseInterface */ protected $response; /** * Create builder for the given response. */ public function __construct(ResponseInterface $response) { $this->response = $response; } /** * Return response. * * @return ResponseInterface */ public function getResponse() { return $this->response; } /** * Add headers represented by an array of header lines. * * @param string[] $headers response headers as array of header lines * * @return $this * * @throws \UnexpectedValueException for invalid header values * @throws \InvalidArgumentException for invalid status code arguments */ public function setHeadersFromArray(array $headers) { $status = array_shift($headers); $this->setStatus($status); foreach ($headers as $headerLine) { $headerLine = trim($headerLine); if ('' === $headerLine) { continue; } $this->addHeader($headerLine); } return $this; } /** * Add headers represented by a single string. * * @param string $headers response headers as single string * * @return $this * * @throws \InvalidArgumentException if $headers is not a string on object with __toString() * @throws \UnexpectedValueException for invalid header values */ public function setHeadersFromString($headers) { if (!(is_string($headers) || (is_object($headers) && method_exists($headers, '__toString'))) ) { throw new \InvalidArgumentException( sprintf( '%s expects parameter 1 to be a string, %s given', __METHOD__, is_object($headers) ? get_class($headers) : gettype($headers) ) ); } $this->setHeadersFromArray(explode("\r\n", $headers)); return $this; } /** * Set response status from a status string. * * @param string $statusLine response status as a string * * @return $this * * @throws \InvalidArgumentException for invalid status line */ public function setStatus($statusLine) { $parts = explode(' ', $statusLine, 3); if (count($parts) < 2 || 0 !== strpos(strtolower($parts[0]), 'http/')) { throw new \InvalidArgumentException( sprintf('"%s" is not a valid HTTP status line', $statusLine) ); } $reasonPhrase = count($parts) > 2 ? $parts[2] : ''; $this->response = $this->response ->withStatus((int) $parts[1], $reasonPhrase) ->withProtocolVersion(substr($parts[0], 5)); return $this; } /** * Add header represented by a string. * * @param string $headerLine response header as a string * * @return $this * * @throws \InvalidArgumentException for invalid header names or values */ public function addHeader($headerLine) { $parts = explode(':', $headerLine, 2); if (2 !== count($parts)) { throw new \InvalidArgumentException( sprintf('"%s" is not a valid HTTP header line', $headerLine) ); } $name = trim($parts[0]); $value = trim($parts[1]); if ($this->response->hasHeader($name)) { $this->response = $this->response->withAddedHeader($name, $value); } else { $this->response = $this->response->withHeader($name, $value); } return $this; } } message/src/MessageFactory/GuzzleMessageFactory.php 0000644 00000002721 15111300111 0016503 0 ustar 00 <?php namespace Http\Message\MessageFactory; use GuzzleHttp\Psr7\Request; use GuzzleHttp\Psr7\Response; use Http\Message\MessageFactory; if (!interface_exists(MessageFactory::class)) { throw new \LogicException('You cannot use "Http\Message\MessageFactory\GuzzleMessageFactory" as the "php-http/message-factory" package is not installed. Try running "composer require php-http/message-factory". Note that this package is deprecated, use "psr/http-factory" instead'); } /** * Creates Guzzle messages. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> * * @deprecated This will be removed in php-http/message2.0. Consider using the official Guzzle PSR-17 factory */ final class GuzzleMessageFactory implements MessageFactory { /** * {@inheritdoc} */ public function createRequest( $method, $uri, array $headers = [], $body = null, $protocolVersion = '1.1' ) { return new Request( $method, $uri, $headers, $body, $protocolVersion ); } /** * {@inheritdoc} */ public function createResponse( $statusCode = 200, $reasonPhrase = null, array $headers = [], $body = null, $protocolVersion = '1.1' ) { return new Response( $statusCode, $headers, $body, $protocolVersion, $reasonPhrase ); } } message/src/MessageFactory/SlimMessageFactory.php 0000644 00000004000 15111300111 0016117 0 ustar 00 <?php namespace Http\Message\MessageFactory; use Http\Message\MessageFactory; use Http\Message\StreamFactory\SlimStreamFactory; use Http\Message\UriFactory\SlimUriFactory; use Slim\Http\Headers; use Slim\Http\Request; use Slim\Http\Response; if (!interface_exists(MessageFactory::class)) { throw new \LogicException('You cannot use "Http\Message\MessageFactory\SlimMessageFactory" as the "php-http/message-factory" package is not installed. Try running "composer require php-http/message-factory". Note that this package is deprecated, use "psr/http-factory" instead'); } /** * Creates Slim 3 messages. * * @author Mika Tuupola <tuupola@appelsiini.net> * * @deprecated This will be removed in php-http/message2.0. Consider using the official Slim PSR-17 factory */ final class SlimMessageFactory implements MessageFactory { /** * @var SlimStreamFactory */ private $streamFactory; /** * @var SlimUriFactory */ private $uriFactory; public function __construct() { $this->streamFactory = new SlimStreamFactory(); $this->uriFactory = new SlimUriFactory(); } /** * {@inheritdoc} */ public function createRequest( $method, $uri, array $headers = [], $body = null, $protocolVersion = '1.1' ) { return (new Request( $method, $this->uriFactory->createUri($uri), new Headers($headers), [], [], $this->streamFactory->createStream($body), [] ))->withProtocolVersion($protocolVersion); } /** * {@inheritdoc} */ public function createResponse( $statusCode = 200, $reasonPhrase = null, array $headers = [], $body = null, $protocolVersion = '1.1' ) { return (new Response( $statusCode, new Headers($headers), $this->streamFactory->createStream($body) ))->withProtocolVersion($protocolVersion); } } message/src/MessageFactory/DiactorosMessageFactory.php 0000644 00000004673 15111300111 0017162 0 ustar 00 <?php namespace Http\Message\MessageFactory; use Http\Message\MessageFactory; use Http\Message\StreamFactory\DiactorosStreamFactory; use Laminas\Diactoros\Request as LaminasRequest; use Laminas\Diactoros\Response as LaminasResponse; use Zend\Diactoros\Request as ZendRequest; use Zend\Diactoros\Response as ZendResponse; if (!interface_exists(MessageFactory::class)) { throw new \LogicException('You cannot use "Http\Message\MessageFactory\DiactorosMessageFactory" as the "php-http/message-factory" package is not installed. Try running "composer require php-http/message-factory". Note that this package is deprecated, use "psr/http-factory" instead'); } /** * Creates Diactoros messages. * * @author GeLo <geloen.eric@gmail.com> * * @deprecated This will be removed in php-http/message2.0. Consider using the official Diactoros PSR-17 factory */ final class DiactorosMessageFactory implements MessageFactory { /** * @var DiactorosStreamFactory */ private $streamFactory; public function __construct() { $this->streamFactory = new DiactorosStreamFactory(); } /** * {@inheritdoc} */ public function createRequest( $method, $uri, array $headers = [], $body = null, $protocolVersion = '1.1' ) { if (class_exists(LaminasRequest::class)) { return (new LaminasRequest( $uri, $method, $this->streamFactory->createStream($body), $headers ))->withProtocolVersion($protocolVersion); } return (new ZendRequest( $uri, $method, $this->streamFactory->createStream($body), $headers ))->withProtocolVersion($protocolVersion); } /** * {@inheritdoc} */ public function createResponse( $statusCode = 200, $reasonPhrase = null, array $headers = [], $body = null, $protocolVersion = '1.1' ) { if (class_exists(LaminasResponse::class)) { return (new LaminasResponse( $this->streamFactory->createStream($body), $statusCode, $headers ))->withProtocolVersion($protocolVersion); } return (new ZendResponse( $this->streamFactory->createStream($body), $statusCode, $headers ))->withProtocolVersion($protocolVersion); } } message/src/Formatter.php 0000644 00000001764 15111300111 0011423 0 ustar 00 <?php namespace Http\Message; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; /** * Formats a request and/or a response as a string. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> * * The formatResponseForRequest method will be added to this interface in the next major version, replacing the formatRequest method. * Meanwhile, callers SHOULD check the formatter for the existence of formatResponseForRequest and call that if available. * * @method string formatResponseForRequest(ResponseInterface $response, RequestInterface $request) Formats a response in context of its request. */ interface Formatter { /** * Formats a request. * * @return string */ public function formatRequest(RequestInterface $request); /** * @deprecated since 1.13, use formatResponseForRequest() instead * * Formats a response. * * @return string */ public function formatResponse(ResponseInterface $response); } message/src/UriFactory/GuzzleUriFactory.php 0000644 00000001632 15111300111 0015031 0 ustar 00 <?php namespace Http\Message\UriFactory; use GuzzleHttp\Psr7\Utils; use Http\Message\UriFactory; use function GuzzleHttp\Psr7\uri_for; if (!interface_exists(UriFactory::class)) { throw new \LogicException('You cannot use "Http\Message\MessageFactory\GuzzleUriFactory" as the "php-http/message-factory" package is not installed. Try running "composer require php-http/message-factory". Note that this package is deprecated, use "psr/http-factory" instead'); } /** * Creates Guzzle URI. * * @author David de Boer <david@ddeboer.nl> * * @deprecated This will be removed in php-http/message2.0. Consider using the official Guzzle PSR-17 factory */ final class GuzzleUriFactory implements UriFactory { /** * {@inheritdoc} */ public function createUri($uri) { if (class_exists(Utils::class)) { return Utils::uriFor($uri); } return uri_for($uri); } } message/src/UriFactory/SlimUriFactory.php 0000644 00000002021 15111300111 0014446 0 ustar 00 <?php namespace Http\Message\UriFactory; use Http\Message\UriFactory; use Psr\Http\Message\UriInterface; use Slim\Http\Uri; if (!interface_exists(UriFactory::class)) { throw new \LogicException('You cannot use "Http\Message\MessageFactory\SlimUriFactory" as the "php-http/message-factory" package is not installed. Try running "composer require php-http/message-factory". Note that this package is deprecated, use "psr/http-factory" instead'); } /** * Creates Slim 3 URI. * * @author Mika Tuupola <tuupola@appelsiini.net> * * @deprecated This will be removed in php-http/message2.0. Consider using the official Slim PSR-17 factory */ final class SlimUriFactory implements UriFactory { /** * {@inheritdoc} */ public function createUri($uri) { if ($uri instanceof UriInterface) { return $uri; } if (is_string($uri)) { return Uri::createFromString($uri); } throw new \InvalidArgumentException('URI must be a string or UriInterface'); } } message/src/UriFactory/DiactorosUriFactory.php 0000644 00000002267 15111300111 0015505 0 ustar 00 <?php namespace Http\Message\UriFactory; use Http\Message\UriFactory; use Laminas\Diactoros\Uri as LaminasUri; use Psr\Http\Message\UriInterface; use Zend\Diactoros\Uri as ZendUri; if (!interface_exists(UriFactory::class)) { throw new \LogicException('You cannot use "Http\Message\MessageFactory\DiactorosUriFactory" as the "php-http/message-factory" package is not installed. Try running "composer require php-http/message-factory". Note that this package is deprecated, use "psr/http-factory" instead'); } /** * Creates Diactoros URI. * * @author David de Boer <david@ddeboer.nl> * * @deprecated This will be removed in php-http/message2.0. Consider using the official Diactoros PSR-17 factory */ final class DiactorosUriFactory implements UriFactory { /** * {@inheritdoc} */ public function createUri($uri) { if ($uri instanceof UriInterface) { return $uri; } elseif (is_string($uri)) { if (class_exists(LaminasUri::class)) { return new LaminasUri($uri); } return new ZendUri($uri); } throw new \InvalidArgumentException('URI must be a string or UriInterface'); } } message/.php-cs-fixer.dist.php 0000644 00000000473 15111300111 0012212 0 ustar 00 <?php $finder = PhpCsFixer\Finder::create() ->in(__DIR__.'/src') ->in(__DIR__.'/spec') ->name('*.php') ; $config = new PhpCsFixer\Config(); return $config ->setRiskyAllowed(true) ->setRules([ '@Symfony' => true, 'single_line_throw' => false, ]) ->setFinder($finder) ; message/README.md 0000644 00000002460 15111300111 0007431 0 ustar 00 # HTTP Message [](https://github.com/php-http/message/releases) [](LICENSE) [](https://github.com/php-http/message/actions/workflows/ci.yml) [](https://packagist.org/packages/php-http/message) **HTTP Message related tools.** ## Install Via Composer ``` bash $ composer require php-http/message ``` ## Intro This package contains various PSR-7 tools which might be useful in an HTTP workflow: - Authentication method implementations - Various Stream encoding tools - Message decorators - Message factory implementations for Guzzle PSR-7 and Diactoros - Cookie implementation - Request matchers ## Documentation Please see the [official documentation](http://docs.php-http.org/en/latest/message.html). ## Testing ``` bash $ composer test ``` ## Credits Thanks to [Cuzzle](https://github.com/namshi/cuzzle) for inpiration for the `CurlCommandFormatter`. ## License The MIT License (MIT). Please see [License File](LICENSE) for more information. message/LICENSE 0000644 00000002072 15111300111 0007156 0 ustar 00 Copyright (c) 2015-2016 PHP HTTP Team <team@php-http.org> 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. message/puli.json 0000644 00000011306 15111300111 0010015 0 ustar 00 { "version": "1.0", "name": "php-http/message", "bindings": { "064d003d-78a1-48c4-8f3b-1f92ff25da69": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\MessageFactory\\DiactorosMessageFactory", "type": "Http\\Message\\MessageFactory", "parameters": { "depends": "Zend\\Diactoros\\Request" } }, "0836751e-6558-4d1b-8993-4a52012947c3": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\MessageFactory\\SlimMessageFactory", "type": "Http\\Message\\ResponseFactory" }, "1d127622-dc61-4bfa-b9da-d221548d72c3": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\MessageFactory\\SlimMessageFactory", "type": "Http\\Message\\RequestFactory" }, "2438c2d0-0658-441f-8855-ddaf0f87d54d": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\MessageFactory\\GuzzleMessageFactory", "type": "Http\\Message\\MessageFactory", "parameters": { "depends": "GuzzleHttp\\Psr7\\Request" } }, "253aa08c-d705-46e7-b1d2-e28c97eef792": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\MessageFactory\\GuzzleMessageFactory", "type": "Http\\Message\\RequestFactory", "parameters": { "depends": "GuzzleHttp\\Psr7\\Request" } }, "273a34f9-62f4-4ba1-9801-b1284d49ff89": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\StreamFactory\\GuzzleStreamFactory", "type": "Http\\Message\\StreamFactory", "parameters": { "depends": "GuzzleHttp\\Psr7\\Stream" } }, "304b83db-b594-4d83-ae75-1f633adf92f7": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\UriFactory\\GuzzleUriFactory", "type": "Http\\Message\\UriFactory", "parameters": { "depends": "GuzzleHttp\\Psr7\\Uri" } }, "3f4bc1cd-aa95-4702-9fa7-65408e471691": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\UriFactory\\DiactorosUriFactory", "type": "Http\\Message\\UriFactory", "parameters": { "depends": "Zend\\Diactoros\\Uri" } }, "4672a6ee-ad9e-4109-a5d1-b7d46f26c7a1": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\MessageFactory\\SlimMessageFactory", "type": "Http\\Message\\MessageFactory" }, "6234e947-d3bd-43eb-97d5-7f9e22e6bb1b": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\MessageFactory\\DiactorosMessageFactory", "type": "Http\\Message\\ResponseFactory", "parameters": { "depends": "Zend\\Diactoros\\Response" } }, "6a9ad6ce-d82c-470f-8e30-60f21d9d95bf": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\UriFactory\\SlimUriFactory", "type": "Http\\Message\\UriFactory" }, "72c2afa0-ea56-4d03-adb6-a9f241a8a734": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\StreamFactory\\SlimStreamFactory", "type": "Http\\Message\\StreamFactory" }, "95c1be8f-39fe-4abd-8351-92cb14379a75": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\StreamFactory\\DiactorosStreamFactory", "type": "Http\\Message\\StreamFactory", "parameters": { "depends": "Zend\\Diactoros\\Stream" } }, "a018af27-7590-4dcf-83a1-497f95604cd6": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\MessageFactory\\GuzzleMessageFactory", "type": "Http\\Message\\ResponseFactory", "parameters": { "depends": "GuzzleHttp\\Psr7\\Response" } }, "c07955b1-de46-43db-923b-d07fae9382cb": { "_class": "Puli\\Discovery\\Binding\\ClassBinding", "class": "Http\\Message\\MessageFactory\\DiactorosMessageFactory", "type": "Http\\Message\\RequestFactory", "parameters": { "depends": "Zend\\Diactoros\\Request" } } } } message/composer.json 0000644 00000003252 15111300111 0010674 0 ustar 00 { "name": "php-http/message", "description": "HTTP Message related tools", "keywords": [ "message", "http", "psr-7" ], "homepage": "http://php-http.org", "license": "MIT", "authors": [ { "name": "Márk Sági-Kazár", "email": "mark.sagikazar@gmail.com" } ], "require": { "php": "^7.2 || ^8.0", "clue/stream-filter": "^1.5", "psr/http-message": "^1.1 || ^2.0" }, "provide": { "php-http/message-factory-implementation": "1.0" }, "require-dev": { "ext-zlib": "*", "ergebnis/composer-normalize": "^2.6", "guzzlehttp/psr7": "^1.0 || ^2.0", "php-http/message-factory": "^1.0.2", "phpspec/phpspec": "^5.1 || ^6.3 || ^7.1", "slim/slim": "^3.0", "laminas/laminas-diactoros": "^2.0 || ^3.0" }, "suggest": { "ext-zlib": "Used with compressor/decompressor streams", "guzzlehttp/psr7": "Used with Guzzle PSR-7 Factories", "laminas/laminas-diactoros": "Used with Diactoros Factories", "slim/slim": "Used with Slim Framework PSR-7 implementation" }, "config": { "sort-packages": true, "allow-plugins": { "ergebnis/composer-normalize": true } }, "autoload": { "psr-4": { "Http\\Message\\": "src/" }, "files": [ "src/filters.php" ] }, "autoload-dev": { "psr-4": { "spec\\Http\\Message\\": "spec/" } }, "scripts": { "test": "vendor/bin/phpspec run", "test-ci": "vendor/bin/phpspec run -c phpspec.ci.yml" } } message/apigen.neon 0000644 00000000106 15111300111 0010271 0 ustar 00 source: - src/ destination: build/api/ templateTheme: bootstrap message/CHANGELOG.md 0000644 00000020074 15111300111 0007764 0 ustar 00 # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [1.16.0] - 2023-05-17 - Remove direct dependency on `php-http/message-factory` as it is only needed for the deprecated Httplug factories. Upgrade to PSR-17 message factories provided by your HTTP client implementation. If you need the Httplug factories for the time being, you can `composer require php-http/message-factory` in your application. ## [1.15.0] - 2023-05-10 **If you use the decorator classes, you might need to adjust your code to the parameter and return type declarations added in PSR-7** - Actually make compatible with PSR-7 1.1 and 2.0 - Drop support for PHP 7.1 ## [1.14.0] - 2023-04-14 (broken) **This release is not actually compatible with PSR-7 1.1 or 2.0** - Allow installation with http-message (PSR-7) version 2 in addition to version 1. - Support for PHP 8.2 ## [1.13.0] - 2022-02-11 - Added `Formatter::formatResponseForRequest()` to allow the formatter to get context from the request to decide what of the response to output. - Deprecated `Formatter::formatResponse()` in favor of the new `formatResponseForRequest` method. ## [1.12.0] - 2021-08-29 - Added support for adjusting binary detection regex in FullHttpMessageFormatter. ## [1.11.2] - 2021-08-03 - Support GuzzleHttp/Psr7 version 2.0 in the (deprecated) GuzzleStreamFactory. ## [1.11.1] - 2021-05-24 - Support GuzzleHttp/Psr7 version 2.0 in the (deprecated) GuzzleUriFactory. ## [1.11.0] - 2020-02-01 - Migrated from `zendframework/zend-diactoros` to `laminas/laminas-diactoros`. Users are encouraged to update their dependencies by simply replacing the Zend package with the Laminas package. Due to the [laminas-zendframework-brige](https://github.com/laminas/laminas-zendframework-bridge), BC changes are not expected and legacy code does not need to be refactored (though it is [recommended and simple](https://docs.laminas.dev/migration/)). - The diactoros factories of `php-http/message` will return objects from the `Laminas\Diactoros\` namespace, if the respective classes are available via autoloading, but continue to return objects from `Zend\Diactoros\` namespace otherwise. - Allow to specify the hashing algorithm for WSSE authentication. ## [1.10.0] - 2020-11-11 - Added support for PHP 8.0. ## [1.9.1] - 2020-10-13 - Improved detection of binary stream to not consider newlines, carriage return or tabs as binary. ## [1.9.0] - 2020-08-17 - Omitted binary body in FullHttpMessageFormatter and CurlCommandFormatter. `[binary stream omitted]` will be shown instead. ### Added - New Header authentication method for arbitrary header authentication. ## [1.8.0] - 2019-08-05 ### Changed - Raised minimum PHP version to 7.1 ### Fixed - Fatal error on `CurlCommandFormatter` when body is larger than `escapeshellarg` allowed length. - Do not read stream in message formatter if stream is not seekable. ## [1.7.2] - 2018-10-30 ### Fixed - FilteredStream uses `@trigger_error` instead of throwing exceptions to not break careless users. You still need to fix your stream code to respect `isSeekable`. Seeking does not work as expected, and we will add exceptions in version 2. ## [1.7.1] - 2018-10-29 ### Fixed - FilteredStream is not actually seekable ## [1.7.0] - 2018-08-15 ### Fixed - Fix CurlCommandFormatter for binary request payloads - Fix QueryParam authentication to assemble proper URL regardless of PHP `arg_separator.output` directive - Do not pass `null` parameters to `Clue\StreamFilter\fun` ### Changed - Dropped tests on HHVM ## [1.6.0] - 2017-07-05 ### Added - CookieUtil::parseDate to create a date from cookie date string ### Fixed - Fix curl command of CurlFormatter when there is an user-agent header ## [1.5.0] - 2017-02-14 ### Added - Check for empty string in Stream factories - Cookie::createWithoutValidation Static constructor to create a cookie. Will not perform any attribute validation during instantiation. - Cookie::isValid Method to check if cookie attributes are valid. ### Fixed - FilteredStream::getSize returns null because the contents size is unknown. - Stream factories does not rewinds streams. The previous behavior was not coherent between factories and inputs. ### Deprecated - FilteredStream::getReadFilter The read filter is internal and should never be used by consuming code. - FilteredStream::getWriteFilter We did not implement writing to the streams at all. And if we do, the filter is an internal information and should not be used by consuming code. ## [1.4.1] - 2016-12-16 ### Fixed - Cookie::matchPath Cookie with root path (`/`) will not match sub path (e.g. `/cookie`). ## [1.4.0] - 2016-10-20 ### Added - Message, stream and URI factories for [Slim Framework](https://github.com/slimphp/Slim) - BufferedStream that allow you to decorate a non-seekable stream with a seekable one. - cUrlFormatter to be able to redo the request with a cURL command ## [1.3.1] - 2016-07-15 ### Fixed - FullHttpMessageFormatter will not read from streams that you cannot rewind (non-seekable) - FullHttpMessageFormatter will not read from the stream if $maxBodyLength is zero - FullHttpMessageFormatter rewinds streams after they are read ## [1.3.0] - 2016-07-14 ### Added - FullHttpMessageFormatter to include headers and body in the formatted message ### Fixed - #41: Response builder broke header value ## [1.2.0] - 2016-03-29 ### Added - The RequestMatcher is built after the Symfony RequestMatcher and separates scheme, host and path expressions and provides an option to filter on the method - New RequestConditional authentication method using request matchers - Add automatic basic auth info detection based on the URL ### Changed - Improved ResponseBuilder ### Deprecated - RegexRequestMatcher, use RequestMatcher instead - Matching authenitcation method, use RequestConditional instead ## [1.1.0] - 2016-02-25 ### Added - Add a request matcher interface and regex implementation - Add a callback request matcher implementation - Add a ResponseBuilder, to create PSR7 Response from a string ### Fixed - Fix casting string on a FilteredStream not filtering the output ## [1.0.0] - 2016-01-27 ## [0.2.0] - 2015-12-29 ### Added - Autoregistration of stream filters using Composer autoload - Cookie - [Apigen](http://www.apigen.org/) configuration ## [0.1.2] - 2015-12-26 ### Added - Request and response factory bindings ### Fixed - Chunk filter namespace in Dechunk stream ## [0.1.1] - 2015-12-25 ### Added - Formatter ## 0.1.0 - 2015-12-24 ### Added - Authentication - Encoding - Message decorator - Message factory (Guzzle, Diactoros) [Unreleased]: https://github.com/php-http/message/compare/1.10.0...HEAD [1.10.0]: https://github.com/php-http/message/compare/1.9.1...1.10.0 [1.9.1]: https://github.com/php-http/message/compare/1.9.0...1.9.1 [1.9.0]: https://github.com/php-http/message/compare/1.8.0...1.9.0 [1.8.0]: https://github.com/php-http/message/compare/1.7.2...1.8.0 [1.7.2]: https://github.com/php-http/message/compare/v1.7.1...1.7.2 [1.7.1]: https://github.com/php-http/message/compare/1.7.0...v1.7.1 [1.7.0]: https://github.com/php-http/message/compare/1.6.0...1.7.0 [1.6.0]: https://github.com/php-http/message/compare/1.5.0...1.6.0 [1.5.0]: https://github.com/php-http/message/compare/v1.4.1...1.5.0 [1.4.1]: https://github.com/php-http/message/compare/v1.4.0...v1.4.1 [1.4.0]: https://github.com/php-http/message/compare/v1.3.1...v1.4.0 [1.3.1]: https://github.com/php-http/message/compare/v1.3.0...v1.3.1 [1.3.0]: https://github.com/php-http/message/compare/v1.2.0...v1.3.0 [1.2.0]: https://github.com/php-http/message/compare/v1.1.0...v1.2.0 [1.1.0]: https://github.com/php-http/message/compare/v1.0.0...v1.1.0 [1.0.0]: https://github.com/php-http/message/compare/0.2.0...v1.0.0 [0.2.0]: https://github.com/php-http/message/compare/v0.1.2...0.2.0 [0.1.2]: https://github.com/php-http/message/compare/v0.1.1...v0.1.2 [0.1.1]: https://github.com/php-http/message/compare/v0.1.0...v0.1.1 message-factory/src/MessageFactory.php 0000644 00000000535 15111300111 0014034 0 ustar 00 <?php namespace Http\Message; /** * Factory for PSR-7 Request and Response. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> * * @deprecated since version 1.1, use Psr\Http\Message\RequestFactoryInterface and Psr\Http\Message\ResponseFactoryInterface instead. */ interface MessageFactory extends RequestFactory, ResponseFactory { } message-factory/src/ResponseFactory.php 0000644 00000001764 15111300111 0014253 0 ustar 00 <?php namespace Http\Message; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; /** * Factory for PSR-7 Response. * * This factory contract can be reused in Message and Server Message factories. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> * * @deprecated since version 1.1, use Psr\Http\Message\ResponseFactoryInterface instead. */ interface ResponseFactory { /** * Creates a new PSR-7 response. * * @param int $statusCode * @param string|null $reasonPhrase * @param array $headers * @param resource|string|StreamInterface|null $body * @param string $protocolVersion * * @return ResponseInterface */ public function createResponse( $statusCode = 200, $reasonPhrase = null, array $headers = [], $body = null, $protocolVersion = '1.1' ); } message-factory/src/StreamFactory.php 0000644 00000001206 15111300111 0013677 0 ustar 00 <?php namespace Http\Message; use Psr\Http\Message\StreamInterface; /** * Factory for PSR-7 Stream. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> * * @deprecated since version 1.1, use Psr\Http\Message\StreamFactoryInterface instead. */ interface StreamFactory { /** * Creates a new PSR-7 stream. * * @param string|resource|StreamInterface|null $body * * @return StreamInterface * * @throws \InvalidArgumentException if the stream body is invalid * @throws \RuntimeException if creating the stream from $body fails */ public function createStream($body = null); } message-factory/src/error_log 0000644 00000000527 15111300111 0012325 0 ustar 00 [25-Nov-2025 03:05:29 UTC] PHP Fatal error: Uncaught Error: Interface "Http\Message\RequestFactory" not found in /home/fluxyjvi/public_html/project/vendor/php-http/message-factory/src/MessageFactory.php:12 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/php-http/message-factory/src/MessageFactory.php on line 12 message-factory/src/RequestFactory.php 0000644 00000001626 15111300111 0014102 0 ustar 00 <?php namespace Http\Message; use Psr\Http\Message\UriInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\StreamInterface; /** * Factory for PSR-7 Request. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> * * @deprecated since version 1.1, use Psr\Http\Message\RequestFactoryInterface instead. */ interface RequestFactory { /** * Creates a new PSR-7 request. * * @param string $method * @param string|UriInterface $uri * @param array $headers * @param resource|string|StreamInterface|null $body * @param string $protocolVersion * * @return RequestInterface */ public function createRequest( $method, $uri, array $headers = [], $body = null, $protocolVersion = '1.1' ); } message-factory/src/UriFactory.php 0000644 00000001040 15111300111 0013177 0 ustar 00 <?php namespace Http\Message; use Psr\Http\Message\UriInterface; /** * Factory for PSR-7 URI. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> * * @deprecated since version 1.1, use Psr\Http\Message\UriFactoryInterface instead. */ interface UriFactory { /** * Creates an PSR-7 URI. * * @param string|UriInterface $uri * * @return UriInterface * * @throws \InvalidArgumentException if the $uri argument can not be converted into a valid URI */ public function createUri($uri); } message-factory/README.md 0000644 00000002634 15111300111 0011101 0 ustar 00 # PSR-7 Message Factory [](https://github.com/php-http/message-factory/releases) [](LICENSE) [](https://packagist.org/packages/php-http/message-factory) **Factory interfaces for PSR-7 HTTP Message.** ## Obsolete The PHP-HTTP factories have become obsolete with the [PSR-17](https://www.php-fig.org/psr/psr-17/) factories standard. All major HTTP client implementors provide [PSR-17 factories](https://packagist.org/packages/psr/http-factory). This package will remain available for the time being to not break legacy code, but we encourage everybody to move to PSR-17. ## Install Via Composer ``` bash $ composer require php-http/message-factory ``` ## Documentation Please see the [official documentation](http://docs.php-http.org/en/latest/message/message-factory.html). ## Contributing Please see our [contributing guide](http://docs.php-http.org/en/latest/development/contributing.html). ## Security If you discover any security related issues, please contact us at [security@php-http.org](mailto:security@php-http.org). ## License The MIT License (MIT). Please see [License File](LICENSE) for more information. message-factory/LICENSE 0000644 00000002072 15111300111 0010623 0 ustar 00 Copyright (c) 2015-2016 PHP HTTP Team <team@php-http.org> 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. message-factory/puli.json 0000644 00000002641 15111300111 0011464 0 ustar 00 { "version": "1.0", "name": "php-http/message-factory", "binding-types": { "Http\\Message\\MessageFactory": { "description": "PSR-7 Message Factory", "parameters": { "depends": { "description": "Optional class dependency which can be checked by consumers" } } }, "Http\\Message\\RequestFactory": { "parameters": { "depends": { "description": "Optional class dependency which can be checked by consumers" } } }, "Http\\Message\\ResponseFactory": { "parameters": { "depends": { "description": "Optional class dependency which can be checked by consumers" } } }, "Http\\Message\\StreamFactory": { "description": "PSR-7 Stream Factory", "parameters": { "depends": { "description": "Optional class dependency which can be checked by consumers" } } }, "Http\\Message\\UriFactory": { "description": "PSR-7 URI Factory", "parameters": { "depends": { "description": "Optional class dependency which can be checked by consumers" } } } } } message-factory/composer.json 0000644 00000001204 15111300111 0012334 0 ustar 00 { "name": "php-http/message-factory", "description": "Factory interfaces for PSR-7 HTTP Message", "license": "MIT", "keywords": ["http", "factory", "message", "stream", "uri"], "homepage": "http://php-http.org", "authors": [ { "name": "Márk Sági-Kazár", "email": "mark.sagikazar@gmail.com" } ], "require": { "php": ">=5.4", "psr/http-message": "^1.0 || ^2.0" }, "autoload": { "psr-4": { "Http\\Message\\": "src/" } }, "extra": { "branch-alias": { "dev-master": "1.x-dev" } } } message-factory/CHANGELOG.md 0000644 00000002054 15111300111 0011427 0 ustar 00 # Change Log ## 1.1.0 - 2023-04-14 ### Changed - Allow `psr/http-message` v2 in addition to v1 - Deprecate all interfaces in favor of [PSR-17](https://www.php-fig.org/psr/psr-17/) ## 1.0.2 - 2015-12-19 ### Added - Request and Response factory binding types to Puli ## 1.0.1 - 2015-12-17 ### Added - Puli configuration and binding types ## 1.0.0 - 2015-12-15 ### Added - Response Factory in order to be reused in Message and Server Message factories - Request Factory ### Changed - Message Factory extends Request and Response factories ## 1.0.0-RC1 - 2015-12-14 ### Added - CS check ### Changed - RuntimeException is thrown when the StreamFactory cannot write to the underlying stream ## 0.3.0 - 2015-11-16 ### Removed - Client Context Factory - Factory Awares and Templates ## 0.2.0 - 2015-11-16 ### Changed - Reordered the parameters when creating a message to have the protocol last, as its the least likely to need to be changed. ## 0.1.0 - 2015-06-01 ### Added - Initial release ### Changed - Helpers are renamed to templates message-factory/CONTRIBUTING 0000644 00000000114 15111300111 0011443 0 ustar 00 Please see http://docs.php-http.org/en/latest/development/contributing.html
Simpan