NEW Upgrade Sabre lib to 4.6.0

This commit is contained in:
Laurent Destailleur
2024-01-15 13:58:04 +01:00
parent a2df2f2553
commit 96925bc645
124 changed files with 2843 additions and 2656 deletions

View File

@@ -42,7 +42,7 @@ PrestaShop-WS-Lib 94feb5f OSL-3.0 No
PSR/Logs 1.0 MIT License Yes Library for logs (used by DebugBar) PSR/Logs 1.0 MIT License Yes Library for logs (used by DebugBar)
PSR/simple-cache ? MIT License Yes Library for cache (used by PHPSpreadSheet) PSR/simple-cache ? MIT License Yes Library for cache (used by PHPSpreadSheet)
Restler 3.1.1 LGPL-3+ Yes Library to develop REST Web services (+ swagger-ui js lib into dir explorer) Restler 3.1.1 LGPL-3+ Yes Library to develop REST Web services (+ swagger-ui js lib into dir explorer)
Sabre 4.0.2 BSD Yes DAV support Sabre 4.6.0 BSD Yes DAV support
Swift Mailer 5.4.2-DEV MIT License Yes Comprehensive mailing tools for PHP Swift Mailer 5.4.2-DEV MIT License Yes Comprehensive mailing tools for PHP
Symfony/var-dumper ??? MIT License Yes Library to make var dump (used by DebugBar) Symfony/var-dumper ??? MIT License Yes Library to make var dump (used by DebugBar)
Stripe 10.7.0 MIT Licence Yes Library for Stripe module Stripe 10.7.0 MIT Licence Yes Library for Stripe module

View File

@@ -1,19 +1,39 @@
* Swith to the minimal version of PHP
update-alternatives --config php
* To list packages * To list packages
composer show -i cd htdocs/includes/diroflib
composer install
composer show -i
* To test upgrade of a lib with composer:
* To upgrade a lib with composer using the composer.json of the library only:
Remove entry in composer.lock Remove entry in composer.lock
Edit composer.json to change version to "x.y.z"
composer -v update --root-reqs --no-dev --no-autoloader --dry-run ccampbell/chromephp
* To upgrade a lib with composer: cd htdocs/includes/diroflib
rm composer.lock
Edit composer.json to change version to "x.y.z"
composer -v update --root-reqs --no-dev --ignore-platform-reqs
composer -v update --root-reqs --no-dev --ignore-platform-reqs [--no-autoloader] [--dry-run] ccampbell/chromephp
* To upgrade a lib with composer using the composer.json of Dolibarr:
Remove entry in composer.lock Remove entry in composer.lock
cd /
mv composer.json.disabled composer.json
rm composer.lock
Edit composer.json to change version to "x.y.z" Edit composer.json to change version to "x.y.z"
composer -v update --root-reqs --no-dev --no-autoloader ccampbell/chromephp
composer -v update --root-reqs --no-dev --ignore-platform-reqs
composer -v update --root-reqs --no-dev --ignore-platform-reqs [--no-autoloader] [--dry-run] ccampbell/chromephp

View File

@@ -33,16 +33,9 @@
"tecnickcom/tcpdf" : "6.3.2", "tecnickcom/tcpdf" : "6.3.2",
"nnnick/chartjs" : "^3.7.1", "nnnick/chartjs" : "^3.7.1",
"stripe/stripe-php" : "10.7.0", "stripe/stripe-php" : "10.7.0",
"maximebf/debugbar" : "1.18.2", "maximebf/debugbar" : "1.18.2"
"symfony/var-dumper" : ">=3.2"
}, },
"require-dev" : { "require-dev" : {
"php-parallel-lint/php-parallel-lint" : "^0",
"php-parallel-lint/php-console-highlighter" : "^0",
"phpunit/phpunit" : "^4",
"squizlabs/php_codesniffer" : "^2",
"phpunit/phpunit-selenium" : "^2",
"rector/rector" : "^0.16.0"
}, },
"suggest" : { "suggest" : {
"ext-mysqlnd" : "To use with MySQL or MariaDB", "ext-mysqlnd" : "To use with MySQL or MariaDB",
@@ -50,7 +43,7 @@
"ext-pgsql" : "To use with PostgreSQL", "ext-pgsql" : "To use with PostgreSQL",
"ext-gd" : "Image manipulation (Required but maybe built-in PHP)", "ext-gd" : "Image manipulation (Required but maybe built-in PHP)",
"ext-imagick" : "Generation of thumbs from PDF", "ext-imagick" : "Generation of thumbs from PDF",
"ext-mcrypt" : "(Required but maybe built-in PHP)", "ext-intl" : "Intl",
"ext-openssl" : "Secure connections (Emails, SOAP\u2026)", "ext-openssl" : "Secure connections (Emails, SOAP\u2026)",
"ext-mbstring" : "Handle non UTF-8 characters", "ext-mbstring" : "Handle non UTF-8 characters",
"ext-soap" : "Native SOAP", "ext-soap" : "Native SOAP",

View File

@@ -49,7 +49,9 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
require_once DOL_DOCUMENT_ROOT.'/dav/dav.class.php'; require_once DOL_DOCUMENT_ROOT.'/dav/dav.class.php';
require_once DOL_DOCUMENT_ROOT.'/dav/dav.lib.php'; require_once DOL_DOCUMENT_ROOT.'/dav/dav.lib.php';
require_once DOL_DOCUMENT_ROOT.'/includes/sabre/autoload.php'; require_once DOL_DOCUMENT_ROOT.'/includes/sabre/autoload.php';
//require_once DOL_DOCUMENT_ROOT.'/includes/autoload.php';
$user = new User($db); $user = new User($db);

View File

@@ -4,4 +4,4 @@
require_once __DIR__ . '/composer/autoload_real.php'; require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit60b9ac98a8448ede6c445b0fd4bd31e0::getLoader(); return ComposerAutoloaderInit51cd53f153efda61d1f1f814155d1c4a::getLoader();

View File

@@ -0,0 +1,6 @@
{
"require" : {
"php": ">=7.1.0",
"sabre/dav" : ">=3.0.0"
}
}

513
htdocs/includes/sabre/composer.lock generated Normal file
View File

@@ -0,0 +1,513 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "fffed375dc9f645f46fc681f0b1b7f07",
"packages": [
{
"name": "psr/log",
"version": "1.1.4",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.4"
},
"time": "2021-05-03T11:20:27+00:00"
},
{
"name": "sabre/dav",
"version": "4.6.0",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/dav.git",
"reference": "554145304b4a026477d130928d16e626939b0b2a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/dav/zipball/554145304b4a026477d130928d16e626939b0b2a",
"reference": "554145304b4a026477d130928d16e626939b0b2a",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-date": "*",
"ext-dom": "*",
"ext-iconv": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-pcre": "*",
"ext-simplexml": "*",
"ext-spl": "*",
"lib-libxml": ">=2.7.0",
"php": "^7.1.0 || ^8.0",
"psr/log": "^1.0 || ^2.0 || ^3.0",
"sabre/event": "^5.0",
"sabre/http": "^5.0.5",
"sabre/uri": "^2.0",
"sabre/vobject": "^4.2.1",
"sabre/xml": "^2.0.1"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.19",
"monolog/monolog": "^1.27 || ^2.0",
"phpstan/phpstan": "^0.12 || ^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6"
},
"suggest": {
"ext-curl": "*",
"ext-imap": "*",
"ext-pdo": "*"
},
"bin": [
"bin/sabredav",
"bin/naturalselection"
],
"type": "library",
"autoload": {
"psr-4": {
"Sabre\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
}
],
"description": "WebDAV Framework for PHP",
"homepage": "http://sabre.io/",
"keywords": [
"CalDAV",
"CardDAV",
"WebDAV",
"framework",
"iCalendar"
],
"support": {
"forum": "https://groups.google.com/group/sabredav-discuss",
"issues": "https://github.com/sabre-io/dav/issues",
"source": "https://github.com/fruux/sabre-dav"
},
"time": "2023-12-11T13:01:23+00:00"
},
{
"name": "sabre/event",
"version": "5.1.4",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/event.git",
"reference": "d7da22897125d34d7eddf7977758191c06a74497"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/event/zipball/d7da22897125d34d7eddf7977758191c06a74497",
"reference": "d7da22897125d34d7eddf7977758191c06a74497",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.17.1",
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
},
"type": "library",
"autoload": {
"files": [
"lib/coroutine.php",
"lib/Loop/functions.php",
"lib/Promise/functions.php"
],
"psr-4": {
"Sabre\\Event\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
}
],
"description": "sabre/event is a library for lightweight event-based programming",
"homepage": "http://sabre.io/event/",
"keywords": [
"EventEmitter",
"async",
"coroutine",
"eventloop",
"events",
"hooks",
"plugin",
"promise",
"reactor",
"signal"
],
"support": {
"forum": "https://groups.google.com/group/sabredav-discuss",
"issues": "https://github.com/sabre-io/event/issues",
"source": "https://github.com/fruux/sabre-event"
},
"time": "2021-11-04T06:51:17+00:00"
},
{
"name": "sabre/http",
"version": "5.1.10",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/http.git",
"reference": "f9f3d1fba8916fa2f4ec25636c4fedc26cb94e02"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/http/zipball/f9f3d1fba8916fa2f4ec25636c4fedc26cb94e02",
"reference": "f9f3d1fba8916fa2f4ec25636c4fedc26cb94e02",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-curl": "*",
"ext-mbstring": "*",
"php": "^7.1 || ^8.0",
"sabre/event": ">=4.0 <6.0",
"sabre/uri": "^2.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.17.1",
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
},
"suggest": {
"ext-curl": " to make http requests with the Client class"
},
"type": "library",
"autoload": {
"files": [
"lib/functions.php"
],
"psr-4": {
"Sabre\\HTTP\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
}
],
"description": "The sabre/http library provides utilities for dealing with http requests and responses. ",
"homepage": "https://github.com/fruux/sabre-http",
"keywords": [
"http"
],
"support": {
"forum": "https://groups.google.com/group/sabredav-discuss",
"issues": "https://github.com/sabre-io/http/issues",
"source": "https://github.com/fruux/sabre-http"
},
"time": "2023-08-18T01:55:28+00:00"
},
{
"name": "sabre/uri",
"version": "2.2.4",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/uri.git",
"reference": "c0c9af9f7754e60a49ebd760e1708adc6d1510c0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/uri/zipball/c0c9af9f7754e60a49ebd760e1708adc6d1510c0",
"reference": "c0c9af9f7754e60a49ebd760e1708adc6d1510c0",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.19.3",
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
},
"type": "library",
"autoload": {
"files": [
"lib/functions.php"
],
"psr-4": {
"Sabre\\Uri\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
}
],
"description": "Functions for making sense out of URIs.",
"homepage": "http://sabre.io/uri/",
"keywords": [
"rfc3986",
"uri",
"url"
],
"support": {
"forum": "https://groups.google.com/group/sabredav-discuss",
"issues": "https://github.com/sabre-io/uri/issues",
"source": "https://github.com/fruux/sabre-uri"
},
"time": "2022-09-19T12:25:28+00:00"
},
{
"name": "sabre/vobject",
"version": "4.5.4",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/vobject.git",
"reference": "a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772",
"reference": "a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^7.1 || ^8.0",
"sabre/xml": "^2.1 || ^3.0 || ^4.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.17.1",
"phpstan/phpstan": "^0.12",
"phpunit/php-invoker": "^2.0 || ^3.1",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
},
"suggest": {
"hoa/bench": "If you would like to run the benchmark scripts"
},
"bin": [
"bin/vobject",
"bin/generate_vcards"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Sabre\\VObject\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
},
{
"name": "Dominik Tobschall",
"email": "dominik@fruux.com",
"homepage": "http://tobschall.de/",
"role": "Developer"
},
{
"name": "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net",
"homepage": "http://mnt.io/",
"role": "Developer"
}
],
"description": "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects",
"homepage": "http://sabre.io/vobject/",
"keywords": [
"availability",
"freebusy",
"iCalendar",
"ical",
"ics",
"jCal",
"jCard",
"recurrence",
"rfc2425",
"rfc2426",
"rfc2739",
"rfc4770",
"rfc5545",
"rfc5546",
"rfc6321",
"rfc6350",
"rfc6351",
"rfc6474",
"rfc6638",
"rfc6715",
"rfc6868",
"vCalendar",
"vCard",
"vcf",
"xCal",
"xCard"
],
"support": {
"forum": "https://groups.google.com/group/sabredav-discuss",
"issues": "https://github.com/sabre-io/vobject/issues",
"source": "https://github.com/fruux/sabre-vobject"
},
"time": "2023-11-09T12:54:37+00:00"
},
{
"name": "sabre/xml",
"version": "2.2.6",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/xml.git",
"reference": "9cde7cdab1e50893cc83b037b40cd47bfde42a2b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/xml/zipball/9cde7cdab1e50893cc83b037b40cd47bfde42a2b",
"reference": "9cde7cdab1e50893cc83b037b40cd47bfde42a2b",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-xmlreader": "*",
"ext-xmlwriter": "*",
"lib-libxml": ">=2.6.20",
"php": "^7.1 || ^8.0",
"sabre/uri": ">=1.0,<3.0.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.17.1",
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
},
"type": "library",
"autoload": {
"files": [
"lib/Deserializer/functions.php",
"lib/Serializer/functions.php"
],
"psr-4": {
"Sabre\\Xml\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
},
{
"name": "Markus Staab",
"email": "markus.staab@redaxo.de",
"role": "Developer"
}
],
"description": "sabre/xml is an XML library that you may not hate.",
"homepage": "https://sabre.io/xml/",
"keywords": [
"XMLReader",
"XMLWriter",
"dom",
"xml"
],
"support": {
"forum": "https://groups.google.com/group/sabredav-discuss",
"issues": "https://github.com/sabre-io/xml/issues",
"source": "https://github.com/fruux/sabre-xml"
},
"time": "2023-06-28T12:56:05+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=7.1.0"
},
"platform-dev": [],
"plugin-api-version": "2.2.0"
}

View File

