Compare commits

...

3 Commits

Author SHA1 Message Date
Anne-Cath
d54e71f0f9 N°9248 - REST API - Updating a link creates an empty caselog on the linked object when there is no change 2026-02-27 11:21:32 +01:00
Lenaick
fc967c06ce N°8834 - Add compatibility with PHP 8.4 (#819)
* N°8834 - Add compatibility with PHP 8.4

* Rollback of scssphp/scssphp version upgrade due to compilation error
2026-02-26 10:36:32 +01:00
Eric Espie
d4821b7edc remove log level config 2026-02-26 10:19:34 +01:00
963 changed files with 12554 additions and 7437 deletions

View File

@@ -4,7 +4,7 @@
"type": "project",
"license": "AGPL-3.0-only",
"require": {
"php": ">=8.1.0 <8.4.0",
"php": ">=8.1.0 <8.5.0",
"ext-ctype": "*",
"ext-dom": "*",
"ext-gd": "*",
@@ -12,8 +12,7 @@
"ext-json": "*",
"ext-mysqli": "*",
"ext-soap": "*",
"apereo/phpcas": "~1.6.0",
"firebase/php-jwt": "^6.4.0",
"apereo/phpcas": "dev-master",
"guzzlehttp/guzzle": "^7.5.1",
"league/oauth2-google": "^4.0.1",
"nikic/php-parser": "^4.14.0",
@@ -40,6 +39,12 @@
"symfony/stopwatch": "~6.4.0",
"symfony/web-profiler-bundle": "~6.4.0"
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/EsupPortail/phpCAS"
}
],
"suggest": {
"ext-libsodium": "Required to use the AttributeEncryptedString.",
"ext-openssl": "Can be used as a polyfill if libsodium is not installed",

852
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -179,7 +179,7 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
assert($oLink instanceof $this->sClass);
$iObjectId = $oLink->GetKey();
if (array_key_exists($iObjectId, $this->aPreserved)) {
if (array_key_exists($iObjectId, $this->aPreserved) && !$oLink->Equals(MetaModel::GetObject(get_class($oLink), $iObjectId, true))) {
unset($this->aPreserved[$iObjectId]);
$this->aModified[$iObjectId] = $oLink;
$this->bHasDelta = true;

View File

@@ -13,7 +13,7 @@ Api documentation can be found here:
https://apereo.github.io/phpCAS/api/
[![Test](https://github.com/apereo/phpCAS/actions/workflows/test.yml/badge.svg)](https://github.com/apereo/phpCAS/actions/workflows/test.yml)
[![Test](https://github.com/EsupPortail/phpCAS/actions/workflows/test.yml/badge.svg)](https://github.com/EsupPortail/phpCAS/actions/workflows/test.yml)
LICENSE
-------

View File

@@ -57,7 +57,7 @@ if (!isset($_SERVER['REQUEST_URI']) && isset($_SERVER['SCRIPT_NAME']) && isset($
/**
* phpCAS version. accessible for the user by phpCAS::getVersion().
*/
define('PHPCAS_VERSION', '1.6.1');
define('PHPCAS_VERSION', '1.6.1+');
/**
* @addtogroup public
@@ -303,7 +303,7 @@ class phpCAS
/**
* This variable is used to enable verbose mode
* This pevents debug info to be show to the user. Since it's a security
* This prevents debug info to be show to the user. Since it's a security
* feature the default is false
*
* @hideinitializer
@@ -338,7 +338,7 @@ class phpCAS
* @param bool $changeSessionID Allow phpCAS to change the session_id
* (Single Sign Out/handleLogoutRequests
* is based on that change)
* @param \SessionHandlerInterface $sessionHandler the session handler
* @param \SessionHandlerInterface|null $sessionHandler the session handler
*
* @return void a newly created CAS_Client object
* @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
@@ -347,7 +347,7 @@ class phpCAS
*/
public static function client($server_version, $server_hostname,
$server_port, $server_uri, $service_base_url,
$changeSessionID = true, \SessionHandlerInterface $sessionHandler = null
$changeSessionID = true, ?\SessionHandlerInterface $sessionHandler = null
) {
phpCAS :: traceBegin();
if (is_object(self::$_PHPCAS_CLIENT)) {
@@ -393,7 +393,7 @@ class phpCAS
* @param bool $changeSessionID Allow phpCAS to change the session_id
* (Single Sign Out/handleLogoutRequests
* is based on that change)
* @param \SessionHandlerInterface $sessionHandler the session handler
* @param \SessionHandlerInterface|null $sessionHandler the session handler
*
* @return void a newly created CAS_Client object
* @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
@@ -402,14 +402,14 @@ class phpCAS
*/
public static function proxy($server_version, $server_hostname,
$server_port, $server_uri, $service_base_url,
$changeSessionID = true, \SessionHandlerInterface $sessionHandler = null
$changeSessionID = true, ?\SessionHandlerInterface $sessionHandler = null
) {
phpCAS :: traceBegin();
if (is_object(self::$_PHPCAS_CLIENT)) {
phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');
}
// store where the initialzer is called from
// store where the initializer is called from
$dbg = debug_backtrace();
self::$_PHPCAS_INIT_CALL = array (
'done' => true,
@@ -560,7 +560,7 @@ class phpCAS
$indent_str .= '| ';
}
// allow for multiline output with proper identing. Usefull for
// allow for multiline output with proper identing. Useful for
// dumping cas answers etc.
$str2 = str_replace("\n", "\n" . self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str, $str);
$str3 = self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str . $str2;
@@ -568,7 +568,7 @@ class phpCAS
self::$_PHPCAS_DEBUG['logger']->info($str3);
}
if (!empty(self::$_PHPCAS_DEBUG['filename'])) {
// Check if file exists and modifiy file permissions to be only
// Check if file exists and modify file permissions to be only
// readable by the webserver
if (!file_exists(self::$_PHPCAS_DEBUG['filename'])) {
touch(self::$_PHPCAS_DEBUG['filename']);
@@ -1769,7 +1769,7 @@ class phpCAS
/**
* If you want your service to be proxied you have to enable it (default
* disabled) and define an accepable list of proxies that are allowed to
* disabled) and define an acceptable list of proxies that are allowed to
* proxy your service.
*
* Add each allowed proxy definition object. For the normal CAS_ProxyChain
@@ -1790,7 +1790,7 @@ class phpCAS
* 'http://client.example.com/'
* )));
*
* For quick testing or in certain production screnarios you might want to
* For quick testing or in certain production scenarios you might want to
* allow allow any other valid service to proxy your service. To do so, add
* the "Any" chain:
* phpCAS::allowProxyChain(new CAS_ProxyChain_Any);
@@ -1897,7 +1897,7 @@ class phpCAS
}
/**
* Checks of a proxy client aready exists
* Checks of a proxy client already exists
*
* @throws CAS_OutOfSequenceBeforeProxyException
*

View File

@@ -788,7 +788,7 @@ class CAS_Client
'file' => $dbg[1]['file'],
'line' => $dbg[1]['line'],
'method' => $dbg[1]['class'] . '::' . $dbg[1]['function'],
'result' => (boolean)$auth
'result' => (bool)$auth
);
}
private $_authentication_caller;
@@ -926,7 +926,7 @@ class CAS_Client
* CAS_ServiceBaseUrl_Interface for custom
* behavior. Added in 1.6.0. Similar to
* serverName config in other CAS clients.
* @param \SessionHandlerInterface $sessionHandler the session handler
* @param \SessionHandlerInterface|null $sessionHandler the session handler
*
* @return self a newly created CAS_Client object
*/
@@ -938,7 +938,7 @@ class CAS_Client
$server_uri,
$service_base_url,
$changeSessionID = true,
\SessionHandlerInterface $sessionHandler = null
?\SessionHandlerInterface $sessionHandler = null
) {
// Argument validation
if (gettype($server_version) != 'string')
@@ -3166,7 +3166,7 @@ class CAS_Client
$proxiedService->setCasClient($this);
}
return $proxiedService;
case PHPCAS_PROXIED_SERVICE_IMAP;
case PHPCAS_PROXIED_SERVICE_IMAP:
$proxiedService = new CAS_ProxiedService_Imap($this->_getUser());
if ($proxiedService instanceof CAS_ProxiedService_Testable) {
$proxiedService->setCasClient($this);

View File

@@ -316,7 +316,7 @@ class CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage
try {
$pdo->beginTransaction();
$query = $pdo->query($this->createTableSQL());
$query = $pdo->query($this->createTableSql());
$query->closeCursor();
$pdo->commit();

View File

@@ -127,6 +127,12 @@ class CAS_PGTStorage_File extends CAS_PGTStorage_AbstractStorage
if (!preg_match('`^[a-zA-Z]:`', $path)) {
phpCAS::error('an absolute path is needed for PGT storage to file');
}
// ensure that the directory separator on Windows is '/' for consistency with the rest of the phpcas code
$path = str_replace(DIRECTORY_SEPARATOR , '/', $path);
// store the path (with a trailing '/')
$path = preg_replace('|([^/])$|', '$1/', $path);
} else {

View File

@@ -139,7 +139,12 @@ implements CAS_Request_MultiRequestInterface
$buf = curl_multi_getcontent($handles[$i]);
$request->_storeResponseBody($buf);
curl_multi_remove_handle($multiHandle, $handles[$i]);
curl_close($handles[$i]);
if (PHP_VERSION_ID < 80000) {
curl_close($handles[$i]);
} else {
// unreference it => it will be closed
unset($handles[$i]);
}
}
curl_multi_close($multiHandle);

View File

@@ -86,7 +86,9 @@ implements CAS_Request_RequestInterface
}
// close the CURL session
curl_close($ch);
if (PHP_VERSION_ID < 80000) {
curl_close($ch);
}
phpCAS::traceEnd($res);
return $res;

0
lib/bin/patch-type-declarations Normal file → Executable file
View File

View File

@@ -1,5 +0,0 @@
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0/patch-type-declarations
SET COMPOSER_RUNTIME_BIN_DIR=%~dp0
php "%BIN_TARGET%" %*

0
lib/bin/php-parse Normal file → Executable file
View File

View File

@@ -1,5 +0,0 @@
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0/php-parse
SET COMPOSER_RUNTIME_BIN_DIR=%~dp0
php "%BIN_TARGET%" %*

0
lib/bin/pscss Normal file → Executable file
View File

View File

@@ -1,5 +0,0 @@
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0/pscss
SET COMPOSER_RUNTIME_BIN_DIR=%~dp0
php "%BIN_TARGET%" %*

0
lib/bin/var-dump-server Normal file → Executable file
View File

View File

@@ -1,5 +0,0 @@
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0/var-dump-server
SET COMPOSER_RUNTIME_BIN_DIR=%~dp0
php "%BIN_TARGET%" %*

0
lib/bin/yaml-lint Normal file → Executable file
View File

View File

@@ -1,5 +0,0 @@
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0/yaml-lint
SET COMPOSER_RUNTIME_BIN_DIR=%~dp0
php "%BIN_TARGET%" %*

View File

@@ -958,6 +958,7 @@ return array(
'PDF417' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/pdf417.php',
'PDFBulkExport' => $baseDir . '/core/pdfbulkexport.class.inc.php',
'PEAR' => $vendorDir . '/pear/pear-core-minimal/src/PEAR.php',
'PEAR_Error' => $vendorDir . '/pear/pear-core-minimal/src/PEAR.php',
'PEAR_ErrorStack' => $vendorDir . '/pear/pear-core-minimal/src/PEAR/ErrorStack.php',
'PEAR_Exception' => $vendorDir . '/pear/pear_exception/PEAR/Exception.php',
'Pelago\\Emogrifier\\Caching\\SimpleStringCache' => $vendorDir . '/pelago/emogrifier/src/Caching/SimpleStringCache.php',
@@ -1645,22 +1646,43 @@ return array(
'Symfony\\Component\\Cache\\Psr16Cache' => $vendorDir . '/symfony/cache/Psr16Cache.php',
'Symfony\\Component\\Cache\\ResettableInterface' => $vendorDir . '/symfony/cache/ResettableInterface.php',
'Symfony\\Component\\Cache\\Traits\\AbstractAdapterTrait' => $vendorDir . '/symfony/cache/Traits/AbstractAdapterTrait.php',
'Symfony\\Component\\Cache\\Traits\\CachedValueInterface' => $vendorDir . '/symfony/cache/Traits/CachedValueInterface.php',
'Symfony\\Component\\Cache\\Traits\\ContractsTrait' => $vendorDir . '/symfony/cache/Traits/ContractsTrait.php',
'Symfony\\Component\\Cache\\Traits\\FilesystemCommonTrait' => $vendorDir . '/symfony/cache/Traits/FilesystemCommonTrait.php',
'Symfony\\Component\\Cache\\Traits\\FilesystemTrait' => $vendorDir . '/symfony/cache/Traits/FilesystemTrait.php',
'Symfony\\Component\\Cache\\Traits\\ProxyTrait' => $vendorDir . '/symfony/cache/Traits/ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\Redis5Proxy' => $vendorDir . '/symfony/cache/Traits/Redis5Proxy.php',
'Symfony\\Component\\Cache\\Traits\\Redis61ProxyTrait' => $vendorDir . '/symfony/cache/Traits/Redis61ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\Redis62ProxyTrait' => $vendorDir . '/symfony/cache/Traits/Redis62ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\Redis63ProxyTrait' => $vendorDir . '/symfony/cache/Traits/Redis63ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\Redis6Proxy' => $vendorDir . '/symfony/cache/Traits/Redis6Proxy.php',
'Symfony\\Component\\Cache\\Traits\\Redis6ProxyTrait' => $vendorDir . '/symfony/cache/Traits/Redis6ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\RedisCluster5Proxy' => $vendorDir . '/symfony/cache/Traits/RedisCluster5Proxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisCluster61ProxyTrait' => $vendorDir . '/symfony/cache/Traits/RedisCluster61ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\RedisCluster62ProxyTrait' => $vendorDir . '/symfony/cache/Traits/RedisCluster62ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\RedisCluster63ProxyTrait' => $vendorDir . '/symfony/cache/Traits/RedisCluster63ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\RedisCluster6Proxy' => $vendorDir . '/symfony/cache/Traits/RedisCluster6Proxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisCluster6ProxyTrait' => $vendorDir . '/symfony/cache/Traits/RedisCluster6ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\RedisClusterNodeProxy' => $vendorDir . '/symfony/cache/Traits/RedisClusterNodeProxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisClusterProxy' => $vendorDir . '/symfony/cache/Traits/RedisClusterProxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisProxy' => $vendorDir . '/symfony/cache/Traits/RedisProxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisTrait' => $vendorDir . '/symfony/cache/Traits/RedisTrait.php',
'Symfony\\Component\\Cache\\Traits\\RelayProxy' => $vendorDir . '/symfony/cache/Traits/RelayProxy.php',
'Symfony\\Component\\Cache\\Traits\\RelayProxyTrait' => $vendorDir . '/symfony/cache/Traits/RelayProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\BgsaveTrait' => $vendorDir . '/symfony/cache/Traits/Relay/BgsaveTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\CopyTrait' => $vendorDir . '/symfony/cache/Traits/Relay/CopyTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\FtTrait' => $vendorDir . '/symfony/cache/Traits/Relay/FtTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\GeosearchTrait' => $vendorDir . '/symfony/cache/Traits/Relay/GeosearchTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\GetWithMetaTrait' => $vendorDir . '/symfony/cache/Traits/Relay/GetWithMetaTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\GetrangeTrait' => $vendorDir . '/symfony/cache/Traits/Relay/GetrangeTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\HsetTrait' => $vendorDir . '/symfony/cache/Traits/Relay/HsetTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\IsTrackedTrait' => $vendorDir . '/symfony/cache/Traits/Relay/IsTrackedTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\MoveTrait' => $vendorDir . '/symfony/cache/Traits/Relay/MoveTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\NullableReturnTrait' => $vendorDir . '/symfony/cache/Traits/Relay/NullableReturnTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\PfcountTrait' => $vendorDir . '/symfony/cache/Traits/Relay/PfcountTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay11Trait' => $vendorDir . '/symfony/cache/Traits/Relay/Relay11Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay121Trait' => $vendorDir . '/symfony/cache/Traits/Relay/Relay121Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay12Trait' => $vendorDir . '/symfony/cache/Traits/Relay/Relay12Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay20Trait' => $vendorDir . '/symfony/cache/Traits/Relay/Relay20Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\SwapdbTrait' => $vendorDir . '/symfony/cache/Traits/Relay/SwapdbTrait.php',
'Symfony\\Component\\Config\\Builder\\ClassBuilder' => $vendorDir . '/symfony/config/Builder/ClassBuilder.php',
'Symfony\\Component\\Config\\Builder\\ConfigBuilderGenerator' => $vendorDir . '/symfony/config/Builder/ConfigBuilderGenerator.php',
'Symfony\\Component\\Config\\Builder\\ConfigBuilderGeneratorInterface' => $vendorDir . '/symfony/config/Builder/ConfigBuilderGeneratorInterface.php',
@@ -1825,6 +1847,7 @@ return array(
'Symfony\\Component\\Console\\Helper\\TableRows' => $vendorDir . '/symfony/console/Helper/TableRows.php',
'Symfony\\Component\\Console\\Helper\\TableSeparator' => $vendorDir . '/symfony/console/Helper/TableSeparator.php',
'Symfony\\Component\\Console\\Helper\\TableStyle' => $vendorDir . '/symfony/console/Helper/TableStyle.php',
'Symfony\\Component\\Console\\Helper\\TerminalInputHelper' => $vendorDir . '/symfony/console/Helper/TerminalInputHelper.php',
'Symfony\\Component\\Console\\Input\\ArgvInput' => $vendorDir . '/symfony/console/Input/ArgvInput.php',
'Symfony\\Component\\Console\\Input\\ArrayInput' => $vendorDir . '/symfony/console/Input/ArrayInput.php',
'Symfony\\Component\\Console\\Input\\Input' => $vendorDir . '/symfony/console/Input/Input.php',
@@ -2699,7 +2722,6 @@ return array(
'Symfony\\Component\\VarDumper\\Cloner\\Cursor' => $vendorDir . '/symfony/var-dumper/Cloner/Cursor.php',
'Symfony\\Component\\VarDumper\\Cloner\\Data' => $vendorDir . '/symfony/var-dumper/Cloner/Data.php',
'Symfony\\Component\\VarDumper\\Cloner\\DumperInterface' => $vendorDir . '/symfony/var-dumper/Cloner/DumperInterface.php',
'Symfony\\Component\\VarDumper\\Cloner\\Internal\\NoDefault' => $vendorDir . '/symfony/var-dumper/Cloner/Internal/NoDefault.php',
'Symfony\\Component\\VarDumper\\Cloner\\Stub' => $vendorDir . '/symfony/var-dumper/Cloner/Stub.php',
'Symfony\\Component\\VarDumper\\Cloner\\VarCloner' => $vendorDir . '/symfony/var-dumper/Cloner/VarCloner.php',
'Symfony\\Component\\VarDumper\\Command\\Descriptor\\CliDescriptor' => $vendorDir . '/symfony/var-dumper/Command/Descriptor/CliDescriptor.php',
@@ -2854,6 +2876,7 @@ return array(
'Twig\\ExpressionParser\\InfixExpressionParserInterface' => $vendorDir . '/twig/twig/src/ExpressionParser/InfixExpressionParserInterface.php',
'Twig\\ExpressionParser\\Infix\\ArgumentsTrait' => $vendorDir . '/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php',
'Twig\\ExpressionParser\\Infix\\ArrowExpressionParser' => $vendorDir . '/twig/twig/src/ExpressionParser/Infix/ArrowExpressionParser.php',
'Twig\\ExpressionParser\\Infix\\AssignmentExpressionParser' => $vendorDir . '/twig/twig/src/ExpressionParser/Infix/AssignmentExpressionParser.php',
'Twig\\ExpressionParser\\Infix\\BinaryOperatorExpressionParser' => $vendorDir . '/twig/twig/src/ExpressionParser/Infix/BinaryOperatorExpressionParser.php',
'Twig\\ExpressionParser\\Infix\\ConditionalTernaryExpressionParser' => $vendorDir . '/twig/twig/src/ExpressionParser/Infix/ConditionalTernaryExpressionParser.php',
'Twig\\ExpressionParser\\Infix\\DotExpressionParser' => $vendorDir . '/twig/twig/src/ExpressionParser/Infix/DotExpressionParser.php',
@@ -2939,10 +2962,15 @@ return array(
'Twig\\Node\\Expression\\Binary\\MulBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/MulBinary.php',
'Twig\\Node\\Expression\\Binary\\NotEqualBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/NotEqualBinary.php',
'Twig\\Node\\Expression\\Binary\\NotInBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/NotInBinary.php',
'Twig\\Node\\Expression\\Binary\\NotSameAsBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/NotSameAsBinary.php',
'Twig\\Node\\Expression\\Binary\\NullCoalesceBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/NullCoalesceBinary.php',
'Twig\\Node\\Expression\\Binary\\ObjectDestructuringSetBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/ObjectDestructuringSetBinary.php',
'Twig\\Node\\Expression\\Binary\\OrBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/OrBinary.php',
'Twig\\Node\\Expression\\Binary\\PowerBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/PowerBinary.php',
'Twig\\Node\\Expression\\Binary\\RangeBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/RangeBinary.php',
'Twig\\Node\\Expression\\Binary\\SameAsBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/SameAsBinary.php',
'Twig\\Node\\Expression\\Binary\\SequenceDestructuringSetBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/SequenceDestructuringSetBinary.php',
'Twig\\Node\\Expression\\Binary\\SetBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/SetBinary.php',
'Twig\\Node\\Expression\\Binary\\SpaceshipBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/SpaceshipBinary.php',
'Twig\\Node\\Expression\\Binary\\StartsWithBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/StartsWithBinary.php',
'Twig\\Node\\Expression\\Binary\\SubBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/SubBinary.php',
@@ -2951,6 +2979,7 @@ return array(
'Twig\\Node\\Expression\\CallExpression' => $vendorDir . '/twig/twig/src/Node/Expression/CallExpression.php',
'Twig\\Node\\Expression\\ConditionalExpression' => $vendorDir . '/twig/twig/src/Node/Expression/ConditionalExpression.php',
'Twig\\Node\\Expression\\ConstantExpression' => $vendorDir . '/twig/twig/src/Node/Expression/ConstantExpression.php',
'Twig\\Node\\Expression\\EmptyExpression' => $vendorDir . '/twig/twig/src/Node/Expression/EmptyExpression.php',
'Twig\\Node\\Expression\\FilterExpression' => $vendorDir . '/twig/twig/src/Node/Expression/FilterExpression.php',
'Twig\\Node\\Expression\\Filter\\DefaultFilter' => $vendorDir . '/twig/twig/src/Node/Expression/Filter/DefaultFilter.php',
'Twig\\Node\\Expression\\Filter\\RawFilter' => $vendorDir . '/twig/twig/src/Node/Expression/Filter/RawFilter.php',

View File

@@ -8,5 +8,4 @@ $baseDir = dirname($vendorDir);
return array(
'Console' => array($vendorDir . '/pear/console_getopt'),
'Archive_Tar' => array($vendorDir . '/pear/archive_tar'),
'' => array($vendorDir . '/pear/pear-core-minimal/src'),
);

View File

@@ -360,10 +360,6 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
),
);
public static $fallbackDirsPsr0 = array (
0 => __DIR__ . '/..' . '/pear/pear-core-minimal/src',
);
public static $classMap = array (
'AbstractApplicationObjectExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
'AbstractApplicationUIExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
@@ -1317,6 +1313,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'PDF417' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/pdf417.php',
'PDFBulkExport' => __DIR__ . '/../..' . '/core/pdfbulkexport.class.inc.php',
'PEAR' => __DIR__ . '/..' . '/pear/pear-core-minimal/src/PEAR.php',
'PEAR_Error' => __DIR__ . '/..' . '/pear/pear-core-minimal/src/PEAR.php',
'PEAR_ErrorStack' => __DIR__ . '/..' . '/pear/pear-core-minimal/src/PEAR/ErrorStack.php',
'PEAR_Exception' => __DIR__ . '/..' . '/pear/pear_exception/PEAR/Exception.php',
'Pelago\\Emogrifier\\Caching\\SimpleStringCache' => __DIR__ . '/..' . '/pelago/emogrifier/src/Caching/SimpleStringCache.php',
@@ -2004,22 +2001,43 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Symfony\\Component\\Cache\\Psr16Cache' => __DIR__ . '/..' . '/symfony/cache/Psr16Cache.php',
'Symfony\\Component\\Cache\\ResettableInterface' => __DIR__ . '/..' . '/symfony/cache/ResettableInterface.php',
'Symfony\\Component\\Cache\\Traits\\AbstractAdapterTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/AbstractAdapterTrait.php',
'Symfony\\Component\\Cache\\Traits\\CachedValueInterface' => __DIR__ . '/..' . '/symfony/cache/Traits/CachedValueInterface.php',
'Symfony\\Component\\Cache\\Traits\\ContractsTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ContractsTrait.php',
'Symfony\\Component\\Cache\\Traits\\FilesystemCommonTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/FilesystemCommonTrait.php',
'Symfony\\Component\\Cache\\Traits\\FilesystemTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/FilesystemTrait.php',
'Symfony\\Component\\Cache\\Traits\\ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\Redis5Proxy' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis5Proxy.php',
'Symfony\\Component\\Cache\\Traits\\Redis61ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis61ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\Redis62ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis62ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\Redis63ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis63ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\Redis6Proxy' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis6Proxy.php',
'Symfony\\Component\\Cache\\Traits\\Redis6ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis6ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\RedisCluster5Proxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster5Proxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisCluster61ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster61ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\RedisCluster62ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster62ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\RedisCluster63ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster63ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\RedisCluster6Proxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster6Proxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisCluster6ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster6ProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\RedisClusterNodeProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisClusterNodeProxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisClusterProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisClusterProxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisProxy.php',
'Symfony\\Component\\Cache\\Traits\\RedisTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisTrait.php',
'Symfony\\Component\\Cache\\Traits\\RelayProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RelayProxy.php',
'Symfony\\Component\\Cache\\Traits\\RelayProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RelayProxyTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\BgsaveTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/BgsaveTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\CopyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/CopyTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\FtTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/FtTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\GeosearchTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/GeosearchTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\GetWithMetaTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/GetWithMetaTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\GetrangeTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/GetrangeTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\HsetTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/HsetTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\IsTrackedTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/IsTrackedTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\MoveTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/MoveTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\NullableReturnTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/NullableReturnTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\PfcountTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/PfcountTrait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay11Trait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/Relay11Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay121Trait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/Relay121Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay12Trait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/Relay12Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\Relay20Trait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/Relay20Trait.php',
'Symfony\\Component\\Cache\\Traits\\Relay\\SwapdbTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/SwapdbTrait.php',
'Symfony\\Component\\Config\\Builder\\ClassBuilder' => __DIR__ . '/..' . '/symfony/config/Builder/ClassBuilder.php',
'Symfony\\Component\\Config\\Builder\\ConfigBuilderGenerator' => __DIR__ . '/..' . '/symfony/config/Builder/ConfigBuilderGenerator.php',
'Symfony\\Component\\Config\\Builder\\ConfigBuilderGeneratorInterface' => __DIR__ . '/..' . '/symfony/config/Builder/ConfigBuilderGeneratorInterface.php',
@@ -2184,6 +2202,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Symfony\\Component\\Console\\Helper\\TableRows' => __DIR__ . '/..' . '/symfony/console/Helper/TableRows.php',
'Symfony\\Component\\Console\\Helper\\TableSeparator' => __DIR__ . '/..' . '/symfony/console/Helper/TableSeparator.php',
'Symfony\\Component\\Console\\Helper\\TableStyle' => __DIR__ . '/..' . '/symfony/console/Helper/TableStyle.php',
'Symfony\\Component\\Console\\Helper\\TerminalInputHelper' => __DIR__ . '/..' . '/symfony/console/Helper/TerminalInputHelper.php',
'Symfony\\Component\\Console\\Input\\ArgvInput' => __DIR__ . '/..' . '/symfony/console/Input/ArgvInput.php',
'Symfony\\Component\\Console\\Input\\ArrayInput' => __DIR__ . '/..' . '/symfony/console/Input/ArrayInput.php',
'Symfony\\Component\\Console\\Input\\Input' => __DIR__ . '/..' . '/symfony/console/Input/Input.php',
@@ -3058,7 +3077,6 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Symfony\\Component\\VarDumper\\Cloner\\Cursor' => __DIR__ . '/..' . '/symfony/var-dumper/Cloner/Cursor.php',
'Symfony\\Component\\VarDumper\\Cloner\\Data' => __DIR__ . '/..' . '/symfony/var-dumper/Cloner/Data.php',
'Symfony\\Component\\VarDumper\\Cloner\\DumperInterface' => __DIR__ . '/..' . '/symfony/var-dumper/Cloner/DumperInterface.php',
'Symfony\\Component\\VarDumper\\Cloner\\Internal\\NoDefault' => __DIR__ . '/..' . '/symfony/var-dumper/Cloner/Internal/NoDefault.php',
'Symfony\\Component\\VarDumper\\Cloner\\Stub' => __DIR__ . '/..' . '/symfony/var-dumper/Cloner/Stub.php',
'Symfony\\Component\\VarDumper\\Cloner\\VarCloner' => __DIR__ . '/..' . '/symfony/var-dumper/Cloner/VarCloner.php',
'Symfony\\Component\\VarDumper\\Command\\Descriptor\\CliDescriptor' => __DIR__ . '/..' . '/symfony/var-dumper/Command/Descriptor/CliDescriptor.php',
@@ -3213,6 +3231,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Twig\\ExpressionParser\\InfixExpressionParserInterface' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser/InfixExpressionParserInterface.php',
'Twig\\ExpressionParser\\Infix\\ArgumentsTrait' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php',
'Twig\\ExpressionParser\\Infix\\ArrowExpressionParser' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser/Infix/ArrowExpressionParser.php',
'Twig\\ExpressionParser\\Infix\\AssignmentExpressionParser' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser/Infix/AssignmentExpressionParser.php',
'Twig\\ExpressionParser\\Infix\\BinaryOperatorExpressionParser' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser/Infix/BinaryOperatorExpressionParser.php',
'Twig\\ExpressionParser\\Infix\\ConditionalTernaryExpressionParser' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser/Infix/ConditionalTernaryExpressionParser.php',
'Twig\\ExpressionParser\\Infix\\DotExpressionParser' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser/Infix/DotExpressionParser.php',
@@ -3298,10 +3317,15 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Twig\\Node\\Expression\\Binary\\MulBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/MulBinary.php',
'Twig\\Node\\Expression\\Binary\\NotEqualBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/NotEqualBinary.php',
'Twig\\Node\\Expression\\Binary\\NotInBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/NotInBinary.php',
'Twig\\Node\\Expression\\Binary\\NotSameAsBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/NotSameAsBinary.php',
'Twig\\Node\\Expression\\Binary\\NullCoalesceBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/NullCoalesceBinary.php',
'Twig\\Node\\Expression\\Binary\\ObjectDestructuringSetBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/ObjectDestructuringSetBinary.php',
'Twig\\Node\\Expression\\Binary\\OrBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/OrBinary.php',
'Twig\\Node\\Expression\\Binary\\PowerBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/PowerBinary.php',
'Twig\\Node\\Expression\\Binary\\RangeBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/RangeBinary.php',
'Twig\\Node\\Expression\\Binary\\SameAsBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/SameAsBinary.php',
'Twig\\Node\\Expression\\Binary\\SequenceDestructuringSetBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/SequenceDestructuringSetBinary.php',
'Twig\\Node\\Expression\\Binary\\SetBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/SetBinary.php',
'Twig\\Node\\Expression\\Binary\\SpaceshipBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/SpaceshipBinary.php',
'Twig\\Node\\Expression\\Binary\\StartsWithBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/StartsWithBinary.php',
'Twig\\Node\\Expression\\Binary\\SubBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/SubBinary.php',
@@ -3310,6 +3334,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Twig\\Node\\Expression\\CallExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/CallExpression.php',
'Twig\\Node\\Expression\\ConditionalExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/ConditionalExpression.php',
'Twig\\Node\\Expression\\ConstantExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/ConstantExpression.php',
'Twig\\Node\\Expression\\EmptyExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/EmptyExpression.php',
'Twig\\Node\\Expression\\FilterExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/FilterExpression.php',
'Twig\\Node\\Expression\\Filter\\DefaultFilter' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Filter/DefaultFilter.php',
'Twig\\Node\\Expression\\Filter\\RawFilter' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Filter/RawFilter.php',
@@ -3542,7 +3567,6 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
$loader->prefixLengthsPsr4 = ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::$prefixesPsr0;
$loader->fallbackDirsPsr0 = ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::$fallbackDirsPsr0;
$loader->classMap = ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::$classMap;
}, null, ClassLoader::class);

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
<?php return array(
'root' => array(
'name' => 'combodo/itop',
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => 'd5706fcbef58868cb8bd6ee6f3af133ca4fdab3e',
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => null,
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -11,18 +11,20 @@
),
'versions' => array(
'apereo/phpcas' => array(
'pretty_version' => '1.6.1',
'version' => '1.6.1.0',
'reference' => 'c129708154852656aabb13d8606cd5b12dbbabac',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '57a7744146a963d8fa80192e0ab351051b711ff6',
'type' => 'library',
'install_path' => __DIR__ . '/../apereo/phpcas',
'aliases' => array(),
'aliases' => array(
0 => '1.3.x-dev',
),
'dev_requirement' => false,
),
'combodo/itop' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => 'd5706fcbef58868cb8bd6ee6f3af133ca4fdab3e',
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => null,
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -47,77 +49,68 @@
'dev_requirement' => false,
),
'firebase/php-jwt' => array(
'pretty_version' => 'v6.10.0',
'version' => '6.10.0.0',
'reference' => 'a49db6f0a5033aef5143295342f1c95521b075ff',
'pretty_version' => 'v7.0.2',
'version' => '7.0.2.0',
'reference' => '5645b43af647b6947daac1d0f659dd1fbe8d3b65',
'type' => 'library',
'install_path' => __DIR__ . '/../firebase/php-jwt',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/guzzle' => array(
'pretty_version' => '7.8.1',
'version' => '7.8.1.0',
'reference' => '41042bc7ab002487b876a0683fc8dce04ddce104',
'pretty_version' => '7.10.0',
'version' => '7.10.0.0',
'reference' => 'b51ac707cfa420b7bfd4e4d5e510ba8008e822b4',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/promises' => array(
'pretty_version' => '2.0.2',
'version' => '2.0.2.0',
'reference' => 'bbff78d96034045e58e13dedd6ad91b5d1253223',
'pretty_version' => '2.3.0',
'version' => '2.3.0.0',
'reference' => '481557b130ef3790cf82b713667b43030dc9c957',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/promises',
'aliases' => array(),
'dev_requirement' => false,
),
'guzzlehttp/psr7' => array(
'pretty_version' => '2.6.2',
'version' => '2.6.2.0',
'reference' => '45b30f99ac27b5ca93cb4831afe16285f57b8221',
'pretty_version' => '2.8.0',
'version' => '2.8.0.0',
'reference' => '21dc724a0583619cd1652f673303492272778051',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
'aliases' => array(),
'dev_requirement' => false,
),
'league/oauth2-client' => array(
'pretty_version' => '2.7.0',
'version' => '2.7.0.0',
'reference' => '160d6274b03562ebeb55ed18399281d8118b76c8',
'pretty_version' => '2.9.0',
'version' => '2.9.0.0',
'reference' => '26e8c5da4f3d78cede7021e09b1330a0fc093d5e',
'type' => 'library',
'install_path' => __DIR__ . '/../league/oauth2-client',
'aliases' => array(),
'dev_requirement' => false,
),
'league/oauth2-google' => array(
'pretty_version' => '4.0.1',
'version' => '4.0.1.0',
'reference' => '1b01ba18ba31b29e88771e3e0979e5c91d4afe76',
'pretty_version' => '4.1.0',
'version' => '4.1.0.0',
'reference' => '8b9bb43740ac6d994aca881a35f7bacbe98c0ffb',
'type' => 'library',
'install_path' => __DIR__ . '/../league/oauth2-google',
'aliases' => array(),
'dev_requirement' => false,
),
'nikic/php-parser' => array(
'pretty_version' => 'v4.18.0',
'version' => '4.18.0.0',
'reference' => '1bcbb2179f97633e98bbbc87044ee2611c7d7999',
'pretty_version' => 'v4.19.5',
'version' => '4.19.5.0',
'reference' => '51bd93cc741b7fc3d63d20b6bdcd99fdaa359837',
'type' => 'library',
'install_path' => __DIR__ . '/../nikic/php-parser',
'aliases' => array(),
'dev_requirement' => false,
),
'paragonie/random_compat' => array(
'pretty_version' => 'v9.99.100',
'version' => '9.99.100.0',
'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
'type' => 'library',
'install_path' => __DIR__ . '/../paragonie/random_compat',
'aliases' => array(),
'dev_requirement' => false,
),
'pear/archive_tar' => array(
'pretty_version' => '1.4.14',
'version' => '1.4.14.0',
@@ -137,9 +130,9 @@
'dev_requirement' => false,
),
'pear/pear-core-minimal' => array(
'pretty_version' => 'v1.10.11',
'version' => '1.10.11.0',
'reference' => '68d0d32ada737153b7e93b8d3c710ebe70ac867d',
'pretty_version' => 'v1.10.18',
'version' => '1.10.18.0',
'reference' => 'c7b55789d01de0ce090d289b73f1bbd6a2f113b1',
'type' => 'library',
'install_path' => __DIR__ . '/../pear/pear-core-minimal',
'aliases' => array(),
@@ -155,9 +148,9 @@
'dev_requirement' => false,
),
'pelago/emogrifier' => array(
'pretty_version' => 'v7.2.0',
'version' => '7.2.0.0',
'reference' => '727bdf7255b51798307f17dec52ff8a91f1c7de3',
'pretty_version' => 'v7.3.0',
'version' => '7.3.0.0',
'reference' => '6e00d9d8235e8cc8eec857e8dcd6cfeefdfd0cd6',
'type' => 'library',
'install_path' => __DIR__ . '/../pelago/emogrifier',
'aliases' => array(),
@@ -224,9 +217,9 @@
),
),
'psr/http-factory' => array(
'pretty_version' => '1.0.2',
'version' => '1.0.2.0',
'reference' => 'e616d01114759c4c489f93b099585439f795fe35',
'pretty_version' => '1.1.0',
'version' => '1.1.0.0',
'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-factory',
'aliases' => array(),
@@ -286,22 +279,22 @@
'rsky/pear-core-min' => array(
'dev_requirement' => false,
'replaced' => array(
0 => 'v1.10.11',
0 => 'v1.10.18',
),
),
'sabberworm/php-css-parser' => array(
'pretty_version' => '8.4.0',
'version' => '8.4.0.0',
'reference' => 'e41d2140031d533348b2192a83f02d8dd8a71d30',
'pretty_version' => 'v8.9.0',
'version' => '8.9.0.0',
'reference' => 'd8e916507b88e389e26d4ab03c904a082aa66bb9',
'type' => 'library',
'install_path' => __DIR__ . '/../sabberworm/php-css-parser',
'aliases' => array(),
'dev_requirement' => false,
),
'scssphp/scssphp' => array(
'pretty_version' => 'v1.12.1',
'version' => '1.12.1.0',
'reference' => '394ed1e960138710a60d035c1a85d43d0bf0faeb',
'pretty_version' => 'v1.13.0',
'version' => '1.13.0.0',
'reference' => '63d1157457e5554edf00b0c1fabab4c1511d2520',
'type' => 'library',
'install_path' => __DIR__ . '/../scssphp/scssphp',
'aliases' => array(),
@@ -317,9 +310,9 @@
'dev_requirement' => false,
),
'symfony/cache' => array(
'pretty_version' => 'v6.4.12',
'version' => '6.4.12.0',
'reference' => 'a463451b7f6ac4a47b98dbfc78ec2d3560c759d8',
'pretty_version' => 'v6.4.33',
'version' => '6.4.33.0',
'reference' => '5b088fa41eb9568748dc255c45e4054c387ba73b',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/cache',
'aliases' => array(),
@@ -341,45 +334,45 @@
),
),
'symfony/config' => array(
'pretty_version' => 'v6.4.0',
'version' => '6.4.0.0',
'reference' => '5d33e0fb707d603330e0edfd4691803a1253572e',
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => 'd445badf0ad2c2a492e38c0378c39997a56ef97b',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/config',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/console' => array(
'pretty_version' => 'v6.4.2',
'version' => '6.4.2.0',
'reference' => '0254811a143e6bc6c8deea08b589a7e68a37f625',
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/console',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/css-selector' => array(
'pretty_version' => 'v6.4.0',
'version' => '6.4.0.0',
'reference' => 'd036c6c0d0b09e24a14a35f8292146a658f986e4',
'pretty_version' => 'v6.4.24',
'version' => '6.4.24.0',
'reference' => '9b784413143701aa3c94ac1869a159a9e53e8761',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/css-selector',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/debug-bundle' => array(
'pretty_version' => 'v6.4.0',
'version' => '6.4.0.0',
'reference' => '1e07027423d1d37125b60a50997ada26a9d9d202',
'pretty_version' => 'v6.4.27',
'version' => '6.4.27.0',
'reference' => '21a61c55192d558a6b81cdb12e8c010fc9474fe0',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../symfony/debug-bundle',
'aliases' => array(),
'dev_requirement' => true,
),
'symfony/dependency-injection' => array(
'pretty_version' => 'v6.4.2',
'version' => '6.4.2.0',
'reference' => '226ea431b1eda6f0d9f5a4b278757171960bb195',
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => 'b17882e933c4c606620247b6708ab53aa3b88753',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/dependency-injection',
'aliases' => array(),
@@ -395,27 +388,27 @@
'dev_requirement' => false,
),
'symfony/dotenv' => array(
'pretty_version' => 'v6.4.2',
'version' => '6.4.2.0',
'reference' => '835f8d2d1022934ac038519de40b88158798c96f',
'pretty_version' => 'v6.4.30',
'version' => '6.4.30.0',
'reference' => '924edbc9631b75302def0258ed1697948b17baf6',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/dotenv',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/error-handler' => array(
'pretty_version' => 'v6.4.0',
'version' => '6.4.0.0',
'reference' => 'c873490a1c97b3a0a4838afc36ff36c112d02788',
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '8c18400784fcb014dc73c8d5601a9576af7f8ad4',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/error-handler',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/event-dispatcher' => array(
'pretty_version' => 'v6.4.25',
'version' => '6.4.25.0',
'reference' => 'b0cf3162020603587363f0551cd3be43958611ff',
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '99d7e101826e6610606b9433248f80c1997cd20b',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/event-dispatcher',
'aliases' => array(),
@@ -437,81 +430,81 @@
),
),
'symfony/filesystem' => array(
'pretty_version' => 'v6.4.0',
'version' => '6.4.0.0',
'reference' => '952a8cb588c3bc6ce76f6023000fb932f16a6e59',
'pretty_version' => 'v6.4.30',
'version' => '6.4.30.0',
'reference' => '441c6b69f7222aadae7cbf5df588496d5ee37789',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/filesystem',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/finder' => array(
'pretty_version' => 'v6.4.0',
'version' => '6.4.0.0',
'reference' => '11d736e97f116ac375a81f96e662911a34cd50ce',
'pretty_version' => 'v6.4.33',
'version' => '6.4.33.0',
'reference' => '24965ca011dac87431729640feef8bcf7b5523e0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/finder',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/framework-bundle' => array(
'pretty_version' => 'v6.4.2',
'version' => '6.4.2.0',
'reference' => 'c26a221e0462027d1f9d4a802ed63f8ab07a43d0',
'pretty_version' => 'v6.4.33',
'version' => '6.4.33.0',
'reference' => '9ef2d0b63b9e855ba351e770a603d89699115801',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../symfony/framework-bundle',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/http-foundation' => array(
'pretty_version' => 'v6.4.29',
'version' => '6.4.29.0',
'reference' => 'b03d11e015552a315714c127d8d1e0f9e970ec88',
'pretty_version' => 'v6.4.33',
'version' => '6.4.33.0',
'reference' => 'f1a490cc9d595ba7ebe684220e625d1e472ad278',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/http-foundation',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/http-kernel' => array(
'pretty_version' => 'v6.4.2',
'version' => '6.4.2.0',
'reference' => '13e8387320b5942d0dc408440c888e2d526efef4',
'pretty_version' => 'v6.4.33',
'version' => '6.4.33.0',
'reference' => '73fa5c999d7f741ca544a97d3c791cc97890ae4d',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/http-kernel',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/mailer' => array(
'pretty_version' => 'v6.4.25',
'version' => '6.4.25.0',
'reference' => '628b43b45a3e6b15c8a633fb22df547ed9b492a2',
'pretty_version' => 'v6.4.31',
'version' => '6.4.31.0',
'reference' => '8835f93333474780fda1b987cae37e33c3e026ca',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/mailer',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/mime' => array(
'pretty_version' => 'v6.4.24',
'version' => '6.4.24.0',
'reference' => '664d5e844a2de5e11c8255d0aef6bc15a9660ac7',
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '7409686879ca36c09fc970a5fa8ff6e93504dba4',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/mime',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => 'ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb',
'pretty_version' => 'v1.33.0',
'version' => '1.33.0.0',
'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-intl-grapheme' => array(
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '875e90aeea2777b6f135677f618529449334a612',
'pretty_version' => 'v1.33.0',
'version' => '1.33.0.0',
'reference' => '380872130d3a5dd3ace2f4010d95125fde5d5c70',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme',
'aliases' => array(),
@@ -554,18 +547,18 @@
'dev_requirement' => false,
),
'symfony/routing' => array(
'pretty_version' => 'v6.4.2',
'version' => '6.4.2.0',
'reference' => '98eab13a07fddc85766f1756129c69f207ffbc21',
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '0dc6253e864e71b486e8ba4970a56ab849106ebe',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/routing',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/runtime' => array(
'pretty_version' => 'v6.4.24',
'version' => '6.4.24.0',
'reference' => 'c1cc6721646f546627236c57f835272806087337',
'pretty_version' => 'v6.4.30',
'version' => '6.4.30.0',
'reference' => 'fb3149ee85d3b639dd3e49ea9dda05656f0537e3',
'type' => 'composer-plugin',
'install_path' => __DIR__ . '/../symfony/runtime',
'aliases' => array(),
@@ -587,54 +580,54 @@
),
),
'symfony/stopwatch' => array(
'pretty_version' => 'v6.4.0',
'version' => '6.4.0.0',
'reference' => 'fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2',
'pretty_version' => 'v6.4.24',
'version' => '6.4.24.0',
'reference' => 'b67e94e06a05d9572c2fa354483b3e13e3cb1898',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/stopwatch',
'aliases' => array(),
'dev_requirement' => true,
),
'symfony/string' => array(
'pretty_version' => 'v6.4.2',
'version' => '6.4.2.0',
'reference' => '7cb80bc10bfcdf6b5492741c0b9357dac66940bc',
'pretty_version' => 'v6.4.30',
'version' => '6.4.30.0',
'reference' => '50590a057841fa6bf69d12eceffce3465b9e32cb',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/string',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/translation-contracts' => array(
'pretty_version' => 'v3.4.0',
'version' => '3.4.0.0',
'reference' => 'dee0c6e5b4c07ce851b462530088e64b255ac9c5',
'pretty_version' => 'v3.6.1',
'version' => '3.6.1.0',
'reference' => '65a8bc82080447fae78373aa10f8d13b38338977',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation-contracts',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/twig-bridge' => array(
'pretty_version' => 'v6.4.0',
'version' => '6.4.0.0',
'reference' => '142bc3ad4a61d7eedf7cc21d8ef2bd8a8e7417bf',
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '1dcf980dd4f79885b986befdeb1c1bc0d6aedfc8',
'type' => 'symfony-bridge',
'install_path' => __DIR__ . '/../symfony/twig-bridge',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/twig-bundle' => array(
'pretty_version' => 'v6.4.0',
'version' => '6.4.0.0',
'reference' => '35d84393e598dfb774e6a2bf49e5229a8a6dbe4c',
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => 'a5c8dcc11a5bf9c96320da20070d2e158a4e0b30',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../symfony/twig-bundle',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/var-dumper' => array(
'pretty_version' => 'v6.4.2',
'version' => '6.4.2.0',
'reference' => '68d6573ec98715ddcae5a0a85bee3c1c27a4c33f',
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '131fc9915e0343052af5ed5040401b481ca192aa',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/var-dumper',
'aliases' => array(),
@@ -650,45 +643,45 @@
'dev_requirement' => false,
),
'symfony/web-profiler-bundle' => array(
'pretty_version' => 'v6.4.2',
'version' => '6.4.2.0',
'reference' => '38462d16856740ec0d1ba2cb902eebf09100dde2',
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '011f59e3f3d20f60d11b4e78b8dc63504f56e145',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../symfony/web-profiler-bundle',
'aliases' => array(),
'dev_requirement' => true,
),
'symfony/yaml' => array(
'pretty_version' => 'v6.4.0',
'version' => '6.4.0.0',
'reference' => '4f9237a1bb42455d609e6687d2613dde5b41a587',
'pretty_version' => 'v6.4.30',
'version' => '6.4.30.0',
'reference' => '8207ae83da19ee3748d6d4f567b4d9a7c656e331',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/yaml',
'aliases' => array(),
'dev_requirement' => false,
),
'tecnickcom/tcpdf' => array(
'pretty_version' => '6.10.0',
'version' => '6.10.0.0',
'reference' => 'ca5b6de294512145db96bcbc94e61696599c391d',
'pretty_version' => '6.10.1',
'version' => '6.10.1.0',
'reference' => '7a2701251e5d52fc3d508fd71704683eb54f5939',
'type' => 'library',
'install_path' => __DIR__ . '/../tecnickcom/tcpdf',
'aliases' => array(),
'dev_requirement' => false,
),
'thenetworg/oauth2-azure' => array(
'pretty_version' => 'v2.2.2',
'version' => '2.2.2.0',
'reference' => 'be204a5135f016470a9c33e82ab48785bbc11af2',
'pretty_version' => 'v2.2.4',
'version' => '2.2.4.0',
'reference' => 'a897d60b6b127daa2f27b1b4e62e7af40829d02f',
'type' => 'library',
'install_path' => __DIR__ . '/../thenetworg/oauth2-azure',
'aliases' => array(),
'dev_requirement' => false,
),
'twig/twig' => array(
'pretty_version' => 'v3.21.1',
'version' => '3.21.1.0',
'reference' => '285123877d4dd97dd7c11842ac5fb7e86e60d81d',
'pretty_version' => 'v3.23.0',
'version' => '3.23.0.0',
'reference' => 'a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9',
'type' => 'library',
'install_path' => __DIR__ . '/../twig/twig',
'aliases' => array(),

View File

@@ -1,5 +1,64 @@
# Changelog
## [7.0.2](https://github.com/firebase/php-jwt/compare/v7.0.1...v7.0.2) (2025-12-16)
### Bug Fixes
* add key length validation for ec keys ([#615](https://github.com/firebase/php-jwt/issues/615)) ([7044f9a](https://github.com/firebase/php-jwt/commit/7044f9ae7e7d175d28cca71714feb236f1c0e252))
## [7.0.0](https://github.com/firebase/php-jwt/compare/v6.11.1...v7.0.0) (2025-12-15)
### ⚠️ ⚠️ ⚠️ Security Fixes ⚠️ ⚠️ ⚠️
* add key size validation ([#613](https://github.com/firebase/php-jwt/issues/613)) ([6b80341](https://github.com/firebase/php-jwt/commit/6b80341bf57838ea2d011487917337901cd71576))
**NOTE**: This fix will cause keys with a size below the minimally allowed size to break.
### Features
* add SensitiveParameter attribute to security-critical parameters ([#603](https://github.com/firebase/php-jwt/issues/603)) ([4dbfac0](https://github.com/firebase/php-jwt/commit/4dbfac0260eeb0e9e643063c99998e3219cc539b))
* store timestamp in `ExpiredException` ([#604](https://github.com/firebase/php-jwt/issues/604)) ([f174826](https://github.com/firebase/php-jwt/commit/f1748260d218a856b6a0c23715ac7fae1d7ca95b))
### Bug Fixes
* validate iat and nbf on payload ([#568](https://github.com/firebase/php-jwt/issues/568)) ([953b2c8](https://github.com/firebase/php-jwt/commit/953b2c88bb445b7e3bb82a5141928f13d7343afd))
## [6.11.1](https://github.com/firebase/php-jwt/compare/v6.11.0...v6.11.1) (2025-04-09)
### Bug Fixes
* update error text for consistency ([#528](https://github.com/firebase/php-jwt/issues/528)) ([c11113a](https://github.com/firebase/php-jwt/commit/c11113afa13265e016a669e75494b9203b8a7775))
## [6.11.0](https://github.com/firebase/php-jwt/compare/v6.10.2...v6.11.0) (2025-01-23)
### Features
* support octet typed JWK ([#587](https://github.com/firebase/php-jwt/issues/587)) ([7cb8a26](https://github.com/firebase/php-jwt/commit/7cb8a265fa81edf2fa6ef8098f5bc5ae573c33ad))
### Bug Fixes
* refactor constructor Key to use PHP 8.0 syntax ([#577](https://github.com/firebase/php-jwt/issues/577)) ([29fa2ce](https://github.com/firebase/php-jwt/commit/29fa2ce9e0582cd397711eec1e80c05ce20fabca))
## [6.10.2](https://github.com/firebase/php-jwt/compare/v6.10.1...v6.10.2) (2024-11-24)
### Bug Fixes
* Mitigate PHP8.4 deprecation warnings ([#570](https://github.com/firebase/php-jwt/issues/570)) ([76808fa](https://github.com/firebase/php-jwt/commit/76808fa227f3811aa5cdb3bf81233714b799a5b5))
* support php 8.4 ([#583](https://github.com/firebase/php-jwt/issues/583)) ([e3d68b0](https://github.com/firebase/php-jwt/commit/e3d68b044421339443c74199edd020e03fb1887e))
## [6.10.1](https://github.com/firebase/php-jwt/compare/v6.10.0...v6.10.1) (2024-05-18)
### Bug Fixes
* ensure ratelimit expiry is set every time ([#556](https://github.com/firebase/php-jwt/issues/556)) ([09cb208](https://github.com/firebase/php-jwt/commit/09cb2081c2c3bc0f61e2f2a5fbea5741f7498648))
* ratelimit cache expiration ([#550](https://github.com/firebase/php-jwt/issues/550)) ([dda7250](https://github.com/firebase/php-jwt/commit/dda725033585ece30ff8cae8937320d7e9f18bae))
## [6.10.0](https://github.com/firebase/php-jwt/compare/v6.9.0...v6.10.0) (2023-11-28)

View File

@@ -17,7 +17,7 @@ composer require firebase/php-jwt
```
Optionally, install the `paragonie/sodium_compat` package from composer if your
php is < 7.2 or does not have libsodium installed:
php env does not have libsodium installed:
```bash
composer require paragonie/sodium_compat
@@ -48,7 +48,8 @@ $decoded = JWT::decode($jwt, new Key($key, 'HS256'));
print_r($decoded);
// Pass a stdClass in as the third parameter to get the decoded header values
$decoded = JWT::decode($jwt, new Key($key, 'HS256'), $headers = new stdClass());
$headers = new stdClass();
$decoded = JWT::decode($jwt, new Key($key, 'HS256'), $headers);
print_r($headers);
/*
@@ -185,7 +186,7 @@ $passphrase = '[YOUR_PASSPHRASE]';
// Can be generated with "ssh-keygen -t rsa -m pem"
$privateKeyFile = '/path/to/key-with-passphrase.pem';
// Create a private key of type "resource"
/** @var OpenSSLAsymmetricKey $privateKey */
$privateKey = openssl_pkey_get_private(
file_get_contents($privateKeyFile),
$passphrase
@@ -290,7 +291,7 @@ $jwks = ['keys' => []];
// JWK::parseKeySet($jwks) returns an associative array of **kid** to Firebase\JWT\Key
// objects. Pass this as the second parameter to JWT::decode.
JWT::decode($payload, JWK::parseKeySet($jwks));
JWT::decode($jwt, JWK::parseKeySet($jwks));
```
Using Cached Key Sets
@@ -349,7 +350,7 @@ use InvalidArgumentException;
use UnexpectedValueException;
try {
$decoded = JWT::decode($payload, $keys);
$decoded = JWT::decode($jwt, $keys);
} catch (InvalidArgumentException $e) {
// provided key/key-array is empty or malformed.
} catch (DomainException $e) {
@@ -379,7 +380,7 @@ like this:
use Firebase\JWT\JWT;
use UnexpectedValueException;
try {
$decoded = JWT::decode($payload, $keys);
$decoded = JWT::decode($jwt, $keys);
} catch (LogicException $e) {
// errors having to do with environmental setup or malformed JWT Keys
} catch (UnexpectedValueException $e) {
@@ -394,7 +395,7 @@ instead, you can do the following:
```php
// return type is stdClass
$decoded = JWT::decode($payload, $keys);
$decoded = JWT::decode($jwt, $keys);
// cast to array
$decoded = json_decode(json_encode($decoded), true);

View File

@@ -20,7 +20,7 @@
],
"license": "BSD-3-Clause",
"require": {
"php": "^7.4||^8.0"
"php": "^8.0"
},
"suggest": {
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present",
@@ -32,10 +32,10 @@
}
},
"require-dev": {
"guzzlehttp/guzzle": "^6.5||^7.4",
"guzzlehttp/guzzle": "^7.4",
"phpspec/prophecy-phpunit": "^2.0",
"phpunit/phpunit": "^9.5",
"psr/cache": "^1.0||^2.0",
"psr/cache": "^2.0||^3.0",
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0"
}

View File

@@ -80,9 +80,9 @@ class CachedKeySet implements ArrayAccess
ClientInterface $httpClient,
RequestFactoryInterface $httpFactory,
CacheItemPoolInterface $cache,
int $expiresAfter = null,
?int $expiresAfter = null,
bool $rateLimit = false,
string $defaultAlg = null
?string $defaultAlg = null
) {
$this->jwksUri = $jwksUri;
$this->httpClient = $httpClient;
@@ -180,7 +180,7 @@ class CachedKeySet implements ArrayAccess
$jwksResponse = $this->httpClient->sendRequest($request);
if ($jwksResponse->getStatusCode() !== 200) {
throw new UnexpectedValueException(
sprintf('HTTP Error: %d %s for URI "%s"',
\sprintf('HTTP Error: %d %s for URI "%s"',
$jwksResponse->getStatusCode(),
$jwksResponse->getReasonPhrase(),
$this->jwksUri,
@@ -212,15 +212,21 @@ class CachedKeySet implements ArrayAccess
}
$cacheItem = $this->cache->getItem($this->rateLimitCacheKey);
if (!$cacheItem->isHit()) {
$cacheItem->expiresAfter(1); // # of calls are cached each minute
$cacheItemData = [];
if ($cacheItem->isHit() && \is_array($data = $cacheItem->get())) {
$cacheItemData = $data;
}
$callsPerMinute = (int) $cacheItem->get();
$callsPerMinute = $cacheItemData['callsPerMinute'] ?? 0;
$expiry = $cacheItemData['expiry'] ?? new \DateTime('+60 seconds', new \DateTimeZone('UTC'));
if (++$callsPerMinute > $this->maxCallsPerMinute) {
return true;
}
$cacheItem->set($callsPerMinute);
$cacheItem->set(['expiry' => $expiry, 'callsPerMinute' => $callsPerMinute]);
$cacheItem->expiresAt($expiry);
$this->cache->save($cacheItem);
return false;
}

View File

@@ -6,6 +6,8 @@ class ExpiredException extends \UnexpectedValueException implements JWTException
{
private object $payload;
private ?int $timestamp = null;
public function setPayload(object $payload): void
{
$this->payload = $payload;
@@ -15,4 +17,14 @@ class ExpiredException extends \UnexpectedValueException implements JWTException
{
return $this->payload;
}
public function setTimestamp(int $timestamp): void
{
$this->timestamp = $timestamp;
}
public function getTimestamp(): ?int
{
return $this->timestamp;
}
}

View File

@@ -52,7 +52,7 @@ class JWK
*
* @uses parseKey
*/
public static function parseKeySet(array $jwks, string $defaultAlg = null): array
public static function parseKeySet(#[\SensitiveParameter] array $jwks, ?string $defaultAlg = null): array
{
$keys = [];
@@ -93,7 +93,7 @@ class JWK
*
* @uses createPemFromModulusAndExponent
*/
public static function parseKey(array $jwk, string $defaultAlg = null): ?Key
public static function parseKey(#[\SensitiveParameter] array $jwk, ?string $defaultAlg = null): ?Key
{
if (empty($jwk)) {
throw new InvalidArgumentException('JWK must not be empty');
@@ -172,6 +172,12 @@ class JWK
// This library works internally with EdDSA keys (Ed25519) encoded in standard base64.
$publicKey = JWT::convertBase64urlToBase64($jwk['x']);
return new Key($publicKey, $jwk['alg']);
case 'oct':
if (!isset($jwk['k'])) {
throw new UnexpectedValueException('k not set');
}
return new Key(JWT::urlsafeB64Decode($jwk['k']), $jwk['alg']);
default:
break;
}
@@ -212,7 +218,7 @@ class JWK
)
);
return sprintf(
return \sprintf(
"-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n",
wordwrap(base64_encode($pem), 64, "\n", true)
);

View File

@@ -31,6 +31,8 @@ class JWT
private const ASN1_SEQUENCE = 0x10;
private const ASN1_BIT_STRING = 0x03;
private const RSA_KEY_MIN_LENGTH=2048;
/**
* When checking nbf, iat or expiration times,
* we want to provide some extra leeway time to
@@ -95,8 +97,8 @@ class JWT
*/
public static function decode(
string $jwt,
$keyOrKeyArray,
stdClass &$headers = null
#[\SensitiveParameter] $keyOrKeyArray,
?stdClass &$headers = null
): stdClass {
// Validate JWT
$timestamp = \is_null(static::$timestamp) ? \time() : static::$timestamp;
@@ -127,6 +129,16 @@ class JWT
if (!$payload instanceof stdClass) {
throw new UnexpectedValueException('Payload must be a JSON object');
}
if (isset($payload->iat) && !\is_numeric($payload->iat)) {
throw new UnexpectedValueException('Payload iat must be a number');
}
if (isset($payload->nbf) && !\is_numeric($payload->nbf)) {
throw new UnexpectedValueException('Payload nbf must be a number');
}
if (isset($payload->exp) && !\is_numeric($payload->exp)) {
throw new UnexpectedValueException('Payload exp must be a number');
}
$sig = static::urlsafeB64Decode($cryptob64);
if (empty($header->alg)) {
throw new UnexpectedValueException('Empty algorithm');
@@ -154,7 +166,7 @@ class JWT
// token can actually be used. If it's not yet that time, abort.
if (isset($payload->nbf) && floor($payload->nbf) > ($timestamp + static::$leeway)) {
$ex = new BeforeValidException(
'Cannot handle token with nbf prior to ' . \date(DateTime::ISO8601, (int) $payload->nbf)
'Cannot handle token with nbf prior to ' . \date(DateTime::ATOM, (int) floor($payload->nbf))
);
$ex->setPayload($payload);
throw $ex;
@@ -165,7 +177,7 @@ class JWT
// correctly used the nbf claim).
if (!isset($payload->nbf) && isset($payload->iat) && floor($payload->iat) > ($timestamp + static::$leeway)) {
$ex = new BeforeValidException(
'Cannot handle token with iat prior to ' . \date(DateTime::ISO8601, (int) $payload->iat)
'Cannot handle token with iat prior to ' . \date(DateTime::ATOM, (int) floor($payload->iat))
);
$ex->setPayload($payload);
throw $ex;
@@ -175,6 +187,7 @@ class JWT
if (isset($payload->exp) && ($timestamp - static::$leeway) >= $payload->exp) {
$ex = new ExpiredException('Expired token');
$ex->setPayload($payload);
$ex->setTimestamp($timestamp);
throw $ex;
}
@@ -185,7 +198,7 @@ class JWT
* Converts and signs a PHP array into a JWT string.
*
* @param array<mixed> $payload PHP array
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
* @param string $alg Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256',
* 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
* @param string $keyId
@@ -198,13 +211,13 @@ class JWT
*/
public static function encode(
array $payload,
$key,
#[\SensitiveParameter] $key,
string $alg,
string $keyId = null,
array $head = null
?string $keyId = null,
?array $head = null
): string {
$header = ['typ' => 'JWT'];
if (isset($head) && \is_array($head)) {
if (isset($head)) {
$header = \array_merge($header, $head);
}
$header['alg'] = $alg;
@@ -226,7 +239,7 @@ class JWT
* Sign a string with a given key and algorithm.
*
* @param string $msg The message to sign
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
* @param string $alg Supported algorithms are 'EdDSA', 'ES384', 'ES256', 'ES256K', 'HS256',
* 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
*
@@ -236,7 +249,7 @@ class JWT
*/
public static function sign(
string $msg,
$key,
#[\SensitiveParameter] $key,
string $alg
): string {
if (empty(static::$supported_algs[$alg])) {
@@ -248,10 +261,19 @@ class JWT
if (!\is_string($key)) {
throw new InvalidArgumentException('key must be a string when using hmac');
}
self::validateHmacKeyLength($key, $algorithm);
return \hash_hmac($algorithm, $msg, $key, true);
case 'openssl':
$signature = '';
$success = \openssl_sign($msg, $signature, $key, $algorithm); // @phpstan-ignore-line
if (!$key = openssl_pkey_get_private($key)) {
throw new DomainException('OpenSSL unable to validate key');
}
if (str_starts_with($alg, 'RS')) {
self::validateRsaKeyLength($key);
} elseif (str_starts_with($alg, 'ES')) {
self::validateEcKeyLength($key, $alg);
}
$success = \openssl_sign($msg, $signature, $key, $algorithm);
if (!$success) {
throw new DomainException('OpenSSL unable to sign data');
}
@@ -290,7 +312,7 @@ class JWT
*
* @param string $msg The original message (header and body)
* @param string $signature The original signature
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial For Ed*, ES*, HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial For Ed*, ES*, HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey
* @param string $alg The algorithm
*
* @return bool
@@ -300,7 +322,7 @@ class JWT
private static function verify(
string $msg,
string $signature,
$keyMaterial,
#[\SensitiveParameter] $keyMaterial,
string $alg
): bool {
if (empty(static::$supported_algs[$alg])) {
@@ -310,7 +332,15 @@ class JWT
list($function, $algorithm) = static::$supported_algs[$alg];
switch ($function) {
case 'openssl':
$success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm); // @phpstan-ignore-line
if (!$key = openssl_pkey_get_public($keyMaterial)) {
throw new DomainException('OpenSSL unable to validate key');
}
if (str_starts_with($alg, 'RS')) {
self::validateRsaKeyLength($key);
} elseif (str_starts_with($alg, 'ES')) {
self::validateEcKeyLength($key, $alg);
}
$success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm);
if ($success === 1) {
return true;
}
@@ -347,6 +377,7 @@ class JWT
if (!\is_string($keyMaterial)) {
throw new InvalidArgumentException('key must be a string when using hmac');
}
self::validateHmacKeyLength($keyMaterial, $algorithm);
$hash = \hash_hmac($algorithm, $msg, $keyMaterial, true);
return self::constantTimeEquals($hash, $signature);
}
@@ -384,12 +415,7 @@ class JWT
*/
public static function jsonEncode(array $input): string
{
if (PHP_VERSION_ID >= 50400) {
$json = \json_encode($input, \JSON_UNESCAPED_SLASHES);
} else {
// PHP 5.3 only
$json = \json_encode($input);
}
$json = \json_encode($input, \JSON_UNESCAPED_SLASHES);
if ($errno = \json_last_error()) {
self::handleJsonError($errno);
} elseif ($json === 'null') {
@@ -459,7 +485,7 @@ class JWT
* @return Key
*/
private static function getKey(
$keyOrKeyArray,
#[\SensitiveParameter] $keyOrKeyArray,
?string $kid
): Key {
if ($keyOrKeyArray instanceof Key) {
@@ -666,4 +692,57 @@ class JWT
return [$pos, $data];
}
/**
* Validate HMAC key length
*
* @param string $key HMAC key material
* @param string $algorithm The algorithm
*
* @throws DomainException Provided key is too short
*/
private static function validateHmacKeyLength(string $key, string $algorithm): void
{
$keyLength = \strlen($key) * 8;
$minKeyLength = (int) \str_replace('SHA', '', $algorithm);
if ($keyLength < $minKeyLength) {
throw new DomainException('Provided key is too short');
}
}
/**
* Validate RSA key length
*
* @param OpenSSLAsymmetricKey $key RSA key material
* @throws DomainException Provided key is too short
*/
private static function validateRsaKeyLength(#[\SensitiveParameter] OpenSSLAsymmetricKey $key): void
{
if (!$keyDetails = openssl_pkey_get_details($key)) {
throw new DomainException('Unable to validate key');
}
if ($keyDetails['bits'] < self::RSA_KEY_MIN_LENGTH) {
throw new DomainException('Provided key is too short');
}
}
/**
* Validate RSA key length
*
* @param OpenSSLAsymmetricKey $key RSA key material
* @param string $algorithm The algorithm
* @throws DomainException Provided key is too short
*/
private static function validateEcKeyLength(
#[\SensitiveParameter] OpenSSLAsymmetricKey $key,
string $algorithm
): void {
if (!$keyDetails = openssl_pkey_get_details($key)) {
throw new DomainException('Unable to validate key');
}
$minKeyLength = (int) \str_replace('ES', '', $algorithm);
if ($keyDetails['bits'] < $minKeyLength) {
throw new DomainException('Provided key is too short');
}
}
}

View File

@@ -9,26 +9,20 @@ use TypeError;
class Key
{
/** @var string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate */
private $keyMaterial;
/** @var string */
private $algorithm;
/**
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial
* @param string $algorithm
*/
public function __construct(
$keyMaterial,
string $algorithm
#[\SensitiveParameter] private $keyMaterial,
private string $algorithm
) {
if (
!\is_string($keyMaterial)
&& !$keyMaterial instanceof OpenSSLAsymmetricKey
&& !$keyMaterial instanceof OpenSSLCertificate
&& !\is_resource($keyMaterial)
) {
throw new TypeError('Key material must be a string, resource, or OpenSSLAsymmetricKey');
throw new TypeError('Key material must be a string, OpenSSLCertificate, or OpenSSLAsymmetricKey');
}
if (empty($keyMaterial)) {
@@ -38,10 +32,6 @@ class Key
if (empty($algorithm)) {
throw new InvalidArgumentException('Algorithm must not be empty');
}
// TODO: Remove in PHP 8.0 in favor of class constructor property promotion
$this->keyMaterial = $keyMaterial;
$this->algorithm = $algorithm;
}
/**
@@ -55,7 +45,7 @@ class Key
}
/**
* @return string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate
* @return string|OpenSSLAsymmetricKey|OpenSSLCertificate
*/
public function getKeyMaterial()
{

View File

@@ -2,6 +2,56 @@
Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version.
## 7.10.0 - 2025-08-23
### Added
- Support for PHP 8.5
### Changed
- Adjusted `guzzlehttp/promises` version constraint to `^2.3`
- Adjusted `guzzlehttp/psr7` version constraint to `^2.8`
## 7.9.3 - 2025-03-27
### Changed
- Remove explicit content-length header for GET requests
- Improve compatibility with bad servers for boolean cookie values
## 7.9.2 - 2024-07-24
### Fixed
- Adjusted handler selection to use cURL if its version is 7.21.2 or higher, rather than 7.34.0
## 7.9.1 - 2024-07-19
### Fixed
- Fix TLS 1.3 check for HTTP/2 requests
## 7.9.0 - 2024-07-18
### Changed
- Improve protocol version checks to provide feedback around unsupported protocols
- Only select the cURL handler by default if 7.34.0 or higher is linked
- Improved `CurlMultiHandler` to avoid busy wait if possible
- Dropped support for EOL `guzzlehttp/psr7` v1
- Improved URI user info redaction in errors
## 7.8.2 - 2024-07-18
### Added
- Support for PHP 8.4
## 7.8.1 - 2023-12-03

View File

@@ -62,11 +62,11 @@ composer require guzzlehttp/guzzle
| Version | Status | Packagist | Namespace | Repo | Docs | PSR-7 | PHP Version |
|---------|---------------------|---------------------|--------------|---------------------|---------------------|-------|--------------|
| 3.x | EOL | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No | >=5.3.3,<7.0 |
| 4.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A | No | >=5.4,<7.0 |
| 5.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >=5.4,<7.4 |
| 6.x | Security fixes only | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes | >=5.5,<8.0 |
| 7.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes | >=7.2.5,<8.4 |
| 3.x | EOL (2016-10-31) | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No | >=5.3.3,<7.0 |
| 4.x | EOL (2016-10-31) | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A | No | >=5.4,<7.0 |
| 5.x | EOL (2019-10-31) | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >=5.4,<7.4 |
| 6.x | EOL (2023-10-31) | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes | >=5.5,<8.0 |
| 7.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes | >=7.2.5,<8.5 |
[guzzle-3-repo]: https://github.com/guzzle/guzzle3
[guzzle-4-repo]: https://github.com/guzzle/guzzle/tree/4.x

View File

@@ -50,11 +50,39 @@
"homepage": "https://github.com/Tobion"
}
],
"repositories": [
{
"type": "package",
"package": {
"name": "guzzle/client-integration-tests",
"version": "v3.0.2",
"dist": {
"url": "https://codeload.github.com/guzzle/client-integration-tests/zip/2c025848417c1135031fdf9c728ee53d0a7ceaee",
"type": "zip"
},
"require": {
"php": "^7.2.5 || ^8.0",
"phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.11",
"php-http/message": "^1.0 || ^2.0",
"guzzlehttp/psr7": "^1.7 || ^2.0",
"th3n3rd/cartesian-product": "^0.3"
},
"autoload": {
"psr-4": {
"Http\\Client\\Tests\\": "src/"
}
},
"bin": [
"bin/http_test_server"
]
}
}
],
"require": {
"php": "^7.2.5 || ^8.0",
"ext-json": "*",
"guzzlehttp/promises": "^1.5.3 || ^2.0.1",
"guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
"guzzlehttp/promises": "^2.3",
"guzzlehttp/psr7": "^2.8",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
},
@@ -64,9 +92,9 @@
"require-dev": {
"ext-curl": "*",
"bamarni/composer-bin-plugin": "^1.8.2",
"php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
"guzzle/client-integration-tests": "3.0.2",
"php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.36 || ^9.6.15",
"phpunit/phpunit": "^8.5.39 || ^9.6.20",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"suggest": {

View File

@@ -11,7 +11,7 @@ final class BodySummarizer implements BodySummarizerInterface
*/
private $truncateAt;
public function __construct(int $truncateAt = null)
public function __construct(?int $truncateAt = null)
{
$this->truncateAt = $truncateAt;
}
@@ -22,7 +22,7 @@ final class BodySummarizer implements BodySummarizerInterface
public function summarize(MessageInterface $message): ?string
{
return $this->truncateAt === null
? \GuzzleHttp\Psr7\Message::bodySummary($message)
: \GuzzleHttp\Psr7\Message::bodySummary($message, $this->truncateAt);
? Psr7\Message::bodySummary($message)
: Psr7\Message::bodySummary($message, $this->truncateAt);
}
}

View File

@@ -52,7 +52,7 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
*
* @param array $config Client configuration settings.
*
* @see \GuzzleHttp\RequestOptions for a list of available request options.
* @see RequestOptions for a list of available request options.
*/
public function __construct(array $config = [])
{
@@ -202,7 +202,7 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
*
* @deprecated Client::getConfig will be removed in guzzlehttp/guzzle:8.0.
*/
public function getConfig(string $option = null)
public function getConfig(?string $option = null)
{
return $option === null
? $this->config

View File

@@ -80,5 +80,5 @@ interface ClientInterface
*
* @deprecated ClientInterface::getConfig will be removed in guzzlehttp/guzzle:8.0.
*/
public function getConfig(string $option = null);
public function getConfig(?string $option = null);
}

View File

@@ -103,7 +103,7 @@ class CookieJar implements CookieJarInterface
}, $this->getIterator()->getArrayCopy());
}
public function clear(string $domain = null, string $path = null, string $name = null): void
public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void
{
if (!$domain) {
$this->cookies = [];

View File

@@ -62,7 +62,7 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
* @param string|null $path Clears cookies matching a domain and path
* @param string|null $name Clears cookies matching a domain, path, and name
*/
public function clear(string $domain = null, string $path = null, string $name = null): void;
public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void;
/**
* Discard all sessions cookies.

View File

@@ -62,6 +62,10 @@ class SetCookie
if (is_numeric($value)) {
$data[$search] = (int) $value;
}
} elseif ($search === 'Secure' || $search === 'Discard' || $search === 'HttpOnly') {
if ($value) {
$data[$search] = true;
}
} else {
$data[$search] = $value;
}

View File

@@ -14,7 +14,7 @@ class BadResponseException extends RequestException
string $message,
RequestInterface $request,
ResponseInterface $response,
\Throwable $previous = null,
?\Throwable $previous = null,
array $handlerContext = []
) {
parent::__construct($message, $request, $response, $previous, $handlerContext);

View File

@@ -25,7 +25,7 @@ class ConnectException extends TransferException implements NetworkExceptionInte
public function __construct(
string $message,
RequestInterface $request,
\Throwable $previous = null,
?\Throwable $previous = null,
array $handlerContext = []
) {
parent::__construct($message, 0, $previous);

View File

@@ -7,7 +7,6 @@ use GuzzleHttp\BodySummarizerInterface;
use Psr\Http\Client\RequestExceptionInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
/**
* HTTP Request exception
@@ -32,8 +31,8 @@ class RequestException extends TransferException implements RequestExceptionInte
public function __construct(
string $message,
RequestInterface $request,
ResponseInterface $response = null,
\Throwable $previous = null,
?ResponseInterface $response = null,
?\Throwable $previous = null,
array $handlerContext = []
) {
// Set the code of the exception if the response is set and not future.
@@ -63,10 +62,10 @@ class RequestException extends TransferException implements RequestExceptionInte
*/
public static function create(
RequestInterface $request,
ResponseInterface $response = null,
\Throwable $previous = null,
?ResponseInterface $response = null,
?\Throwable $previous = null,
array $handlerContext = [],
BodySummarizerInterface $bodySummarizer = null
?BodySummarizerInterface $bodySummarizer = null
): self {
if (!$response) {
return new self(
@@ -90,8 +89,7 @@ class RequestException extends TransferException implements RequestExceptionInte
$className = __CLASS__;
}
$uri = $request->getUri();
$uri = static::obfuscateUri($uri);
$uri = \GuzzleHttp\Psr7\Utils::redactUserInfo($request->getUri());
// Client Error: `GET /` resulted in a `404 Not Found` response:
// <html> ... (truncated)
@@ -113,20 +111,6 @@ class RequestException extends TransferException implements RequestExceptionInte
return new $className($message, $request, $response, $previous, $handlerContext);
}
/**
* Obfuscates URI if there is a username and a password present
*/
private static function obfuscateUri(UriInterface $uri): UriInterface
{
$userInfo = $uri->getUserInfo();
if (false !== ($pos = \strpos($userInfo, ':'))) {
return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***');
}
return $uri;
}
/**
* Get the request that caused the exception
*/

View File

@@ -11,6 +11,7 @@ use GuzzleHttp\Psr7\LazyOpenStream;
use GuzzleHttp\TransferStats;
use GuzzleHttp\Utils;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\UriInterface;
/**
* Creates curl resources from a request
@@ -46,6 +47,16 @@ class CurlFactory implements CurlFactoryInterface
public function create(RequestInterface $request, array $options): EasyHandle
{
$protocolVersion = $request->getProtocolVersion();
if ('2' === $protocolVersion || '2.0' === $protocolVersion) {
if (!self::supportsHttp2()) {
throw new ConnectException('HTTP/2 is supported by the cURL handler, however libcurl is built without HTTP/2 support.', $request);
}
} elseif ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {
throw new ConnectException(sprintf('HTTP/%s is not supported by the cURL handler.', $protocolVersion), $request);
}
if (isset($options['curl']['body_as_string'])) {
$options['_body_as_string'] = $options['curl']['body_as_string'];
unset($options['curl']['body_as_string']);
@@ -72,13 +83,51 @@ class CurlFactory implements CurlFactoryInterface
return $easy;
}
private static function supportsHttp2(): bool
{
static $supportsHttp2 = null;
if (null === $supportsHttp2) {
$supportsHttp2 = self::supportsTls12()
&& defined('CURL_VERSION_HTTP2')
&& (\CURL_VERSION_HTTP2 & \curl_version()['features']);
}
return $supportsHttp2;
}
private static function supportsTls12(): bool
{
static $supportsTls12 = null;
if (null === $supportsTls12) {
$supportsTls12 = \CURL_SSLVERSION_TLSv1_2 & \curl_version()['features'];
}
return $supportsTls12;
}
private static function supportsTls13(): bool
{
static $supportsTls13 = null;
if (null === $supportsTls13) {
$supportsTls13 = defined('CURL_SSLVERSION_TLSv1_3')
&& (\CURL_SSLVERSION_TLSv1_3 & \curl_version()['features']);
}
return $supportsTls13;
}
public function release(EasyHandle $easy): void
{
$resource = $easy->handle;
unset($easy->handle);
if (\count($this->handles) >= $this->maxHandles) {
\curl_close($resource);
if (PHP_VERSION_ID < 80000) {
\curl_close($resource);
}
} else {
// Remove all callback functions as they can hold onto references
// and are not cleaned up by curl_reset. Using curl_setopt_array
@@ -147,7 +196,7 @@ class CurlFactory implements CurlFactoryInterface
'error' => \curl_error($easy->handle),
'appconnect_time' => \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME),
] + \curl_getinfo($easy->handle);
$ctx[self::CURL_VERSION_STR] = \curl_version()['version'];
$ctx[self::CURL_VERSION_STR] = self::getCurlVersion();
$factory->release($easy);
// Retry when nothing is present or when curl failed to rewind.
@@ -158,6 +207,17 @@ class CurlFactory implements CurlFactoryInterface
return self::createRejection($easy, $ctx);
}
private static function getCurlVersion(): string
{
static $curlVersion = null;
if (null === $curlVersion) {
$curlVersion = \curl_version()['version'];
}
return $curlVersion;
}
private static function createRejection(EasyHandle $easy, array $ctx): PromiseInterface
{
static $connectionErrors = [
@@ -194,15 +254,22 @@ class CurlFactory implements CurlFactoryInterface
);
}
$uri = $easy->request->getUri();
$sanitizedError = self::sanitizeCurlError($ctx['error'] ?? '', $uri);
$message = \sprintf(
'cURL error %s: %s (%s)',
$ctx['errno'],
$ctx['error'],
$sanitizedError,
'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'
);
$uriString = (string) $easy->request->getUri();
if ($uriString !== '' && false === \strpos($ctx['error'], $uriString)) {
$message .= \sprintf(' for %s', $uriString);
if ('' !== $sanitizedError) {
$redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($uri)->__toString();
if ($redactedUriString !== '' && false === \strpos($sanitizedError, $redactedUriString)) {
$message .= \sprintf(' for %s', $redactedUriString);
}
}
// Create a connection exception if it was a specific error code.
@@ -213,6 +280,24 @@ class CurlFactory implements CurlFactoryInterface
return P\Create::rejectionFor($error);
}
private static function sanitizeCurlError(string $error, UriInterface $uri): string
{
if ('' === $error) {
return $error;
}
$baseUri = $uri->withQuery('')->withFragment('');
$baseUriString = $baseUri->__toString();
if ('' === $baseUriString) {
return $error;
}
$redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($baseUri)->__toString();
return str_replace($baseUriString, $redactedUriString, $error);
}
/**
* @return array<int|string, mixed>
*/
@@ -232,10 +317,11 @@ class CurlFactory implements CurlFactoryInterface
}
$version = $easy->request->getProtocolVersion();
if ($version == 1.1) {
$conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1;
} elseif ($version == 2.0) {
if ('2' === $version || '2.0' === $version) {
$conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_2_0;
} elseif ('1.1' === $version) {
$conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1;
} else {
$conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_0;
}
@@ -390,8 +476,10 @@ class CurlFactory implements CurlFactoryInterface
// The empty string enables all available decoders and implicitly
// sets a matching 'Accept-Encoding' header.
$conf[\CURLOPT_ENCODING] = '';
// But as the user did not specify any acceptable encodings we need
// to overwrite this implicit header with an empty one.
// But as the user did not specify any encoding preference,
// let's leave it up to server by preventing curl from sending
// the header, which will be interpreted as 'Accept-Encoding: *'.
// https://www.rfc-editor.org/rfc/rfc9110#field.accept-encoding
$conf[\CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
}
}
@@ -455,23 +543,35 @@ class CurlFactory implements CurlFactoryInterface
}
if (isset($options['crypto_method'])) {
if (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']) {
if (!defined('CURL_SSLVERSION_TLSv1_0')) {
throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.0 not supported by your version of cURL');
$protocolVersion = $easy->request->getProtocolVersion();
// If HTTP/2, upgrade TLS 1.0 and 1.1 to 1.2
if ('2' === $protocolVersion || '2.0' === $protocolVersion) {
if (
\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']
|| \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method']
|| \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']
) {
$conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2;
} elseif (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) {
if (!self::supportsTls13()) {
throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL');
}
$conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3;
} else {
throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided');
}
} elseif (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']) {
$conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_0;
} elseif (\STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method']) {
if (!defined('CURL_SSLVERSION_TLSv1_1')) {
throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.1 not supported by your version of cURL');
}
$conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_1;
} elseif (\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']) {
if (!defined('CURL_SSLVERSION_TLSv1_2')) {
if (!self::supportsTls12()) {
throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.2 not supported by your version of cURL');
}
$conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2;
} elseif (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) {
if (!defined('CURL_SSLVERSION_TLSv1_3')) {
if (!self::supportsTls13()) {
throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL');
}
$conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3;
@@ -631,7 +731,10 @@ class CurlFactory implements CurlFactoryInterface
public function __destruct()
{
foreach ($this->handles as $id => $handle) {
\curl_close($handle);
if (PHP_VERSION_ID < 80000) {
\curl_close($handle);
}
unset($this->handles[$id]);
}
}

View File

@@ -2,6 +2,7 @@
namespace GuzzleHttp\Handler;
use Closure;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\PromiseInterface;
@@ -159,6 +160,9 @@ class CurlMultiHandler
}
}
// Run curl_multi_exec in the queue to enable other async tasks to run
P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue']));
// Step through the task queue which may add additional requests.
P\Utils::queue()->run();
@@ -169,11 +173,24 @@ class CurlMultiHandler
}
while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
// Prevent busy looping for slow HTTP requests.
\curl_multi_select($this->_mh, $this->selectTimeout);
}
$this->processMessages();
}
/**
* Runs \curl_multi_exec() inside the event loop, to prevent busy looping
*/
private function tickInQueue(): void
{
if (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
\curl_multi_select($this->_mh, 0);
P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue']));
}
}
/**
* Runs until all outstanding connections have completed.
*/
@@ -223,7 +240,10 @@ class CurlMultiHandler
$handle = $this->handles[$id]['easy']->handle;
unset($this->delays[$id], $this->handles[$id]);
\curl_multi_remove_handle($this->_mh, $handle);
\curl_close($handle);
if (PHP_VERSION_ID < 80000) {
\curl_close($handle);
}
return true;
}

View File

@@ -52,21 +52,21 @@ class MockHandler implements \Countable
* @param callable|null $onFulfilled Callback to invoke when the return value is fulfilled.
* @param callable|null $onRejected Callback to invoke when the return value is rejected.
*/
public static function createWithMiddleware(array $queue = null, callable $onFulfilled = null, callable $onRejected = null): HandlerStack
public static function createWithMiddleware(?array $queue = null, ?callable $onFulfilled = null, ?callable $onRejected = null): HandlerStack
{
return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
}
/**
* The passed in value must be an array of
* {@see \Psr\Http\Message\ResponseInterface} objects, Exceptions,
* {@see ResponseInterface} objects, Exceptions,
* callables, or Promises.
*
* @param array<int, mixed>|null $queue The parameters to be passed to the append function, as an indexed array.
* @param callable|null $onFulfilled Callback to invoke when the return value is fulfilled.
* @param callable|null $onRejected Callback to invoke when the return value is rejected.
*/
public function __construct(array $queue = null, callable $onFulfilled = null, callable $onRejected = null)
public function __construct(?array $queue = null, ?callable $onFulfilled = null, ?callable $onRejected = null)
{
$this->onFulfilled = $onFulfilled;
$this->onRejected = $onRejected;
@@ -200,7 +200,7 @@ class MockHandler implements \Countable
private function invokeStats(
RequestInterface $request,
array $options,
ResponseInterface $response = null,
?ResponseInterface $response = null,
$reason = null
): void {
if (isset($options['on_stats'])) {

View File

@@ -17,10 +17,10 @@ class Proxy
* Sends synchronous requests to a specific handler while sending all other
* requests to another handler.
*
* @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default Handler used for normal responses
* @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $sync Handler used for synchronous responses.
* @param callable(RequestInterface, array): PromiseInterface $default Handler used for normal responses
* @param callable(RequestInterface, array): PromiseInterface $sync Handler used for synchronous responses.
*
* @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler.
* @return callable(RequestInterface, array): PromiseInterface Returns the composed handler.
*/
public static function wrapSync(callable $default, callable $sync): callable
{
@@ -37,10 +37,10 @@ class Proxy
* performance benefits of curl while still supporting true streaming
* through the StreamHandler.
*
* @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default Handler used for non-streaming responses
* @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $streaming Handler used for streaming responses
* @param callable(RequestInterface, array): PromiseInterface $default Handler used for non-streaming responses
* @param callable(RequestInterface, array): PromiseInterface $streaming Handler used for streaming responses
*
* @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler.
* @return callable(RequestInterface, array): PromiseInterface Returns the composed handler.
*/
public static function wrapStreaming(callable $default, callable $streaming): callable
{

View File

@@ -40,6 +40,12 @@ class StreamHandler
\usleep($options['delay'] * 1000);
}
$protocolVersion = $request->getProtocolVersion();
if ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {
throw new ConnectException(sprintf('HTTP/%s is not supported by the stream handler.', $protocolVersion), $request);
}
$startTime = isset($options['on_stats']) ? Utils::currentTime() : null;
try {
@@ -47,8 +53,14 @@ class StreamHandler
$request = $request->withoutHeader('Expect');
// Append a content-length header if body size is zero to match
// cURL's behavior.
if (0 === $request->getBody()->getSize()) {
// the behavior of `CurlHandler`
if (
(
0 === \strcasecmp('PUT', $request->getMethod())
|| 0 === \strcasecmp('POST', $request->getMethod())
)
&& 0 === $request->getBody()->getSize()
) {
$request = $request->withHeader('Content-Length', '0');
}
@@ -83,8 +95,8 @@ class StreamHandler
array $options,
RequestInterface $request,
?float $startTime,
ResponseInterface $response = null,
\Throwable $error = null
?ResponseInterface $response = null,
?\Throwable $error = null
): void {
if (isset($options['on_stats'])) {
$stats = new TransferStats($request, $response, Utils::currentTime() - $startTime, $error, []);
@@ -273,7 +285,7 @@ class StreamHandler
// HTTP/1.1 streams using the PHP stream wrapper require a
// Connection: close header
if ($request->getProtocolVersion() == '1.1'
if ($request->getProtocolVersion() === '1.1'
&& !$request->hasHeader('Connection')
) {
$request = $request->withHeader('Connection', 'close');
@@ -321,8 +333,15 @@ class StreamHandler
);
return $this->createResource(
function () use ($uri, &$http_response_header, $contextResource, $context, $options, $request) {
function () use ($uri, $contextResource, $context, $options, $request) {
$resource = @\fopen((string) $uri, 'r', false, $contextResource);
// See https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_the_http_response_header_predefined_variable
if (function_exists('http_get_last_response_headers')) {
/** @var array|null */
$http_response_header = \http_get_last_response_headers();
}
$this->lastHeaders = $http_response_header ?? [];
if (false === $resource) {

View File

@@ -44,7 +44,7 @@ class HandlerStack
* handler is provided, the best handler for your
* system will be utilized.
*/
public static function create(callable $handler = null): self
public static function create(?callable $handler = null): self
{
$stack = new self($handler ?: Utils::chooseHandler());
$stack->push(Middleware::httpErrors(), 'http_errors');
@@ -58,7 +58,7 @@ class HandlerStack
/**
* @param (callable(RequestInterface, array): PromiseInterface)|null $handler Underlying HTTP handler.
*/
public function __construct(callable $handler = null)
public function __construct(?callable $handler = null)
{
$this->handler = $handler;
}
@@ -131,7 +131,7 @@ class HandlerStack
* @param callable(callable): callable $middleware Middleware function
* @param string $name Name to register for this middleware.
*/
public function unshift(callable $middleware, string $name = null): void
public function unshift(callable $middleware, ?string $name = null): void
{
\array_unshift($this->stack, [$middleware, $name]);
$this->cached = null;

View File

@@ -68,7 +68,7 @@ class MessageFormatter implements MessageFormatterInterface
* @param ResponseInterface|null $response Response that was received
* @param \Throwable|null $error Exception that was received
*/
public function format(RequestInterface $request, ResponseInterface $response = null, \Throwable $error = null): string
public function format(RequestInterface $request, ?ResponseInterface $response = null, ?\Throwable $error = null): string
{
$cache = [];

View File

@@ -14,5 +14,5 @@ interface MessageFormatterInterface
* @param ResponseInterface|null $response Response that was received
* @param \Throwable|null $error Exception that was received
*/
public function format(RequestInterface $request, ResponseInterface $response = null, \Throwable $error = null): string;
public function format(RequestInterface $request, ?ResponseInterface $response = null, ?\Throwable $error = null): string;
}

View File

@@ -55,7 +55,7 @@ final class Middleware
*
* @return callable(callable): callable Returns a function that accepts the next handler.
*/
public static function httpErrors(BodySummarizerInterface $bodySummarizer = null): callable
public static function httpErrors(?BodySummarizerInterface $bodySummarizer = null): callable
{
return static function (callable $handler) use ($bodySummarizer): callable {
return static function ($request, array $options) use ($handler, $bodySummarizer) {
@@ -132,7 +132,7 @@ final class Middleware
*
* @return callable Returns a function that accepts the next handler.
*/
public static function tap(callable $before = null, callable $after = null): callable
public static function tap(?callable $before = null, ?callable $after = null): callable
{
return static function (callable $handler) use ($before, $after): callable {
return static function (RequestInterface $request, array $options) use ($handler, $before, $after) {
@@ -176,7 +176,7 @@ final class Middleware
*
* @return callable Returns a function that accepts the next handler.
*/
public static function retry(callable $decider, callable $delay = null): callable
public static function retry(callable $decider, ?callable $delay = null): callable
{
return static function (callable $handler) use ($decider, $delay): RetryMiddleware {
return new RetryMiddleware($decider, $handler, $delay);
@@ -187,12 +187,12 @@ final class Middleware
* Middleware that logs requests, responses, and errors using a message
* formatter.
*
* @phpstan-param \Psr\Log\LogLevel::* $logLevel Level at which to log requests.
*
* @param LoggerInterface $logger Logs messages.
* @param MessageFormatterInterface|MessageFormatter $formatter Formatter used to create message strings.
* @param string $logLevel Level at which to log requests.
*
* @phpstan-param \Psr\Log\LogLevel::* $logLevel Level at which to log requests.
*
* @return callable Returns a function that accepts the next handler.
*/
public static function log(LoggerInterface $logger, $formatter, string $logLevel = 'info'): callable

View File

@@ -86,7 +86,7 @@ class Pool implements PromisorInterface
* @param ClientInterface $client Client used to send the requests
* @param array|\Iterator $requests Requests to send concurrently.
* @param array $options Passes through the options available in
* {@see \GuzzleHttp\Pool::__construct}
* {@see Pool::__construct}
*
* @return array Returns an array containing the response or an exception
* in the same order that the requests were sent.

View File

@@ -76,8 +76,8 @@ class PrepareBodyMiddleware
$expect = $options['expect'] ?? null;
// Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0
if ($expect === false || $request->getProtocolVersion() < 1.1) {
// Return if disabled or using HTTP/1.0
if ($expect === false || $request->getProtocolVersion() === '1.0') {
return;
}

View File

@@ -61,7 +61,7 @@ final class RequestOptions
* Specifies whether or not cookies are used in a request or what cookie
* jar to use or what cookies to send. This option only works if your
* handler has the `cookie` middleware. Valid values are `false` and
* an instance of {@see \GuzzleHttp\Cookie\CookieJarInterface}.
* an instance of {@see Cookie\CookieJarInterface}.
*/
public const COOKIES = 'cookies';

View File

@@ -40,7 +40,7 @@ class RetryMiddleware
* and returns the number of
* milliseconds to delay.
*/
public function __construct(callable $decider, callable $nextHandler, callable $delay = null)
public function __construct(callable $decider, callable $nextHandler, ?callable $delay = null)
{
$this->decider = $decider;
$this->nextHandler = $nextHandler;
@@ -110,7 +110,7 @@ class RetryMiddleware
};
}
private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null): PromiseInterface
private function doRetry(RequestInterface $request, array $options, ?ResponseInterface $response = null): PromiseInterface
{
$options['delay'] = ($this->delay)(++$options['retries'], $response, $request);

View File

@@ -46,8 +46,8 @@ final class TransferStats
*/
public function __construct(
RequestInterface $request,
ResponseInterface $response = null,
float $transferTime = null,
?ResponseInterface $response = null,
?float $transferTime = null,
$handlerErrorData = null,
array $handlerStats = []
) {

View File

@@ -71,7 +71,7 @@ final class Utils
return \STDOUT;
}
return \GuzzleHttp\Psr7\Utils::tryFopen('php://output', 'w');
return Psr7\Utils::tryFopen('php://output', 'w');
}
/**
@@ -79,7 +79,7 @@ final class Utils
*
* The returned handler is not wrapped by any default middlewares.
*
* @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the best handler for the given system.
* @return callable(\Psr\Http\Message\RequestInterface, array): Promise\PromiseInterface Returns the best handler for the given system.
*
* @throws \RuntimeException if no viable Handler is available.
*/
@@ -87,7 +87,7 @@ final class Utils
{
$handler = null;
if (\defined('CURLOPT_CUSTOMREQUEST')) {
if (\defined('CURLOPT_CUSTOMREQUEST') && \function_exists('curl_version') && version_compare(curl_version()['version'], '7.21.2') >= 0) {
if (\function_exists('curl_multi_exec') && \function_exists('curl_exec')) {
$handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
} elseif (\function_exists('curl_exec')) {

View File

@@ -50,7 +50,7 @@ function debug_resource($value = null)
*
* The returned handler is not wrapped by any default middlewares.
*
* @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the best handler for the given system.
* @return callable(\Psr\Http\Message\RequestInterface, array): Promise\PromiseInterface Returns the best handler for the given system.
*
* @throws \RuntimeException if no viable Handler is available.
*

View File

@@ -1,6 +1,41 @@
# CHANGELOG
## 2.3.0 - 2025-08-22
### Added
- PHP 8.5 support
## 2.2.0 - 2025-03-27
### Fixed
- Revert "Allow an empty EachPromise to be resolved by running the queue"
## 2.1.0 - 2025-03-27
### Added
- Allow an empty EachPromise to be resolved by running the queue
## 2.0.4 - 2024-10-17
### Fixed
- Once settled, don't allow further rejection of additional promises
## 2.0.3 - 2024-07-18
### Changed
- PHP 8.4 support
## 2.0.2 - 2023-12-03
### Changed

View File

@@ -38,10 +38,10 @@ composer require guzzlehttp/promises
## Version Guidance
| Version | Status | PHP Version |
|---------|------------------------|--------------|
| 1.x | Bug and security fixes | >=5.5,<8.3 |
| 2.x | Latest | >=7.2.5,<8.4 |
| Version | Status | PHP Version |
|---------|---------------------|--------------|
| 1.x | Security fixes only | >=5.5,<8.3 |
| 2.x | Latest | >=7.2.5,<8.6 |
## Quick Start

View File

@@ -30,7 +30,7 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.36 || ^9.6.15"
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"autoload": {
"psr-4": {

View File

@@ -84,8 +84,8 @@ final class Coroutine implements PromiseInterface
}
public function then(
callable $onFulfilled = null,
callable $onRejected = null
?callable $onFulfilled = null,
?callable $onRejected = null
): PromiseInterface {
return $this->result->then($onFulfilled, $onRejected);
}

View File

@@ -23,8 +23,8 @@ final class Each
*/
public static function of(
$iterable,
callable $onFulfilled = null,
callable $onRejected = null
?callable $onFulfilled = null,
?callable $onRejected = null
): PromiseInterface {
return (new EachPromise($iterable, [
'fulfilled' => $onFulfilled,
@@ -46,8 +46,8 @@ final class Each
public static function ofLimit(
$iterable,
$concurrency,
callable $onFulfilled = null,
callable $onRejected = null
?callable $onFulfilled = null,
?callable $onRejected = null
): PromiseInterface {
return (new EachPromise($iterable, [
'fulfilled' => $onFulfilled,
@@ -67,7 +67,7 @@ final class Each
public static function ofLimitAll(
$iterable,
$concurrency,
callable $onFulfilled = null
?callable $onFulfilled = null
): PromiseInterface {
return self::ofLimit(
$iterable,

View File

@@ -31,8 +31,8 @@ class FulfilledPromise implements PromiseInterface
}
public function then(
callable $onFulfilled = null,
callable $onRejected = null
?callable $onFulfilled = null,
?callable $onRejected = null
): PromiseInterface {
// Return itself if there is no onFulfilled function.
if (!$onFulfilled) {

View File

@@ -25,16 +25,16 @@ class Promise implements PromiseInterface
* @param callable $cancelFn Fn that when invoked cancels the promise.
*/
public function __construct(
callable $waitFn = null,
callable $cancelFn = null
?callable $waitFn = null,
?callable $cancelFn = null
) {
$this->waitFn = $waitFn;
$this->cancelFn = $cancelFn;
}
public function then(
callable $onFulfilled = null,
callable $onRejected = null
?callable $onFulfilled = null,
?callable $onRejected = null
): PromiseInterface {
if ($this->state === self::PENDING) {
$p = new Promise(null, [$this, 'cancel']);

View File

@@ -27,8 +27,8 @@ interface PromiseInterface
* @param callable $onRejected Invoked when the promise is rejected.
*/
public function then(
callable $onFulfilled = null,
callable $onRejected = null
?callable $onFulfilled = null,
?callable $onRejected = null
): PromiseInterface;
/**

View File

@@ -31,8 +31,8 @@ class RejectedPromise implements PromiseInterface
}
public function then(
callable $onFulfilled = null,
callable $onRejected = null
?callable $onFulfilled = null,
?callable $onRejected = null
): PromiseInterface {
// If there's no onRejected callback then just return self.
if (!$onRejected) {

View File

@@ -18,7 +18,7 @@ class RejectionException extends \RuntimeException
* @param mixed $reason Rejection reason.
* @param string|null $description Optional description.
*/
public function __construct($reason, string $description = null)
public function __construct($reason, ?string $description = null)
{
$this->reason = $reason;

View File

@@ -21,7 +21,7 @@ final class Utils
*
* @param TaskQueueInterface|null $assign Optionally specify a new queue instance.
*/
public static function queue(TaskQueueInterface $assign = null): TaskQueueInterface
public static function queue(?TaskQueueInterface $assign = null): TaskQueueInterface
{
static $queue;
@@ -144,7 +144,9 @@ final class Utils
$results[$idx] = $value;
},
function ($reason, $idx, Promise $aggregate): void {
$aggregate->reject($reason);
if (Is::pending($aggregate)) {
$aggregate->reject($reason);
}
}
)->then(function () use (&$results) {
ksort($results);

View File

@@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 2.8.0 - 2025-08-23
### Added
- Allow empty lists as header values
### Changed
- PHP 8.5 support
## 2.7.1 - 2025-03-27
### Fixed
- Fixed uppercase IPv6 addresses in URI
### Changed
- Improve uploaded file error message
## 2.7.0 - 2024-07-18
### Added
- Add `Utils::redactUserInfo()` method
- Add ability to encode bools as ints in `Query::build`
## 2.6.3 - 2024-07-18
### Fixed
- Make `StreamWrapper::stream_stat()` return `false` if inner stream's size is `null`
### Changed
- PHP 8.4 support
## 2.6.2 - 2023-12-03
### Fixed

View File

@@ -24,8 +24,8 @@ composer require guzzlehttp/psr7
| Version | Status | PHP Version |
|---------|---------------------|--------------|
| 1.x | Security fixes only | >=5.4,<8.1 |
| 2.x | Latest | >=7.2.5,<8.4 |
| 1.x | EOL (2024-06-30) | >=5.4,<8.2 |
| 2.x | Latest | >=7.2.5,<8.6 |
## AppendStream
@@ -436,7 +436,7 @@ will be parsed into `['foo[a]' => '1', 'foo[b]' => '2'])`.
## `GuzzleHttp\Psr7\Query::build`
`public static function build(array $params, int|false $encoding = PHP_QUERY_RFC3986): string`
`public static function build(array $params, int|false $encoding = PHP_QUERY_RFC3986, bool $treatBoolsAsInts = true): string`
Build a query string from an array of key value pairs.
@@ -498,11 +498,18 @@ a message.
## `GuzzleHttp\Psr7\Utils::readLine`
`public static function readLine(StreamInterface $stream, int $maxLength = null): string`
`public static function readLine(StreamInterface $stream, ?int $maxLength = null): string`
Read a line from the stream up to the maximum allowed buffer length.
## `GuzzleHttp\Psr7\Utils::redactUserInfo`
`public static function redactUserInfo(UriInterface $uri): UriInterface`
Redact the password in the user info part of a URI.
## `GuzzleHttp\Psr7\Utils::streamFor`
`public static function streamFor(resource|string|null|int|float|bool|StreamInterface|callable|\Iterator $resource = '', array $options = []): StreamInterface`
@@ -674,7 +681,7 @@ termed a relative-path reference.
### `GuzzleHttp\Psr7\Uri::isSameDocumentReference`
`public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool`
`public static function isSameDocumentReference(UriInterface $uri, ?UriInterface $base = null): bool`
Whether the URI is a same-document reference. A same-document reference refers to a URI that is, aside from its
fragment component, identical to the base URI. When no base URI is given, only an empty URI reference

View File

@@ -61,8 +61,8 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "^0.9",
"phpunit/phpunit": "^8.5.36 || ^9.6.15"
"http-interop/http-factory-tests": "0.9.0",
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"

View File

@@ -33,7 +33,7 @@ final class CachingStream implements StreamInterface
*/
public function __construct(
StreamInterface $stream,
StreamInterface $target = null
?StreamInterface $target = null
) {
$this->remoteStream = $stream;
$this->stream = $target ?: new Stream(Utils::tryFopen('php://temp', 'r+'));

View File

@@ -27,10 +27,10 @@ final class HttpFactory implements RequestFactoryInterface, ResponseFactoryInter
{
public function createUploadedFile(
StreamInterface $stream,
int $size = null,
?int $size = null,
int $error = \UPLOAD_ERR_OK,
string $clientFilename = null,
string $clientMediaType = null
?string $clientFilename = null,
?string $clientMediaType = null
): UploadedFileInterface {
if ($size === null) {
$size = $stream->getSize();

View File

@@ -174,10 +174,6 @@ trait MessageTrait
return $this->trimAndValidateHeaderValues([$value]);
}
if (count($value) === 0) {
throw new \InvalidArgumentException('Header value can not be an empty array.');
}
return $this->trimAndValidateHeaderValues($value);
}

View File

@@ -32,7 +32,7 @@ final class MultipartStream implements StreamInterface
*
* @throws \InvalidArgumentException
*/
public function __construct(array $elements = [], string $boundary = null)
public function __construct(array $elements = [], ?string $boundary = null)
{
$this->boundary = $boundary ?: bin2hex(random_bytes(20));
$this->stream = $this->createStream($elements);

View File

@@ -63,12 +63,15 @@ final class Query
* string. This function does not modify the provided keys when an array is
* encountered (like `http_build_query()` would).
*
* @param array $params Query string parameters.
* @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
* to encode using RFC3986, or PHP_QUERY_RFC1738
* to encode using RFC1738.
* @param array $params Query string parameters.
* @param int|false $encoding Set to false to not encode,
* PHP_QUERY_RFC3986 to encode using
* RFC3986, or PHP_QUERY_RFC1738 to
* encode using RFC1738.
* @param bool $treatBoolsAsInts Set to true to encode as 0/1, and
* false as false/true.
*/
public static function build(array $params, $encoding = PHP_QUERY_RFC3986): string
public static function build(array $params, $encoding = PHP_QUERY_RFC3986, bool $treatBoolsAsInts = true): string
{
if (!$params) {
return '';
@@ -86,12 +89,14 @@ final class Query
throw new \InvalidArgumentException('Invalid type');
}
$castBool = $treatBoolsAsInts ? static function ($v) { return (int) $v; } : static function ($v) { return $v ? 'true' : 'false'; };
$qs = '';
foreach ($params as $k => $v) {
$k = $encoder((string) $k);
if (!is_array($v)) {
$qs .= $k;
$v = is_bool($v) ? (int) $v : $v;
$v = is_bool($v) ? $castBool($v) : $v;
if ($v !== null) {
$qs .= '='.$encoder((string) $v);
}
@@ -99,7 +104,7 @@ final class Query
} else {
foreach ($v as $vv) {
$qs .= $k;
$vv = is_bool($vv) ? (int) $vv : $vv;
$vv = is_bool($vv) ? $castBool($vv) : $vv;
if ($vv !== null) {
$qs .= '='.$encoder((string) $vv);
}

View File

@@ -96,7 +96,7 @@ class Response implements ResponseInterface
array $headers = [],
$body = null,
string $version = '1.1',
string $reason = null
?string $reason = null
) {
$this->assertStatusCodeRange($status);

View File

@@ -69,7 +69,7 @@ final class StreamWrapper
}
}
public function stream_open(string $path, string $mode, int $options, string &$opened_path = null): bool
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path = null): bool
{
$options = stream_context_get_options($this->context);
@@ -136,10 +136,14 @@ final class StreamWrapper
* ctime: int,
* blksize: int,
* blocks: int
* }
* }|false
*/
public function stream_stat(): array
public function stream_stat()
{
if ($this->stream->getSize() === null) {
return false;
}
static $modeMap = [
'r' => 33060,
'rb' => 33060,

View File

@@ -11,15 +11,15 @@ use RuntimeException;
class UploadedFile implements UploadedFileInterface
{
private const ERRORS = [
UPLOAD_ERR_OK,
UPLOAD_ERR_INI_SIZE,
UPLOAD_ERR_FORM_SIZE,
UPLOAD_ERR_PARTIAL,
UPLOAD_ERR_NO_FILE,
UPLOAD_ERR_NO_TMP_DIR,
UPLOAD_ERR_CANT_WRITE,
UPLOAD_ERR_EXTENSION,
private const ERROR_MAP = [
UPLOAD_ERR_OK => 'UPLOAD_ERR_OK',
UPLOAD_ERR_INI_SIZE => 'UPLOAD_ERR_INI_SIZE',
UPLOAD_ERR_FORM_SIZE => 'UPLOAD_ERR_FORM_SIZE',
UPLOAD_ERR_PARTIAL => 'UPLOAD_ERR_PARTIAL',
UPLOAD_ERR_NO_FILE => 'UPLOAD_ERR_NO_FILE',
UPLOAD_ERR_NO_TMP_DIR => 'UPLOAD_ERR_NO_TMP_DIR',
UPLOAD_ERR_CANT_WRITE => 'UPLOAD_ERR_CANT_WRITE',
UPLOAD_ERR_EXTENSION => 'UPLOAD_ERR_EXTENSION',
];
/**
@@ -64,8 +64,8 @@ class UploadedFile implements UploadedFileInterface
$streamOrFile,
?int $size,
int $errorStatus,
string $clientFilename = null,
string $clientMediaType = null
?string $clientFilename = null,
?string $clientMediaType = null
) {
$this->setError($errorStatus);
$this->size = $size;
@@ -104,7 +104,7 @@ class UploadedFile implements UploadedFileInterface
*/
private function setError(int $error): void
{
if (false === in_array($error, UploadedFile::ERRORS, true)) {
if (!isset(UploadedFile::ERROR_MAP[$error])) {
throw new InvalidArgumentException(
'Invalid error status for UploadedFile'
);
@@ -137,7 +137,7 @@ class UploadedFile implements UploadedFileInterface
private function validateActive(): void
{
if (false === $this->isOk()) {
throw new RuntimeException('Cannot retrieve stream due to upload error');
throw new RuntimeException(\sprintf('Cannot retrieve stream due to upload error (%s)', self::ERROR_MAP[$this->error]));
}
if ($this->isMoved()) {

View File

@@ -107,7 +107,7 @@ class Uri implements UriInterface, \JsonSerializable
{
// If IPv6
$prefix = '';
if (preg_match('%^(.*://\[[0-9:a-f]+\])(.*?)$%', $url, $matches)) {
if (preg_match('%^(.*://\[[0-9:a-fA-F]+\])(.*?)$%', $url, $matches)) {
/** @var array{0:string, 1:string, 2:string} $matches */
$prefix = $matches[1];
$url = $matches[2];
@@ -279,7 +279,7 @@ class Uri implements UriInterface, \JsonSerializable
*
* @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.4
*/
public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool
public static function isSameDocumentReference(UriInterface $uri, ?UriInterface $base = null): bool
{
if ($base !== null) {
$uri = UriResolver::resolve($base, $uri);

View File

@@ -231,7 +231,7 @@ final class Utils
* @param StreamInterface $stream Stream to read from
* @param int|null $maxLength Maximum buffer length
*/
public static function readLine(StreamInterface $stream, int $maxLength = null): string
public static function readLine(StreamInterface $stream, ?int $maxLength = null): string
{
$buffer = '';
$size = 0;
@@ -250,6 +250,20 @@ final class Utils
return $buffer;
}
/**
* Redact the password in the user info part of a URI.
*/
public static function redactUserInfo(UriInterface $uri): UriInterface
{
$userInfo = $uri->getUserInfo();
if (false !== ($pos = \strpos($userInfo, ':'))) {
return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***');
}
return $uri;
}
/**
* Create a new stream based on the input type.
*
@@ -383,7 +397,7 @@ final class Utils
restore_error_handler();
if ($ex) {
/** @var $ex \RuntimeException */
/** @var \RuntimeException $ex */
throw $ex;
}
@@ -430,7 +444,7 @@ final class Utils
restore_error_handler();
if ($ex) {
/** @var $ex \RuntimeException */
/** @var \RuntimeException $ex */
throw $ex;
}

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2013-2020 Alex Bilbie <hello@alexbilbie.com>
Copyright (c) 2013-2023 Alex Bilbie <hello@alexbilbie.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -24,14 +24,16 @@ This package is compliant with [PSR-1][], [PSR-2][], [PSR-4][], and [PSR-7][]. I
We support the following versions of PHP:
* PHP 8.5
* PHP 8.4
* PHP 8.3
* PHP 8.2
* PHP 8.1
* PHP 8.0
* PHP 7.4
* PHP 7.3
* PHP 7.2
* PHP 7.1
* PHP 7.0
* PHP 5.6
## Provider Clients

View File

@@ -6,15 +6,15 @@
"sort-packages": true
},
"require": {
"php": "^5.6 || ^7.0 || ^8.0",
"guzzlehttp/guzzle": "^6.0 || ^7.0",
"paragonie/random_compat": "^1 || ^2 || ^9.99"
"php": "^7.1 || >=8.0.0 <8.6.0",
"ext-json": "*",
"guzzlehttp/guzzle": "^6.5.8 || ^7.4.5"
},
"require-dev": {
"mockery/mockery": "^1.3.5",
"php-parallel-lint/php-parallel-lint": "^1.3.1",
"phpunit/phpunit": "^5.7 || ^6.0 || ^9.5",
"squizlabs/php_codesniffer": "^2.3 || ^3.0"
"php-parallel-lint/php-parallel-lint": "^1.4",
"phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11",
"squizlabs/php_codesniffer": "^3.11"
},
"keywords": [
"oauth",
@@ -49,10 +49,5 @@
"psr-4": {
"League\\OAuth2\\Client\\Test\\": "test/src/"
}
},
"extra": {
"branch-alias": {
"dev-2.x": "2.0.x-dev"
}
}
}

View File

@@ -17,6 +17,7 @@ namespace League\OAuth2\Client\Provider;
use GuzzleHttp\Client as HttpClient;
use GuzzleHttp\ClientInterface as HttpClientInterface;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Exception\GuzzleException;
use InvalidArgumentException;
use League\OAuth2\Client\Grant\AbstractGrant;
use League\OAuth2\Client\Grant\GrantFactory;
@@ -405,6 +406,7 @@ abstract class AbstractProvider
*
* @param array $options
* @return array Authorization parameters
* @throws InvalidArgumentException
*/
protected function getAuthorizationParameters(array $options)
{
@@ -476,6 +478,7 @@ abstract class AbstractProvider
*
* @param array $options
* @return string Authorization URL
* @throws InvalidArgumentException
*/
public function getAuthorizationUrl(array $options = [])
{
@@ -492,10 +495,11 @@ abstract class AbstractProvider
* @param array $options
* @param callable|null $redirectHandler
* @return mixed
* @throws InvalidArgumentException
*/
public function authorize(
array $options = [],
callable $redirectHandler = null
?callable $redirectHandler = null
) {
$url = $this->getAuthorizationUrl($options);
if ($redirectHandler) {
@@ -613,13 +617,20 @@ abstract class AbstractProvider
*
* @param mixed $grant
* @param array<string, mixed> $options
* @throws IdentityProviderException
* @return AccessTokenInterface
* @throws IdentityProviderException
* @throws UnexpectedValueException
* @throws GuzzleException
*/
public function getAccessToken($grant, array $options = [])
{
$grant = $this->verifyGrant($grant);
if (isset($options['scope']) && is_array($options['scope'])) {
$separator = $this->getScopeSeparator();
$options['scope'] = implode($separator, $options['scope']);
}
$params = [
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret,
@@ -700,6 +711,7 @@ abstract class AbstractProvider
*
* @param RequestInterface $request
* @return ResponseInterface
* @throws GuzzleException
*/
public function getResponse(RequestInterface $request)
{
@@ -710,8 +722,10 @@ abstract class AbstractProvider
* Sends a request and returns the parsed response.
*
* @param RequestInterface $request
* @throws IdentityProviderException
* @return mixed
* @throws IdentityProviderException
* @throws UnexpectedValueException
* @throws GuzzleException
*/
public function getParsedResponse(RequestInterface $request)
{
@@ -757,7 +771,7 @@ abstract class AbstractProvider
*/
protected function getContentType(ResponseInterface $response)
{
return join(';', (array) $response->getHeader('content-type'));
return implode(';', $response->getHeader('content-type'));
}
/**
@@ -815,7 +829,7 @@ abstract class AbstractProvider
* Custom mapping of expiration, etc should be done here. Always call the
* parent method when overloading this method.
*
* @param mixed $result
* @param array<string, mixed> $result
* @return array
*/
protected function prepareAccessTokenResponse(array $result)
@@ -859,6 +873,9 @@ abstract class AbstractProvider
*
* @param AccessToken $token
* @return ResourceOwnerInterface
* @throws IdentityProviderException
* @throws UnexpectedValueException
* @throws GuzzleException
*/
public function getResourceOwner(AccessToken $token)
{
@@ -872,6 +889,9 @@ abstract class AbstractProvider
*
* @param AccessToken $token
* @return mixed
* @throws IdentityProviderException
* @throws UnexpectedValueException
* @throws GuzzleException
*/
protected function fetchResourceOwnerDetails(AccessToken $token)
{

View File

@@ -22,7 +22,7 @@ use RuntimeException;
*
* @link http://tools.ietf.org/html/rfc6749#section-1.4 Access Token (RFC 6749, §1.4)
*/
class AccessToken implements AccessTokenInterface, ResourceOwnerAccessTokenInterface
class AccessToken implements AccessTokenInterface, ResourceOwnerAccessTokenInterface, SettableRefreshTokenInterface
{
/**
* @var string
@@ -118,7 +118,7 @@ class AccessToken implements AccessTokenInterface, ResourceOwnerAccessTokenInter
} elseif (!empty($options['expires'])) {
// Some providers supply the seconds until expiration rather than
// the exact timestamp. Take a best guess at which we received.
$expires = $options['expires'];
$expires = (int) $options['expires'];
if (!$this->isExpirationTimestamp($expires)) {
$expires += $this->getTimeNow();
@@ -169,6 +169,14 @@ class AccessToken implements AccessTokenInterface, ResourceOwnerAccessTokenInter
return $this->refreshToken;
}
/**
* @inheritdoc
*/
public function setRefreshToken($refreshToken)
{
$this->refreshToken = $refreshToken;
}
/**
* @inheritdoc
*/
@@ -196,7 +204,7 @@ class AccessToken implements AccessTokenInterface, ResourceOwnerAccessTokenInter
throw new RuntimeException('"expires" is not set on the token');
}
return $expires < time();
return $expires < $this->getTimeNow();
}
/**

View File

@@ -1,5 +1,12 @@
OAuth 2.0 Google Provider Changelog
## 4.1.0 - 2025-12-15
### Added
- Added getEmailVerified(), isEmailTrustworthy() to user definition, #132 by @dt-thomas-durand
## 4.0.1 - 2022-03-17
### Changed

View File

@@ -1,6 +1,6 @@
# Google Provider for OAuth 2.0 Client
[![Build Status](https://img.shields.io/github/workflow/status/thephpleague/oauth2-google/test/main)](https://github.com/thephpleague/oauth2-google/actions/workflows/test.yaml)
[![Build Status](https://img.shields.io/github/actions/workflow/status/thephpleague/oauth2-google/ci.yml?branch=main)](https://github.com/thephpleague/oauth2-google/actions/workflows/ci.yml)
[![Code Coverage](https://img.shields.io/codecov/c/gh/thephpleague/oauth2-google)](https://app.codecov.io/gh/thephpleague/oauth2-google)
[![License](https://img.shields.io/packagist/l/league/oauth2-google)](https://github.com/thephpleague/oauth2-google/blob/main/LICENSE)
[![Latest Stable Version](https://img.shields.io/packagist/v/league/oauth2-google)](https://packagist.org/packages/league/oauth2-google)
@@ -22,6 +22,8 @@ The following versions of PHP are supported.
* PHP 7.4
* PHP 8.0
* PHP 8.1
* PHP 8.2
* PHP 8.3
This package uses [OpenID Connect][openid-connect] to authenticate users with
Google accounts.

View File

@@ -72,6 +72,36 @@ class GoogleUser implements ResourceOwnerInterface
return $this->getResponseValue('email');
}
/**
* Get email_verified attribute.
*
* @return bool|null
*/
public function getEmailVerified(): ?bool
{
return $this->getResponseValue('email_verified');
}
/**
* Returns whether the email is trustable enough to be used for authentication purpose.
*
* @see https://developers.google.com/identity/gsi/web/guides/verify-google-id-token
*/
public function isEmailTrustworthy(): bool
{
$email = $this->getEmail();
if (! $email) {
return false;
}
if ('@gmail.com' === substr($email, -10)) {
return true;
}
if ($this->getHostedDomain() && $this->getEmailVerified()) {
return true;
}
return false;
}
/**
* Get hosted domain.
*

View File

@@ -6,7 +6,7 @@ PHP Parser
This is a PHP 5.2 to PHP 8.2 parser written in PHP. Its purpose is to simplify static code analysis and
manipulation.
[**Documentation for version 4.x**][doc_4_x] (stable; for running on PHP >= 7.0; for parsing PHP 5.2 to PHP 8.2).
[**Documentation for version 4.x**][doc_4_x] (stable; for running on PHP >= 7.1; for parsing PHP 5.2 to PHP 8.2).
[Documentation for version 3.x][doc_3_x] (unsupported; for running on PHP >= 5.5; for parsing PHP 5.2 to PHP 7.2).

View File

@@ -13,18 +13,13 @@
}
],
"require": {
"php": ">=7.0",
"php": ">=7.1",
"ext-tokenizer": "*"
},
"require-dev": {
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
"ircmaxell/php-yacc": "^0.0.7"
},
"extra": {
"branch-alias": {
"dev-master": "4.9-dev"
}
},
"autoload": {
"psr-4": {
"PhpParser\\": "lib/PhpParser"

View File

@@ -26,7 +26,7 @@ class ClassConst implements PhpParser\Builder
* Creates a class constant builder
*
* @param string|Identifier $name Name
* @param Node\Expr|bool|null|int|float|string|array $value Value
* @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value Value
*/
public function __construct($name, $value) {
$this->constants = [new Const_($name, BuilderHelpers::normalizeValue($value))];
@@ -36,7 +36,7 @@ class ClassConst implements PhpParser\Builder
* Add another constant to const group
*
* @param string|Identifier $name Name
* @param Node\Expr|bool|null|int|float|string|array $value Value
* @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value Value
*
* @return $this The builder instance (for fluid interface)
*/

View File

@@ -213,7 +213,7 @@ class BuilderFactory
/**
* Creates node a for a literal value.
*
* @param Expr|bool|null|int|float|string|array $value $value
* @param Expr|bool|null|int|float|string|array|\UnitEnum $value $value
*
* @return Expr
*/

View File

@@ -6,6 +6,7 @@ use PhpParser\Node\ComplexType;
use PhpParser\Node\Expr;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\NullableType;
use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt;
@@ -215,7 +216,7 @@ final class BuilderHelpers
* Normalizes a value: Converts nulls, booleans, integers,
* floats, strings and arrays into their respective nodes
*
* @param Node\Expr|bool|null|int|float|string|array $value The value to normalize
* @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value The value to normalize
*
* @return Expr The normalized value
*/
@@ -269,6 +270,10 @@ final class BuilderHelpers
return new Expr\Array_($items);
}
if ($value instanceof \UnitEnum) {
return new Expr\ClassConstFetch(new FullyQualified(\get_class($value)), new Identifier($value->name));
}
throw new \LogicException('Invalid value');
}

View File

@@ -37,7 +37,7 @@ class ConstExprEvaluator
*
* @param callable|null $fallbackEvaluator To call if subexpression cannot be evaluated
*/
public function __construct(callable $fallbackEvaluator = null) {
public function __construct(?callable $fallbackEvaluator = null) {
$this->fallbackEvaluator = $fallbackEvaluator ?? function(Expr $expr) {
throw new ConstExprEvaluationException(
"Expression of type {$expr->getType()} cannot be evaluated"

View File

@@ -31,7 +31,7 @@ class PrintableNewAnonClassNode extends Expr
public $stmts;
public function __construct(
array $attrGroups, int $flags, array $args, Node\Name $extends = null, array $implements,
array $attrGroups, int $flags, array $args, ?Node\Name $extends, array $implements,
array $stmts, array $attributes
) {
parent::__construct($attributes);

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