@@ -37,57 +37,130 @@ namespace Composer\Autoload;
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/ * @see https://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/ * @see https://www.php-fig.org/psr/psr-4/
*/ */
class ClassLoader class ClassLoader
{ {
/** @var ?string */
private $vendorDir;
// PSR-4 // PSR-4
/**
* @var array[]
* @psalm-var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array(); private $prefixLengthsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, array<int, string>>
*/
private $prefixDirsPsr4 = array(); private $prefixDirsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr4 = array(); private $fallbackDirsPsr4 = array();
// PSR-0 // PSR-0
/**
* @var array[]
* @psalm-var array<string, array<string, string[]>>
*/
private $prefixesPsr0 = array(); private $prefixesPsr0 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr0 = array(); private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false; private $useIncludePath = false;
/**
* @var string[]
* @psalm-var array<string, string>
*/
private $classMap = array(); private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false; private $classMapAuthoritative = false;
/**
* @var bool[]
* @psalm-var array<string, bool>
*/
private $missingClasses = array(); private $missingClasses = array();
/** @var ?string */
private $apcuPrefix; private $apcuPrefix;
/**
* @var self[]
*/
private static $registeredLoaders = array();
/**
* @param ?string $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
}
/**
* @return string[]
*/
public function getPrefixes() public function getPrefixes()
{ {
if (!empty($this->prefixesPsr0)) { if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0); return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
} }
return array(); return array();
} }
/**
* @return array[]
* @psalm-return array<string, array<int, string>>
*/
public function getPrefixesPsr4() public function getPrefixesPsr4()
{ {
return $this->prefixDirsPsr4; return $this->prefixDirsPsr4;
} }
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirs() public function getFallbackDirs()
{ {
return $this->fallbackDirsPsr0; return $this->fallbackDirsPsr0;
} }
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirsPsr4() public function getFallbackDirsPsr4()
{ {
return $this->fallbackDirsPsr4; return $this->fallbackDirsPsr4;
} }
/**
* @return string[] Array of classname => path
* @psalm-return array<string, string>
*/
public function getClassMap() public function getClassMap()
{ {
return $this->classMap; return $this->classMap;
} }
/** /**
* @param array $classMap Class to filename map * @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
*
* @return void
*/ */
public function addClassMap(array $classMap) public function addClassMap(array $classMap)
{ {
@@ -102,9 +175,11 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix, either * Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix. * appending or prepending to the ones previously set for this prefix.
* *
* @param string $prefix The prefix * @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories * @param string[]|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories * @param bool $prepend Whether to prepend the directories
*
* @return void
*/ */
public function add($prefix, $paths, $prepend = false) public function add($prefix, $paths, $prepend = false)
{ {
@@ -147,11 +222,13 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace, either * Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace. * appending or prepending to the ones previously set for this namespace.
* *
* @param string $prefix The prefix/namespace, with trailing '\\' * @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories * @param string[]|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories * @param bool $prepend Whether to prepend the directories
* *
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*
* @return void
*/ */
public function addPsr4($prefix, $paths, $prepend = false) public function addPsr4($prefix, $paths, $prepend = false)
{ {
@@ -195,8 +272,10 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix, * Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix. * replacing any others previously set for this prefix.
* *
* @param string $prefix The prefix * @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories * @param string[]|string $paths The PSR-0 base directories
*
* @return void
*/ */
public function set($prefix, $paths) public function set($prefix, $paths)
{ {
@@ -211,10 +290,12 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace, * Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace. * replacing any others previously set for this namespace.
* *
* @param string $prefix The prefix/namespace, with trailing '\\' * @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories * @param string[]|string $paths The PSR-4 base directories
* *
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*
* @return void
*/ */
public function setPsr4($prefix, $paths) public function setPsr4($prefix, $paths)
{ {
@@ -234,6 +315,8 @@ class ClassLoader
* Turns on searching the include path for class files. * Turns on searching the include path for class files.
* *
* @param bool $useIncludePath * @param bool $useIncludePath
*
* @return void
*/ */
public function setUseIncludePath($useIncludePath) public function setUseIncludePath($useIncludePath)
{ {
@@ -256,6 +339,8 @@ class ClassLoader
* that have not been registered with the class map. * that have not been registered with the class map.
* *
* @param bool $classMapAuthoritative * @param bool $classMapAuthoritative
*
* @return void
*/ */
public function setClassMapAuthoritative($classMapAuthoritative) public function setClassMapAuthoritative($classMapAuthoritative)
{ {
@@ -276,10 +361,12 @@ class ClassLoader
* APCu prefix to use to cache found/not-found classes, if the extension is enabled. * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
* *
* @param string|null $apcuPrefix * @param string|null $apcuPrefix
*
* @return void
*/ */
public function setApcuPrefix($apcuPrefix) public function setApcuPrefix($apcuPrefix)
{ {
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
} }
/** /**
@@ -296,25 +383,44 @@ class ClassLoader
* Registers this instance as an autoloader. * Registers this instance as an autoloader.
* *
* @param bool $prepend Whether to prepend the autoloader or not * @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/ */
public function register($prepend = false) public function register($prepend = false)
{ {
spl_autoload_register(array($this, 'loadClass'), true, $prepend); spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
} }
/** /**
* Unregisters this instance as an autoloader. * Unregisters this instance as an autoloader.
*
* @return void
*/ */
public function unregister() public function unregister()
{ {
spl_autoload_unregister(array($this, 'loadClass')); spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
} }
/** /**
* Loads the given class or interface. * Loads the given class or interface.
* *
* @param string $class The name of the class * @param string $class The name of the class
* @return bool|null True if loaded, null otherwise * @return true|null True if loaded, null otherwise
*/ */
public function loadClass($class) public function loadClass($class)
{ {
@@ -323,6 +429,8 @@ class ClassLoader
return true; return true;
} }
return null;
} }
/** /**
@@ -367,6 +475,21 @@ class ClassLoader
return $file; return $file;
} }
/**
* Returns the currently registered loaders indexed by their corresponding vendor directories.
*
* @return self[]
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext) private function findFileWithExtension($class, $ext)
{ {
// PSR-4 lookup // PSR-4 lookup
@@ -374,10 +497,14 @@ class ClassLoader
$first = $class[0]; $first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) { if (isset($this->prefixLengthsPsr4[$first])) {
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { $subPath = $class;
if (0 === strpos($class, $prefix)) { while (false !== $lastPos = strrpos($subPath, '\\')) {
foreach ($this->prefixDirsPsr4[$prefix] as $dir) { $subPath = substr($subPath, 0, $lastPos);
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { $search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file; return $file;
} }
} }
@@ -434,6 +561,10 @@ class ClassLoader
* Scope isolated include. * Scope isolated include.
* *
* Prevents access to $this/self from included files. * Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/ */
function includeFile($file) function includeFile($file)
{ {

View File

@@ -0,0 +1,350 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;
/**
* This class is copied in every Composer installed project and available to all
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
*/
private static $installed;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
private static $installedByVendor = array();
/**
* Returns a list of all package names which are present, either by being installed, replaced or provided
*
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}
if (1 === \count($packages)) {
return $packages[0];
}
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
/**
* Checks whether the given package is installed
*
* This also returns true if the package name is provided or replaced by another package
*
* @param string $packageName
* @param bool $includeDevRequirements
* @return bool
*/
public static function isInstalled($packageName, $includeDevRequirements = true)
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
}
}
return false;
}
/**
* Checks whether the given package satisfies a version constraint
*
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
*
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
*
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
* @param string $packageName
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
* @return bool
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
/**
* Returns a version constraint representing all the range(s) which are installed for a given package
*
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
* whether a given version of a package is installed, and not just whether it exists
*
* @param string $packageName
* @return string Version constraint usable with composer/semver
*/
public static function getVersionRanges($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['version'])) {
return null;
}
return $installed['versions'][$packageName]['version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getPrettyVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return $installed['versions'][$packageName]['pretty_version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
*/
public static function getReference($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['reference'])) {
return null;
}
return $installed['versions'][$packageName]['reference'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
*/
public static function getInstallPath($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
*/
public static function getRootPackage()
{
$installed = self::getInstalled();
return $installed[0]['root'];
}
/**
* Returns the raw installed.php data for custom implementations
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
*/
public static function getRawData()
{
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
return self::$installed;
}
/**
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
public static function getAllRawData()
{
return self::getInstalled();
}
/**
* Lets you reload the static array from another file
*
* This is only useful for complex integrations in which a project needs to use
* this class but then also needs to execute another project's autoloader in process,
* and wants to ensure both projects have access to their version of installed.php.
*
* A typical case would be PHPUnit, where it would need to make sure it reads all
* the data it needs from this class, then call reload() with
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
* the project in which it runs can then also use this class safely, without
* interference between PHPUnit's dependencies and the project's dependencies.
*
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
private static function getInstalled()
{
if (null === self::$canGetVendors) {
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}
$installed = array();
if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
}
}
}
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = require __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
$installed[] = self::$installed;
return $installed;
}
}

View File

@@ -1,5 +1,5 @@
Copyright (c) 2016 Nils Adermann, Jordi Boggiano Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -6,4 +6,5 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
); );

View File

@@ -7,10 +7,10 @@ $baseDir = dirname($vendorDir);
return array( return array(
'383eaff206634a77a1be54e64e6459c7' => $vendorDir . '/sabre/uri/lib/functions.php', '383eaff206634a77a1be54e64e6459c7' => $vendorDir . '/sabre/uri/lib/functions.php',
'3569eecfeed3bcf0bad3c998a494ecb8' => $vendorDir . '/sabre/xml/lib/Deserializer/functions.php',
'93aa591bc4ca510c520999e34229ee79' => $vendorDir . '/sabre/xml/lib/Serializer/functions.php',
'2b9d0f43f9552984cfa82fee95491826' => $vendorDir . '/sabre/event/lib/coroutine.php', '2b9d0f43f9552984cfa82fee95491826' => $vendorDir . '/sabre/event/lib/coroutine.php',
'd81bab31d3feb45bfe2f283ea3c8fdf7' => $vendorDir . '/sabre/event/lib/Loop/functions.php', 'd81bab31d3feb45bfe2f283ea3c8fdf7' => $vendorDir . '/sabre/event/lib/Loop/functions.php',
'a1cce3d26cc15c00fcd0b3354bd72c88' => $vendorDir . '/sabre/event/lib/Promise/functions.php', 'a1cce3d26cc15c00fcd0b3354bd72c88' => $vendorDir . '/sabre/event/lib/Promise/functions.php',
'3569eecfeed3bcf0bad3c998a494ecb8' => $vendorDir . '/sabre/xml/lib/Deserializer/functions.php',
'93aa591bc4ca510c520999e34229ee79' => $vendorDir . '/sabre/xml/lib/Serializer/functions.php',
'ebdb698ed4152ae445614b69b5e4bb6a' => $vendorDir . '/sabre/http/lib/functions.php', 'ebdb698ed4152ae445614b69b5e4bb6a' => $vendorDir . '/sabre/http/lib/functions.php',
); );

View File

@@ -11,9 +11,6 @@ return array(
'Sabre\\Uri\\' => array($vendorDir . '/sabre/uri/lib'), 'Sabre\\Uri\\' => array($vendorDir . '/sabre/uri/lib'),
'Sabre\\HTTP\\' => array($vendorDir . '/sabre/http/lib'), 'Sabre\\HTTP\\' => array($vendorDir . '/sabre/http/lib'),
'Sabre\\Event\\' => array($vendorDir . '/sabre/event/lib'), 'Sabre\\Event\\' => array($vendorDir . '/sabre/event/lib'),
'Sabre\\DAV\\' => array($vendorDir . '/sabre/dav/lib/DAV'), 'Sabre\\' => array($vendorDir . '/sabre/dav/lib'),
'Sabre\\DAVACL\\' => array($vendorDir . '/sabre/dav/lib/DAVACL'),
'Sabre\\CardDAV\\' => array($vendorDir . '/sabre/dav/lib/CardDAV'),
'Sabre\\CalDAV\\' => array($vendorDir . '/sabre/dav/lib/CalDAV'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
); );

View File

@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer // autoload_real.php @generated by Composer
class ComposerAutoloaderInit60b9ac98a8448ede6c445b0fd4bd31e0 class ComposerAutoloaderInit51cd53f153efda61d1f1f814155d1c4a
{ {
private static $loader; private static $loader;
@@ -13,21 +13,26 @@ class ComposerAutoloaderInit60b9ac98a8448ede6c445b0fd4bd31e0
} }
} }
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader() public static function getLoader()
{ {
if (null !== self::$loader) { if (null !== self::$loader) {
return self::$loader; return self::$loader;
} }
spl_autoload_register(array('ComposerAutoloaderInit60b9ac98a8448ede6c445b0fd4bd31e0', 'loadClassLoader'), true, true); require __DIR__ . '/platform_check.php';
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit60b9ac98a8448ede6c445b0fd4bd31e0', 'loadClassLoader')); spl_autoload_register(array('ComposerAutoloaderInit51cd53f153efda61d1f1f814155d1c4a', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInit51cd53f153efda61d1f1f814155d1c4a', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) { if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php'; require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit60b9ac98a8448ede6c445b0fd4bd31e0::getInitializer($loader)); call_user_func(\Composer\Autoload\ComposerStaticInit51cd53f153efda61d1f1f814155d1c4a::getInitializer($loader));
} else { } else {
$map = require __DIR__ . '/autoload_namespaces.php'; $map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) { foreach ($map as $namespace => $path) {
@@ -48,23 +53,28 @@ class ComposerAutoloaderInit60b9ac98a8448ede6c445b0fd4bd31e0
$loader->register(true); $loader->register(true);
if ($useStaticLoader) { if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit60b9ac98a8448ede6c445b0fd4bd31e0::$files; $includeFiles = Composer\Autoload\ComposerStaticInit51cd53f153efda61d1f1f814155d1c4a::$files;
} else { } else {
$includeFiles = require __DIR__ . '/autoload_files.php'; $includeFiles = require __DIR__ . '/autoload_files.php';
} }
foreach ($includeFiles as $fileIdentifier => $file) { foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire60b9ac98a8448ede6c445b0fd4bd31e0($fileIdentifier, $file); composerRequire51cd53f153efda61d1f1f814155d1c4a($fileIdentifier, $file);
} }
return $loader; return $loader;
} }
} }
function composerRequire60b9ac98a8448ede6c445b0fd4bd31e0($fileIdentifier, $file) /**
* @param string $fileIdentifier
* @param string $file
* @return void
*/
function composerRequire51cd53f153efda61d1f1f814155d1c4a($fileIdentifier, $file)
{ {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file;
} }
} }

View File

@@ -4,15 +4,15 @@
namespace Composer\Autoload; namespace Composer\Autoload;
class ComposerStaticInit60b9ac98a8448ede6c445b0fd4bd31e0 class ComposerStaticInit51cd53f153efda61d1f1f814155d1c4a
{ {
public static $files = array ( public static $files = array (
'383eaff206634a77a1be54e64e6459c7' => __DIR__ . '/..' . '/sabre/uri/lib/functions.php', '383eaff206634a77a1be54e64e6459c7' => __DIR__ . '/..' . '/sabre/uri/lib/functions.php',
'3569eecfeed3bcf0bad3c998a494ecb8' => __DIR__ . '/..' . '/sabre/xml/lib/Deserializer/functions.php',
'93aa591bc4ca510c520999e34229ee79' => __DIR__ . '/..' . '/sabre/xml/lib/Serializer/functions.php',
'2b9d0f43f9552984cfa82fee95491826' => __DIR__ . '/..' . '/sabre/event/lib/coroutine.php', '2b9d0f43f9552984cfa82fee95491826' => __DIR__ . '/..' . '/sabre/event/lib/coroutine.php',
'd81bab31d3feb45bfe2f283ea3c8fdf7' => __DIR__ . '/..' . '/sabre/event/lib/Loop/functions.php', 'd81bab31d3feb45bfe2f283ea3c8fdf7' => __DIR__ . '/..' . '/sabre/event/lib/Loop/functions.php',
'a1cce3d26cc15c00fcd0b3354bd72c88' => __DIR__ . '/..' . '/sabre/event/lib/Promise/functions.php', 'a1cce3d26cc15c00fcd0b3354bd72c88' => __DIR__ . '/..' . '/sabre/event/lib/Promise/functions.php',
'3569eecfeed3bcf0bad3c998a494ecb8' => __DIR__ . '/..' . '/sabre/xml/lib/Deserializer/functions.php',
'93aa591bc4ca510c520999e34229ee79' => __DIR__ . '/..' . '/sabre/xml/lib/Serializer/functions.php',
'ebdb698ed4152ae445614b69b5e4bb6a' => __DIR__ . '/..' . '/sabre/http/lib/functions.php', 'ebdb698ed4152ae445614b69b5e4bb6a' => __DIR__ . '/..' . '/sabre/http/lib/functions.php',
); );
@@ -24,10 +24,7 @@ class ComposerStaticInit60b9ac98a8448ede6c445b0fd4bd31e0
'Sabre\\Uri\\' => 10, 'Sabre\\Uri\\' => 10,
'Sabre\\HTTP\\' => 11, 'Sabre\\HTTP\\' => 11,
'Sabre\\Event\\' => 12, 'Sabre\\Event\\' => 12,
'Sabre\\DAV\\' => 10, 'Sabre\\' => 6,
'Sabre\\DAVACL\\' => 13,
'Sabre\\CardDAV\\' => 14,
'Sabre\\CalDAV\\' => 13,
), ),
'P' => 'P' =>
array ( array (
@@ -56,21 +53,9 @@ class ComposerStaticInit60b9ac98a8448ede6c445b0fd4bd31e0
array ( array (
0 => __DIR__ . '/..' . '/sabre/event/lib', 0 => __DIR__ . '/..' . '/sabre/event/lib',
), ),
'Sabre\\DAV\\' => 'Sabre\\' =>
array ( array (
0 => __DIR__ . '/..' . '/sabre/dav/lib/DAV', 0 => __DIR__ . '/..' . '/sabre/dav/lib',
),
'Sabre\\DAVACL\\' =>
array (
0 => __DIR__ . '/..' . '/sabre/dav/lib/DAVACL',
),
'Sabre\\CardDAV\\' =>
array (
0 => __DIR__ . '/..' . '/sabre/dav/lib/CardDAV',
),
'Sabre\\CalDAV\\' =>
array (
0 => __DIR__ . '/..' . '/sabre/dav/lib/CalDAV',
), ),
'Psr\\Log\\' => 'Psr\\Log\\' =>
array ( array (
@@ -78,11 +63,16 @@ class ComposerStaticInit60b9ac98a8448ede6c445b0fd4bd31e0
), ),
); );
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
);
public static function getInitializer(ClassLoader $loader) public static function getInitializer(ClassLoader $loader)
{ {
return \Closure::bind(function () use ($loader) { return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit60b9ac98a8448ede6c445b0fd4bd31e0::$prefixLengthsPsr4; $loader->prefixLengthsPsr4 = ComposerStaticInit51cd53f153efda61d1f1f814155d1c4a::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit60b9ac98a8448ede6c445b0fd4bd31e0::$prefixDirsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInit51cd53f153efda61d1f1f814155d1c4a::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit51cd53f153efda61d1f1f814155d1c4a::$classMap;
}, null, ClassLoader::class); }, null, ClassLoader::class);
} }

View File

@@ -1,470 +1,519 @@
[ {
{ "packages": [
"name": "sabre/uri", {
"version": "1.2.0", "name": "psr/log",
"version_normalized": "1.2.0.0", "version": "1.1.4",
"source": { "version_normalized": "1.1.4.0",
"type": "git", "source": {
"url": "https://github.com/fruux/sabre-uri.git", "type": "git",
"reference": "8545a3335f741d4b7700bb14efb41b4c03775dcd" "url": "https://github.com/php-fig/log.git",
}, "reference": "d49695b909c3b7628b6289db5479a1c204601f11"
"dist": { },
"type": "zip", "dist": {
"url": "https://api.github.com/repos/fruux/sabre-uri/zipball/8545a3335f741d4b7700bb14efb41b4c03775dcd", "type": "zip",
"reference": "8545a3335f741d4b7700bb14efb41b4c03775dcd", "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
"shasum": "" "reference": "d49695b909c3b7628b6289db5479a1c204601f11",
}, "shasum": ""
"require": { },
"php": ">=5.4.7" "require": {
}, "php": ">=5.3.0"
"require-dev": { },
"phpunit/phpunit": "*", "time": "2021-05-03T11:20:27+00:00",
"sabre/cs": "~1.0.0" "type": "library",
}, "extra": {
"time": "2016-12-07T01:17:59+00:00", "branch-alias": {
"type": "library", "dev-master": "1.1.x-dev"
"installation-source": "dist", }
"autoload": { },
"files": [ "installation-source": "dist",
"lib/functions.php" "autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
], ],
"psr-4": { "authors": [
"Sabre\\Uri\\": "lib/" {
} "name": "PHP-FIG",
}, "homepage": "https://www.php-fig.org/"
"notification-url": "https://packagist.org/downloads/", }
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
}
],
"description": "Functions for making sense out of URIs.",
"homepage": "http://sabre.io/uri/",
"keywords": [
"rfc3986",
"uri",
"url"
]
},
{
"name": "sabre/xml",
"version": "1.5.0",
"version_normalized": "1.5.0.0",
"source": {
"type": "git",
"url": "https://github.com/fruux/sabre-xml.git",
"reference": "59b20e5bbace9912607481634f97d05a776ffca7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fruux/sabre-xml/zipball/59b20e5bbace9912607481634f97d05a776ffca7",
"reference": "59b20e5bbace9912607481634f97d05a776ffca7",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-xmlreader": "*",
"ext-xmlwriter": "*",
"lib-libxml": ">=2.6.20",
"php": ">=5.5.5",
"sabre/uri": ">=1.0,<3.0.0"
},
"require-dev": {
"phpunit/phpunit": "*",
"sabre/cs": "~1.0.0"
},
"time": "2016-10-09T22:57:52+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Sabre\\Xml\\": "lib/"
},
"files": [
"lib/Deserializer/functions.php",
"lib/Serializer/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
},
{
"name": "Markus Staab",
"email": "markus.staab@redaxo.de",
"role": "Developer"
}
],
"description": "sabre/xml is an XML library that you may not hate.",
"homepage": "https://sabre.io/xml/",
"keywords": [
"XMLReader",
"XMLWriter",
"dom",
"xml"
]
},
{
"name": "sabre/vobject",
"version": "4.1.2",
"version_normalized": "4.1.2.0",
"source": {
"type": "git",
"url": "https://github.com/fruux/sabre-vobject.git",
"reference": "d0fde2fafa2a3dad1f559c2d1c2591d4fd75ae3c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fruux/sabre-vobject/zipball/d0fde2fafa2a3dad1f559c2d1c2591d4fd75ae3c",
"reference": "d0fde2fafa2a3dad1f559c2d1c2591d4fd75ae3c",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": ">=5.5",
"sabre/xml": ">=1.5 <3.0"
},
"require-dev": {
"phpunit/phpunit": "*",
"sabre/cs": "^1.0.0"
},
"suggest": {
"hoa/bench": "If you would like to run the benchmark scripts"
},
"time": "2016-12-06T04:14:09+00:00",
"bin": [
"bin/vobject",
"bin/generate_vcards"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Sabre\\VObject\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
},
{
"name": "Dominik Tobschall",
"email": "dominik@fruux.com",
"homepage": "http://tobschall.de/",
"role": "Developer"
},
{
"name": "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net",
"homepage": "http://mnt.io/",
"role": "Developer"
}
],
"description": "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects",
"homepage": "http://sabre.io/vobject/",
"keywords": [
"availability",
"freebusy",
"iCalendar",
"ical",
"ics",
"jCal",
"jCard",
"recurrence",
"rfc2425",
"rfc2426",
"rfc2739",
"rfc4770",
"rfc5545",
"rfc5546",
"rfc6321",
"rfc6350",
"rfc6351",
"rfc6474",
"rfc6638",
"rfc6715",
"rfc6868",
"vCalendar",
"vCard",
"vcf",
"xCal",
"xCard"
]
},
{
"name": "sabre/event",
"version": "3.0.0",
"version_normalized": "3.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/fruux/sabre-event.git",
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fruux/sabre-event/zipball/831d586f5a442dceacdcf5e9c4c36a4db99a3534",
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534",
"shasum": ""
},
"require": {
"php": ">=5.5"
},
"require-dev": {
"phpunit/phpunit": "*",
"sabre/cs": "~0.0.4"
},
"time": "2015-11-05T20:14:39+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Sabre\\Event\\": "lib/"
},
"files": [
"lib/coroutine.php",
"lib/Loop/functions.php",
"lib/Promise/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
}
],
"description": "sabre/event is a library for lightweight event-based programming",
"homepage": "http://sabre.io/event/",
"keywords": [
"EventEmitter",
"async",
"events",
"hooks",
"plugin",
"promise",
"signal"
]
},
{
"name": "sabre/http",
"version": "4.2.2",
"version_normalized": "4.2.2.0",
"source": {
"type": "git",
"url": "https://github.com/fruux/sabre-http.git",
"reference": "dd50e7260356f4599d40270826f9548b23efa204"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fruux/sabre-http/zipball/dd50e7260356f4599d40270826f9548b23efa204",
"reference": "dd50e7260356f4599d40270826f9548b23efa204",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-mbstring": "*",
"php": ">=5.4",
"sabre/event": ">=1.0.0,<4.0.0",
"sabre/uri": "~1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.3",
"sabre/cs": "~0.0.1"
},
"suggest": {
"ext-curl": " to make http requests with the Client class"
},
"time": "2017-01-02T19:38:42+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"files": [
"lib/functions.php"
], ],
"psr-4": { "description": "Common interface for logging libraries",
"Sabre\\HTTP\\": "lib/" "homepage": "https://github.com/php-fig/log",
} "keywords": [
"log",
"psr",
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.4"
},
"install-path": "../psr/log"
}, },
"notification-url": "https://packagist.org/downloads/", {
"license": [ "name": "sabre/dav",
"BSD-3-Clause" "version": "4.6.0",
], "version_normalized": "4.6.0.0",
"authors": [ "source": {
{ "type": "git",
"name": "Evert Pot", "url": "https://github.com/sabre-io/dav.git",
"email": "me@evertpot.com", "reference": "554145304b4a026477d130928d16e626939b0b2a"
"homepage": "http://evertpot.com/", },
"role": "Developer" "dist": {
} "type": "zip",
], "url": "https://api.github.com/repos/sabre-io/dav/zipball/554145304b4a026477d130928d16e626939b0b2a",
"description": "The sabre/http library provides utilities for dealing with http requests and responses. ", "reference": "554145304b4a026477d130928d16e626939b0b2a",
"homepage": "https://github.com/fruux/sabre-http", "shasum": ""
"keywords": [ },
"http" "require": {
] "ext-ctype": "*",
}, "ext-date": "*",
{ "ext-dom": "*",
"name": "psr/log", "ext-iconv": "*",
"version": "1.0.2", "ext-json": "*",
"version_normalized": "1.0.2.0", "ext-mbstring": "*",
"source": { "ext-pcre": "*",
"type": "git", "ext-simplexml": "*",
"url": "https://github.com/php-fig/log.git", "ext-spl": "*",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" "lib-libxml": ">=2.7.0",
"php": "^7.1.0 || ^8.0",
"psr/log": "^1.0 || ^2.0 || ^3.0",
"sabre/event": "^5.0",
"sabre/http": "^5.0.5",
"sabre/uri": "^2.0",
"sabre/vobject": "^4.2.1",
"sabre/xml": "^2.0.1"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.19",
"monolog/monolog": "^1.27 || ^2.0",
"phpstan/phpstan": "^0.12 || ^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6"
},
"suggest": {
"ext-curl": "*",
"ext-imap": "*",
"ext-pdo": "*"
},
"time": "2023-12-11T13:01:23+00:00",
"bin": [
"bin/sabredav",
"bin/naturalselection"
],
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Sabre\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
}
],
"description": "WebDAV Framework for PHP",
"homepage": "http://sabre.io/",
"keywords": [
"CalDAV",
"CardDAV",
"WebDAV",
"framework",
"iCalendar"
],
"support": {
"forum": "https://groups.google.com/group/sabredav-discuss",
"issues": "https://github.com/sabre-io/dav/issues",
"source": "https://github.com/fruux/sabre-dav"
},
"install-path": "../sabre/dav"
}, },
"dist": { {
"type": "zip", "name": "sabre/event",
"url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", "version": "5.1.4",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", "version_normalized": "5.1.4.0",
"shasum": "" "source": {
"type": "git",
"url": "https://github.com/sabre-io/event.git",
"reference": "d7da22897125d34d7eddf7977758191c06a74497"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/event/zipball/d7da22897125d34d7eddf7977758191c06a74497",
"reference": "d7da22897125d34d7eddf7977758191c06a74497",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.17.1",
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
},
"time": "2021-11-04T06:51:17+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"files": [
"lib/coroutine.php",
"lib/Loop/functions.php",
"lib/Promise/functions.php"
],
"psr-4": {
"Sabre\\Event\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
}
],
"description": "sabre/event is a library for lightweight event-based programming",
"homepage": "http://sabre.io/event/",
"keywords": [
"EventEmitter",
"async",
"coroutine",
"eventloop",
"events",
"hooks",
"plugin",
"promise",
"reactor",
"signal"
],
"support": {
"forum": "https://groups.google.com/group/sabredav-discuss",
"issues": "https://github.com/sabre-io/event/issues",
"source": "https://github.com/fruux/sabre-event"
},
"install-path": "../sabre/event"
}, },
"require": { {
"php": ">=5.3.0" "name": "sabre/http",
"version": "5.1.10",
"version_normalized": "5.1.10.0",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/http.git",
"reference": "f9f3d1fba8916fa2f4ec25636c4fedc26cb94e02"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/http/zipball/f9f3d1fba8916fa2f4ec25636c4fedc26cb94e02",
"reference": "f9f3d1fba8916fa2f4ec25636c4fedc26cb94e02",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-curl": "*",
"ext-mbstring": "*",
"php": "^7.1 || ^8.0",
"sabre/event": ">=4.0 <6.0",
"sabre/uri": "^2.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.17.1",
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
},
"suggest": {
"ext-curl": " to make http requests with the Client class"
},
"time": "2023-08-18T01:55:28+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"files": [
"lib/functions.php"
],
"psr-4": {
"Sabre\\HTTP\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
}
],
"description": "The sabre/http library provides utilities for dealing with http requests and responses. ",
"homepage": "https://github.com/fruux/sabre-http",
"keywords": [
"http"
],
"support": {
"forum": "https://groups.google.com/group/sabredav-discuss",
"issues": "https://github.com/sabre-io/http/issues",
"source": "https://github.com/fruux/sabre-http"
},
"install-path": "../sabre/http"
}, },
"time": "2016-10-10T12:19:37+00:00", {
"type": "library", "name": "sabre/uri",
"extra": { "version": "2.2.4",
"branch-alias": { "version_normalized": "2.2.4.0",
"dev-master": "1.0.x-dev" "source": {
} "type": "git",
"url": "https://github.com/sabre-io/uri.git",
"reference": "c0c9af9f7754e60a49ebd760e1708adc6d1510c0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/uri/zipball/c0c9af9f7754e60a49ebd760e1708adc6d1510c0",
"reference": "c0c9af9f7754e60a49ebd760e1708adc6d1510c0",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.19.3",
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
},
"time": "2022-09-19T12:25:28+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"files": [
"lib/functions.php"
],
"psr-4": {
"Sabre\\Uri\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
}
],
"description": "Functions for making sense out of URIs.",
"homepage": "http://sabre.io/uri/",
"keywords": [
"rfc3986",
"uri",
"url"
],
"support": {
"forum": "https://groups.google.com/group/sabredav-discuss",
"issues": "https://github.com/sabre-io/uri/issues",
"source": "https://github.com/fruux/sabre-uri"
},
"install-path": "../sabre/uri"
}, },
"installation-source": "dist", {
"autoload": { "name": "sabre/vobject",
"psr-4": { "version": "4.5.4",
"Psr\\Log\\": "Psr/Log/" "version_normalized": "4.5.4.0",
} "source": {
"type": "git",
"url": "https://github.com/sabre-io/vobject.git",
"reference": "a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772",
"reference": "a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^7.1 || ^8.0",
"sabre/xml": "^2.1 || ^3.0 || ^4.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.17.1",
"phpstan/phpstan": "^0.12",
"phpunit/php-invoker": "^2.0 || ^3.1",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
},
"suggest": {
"hoa/bench": "If you would like to run the benchmark scripts"
},
"time": "2023-11-09T12:54:37+00:00",
"bin": [
"bin/vobject",
"bin/generate_vcards"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Sabre\\VObject\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
},
{
"name": "Dominik Tobschall",
"email": "dominik@fruux.com",
"homepage": "http://tobschall.de/",
"role": "Developer"
},
{
"name": "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net",
"homepage": "http://mnt.io/",
"role": "Developer"
}
],
"description": "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects",
"homepage": "http://sabre.io/vobject/",
"keywords": [
"availability",
"freebusy",
"iCalendar",
"ical",
"ics",
"jCal",
"jCard",
"recurrence",
"rfc2425",
"rfc2426",
"rfc2739",
"rfc4770",
"rfc5545",
"rfc5546",
"rfc6321",
"rfc6350",
"rfc6351",
"rfc6474",
"rfc6638",
"rfc6715",
"rfc6868",
"vCalendar",
"vCard",
"vcf",
"xCal",
"xCard"
],
"support": {
"forum": "https://groups.google.com/group/sabredav-discuss",
"issues": "https://github.com/sabre-io/vobject/issues",
"source": "https://github.com/fruux/sabre-vobject"
},
"install-path": "../sabre/vobject"
}, },
"notification-url": "https://packagist.org/downloads/", {
"license": [ "name": "sabre/xml",
"MIT" "version": "2.2.6",
], "version_normalized": "2.2.6.0",
"authors": [ "source": {
{ "type": "git",
"name": "PHP-FIG", "url": "https://github.com/sabre-io/xml.git",
"homepage": "http://www.php-fig.org/" "reference": "9cde7cdab1e50893cc83b037b40cd47bfde42a2b"
} },
], "dist": {
"description": "Common interface for logging libraries", "type": "zip",
"homepage": "https://github.com/php-fig/log", "url": "https://api.github.com/repos/sabre-io/xml/zipball/9cde7cdab1e50893cc83b037b40cd47bfde42a2b",
"keywords": [ "reference": "9cde7cdab1e50893cc83b037b40cd47bfde42a2b",
"log", "shasum": ""
"psr", },
"psr-3" "require": {
] "ext-dom": "*",
}, "ext-xmlreader": "*",
{ "ext-xmlwriter": "*",
"name": "sabre/dav", "lib-libxml": ">=2.6.20",
"version": "3.2.2", "php": "^7.1 || ^8.0",
"version_normalized": "3.2.2.0", "sabre/uri": ">=1.0,<3.0.0"
"source": { },
"type": "git", "require-dev": {
"url": "https://github.com/fruux/sabre-dav.git", "friendsofphp/php-cs-fixer": "~2.17.1",
"reference": "e987775e619728f12205606c9cc3ee565ffb1516" "phpstan/phpstan": "^0.12",
}, "phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
"dist": { },
"type": "zip", "time": "2023-06-28T12:56:05+00:00",
"url": "https://api.github.com/repos/fruux/sabre-dav/zipball/e987775e619728f12205606c9cc3ee565ffb1516", "type": "library",
"reference": "e987775e619728f12205606c9cc3ee565ffb1516", "installation-source": "dist",
"shasum": "" "autoload": {
}, "files": [
"require": { "lib/Deserializer/functions.php",
"ext-ctype": "*", "lib/Serializer/functions.php"
"ext-date": "*", ],
"ext-dom": "*", "psr-4": {
"ext-iconv": "*", "Sabre\\Xml\\": "lib/"
"ext-mbstring": "*", }
"ext-pcre": "*", },
"ext-simplexml": "*", "notification-url": "https://packagist.org/downloads/",
"ext-spl": "*", "license": [
"lib-libxml": ">=2.7.0", "BSD-3-Clause"
"php": ">=5.5.0", ],
"psr/log": "^1.0", "authors": [
"sabre/event": ">=2.0.0, <4.0.0", {
"sabre/http": "^4.2.1", "name": "Evert Pot",
"sabre/uri": "^1.0.1", "email": "me@evertpot.com",
"sabre/vobject": "^4.1.0", "homepage": "http://evertpot.com/",
"sabre/xml": "^1.4.0" "role": "Developer"
}, },
"require-dev": { {
"evert/phpdoc-md": "~0.1.0", "name": "Markus Staab",
"monolog/monolog": "^1.18", "email": "markus.staab@redaxo.de",
"phpunit/phpunit": "> 4.8, <6.0.0", "role": "Developer"
"sabre/cs": "^1.0.0" }
}, ],
"suggest": { "description": "sabre/xml is an XML library that you may not hate.",
"ext-curl": "*", "homepage": "https://sabre.io/xml/",
"ext-pdo": "*" "keywords": [
}, "XMLReader",
"time": "2017-02-15T03:06:08+00:00", "XMLWriter",
"bin": [ "dom",
"bin/sabredav", "xml"
"bin/naturalselection" ],
], "support": {
"type": "library", "forum": "https://groups.google.com/group/sabredav-discuss",
"extra": { "issues": "https://github.com/sabre-io/xml/issues",
"branch-alias": { "source": "https://github.com/fruux/sabre-xml"
"dev-master": "3.1.0-dev" },
} "install-path": "../sabre/xml"
}, }
"installation-source": "dist", ],
"autoload": { "dev": false,
"psr-4": { "dev-package-names": []
"Sabre\\DAV\\": "lib/DAV/", }
"Sabre\\DAVACL\\": "lib/DAVACL/",
"Sabre\\CalDAV\\": "lib/CalDAV/",
"Sabre\\CardDAV\\": "lib/CardDAV/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Evert Pot",
"email": "me@evertpot.com",
"homepage": "http://evertpot.com/",
"role": "Developer"
}
],
"description": "WebDAV Framework for PHP",
"homepage": "http://sabre.io/",
"keywords": [
"CalDAV",
"CardDAV",
"WebDAV",
"framework",
"iCalendar"
]
}
]

View File

@@ -0,0 +1,86 @@
<?php return array(
'root' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => 'a2df2f2553a3f36892665f58c0e5a115a4d56038',
'name' => '__root__',
'dev' => false,
),
'versions' => array(
'__root__' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => 'a2df2f2553a3f36892665f58c0e5a115a4d56038',
'dev_requirement' => false,
),
'psr/log' => array(
'pretty_version' => '1.1.4',
'version' => '1.1.4.0',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/log',
'aliases' => array(),
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
'dev_requirement' => false,
),
'sabre/dav' => array(
'pretty_version' => '4.6.0',
'version' => '4.6.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sabre/dav',
'aliases' => array(),
'reference' => '554145304b4a026477d130928d16e626939b0b2a',
'dev_requirement' => false,
),
'sabre/event' => array(
'pretty_version' => '5.1.4',
'version' => '5.1.4.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sabre/event',
'aliases' => array(),
'reference' => 'd7da22897125d34d7eddf7977758191c06a74497',
'dev_requirement' => false,
),
'sabre/http' => array(
'pretty_version' => '5.1.10',
'version' => '5.1.10.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sabre/http',
'aliases' => array(),
'reference' => 'f9f3d1fba8916fa2f4ec25636c4fedc26cb94e02',
'dev_requirement' => false,
),
'sabre/uri' => array(
'pretty_version' => '2.2.4',
'version' => '2.2.4.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sabre/uri',
'aliases' => array(),
'reference' => 'c0c9af9f7754e60a49ebd760e1708adc6d1510c0',
'dev_requirement' => false,
),
'sabre/vobject' => array(
'pretty_version' => '4.5.4',
'version' => '4.5.4.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sabre/vobject',
'aliases' => array(),
'reference' => 'a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772',
'dev_requirement' => false,
),
'sabre/xml' => array(
'pretty_version' => '2.2.6',
'version' => '2.2.6.0',
'type' => 'library',
'install_path' => __DIR__ . '/../sabre/xml',
'aliases' => array(),
'reference' => '9cde7cdab1e50893cc83b037b40cd47bfde42a2b',
'dev_requirement' => false,
),
),
);

View File

@@ -0,0 +1,26 @@
<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 70100)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.1.0". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
} elseif (!headers_sent()) {
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
}
}
trigger_error(
'Composer detected issues in your platform: ' . implode(' ', $issues),
E_USER_ERROR
);
}

View File

@@ -1 +0,0 @@
vendor

View File

@@ -14,8 +14,8 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* System is unusable. * System is unusable.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -30,8 +30,8 @@ abstract class AbstractLogger implements LoggerInterface
* Example: Entire website down, database unavailable, etc. This should * Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up. * trigger the SMS alerts and wake you up.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -45,8 +45,8 @@ abstract class AbstractLogger implements LoggerInterface
* *
* Example: Application component unavailable, unexpected exception. * Example: Application component unavailable, unexpected exception.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -59,8 +59,8 @@ abstract class AbstractLogger implements LoggerInterface
* Runtime errors that do not require immediate action but should typically * Runtime errors that do not require immediate action but should typically
* be logged and monitored. * be logged and monitored.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -75,8 +75,8 @@ abstract class AbstractLogger implements LoggerInterface
* Example: Use of deprecated APIs, poor use of an API, undesirable things * Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong. * that are not necessarily wrong.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -88,8 +88,8 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* Normal but significant events. * Normal but significant events.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -103,8 +103,8 @@ abstract class AbstractLogger implements LoggerInterface
* *
* Example: User logs in, SQL logs. * Example: User logs in, SQL logs.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -116,8 +116,8 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* Detailed debug information. * Detailed debug information.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */

View File

@@ -10,7 +10,7 @@ trait LoggerAwareTrait
/** /**
* The logger instance. * The logger instance.
* *
* @var LoggerInterface * @var LoggerInterface|null
*/ */
protected $logger; protected $logger;

View File

@@ -22,8 +22,8 @@ interface LoggerInterface
/** /**
* System is unusable. * System is unusable.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -35,8 +35,8 @@ interface LoggerInterface
* Example: Entire website down, database unavailable, etc. This should * Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up. * trigger the SMS alerts and wake you up.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -47,8 +47,8 @@ interface LoggerInterface
* *
* Example: Application component unavailable, unexpected exception. * Example: Application component unavailable, unexpected exception.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -58,8 +58,8 @@ interface LoggerInterface
* Runtime errors that do not require immediate action but should typically * Runtime errors that do not require immediate action but should typically
* be logged and monitored. * be logged and monitored.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -71,8 +71,8 @@ interface LoggerInterface
* Example: Use of deprecated APIs, poor use of an API, undesirable things * Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong. * that are not necessarily wrong.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -81,8 +81,8 @@ interface LoggerInterface
/** /**
* Normal but significant events. * Normal but significant events.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -93,8 +93,8 @@ interface LoggerInterface
* *
* Example: User logs in, SQL logs. * Example: User logs in, SQL logs.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -103,8 +103,8 @@ interface LoggerInterface
/** /**
* Detailed debug information. * Detailed debug information.
* *
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*/ */
@@ -113,11 +113,13 @@ interface LoggerInterface
/** /**
* Logs with an arbitrary level. * Logs with an arbitrary level.
* *
* @param mixed $level * @param mixed $level
* @param string $message * @param string $message
* @param array $context * @param mixed[] $context
* *
* @return void * @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/ */
public function log($level, $message, array $context = array()); public function log($level, $message, array $context = array());
} }

View File

@@ -135,6 +135,8 @@ trait LoggerTrait
* @param array $context * @param array $context
* *
* @return void * @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/ */
abstract public function log($level, $message, array $context = array()); abstract public function log($level, $message, array $context = array());
} }

View File

@@ -20,6 +20,8 @@ class NullLogger extends AbstractLogger
* @param array $context * @param array $context
* *
* @return void * @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/ */
public function log($level, $message, array $context = array()) public function log($level, $message, array $context = array())
{ {

View File

@@ -0,0 +1,18 @@
<?php
namespace Psr\Log\Test;
/**
* This class is internal and does not follow the BC promise.
*
* Do NOT use this class in any way.
*
* @internal
*/
class DummyTest
{
public function __toString()
{
return 'DummyTest';
}
}

View File

@@ -4,6 +4,7 @@ namespace Psr\Log\Test;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
use PHPUnit\Framework\TestCase;
/** /**
* Provides a base test class for ensuring compliance with the LoggerInterface. * Provides a base test class for ensuring compliance with the LoggerInterface.
@@ -11,7 +12,7 @@ use Psr\Log\LogLevel;
* Implementors can extend the class and implement abstract methods to run this * Implementors can extend the class and implement abstract methods to run this
* as part of their test suite. * as part of their test suite.
*/ */
abstract class LoggerInterfaceTest extends \PHPUnit_Framework_TestCase abstract class LoggerInterfaceTest extends TestCase
{ {
/** /**
* @return LoggerInterface * @return LoggerInterface
@@ -101,6 +102,9 @@ abstract class LoggerInterfaceTest extends \PHPUnit_Framework_TestCase
public function testContextCanContainAnything() public function testContextCanContainAnything()
{ {
$closed = fopen('php://memory', 'r');
fclose($closed);
$context = array( $context = array(
'bool' => true, 'bool' => true,
'null' => null, 'null' => null,
@@ -110,6 +114,7 @@ abstract class LoggerInterfaceTest extends \PHPUnit_Framework_TestCase
'nested' => array('with object' => new DummyTest), 'nested' => array('with object' => new DummyTest),
'object' => new \DateTime, 'object' => new \DateTime,
'resource' => fopen('php://memory', 'r'), 'resource' => fopen('php://memory', 'r'),
'closed' => $closed,
); );
$this->getLogger()->warning('Crazy context data', $context); $this->getLogger()->warning('Crazy context data', $context);
@@ -131,10 +136,3 @@ abstract class LoggerInterfaceTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($expected, $this->getLogs()); $this->assertEquals($expected, $this->getLogs());
} }
} }
class DummyTest
{
public function __toString()
{
}
}

View File

@@ -0,0 +1,147 @@
<?php
namespace Psr\Log\Test;
use Psr\Log\AbstractLogger;
/**
* Used for testing purposes.
*
* It records all records and gives you access to them for verification.
*
* @method bool hasEmergency($record)
* @method bool hasAlert($record)
* @method bool hasCritical($record)
* @method bool hasError($record)
* @method bool hasWarning($record)
* @method bool hasNotice($record)
* @method bool hasInfo($record)
* @method bool hasDebug($record)
*
* @method bool hasEmergencyRecords()
* @method bool hasAlertRecords()
* @method bool hasCriticalRecords()
* @method bool hasErrorRecords()
* @method bool hasWarningRecords()
* @method bool hasNoticeRecords()
* @method bool hasInfoRecords()
* @method bool hasDebugRecords()
*
* @method bool hasEmergencyThatContains($message)
* @method bool hasAlertThatContains($message)
* @method bool hasCriticalThatContains($message)
* @method bool hasErrorThatContains($message)
* @method bool hasWarningThatContains($message)
* @method bool hasNoticeThatContains($message)
* @method bool hasInfoThatContains($message)
* @method bool hasDebugThatContains($message)
*
* @method bool hasEmergencyThatMatches($message)
* @method bool hasAlertThatMatches($message)
* @method bool hasCriticalThatMatches($message)
* @method bool hasErrorThatMatches($message)
* @method bool hasWarningThatMatches($message)
* @method bool hasNoticeThatMatches($message)
* @method bool hasInfoThatMatches($message)
* @method bool hasDebugThatMatches($message)
*
* @method bool hasEmergencyThatPasses($message)
* @method bool hasAlertThatPasses($message)
* @method bool hasCriticalThatPasses($message)
* @method bool hasErrorThatPasses($message)
* @method bool hasWarningThatPasses($message)
* @method bool hasNoticeThatPasses($message)
* @method bool hasInfoThatPasses($message)
* @method bool hasDebugThatPasses($message)
*/
class TestLogger extends AbstractLogger
{
/**
* @var array
*/
public $records = [];
public $recordsByLevel = [];
/**
* @inheritdoc
*/
public function log($level, $message, array $context = [])
{
$record = [
'level' => $level,
'message' => $message,
'context' => $context,
];
$this->recordsByLevel[$record['level']][] = $record;
$this->records[] = $record;
}
public function hasRecords($level)
{
return isset($this->recordsByLevel[$level]);
}
public function hasRecord($record, $level)
{
if (is_string($record)) {
$record = ['message' => $record];
}
return $this->hasRecordThatPasses(function ($rec) use ($record) {
if ($rec['message'] !== $record['message']) {
return false;
}
if (isset($record['context']) && $rec['context'] !== $record['context']) {
return false;
}
return true;
}, $level);
}
public function hasRecordThatContains($message, $level)
{
return $this->hasRecordThatPasses(function ($rec) use ($message) {
return strpos($rec['message'], $message) !== false;
}, $level);
}
public function hasRecordThatMatches($regex, $level)
{
return $this->hasRecordThatPasses(function ($rec) use ($regex) {
return preg_match($regex, $rec['message']) > 0;
}, $level);
}
public function hasRecordThatPasses(callable $predicate, $level)
{
if (!isset($this->recordsByLevel[$level])) {
return false;
}
foreach ($this->recordsByLevel[$level] as $i => $rec) {
if (call_user_func($predicate, $rec, $i)) {
return true;
}
}
return false;
}
public function __call($method, $args)
{
if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) {
$genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3];
$level = strtolower($matches[2]);
if (method_exists($this, $genericMethod)) {
$args[] = $level;
return call_user_func_array([$this, $genericMethod], $args);
}
}
throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()');
}
public function reset()
{
$this->records = [];
$this->recordsByLevel = [];
}
}

View File

@@ -7,6 +7,13 @@ This repository holds all interfaces/classes/traits related to
Note that this is not a logger of its own. It is merely an interface that Note that this is not a logger of its own. It is merely an interface that
describes a logger. See the specification for more details. describes a logger. See the specification for more details.
Installation
------------
```bash
composer require psr/log
```
Usage Usage
----- -----
@@ -31,6 +38,12 @@ class Foo
if ($this->logger) { if ($this->logger) {
$this->logger->info('Doing work'); $this->logger->info('Doing work');
} }
try {
$this->doSomethingElse();
} catch (Exception $exception) {
$this->logger->error('Oh no!', array('exception' => $exception));
}
// do something useful // do something useful
} }

View File

@@ -7,7 +7,7 @@
"authors": [ "authors": [
{ {
"name": "PHP-FIG", "name": "PHP-FIG",
"homepage": "http://www.php-fig.org/" "homepage": "https://www.php-fig.org/"
} }
], ],
"require": { "require": {
@@ -20,7 +20,7 @@
}, },
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0.x-dev" "dev-master": "1.1.x-dev"
} }
} }
} }

View File

@@ -1,73 +0,0 @@
language: php
sudo: required
branches:
only:
- master
php:
- 7.1
- 7.2
- 7.3
- 7.4
env:
global:
- SABRE_MYSQLUSER="root"
- SABRE_MYSQLPASS=""
- SABRE_MYSQLDSN="mysql:host=127.0.0.1;dbname=sabredav_test"
- RUN_PHPCSFIXER="TRUE"
- RUN_PHPUNIT="TRUE"
- RUN_PHPSTAN="FALSE"
matrix:
- PREFER_LOWEST="" TEST_DEPS="" REPORT_COVERAGE="TRUE" WITH_COVERAGE="--coverage-clover=coverage.xml"
- PREFER_LOWEST="--prefer-lowest" TEST_DEPS="tests/Sabre/" REPORT_COVERAGE="FALSE" WITH_COVERAGE=""
matrix:
include:
- name: 'PHP8'
dist: bionic
php: 8.0
env:
- RUN_PHPCSFIXER="FALSE"
- REPORT_COVERAGE="FALSE"
- name: 'PHPStan'
php: 7.4
env:
- RUN_PHPCSFIXER="FALSE"
- RUN_PHPUNIT="FALSE"
- RUN_PHPSTAN="TRUE"
- REPORT_COVERAGE="FALSE"
- name: 'Test with streaming propfind'
php: 7.2
env:
- RUN_TEST_WITH_STREAMING_PROPFIND="TRUE"
- REPORT_COVERAGE="FALSE"
fast_finish: true
services:
- mysql
- postgresql
before_script:
- mysql -u root -h 127.0.0.1 -e 'create database sabredav_test'
- psql -c "create database sabredav_test" -U postgres
- psql -c "create user sabredav with PASSWORD 'sabredav';GRANT ALL PRIVILEGES ON DATABASE sabredav_test TO sabredav" -U postgres
- if [ $RUN_PHPCSFIXER == "FALSE" ]; then composer remove --no-update --dev friendsofphp/php-cs-fixer; fi
- composer update $PREFER_LOWEST
addons:
postgresql: "9.5"
script:
- if [ $RUN_PHPCSFIXER == "TRUE" ]; then php vendor/bin/php-cs-fixer fix --dry-run --diff; fi
- if [ $RUN_PHPUNIT == "TRUE" ]; then php vendor/bin/phpunit --configuration tests/phpunit.xml $WITH_COVERAGE $TEST_DEPS; fi
- if [ $RUN_PHPUNIT == "TRUE" ]; then rm -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini; fi
- if [ $RUN_PHPSTAN == "TRUE" ]; then composer phpstan; fi
after_success:
- if [ $REPORT_COVERAGE == "TRUE" ]; then bash <(curl -s https://codecov.io/bash); fi
cache:
directories:
- $HOME/.composer/cache

View File

@@ -15,11 +15,11 @@
], ],
"require": { "require": {
"php": "^7.1.0 || ^8.0", "php": "^7.1.0 || ^8.0",
"sabre/vobject": "^4.5.1", "sabre/vobject": "^4.2.1",
"sabre/event" : "^5.0.0", "sabre/event" : "^5.0",
"sabre/xml" : "^2.5.5", "sabre/xml" : "^2.0.1",
"sabre/http" : "^5.0.5", "sabre/http" : "^5.0.5",
"sabre/uri" : "^2.2.3", "sabre/uri" : "^2.0",
"ext-dom": "*", "ext-dom": "*",
"ext-pcre": "*", "ext-pcre": "*",
"ext-spl": "*", "ext-spl": "*",
@@ -33,11 +33,11 @@
"ext-json": "*" "ext-json": "*"
}, },
"require-dev" : { "require-dev" : {
"friendsofphp/php-cs-fixer": "^2.17.1", "friendsofphp/php-cs-fixer": "^2.19",
"phpstan/phpstan": "^0.12", "monolog/monolog": "^1.27 || ^2.0",
"phpunit/phpunit" : "^7.5 || ^8.5 || ^9.0", "phpstan/phpstan": "^0.12 || ^1.0",
"evert/phpdoc-md" : "~0.1.0", "phpstan/phpstan-phpunit": "^1.0",
"monolog/monolog": "^1.18" "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6"
}, },
"suggest" : { "suggest" : {
"ext-curl" : "*", "ext-curl" : "*",
@@ -46,21 +46,12 @@
}, },
"autoload": { "autoload": {
"psr-4" : { "psr-4" : {
"Sabre\\DAV\\" : "lib/DAV/", "Sabre\\" : "lib/"
"Sabre\\DAVACL\\" : "lib/DAVACL/",
"Sabre\\CalDAV\\" : "lib/CalDAV/",
"Sabre\\CardDAV\\" : "lib/CardDAV/"
} }
}, },
"autoload-dev" : { "autoload-dev" : {
"psr-4" : { "psr-4" : {
"Sabre\\" : "tests/Sabre/", "Sabre\\" : "tests/Sabre/"
"Sabre\\CalDAV\\" : "tests/Sabre/CalDAV",
"Sabre\\CardDAV\\" : "tests/Sabre/CardDAV",
"Sabre\\DAV\\" : "tests/Sabre/DAV",
"Sabre\\DAV\\Property\\" : "tests/Sabre/DAV/Xml/Property",
"Sabre\\DAVACL\\" : "tests/Sabre/DAVACL",
"Sabre\\HTTP\\" : "tests/Sabre/HTTP"
} }
}, },
"support" : { "support" : {

View File

@@ -78,7 +78,7 @@ abstract class AbstractBackend implements BackendInterface
* *
* This default may well be good enough for personal use, and calendars * This default may well be good enough for personal use, and calendars
* that aren't very large. But if you anticipate high usage, big calendars * that aren't very large. But if you anticipate high usage, big calendars
* or high loads, you are strongly adviced to optimize certain paths. * or high loads, you are strongly advised to optimize certain paths.
* *
* The best way to do so is override this method and to optimize * The best way to do so is override this method and to optimize
* specifically for 'common filters'. * specifically for 'common filters'.
@@ -95,7 +95,7 @@ abstract class AbstractBackend implements BackendInterface
* Note that especially time-range-filters may be difficult to parse. A * Note that especially time-range-filters may be difficult to parse. A
* time-range filter specified on a VEVENT must for instance also handle * time-range filter specified on a VEVENT must for instance also handle
* recurrence rules correctly. * recurrence rules correctly.
* A good example of how to interprete all these filters can also simply * A good example of how to interpret all these filters can also simply
* be found in \Sabre\CalDAV\CalendarQueryFilter. This class is as correct * be found in \Sabre\CalDAV\CalendarQueryFilter. This class is as correct
* as possible, so it gives you a good idea on what type of stuff you need * as possible, so it gives you a good idea on what type of stuff you need
* to think of. * to think of.

View File

@@ -939,7 +939,7 @@ SQL;
* @param int $syncLevel * @param int $syncLevel
* @param int $limit * @param int $limit
* *
* @return array * @return array|null
*/ */
public function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit = null) public function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit = null)
{ {

View File

@@ -77,7 +77,7 @@ interface SyncSupport extends BackendInterface
* @param int $syncLevel * @param int $syncLevel
* @param int $limit * @param int $limit
* *
* @return array * @return array|null
*/ */
public function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit = null); public function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit = null);
} }

View File

@@ -186,17 +186,17 @@ class Calendar implements ICalendar, DAV\IProperties, DAV\Sync\ISyncCollection,
* The contents of the new file must be a valid ICalendar string. * The contents of the new file must be a valid ICalendar string.
* *
* @param string $name * @param string $name
* @param resource $calendarData * @param resource $data
* *
* @return string|null * @return string|null
*/ */
public function createFile($name, $calendarData = null) public function createFile($name, $data = null)
{ {
if (is_resource($calendarData)) { if (is_resource($data)) {
$calendarData = stream_get_contents($calendarData); $data = stream_get_contents($data);
} }
return $this->caldavBackend->createCalendarObject($this->calendarInfo['id'], $name, $calendarData); return $this->caldavBackend->createCalendarObject($this->calendarInfo['id'], $name, $data);
} }
/** /**
@@ -442,7 +442,7 @@ class Calendar implements ICalendar, DAV\IProperties, DAV\Sync\ISyncCollection,
* @param int $syncLevel * @param int $syncLevel
* @param int $limit * @param int $limit
* *
* @return array * @return array|null
*/ */
public function getChanges($syncToken, $syncLevel, $limit = null) public function getChanges($syncToken, $syncLevel, $limit = null)
{ {

View File

@@ -96,10 +96,10 @@ class CalendarHome implements DAV\IExtendedCollection, DAVACL\IACL
* *
* This is currently not allowed * This is currently not allowed
* *
* @param string $filename * @param string $name
* @param resource $data * @param resource $data
*/ */
public function createFile($filename, $data = null) public function createFile($name, $data = null)
{ {
throw new DAV\Exception\MethodNotAllowed('Creating new files in this collection is not supported'); throw new DAV\Exception\MethodNotAllowed('Creating new files in this collection is not supported');
} }

View File

@@ -30,13 +30,6 @@ class IMipPlugin extends DAV\ServerPlugin
*/ */
protected $senderEmail; protected $senderEmail;
/**
* ITipMessage.
*
* @var ITip\Message
*/
protected $itipMessage;
/** /**
* Creates the email handler. * Creates the email handler.
* *

View File

@@ -605,10 +605,9 @@ class Plugin extends ServerPlugin
* *
* This method may update $newObject to add any status changes. * This method may update $newObject to add any status changes.
* *
* @param VCalendar|string $oldObject * @param VCalendar|string|null $oldObject
* @param array $ignore any addresses to not send messages to * @param array $ignore any addresses to not send messages to
* @param bool $modified a marker to indicate that the original object * @param bool $modified a marker to indicate that the original object modified by this process
* modified by this process
*/ */
protected function processICalendarChange($oldObject, VCalendar $newObject, array $addresses, array $ignore = [], &$modified = false) protected function processICalendarChange($oldObject, VCalendar $newObject, array $addresses, array $ignore = [], &$modified = false)
{ {
@@ -969,7 +968,7 @@ class Plugin extends ServerPlugin
* *
* @return bool * @return bool
*/ */
private function scheduleReply(RequestInterface $request) protected function scheduleReply(RequestInterface $request)
{ {
$scheduleReply = $request->getHeader('Schedule-Reply'); $scheduleReply = $request->getHeader('Schedule-Reply');

View File

@@ -53,7 +53,7 @@ class PropFilter implements XmlDeserializable
'is-not-defined' => false, 'is-not-defined' => false,
'param-filters' => [], 'param-filters' => [],
'text-match' => null, 'text-match' => null,
'time-range' => false, 'time-range' => [],
]; ];
$att = $reader->parseAttributes(); $att = $reader->parseAttributes();

View File

@@ -129,19 +129,19 @@ class AddressBook extends DAV\Collection implements IAddressBook, DAV\IPropertie
* This method may return an ETag. * This method may return an ETag.
* *
* @param string $name * @param string $name
* @param resource $vcardData * @param resource $data
* *
* @return string|null * @return string|null
*/ */
public function createFile($name, $vcardData = null) public function createFile($name, $data = null)
{ {
if (is_resource($vcardData)) { if (is_resource($data)) {
$vcardData = stream_get_contents($vcardData); $data = stream_get_contents($data);
} }
// Converting to UTF-8, if needed // Converting to UTF-8, if needed
$vcardData = DAV\StringUtil::ensureUTF8($vcardData); $data = DAV\StringUtil::ensureUTF8($data);
return $this->carddavBackend->createCard($this->addressBookInfo['id'], $name, $vcardData); return $this->carddavBackend->createCard($this->addressBookInfo['id'], $name, $data);
} }
/** /**
@@ -317,7 +317,7 @@ class AddressBook extends DAV\Collection implements IAddressBook, DAV\IPropertie
* @param int $syncLevel * @param int $syncLevel
* @param int $limit * @param int $limit
* *
* @return array * @return array|null
*/ */
public function getChanges($syncToken, $syncLevel, $limit = null) public function getChanges($syncToken, $syncLevel, $limit = null)
{ {

View File

@@ -92,10 +92,10 @@ class AddressBookHome extends DAV\Collection implements DAV\IExtendedCollection,
* *
* This is currently not allowed * This is currently not allowed
* *
* @param string $filename * @param string $name
* @param resource $data * @param resource $data
*/ */
public function createFile($filename, $data = null) public function createFile($name, $data = null)
{ {
throw new DAV\Exception\MethodNotAllowed('Creating new files in this collection is not supported'); throw new DAV\Exception\MethodNotAllowed('Creating new files in this collection is not supported');
} }

View File

@@ -452,7 +452,7 @@ class PDO extends AbstractBackend implements SyncSupport
* @param int $syncLevel * @param int $syncLevel
* @param int $limit * @param int $limit
* *
* @return array * @return array|null
*/ */
public function getChangesForAddressBook($addressBookId, $syncToken, $syncLevel, $limit = null) public function getChangesForAddressBook($addressBookId, $syncToken, $syncLevel, $limit = null)
{ {

View File

@@ -77,7 +77,7 @@ interface SyncSupport extends BackendInterface
* @param int $syncLevel * @param int $syncLevel
* @param int $limit * @param int $limit
* *
* @return array * @return array|null
*/ */
public function getChangesForAddressBook($addressBookId, $syncToken, $syncLevel, $limit = null); public function getChangesForAddressBook($addressBookId, $syncToken, $syncLevel, $limit = null);
} }

View File

@@ -38,7 +38,7 @@ class AddressBookMultiGetReport implements XmlDeserializable
public $hrefs; public $hrefs;
/** /**
* The mimetype of the content that should be returend. Usually * The mimetype of the content that should be returned. Usually
* text/vcard. * text/vcard.
* *
* @var string * @var string
@@ -53,6 +53,13 @@ class AddressBookMultiGetReport implements XmlDeserializable
*/ */
public $version = null; public $version = null;
/**
* An array with requested vcard properties.
*
* @var array
*/
public $addressDataProperties;
/** /**
* The deserialize method is called during xml parsing. * The deserialize method is called during xml parsing.
* *

View File

@@ -173,28 +173,99 @@ class Client extends HTTP\Client
$this->propertyMap = &$this->xml->elementMap; $this->propertyMap = &$this->xml->elementMap;
} }
/**
* Does a PROPFIND request with filtered response returning only available properties.
*
* The list of requested properties must be specified as an array, in clark
* notation.
*
* Depth should be either 0 or 1. A depth of 1 will cause a request to be
* made to the server to also return all child resources.
*
* For depth 0, just the array of properties for the resource is returned.
*
* For depth 1, the returned array will contain a list of resource names as keys,
* and an array of properties as values.
*
* The array of properties will contain the properties as keys with their values as the value.
* Only properties that are actually returned from the server without error will be
* returned, anything else is discarded.
*
* @param 1|0 $depth
*/
public function propFind($url, array $properties, $depth = 0): array
{
$result = $this->doPropFind($url, $properties, $depth);
// If depth was 0, we only return the top item
if (0 === $depth) {
reset($result);
$result = current($result);
return isset($result[200]) ? $result[200] : [];
}
$newResult = [];
foreach ($result as $href => $statusList) {
$newResult[$href] = isset($statusList[200]) ? $statusList[200] : [];
}
return $newResult;
}
/**
* Does a PROPFIND request with unfiltered response.
*
* The list of requested properties must be specified as an array, in clark
* notation.
*
* Depth should be either 0 or 1. A depth of 1 will cause a request to be
* made to the server to also return all child resources.
*
* For depth 0, just the multi-level array of status and properties for the resource is returned.
*
* For depth 1, the returned array will contain a list of resources as keys and
* a multi-level array containing status and properties as value.
*
* The multi-level array of status and properties is formatted the same as what is
* documented for parseMultiStatus.
*
* All properties that are actually returned from the server are returned by this method.
*
* @param 1|0 $depth
*/
public function propFindUnfiltered(string $url, array $properties, int $depth = 0): array
{
$result = $this->doPropFind($url, $properties, $depth);
// If depth was 0, we only return the top item
if (0 === $depth) {
reset($result);
return current($result);
} else {
return $result;
}
}
/** /**
* Does a PROPFIND request. * Does a PROPFIND request.
* *
* The list of requested properties must be specified as an array, in clark * The list of requested properties must be specified as an array, in clark
* notation. * notation.
* *
* The returned array will contain a list of filenames as keys, and
* properties as values.
*
* The properties array will contain the list of properties. Only properties
* that are actually returned from the server (without error) will be
* returned, anything else is discarded.
*
* Depth should be either 0 or 1. A depth of 1 will cause a request to be * Depth should be either 0 or 1. A depth of 1 will cause a request to be
* made to the server to also return all child resources. * made to the server to also return all child resources.
* *
* @param string $url * The returned array will contain a list of resources as keys and
* @param int $depth * a multi-level array containing status and properties as value.
* *
* @return array * The multi-level array of status and properties is formatted the same as what is
* documented for parseMultiStatus.
*
* @param 1|0 $depth
*/ */
public function propFind($url, array $properties, $depth = 0) private function doPropFind($url, array $properties, $depth = 0): array
{ {
$dom = new \DOMDocument('1.0', 'UTF-8'); $dom = new \DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true; $dom->formatOutput = true;
@@ -232,22 +303,7 @@ class Client extends HTTP\Client
throw new HTTP\ClientHttpException($response); throw new HTTP\ClientHttpException($response);
} }
$result = $this->parseMultiStatus($response->getBodyAsString()); return $this->parseMultiStatus($response->getBodyAsString());
// If depth was 0, we only return the top item
if (0 === $depth) {
reset($result);
$result = current($result);
return isset($result[200]) ? $result[200] : [];
}
$newResult = [];
foreach ($result as $href => $statusList) {
$newResult[$href] = isset($statusList[200]) ? $statusList[200] : [];
}
return $newResult;
} }
/** /**
@@ -385,7 +441,7 @@ class Client extends HTTP\Client
{ {
return Uri\resolve( return Uri\resolve(
$this->baseUri, $this->baseUri,
$url (string) $url
); );
} }

View File

@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Sabre\DAV;
/**
* INodeByPath.
*
* This interface adds a tiny bit of functionality to collections.
*
* Getting a node that is deep in the tree normally requires going trough each parent node
* which can cause a significant performance overhead.
*
* Implementing this interface allows solving this overhead by directly jumping to the target node.
*
* @copyright Copyright (C) Robin Appelman (https://icewind.nl/)
* @author Robin Appelman (https://icewind.nl/)
* @license http://sabre.io/license/ Modified BSD License
*/
interface INodeByPath
{
/**
* Returns the INode object for the requested path.
*
* In case where this collection can not retrieve the requested node
* but also can not determine that the node does not exists,
* null should be returned to signal that the caller should fallback
* to walking the directory tree.
*
* @param string $path
*
* @return INode|null
*/
public function getNodeForPath($path);
}

View File

@@ -84,7 +84,7 @@ interface ISyncCollection extends DAV\ICollection
* @param int $syncLevel * @param int $syncLevel
* @param int $limit * @param int $limit
* *
* @return array * @return array|null
*/ */
public function getChanges($syncToken, $syncLevel, $limit = null); public function getChanges($syncToken, $syncLevel, $limit = null);
} }

View File

@@ -16,7 +16,7 @@ use Sabre\Uri;
* @author Evert Pot (http://evertpot.com/) * @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License * @license http://sabre.io/license/ Modified BSD License
*/ */
class Tree class Tree implements INodeByPath
{ {
/** /**
* The root node. * The root node.
@@ -62,20 +62,26 @@ class Tree
return $this->rootNode; return $this->rootNode;
} }
// Attempting to fetch its parent $parts = explode('/', $path);
list($parentName, $baseName) = Uri\split($path); $node = $this->rootNode;
// If there was no parent, we must simply ask it from the root node. while (count($parts)) {
if ('' === $parentName) { if (!($node instanceof ICollection)) {
$node = $this->rootNode->getChild($baseName);
} else {
// Otherwise, we recursively grab the parent and ask him/her.
$parent = $this->getNodeForPath($parentName);
if (!($parent instanceof ICollection)) {
throw new Exception\NotFound('Could not find node at path: '.$path); throw new Exception\NotFound('Could not find node at path: '.$path);
} }
$node = $parent->getChild($baseName);
if ($node instanceof INodeByPath) {
$targetNode = $node->getNodeForPath(implode('/', $parts));
if ($targetNode instanceof Node) {
$node = $targetNode;
break;
}
}
$part = array_shift($parts);
if ('' !== $part) {
$node = $node->getChild($part);
}
} }
$this->cache[$path] = $node; $this->cache[$path] = $node;

View File

@@ -16,5 +16,5 @@ class Version
/** /**
* Full version number. * Full version number.
*/ */
const VERSION = '4.4.0'; public const VERSION = '4.6.0';
} }

View File

@@ -40,7 +40,7 @@ class Response implements Element
* *
* This is currently only used in WebDAV-Sync * This is currently only used in WebDAV-Sync
* *
* @var string * @var string|null
*/ */
protected $httpStatus; protected $httpStatus;
@@ -112,13 +112,21 @@ class Response implements Element
*/ */
public function xmlSerialize(Writer $writer) public function xmlSerialize(Writer $writer)
{ {
if ($status = $this->getHTTPStatus()) { /*
$writer->writeElement('{DAV:}status', 'HTTP/1.1 '.$status.' '.\Sabre\HTTP\Response::$statusCodes[$status]); * Accordingly to the RFC the element looks like:
} * <!ELEMENT response (href, ((href*, status)|(propstat+)), error?, responsedescription? , location?) >
*
* So the response
* - MUST contain a href and
* - EITHER a status and additional href(s)
* OR one or more propstat(s)
*/
$writer->writeElement('{DAV:}href', $writer->contextUri.\Sabre\HTTP\encodePath($this->getHref())); $writer->writeElement('{DAV:}href', $writer->contextUri.\Sabre\HTTP\encodePath($this->getHref()));
$empty = true; $empty = true;
$httpStatus = $this->getHTTPStatus();
// Add propstat elements
foreach ($this->getResponseProperties() as $status => $properties) { foreach ($this->getResponseProperties() as $status => $properties) {
// Skipping empty lists // Skipping empty lists
if (!$properties || (!is_int($status) && !ctype_digit($status))) { if (!$properties || (!is_int($status) && !ctype_digit($status))) {
@@ -130,19 +138,25 @@ class Response implements Element
$writer->writeElement('{DAV:}status', 'HTTP/1.1 '.$status.' '.\Sabre\HTTP\Response::$statusCodes[$status]); $writer->writeElement('{DAV:}status', 'HTTP/1.1 '.$status.' '.\Sabre\HTTP\Response::$statusCodes[$status]);
$writer->endElement(); // {DAV:}propstat $writer->endElement(); // {DAV:}propstat
} }
// The WebDAV spec only allows the status element on responses _without_ a propstat
if ($empty) { if ($empty) {
/* if (null !== $httpStatus) {
* The WebDAV spec _requires_ at least one DAV:propstat to appear for $writer->writeElement('{DAV:}status', 'HTTP/1.1 '.$httpStatus.' '.\Sabre\HTTP\Response::$statusCodes[$httpStatus]);
* every DAV:response. In some circumstances however, there are no } else {
* properties to encode. /*
* * The WebDAV spec _requires_ at least one DAV:propstat to appear for
* In those cases we MUST specify at least one DAV:propstat anyway, with * every DAV:response if there is no status.
* no properties. * In some circumstances however, there are no properties to encode.
*/ *
$writer->writeElement('{DAV:}propstat', [ * In those cases we MUST specify at least one DAV:propstat anyway, with
'{DAV:}prop' => [], * no properties.
'{DAV:}status' => 'HTTP/1.1 418 '.\Sabre\HTTP\Response::$statusCodes[418], */
]); $writer->writeElement('{DAV:}propstat', [
'{DAV:}prop' => [],
'{DAV:}status' => 'HTTP/1.1 418 '.\Sabre\HTTP\Response::$statusCodes[418],
]);
}
} }
} }

View File

@@ -34,6 +34,19 @@ class Href implements Element, HtmlOutput
*/ */
protected $hrefs; protected $hrefs;
/**
* Automatically prefix the url with the server base directory.
* Note: use of this property in code was removed in PR:
* https://github.com/sabre-io/dav/pull/801
* But the property is left here because old data may still exist
* that has this property saved.
* See discussion in issue:
* https://github.com/sabre-io/Baikal/issues/1154.
*
* @var bool
*/
protected $autoPrefix = true;
/** /**
* Constructor. * Constructor.
* *

View File

@@ -48,7 +48,7 @@ interface BackendInterface
public function getPrincipalByPath($path); public function getPrincipalByPath($path);
/** /**
* Updates one ore more webdav properties on a principal. * Updates one or more webdav properties on a principal.
* *
* The list of mutations is stored in a Sabre\DAV\PropPatch object. * The list of mutations is stored in a Sabre\DAV\PropPatch object.
* To do the actual updates, you must tell this object which properties * To do the actual updates, you must tell this object which properties

View File

@@ -1,14 +0,0 @@
#composer
vendor
composer.lock
#binaries
bin/sabre-cs-fixer
bin/php-cs-fixer
bin/phpunit
#vim lock files
.*.swp
#development stuff
tests/cov

View File

@@ -1,23 +0,0 @@
language: php
php:
- 7
matrix:
allow_failures:
- php: hhvm
env:
matrix:
- LOWEST_DEPS=""
- LOWEST_DEPS="--prefer-lowest"
before_script:
- composer update --prefer-source $LOWEST_DEPS
script:
- ./bin/phpunit
- ./bin/sabre-cs-fixer fix . --dry-run --diff
sudo: false
cache: vendor

View File

@@ -1,104 +0,0 @@
ChangeLog
=========
5.0.0 (2016-10-23)
------------------
* #42: The `coroutine` function now supports `return` in the passed generator
function. This allows you to more generally return a value. This is a BC
break as this is a feature that was only made possible with PHP 7, and
before the coroutine function would only ever return the last thing that
was yielded. If you depended on that feature, replace your last `yield` with
a `return`.
4.0.0 (2016-09-19)
------------------
* sabre/event now requires PHP 7. If you need PHP 5.5 support, just keep
using 3.0.0.
* PHP 7 type hints are now used everywhere. We're also using strict_types.
* Support for a new `WildcardEmitter` which allows you to listen for events
using the `*` wildcard.
* Removed deprecated functions `Promise::error` and `Promise::all`. Instead,
use `Promise::otherwise` and `Promise\all()`.
* `EventEmitter`, `EventEmitterTrait` and `EventEmitterInterface` are now just
called `Emitter`, `EmitterTrait`, and `EmitterInterface`.
* When rejecting Promises, it's now _required_ to use an `Exception` or
`Throwable`. This makes the typical case simpler and reduces special cases.
3.0.0 (2015-11-05)
------------------
* Now requires PHP 5.5!
* `Promise::all()` is moved to `Promise\all()`.
* Aside from the `Promise\all()` function, there's now also `Promise\race()`.
* `Promise\reject()` and `Promise\resolve()` have also been added.
* Now 100% compatible with the Ecmascript 6 Promise.
3.0.0-alpha1 (2015-10-23)
-------------------------
* This package now requires PHP 5.5.
* #26: Added an event loop implementation. Also knows as the Reactor Pattern.
* Renamed `Promise::error` to `Promise::otherwise` to be consistent with
ReactPHP and Guzzle. The `error` method is kept for BC but will be removed
in a future version.
* #27: Support for Promise-based coroutines via the `Sabre\Event\coroutine`
function.
* BC Break: Promises now use the EventLoop to run "then"-events in a separate
execution context. In practise that means you need to run the event loop to
wait for any `then`/`otherwise` callbacks to trigger.
* Promises now have a `wait()` method. Allowing you to make a promise
synchronous and simply wait for a result (or exception) to happen.
2.0.2 (2015-05-19)
------------------
* This release has no functional changes. It's just been brought up to date
with the latest coding standards.
2.0.1 (2014-10-06)
------------------
* Fixed: `$priority` was ignored in `EventEmitter::once` method.
* Fixed: Breaking the event chain was not possible in `EventEmitter::once`.
2.0.0 (2014-06-21)
------------------
* Added: When calling emit, it's now possible to specify a callback that will be
triggered after each method handled. This is dubbed the 'continueCallback' and
can be used to implement strategy patterns.
* Added: Promise object!
* Changed: EventEmitter::listeners now returns just the callbacks for an event,
and no longer returns the list by reference. The list is now automatically
sorted by priority.
* Update: Speed improvements.
* Updated: It's now possible to remove all listeners for every event.
* Changed: Now uses psr-4 autoloading.
1.0.1 (2014-06-12)
------------------
* hhvm compatible!
* Fixed: Issue #4. Compatiblitiy for PHP < 5.4.14.
1.0.0 (2013-07-19)
------------------
* Added: removeListener, removeAllListeners
* Added: once, to only listen to an event emitting once.
* Added README.md.
0.0.1-alpha (2013-06-29)
------------------------
* First version!

View File

@@ -1,51 +0,0 @@
sabre/event
===========
A lightweight library for event-based development in PHP.
This library provides the following event-based concepts:
1. EventEmitter.
2. Promises.
3. An event loop.
4. Co-routines.
Full documentation can be found on [the website][1].
Installation
------------
Make sure you have [composer][3] installed, and then run:
composer require sabre/event "^3.0"
This package requires PHP 5.5. The 2.0 branch is still maintained as well, and
supports PHP 5.4.
Build status
------------
| branch | status |
| ------ | ------ |
| master | [![Build Status](https://travis-ci.org/fruux/sabre-event.svg?branch=master)](https://travis-ci.org/fruux/sabre-event) |
| 3.0 | [![Build Status](https://travis-ci.org/fruux/sabre-event.svg?branch=2.0)](https://travis-ci.org/fruux/sabre-event) |
| 2.0 | [![Build Status](https://travis-ci.org/fruux/sabre-event.svg?branch=2.0)](https://travis-ci.org/fruux/sabre-event) |
| 1.0 | [![Build Status](https://travis-ci.org/fruux/sabre-event.svg?branch=1.0)](https://travis-ci.org/fruux/sabre-event) |
| php53 | [![Build Status](https://travis-ci.org/fruux/sabre-event.svg?branch=php53)](https://travis-ci.org/fruux/sabre-event) |
Questions?
----------
Head over to the [sabre/dav mailinglist][4], or you can also just open a ticket
on [GitHub][5].
Made at fruux
-------------
This library is being developed by [fruux](https://fruux.com/). Drop us a line for commercial services or enterprise support.
[1]: http://sabre.io/event/
[3]: http://getcomposer.org/
[4]: http://groups.google.com/group/sabredav-discuss
[5]: https://github.com/fruux/sabre-event/issues/

View File

@@ -16,7 +16,7 @@
"homepage": "http://sabre.io/event/", "homepage": "http://sabre.io/event/",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"require": { "require": {
"php": ">=7.0" "php": "^7.1 || ^8.0"
}, },
"authors": [ "authors": [
{ {
@@ -40,11 +40,30 @@
"lib/Promise/functions.php" "lib/Promise/functions.php"
] ]
}, },
"require-dev": { "autoload-dev": {
"sabre/cs": "~1.0.0", "psr-4" : {
"phpunit/phpunit" : "*" "Sabre\\Event\\" : "tests/Event"
}
}, },
"config" : { "require-dev": {
"bin-dir" : "bin/" "friendsofphp/php-cs-fixer": "~2.17.1",
"phpstan/phpstan": "^0.12",
"phpunit/phpunit" : "^7.5 || ^8.5 || ^9.0"
},
"scripts": {
"phpstan": [
"phpstan analyse lib tests"
],
"cs-fixer": [
"php-cs-fixer fix"
],
"phpunit": [
"phpunit --configuration tests/phpunit.xml"
],
"test": [
"composer phpstan",
"composer cs-fixer",
"composer phpunit"
]
} }
} }

View File

@@ -1,131 +0,0 @@
#!/usr/bin/env php
<?php declare (strict_types=1);
/**
* The following example demonstrates doing asynchronous HTTP requests with
* curl_multi.
*
* We use the event loop to occasionally see if there were any updates.
* This is very rudimentary, but demonstrates the basis of something someone
* might be able to use to create a better async http client.
*
* @copyright Copyright (C) 2007-2015 fruux GmbH. (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
use Sabre\Event\Loop;
use Sabre\Event\Promise;
require __DIR__ . '/../vendor/autoload.php';
// create both cURL resources
$ch1 = curl_init();
$ch2 = curl_init();
// set URL. The httpbin.org test url will wait 5 seconds to respond.
curl_setopt_array($ch1, CURLOPT_URL, "http://httpbin.org/delay/5");
curl_setopt_array($ch2, CURLOPT_URL, "http://httpbin.org/delay/5");
//create the multiple cURL handle
$mh = curl_multi_init();
//add the two handles
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
/**
* This function takes a curl handle as its argument, and returns a Promise.
*
* When the request is finished the Promise will resolve. Any curl errors will
* cause the Promise to reject.
*
* @param resource $curlHandle
* @return Promise
*/
function curl_async_promise($curlHandle) {
}
/**
* This class is used by curl_async_promise. It should generally only get
* constructed once.
*
* @copyright Copyright (C) 2007-2015 fruux GmbH. (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
class CurlScheduler {
protected $curlMultiHandle;
function __construct() {
$this->curlMultiHandle = curl_multi_init();
}
function addHandle($curlHandle) {
curl_multi_add_handle($mh, $curlHandle);
}
}
$active = null;
function curl_multi_loop_scheduler($mh, callable $done) {
$mrc = curl_multi_exec($mh, $active);
switch ($mrc) {
/**
* From the curl docs. If CURM_CALL_MULTI_PERFORM is returned, simply
* call curl_multi_perform immediately again. In PHP this means we
* actually call curl_multi_exec immediately again.
*
* We're doing this in the next tick.
*/
case CURLM_CALL_MULTI_PERFORM :
Loop\nextTick(function() use ($mh, $done) {
curl_multi_loop_scheduler($mh, $done);
});
break;
case CURLM_OK :
if (!$active) {
// We're done!
$done();
return;
}
// Check again after 0.02 seconds
Loop\setTimeout(function() use ($mh, $done) {
curl_multi_loop_scheduler($mh, $done);
}, 0.02);
break;
default :
throw Exception('Curl error: ' . curl_multi_strerror($mrc));
}
}
curl_multi_loop_scheduler($mh, function() {
echo "Success!\n";
});
Loop\run();
//close the handles
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);

View File

@@ -1,100 +0,0 @@
#!/usr/bin/env php
<?php declare (strict_types=1);
use Sabre\Event\Loop;
use Sabre\Event\Promise;
use function Sabre\Event\coroutine;
require __DIR__ . '/../vendor/autoload.php';
/**
* This example shows demonstrates the Promise api.
*/
/* Creating a new promise */
$promise = new Promise();
/* After 2 seconds we fulfill it */
Loop\setTimeout(function() use ($promise) {
echo "Step 1\n";
$promise->fulfill("hello");
}, 2);
/* Callback chain */
$result = $promise
->then(function($value) {
echo "Step 2\n";
// Immediately returning a new value.
return $value . " world";
})
->then(function($value) {
echo "Step 3\n";
// This 'then' returns a new promise which we resolve later.
$promise = new Promise();
// Resolving after 2 seconds
Loop\setTimeout(function() use ($promise, $value) {
$promise->fulfill($value . ", how are ya?");
}, 2);
return $promise;
})
->then(function($value) {
echo "Step 4\n";
// This is the final event handler.
return $value . " you rock!";
})
// Making all async calls synchronous by waiting for the final result.
->wait();
echo $result, "\n";
/* Now an identical example, this time with coroutines. */
$result = coroutine(function() {
$promise = new Promise();
/* After 2 seconds we fulfill it */
Loop\setTimeout(function() use ($promise) {
echo "Step 1\n";
$promise->fulfill("hello");
}, 2);
$value = (yield $promise);
echo "Step 2\n";
$value .= ' world';
echo "Step 3\n";
$promise = new Promise();
Loop\setTimeout(function() use ($promise, $value) {
$promise->fulfill($value . ", how are ya?");
}, 2);
$value = (yield $promise);
echo "Step 4\n";
// This is the final event handler.
yield $value . " you rock!";
})->wait();
echo $result, "\n";

View File

@@ -1,28 +0,0 @@
#!/usr/bin/env php
<?php declare (strict_types=1);
/**
* This example can be used to logfile processing and basically wraps the tail
* command.
*
* The benefit of using this, is that it allows you to tail multiple logs at
* the same time
*
* To stop this application, hit CTRL-C
*/
if ($argc < 2) {
echo "Usage: " . $argv[0] . " filename\n";
exit(1);
}
require __DIR__ . '/../vendor/autoload.php';
$tail = popen('tail -fn0 ' . escapeshellarg($argv[1]), 'r');
\Sabre\Event\Loop\addReadStream($tail, function() use ($tail) {
echo fread($tail, 4096);
});
\Sabre\Event\Loop\run();

View File

@@ -1,4 +1,6 @@
<?php declare (strict_types=1); <?php
declare(strict_types=1);
namespace Sabre\Event; namespace Sabre\Event;
@@ -11,8 +13,7 @@ namespace Sabre\Event;
* @author Evert Pot (http://evertpot.com/) * @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License * @license http://sabre.io/license/ Modified BSD License
*/ */
class Emitter implements EventEmitterInterface { class Emitter implements EmitterInterface
{
use EmitterTrait; use EmitterTrait;
} }

View File

@@ -1,9 +1,11 @@
<?php declare (strict_types=1); <?php
declare(strict_types=1);
namespace Sabre\Event; namespace Sabre\Event;
/** /**
* Event Emitter Interface * Event Emitter Interface.
* *
* Anything that accepts listeners and emits events should implement this * Anything that accepts listeners and emits events should implement this
* interface. * interface.
@@ -12,26 +14,22 @@ namespace Sabre\Event;
* @author Evert Pot (http://evertpot.com/) * @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License * @license http://sabre.io/license/ Modified BSD License
*/ */
interface EmitterInterface { interface EmitterInterface
{
/** /**
* Subscribe to an event. * Subscribe to an event.
*
* @return void
*/ */
function on(string $eventName, callable $callBack, int $priority = 100); public function on(string $eventName, callable $callBack, int $priority = 100);
/** /**
* Subscribe to an event exactly once. * Subscribe to an event exactly once.
*
* @return void
*/ */
function once(string $eventName, callable $callBack, int $priority = 100); public function once(string $eventName, callable $callBack, int $priority = 100);
/** /**
* Emits an event. * Emits an event.
* *
* This method will return true if 0 or more listeners were succesfully * This method will return true if 0 or more listeners were successfully
* handled. false is returned if one of the events broke the event chain. * handled. false is returned if one of the events broke the event chain.
* *
* If the continueCallBack is specified, this callback will be called every * If the continueCallBack is specified, this callback will be called every
@@ -49,7 +47,7 @@ interface EmitterInterface {
* Lastly, if there are 5 event handlers for an event. The continueCallback * Lastly, if there are 5 event handlers for an event. The continueCallback
* will be called at most 4 times. * will be called at most 4 times.
*/ */
function emit(string $eventName, array $arguments = [], callable $continueCallBack = null) : bool; public function emit(string $eventName, array $arguments = [], callable $continueCallBack = null): bool;
/** /**
* Returns the list of listeners for an event. * Returns the list of listeners for an event.
@@ -59,7 +57,7 @@ interface EmitterInterface {
* *
* @return callable[] * @return callable[]
*/ */
function listeners(string $eventName) : array; public function listeners(string $eventName): array;
/** /**
* Removes a specific listener from an event. * Removes a specific listener from an event.
@@ -67,7 +65,7 @@ interface EmitterInterface {
* If the listener could not be found, this method will return false. If it * If the listener could not be found, this method will return false. If it
* was removed it will return true. * was removed it will return true.
*/ */
function removeListener(string $eventName, callable $listener) : bool; public function removeListener(string $eventName, callable $listener): bool;
/** /**
* Removes all listeners. * Removes all listeners.
@@ -75,9 +73,6 @@ interface EmitterInterface {
* If the eventName argument is specified, all listeners for that event are * If the eventName argument is specified, all listeners for that event are
* removed. If it is not specified, every listener for every event is * removed. If it is not specified, every listener for every event is
* removed. * removed.
*
* @return void
*/ */
function removeAllListeners(string $eventName = null); public function removeAllListeners(string $eventName = null);
} }

View File

@@ -1,9 +1,11 @@
<?php declare (strict_types=1); <?php
declare(strict_types=1);
namespace Sabre\Event; namespace Sabre\Event;
/** /**
* Event Emitter Trait * Event Emitter Trait.
* *
* This trait contains all the basic functions to implement an * This trait contains all the basic functions to implement an
* EventEmitterInterface. * EventEmitterInterface.
@@ -15,53 +17,45 @@ namespace Sabre\Event;
* @author Evert Pot (http://evertpot.com/) * @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License * @license http://sabre.io/license/ Modified BSD License
*/ */
trait EmitterTrait { trait EmitterTrait
{
/** /**
* Subscribe to an event. * Subscribe to an event.
*
* @return void
*/ */
function on(string $eventName, callable $callBack, int $priority = 100) { public function on(string $eventName, callable $callBack, int $priority = 100)
{
if (!isset($this->listeners[$eventName])) { if (!isset($this->listeners[$eventName])) {
$this->listeners[$eventName] = [ $this->listeners[$eventName] = [
true, // If there's only one item, it's sorted true, // If there's only one item, it's sorted
[$priority], [$priority],
[$callBack] [$callBack],
]; ];
} else { } else {
$this->listeners[$eventName][0] = false; // marked as unsorted $this->listeners[$eventName][0] = false; // marked as unsorted
$this->listeners[$eventName][1][] = $priority; $this->listeners[$eventName][1][] = $priority;
$this->listeners[$eventName][2][] = $callBack; $this->listeners[$eventName][2][] = $callBack;
} }
} }
/** /**
* Subscribe to an event exactly once. * Subscribe to an event exactly once.
*
* @return void
*/ */
function once(string $eventName, callable $callBack, int $priority = 100) { public function once(string $eventName, callable $callBack, int $priority = 100)
{
$wrapper = null; $wrapper = null;
$wrapper = function() use ($eventName, $callBack, &$wrapper) { $wrapper = function () use ($eventName, $callBack, &$wrapper) {
$this->removeListener($eventName, $wrapper); $this->removeListener($eventName, $wrapper);
return call_user_func_array($callBack, func_get_args());
return \call_user_func_array($callBack, \func_get_args());
}; };
$this->on($eventName, $wrapper, $priority); $this->on($eventName, $wrapper, $priority);
} }
/** /**
* Emits an event. * Emits an event.
* *
* This method will return true if 0 or more listeners were succesfully * This method will return true if 0 or more listeners were successfully
* handled. false is returned if one of the events broke the event chain. * handled. false is returned if one of the events broke the event chain.
* *
* If the continueCallBack is specified, this callback will be called every * If the continueCallBack is specified, this callback will be called every
@@ -79,41 +73,35 @@ trait EmitterTrait {
* Lastly, if there are 5 event handlers for an event. The continueCallback * Lastly, if there are 5 event handlers for an event. The continueCallback
* will be called at most 4 times. * will be called at most 4 times.
*/ */
function emit(string $eventName, array $arguments = [], callable $continueCallBack = null) : bool { public function emit(string $eventName, array $arguments = [], callable $continueCallBack = null): bool
{
if (is_null($continueCallBack)) { if (\is_null($continueCallBack)) {
foreach ($this->listeners($eventName) as $listener) { foreach ($this->listeners($eventName) as $listener) {
$result = \call_user_func_array($listener, $arguments);
$result = call_user_func_array($listener, $arguments); if (false === $result) {
if ($result === false) {
return false; return false;
} }
} }
} else { } else {
$listeners = $this->listeners($eventName); $listeners = $this->listeners($eventName);
$counter = count($listeners); $counter = \count($listeners);
foreach ($listeners as $listener) { foreach ($listeners as $listener) {
--$counter;
$counter--; $result = \call_user_func_array($listener, $arguments);
$result = call_user_func_array($listener, $arguments); if (false === $result) {
if ($result === false) {
return false; return false;
} }
if ($counter > 0) { if ($counter > 0) {
if (!$continueCallBack()) break; if (!$continueCallBack()) {
break;
}
} }
} }
} }
return true; return true;
} }
/** /**
@@ -124,24 +112,22 @@ trait EmitterTrait {
* *
* @return callable[] * @return callable[]
*/ */
function listeners(string $eventName) : array { public function listeners(string $eventName): array
{
if (!isset($this->listeners[$eventName])) { if (!isset($this->listeners[$eventName])) {
return []; return [];
} }
// The list is not sorted // The list is not sorted
if (!$this->listeners[$eventName][0]) { if (!$this->listeners[$eventName][0]) {
// Sorting // Sorting
array_multisort($this->listeners[$eventName][1], SORT_NUMERIC, $this->listeners[$eventName][2]); \array_multisort($this->listeners[$eventName][1], SORT_NUMERIC, $this->listeners[$eventName][2]);
// Marking the listeners as sorted // Marking the listeners as sorted
$this->listeners[$eventName][0] = true; $this->listeners[$eventName][0] = true;
} }
return $this->listeners[$eventName][2]; return $this->listeners[$eventName][2];
} }
/** /**
@@ -150,8 +136,8 @@ trait EmitterTrait {
* If the listener could not be found, this method will return false. If it * If the listener could not be found, this method will return false. If it
* was removed it will return true. * was removed it will return true.
*/ */
function removeListener(string $eventName, callable $listener) : bool { public function removeListener(string $eventName, callable $listener): bool
{
if (!isset($this->listeners[$eventName])) { if (!isset($this->listeners[$eventName])) {
return false; return false;
} }
@@ -159,11 +145,12 @@ trait EmitterTrait {
if ($check === $listener) { if ($check === $listener) {
unset($this->listeners[$eventName][1][$index]); unset($this->listeners[$eventName][1][$index]);
unset($this->listeners[$eventName][2][$index]); unset($this->listeners[$eventName][2][$index]);
return true; return true;
} }
} }
return false;
return false;
} }
/** /**
@@ -172,24 +159,20 @@ trait EmitterTrait {
* If the eventName argument is specified, all listeners for that event are * If the eventName argument is specified, all listeners for that event are
* removed. If it is not specified, every listener for every event is * removed. If it is not specified, every listener for every event is
* removed. * removed.
*
* @return void
*/ */
function removeAllListeners(string $eventName = null) { public function removeAllListeners(string $eventName = null)
{
if (!is_null($eventName)) { if (!\is_null($eventName)) {
unset($this->listeners[$eventName]); unset($this->listeners[$eventName]);
} else { } else {
$this->listeners = []; $this->listeners = [];
} }
} }
/** /**
* The list of listeners * The list of listeners.
* *
* @var array * @var array
*/ */
protected $listeners = []; protected $listeners = [];
} }

View File

@@ -1,19 +1,20 @@
<?php declare (strict_types=1); <?php
declare(strict_types=1);
namespace Sabre\Event; namespace Sabre\Event;
/** /**
* This is the old name for the Emitter class. * This is the old name for the Emitter class.
* *
* Instead of of using EventEmitter, please use Emitter. They are identical * Instead of using EventEmitter, please use Emitter. They are identical
* otherwise. * otherwise.
* *
* @copyright Copyright (C) fruux GmbH (https://fruux.com/) * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/) * @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License * @license http://sabre.io/license/ Modified BSD License
*/ */
class EventEmitter implements EmitterInterface { class EventEmitter implements EmitterInterface
{
use EmitterTrait; use EmitterTrait;
} }

View File

@@ -1,4 +1,6 @@
<?php declare (strict_types=1); <?php
declare(strict_types=1);
namespace Sabre\Event\Loop; namespace Sabre\Event\Loop;
@@ -15,20 +17,19 @@ namespace Sabre\Event\Loop;
* @author Evert Pot (http://evertpot.com/) * @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License * @license http://sabre.io/license/ Modified BSD License
*/ */
class Loop { class Loop
{
/** /**
* Executes a function after x seconds. * Executes a function after x seconds.
*
* @return void
*/ */
function setTimeout(callable $cb, float $timeout) { public function setTimeout(callable $cb, float $timeout)
{
$triggerTime = microtime(true) + ($timeout); $triggerTime = microtime(true) + ($timeout);
if (!$this->timers) { if (!$this->timers) {
// Special case when the timers array was empty. // Special case when the timers array was empty.
$this->timers[] = [$triggerTime, $cb]; $this->timers[] = [$triggerTime, $cb];
return; return;
} }
@@ -46,14 +47,12 @@ class Loop {
[[$triggerTime, $cb]] [[$triggerTime, $cb]]
); );
break; break;
} elseif ($index === 0) { } elseif (0 === $index) {
array_unshift($this->timers, [$triggerTime, $cb]); array_unshift($this->timers, [$triggerTime, $cb]);
break; break;
} }
$index--; --$index;
} }
} }
/** /**
@@ -62,12 +61,12 @@ class Loop {
* The value this function returns can be used to stop the interval with * The value this function returns can be used to stop the interval with
* clearInterval. * clearInterval.
*/ */
function setInterval(callable $cb, float $timeout) : array { public function setInterval(callable $cb, float $timeout): array
{
$keepGoing = true; $keepGoing = true;
$f = null; $f = null;
$f = function() use ($cb, &$f, $timeout, &$keepGoing) { $f = function () use ($cb, &$f, $timeout, &$keepGoing) {
if ($keepGoing) { if ($keepGoing) {
$cb(); $cb();
$this->setTimeout($f, $timeout); $this->setTimeout($f, $timeout);
@@ -82,32 +81,24 @@ class Loop {
// Because I'm worried people will be confused by using a boolean as a // Because I'm worried people will be confused by using a boolean as a
// sort of identifier, I added an extra string. // sort of identifier, I added an extra string.
return ['I\'m an implementation detail', &$keepGoing]; return ['I\'m an implementation detail', &$keepGoing];
} }
/** /**
* Stops a running interval. * Stops a running interval.
*
* @return void
*/ */
function clearInterval(array $intervalId) { public function clearInterval(array $intervalId)
{
$intervalId[1] = false; $intervalId[1] = false;
} }
/** /**
* Runs a function immediately at the next iteration of the loop. * Runs a function immediately at the next iteration of the loop.
*
* @return void
*/ */
function nextTick(callable $cb) { public function nextTick(callable $cb)
{
$this->nextTick[] = $cb; $this->nextTick[] = $cb;
} }
/** /**
* Adds a read stream. * Adds a read stream.
* *
@@ -118,13 +109,11 @@ class Loop {
* prevent the eventloop from never stopping. * prevent the eventloop from never stopping.
* *
* @param resource $stream * @param resource $stream
* @return void
*/ */
function addReadStream($stream, callable $cb) { public function addReadStream($stream, callable $cb)
{
$this->readStreams[(int)$stream] = $stream; $this->readStreams[(int) $stream] = $stream;
$this->readCallbacks[(int)$stream] = $cb; $this->readCallbacks[(int) $stream] = $cb;
} }
/** /**
@@ -137,65 +126,53 @@ class Loop {
* prevent the eventloop from never stopping. * prevent the eventloop from never stopping.
* *
* @param resource $stream * @param resource $stream
* @return void
*/ */
function addWriteStream($stream, callable $cb) { public function addWriteStream($stream, callable $cb)
{
$this->writeStreams[(int)$stream] = $stream; $this->writeStreams[(int) $stream] = $stream;
$this->writeCallbacks[(int)$stream] = $cb; $this->writeCallbacks[(int) $stream] = $cb;
} }
/** /**
* Stop watching a stream for reads. * Stop watching a stream for reads.
* *
* @param resource $stream * @param resource $stream
* @return void
*/ */
function removeReadStream($stream) { public function removeReadStream($stream)
{
unset( unset(
$this->readStreams[(int)$stream], $this->readStreams[(int) $stream],
$this->readCallbacks[(int)$stream] $this->readCallbacks[(int) $stream]
); );
} }
/** /**
* Stop watching a stream for writes. * Stop watching a stream for writes.
* *
* @param resource $stream * @param resource $stream
* @return void
*/ */
function removeWriteStream($stream) { public function removeWriteStream($stream)
{
unset( unset(
$this->writeStreams[(int)$stream], $this->writeStreams[(int) $stream],
$this->writeCallbacks[(int)$stream] $this->writeCallbacks[(int) $stream]
); );
} }
/** /**
* Runs the loop. * Runs the loop.
* *
* This function will run continiously, until there's no more events to * This function will run continuously, until there's no more events to
* handle. * handle.
*
* @return void
*/ */
function run() { public function run()
{
$this->running = true; $this->running = true;
do { do {
$hasEvents = $this->tick(true); $hasEvents = $this->tick(true);
} while ($this->running && $hasEvents); } while ($this->running && $hasEvents);
$this->running = false; $this->running = false;
} }
/** /**
@@ -210,8 +187,8 @@ class Loop {
* This function will return true if there are _any_ events left in the * This function will return true if there are _any_ events left in the
* loop after the tick. * loop after the tick.
*/ */
function tick(bool $block = false) : bool { public function tick(bool $block = false): bool
{
$this->runNextTicks(); $this->runNextTicks();
$nextTimeout = $this->runTimers(); $nextTimeout = $this->runTimers();
@@ -232,19 +209,15 @@ class Loop {
$this->runStreams($streamWait); $this->runStreams($streamWait);
return ($this->readStreams || $this->writeStreams || $this->nextTick || $this->timers); return $this->readStreams || $this->writeStreams || $this->nextTick || $this->timers;
} }
/** /**
* Stops a running eventloop * Stops a running eventloop.
*
* @return void
*/ */
function stop() { public function stop()
{
$this->running = false; $this->running = false;
} }
/** /**
@@ -252,15 +225,14 @@ class Loop {
* *
* return void * return void
*/ */
protected function runNextTicks() { protected function runNextTicks()
{
$nextTick = $this->nextTick; $nextTick = $this->nextTick;
$this->nextTick = []; $this->nextTick = [];
foreach ($nextTick as $cb) { foreach ($nextTick as $cb) {
$cb(); $cb();
} }
} }
/** /**
@@ -273,8 +245,8 @@ class Loop {
* *
* @return float|null * @return float|null
*/ */
protected function runTimers() { protected function runTimers()
{
$now = microtime(true); $now = microtime(true);
while (($timer = array_pop($this->timers)) && $timer[0] < $now) { while (($timer = array_pop($this->timers)) && $timer[0] < $now) {
$timer[1](); $timer[1]();
@@ -282,9 +254,9 @@ class Loop {
// Add the last timer back to the array. // Add the last timer back to the array.
if ($timer) { if ($timer) {
$this->timers[] = $timer; $this->timers[] = $timer;
return max(0, $timer[0] - microtime(true)); return max(0, $timer[0] - microtime(true));
} }
} }
/** /**
@@ -295,36 +267,33 @@ class Loop {
* *
* @param float|null timeout * @param float|null timeout
*/ */
protected function runStreams($timeout) { protected function runStreams($timeout)
{
if ($this->readStreams || $this->writeStreams) { if ($this->readStreams || $this->writeStreams) {
$read = $this->readStreams; $read = $this->readStreams;
$write = $this->writeStreams; $write = $this->writeStreams;
$except = null; $except = null;
if (stream_select($read, $write, $except, ($timeout === null) ? null : 0, $timeout ? (int)($timeout * 1000000) : 0)) { // stream_select changes behavior in 8.1 to forbid passing non-null microseconds when the seconds are null.
// Older versions of php don't allow passing null to microseconds.
if (null !== $timeout ? stream_select($read, $write, $except, 0, (int) ($timeout * 1000000)) : stream_select($read, $write, $except, null)) {
// See PHP Bug https://bugs.php.net/bug.php?id=62452 // See PHP Bug https://bugs.php.net/bug.php?id=62452
// Fixed in PHP7 // Fixed in PHP7
foreach ($read as $readStream) { foreach ($read as $readStream) {
$readCb = $this->readCallbacks[(int)$readStream]; $readCb = $this->readCallbacks[(int) $readStream];
$readCb(); $readCb();
} }
foreach ($write as $writeStream) { foreach ($write as $writeStream) {
$writeCb = $this->writeCallbacks[(int)$writeStream]; $writeCb = $this->writeCallbacks[(int) $writeStream];
$writeCb(); $writeCb();
} }
} }
} elseif ($this->running && ($this->nextTick || $this->timers)) { } elseif ($this->running && ($this->nextTick || $this->timers)) {
usleep($timeout !== null ? intval($timeout * 1000000) : 200000); usleep(null !== $timeout ? intval($timeout * 1000000) : 200000);
} }
} }
/** /**
* Is the main loop active * Is the main loop active.
* *
* @var bool * @var bool
*/ */
@@ -361,16 +330,14 @@ class Loop {
/** /**
* List of read callbacks, indexed by stream id. * List of read callbacks, indexed by stream id.
* *
* @var callback[] * @var callable[]
*/ */
protected $readCallbacks = []; protected $readCallbacks = [];
/** /**
* List of write callbacks, indexed by stream id. * List of write callbacks, indexed by stream id.
* *
* @var callback[] * @var callable[]
*/ */
protected $writeCallbacks = []; protected $writeCallbacks = [];
} }

View File

@@ -1,16 +1,15 @@
<?php declare (strict_types=1); <?php
declare(strict_types=1);
namespace Sabre\Event\Loop; namespace Sabre\Event\Loop;
/** /**
* Executes a function after x seconds. * Executes a function after x seconds.
*
* @return void
*/ */
function setTimeout(callable $cb, float $timeout) { function setTimeout(callable $cb, float $timeout)
{
instance()->setTimeout($cb, $timeout); instance()->setTimeout($cb, $timeout);
} }
/** /**
@@ -19,35 +18,27 @@ function setTimeout(callable $cb, float $timeout) {
* The value this function returns can be used to stop the interval with * The value this function returns can be used to stop the interval with
* clearInterval. * clearInterval.
*/ */
function setInterval(callable $cb, float $timeout) : array { function setInterval(callable $cb, float $timeout): array
{
return instance()->setInterval($cb, $timeout); return instance()->setInterval($cb, $timeout);
} }
/** /**
* Stops a running interval. * Stops a running interval.
*
* @return void
*/ */
function clearInterval(array $intervalId) { function clearInterval(array $intervalId)
{
instance()->clearInterval($intervalId); instance()->clearInterval($intervalId);
} }
/** /**
* Runs a function immediately at the next iteration of the loop. * Runs a function immediately at the next iteration of the loop.
*
* @return void
*/ */
function nextTick(callable $cb) { function nextTick(callable $cb)
{
instance()->nextTick($cb); instance()->nextTick($cb);
} }
/** /**
* Adds a read stream. * Adds a read stream.
* *
@@ -58,12 +49,10 @@ function nextTick(callable $cb) {
* prevent the eventloop from never stopping. * prevent the eventloop from never stopping.
* *
* @param resource $stream * @param resource $stream
* @return void
*/ */
function addReadStream($stream, callable $cb) { function addReadStream($stream, callable $cb)
{
instance()->addReadStream($stream, $cb); instance()->addReadStream($stream, $cb);
} }
/** /**
@@ -76,51 +65,41 @@ function addReadStream($stream, callable $cb) {
* prevent the eventloop from never stopping. * prevent the eventloop from never stopping.
* *
* @param resource $stream * @param resource $stream
* @return void
*/ */
function addWriteStream($stream, callable $cb) { function addWriteStream($stream, callable $cb)
{
instance()->addWriteStream($stream, $cb); instance()->addWriteStream($stream, $cb);
} }
/** /**
* Stop watching a stream for reads. * Stop watching a stream for reads.
* *
* @param resource $stream * @param resource $stream
* @return void
*/ */
function removeReadStream($stream) { function removeReadStream($stream)
{
instance()->removeReadStream($stream); instance()->removeReadStream($stream);
} }
/** /**
* Stop watching a stream for writes. * Stop watching a stream for writes.
* *
* @param resource $stream * @param resource $stream
* @return void
*/ */
function removeWriteStream($stream) { function removeWriteStream($stream)
{
instance()->removeWriteStream($stream); instance()->removeWriteStream($stream);
} }
/** /**
* Runs the loop. * Runs the loop.
* *
* This function will run continiously, until there's no more events to * This function will run continuously, until there's no more events to
* handle. * handle.
*
* @return void
*/ */
function run() { function run()
{
instance()->run(); instance()->run();
} }
/** /**
@@ -135,34 +114,30 @@ function run() {
* This function will return true if there are _any_ events left in the * This function will return true if there are _any_ events left in the
* loop after the tick. * loop after the tick.
*/ */
function tick(bool $block = false) : bool { function tick(bool $block = false): bool
{
return instance()->tick($block); return instance()->tick($block);
} }
/** /**
* Stops a running eventloop * Stops a running eventloop.
*
* @return void
*/ */
function stop() { function stop()
{
instance()->stop(); instance()->stop();
} }
/** /**
* Retrieves or sets the global Loop object. * Retrieves or sets the global Loop object.
*/ */
function instance(Loop $newLoop = null) : Loop { function instance(Loop $newLoop = null): Loop
{
static $loop; static $loop;
if ($newLoop) { if ($newLoop) {
$loop = $newLoop; $loop = $newLoop;
} elseif (!$loop) { } elseif (!$loop) {
$loop = new Loop(); $loop = new Loop();
} }
return $loop;
return $loop;
} }

View File

@@ -1,4 +1,6 @@
<?php declare (strict_types=1); <?php
declare(strict_types=1);
namespace Sabre\Event; namespace Sabre\Event;
@@ -20,9 +22,11 @@ use Throwable;
* @copyright Copyright (C) fruux GmbH (https://fruux.com/) * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/) * @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License * @license http://sabre.io/license/ Modified BSD License
*
* @psalm-template TReturn
*/ */
class Promise { class Promise
{
/** /**
* The asynchronous operation is pending. * The asynchronous operation is pending.
*/ */
@@ -54,15 +58,14 @@ class Promise {
* Each are callbacks that map to $this->fulfill and $this->reject. * Each are callbacks that map to $this->fulfill and $this->reject.
* Using the executor is optional. * Using the executor is optional.
*/ */
function __construct(callable $executor = null) { public function __construct(callable $executor = null)
{
if ($executor) { if ($executor) {
$executor( $executor(
[$this, 'fulfill'], [$this, 'fulfill'],
[$this, 'reject'] [$this, 'reject']
); );
} }
} }
/** /**
@@ -84,32 +87,32 @@ class Promise {
* If either of the callbacks throw an exception, the returned promise will * If either of the callbacks throw an exception, the returned promise will
* be rejected and the exception will be passed back. * be rejected and the exception will be passed back.
*/ */
function then(callable $onFulfilled = null, callable $onRejected = null) : Promise { public function then(callable $onFulfilled = null, callable $onRejected = null): Promise
{
// This new subPromise will be returned from this function, and will // This new subPromise will be returned from this function, and will
// be fulfilled with the result of the onFulfilled or onRejected event // be fulfilled with the result of the onFulfilled or onRejected event
// handlers. // handlers.
$subPromise = new self(); $subPromise = new self();
switch ($this->state) { switch ($this->state) {
case self::PENDING : case self::PENDING:
// The operation is pending, so we keep a reference to the // The operation is pending, so we keep a reference to the
// event handlers so we can call them later. // event handlers so we can call them later.
$this->subscribers[] = [$subPromise, $onFulfilled, $onRejected]; $this->subscribers[] = [$subPromise, $onFulfilled, $onRejected];
break; break;
case self::FULFILLED : case self::FULFILLED:
// The async operation is already fulfilled, so we trigger the // The async operation is already fulfilled, so we trigger the
// onFulfilled callback asap. // onFulfilled callback asap.
$this->invokeCallback($subPromise, $onFulfilled); $this->invokeCallback($subPromise, $onFulfilled);
break; break;
case self::REJECTED : case self::REJECTED:
// The async operation failed, so we call teh onRejected // The async operation failed, so we call the onRejected
// callback asap. // callback asap.
$this->invokeCallback($subPromise, $onRejected); $this->invokeCallback($subPromise, $onRejected);
break; break;
} }
return $subPromise;
return $subPromise;
} }
/** /**
@@ -118,20 +121,19 @@ class Promise {
* Its usage is identical to then(). However, the otherwise() function is * Its usage is identical to then(). However, the otherwise() function is
* preferred. * preferred.
*/ */
function otherwise(callable $onRejected) : Promise { public function otherwise(callable $onRejected): Promise
{
return $this->then(null, $onRejected); return $this->then(null, $onRejected);
} }
/** /**
* Marks this promise as fulfilled and sets its return value. * Marks this promise as fulfilled and sets its return value.
* *
* @param mixed $value * @param mixed $value
* @return void
*/ */
function fulfill($value = null) { public function fulfill($value = null)
if ($this->state !== self::PENDING) { {
if (self::PENDING !== $this->state) {
throw new PromiseAlreadyResolvedException('This promise is already resolved, and you\'re not allowed to resolve a promise more than once'); throw new PromiseAlreadyResolvedException('This promise is already resolved, and you\'re not allowed to resolve a promise more than once');
} }
$this->state = self::FULFILLED; $this->state = self::FULFILLED;
@@ -142,12 +144,11 @@ class Promise {
} }
/** /**
* Marks this promise as rejected, and set it's rejection reason. * Marks this promise as rejected, and set its rejection reason.
*
* @return void
*/ */
function reject(Throwable $reason) { public function reject(Throwable $reason)
if ($this->state !== self::PENDING) { {
if (self::PENDING !== $this->state) {
throw new PromiseAlreadyResolvedException('This promise is already resolved, and you\'re not allowed to resolve a promise more than once'); throw new PromiseAlreadyResolvedException('This promise is already resolved, and you\'re not allowed to resolve a promise more than once');
} }
$this->state = self::REJECTED; $this->state = self::REJECTED;
@@ -155,13 +156,12 @@ class Promise {
foreach ($this->subscribers as $subscriber) { foreach ($this->subscribers as $subscriber) {
$this->invokeCallback($subscriber[0], $subscriber[2]); $this->invokeCallback($subscriber[0], $subscriber[2]);
} }
} }
/** /**
* Stops execution until this promise is resolved. * Stops execution until this promise is resolved.
* *
* This method stops exection completely. If the promise is successful with * This method stops execution completely. If the promise is successful with
* a value, this method will return this value. If the promise was * a value, this method will return this value. If the promise was
* rejected, this method will throw an exception. * rejected, this method will throw an exception.
* *
@@ -170,12 +170,12 @@ class Promise {
* chain. * chain.
* *
* @return mixed * @return mixed
* @psalm-return TReturn
*/ */
function wait() { public function wait()
{
$hasEvents = true; $hasEvents = true;
while ($this->state === self::PENDING) { while (self::PENDING === $this->state) {
if (!$hasEvents) { if (!$hasEvents) {
throw new \LogicException('There were no more events in the loop. This promise will never be fulfilled.'); throw new \LogicException('There were no more events in the loop. This promise will never be fulfilled.');
} }
@@ -183,10 +183,9 @@ class Promise {
// As long as the promise is not fulfilled, we tell the event loop // As long as the promise is not fulfilled, we tell the event loop
// to handle events, and to block. // to handle events, and to block.
$hasEvents = Loop\tick(true); $hasEvents = Loop\tick(true);
} }
if ($this->state === self::FULFILLED) { if (self::FULFILLED === $this->state) {
// If the state of this promise is fulfilled, we can return the value. // If the state of this promise is fulfilled, we can return the value.
return $this->value; return $this->value;
} else { } else {
@@ -194,11 +193,8 @@ class Promise {
// errored. Therefore we need to throw an exception. // errored. Therefore we need to throw an exception.
throw $this->value; throw $this->value;
} }
} }
/** /**
* A list of subscribers. Subscribers are the callbacks that want us to let * A list of subscribers. Subscribers are the callbacks that want us to let
* them know if the callback was fulfilled or rejected. * them know if the callback was fulfilled or rejected.
@@ -224,21 +220,18 @@ class Promise {
* correctly, and any chained promises are also correctly fulfilled or * correctly, and any chained promises are also correctly fulfilled or
* rejected. * rejected.
* *
* @param Promise $subPromise
* @param callable $callBack * @param callable $callBack
* @return void
*/ */
private function invokeCallback(Promise $subPromise, callable $callBack = null) { private function invokeCallback(Promise $subPromise, callable $callBack = null)
{
// We use 'nextTick' to ensure that the event handlers are always // We use 'nextTick' to ensure that the event handlers are always
// triggered outside of the calling stack in which they were originally // triggered outside of the calling stack in which they were originally
// passed to 'then'. // passed to 'then'.
// //
// This makes the order of execution more predictable. // This makes the order of execution more predictable.
Loop\nextTick(function() use ($callBack, $subPromise) { Loop\nextTick(function () use ($callBack, $subPromise) {
if (is_callable($callBack)) { if (is_callable($callBack)) {
try { try {
$result = $callBack($this->value); $result = $callBack($this->value);
if ($result instanceof self) { if ($result instanceof self) {
// If the callback (onRejected or onFulfilled) // If the callback (onRejected or onFulfilled)
@@ -257,7 +250,7 @@ class Promise {
$subPromise->reject($e); $subPromise->reject($e);
} }
} else { } else {
if ($this->state === self::FULFILLED) { if (self::FULFILLED === $this->state) {
$subPromise->fulfill($this->value); $subPromise->fulfill($this->value);
} else { } else {
$subPromise->reject($this->value); $subPromise->reject($this->value);
@@ -265,5 +258,4 @@ class Promise {
} }
}); });
} }
} }

View File

@@ -1,4 +1,6 @@
<?php declare (strict_types=1); <?php
declare(strict_types=1);
namespace Sabre\Event\Promise; namespace Sabre\Event\Promise;
@@ -14,48 +16,50 @@ use Throwable;
* @license http://sabre.io/license/ Modified BSD License * @license http://sabre.io/license/ Modified BSD License
*/ */
/** /**
* This function takes an array of Promises, and returns a Promise that * This function takes an array of Promises, and returns a Promise that
* resolves when all of the given arguments have resolved. * resolves when all the given arguments have resolved.
* *
* The returned Promise will resolve with a value that's an array of all the * The returned Promise will resolve with a value that's an array of all the
* values the given promises have been resolved with. * values the given promises have been resolved with.
* *
* This array will be in the exact same order as the array of input promises. * This array will be in the exact same order as the array of input promises.
* *
* If any of the given Promises fails, the returned promise will immidiately * If any of the given Promises fails, the returned promise will immediately
* fail with the first Promise that fails, and its reason. * fail with the first Promise that fails, and its reason.
* *
* @param Promise[] $promises * @param Promise[] $promises
*/ */
function all(array $promises) : Promise { function all(array $promises): Promise
{
return new Promise(function ($success, $fail) use ($promises) {
if (empty($promises)) {
$success([]);
return new Promise(function($success, $fail) use ($promises) { return;
}
$successCount = 0; $successCount = 0;
$completeResult = []; $completeResult = [];
foreach ($promises as $promiseIndex => $subPromise) { foreach ($promises as $promiseIndex => $subPromise) {
$subPromise->then( $subPromise->then(
function($result) use ($promiseIndex, &$completeResult, &$successCount, $success, $promises) { function ($result) use ($promiseIndex, &$completeResult, &$successCount, $success, $promises) {
$completeResult[$promiseIndex] = $result; $completeResult[$promiseIndex] = $result;
$successCount++; ++$successCount;
if ($successCount === count($promises)) { if ($successCount === count($promises)) {
$success($completeResult); $success($completeResult);
} }
return $result; return $result;
} }
)->otherwise( )->otherwise(
function($reason) use ($fail) { function ($reason) use ($fail) {
$fail($reason); $fail($reason);
} }
); );
} }
}); });
} }
/** /**
@@ -67,22 +71,20 @@ function all(array $promises) : Promise {
* *
* @param Promise[] $promises * @param Promise[] $promises
*/ */
function race(array $promises) : Promise { function race(array $promises): Promise
{
return new Promise(function($success, $fail) use ($promises) { return new Promise(function ($success, $fail) use ($promises) {
$alreadyDone = false; $alreadyDone = false;
foreach ($promises as $promise) { foreach ($promises as $promise) {
$promise->then( $promise->then(
function($result) use ($success, &$alreadyDone) { function ($result) use ($success, &$alreadyDone) {
if ($alreadyDone) { if ($alreadyDone) {
return; return;
} }
$alreadyDone = true; $alreadyDone = true;
$success($result); $success($result);
}, },
function($reason) use ($fail, &$alreadyDone) { function ($reason) use ($fail, &$alreadyDone) {
if ($alreadyDone) { if ($alreadyDone) {
return; return;
} }
@@ -90,14 +92,10 @@ function race(array $promises) : Promise {
$fail($reason); $fail($reason);
} }
); );
} }
}); });
} }
/** /**
* Returns a Promise that resolves with the given value. * Returns a Promise that resolves with the given value.
* *
@@ -106,25 +104,25 @@ function race(array $promises) : Promise {
* *
* @param mixed $value * @param mixed $value
*/ */
function resolve($value) : Promise { function resolve($value): Promise
{
if ($value instanceof Promise) { if ($value instanceof Promise) {
return $value->then(); return $value->then();
} else { } else {
$promise = new Promise(); $promise = new Promise();
$promise->fulfill($value); $promise->fulfill($value);
return $promise; return $promise;
} }
} }
/** /**
* Returns a Promise that will reject with the given reason. * Returns a Promise that will reject with the given reason.
*/ */
function reject(Throwable $reason) : Promise { function reject(Throwable $reason): Promise
{
$promise = new Promise(); $promise = new Promise();
$promise->reject($reason); $promise->reject($reason);
return $promise;
return $promise;
} }

View File

@@ -1,4 +1,6 @@
<?php declare (strict_types=1); <?php
declare(strict_types=1);
namespace Sabre\Event; namespace Sabre\Event;
@@ -10,6 +12,6 @@ namespace Sabre\Event;
* @author Evert Pot (http://evertpot.com/) * @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License * @license http://sabre.io/license/ Modified BSD License
*/ */
class PromiseAlreadyResolvedException extends \LogicException { class PromiseAlreadyResolvedException extends \LogicException
{
} }

View File

@@ -1,4 +1,6 @@
<?php declare (strict_types=1); <?php
declare(strict_types=1);
namespace Sabre\Event; namespace Sabre\Event;
@@ -9,11 +11,10 @@ namespace Sabre\Event;
* @author Evert Pot (http://evertpot.com/) * @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License * @license http://sabre.io/license/ Modified BSD License
*/ */
class Version { class Version
{
/** /**
* Full version number * Full version number.
*/ */
const VERSION = '5.0.0'; const VERSION = '5.1.4';
} }

View File

@@ -1,4 +1,6 @@
<?php declare (strict_types=1); <?php
declare(strict_types=1);
namespace Sabre\Event; namespace Sabre\Event;
@@ -14,24 +16,21 @@ namespace Sabre\Event;
* on('change:*') * on('change:*')
* *
* A few notes: * A few notes:
* *
* - Wildcards only work at the end of an event name. * - Wildcards only work at the end of an event name.
* - Currently you can only use 1 wildcard. * - Currently you can only use 1 wildcard.
* - Using ":" as a separator is optional, but it's highly recommended to use * - Using ":" as a separator is optional, but it's highly recommended to use
* some kind of separator. * some kind of separator.
* *
* The WilcardEmitter is a bit slower than the regular Emitter. If you code * The WildcardEmitter is a bit slower than the regular Emitter. If your code
* must be very high performance, it might be better to try to use the other * must be very high performance, it might be better to try to use the other
* emitter. For must usage the difference is negligible though. * emitter. For most usage the difference is negligible though.
* *
* @copyright Copyright (C) fruux GmbH (https://fruux.com/) * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/) * @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License * @license http://sabre.io/license/ Modified BSD License
*/ */
class WildcardEmitter implements EmitterInterface { class WildcardEmitter implements EmitterInterface
{
use WildcardEmitterTrait; use WildcardEmitterTrait;
} }

View File

@@ -1,9 +1,11 @@
<?php declare (strict_types=1); <?php
declare(strict_types=1);
namespace Sabre\Event; namespace Sabre\Event;
/** /**
* Wildcard Emitter Trait * Wildcard Emitter Trait.
* *
* This trait provides the implementation for WildCardEmitter * This trait provides the implementation for WildCardEmitter
* Refer to that class for the full documentation about this * Refer to that class for the full documentation about this
@@ -17,21 +19,19 @@ namespace Sabre\Event;
* @author Evert Pot (http://evertpot.com/) * @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License * @license http://sabre.io/license/ Modified BSD License
*/ */
trait WildcardEmitterTrait { trait WildcardEmitterTrait
{
/** /**
* Subscribe to an event. * Subscribe to an event.
*
* @return void
*/ */
function on(string $eventName, callable $callBack, int $priority = 100) { public function on(string $eventName, callable $callBack, int $priority = 100)
{
// If it ends with a wildcard, we use the wildcardListeners array // If it ends with a wildcard, we use the wildcardListeners array
if ($eventName[strlen($eventName) - 1] === '*') { if ('*' === $eventName[\strlen($eventName) - 1]) {
$eventName = substr($eventName, 0, -1); $eventName = \substr($eventName, 0, -1);
$listeners = & $this->wildcardListeners; $listeners = &$this->wildcardListeners;
} else { } else {
$listeners = & $this->listeners; $listeners = &$this->listeners;
} }
// Always fully reset the listener index. This is fairly sane for most // Always fully reset the listener index. This is fairly sane for most
@@ -44,32 +44,27 @@ trait WildcardEmitterTrait {
$listeners[$eventName] = []; $listeners[$eventName] = [];
} }
$listeners[$eventName][] = [$priority, $callBack]; $listeners[$eventName][] = [$priority, $callBack];
} }
/** /**
* Subscribe to an event exactly once. * Subscribe to an event exactly once.
*
* @return void
*/ */
function once(string $eventName, callable $callBack, int $priority = 100) { public function once(string $eventName, callable $callBack, int $priority = 100)
{
$wrapper = null; $wrapper = null;
$wrapper = function() use ($eventName, $callBack, &$wrapper) { $wrapper = function () use ($eventName, $callBack, &$wrapper) {
$this->removeListener($eventName, $wrapper); $this->removeListener($eventName, $wrapper);
return call_user_func_array($callBack, func_get_args());
return \call_user_func_array($callBack, \func_get_args());
}; };
$this->on($eventName, $wrapper, $priority); $this->on($eventName, $wrapper, $priority);
} }
/** /**
* Emits an event. * Emits an event.
* *
* This method will return true if 0 or more listeners were succesfully * This method will return true if 0 or more listeners were successfully
* handled. false is returned if one of the events broke the event chain. * handled. false is returned if one of the events broke the event chain.
* *
* If the continueCallBack is specified, this callback will be called every * If the continueCallBack is specified, this callback will be called every
@@ -87,42 +82,35 @@ trait WildcardEmitterTrait {
* Lastly, if there are 5 event handlers for an event. The continueCallback * Lastly, if there are 5 event handlers for an event. The continueCallback
* will be called at most 4 times. * will be called at most 4 times.
*/ */
function emit(string $eventName, array $arguments = [], callable $continueCallBack = null) : bool { public function emit(string $eventName, array $arguments = [], callable $continueCallBack = null): bool
{
if (is_null($continueCallBack)) { if (\is_null($continueCallBack)) {
foreach ($this->listeners($eventName) as $listener) { foreach ($this->listeners($eventName) as $listener) {
$result = \call_user_func_array($listener, $arguments);
$result = call_user_func_array($listener, $arguments); if (false === $result) {
if ($result === false) {
return false; return false;
} }
} }
} else { } else {
$listeners = $this->listeners($eventName); $listeners = $this->listeners($eventName);
$counter = count($listeners); $counter = \count($listeners);
foreach ($listeners as $listener) { foreach ($listeners as $listener) {
--$counter;
$counter--; $result = \call_user_func_array($listener, $arguments);
$result = call_user_func_array($listener, $arguments); if (false === $result) {
if ($result === false) {
return false; return false;
} }
if ($counter > 0) { if ($counter > 0) {
if (!$continueCallBack()) break; if (!$continueCallBack()) {
break;
}
} }
} }
} }
return true; return true;
} }
/** /**
@@ -133,46 +121,37 @@ trait WildcardEmitterTrait {
* *
* @return callable[] * @return callable[]
*/ */
function listeners(string $eventName) : array { public function listeners(string $eventName): array
{
if (!array_key_exists($eventName, $this->listenerIndex)) { if (!\array_key_exists($eventName, $this->listenerIndex)) {
// Create a new index. // Create a new index.
$listeners = []; $listeners = [];
$listenersPriority = []; $listenersPriority = [];
if (isset($this->listeners[$eventName])) foreach ($this->listeners[$eventName] as $listener) { if (isset($this->listeners[$eventName])) {
foreach ($this->listeners[$eventName] as $listener) {
$listenersPriority[] = $listener[0]; $listenersPriority[] = $listener[0];
$listeners[] = $listener[1]; $listeners[] = $listener[1];
}
} }
foreach ($this->wildcardListeners as $wcEvent => $wcListeners) { foreach ($this->wildcardListeners as $wcEvent => $wcListeners) {
// Wildcard match // Wildcard match
if (substr($eventName, 0, strlen($wcEvent)) === $wcEvent) { if (\substr($eventName, 0, \strlen($wcEvent)) === $wcEvent) {
foreach ($wcListeners as $listener) { foreach ($wcListeners as $listener) {
$listenersPriority[] = $listener[0]; $listenersPriority[] = $listener[0];
$listeners[] = $listener[1]; $listeners[] = $listener[1];
} }
} }
} }
// Sorting by priority // Sorting by priority
array_multisort($listenersPriority, SORT_NUMERIC, $listeners); \array_multisort($listenersPriority, SORT_NUMERIC, $listeners);
// Creating index // Creating index
$this->listenersIndex[$eventName] = $listeners; $this->listenerIndex[$eventName] = $listeners;
} }
return $this->listenersIndex[$eventName]; return $this->listenerIndex[$eventName];
} }
/** /**
@@ -181,14 +160,14 @@ trait WildcardEmitterTrait {
* If the listener could not be found, this method will return false. If it * If the listener could not be found, this method will return false. If it
* was removed it will return true. * was removed it will return true.
*/ */
function removeListener(string $eventName, callable $listener) : bool { public function removeListener(string $eventName, callable $listener): bool
{
// If it ends with a wildcard, we use the wildcardListeners array // If it ends with a wildcard, we use the wildcardListeners array
if ($eventName[strlen($eventName) - 1] === '*') { if ('*' === $eventName[\strlen($eventName) - 1]) {
$eventName = substr($eventName, 0, -1); $eventName = \substr($eventName, 0, -1);
$listeners = & $this->wildcardListeners; $listeners = &$this->wildcardListeners;
} else { } else {
$listeners = & $this->listeners; $listeners = &$this->listeners;
} }
if (!isset($listeners[$eventName])) { if (!isset($listeners[$eventName])) {
@@ -196,21 +175,17 @@ trait WildcardEmitterTrait {
} }
foreach ($listeners[$eventName] as $index => $check) { foreach ($listeners[$eventName] as $index => $check) {
if ($check[1] === $listener) { if ($check[1] === $listener) {
// Remove listener // Remove listener
unset($listeners[$eventName][$index]); unset($listeners[$eventName][$index]);
// Reset index // Reset index
$this->listenerIndex = []; $this->listenerIndex = [];
return true; return true;
} }
} }
return false; return false;
} }
/** /**
@@ -219,38 +194,32 @@ trait WildcardEmitterTrait {
* If the eventName argument is specified, all listeners for that event are * If the eventName argument is specified, all listeners for that event are
* removed. If it is not specified, every listener for every event is * removed. If it is not specified, every listener for every event is
* removed. * removed.
*
* @return void
*/ */
function removeAllListeners(string $eventName = null) { public function removeAllListeners(string $eventName = null)
{
if (is_null($eventName)) { if (\is_null($eventName)) {
$this->listeners = []; $this->listeners = [];
$this->wildcardListeners = []; $this->wildcardListeners = [];
} else { } else {
if ('*' === $eventName[\strlen($eventName) - 1]) {
if ($eventName[strlen($eventName) - 1] === '*') {
// Wildcard event // Wildcard event
unset($this->wildcardListeners[substr($eventName, 0, -1)]); unset($this->wildcardListeners[\substr($eventName, 0, -1)]);
} else { } else {
unset($this->listeners[$eventName]); unset($this->listeners[$eventName]);
} }
} }
// Reset index // Reset index
$this->listenerIndex = []; $this->listenerIndex = [];
} }
/** /**
* The list of listeners * The list of listeners.
*/ */
protected $listeners = []; protected $listeners = [];
/** /**
* The list of "wildcard listeners". * The list of "wildcard listeners".
*/ */
protected $wildcardListeners = []; protected $wildcardListeners = [];

View File

@@ -1,4 +1,6 @@
<?php declare (strict_types=1); <?php
declare(strict_types=1);
namespace Sabre\Event; namespace Sabre\Event;
@@ -40,13 +42,18 @@ use Throwable;
* *
* }); * });
* *
* @return Sabre\Event\Promise * @return \Sabre\Event\Promise
*
* @psalm-template TReturn
* @psalm-param callable():\Generator<mixed, mixed, mixed, TReturn> $gen
* @psalm-return Promise<TReturn>
*
* @copyright Copyright (C) fruux GmbH (https://fruux.com/) * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/) * @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License * @license http://sabre.io/license/ Modified BSD License
*/ */
function coroutine(callable $gen) : Promise { function coroutine(callable $gen): Promise
{
$generator = $gen(); $generator = $gen();
if (!$generator instanceof Generator) { if (!$generator instanceof Generator) {
throw new \InvalidArgumentException('You must pass a generator function'); throw new \InvalidArgumentException('You must pass a generator function');
@@ -59,22 +66,20 @@ function coroutine(callable $gen) : Promise {
* So tempted to use the mythical y-combinator here, but it's not needed in * So tempted to use the mythical y-combinator here, but it's not needed in
* PHP. * PHP.
*/ */
$advanceGenerator = function() use (&$advanceGenerator, $generator, $promise, &$lastYieldResult) { $advanceGenerator = function () use (&$advanceGenerator, $generator, $promise) {
while ($generator->valid()) { while ($generator->valid()) {
$yieldedValue = $generator->current(); $yieldedValue = $generator->current();
if ($yieldedValue instanceof Promise) { if ($yieldedValue instanceof Promise) {
$yieldedValue->then( $yieldedValue->then(
function($value) use ($generator, &$advanceGenerator, &$lastYieldResult) { function ($value) use ($generator, &$advanceGenerator) {
$generator->send($value); $generator->send($value);
$advanceGenerator(); $advanceGenerator();
}, },
function(Throwable $reason) use ($generator, $advanceGenerator) { function (Throwable $reason) use ($generator, $advanceGenerator) {
$generator->throw($reason); $generator->throw($reason);
$advanceGenerator(); $advanceGenerator();
} }
)->otherwise(function(Throwable $reason) use ($promise) { )->otherwise(function (Throwable $reason) use ($promise) {
// This error handler would be called, if something in the // This error handler would be called, if something in the
// generator throws an exception, and it's not caught // generator throws an exception, and it's not caught
// locally. // locally.
@@ -87,31 +92,25 @@ function coroutine(callable $gen) : Promise {
// If the value was not a promise, we'll just let it pass through. // If the value was not a promise, we'll just let it pass through.
$generator->send($yieldedValue); $generator->send($yieldedValue);
} }
} }
// If the generator is at the end, and we didn't run into an exception, // If the generator is at the end, and we didn't run into an exception,
// We're grabbing the "return" value and fulfilling our top-level // We're grabbing the "return" value and fulfilling our top-level
// promise with its value. // promise with its value.
if (!$generator->valid() && $promise->state === Promise::PENDING) { if (!$generator->valid() && Promise::PENDING === $promise->state) {
$returnValue = $generator->getReturn(); $returnValue = $generator->getReturn();
// The return value is a promise.
if ($returnValue instanceof Promise) {
$returnValue->then(function($value) use ($promise) {
$promise->fulfill($value);
}, function(Throwable $reason) {
$promise->reject($reason);
});
} else {
$promise->fulfill($returnValue);
}
// The return value is a promise.
if ($returnValue instanceof Promise) {
$returnValue->then(function ($value) use ($promise) {
$promise->fulfill($value);
}, function (Throwable $reason) use ($promise) {
$promise->reject($reason);
});
} else {
$promise->fulfill($returnValue);
}
} }
}; };
try { try {
@@ -121,5 +120,4 @@ function coroutine(callable $gen) : Promise {
} }
return $promise; return $promise;
} }

View File

@@ -0,0 +1,2 @@
parameters:
level: 1

View File

@@ -1,18 +0,0 @@
<phpunit
colors="true"
bootstrap="vendor/autoload.php"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
strict="true"
>
<testsuite name="sabre-event">
<directory>tests/</directory>
</testsuite>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./lib/</directory>
</whitelist>
</filter>
</phpunit>

View File

@@ -4,15 +4,5 @@ composer.lock
# Tests # Tests
tests/cov/ tests/cov/
.phpunit.result.cache
# Composer binaries
bin/phpunit*
bin/phpcs*
bin/php-cs-fixer*
bin/sabre-cs-fixer*
# Vim
.*.swp
# development stuff
.php_cs.cache .php_cs.cache

View File

@@ -6,7 +6,7 @@ $config->getFinder()
->in(__DIR__); ->in(__DIR__);
$config->setRules([ $config->setRules([
'@PSR1' => true, '@PSR1' => true,
'@Symfony' =>true '@Symfony' => true
]); ]);
return $config; return $config;

View File

@@ -1,41 +0,0 @@
language: php
sudo: required
php:
- 7.0
- 7.1
- 7.2
- 7.3
- 7.4snapshot
env:
global:
- RUN_PHPSTAN="FALSE"
matrix:
- PREFER_LOWEST="" WITH_COVERAGE="--coverage-clover=coverage.xml"
- PREFER_LOWEST="--prefer-lowest" $WITH_COVERAGE=""
matrix:
include:
- name: 'PHPStan'
php: 7.2
env: RUN_PHPSTAN="TRUE"
fast_finish: true
cache:
directories:
- $HOME/.composer/cache
install:
- if [ $RUN_PHPSTAN == "TRUE" ]; then composer require --dev phpstan/phpstan; fi
before_script:
- composer update --prefer-source $PREFER_LOWEST
- PHP_BIN=$(phpenv which php)
- sudo $PHP_BIN -S localhost:80 -t $TRAVIS_BUILD_DIR/tests/www 2>/dev/null &
script:
- if [ $RUN_PHPSTAN == "FALSE" ]; then ./bin/phpunit --configuration tests/phpunit.xml $WITH_COVERAGE; fi
- if [ $RUN_PHPSTAN == "TRUE" ]; then php ./bin/phpstan analyse -c phpstan.neon lib; fi
after_success:
- bash <(curl -s https://codecov.io/bash)

View File

@@ -1,6 +1,68 @@
ChangeLog ChangeLog
========= =========
5.1.10 (2023-08-18)
------------------
* #225 Enhance tests/bootstrap.php to find autoloader in more environments (@phil-davis)
5.1.9 (2023-08-17)
------------------
* #223 skip testParseMimeTypeOnInvalidMimeType (@phil-davis)
5.1.8 (2023-08-17)
------------------
* #215 Improve CURLOPT_HTTPHEADER Setting Assignment (@amrita-shrestha)
5.1.7 (2023-06-26)
------------------
* #98 and #176 Add more tests (@peter279k)
* #207 fix: handle client disconnect properly with ignore_user_abort true (@kesselb)
5.1.6 (2022-07-15)
------------------
* #187 Allow testSendToGetLargeContent peak memory usage to be specified externally (@phil-davis)
* #188 Fix various small typos and grammar (@phil-davis)
* #189 Fix typo in text of status code 203 'Non-Authoritative Information' (@phil-davis)
5.1.5 (2022-07-09)
------------------
* #184 Remove 4GB file size workaround for 32bit OS / Stream Videos on IOS (@schoetju)
5.1.4 (2022-06-24)
------------------
* #182 Fix encoding detection on PHP 8.1 (@come-nc)
5.1.3 (2021-11-04)
------------------
* #179 version bump that was missed in 5.1.2 (@phil-davis)
5.1.2 (2021-11-04)
-------------------------
* #169 Ensure $_SERVER keys are read as strings (@fredrik-eriksson)
* #170 Fix deprecated usages on PHP 8.1 (@cedric-anne)
* #175 Add resource size to CURL options in client (from #172 ) (@Dartui)
5.1.1 (2020-10-03)
-------------------------
* #160: Added support for PHP 8.0 (@phil-davis)
5.1.0 (2020-01-31)
-------------------------
* Added support for PHP 7.4, dropped support for PHP 7.0 (@phil-davis)
* Updated testsuite for phpunit8, added phpstan coverage (@phil-davis)
* Added autoload-dev for test classes (@C0pyR1ght)
5.0.5 (2019-11-28) 5.0.5 (2019-11-28)
------------------------- -------------------------
@@ -48,7 +110,7 @@ ChangeLog
* #65: It's now possible to supply request/response bodies using a callback * #65: It's now possible to supply request/response bodies using a callback
functions. This allows very high-speed/low-memory responses to be created. functions. This allows very high-speed/low-memory responses to be created.
(@petrkotek). (@petrkotek).
* Strict typing is used every where this is applicable. * Strict typing is used everywhere this is applicable.
* Removed `URLUtil` class. It was deprecated a long time ago, and most of * Removed `URLUtil` class. It was deprecated a long time ago, and most of
its functions moved to the `sabre/uri` package. its functions moved to the `sabre/uri` package.
* Removed `Util` class. Most of its functions moved to the `functions.php` * Removed `Util` class. Most of its functions moved to the `functions.php`
@@ -67,7 +129,7 @@ ChangeLog
4.2.3 (2017-06-12) 4.2.3 (2017-06-12)
------------------ ------------------
* #74, #77: Work around 4GB file size limit at 32 Bit systems * #74, #77: Work around 4GB file size limit at 32-Bit systems
4.2.2 (2017-01-02) 4.2.2 (2017-01-02)
@@ -255,7 +317,7 @@ ChangeLog
* Changed: Response::send() is now Sapi::sendResponse($response). * Changed: Response::send() is now Sapi::sendResponse($response).
* Changed: Request::createFromPHPRequest is now Sapi::getRequest(). * Changed: Request::createFromPHPRequest is now Sapi::getRequest().
* Changed: Message::getBodyAsStream and Message::getBodyAsString were added. The * Changed: Message::getBodyAsStream and Message::getBodyAsString were added. The
existing Message::getBody changed it's behavior, so be careful. existing Message::getBody changed its behavior, so be careful.
2.0.0alpha5 (2013-11-07) 2.0.0alpha5 (2013-11-07)

View File

@@ -28,11 +28,11 @@ The objects are extendable and easily mockable.
Build status Build status
------------ ------------
| branch | status | | branch | status |
| ------ | ------ | |--------|---------------------------------------------------------------------------------------------------------------|
| master | [![Build Status](https://travis-ci.org/sabre-io/http.svg?branch=master)](https://travis-ci.org/sabre-io/http) | | master | [![Build Status](https://travis-ci.org/sabre-io/http.svg?branch=master)](https://travis-ci.org/sabre-io/http) |
| 4.2 | [![Build Status](https://travis-ci.org/sabre-io/http.svg?branch=4.2)](https://travis-ci.org/sabre-io/http) | | 4.2 | [![Build Status](https://travis-ci.org/sabre-io/http.svg?branch=4.2)](https://travis-ci.org/sabre-io/http) |
| 3.0 | [![Build Status](https://travis-ci.org/sabre-io/http.svg?branch=3.0)](https://travis-ci.org/sabre-io/http) | | 3.0 | [![Build Status](https://travis-ci.org/sabre-io/http.svg?branch=3.0)](https://travis-ci.org/sabre-io/http) |
Installation Installation
------------ ------------
@@ -84,7 +84,7 @@ $request = HTTP\Sapi::getRequest();
This line should only happen once in your entire application. Everywhere else This line should only happen once in your entire application. Everywhere else
you should pass this request object around using dependency injection. you should pass this request object around using dependency injection.
You should always typehint on it's interface: You should always typehint on its interface:
```php ```php
function handleRequest(HTTP\RequestInterface $request) { function handleRequest(HTTP\RequestInterface $request) {
@@ -133,9 +133,9 @@ Simply extending Request and Response may pose some problems:
1. You may want to extend the objects with new behaviors differently, in 1. You may want to extend the objects with new behaviors differently, in
different subsystems of your application, different subsystems of your application,
2. The `Sapi::getRequest` factory always returns a instance of 2. The `Sapi::getRequest` factory always returns an instance of
`Request` so you would have to override the factory method as well, `Request` so you would have to override the factory method as well,
3. By controlling the instantation and depend on specific `Request` and 3. By controlling the instantiation and depend on specific `Request` and
`Response` instances in your library or application, you make it harder to `Response` instances in your library or application, you make it harder to
work with other applications which also use `sabre/http`. work with other applications which also use `sabre/http`.
@@ -162,7 +162,7 @@ class MyRequest extends HTTP\RequestDecorator {
Our application assumes that the true `Request` object was instantiated Our application assumes that the true `Request` object was instantiated
somewhere else, by some other subsystem. This could simply be a call like somewhere else, by some other subsystem. This could simply be a call like
`$request = Sapi::getRequest()` at the top of your application, `$request = Sapi::getRequest()` at the top of your application,
but could also be somewhere in a unittest. but could also be somewhere in a unit test.
All we know in the current subsystem, is that we received a `$request` and All we know in the current subsystem, is that we received a `$request` and
that it implements `Sabre\HTTP\RequestInterface`. To decorate this object, that it implements `Sabre\HTTP\RequestInterface`. To decorate this object,
@@ -296,7 +296,7 @@ $remoteUrl = 'http://example.org/';
// The url we're proxying from. Please note that this must be a relative url, // The url we're proxying from. Please note that this must be a relative url,
// and basically acts as the base url. // and basically acts as the base url.
// //
// If youre $remoteUrl doesn't end with a slash, this one probably shouldn't // If your $remoteUrl doesn't end with a slash, this one probably shouldn't
// either. // either.
$myBaseUrl = '/reverseproxy.php'; $myBaseUrl = '/reverseproxy.php';
// $myBaseUrl = '/~evert/sabre/http/examples/reverseproxy.php/'; // $myBaseUrl = '/~evert/sabre/http/examples/reverseproxy.php/';
@@ -412,10 +412,10 @@ function setBaseUrl($url);
* If the full path is equal to the base url, this method will return an * If the full path is equal to the base url, this method will return an
* empty string. * empty string.
* *
* This method will also urldecode the path, and if the url was incoded as * This method will also urldecode the path, and if the url was encoded as
* ISO-8859-1, it will convert it to UTF-8. * ISO-8859-1, it will convert it to UTF-8.
* *
* If the path is outside of the base url, a LogicException will be thrown. * If the path is outside the base url, a LogicException will be thrown.
* *
* @return string * @return string
*/ */
@@ -491,7 +491,7 @@ function getBodyAsStream();
function getBodyAsString(); function getBodyAsString();
/** /**
* Returns the message body, as it's internal representation. * Returns the message body, as its internal representation.
* *
* This could be either a string or a stream. * This could be either a string or a stream.
* *
@@ -515,7 +515,7 @@ function setBody($body);
function getHeaders(); function getHeaders();
/** /**
* Returns a specific HTTP header, based on it's name. * Returns a specific HTTP header, based on its name.
* *
* The name must be treated as case-insensitive. * The name must be treated as case-insensitive.
* *
@@ -529,7 +529,7 @@ function getHeader($name);
/** /**
* Updates a HTTP header. * Updates a HTTP header.
* *
* The case-sensitity of the name value must be retained as-is. * The case-sensitivity of the name value must be retained as-is.
* *
* @param string $name * @param string $name
* @param string $value * @param string $value
@@ -561,7 +561,7 @@ function addHeaders(array $headers);
/** /**
* Removes a HTTP header. * Removes a HTTP header.
* *
* The specified header name must be treated as case-insenstive. * The specified header name must be treated as case-insensitive.
* This method should return true if the header was successfully deleted, * This method should return true if the header was successfully deleted,
* and false if the header did not exist. * and false if the header did not exist.
* *
@@ -593,7 +593,7 @@ function getHttpVersion();
/** /**
* Returns the current HTTP status. * Returns the current HTTP status.
* *
* This is the status-code as well as the human readable string. * This is the status-code as well as the human-readable string.
* *
* @return string * @return string
*/ */
@@ -602,7 +602,7 @@ function getStatus();
/** /**
* Sets the HTTP status code. * Sets the HTTP status code.
* *
* This can be either the full HTTP status code with human readable string, * This can be either the full HTTP status code with human-readable string,
* for example: "403 I can't let you do that, Dave". * for example: "403 I can't let you do that, Dave".
* *
* Or just the code, in which case the appropriate default message will be * Or just the code, in which case the appropriate default message will be
@@ -635,7 +635,7 @@ function getBodyAsStream();
function getBodyAsString(); function getBodyAsString();
/** /**
* Returns the message body, as it's internal representation. * Returns the message body, as its internal representation.
* *
* This could be either a string or a stream. * This could be either a string or a stream.
* *
@@ -660,7 +660,7 @@ function setBody($body);
function getHeaders(); function getHeaders();
/** /**
* Returns a specific HTTP header, based on it's name. * Returns a specific HTTP header, based on its name.
* *
* The name must be treated as case-insensitive. * The name must be treated as case-insensitive.
* *
@@ -674,7 +674,7 @@ function getHeader($name);
/** /**
* Updates a HTTP header. * Updates a HTTP header.
* *
* The case-sensitity of the name value must be retained as-is. * The case-sensitivity of the name value must be retained as-is.
* *
* @param string $name * @param string $name
* @param string $value * @param string $value
@@ -706,7 +706,7 @@ function addHeaders(array $headers);
/** /**
* Removes a HTTP header. * Removes a HTTP header.
* *
* The specified header name must be treated as case-insenstive. * The specified header name must be treated as case-insensitive.
* This method should return true if the header was successfully deleted, * This method should return true if the header was successfully deleted,
* and false if the header did not exist. * and false if the header did not exist.
* *

View File

@@ -1,44 +1,59 @@
{ {
"name": "sabre/http", "name" : "sabre/http",
"description" : "The sabre/http library provides utilities for dealing with http requests and responses. ", "description" : "The sabre/http library provides utilities for dealing with http requests and responses. ",
"keywords" : [ "HTTP" ], "keywords" : [
"homepage" : "https://github.com/fruux/sabre-http", "HTTP"
"license" : "BSD-3-Clause", ],
"require" : { "homepage" : "https://github.com/fruux/sabre-http",
"php" : "^7.0", "license" : "BSD-3-Clause",
"ext-mbstring" : "*", "require" : {
"ext-ctype" : "*", "php" : "^7.1 || ^8.0",
"ext-curl" : "*", "ext-mbstring" : "*",
"sabre/event" : ">=4.0 <6.0", "ext-ctype" : "*",
"sabre/uri" : "^2.0" "ext-curl" : "*",
}, "sabre/event" : ">=4.0 <6.0",
"require-dev" : { "sabre/uri" : "^2.0"
"phpunit/phpunit" : "^6.0 || ^7.0" },
}, "require-dev" : {
"suggest" : { "friendsofphp/php-cs-fixer" : "~2.17.1",
"ext-curl" : " to make http requests with the Client class" "phpstan/phpstan" : "^0.12",
}, "phpunit/phpunit" : "^7.5 || ^8.5 || ^9.0"
"authors" : [ },
{ "suggest" : {
"name" : "Evert Pot", "ext-curl" : " to make http requests with the Client class"
"email" : "me@evertpot.com", },
"homepage" : "http://evertpot.com/", "authors" : [{
"role" : "Developer" "name" : "Evert Pot",
} "email" : "me@evertpot.com",
], "homepage" : "http://evertpot.com/",
"support" : { "role" : "Developer"
"forum" : "https://groups.google.com/group/sabredav-discuss", }
"source" : "https://github.com/fruux/sabre-http" ],
}, "support" : {
"autoload" : { "forum" : "https://groups.google.com/group/sabredav-discuss",
"files" : [ "source" : "https://github.com/fruux/sabre-http"
"lib/functions.php" },
], "autoload" : {
"psr-4" : { "files" : [
"Sabre\\HTTP\\" : "lib/" "lib/functions.php"
} ],
}, "psr-4" : {
"config" : { "Sabre\\HTTP\\" : "lib/"
"bin-dir" : "bin/" }
} },
} "autoload-dev" : {
"psr-4" : {
"Sabre\\HTTP\\" : "tests/HTTP"
}
},
"scripts" : {
"phpstan" : "phpstan analyse lib tests",
"cs-fixer" : "php-cs-fixer fix",
"phpunit" : "phpunit --configuration tests/phpunit.xml",
"test" : [
"composer phpstan",
"composer cs-fixer",
"composer phpunit"
]
}
}

View File

@@ -1,62 +0,0 @@
<?php
/**
* This example demonstrates the ability for clients to work asynchronously.
*
* By default up to 10 requests will be executed in paralel. HTTP connections
* are re-used and DNS is cached, all thanks to the power of curl.
*
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
use Sabre\HTTP\Client;
use Sabre\HTTP\Request;
// Find the autoloader
$paths = [
__DIR__.'/../vendor/autoload.php',
__DIR__.'/../../../autoload.php',
__DIR__.'/vendor/autoload.php',
];
foreach ($paths as $path) {
if (file_exists($path)) {
include $path;
break;
}
}
// This is the request we're repeating a 1000 times.
$request = new Request('GET', 'http://localhost/');
$client = new Client();
for ($i = 0; $i < 1000; ++$i) {
echo "$i sending\n";
$client->sendAsync(
$request,
// This is the 'success' callback
function ($response) use ($i) {
echo "$i -> ".$response->getStatus()."\n";
},
// This is the 'error' callback. It is called for general connection
// problems (such as not being able to connect to a host, dns errors,
// etc.) and also cases where a response was returned, but it had a
// status code of 400 or higher.
function ($error) use ($i) {
if (Client::STATUS_CURLERROR === $error['status']) {
// Curl errors
echo "$i -> curl error: ".$error['curl_errmsg']."\n";
} else {
// HTTP errors
echo "$i -> ".$error['response']->getStatus()."\n";
}
}
);
}
// After everything is done, we call 'wait'. This causes the client to wait for
// all outstanding http requests to complete.
$client->wait();

View File

@@ -1,50 +0,0 @@
<?php
/**
* This example shows how to do Basic authentication.
* *.
*
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
$userList = [
'user1' => 'password',
'user2' => 'password',
];
use Sabre\HTTP\Auth;
use Sabre\HTTP\Response;
use Sabre\HTTP\Sapi;
// Find the autoloader
$paths = [
__DIR__.'/../vendor/autoload.php',
__DIR__.'/../../../autoload.php',
__DIR__.'/vendor/autoload.php',
];
foreach ($paths as $path) {
if (file_exists($path)) {
include $path;
break;
}
}
$request = Sapi::getRequest();
$response = new Response();
$basicAuth = new Auth\Basic('Locked down area', $request, $response);
if (!$userPass = $basicAuth->getCredentials()) {
// No username or password given
$basicAuth->requireLogin();
} elseif (!isset($userList[$userPass[0]]) || $userList[$userPass[0]] !== $userPass[1]) {
// Username or password are incorrect
$basicAuth->requireLogin();
} else {
// Success !
$response->setBody('You are logged in!');
}
// Sending the response
Sapi::sendResponse($response);

View File

@@ -1,37 +0,0 @@
<?php
/**
* This example shows how to make a HTTP request with the Request and Response
* objects.
*
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
use Sabre\HTTP\Client;
use Sabre\HTTP\Request;
// Find the autoloader
$paths = [
__DIR__.'/../vendor/autoload.php',
__DIR__.'/../../../autoload.php',
__DIR__.'/vendor/autoload.php',
];
foreach ($paths as $path) {
if (file_exists($path)) {
include $path;
break;
}
}
// Constructing the request.
$request = new Request('GET', 'http://localhost/');
$client = new Client();
//$client->addCurlSetting(CURLOPT_PROXY,'localhost:8888');
$response = $client->send($request);
echo "Response:\n";
echo (string) $response;

View File

@@ -1,51 +0,0 @@
<?php
/**
* This example shows how to do Digest authentication.
* *.
*
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
* @author Markus Staab
* @license http://sabre.io/license/ Modified BSD License
*/
$userList = [
'user1' => 'password',
'user2' => 'password',
];
use Sabre\HTTP\Auth;
use Sabre\HTTP\Response;
use Sabre\HTTP\Sapi;
// Find the autoloader
$paths = [
__DIR__.'/../vendor/autoload.php',
__DIR__.'/../../../autoload.php',
__DIR__.'/vendor/autoload.php',
];
foreach ($paths as $path) {
if (file_exists($path)) {
include $path;
break;
}
}
$request = Sapi::getRequest();
$response = new Response();
$digestAuth = new Auth\Digest('Locked down area', $request, $response);
$digestAuth->init();
if (!$userName = $digestAuth->getUsername()) {
// No username given
$digestAuth->requireLogin();
} elseif (!isset($userList[$userName]) || !$digestAuth->validatePassword($userList[$userName])) {
// Username or password are incorrect
$digestAuth->requireLogin();
} else {
// Success !
$response->setBody('You are logged in!');
}
// Sending the response
Sapi::sendResponse($response);

View File

@@ -1,48 +0,0 @@
<?php
// The url we're proxying to.
$remoteUrl = 'http://example.org/';
// The url we're proxying from. Please note that this must be a relative url,
// and basically acts as the base url.
//
// If your $remoteUrl doesn't end with a slash, this one probably shouldn't
// either.
$myBaseUrl = '/reverseproxy.php';
// $myBaseUrl = '/~evert/sabre/http/examples/reverseproxy.php/';
use Sabre\HTTP\Client;
use Sabre\HTTP\Sapi;
// Find the autoloader
$paths = [
__DIR__.'/../vendor/autoload.php',
__DIR__.'/../../../autoload.php',
__DIR__.'/vendor/autoload.php',
];
foreach ($paths as $path) {
if (file_exists($path)) {
include $path;
break;
}
}
$request = Sapi::getRequest();
$request->setBaseUrl($myBaseUrl);
$subRequest = clone $request;
// Removing the Host header.
$subRequest->removeHeader('Host');
// Rewriting the url.
$subRequest->setUrl($remoteUrl.$request->getPath());
$client = new Client();
// Sends the HTTP request to the server
$response = $client->send($subRequest);
// Sends the response back to the client that connected to the proxy.
Sapi::sendResponse($response);

View File

@@ -1,50 +0,0 @@
<?php
/**
* This simple example shows the capability of Request and Response objects to
* serialize themselves as strings.
*
* This is mainly useful for debugging purposes.
*
* @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/).
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
use Sabre\HTTP\Request;
use Sabre\HTTP\Response;
// Find the autoloader
$paths = [
__DIR__.'/../vendor/autoload.php',
__DIR__.'/../../../autoload.php',
__DIR__.'/vendor/autoload.php',
];
foreach ($paths as $path) {
if (file_exists($path)) {
include $path;
break;
}
}
$request = new Request('POST', '/foo');
$request->setHeaders([
'Host' => 'example.org',
'Content-Type' => 'application/json',
]);
$request->setBody(json_encode(['foo' => 'bar']));
echo $request;
echo "\r\n\r\n";
$response = new Response(424);
$response->setHeaders([
'Content-Type' => 'text/plain',
'Connection' => 'close',
]);
$response->setBody('ABORT! ABORT!');
echo $response;
echo "\r\n";

View File

@@ -42,7 +42,7 @@ abstract class AbstractAuth
/** /**
* Creates the object. * Creates the object.
*/ */
public function __construct(string $realm = 'SabreTooth', RequestInterface $request, ResponseInterface $response) public function __construct(string $realm, RequestInterface $request, ResponseInterface $response)
{ {
$this->realm = $realm; $this->realm = $realm;
$this->request = $request; $this->request = $request;
@@ -50,7 +50,7 @@ abstract class AbstractAuth
} }
/** /**
* This method sends the needed HTTP header and statuscode (401) to force * This method sends the needed HTTP header and status code (401) to force
* the user to login. * the user to login.
*/ */
abstract public function requireLogin(); abstract public function requireLogin();

View File

@@ -49,7 +49,7 @@ class Basic extends AbstractAuth
} }
/** /**
* This method sends the needed HTTP header and statuscode (401) to force * This method sends the needed HTTP header and status code (401) to force
* the user to login. * the user to login.
*/ */
public function requireLogin() public function requireLogin()

View File

@@ -42,7 +42,7 @@ class Bearer extends AbstractAuth
} }
/** /**
* This method sends the needed HTTP header and statuscode (401) to force * This method sends the needed HTTP header and status code (401) to force
* authentication. * authentication.
*/ */
public function requireLogin() public function requireLogin()

View File

@@ -46,7 +46,7 @@ class Digest extends AbstractAuth
/** /**
* Initializes the object. * Initializes the object.
*/ */
public function __construct(string $realm = 'SabreTooth', RequestInterface $request, ResponseInterface $response) public function __construct(string $realm, RequestInterface $request, ResponseInterface $response)
{ {
$this->nonce = uniqid(); $this->nonce = uniqid();
$this->opaque = md5($realm); $this->opaque = md5($realm);
@@ -133,7 +133,7 @@ class Digest extends AbstractAuth
return false; return false;
} }
// We need to add an md5 of the entire request body to the A2 part of the hash // We need to add an md5 of the entire request body to the A2 part of the hash
$body = $this->request->getBody($asString = true); $body = $this->request->getBody();
$this->request->setBody($body); $this->request->setBody($body);
$A2 .= ':'.md5($body); $A2 .= ':'.md5($body);
} elseif (!($this->qop & self::QOP_AUTH)) { } elseif (!($this->qop & self::QOP_AUTH)) {
@@ -174,7 +174,7 @@ class Digest extends AbstractAuth
/** /**
* This method returns the full digest string. * This method returns the full digest string.
* *
* It should be compatibile with mod_php format and other webservers. * It should be compatible with mod_php format and other webservers.
* *
* If the header could not be found, null will be returned * If the header could not be found, null will be returned
* *

View File

@@ -26,7 +26,7 @@ use Sabre\Uri;
* request before it's done, such as adding authentication headers. * request before it's done, such as adding authentication headers.
* *
* The afterRequest event will be emitted after the request is completed * The afterRequest event will be emitted after the request is completed
* succesfully. * successfully.
* *
* If a HTTP error is returned (status code higher than 399) the error event is * If a HTTP error is returned (status code higher than 399) the error event is
* triggered. It's possible using this event to retry the request, by setting * triggered. It's possible using this event to retry the request, by setting
@@ -53,7 +53,7 @@ class Client extends EventEmitter
protected $curlSettings = []; protected $curlSettings = [];
/** /**
* Wether or not exceptions should be thrown when a HTTP error is returned. * Whether exceptions should be thrown when a HTTP error is returned.
* *
* @var bool * @var bool
*/ */
@@ -376,11 +376,16 @@ class Client extends EventEmitter
default: default:
$body = $request->getBody(); $body = $request->getBody();
if (is_resource($body)) { if (is_resource($body)) {
$bodyStat = fstat($body);
// This needs to be set to PUT, regardless of the actual // This needs to be set to PUT, regardless of the actual
// method used. Without it, INFILE will be ignored for some // method used. Without it, INFILE will be ignored for some
// reason. // reason.
$settings[CURLOPT_PUT] = true; $settings[CURLOPT_PUT] = true;
$settings[CURLOPT_INFILE] = $request->getBody(); $settings[CURLOPT_INFILE] = $body;
if (false !== $bodyStat && array_key_exists('size', $bodyStat)) {
$settings[CURLOPT_INFILESIZE] = $bodyStat['size'];
}
} else { } else {
// For security we cast this to a string. If somehow an array could // For security we cast this to a string. If somehow an array could
// be passed here, it would be possible for an attacker to use @ to // be passed here, it would be possible for an attacker to use @ to
@@ -397,7 +402,10 @@ class Client extends EventEmitter
$nHeaders[] = $key.': '.$value; $nHeaders[] = $key.': '.$value;
} }
} }
$settings[CURLOPT_HTTPHEADER] = $nHeaders;
if ([] !== $nHeaders) {
$settings[CURLOPT_HTTPHEADER] = $nHeaders;
}
$settings[CURLOPT_URL] = $request->getUrl(); $settings[CURLOPT_URL] = $request->getUrl();
// FIXME: CURLOPT_PROTOCOLS is currently unsupported by HHVM // FIXME: CURLOPT_PROTOCOLS is currently unsupported by HHVM
if (defined('CURLOPT_PROTOCOLS')) { if (defined('CURLOPT_PROTOCOLS')) {
@@ -450,8 +458,6 @@ class Client extends EventEmitter
* * http_code - HTTP status code, as an int. Only set if Only set if * * http_code - HTTP status code, as an int. Only set if Only set if
* status is STATUS_SUCCESS, or STATUS_HTTPERROR * status is STATUS_SUCCESS, or STATUS_HTTPERROR
* *
* @param array $headerLines
* @param string $body
* @param resource $curlHandle * @param resource $curlHandle
*/ */
protected function parseCurlResponse(array $headerLines, string $body, $curlHandle): array protected function parseCurlResponse(array $headerLines, string $body, $curlHandle): array

View File

@@ -88,7 +88,7 @@ abstract class Message implements MessageInterface
* @var string|int|null * @var string|int|null
*/ */
$contentLength = $this->getHeader('Content-Length'); $contentLength = $this->getHeader('Content-Length');
if (is_int($contentLength) || ctype_digit($contentLength)) { if (null !== $contentLength && (is_int($contentLength) || ctype_digit($contentLength))) {
return stream_get_contents($body, (int) $contentLength); return stream_get_contents($body, (int) $contentLength);
} }
@@ -96,7 +96,7 @@ abstract class Message implements MessageInterface
} }
/** /**
* Returns the message body, as it's internal representation. * Returns the message body, as its internal representation.
* *
* This could be either a string, a stream or a callback writing the body to php://output. * This could be either a string, a stream or a callback writing the body to php://output.
* *
@@ -141,7 +141,7 @@ abstract class Message implements MessageInterface
} }
/** /**
* Returns a specific HTTP header, based on it's name. * Returns a specific HTTP header, based on its name.
* *
* The name must be treated as case-insensitive. * The name must be treated as case-insensitive.
* If the header does not exist, this method must return null. * If the header does not exist, this method must return null.
@@ -172,7 +172,7 @@ abstract class Message implements MessageInterface
* For every time the HTTP header appeared in the request or response, an * For every time the HTTP header appeared in the request or response, an
* item will appear in the array. * item will appear in the array.
* *
* If the header did not exists, this method will return an empty array. * If the header did not exist, this method will return an empty array.
* *
* @return string[] * @return string[]
*/ */
@@ -283,8 +283,6 @@ abstract class Message implements MessageInterface
/** /**
* Returns the HTTP version. * Returns the HTTP version.
*
* @return string
*/ */
public function getHttpVersion(): string public function getHttpVersion(): string
{ {

View File

@@ -51,7 +51,7 @@ trait MessageDecoratorTrait
} }
/** /**
* Returns the message body, as it's internal representation. * Returns the message body, as its internal representation.
* *
* This could be either a string or a stream. * This could be either a string or a stream.
* *
@@ -91,7 +91,7 @@ trait MessageDecoratorTrait
} }
/** /**
* Returns a specific HTTP header, based on it's name. * Returns a specific HTTP header, based on its name.
* *
* The name must be treated as case-insensitive. * The name must be treated as case-insensitive.
* If the header does not exist, this method must return null. * If the header does not exist, this method must return null.
@@ -116,7 +116,7 @@ trait MessageDecoratorTrait
* For every time the HTTP header appeared in the request or response, an * For every time the HTTP header appeared in the request or response, an
* item will appear in the array. * item will appear in the array.
* *
* If the header did not exists, this method will return an empty array. * If the header did not exist, this method will return an empty array.
*/ */
public function getHeaderAsArray(string $name): array public function getHeaderAsArray(string $name): array
{ {
@@ -180,8 +180,6 @@ trait MessageDecoratorTrait
* The specified header name must be treated as case-insensitive. * The specified header name must be treated as case-insensitive.
* This method should return true if the header was successfully deleted, * This method should return true if the header was successfully deleted,
* and false if the header did not exist. * and false if the header did not exist.
*
* @return bool
*/ */
public function removeHeader(string $name): bool public function removeHeader(string $name): bool
{ {

View File

@@ -29,13 +29,11 @@ interface MessageInterface
* *
* Note that because the underlying data may be based on a stream, this * Note that because the underlying data may be based on a stream, this
* method could only work correctly the first time. * method could only work correctly the first time.
*
* @return string
*/ */
public function getBodyAsString(): string; public function getBodyAsString(): string;
/** /**
* Returns the message body, as it's internal representation. * Returns the message body, as its internal representation.
* *
* This could be either a string, a stream or a callback writing the body to php://output * This could be either a string, a stream or a callback writing the body to php://output
* *
@@ -63,7 +61,7 @@ interface MessageInterface
public function hasHeader(string $name): bool; public function hasHeader(string $name): bool;
/** /**
* Returns a specific HTTP header, based on it's name. * Returns a specific HTTP header, based on its name.
* *
* The name must be treated as case-insensitive. * The name must be treated as case-insensitive.
* If the header does not exist, this method must return null. * If the header does not exist, this method must return null.
@@ -85,7 +83,7 @@ interface MessageInterface
* For every time the HTTP header appeared in the request or response, an * For every time the HTTP header appeared in the request or response, an
* item will appear in the array. * item will appear in the array.
* *
* If the header did not exists, this method will return an empty array. * If the header did not exist, this method will return an empty array.
* *
* @return string[] * @return string[]
*/ */
@@ -94,7 +92,7 @@ interface MessageInterface
/** /**
* Updates a HTTP header. * Updates a HTTP header.
* *
* The case-sensitity of the name value must be retained as-is. * The case-sensitivity of the name value must be retained as-is.
* *
* If the header already existed, it will be overwritten. * If the header already existed, it will be overwritten.
* *
@@ -133,7 +131,7 @@ interface MessageInterface
/** /**
* Removes a HTTP header. * Removes a HTTP header.
* *
* The specified header name must be treated as case-insenstive. * The specified header name must be treated as case-insensitive.
* This method should return true if the header was successfully deleted, * This method should return true if the header was successfully deleted,
* and false if the header did not exist. * and false if the header did not exist.
*/ */

View File

@@ -155,7 +155,7 @@ class Request extends Message implements RequestInterface
* If the full path is equal to the base url, this method will return an * If the full path is equal to the base url, this method will return an
* empty string. * empty string.
* *
* This method will also urldecode the path, and if the url was incoded as * This method will also urldecode the path, and if the url was encoded as
* ISO-8859-1, it will convert it to UTF-8. * ISO-8859-1, it will convert it to UTF-8.
* *
* If the path is outside of the base url, a LogicException will be thrown. * If the path is outside of the base url, a LogicException will be thrown.

View File

@@ -104,7 +104,7 @@ class RequestDecorator implements RequestInterface
* If the full path is equal to the base url, this method will return an * If the full path is equal to the base url, this method will return an
* empty string. * empty string.
* *
* This method will also urldecode the path, and if the url was incoded as * This method will also urldecode the path, and if the url was encoded as
* ISO-8859-1, it will convert it to UTF-8. * ISO-8859-1, it will convert it to UTF-8.
* *
* If the path is outside of the base url, a LogicException will be thrown. * If the path is outside of the base url, a LogicException will be thrown.

View File

@@ -67,7 +67,7 @@ interface RequestInterface extends MessageInterface
* If the full path is equal to the base url, this method will return an * If the full path is equal to the base url, this method will return an
* empty string. * empty string.
* *
* This method will also urldecode the path, and if the url was incoded as * This method will also urldecode the path, and if the url was encoded as
* ISO-8859-1, it will convert it to UTF-8. * ISO-8859-1, it will convert it to UTF-8.
* *
* If the path is outside of the base url, a LogicException will be thrown. * If the path is outside of the base url, a LogicException will be thrown.

View File

@@ -25,7 +25,7 @@ class Response extends Message implements ResponseInterface
200 => 'OK', 200 => 'OK',
201 => 'Created', 201 => 'Created',
202 => 'Accepted', 202 => 'Accepted',
203 => 'Non-Authorative Information', 203 => 'Non-Authoritative Information',
204 => 'No Content', 204 => 'No Content',
205 => 'Reset Content', 205 => 'Reset Content',
206 => 'Partial Content', 206 => 'Partial Content',
@@ -137,7 +137,7 @@ class Response extends Message implements ResponseInterface
/** /**
* Sets the HTTP status code. * Sets the HTTP status code.
* *
* This can be either the full HTTP status code with human readable string, * This can be either the full HTTP status code with human-readable string,
* for example: "403 I can't let you do that, Dave". * for example: "403 I can't let you do that, Dave".
* *
* Or just the code, in which case the appropriate default message will be * Or just the code, in which case the appropriate default message will be
@@ -149,7 +149,7 @@ class Response extends Message implements ResponseInterface
*/ */
public function setStatus($status) public function setStatus($status)
{ {
if (ctype_digit($status) || is_int($status)) { if (is_int($status) || ctype_digit($status)) {
$statusCode = $status; $statusCode = $status;
$statusText = self::$statusCodes[$status] ?? 'Unknown'; $statusText = self::$statusCodes[$status] ?? 'Unknown';
} else { } else {

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