readability: add missing dependencies
This commit is contained in:
parent
f7b3c50828
commit
5006c754c4
|
@ -807,7 +807,7 @@ class Handler_Public extends Handler {
|
|||
} else {
|
||||
user_error("PluginHandler[PUBLIC]: Requested method '$method' of unknown plugin '$plugin_name'.", E_USER_WARNING);
|
||||
header("Content-Type: text/json");
|
||||
print Errors::to_json(Errors::E_UNKNOWN_PLUGIN);
|
||||
print Errors::to_json(Errors::E_UNKNOWN_PLUGIN, ['plugin' => $plugin_name]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -419,5 +419,5 @@
|
|||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.1.0"
|
||||
"plugin-api-version": "2.0.0"
|
||||
}
|
||||
|
|
|
@ -42,75 +42,30 @@ namespace Composer\Autoload;
|
|||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var ?string */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<int, string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, string[]>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var bool[]
|
||||
* @psalm-var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var ?string */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var self[]
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param ?string $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
|
@ -120,47 +75,28 @@ class ClassLoader
|
|||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, array<int, string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] Array of classname => path
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $classMap Class to filename map
|
||||
* @psalm-param array<string, string> $classMap
|
||||
*
|
||||
* @return void
|
||||
* @param array $classMap Class to filename map
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
|
@ -175,11 +111,9 @@ class ClassLoader
|
|||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param string[]|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
|
@ -222,13 +156,11 @@ class ClassLoader
|
|||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
|
@ -272,10 +204,8 @@ class ClassLoader
|
|||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param string[]|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 base directories
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
|
@ -290,12 +220,10 @@ class ClassLoader
|
|||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
|
@ -315,8 +243,6 @@ class ClassLoader
|
|||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
|
@ -339,8 +265,6 @@ class ClassLoader
|
|||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
|
@ -361,8 +285,6 @@ class ClassLoader
|
|||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
|
@ -383,18 +305,14 @@ class ClassLoader
|
|||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
|
||||
if (null === $this->vendorDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
//no-op
|
||||
} elseif ($prepend) {
|
||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||
} else {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
|
@ -404,8 +322,6 @@ class ClassLoader
|
|||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
|
@ -420,7 +336,7 @@ class ClassLoader
|
|||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return true|null True if loaded, null otherwise
|
||||
* @return bool|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
|
@ -429,8 +345,6 @@ class ClassLoader
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -485,11 +399,6 @@ class ClassLoader
|
|||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
|
@ -561,10 +470,6 @@ class ClassLoader
|
|||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
* @private
|
||||
*/
|
||||
function includeFile($file)
|
||||
{
|
||||
|
|
|
@ -18,27 +18,90 @@ 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`
|
||||
* To require it's 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 $installed = array (
|
||||
'root' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'f7b3c50828d4604ac5999daf3c3405e65c877e2f',
|
||||
'name' => '__root__',
|
||||
),
|
||||
'versions' =>
|
||||
array (
|
||||
'__root__' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'f7b3c50828d4604ac5999daf3c3405e65c877e2f',
|
||||
),
|
||||
'fivefilters/readability.php' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
0 => '9999999-dev',
|
||||
),
|
||||
'reference' => '5ad152c70376002f043bb936d8ae5eed103fb993',
|
||||
),
|
||||
'league/uri' =>
|
||||
array (
|
||||
'pretty_version' => '6.7.1',
|
||||
'version' => '6.7.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '2d7c87a0860f3126a39f44a8a9bf2fed402dcfea',
|
||||
),
|
||||
'league/uri-interfaces' =>
|
||||
array (
|
||||
'pretty_version' => '2.3.0',
|
||||
'version' => '2.3.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '00e7e2943f76d8cb50c7dfdc2f6dee356e15e383',
|
||||
),
|
||||
'masterminds/html5' =>
|
||||
array (
|
||||
'pretty_version' => '2.7.5',
|
||||
'version' => '2.7.5.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'f640ac1bdddff06ea333a920c95bbad8872429ab',
|
||||
),
|
||||
'psr/http-message' =>
|
||||
array (
|
||||
'pretty_version' => '1.0.1',
|
||||
'version' => '1.0.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
|
||||
),
|
||||
'psr/log' =>
|
||||
array (
|
||||
'pretty_version' => '1.1.4',
|
||||
'version' => '1.1.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
|
||||
),
|
||||
),
|
||||
);
|
||||
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();
|
||||
|
||||
/**
|
||||
|
@ -54,6 +117,7 @@ class InstalledVersions
|
|||
$packages[] = array_keys($installed['versions']);
|
||||
}
|
||||
|
||||
|
||||
if (1 === \count($packages)) {
|
||||
return $packages[0];
|
||||
}
|
||||
|
@ -61,42 +125,19 @@ class InstalledVersions
|
|||
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)
|
||||
public static function isInstalled($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (isset($installed['versions'][$packageName])) {
|
||||
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,9 +151,10 @@ class InstalledVersions
|
|||
*
|
||||
* 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
|
||||
* @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)
|
||||
|
@ -222,26 +264,9 @@ class InstalledVersions
|
|||
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}
|
||||
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[]}
|
||||
*/
|
||||
public static function getRootPackage()
|
||||
{
|
||||
|
@ -253,38 +278,14 @@ class InstalledVersions
|
|||
/**
|
||||
* 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}>}
|
||||
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[]}, versions: list<string, array{pretty_version: ?string, version: ?string, aliases: ?string[], reference: ?string, replaced: ?string[], provided: ?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
|
||||
*
|
||||
|
@ -301,7 +302,7 @@ class InstalledVersions
|
|||
* @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
|
||||
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[]}, versions: list<string, array{pretty_version: ?string, version: ?string, aliases: ?string[], reference: ?string, replaced: ?string[], provided: ?string[]}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
|
@ -311,7 +312,6 @@ class InstalledVersions
|
|||
|
||||
/**
|
||||
* @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()
|
||||
{
|
||||
|
@ -322,27 +322,16 @@ class InstalledVersions
|
|||
$installed = array();
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
// @phpstan-ignore-next-line
|
||||
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;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
@ -18,4 +17,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ class ComposerAutoloaderInitb44cc79a0eaef9cd9c2f2ac697cbe9c0
|
|||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInitb44cc79a0eaef9cd9c2f2ac697cbe9c0', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInitb44cc79a0eaef9cd9c2f2ac697cbe9c0', 'loadClassLoader'));
|
||||
|
|
|
@ -1,79 +1,79 @@
|
|||
<?php return array(
|
||||
'root' => array(
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'reference' => 'fdd1c43612011060b4b876db438eb7ec62dd077d',
|
||||
'name' => '__root__',
|
||||
'dev' => true,
|
||||
<?php return array (
|
||||
'root' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'versions' => array(
|
||||
'__root__' => array(
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'reference' => 'fdd1c43612011060b4b876db438eb7ec62dd077d',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'fivefilters/readability.php' => array(
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../fivefilters/readability.php',
|
||||
'aliases' => array(
|
||||
0 => '9999999-dev',
|
||||
),
|
||||
'reference' => '5ad152c70376002f043bb936d8ae5eed103fb993',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'league/uri' => array(
|
||||
'pretty_version' => '6.7.1',
|
||||
'version' => '6.7.1.0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../league/uri',
|
||||
'aliases' => array(),
|
||||
'reference' => '2d7c87a0860f3126a39f44a8a9bf2fed402dcfea',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'league/uri-interfaces' => array(
|
||||
'pretty_version' => '2.3.0',
|
||||
'version' => '2.3.0.0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../league/uri-interfaces',
|
||||
'aliases' => array(),
|
||||
'reference' => '00e7e2943f76d8cb50c7dfdc2f6dee356e15e383',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'masterminds/html5' => array(
|
||||
'pretty_version' => '2.7.5',
|
||||
'version' => '2.7.5.0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../masterminds/html5',
|
||||
'aliases' => array(),
|
||||
'reference' => 'f640ac1bdddff06ea333a920c95bbad8872429ab',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'psr/http-message' => array(
|
||||
'pretty_version' => '1.0.1',
|
||||
'version' => '1.0.1.0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../psr/http-message',
|
||||
'aliases' => array(),
|
||||
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
|
||||
'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,
|
||||
),
|
||||
'reference' => 'f7b3c50828d4604ac5999daf3c3405e65c877e2f',
|
||||
'name' => '__root__',
|
||||
),
|
||||
'versions' =>
|
||||
array (
|
||||
'__root__' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'f7b3c50828d4604ac5999daf3c3405e65c877e2f',
|
||||
),
|
||||
'fivefilters/readability.php' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'aliases' =>
|
||||
array (
|
||||
0 => '9999999-dev',
|
||||
),
|
||||
'reference' => '5ad152c70376002f043bb936d8ae5eed103fb993',
|
||||
),
|
||||
'league/uri' =>
|
||||
array (
|
||||
'pretty_version' => '6.7.1',
|
||||
'version' => '6.7.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '2d7c87a0860f3126a39f44a8a9bf2fed402dcfea',
|
||||
),
|
||||
'league/uri-interfaces' =>
|
||||
array (
|
||||
'pretty_version' => '2.3.0',
|
||||
'version' => '2.3.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '00e7e2943f76d8cb50c7dfdc2f6dee356e15e383',
|
||||
),
|
||||
'masterminds/html5' =>
|
||||
array (
|
||||
'pretty_version' => '2.7.5',
|
||||
'version' => '2.7.5.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'f640ac1bdddff06ea333a920c95bbad8872429ab',
|
||||
),
|
||||
'psr/http-message' =>
|
||||
array (
|
||||
'pretty_version' => '1.0.1',
|
||||
'version' => '1.0.1.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
|
||||
),
|
||||
'psr/log' =>
|
||||
array (
|
||||
'pretty_version' => '1.1.4',
|
||||
'version' => '1.1.4.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
// platform_check.php @generated by Composer
|
||||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 70400)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.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
|
||||
);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 ignace nyamagana butera
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,68 @@
|
|||
{
|
||||
"name": "league/uri-interfaces",
|
||||
"description" : "Common interface for URI representation",
|
||||
"keywords": [
|
||||
"url",
|
||||
"uri",
|
||||
"rfc3986",
|
||||
"rfc3987"
|
||||
],
|
||||
"license": "MIT",
|
||||
"homepage": "http://github.com/thephpleague/uri-interfaces",
|
||||
"authors": [
|
||||
{
|
||||
"name" : "Ignace Nyamagana Butera",
|
||||
"email" : "nyamsprod@gmail.com",
|
||||
"homepage" : "https://nyamsprod.com"
|
||||
}
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/nyamsprod"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php" : "^7.2 || ^8.0",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^2.19",
|
||||
"phpstan/phpstan": "^0.12.90",
|
||||
"phpstan/phpstan-strict-rules": "^0.12.9",
|
||||
"phpstan/phpstan-phpunit": "^0.12.19",
|
||||
"phpunit/phpunit": "^8.5.15 || ^9.5"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Uri\\": "src/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"phpunit": "phpunit --coverage-text",
|
||||
"phpcs": "php-cs-fixer fix --dry-run --diff -vvv --allow-risky=yes --ansi",
|
||||
"phpcs:fix": "php-cs-fixer fix -vvv --allow-risky=yes --ansi",
|
||||
"phpstan": "phpstan analyse -l max -c phpstan.neon src --ansi --memory-limit 192M",
|
||||
"test": [
|
||||
"@phpunit",
|
||||
"@phpstan",
|
||||
"@phpcs:fix"
|
||||
]
|
||||
},
|
||||
"scripts-descriptions": {
|
||||
"phpunit": "Runs package test suite",
|
||||
"phpstan": "Runs complete codebase static analysis",
|
||||
"phpcs": "Runs coding style testing",
|
||||
"phpcs:fix": "Fix coding style issues",
|
||||
"test": "Runs all tests"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.x-dev"
|
||||
}
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "to use the IDNA feature",
|
||||
"symfony/intl": "to use the IDNA feature via Symfony Polyfill"
|
||||
}
|
||||
}
|
87
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/AuthorityInterface.php
vendored
Normal file
87
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/AuthorityInterface.php
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Contracts;
|
||||
|
||||
use League\Uri\Exceptions\IdnSupportMissing;
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
|
||||
interface AuthorityInterface extends UriComponentInterface
|
||||
{
|
||||
/**
|
||||
* Returns the host component of the authority.
|
||||
*/
|
||||
public function getHost(): ?string;
|
||||
|
||||
/**
|
||||
* Returns the port component of the authority.
|
||||
*/
|
||||
public function getPort(): ?int;
|
||||
|
||||
/**
|
||||
* Returns the user information component of the authority.
|
||||
*/
|
||||
public function getUserInfo(): ?string;
|
||||
|
||||
/**
|
||||
* Return an instance with the specified host.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified host.
|
||||
*
|
||||
* A null value provided for the host is equivalent to removing the host
|
||||
* information.
|
||||
*
|
||||
* @param ?string $host
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
* @throws IdnSupportMissing for component or transformations
|
||||
* requiring IDN support when IDN support is not present
|
||||
* or misconfigured.
|
||||
*/
|
||||
public function withHost(?string $host): self;
|
||||
|
||||
/**
|
||||
* Return an instance with the specified port.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified port.
|
||||
*
|
||||
* A null value provided for the port is equivalent to removing the port
|
||||
* information.
|
||||
*
|
||||
* @param ?int $port
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
*/
|
||||
public function withPort(?int $port): self;
|
||||
|
||||
/**
|
||||
* Return an instance with the specified user information.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified user information.
|
||||
*
|
||||
* Password is optional, but the user information MUST include the
|
||||
* user; a null value for the user is equivalent to removing user
|
||||
* information.
|
||||
*
|
||||
* @param ?string $user
|
||||
* @param ?string $password
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
*/
|
||||
public function withUserInfo(?string $user, ?string $password = null): self;
|
||||
}
|
92
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/DataPathInterface.php
vendored
Normal file
92
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/DataPathInterface.php
vendored
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Contracts;
|
||||
|
||||
interface DataPathInterface extends PathInterface
|
||||
{
|
||||
/**
|
||||
* Retrieve the data mime type associated to the URI.
|
||||
*
|
||||
* If no mimetype is present, this method MUST return the default mimetype 'text/plain'.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc2397#section-2
|
||||
*/
|
||||
public function getMimeType(): string;
|
||||
|
||||
/**
|
||||
* Retrieve the parameters associated with the Mime Type of the URI.
|
||||
*
|
||||
* If no parameters is present, this method MUST return the default parameter 'charset=US-ASCII'.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc2397#section-2
|
||||
*/
|
||||
public function getParameters(): string;
|
||||
|
||||
/**
|
||||
* Retrieve the mediatype associated with the URI.
|
||||
*
|
||||
* If no mediatype is present, this method MUST return the default parameter 'text/plain;charset=US-ASCII'.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc2397#section-3
|
||||
*
|
||||
* @return string The URI scheme.
|
||||
*/
|
||||
public function getMediaType(): string;
|
||||
|
||||
/**
|
||||
* Retrieves the data string.
|
||||
*
|
||||
* Retrieves the data part of the path. If no data part is provided return
|
||||
* a empty string
|
||||
*/
|
||||
public function getData(): string;
|
||||
|
||||
/**
|
||||
* Tells whether the data is binary safe encoded.
|
||||
*/
|
||||
public function isBinaryData(): bool;
|
||||
|
||||
/**
|
||||
* Save the data to a specific file.
|
||||
*/
|
||||
public function save(string $path, string $mode = 'w'): \SplFileObject;
|
||||
|
||||
/**
|
||||
* Returns an instance where the data part is base64 encoded.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance where the data part is base64 encoded
|
||||
*/
|
||||
public function toBinary(): self;
|
||||
|
||||
/**
|
||||
* Returns an instance where the data part is url encoded following RFC3986 rules.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance where the data part is url encoded
|
||||
*/
|
||||
public function toAscii(): self;
|
||||
|
||||
/**
|
||||
* Return an instance with the specified mediatype parameters.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified mediatype parameters.
|
||||
*
|
||||
* Users must provide encoded characters.
|
||||
*
|
||||
* An empty parameters value is equivalent to removing the parameter.
|
||||
*/
|
||||
public function withParameters(string $parameters): self;
|
||||
}
|
107
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/DomainHostInterface.php
vendored
Normal file
107
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/DomainHostInterface.php
vendored
Normal file
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Contracts;
|
||||
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
|
||||
/**
|
||||
* @extends \IteratorAggregate<string>
|
||||
*/
|
||||
interface DomainHostInterface extends \Countable, HostInterface, \IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* Returns the labels total number.
|
||||
*/
|
||||
public function count(): int;
|
||||
|
||||
/**
|
||||
* Iterate over the Domain labels.
|
||||
*
|
||||
* @return \Iterator<string>
|
||||
*/
|
||||
public function getIterator(): \Iterator;
|
||||
|
||||
/**
|
||||
* Retrieves a single host label.
|
||||
*
|
||||
* If the label offset has not been set, returns the null value.
|
||||
*/
|
||||
public function get(int $offset): ?string;
|
||||
|
||||
/**
|
||||
* Returns the associated key for a specific label or all the keys.
|
||||
*
|
||||
* @param ?string $label
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public function keys(?string $label = null): array;
|
||||
|
||||
/**
|
||||
* Tells whether the domain is absolute.
|
||||
*/
|
||||
public function isAbsolute(): bool;
|
||||
|
||||
/**
|
||||
* Prepends a label to the host.
|
||||
*/
|
||||
public function prepend(string $label): self;
|
||||
|
||||
/**
|
||||
* Appends a label to the host.
|
||||
*/
|
||||
public function append(string $label): self;
|
||||
|
||||
/**
|
||||
* Returns an instance with its Root label.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
*/
|
||||
public function withRootLabel(): self;
|
||||
|
||||
/**
|
||||
* Returns an instance without its Root label.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
*/
|
||||
public function withoutRootLabel(): self;
|
||||
|
||||
/**
|
||||
* Returns an instance with the modified label.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the new label
|
||||
*
|
||||
* If $key is non-negative, the added label will be the label at $key position from the start.
|
||||
* If $key is negative, the added label will be the label at $key position from the end.
|
||||
*
|
||||
* @throws SyntaxError If the key is invalid
|
||||
*/
|
||||
public function withLabel(int $key, string $label): self;
|
||||
|
||||
/**
|
||||
* Returns an instance without the specified label.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the modified component
|
||||
*
|
||||
* If $key is non-negative, the removed label will be the label at $key position from the start.
|
||||
* If $key is negative, the removed label will be the label at $key position from the end.
|
||||
*
|
||||
* @param int ...$keys
|
||||
*
|
||||
* @throws SyntaxError If the key is invalid
|
||||
*/
|
||||
public function withoutLabel(int ...$keys): self;
|
||||
}
|
22
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/FragmentInterface.php
vendored
Normal file
22
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/FragmentInterface.php
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Contracts;
|
||||
|
||||
interface FragmentInterface extends UriComponentInterface
|
||||
{
|
||||
/**
|
||||
* Returns the decoded fragment.
|
||||
*/
|
||||
public function decoded(): ?string;
|
||||
}
|
51
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/HostInterface.php
vendored
Normal file
51
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/HostInterface.php
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Contracts;
|
||||
|
||||
interface HostInterface extends UriComponentInterface
|
||||
{
|
||||
/**
|
||||
* Returns the ascii representation.
|
||||
*/
|
||||
public function toAscii(): ?string;
|
||||
|
||||
/**
|
||||
* Returns the unicode representation.
|
||||
*/
|
||||
public function toUnicode(): ?string;
|
||||
|
||||
/**
|
||||
* Returns the IP version.
|
||||
*
|
||||
* If the host is a not an IP this method will return null
|
||||
*/
|
||||
public function getIpVersion(): ?string;
|
||||
|
||||
/**
|
||||
* Returns the IP component If the Host is an IP address.
|
||||
*
|
||||
* If the host is a not an IP this method will return null
|
||||
*/
|
||||
public function getIp(): ?string;
|
||||
|
||||
/**
|
||||
* Tells whether the host is a domain name.
|
||||
*/
|
||||
public function isDomain(): bool;
|
||||
|
||||
/**
|
||||
* Tells whether the host is an IP Address.
|
||||
*/
|
||||
public function isIp(): bool;
|
||||
}
|
48
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/IpHostInterface.php
vendored
Normal file
48
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/IpHostInterface.php
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Contracts;
|
||||
|
||||
interface IpHostInterface extends HostInterface
|
||||
{
|
||||
/**
|
||||
* Returns whether or not the host is an IPv4 address.
|
||||
*/
|
||||
public function isIpv4(): bool;
|
||||
/**
|
||||
* Returns whether or not the host is an IPv6 address.
|
||||
*/
|
||||
public function isIpv6(): bool;
|
||||
|
||||
/**
|
||||
* Returns whether or not the host is an IPv6 address.
|
||||
*/
|
||||
public function isIpFuture(): bool;
|
||||
|
||||
/**
|
||||
* Returns whether or not the host has a ZoneIdentifier.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6874#section-4
|
||||
*/
|
||||
public function hasZoneIdentifier(): bool;
|
||||
|
||||
/**
|
||||
* Returns an host without its zone identifier according to RFC6874.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance without the host zone identifier according to RFC6874
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6874#section-4
|
||||
*/
|
||||
public function withoutZoneIdentifier(): self;
|
||||
}
|
90
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/PathInterface.php
vendored
Normal file
90
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/PathInterface.php
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Contracts;
|
||||
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
|
||||
interface PathInterface extends UriComponentInterface
|
||||
{
|
||||
/**
|
||||
* Returns the decoded path.
|
||||
*/
|
||||
public function decoded(): string;
|
||||
|
||||
/**
|
||||
* Returns whether or not the path is absolute or relative.
|
||||
*/
|
||||
public function isAbsolute(): bool;
|
||||
|
||||
/**
|
||||
* Returns whether or not the path has a trailing delimiter.
|
||||
*/
|
||||
public function hasTrailingSlash(): bool;
|
||||
|
||||
/**
|
||||
* Returns an instance without dot segments.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the path component normalized by removing
|
||||
* the dot segment.
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
*/
|
||||
public function withoutDotSegments(): self;
|
||||
|
||||
/**
|
||||
* Returns an instance with a leading slash.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the path component with a leading slash
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
*/
|
||||
public function withLeadingSlash(): self;
|
||||
|
||||
/**
|
||||
* Returns an instance without a leading slash.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the path component without a leading slash
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
*/
|
||||
public function withoutLeadingSlash(): self;
|
||||
|
||||
/**
|
||||
* Returns an instance with a trailing slash.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the path component with a trailing slash
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
*/
|
||||
public function withTrailingSlash(): self;
|
||||
|
||||
/**
|
||||
* Returns an instance without a trailing slash.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the path component without a trailing slash
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
*/
|
||||
public function withoutTrailingSlash(): self;
|
||||
}
|
22
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/PortInterface.php
vendored
Normal file
22
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/PortInterface.php
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Contracts;
|
||||
|
||||
interface PortInterface extends UriComponentInterface
|
||||
{
|
||||
/**
|
||||
* Returns the integer representation of the Port.
|
||||
*/
|
||||
public function toInt(): ?int;
|
||||
}
|
227
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/QueryInterface.php
vendored
Normal file
227
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/QueryInterface.php
vendored
Normal file
|
@ -0,0 +1,227 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Contracts;
|
||||
|
||||
/**
|
||||
* @extends \IteratorAggregate<array{0:string, 1:string|null}>
|
||||
*/
|
||||
interface QueryInterface extends \Countable, \IteratorAggregate, UriComponentInterface
|
||||
{
|
||||
/**
|
||||
* Returns the query separator.
|
||||
*/
|
||||
public function getSeparator(): string;
|
||||
|
||||
/**
|
||||
* Returns the number of key/value pairs present in the object.
|
||||
*/
|
||||
public function count(): int;
|
||||
|
||||
/**
|
||||
* Returns an iterator allowing to go through all key/value pairs contained in this object.
|
||||
*
|
||||
* The pair is represented as an array where the first value is the pair key
|
||||
* and the second value the pair value.
|
||||
*
|
||||
* The key of each pair is a string
|
||||
* The value of each pair is a scalar or the null value
|
||||
*
|
||||
* @return \Iterator<int, array{0:string, 1:string|null}>
|
||||
*/
|
||||
public function getIterator(): \Iterator;
|
||||
|
||||
/**
|
||||
* Returns an iterator allowing to go through all key/value pairs contained in this object.
|
||||
*
|
||||
* The return type is as a Iterator where its offset is the pair key and its value the pair value.
|
||||
*
|
||||
* The key of each pair is a string
|
||||
* The value of each pair is a scalar or the null value
|
||||
*
|
||||
* @return iterable<string, string|null>
|
||||
*/
|
||||
public function pairs(): iterable;
|
||||
|
||||
/**
|
||||
* Tells whether a pair with a specific name exists.
|
||||
*
|
||||
* @see https://url.spec.whatwg.org/#dom-urlsearchparams-has
|
||||
*/
|
||||
public function has(string $key): bool;
|
||||
|
||||
/**
|
||||
* Returns the first value associated to the given pair name.
|
||||
*
|
||||
* If no value is found null is returned
|
||||
*
|
||||
* @see https://url.spec.whatwg.org/#dom-urlsearchparams-get
|
||||
*/
|
||||
public function get(string $key): ?string;
|
||||
|
||||
/**
|
||||
* Returns all the values associated to the given pair name as an array or all
|
||||
* the instance pairs.
|
||||
*
|
||||
* If no value is found an empty array is returned
|
||||
*
|
||||
* @see https://url.spec.whatwg.org/#dom-urlsearchparams-getall
|
||||
*
|
||||
* @return array<int, string|null>
|
||||
*/
|
||||
public function getAll(string $key): array;
|
||||
|
||||
/**
|
||||
* Returns the store PHP variables as elements of an array.
|
||||
*
|
||||
* The result is similar as PHP parse_str when used with its
|
||||
* second argument with the difference that variable names are
|
||||
* not mangled.
|
||||
*
|
||||
* If a key is submitted it will returns the value attached to it or null
|
||||
*
|
||||
* @see http://php.net/parse_str
|
||||
* @see https://wiki.php.net/rfc/on_demand_name_mangling
|
||||
*
|
||||
* @param ?string $key
|
||||
* @return mixed the collection of stored PHP variables or the empty array if no input is given,
|
||||
* the single value of a stored PHP variable or null if the variable is not present in the collection
|
||||
*/
|
||||
public function params(?string $key = null);
|
||||
|
||||
/**
|
||||
* Returns the RFC1738 encoded query.
|
||||
*/
|
||||
public function toRFC1738(): ?string;
|
||||
|
||||
/**
|
||||
* Returns the RFC3986 encoded query.
|
||||
*
|
||||
* @see ::getContent
|
||||
*/
|
||||
public function toRFC3986(): ?string;
|
||||
|
||||
/**
|
||||
* Returns an instance with a different separator.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the query component with a different separator
|
||||
*/
|
||||
public function withSeparator(string $separator): self;
|
||||
|
||||
/**
|
||||
* Sorts the query string by offset, maintaining offset to data correlations.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the modified query
|
||||
*
|
||||
* @see https://url.spec.whatwg.org/#dom-urlsearchparams-sort
|
||||
*/
|
||||
public function sort(): self;
|
||||
|
||||
/**
|
||||
* Returns an instance without duplicate key/value pair.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the query component normalized by removing
|
||||
* duplicate pairs whose key/value are the same.
|
||||
*/
|
||||
public function withoutDuplicates(): self;
|
||||
|
||||
/**
|
||||
* Returns an instance without empty key/value where the value is the null value.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the query component normalized by removing
|
||||
* empty pairs.
|
||||
*
|
||||
* A pair is considered empty if its value is equal to the null value
|
||||
*/
|
||||
public function withoutEmptyPairs(): self;
|
||||
|
||||
/**
|
||||
* Returns an instance where numeric indices associated to PHP's array like key are removed.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the query component normalized so that numeric indexes
|
||||
* are removed from the pair key value.
|
||||
*
|
||||
* ie.: toto[3]=bar[3]&foo=bar becomes toto[]=bar[3]&foo=bar
|
||||
*/
|
||||
public function withoutNumericIndices(): self;
|
||||
|
||||
/**
|
||||
* Returns an instance with the a new key/value pair added to it.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the modified query
|
||||
*
|
||||
* If the pair already exists the value will replace the existing value.
|
||||
*
|
||||
* @see https://url.spec.whatwg.org/#dom-urlsearchparams-set
|
||||
*
|
||||
* @param ?string $value
|
||||
*/
|
||||
public function withPair(string $key, ?string $value): self;
|
||||
|
||||
/**
|
||||
* Returns an instance with the new pairs set to it.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the modified query
|
||||
*
|
||||
* @see ::withPair
|
||||
*/
|
||||
public function merge(string $query): self;
|
||||
|
||||
/**
|
||||
* Returns an instance without the specified keys.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the modified component
|
||||
*
|
||||
* @param string ...$keys
|
||||
*/
|
||||
public function withoutPair(string ...$keys): self;
|
||||
|
||||
/**
|
||||
* Returns a new instance with a specified key/value pair appended as a new pair.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the modified query
|
||||
*
|
||||
* @param ?string $value
|
||||
*/
|
||||
public function appendTo(string $key, ?string $value): self;
|
||||
|
||||
/**
|
||||
* Returns an instance with the new pairs appended to it.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the modified query
|
||||
*
|
||||
* If the pair already exists the value will be added to it.
|
||||
*/
|
||||
public function append(string $query): self;
|
||||
|
||||
/**
|
||||
* Returns an instance without the specified params.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the modified component without PHP's value.
|
||||
* PHP's mangled is not taken into account.
|
||||
*
|
||||
* @param string ...$keys
|
||||
*/
|
||||
public function withoutParam(string ...$keys): self;
|
||||
}
|
147
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/SegmentedPathInterface.php
vendored
Normal file
147
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/SegmentedPathInterface.php
vendored
Normal file
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Contracts;
|
||||
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
|
||||
/**
|
||||
* @extends \IteratorAggregate<string>
|
||||
*/
|
||||
interface SegmentedPathInterface extends \Countable, \IteratorAggregate, PathInterface
|
||||
{
|
||||
/**
|
||||
* Returns the total number of segments in the path.
|
||||
*/
|
||||
public function count(): int;
|
||||
|
||||
/**
|
||||
* Iterate over the path segment.
|
||||
*
|
||||
* @return \Iterator<string>
|
||||
*/
|
||||
public function getIterator(): \Iterator;
|
||||
|
||||
/**
|
||||
* Returns parent directory's path.
|
||||
*/
|
||||
public function getDirname(): string;
|
||||
|
||||
/**
|
||||
* Returns the path basename.
|
||||
*/
|
||||
public function getBasename(): string;
|
||||
|
||||
/**
|
||||
* Returns the basename extension.
|
||||
*/
|
||||
public function getExtension(): string;
|
||||
|
||||
/**
|
||||
* Retrieves a single path segment.
|
||||
*
|
||||
* If the segment offset has not been set, returns null.
|
||||
*/
|
||||
public function get(int $offset): ?string;
|
||||
|
||||
/**
|
||||
* Returns the associated key for a specific segment.
|
||||
*
|
||||
* If a value is specified only the keys associated with
|
||||
* the given value will be returned
|
||||
*
|
||||
* @param ?string $segment
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public function keys(?string $segment = null): array;
|
||||
|
||||
/**
|
||||
* Appends a segment to the path.
|
||||
*/
|
||||
public function append(string $segment): self;
|
||||
|
||||
/**
|
||||
* Prepends a segment to the path.
|
||||
*/
|
||||
public function prepend(string $segment): self;
|
||||
|
||||
/**
|
||||
* Returns an instance with the modified segment.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the new segment
|
||||
*
|
||||
* If $key is non-negative, the added segment will be the segment at $key position from the start.
|
||||
* If $key is negative, the added segment will be the segment at $key position from the end.
|
||||
*
|
||||
* @param ?string $segment
|
||||
*
|
||||
* @throws SyntaxError If the key is invalid
|
||||
*/
|
||||
public function withSegment(int $key, ?string $segment): self;
|
||||
|
||||
/**
|
||||
* Returns an instance without the specified segment.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the modified component
|
||||
*
|
||||
* If $key is non-negative, the removed segment will be the segment at $key position from the start.
|
||||
* If $key is negative, the removed segment will be the segment at $key position from the end.
|
||||
*
|
||||
* @param int ...$keys remaining keys to remove
|
||||
*
|
||||
* @throws SyntaxError If the key is invalid
|
||||
*/
|
||||
public function withoutSegment(int ...$keys): self;
|
||||
|
||||
/**
|
||||
* Returns an instance without duplicate delimiters.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the path component normalized by removing
|
||||
* multiple consecutive empty segment
|
||||
*/
|
||||
public function withoutEmptySegments(): self;
|
||||
|
||||
/**
|
||||
* Returns an instance with the specified parent directory's path.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the extension basename modified.
|
||||
*
|
||||
* @param ?string $path
|
||||
*/
|
||||
public function withDirname(?string $path): self;
|
||||
|
||||
/**
|
||||
* Returns an instance with the specified basename.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the extension basename modified.
|
||||
*
|
||||
* @param ?string $basename
|
||||
*/
|
||||
public function withBasename(?string $basename): self;
|
||||
|
||||
/**
|
||||
* Returns an instance with the specified basename extension.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the extension basename modified.
|
||||
*
|
||||
* @param ?string $extension
|
||||
*/
|
||||
public function withExtension(?string $extension): self;
|
||||
}
|
88
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/UriComponentInterface.php
vendored
Normal file
88
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/UriComponentInterface.php
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Contracts;
|
||||
|
||||
use League\Uri\Exceptions\IdnSupportMissing;
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
|
||||
interface UriComponentInterface extends \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* Returns the instance content.
|
||||
*
|
||||
* If the instance is defined, the value returned MUST be encoded according to the
|
||||
* selected encoding algorithm. In any case, the value MUST NOT double-encode any character
|
||||
* depending on the selected encoding algorithm.
|
||||
*
|
||||
* To determine what characters to encode, please refer to RFC 3986, Sections 2 and 3.
|
||||
* or RFC 3987 Section 3. By default the content is encoded according to RFC3986
|
||||
*
|
||||
* If the instance is not defined null is returned
|
||||
*/
|
||||
public function getContent(): ?string;
|
||||
|
||||
/**
|
||||
* Returns the instance string representation.
|
||||
*
|
||||
* If the instance is defined, the value returned MUST be percent-encoded,
|
||||
* but MUST NOT double-encode any characters. To determine what characters
|
||||
* to encode, please refer to RFC 3986, Sections 2 and 3.
|
||||
*
|
||||
* If the instance is not defined an empty string is returned
|
||||
*/
|
||||
public function __toString(): string;
|
||||
|
||||
/**
|
||||
* Returns the instance json representation.
|
||||
*
|
||||
* If the instance is defined, the value returned MUST be percent-encoded,
|
||||
* but MUST NOT double-encode any characters. To determine what characters
|
||||
* to encode, please refer to RFC 3986 or RFC 1738.
|
||||
*
|
||||
* If the instance is not defined null is returned
|
||||
*/
|
||||
public function jsonSerialize(): ?string;
|
||||
|
||||
/**
|
||||
* Returns the instance string representation with its optional URI delimiters.
|
||||
*
|
||||
* The value returned MUST be percent-encoded, but MUST NOT double-encode any
|
||||
* characters. To determine what characters to encode, please refer to RFC 3986,
|
||||
* Sections 2 and 3.
|
||||
*
|
||||
* If the instance is not defined an empty string is returned
|
||||
*/
|
||||
public function getUriComponent(): string;
|
||||
|
||||
/**
|
||||
* Returns an instance with the specified content.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified content.
|
||||
*
|
||||
* Users can provide both encoded and decoded content characters.
|
||||
*
|
||||
* A null value is equivalent to removing the component content.
|
||||
*
|
||||
*
|
||||
* @param ?string $content
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
* @throws IdnSupportMissing for component or transformations
|
||||
* requiring IDN support when IDN support is not present
|
||||
* or misconfigured.
|
||||
*/
|
||||
public function withContent(?string $content): self;
|
||||
}
|
20
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/UriException.php
vendored
Normal file
20
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/UriException.php
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Contracts;
|
||||
|
||||
use Throwable;
|
||||
|
||||
interface UriException extends Throwable
|
||||
{
|
||||
}
|
292
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/UriInterface.php
vendored
Normal file
292
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/UriInterface.php
vendored
Normal file
|
@ -0,0 +1,292 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Contracts;
|
||||
|
||||
use League\Uri\Exceptions\IdnSupportMissing;
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
|
||||
interface UriInterface extends \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* Returns the string representation as a URI reference.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc3986#section-4.1
|
||||
*/
|
||||
public function __toString(): string;
|
||||
|
||||
/**
|
||||
* Returns the string representation as a URI reference.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc3986#section-4.1
|
||||
* @see ::__toString
|
||||
*/
|
||||
public function jsonSerialize(): string;
|
||||
|
||||
/**
|
||||
* Retrieve the scheme component of the URI.
|
||||
*
|
||||
* If no scheme is present, this method MUST return a null value.
|
||||
*
|
||||
* The value returned MUST be normalized to lowercase, per RFC 3986
|
||||
* Section 3.1.
|
||||
*
|
||||
* The trailing ":" character is not part of the scheme and MUST NOT be
|
||||
* added.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.1
|
||||
*/
|
||||
public function getScheme(): ?string;
|
||||
|
||||
/**
|
||||
* Retrieve the authority component of the URI.
|
||||
*
|
||||
* If no scheme is present, this method MUST return a null value.
|
||||
*
|
||||
* If the port component is not set or is the standard port for the current
|
||||
* scheme, it SHOULD NOT be included.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.2
|
||||
*/
|
||||
public function getAuthority(): ?string;
|
||||
|
||||
/**
|
||||
* Retrieve the user information component of the URI.
|
||||
*
|
||||
* If no scheme is present, this method MUST return a null value.
|
||||
*
|
||||
* If a user is present in the URI, this will return that value;
|
||||
* additionally, if the password is also present, it will be appended to the
|
||||
* user value, with a colon (":") separating the values.
|
||||
*
|
||||
* The trailing "@" character is not part of the user information and MUST
|
||||
* NOT be added.
|
||||
*/
|
||||
public function getUserInfo(): ?string;
|
||||
|
||||
/**
|
||||
* Retrieve the host component of the URI.
|
||||
*
|
||||
* If no host is present this method MUST return a null value.
|
||||
*
|
||||
* The value returned MUST be normalized to lowercase, per RFC 3986
|
||||
* Section 3.2.2.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
*/
|
||||
public function getHost(): ?string;
|
||||
|
||||
/**
|
||||
* Retrieve the port component of the URI.
|
||||
*
|
||||
* If a port is present, and it is non-standard for the current scheme,
|
||||
* this method MUST return it as an integer. If the port is the standard port
|
||||
* used with the current scheme, this method SHOULD return null.
|
||||
*
|
||||
* If no port is present, and no scheme is present, this method MUST return
|
||||
* a null value.
|
||||
*
|
||||
* If no port is present, but a scheme is present, this method MAY return
|
||||
* the standard port for that scheme, but SHOULD return null.
|
||||
*/
|
||||
public function getPort(): ?int;
|
||||
|
||||
/**
|
||||
* Retrieve the path component of the URI.
|
||||
*
|
||||
* The path can either be empty or absolute (starting with a slash) or
|
||||
* rootless (not starting with a slash). Implementations MUST support all
|
||||
* three syntaxes.
|
||||
*
|
||||
* Normally, the empty path "" and absolute path "/" are considered equal as
|
||||
* defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically
|
||||
* do this normalization because in contexts with a trimmed base path, e.g.
|
||||
* the front controller, this difference becomes significant. It's the task
|
||||
* of the user to handle both "" and "/".
|
||||
*
|
||||
* The value returned MUST be percent-encoded, but MUST NOT double-encode
|
||||
* any characters. To determine what characters to encode, please refer to
|
||||
* RFC 3986, Sections 2 and 3.3.
|
||||
*
|
||||
* As an example, if the value should include a slash ("/") not intended as
|
||||
* delimiter between path segments, that value MUST be passed in encoded
|
||||
* form (e.g., "%2F") to the instance.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-2
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.3
|
||||
*/
|
||||
public function getPath(): string;
|
||||
|
||||
/**
|
||||
* Retrieve the query string of the URI.
|
||||
*
|
||||
* If no host is present this method MUST return a null value.
|
||||
*
|
||||
* The leading "?" character is not part of the query and MUST NOT be
|
||||
* added.
|
||||
*
|
||||
* The value returned MUST be percent-encoded, but MUST NOT double-encode
|
||||
* any characters. To determine what characters to encode, please refer to
|
||||
* RFC 3986, Sections 2 and 3.4.
|
||||
*
|
||||
* As an example, if a value in a key/value pair of the query string should
|
||||
* include an ampersand ("&") not intended as a delimiter between values,
|
||||
* that value MUST be passed in encoded form (e.g., "%26") to the instance.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-2
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.4
|
||||
*/
|
||||
public function getQuery(): ?string;
|
||||
|
||||
/**
|
||||
* Retrieve the fragment component of the URI.
|
||||
*
|
||||
* If no host is present this method MUST return a null value.
|
||||
*
|
||||
* The leading "#" character is not part of the fragment and MUST NOT be
|
||||
* added.
|
||||
*
|
||||
* The value returned MUST be percent-encoded, but MUST NOT double-encode
|
||||
* any characters. To determine what characters to encode, please refer to
|
||||
* RFC 3986, Sections 2 and 3.5.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-2
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.5
|
||||
*/
|
||||
public function getFragment(): ?string;
|
||||
|
||||
/**
|
||||
* Return an instance with the specified scheme.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified scheme.
|
||||
*
|
||||
* A null value provided for the scheme is equivalent to removing the scheme
|
||||
* information.
|
||||
*
|
||||
* @param ?string $scheme
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
*/
|
||||
public function withScheme(?string $scheme): self;
|
||||
|
||||
/**
|
||||
* Return an instance with the specified user information.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified user information.
|
||||
*
|
||||
* Password is optional, but the user information MUST include the
|
||||
* user; a null value for the user is equivalent to removing user
|
||||
* information.
|
||||
*
|
||||
* @param ?string $user
|
||||
* @param ?string $password
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
*/
|
||||
public function withUserInfo(?string $user, ?string $password = null): self;
|
||||
|
||||
/**
|
||||
* Return an instance with the specified host.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified host.
|
||||
*
|
||||
* A null value provided for the host is equivalent to removing the host
|
||||
* information.
|
||||
*
|
||||
* @param ?string $host
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
* @throws IdnSupportMissing for component or transformations
|
||||
* requiring IDN support when IDN support is not present
|
||||
* or misconfigured.
|
||||
*/
|
||||
public function withHost(?string $host): self;
|
||||
|
||||
/**
|
||||
* Return an instance with the specified port.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified port.
|
||||
*
|
||||
* A null value provided for the port is equivalent to removing the port
|
||||
* information.
|
||||
*
|
||||
* @param ?int $port
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
*/
|
||||
public function withPort(?int $port): self;
|
||||
|
||||
/**
|
||||
* Return an instance with the specified path.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified path.
|
||||
*
|
||||
* The path can either be empty or absolute (starting with a slash) or
|
||||
* rootless (not starting with a slash). Implementations MUST support all
|
||||
* three syntaxes.
|
||||
*
|
||||
* Users can provide both encoded and decoded path characters.
|
||||
* Implementations ensure the correct encoding as outlined in getPath().
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
*/
|
||||
public function withPath(string $path): self;
|
||||
|
||||
/**
|
||||
* Return an instance with the specified query string.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified query string.
|
||||
*
|
||||
* Users can provide both encoded and decoded query characters.
|
||||
* Implementations ensure the correct encoding as outlined in getQuery().
|
||||
*
|
||||
* A null value provided for the query is equivalent to removing the query
|
||||
* information.
|
||||
*
|
||||
* @param ?string $query
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
*/
|
||||
public function withQuery(?string $query): self;
|
||||
|
||||
/**
|
||||
* Return an instance with the specified URI fragment.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified URI fragment.
|
||||
*
|
||||
* Users can provide both encoded and decoded fragment characters.
|
||||
* Implementations ensure the correct encoding as outlined in getFragment().
|
||||
*
|
||||
* A null value provided for the fragment is equivalent to removing the fragment
|
||||
* information.
|
||||
*
|
||||
* @param ?string $fragment
|
||||
*
|
||||
* @throws SyntaxError for invalid component or transformations
|
||||
* that would result in a object in invalid state.
|
||||
*/
|
||||
public function withFragment(?string $fragment): self;
|
||||
}
|
40
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/UserInfoInterface.php
vendored
Normal file
40
plugins/af_readability/vendor/league/uri-interfaces/src/Contracts/UserInfoInterface.php
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Contracts;
|
||||
|
||||
interface UserInfoInterface extends UriComponentInterface
|
||||
{
|
||||
/**
|
||||
* Returns the user component part.
|
||||
*/
|
||||
public function getUser(): ?string;
|
||||
|
||||
/**
|
||||
* Returns the pass component part.
|
||||
*/
|
||||
public function getPass(): ?string;
|
||||
|
||||
/**
|
||||
* Returns an instance with the specified user and/or pass.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified user.
|
||||
*
|
||||
* An empty user is equivalent to removing the user information.
|
||||
*
|
||||
* @param ?string $user
|
||||
* @param ?string $pass
|
||||
*/
|
||||
public function withUserInfo(?string $user, ?string $pass = null): self;
|
||||
}
|
20
plugins/af_readability/vendor/league/uri-interfaces/src/Exceptions/FileinfoSupportMissing.php
vendored
Normal file
20
plugins/af_readability/vendor/league/uri-interfaces/src/Exceptions/FileinfoSupportMissing.php
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Exceptions;
|
||||
|
||||
use League\Uri\Contracts\UriException;
|
||||
|
||||
class FileinfoSupportMissing extends \RuntimeException implements UriException
|
||||
{
|
||||
}
|
20
plugins/af_readability/vendor/league/uri-interfaces/src/Exceptions/IdnSupportMissing.php
vendored
Normal file
20
plugins/af_readability/vendor/league/uri-interfaces/src/Exceptions/IdnSupportMissing.php
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Exceptions;
|
||||
|
||||
use League\Uri\Contracts\UriException;
|
||||
|
||||
class IdnSupportMissing extends \RuntimeException implements UriException
|
||||
{
|
||||
}
|
46
plugins/af_readability/vendor/league/uri-interfaces/src/Exceptions/IdnaConversionFailed.php
vendored
Normal file
46
plugins/af_readability/vendor/league/uri-interfaces/src/Exceptions/IdnaConversionFailed.php
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Exceptions;
|
||||
|
||||
use League\Uri\Idna\IdnaInfo;
|
||||
|
||||
final class IdnaConversionFailed extends SyntaxError
|
||||
{
|
||||
/** @var IdnaInfo|null */
|
||||
private $idnaInfo;
|
||||
|
||||
private function __construct(string $message, IdnaInfo $idnaInfo = null)
|
||||
{
|
||||
parent::__construct($message);
|
||||
$this->idnaInfo = $idnaInfo;
|
||||
}
|
||||
|
||||
public static function dueToIDNAError(string $domain, IdnaInfo $idnaInfo): self
|
||||
{
|
||||
return new self(
|
||||
'The host `'.$domain.'` is invalid : '.implode(', ', $idnaInfo->errorList()).' .',
|
||||
$idnaInfo
|
||||
);
|
||||
}
|
||||
|
||||
public static function dueToInvalidHost(string $domain): self
|
||||
{
|
||||
return new self('The host `'.$domain.'` is not a valid IDN host');
|
||||
}
|
||||
|
||||
public function idnaInfo(): ?IdnaInfo
|
||||
{
|
||||
return $this->idnaInfo;
|
||||
}
|
||||
}
|
20
plugins/af_readability/vendor/league/uri-interfaces/src/Exceptions/SyntaxError.php
vendored
Normal file
20
plugins/af_readability/vendor/league/uri-interfaces/src/Exceptions/SyntaxError.php
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Exceptions;
|
||||
|
||||
use League\Uri\Contracts\UriException;
|
||||
|
||||
class SyntaxError extends \InvalidArgumentException implements UriException
|
||||
{
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Idna;
|
||||
|
||||
use League\Uri\Exceptions\IdnaConversionFailed;
|
||||
use League\Uri\Exceptions\IdnSupportMissing;
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
use function defined;
|
||||
use function function_exists;
|
||||
use function idn_to_ascii;
|
||||
use function idn_to_utf8;
|
||||
use function rawurldecode;
|
||||
use const INTL_IDNA_VARIANT_UTS46;
|
||||
|
||||
/**
|
||||
* @see https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/uidna_8h.html
|
||||
*/
|
||||
final class Idna
|
||||
{
|
||||
private const REGEXP_IDNA_PATTERN = '/[^\x20-\x7f]/';
|
||||
private const MAX_DOMAIN_LENGTH = 253;
|
||||
private const MAX_LABEL_LENGTH = 63;
|
||||
|
||||
/**
|
||||
* General registered name regular expression.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
* @see https://regex101.com/r/fptU8V/1
|
||||
*/
|
||||
private const REGEXP_REGISTERED_NAME = '/
|
||||
(?(DEFINE)
|
||||
(?<unreserved>[a-z0-9_~\-]) # . is missing as it is used to separate labels
|
||||
(?<sub_delims>[!$&\'()*+,;=])
|
||||
(?<encoded>%[A-F0-9]{2})
|
||||
(?<reg_name>(?:(?&unreserved)|(?&sub_delims)|(?&encoded))*)
|
||||
)
|
||||
^(?:(?®_name)\.)*(?®_name)\.?$
|
||||
/ix';
|
||||
|
||||
/**
|
||||
* IDNA options.
|
||||
*/
|
||||
public const IDNA_DEFAULT = 0;
|
||||
public const IDNA_ALLOW_UNASSIGNED = 1;
|
||||
public const IDNA_USE_STD3_RULES = 2;
|
||||
public const IDNA_CHECK_BIDI = 4;
|
||||
public const IDNA_CHECK_CONTEXTJ = 8;
|
||||
public const IDNA_NONTRANSITIONAL_TO_ASCII = 0x10;
|
||||
public const IDNA_NONTRANSITIONAL_TO_UNICODE = 0x20;
|
||||
public const IDNA_CHECK_CONTEXTO = 0x40;
|
||||
|
||||
/**
|
||||
* IDNA errors.
|
||||
*/
|
||||
public const ERROR_NONE = 0;
|
||||
public const ERROR_EMPTY_LABEL = 1;
|
||||
public const ERROR_LABEL_TOO_LONG = 2;
|
||||
public const ERROR_DOMAIN_NAME_TOO_LONG = 4;
|
||||
public const ERROR_LEADING_HYPHEN = 8;
|
||||
public const ERROR_TRAILING_HYPHEN = 0x10;
|
||||
public const ERROR_HYPHEN_3_4 = 0x20;
|
||||
public const ERROR_LEADING_COMBINING_MARK = 0x40;
|
||||
public const ERROR_DISALLOWED = 0x80;
|
||||
public const ERROR_PUNYCODE = 0x100;
|
||||
public const ERROR_LABEL_HAS_DOT = 0x200;
|
||||
public const ERROR_INVALID_ACE_LABEL = 0x400;
|
||||
public const ERROR_BIDI = 0x800;
|
||||
public const ERROR_CONTEXTJ = 0x1000;
|
||||
public const ERROR_CONTEXTO_PUNCTUATION = 0x2000;
|
||||
public const ERROR_CONTEXTO_DIGITS = 0x4000;
|
||||
|
||||
/**
|
||||
* IDNA default options.
|
||||
*/
|
||||
public const IDNA2008_ASCII = self::IDNA_NONTRANSITIONAL_TO_ASCII
|
||||
| self::IDNA_CHECK_BIDI
|
||||
| self::IDNA_USE_STD3_RULES
|
||||
| self::IDNA_CHECK_CONTEXTJ;
|
||||
public const IDNA2008_UNICODE = self::IDNA_NONTRANSITIONAL_TO_UNICODE
|
||||
| self::IDNA_CHECK_BIDI
|
||||
| self::IDNA_USE_STD3_RULES
|
||||
| self::IDNA_CHECK_CONTEXTJ;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private static function supportsIdna(): void
|
||||
{
|
||||
static $idnSupport;
|
||||
if (null === $idnSupport) {
|
||||
$idnSupport = function_exists('\idn_to_ascii') && defined('\INTL_IDNA_VARIANT_UTS46');
|
||||
}
|
||||
|
||||
if (!$idnSupport) {
|
||||
throw new IdnSupportMissing('IDN host can not be processed. Verify that ext/intl is installed for IDN support and that ICU is at least version 4.6.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the input to its IDNA ASCII form.
|
||||
*
|
||||
* This method returns the string converted to IDN ASCII form
|
||||
*
|
||||
* @throws SyntaxError if the string can not be converted to ASCII using IDN UTS46 algorithm
|
||||
*/
|
||||
public static function toAscii(string $domain, int $options): IdnaInfo
|
||||
{
|
||||
$domain = rawurldecode($domain);
|
||||
|
||||
if (1 === preg_match(self::REGEXP_IDNA_PATTERN, $domain)) {
|
||||
self::supportsIdna();
|
||||
|
||||
/* @param-out array{errors: int, isTransitionalDifferent: bool, result: string} $idnaInfo */
|
||||
idn_to_ascii($domain, $options, INTL_IDNA_VARIANT_UTS46, $idnaInfo);
|
||||
if ([] === $idnaInfo) {
|
||||
return IdnaInfo::fromIntl([
|
||||
'result' => strtolower($domain),
|
||||
'isTransitionalDifferent' => false,
|
||||
'errors' => self::validateDomainAndLabelLength($domain),
|
||||
]);
|
||||
}
|
||||
|
||||
/* @var array{errors: int, isTransitionalDifferent: bool, result: string} $idnaInfo */
|
||||
return IdnaInfo::fromIntl($idnaInfo);
|
||||
}
|
||||
|
||||
$error = self::ERROR_NONE;
|
||||
if (1 !== preg_match(self::REGEXP_REGISTERED_NAME, $domain)) {
|
||||
$error |= self::ERROR_DISALLOWED;
|
||||
}
|
||||
|
||||
return IdnaInfo::fromIntl([
|
||||
'result' => strtolower($domain),
|
||||
'isTransitionalDifferent' => false,
|
||||
'errors' => self::validateDomainAndLabelLength($domain) | $error,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the input to its IDNA UNICODE form.
|
||||
*
|
||||
* This method returns the string converted to IDN UNICODE form
|
||||
*
|
||||
* @throws SyntaxError if the string can not be converted to UNICODE using IDN UTS46 algorithm
|
||||
*/
|
||||
public static function toUnicode(string $domain, int $options): IdnaInfo
|
||||
{
|
||||
$domain = rawurldecode($domain);
|
||||
|
||||
if (false === stripos($domain, 'xn--')) {
|
||||
return IdnaInfo::fromIntl(['result' => $domain, 'isTransitionalDifferent' => false, 'errors' => self::ERROR_NONE]);
|
||||
}
|
||||
|
||||
self::supportsIdna();
|
||||
|
||||
/* @param-out array{errors: int, isTransitionalDifferent: bool, result: string} $idnaInfo */
|
||||
idn_to_utf8($domain, $options, INTL_IDNA_VARIANT_UTS46, $idnaInfo);
|
||||
if ([] === $idnaInfo) {
|
||||
throw IdnaConversionFailed::dueToInvalidHost($domain);
|
||||
}
|
||||
|
||||
/* @var array{errors: int, isTransitionalDifferent: bool, result: string} $idnaInfo */
|
||||
return IdnaInfo::fromIntl($idnaInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapted from https://github.com/TRowbotham/idna.
|
||||
*
|
||||
* @see https://github.com/TRowbotham/idna/blob/master/src/Idna.php#L236
|
||||
*/
|
||||
private static function validateDomainAndLabelLength(string $domain): int
|
||||
{
|
||||
$error = self::ERROR_NONE;
|
||||
$labels = explode('.', $domain);
|
||||
$maxDomainSize = self::MAX_DOMAIN_LENGTH;
|
||||
$length = count($labels);
|
||||
|
||||
// If the last label is empty and it is not the first label, then it is the root label.
|
||||
// Increase the max size by 1, making it 254, to account for the root label's "."
|
||||
// delimiter. This also means we don't need to check the last label's length for being too
|
||||
// long.
|
||||
if ($length > 1 && $labels[$length - 1] === '') {
|
||||
++$maxDomainSize;
|
||||
array_pop($labels);
|
||||
}
|
||||
|
||||
if (strlen($domain) > $maxDomainSize) {
|
||||
$error |= self::ERROR_DOMAIN_NAME_TOO_LONG;
|
||||
}
|
||||
|
||||
foreach ($labels as $label) {
|
||||
if (strlen($label) > self::MAX_LABEL_LENGTH) {
|
||||
$error |= self::ERROR_LABEL_TOO_LONG;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Idna;
|
||||
|
||||
use function array_filter;
|
||||
use const ARRAY_FILTER_USE_KEY;
|
||||
|
||||
/**
|
||||
* @see https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/uidna_8h.html
|
||||
*/
|
||||
final class IdnaInfo
|
||||
{
|
||||
private const ERRORS = [
|
||||
Idna::ERROR_EMPTY_LABEL => 'a non-final domain name label (or the whole domain name) is empty',
|
||||
Idna::ERROR_LABEL_TOO_LONG => 'a domain name label is longer than 63 bytes',
|
||||
Idna::ERROR_DOMAIN_NAME_TOO_LONG => 'a domain name is longer than 255 bytes in its storage form',
|
||||
Idna::ERROR_LEADING_HYPHEN => 'a label starts with a hyphen-minus ("-")',
|
||||
Idna::ERROR_TRAILING_HYPHEN => 'a label ends with a hyphen-minus ("-")',
|
||||
Idna::ERROR_HYPHEN_3_4 => 'a label contains hyphen-minus ("-") in the third and fourth positions',
|
||||
Idna::ERROR_LEADING_COMBINING_MARK => 'a label starts with a combining mark',
|
||||
Idna::ERROR_DISALLOWED => 'a label or domain name contains disallowed characters',
|
||||
Idna::ERROR_PUNYCODE => 'a label starts with "xn--" but does not contain valid Punycode',
|
||||
Idna::ERROR_LABEL_HAS_DOT => 'a label contains a dot=full stop',
|
||||
Idna::ERROR_INVALID_ACE_LABEL => 'An ACE label does not contain a valid label string',
|
||||
Idna::ERROR_BIDI => 'a label does not meet the IDNA BiDi requirements (for right-to-left characters)',
|
||||
Idna::ERROR_CONTEXTJ => 'a label does not meet the IDNA CONTEXTJ requirements',
|
||||
Idna::ERROR_CONTEXTO_DIGITS => 'a label does not meet the IDNA CONTEXTO requirements for digits',
|
||||
Idna::ERROR_CONTEXTO_PUNCTUATION => 'a label does not meet the IDNA CONTEXTO requirements for punctuation characters. Some punctuation characters "Would otherwise have been DISALLOWED" but are allowed in certain contexts',
|
||||
];
|
||||
|
||||
/** @var string */
|
||||
private $result;
|
||||
|
||||
/** @var bool */
|
||||
private $isTransitionalDifferent;
|
||||
|
||||
/** @var int */
|
||||
private $errors;
|
||||
|
||||
/**
|
||||
* @var array<int, string>
|
||||
*/
|
||||
private $errorList;
|
||||
|
||||
private function __construct(string $result, bool $isTransitionalDifferent, int $errors)
|
||||
{
|
||||
$this->result = $result;
|
||||
$this->errors = $errors;
|
||||
$this->isTransitionalDifferent = $isTransitionalDifferent;
|
||||
$this->errorList = array_filter(
|
||||
self::ERRORS,
|
||||
function (int $error): bool {
|
||||
return 0 !== ($error & $this->errors);
|
||||
},
|
||||
ARRAY_FILTER_USE_KEY
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{result:string, isTransitionalDifferent:bool, errors:int} $infos
|
||||
*/
|
||||
public static function fromIntl(array $infos): self
|
||||
{
|
||||
return new self($infos['result'], $infos['isTransitionalDifferent'], $infos['errors']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{result:string, isTransitionalDifferent:bool, errors:int} $properties
|
||||
*/
|
||||
public static function __set_state(array $properties): self
|
||||
{
|
||||
return self::fromIntl($properties);
|
||||
}
|
||||
|
||||
public function result(): string
|
||||
{
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
public function isTransitionalDifferent(): bool
|
||||
{
|
||||
return $this->isTransitionalDifferent;
|
||||
}
|
||||
|
||||
public function errors(): int
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
public function error(int $error): ?string
|
||||
{
|
||||
return $this->errorList[$error] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function errorList(): array
|
||||
{
|
||||
return $this->errorList;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 ignace nyamagana butera
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,107 @@
|
|||
{
|
||||
"name": "league/uri",
|
||||
"type": "library",
|
||||
"description" : "URI manipulation library",
|
||||
"keywords": [
|
||||
"url",
|
||||
"uri",
|
||||
"rfc3986",
|
||||
"rfc3987",
|
||||
"rfc6570",
|
||||
"psr-7",
|
||||
"parse_url",
|
||||
"http",
|
||||
"https",
|
||||
"ws",
|
||||
"ftp",
|
||||
"data-uri",
|
||||
"file-uri",
|
||||
"middleware",
|
||||
"parse_str",
|
||||
"query-string",
|
||||
"querystring",
|
||||
"hostname",
|
||||
"uri-template"
|
||||
],
|
||||
"license": "MIT",
|
||||
"homepage": "https://uri.thephpleague.com",
|
||||
"authors": [
|
||||
{
|
||||
"name" : "Ignace Nyamagana Butera",
|
||||
"email" : "nyamsprod@gmail.com",
|
||||
"homepage" : "https://nyamsprod.com"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"forum": "https://thephpleague.slack.com",
|
||||
"docs": "https://uri.thephpleague.com",
|
||||
"issues": "https://github.com/thephpleague/uri/issues"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/nyamsprod"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0",
|
||||
"ext-json": "*",
|
||||
"psr/http-message": "^1.0",
|
||||
"league/uri-interfaces": "^2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^v3.3.2",
|
||||
"nyholm/psr7": "^1.5",
|
||||
"php-http/psr7-integration-tests": "^1.1",
|
||||
"phpstan/phpstan": "^1.2.0",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.0",
|
||||
"phpstan/phpstan-phpunit": "^1.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.1.0",
|
||||
"phpunit/phpunit": "^9.5.10",
|
||||
"psr/http-factory": "^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Uri\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"LeagueTest\\Uri\\": "tests"
|
||||
}
|
||||
},
|
||||
"conflict": {
|
||||
"league/uri-schemes": "^1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"phpcs": "php-cs-fixer fix -v --diff --dry-run --allow-risky=yes --ansi",
|
||||
"phpcs:fix": "php-cs-fixer fix -vvv --allow-risky=yes --ansi",
|
||||
"phpstan": "phpstan analyse -l max -c phpstan.neon src --ansi --memory-limit=256M",
|
||||
"phpunit": "XDEBUG_MODE=coverage phpunit --coverage-text",
|
||||
"test": [
|
||||
"@phpunit",
|
||||
"@phpstan",
|
||||
"@phpcs"
|
||||
]
|
||||
},
|
||||
"scripts-descriptions": {
|
||||
"phpcs": "Runs coding style test suite",
|
||||
"phpstan": "Runs complete codebase static analysis",
|
||||
"phpunit": "Runs unit and functional testing",
|
||||
"test": "Runs full test suite"
|
||||
},
|
||||
"suggest": {
|
||||
"league/uri-components" : "Needed to easily manipulate URI objects",
|
||||
"ext-intl" : "Needed to improve host validation",
|
||||
"ext-fileinfo": "Needed to create Data URI from a filepath",
|
||||
"psr/http-factory": "Needed to use the URI factory"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "6.x-dev"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
}
|
||||
}
|
30
plugins/af_readability/vendor/league/uri/src/Exceptions/TemplateCanNotBeExpanded.php
vendored
Normal file
30
plugins/af_readability/vendor/league/uri/src/Exceptions/TemplateCanNotBeExpanded.php
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\Exceptions;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use League\Uri\Contracts\UriException;
|
||||
|
||||
class TemplateCanNotBeExpanded extends InvalidArgumentException implements UriException
|
||||
{
|
||||
public static function dueToUnableToProcessValueListWithPrefix(string $variableName): self
|
||||
{
|
||||
return new self('The ":" modifier can not be applied on "'.$variableName.'" since it is a list of values.');
|
||||
}
|
||||
|
||||
public static function dueToNestedListOfValue(string $variableName): self
|
||||
{
|
||||
return new self('The "'.$variableName.'" can not be a nested list.');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,335 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri;
|
||||
|
||||
use JsonSerializable;
|
||||
use League\Uri\Contracts\UriInterface;
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
use Psr\Http\Message\UriInterface as Psr7UriInterface;
|
||||
use function is_object;
|
||||
use function is_scalar;
|
||||
use function method_exists;
|
||||
use function sprintf;
|
||||
|
||||
final class Http implements Psr7UriInterface, JsonSerializable
|
||||
{
|
||||
private UriInterface $uri;
|
||||
|
||||
private function __construct(UriInterface $uri)
|
||||
{
|
||||
$this->validate($uri);
|
||||
$this->uri = $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the submitted uri against PSR-7 UriInterface.
|
||||
*
|
||||
* @throws SyntaxError if the given URI does not follow PSR-7 UriInterface rules
|
||||
*/
|
||||
private function validate(UriInterface $uri): void
|
||||
{
|
||||
$scheme = $uri->getScheme();
|
||||
if (null === $scheme && '' === $uri->getHost()) {
|
||||
throw new SyntaxError(sprintf('an URI without scheme can not contains a empty host string according to PSR-7: %s', (string) $uri));
|
||||
}
|
||||
|
||||
$port = $uri->getPort();
|
||||
if (null !== $port && ($port < 0 || $port > 65535)) {
|
||||
throw new SyntaxError(sprintf('The URI port is outside the established TCP and UDP port ranges: %s', (string) $uri->getPort()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method called by PHP's var export.
|
||||
*/
|
||||
public static function __set_state(array $components): self
|
||||
{
|
||||
return new self($components['uri']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance from a string.
|
||||
*
|
||||
* @param string|mixed $uri
|
||||
*/
|
||||
public static function createFromString($uri = ''): self
|
||||
{
|
||||
return new self(Uri::createFromString($uri));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance from a hash of parse_url parts.
|
||||
*
|
||||
* @param array $components a hash representation of the URI similar
|
||||
* to PHP parse_url function result
|
||||
*/
|
||||
public static function createFromComponents(array $components): self
|
||||
{
|
||||
return new self(Uri::createFromComponents($components));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance from the environment.
|
||||
*/
|
||||
public static function createFromServer(array $server): self
|
||||
{
|
||||
return new self(Uri::createFromServer($server));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance from a URI and a Base URI.
|
||||
*
|
||||
* The returned URI must be absolute.
|
||||
*
|
||||
* @param mixed $uri the input URI to create
|
||||
* @param mixed $base_uri the base URI used for reference
|
||||
*/
|
||||
public static function createFromBaseUri($uri, $base_uri = null): self
|
||||
{
|
||||
return new self(Uri::createFromBaseUri($uri, $base_uri));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance from a URI object.
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri the input URI to create
|
||||
*/
|
||||
public static function createFromUri($uri): self
|
||||
{
|
||||
if ($uri instanceof UriInterface) {
|
||||
return new self($uri);
|
||||
}
|
||||
|
||||
return new self(Uri::createFromUri($uri));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getScheme(): string
|
||||
{
|
||||
return (string) $this->uri->getScheme();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getAuthority(): string
|
||||
{
|
||||
return (string) $this->uri->getAuthority();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getUserInfo(): string
|
||||
{
|
||||
return (string) $this->uri->getUserInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getHost(): string
|
||||
{
|
||||
return (string) $this->uri->getHost();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPort(): ?int
|
||||
{
|
||||
return $this->uri->getPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPath(): string
|
||||
{
|
||||
return $this->uri->getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getQuery(): string
|
||||
{
|
||||
return (string) $this->uri->getQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getFragment(): string
|
||||
{
|
||||
return (string) $this->uri->getFragment();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function withScheme($scheme): self
|
||||
{
|
||||
/** @var string $scheme */
|
||||
$scheme = $this->filterInput($scheme);
|
||||
if ('' === $scheme) {
|
||||
$scheme = null;
|
||||
}
|
||||
|
||||
$uri = $this->uri->withScheme($scheme);
|
||||
if ($uri->getScheme() === $this->uri->getScheme()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
return new self($uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely stringify input when possible.
|
||||
*
|
||||
* @param mixed $str the value to evaluate as a string
|
||||
*
|
||||
* @throws SyntaxError if the submitted data can not be converted to string
|
||||
*
|
||||
* @return string|mixed
|
||||
*/
|
||||
private function filterInput($str)
|
||||
{
|
||||
if (is_scalar($str) || (is_object($str) && method_exists($str, '__toString'))) {
|
||||
return (string) $str;
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function withUserInfo($user, $password = null): self
|
||||
{
|
||||
/** @var string $user */
|
||||
$user = $this->filterInput($user);
|
||||
if ('' === $user) {
|
||||
$user = null;
|
||||
}
|
||||
|
||||
$uri = $this->uri->withUserInfo($user, $password);
|
||||
if ($uri->getUserInfo() === $this->uri->getUserInfo()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
return new self($uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function withHost($host): self
|
||||
{
|
||||
/** @var string $host */
|
||||
$host = $this->filterInput($host);
|
||||
if ('' === $host) {
|
||||
$host = null;
|
||||
}
|
||||
|
||||
$uri = $this->uri->withHost($host);
|
||||
if ($uri->getHost() === $this->uri->getHost()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
return new self($uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function withPort($port): self
|
||||
{
|
||||
$uri = $this->uri->withPort($port);
|
||||
if ($uri->getPort() === $this->uri->getPort()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
return new self($uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function withPath($path): self
|
||||
{
|
||||
$uri = $this->uri->withPath($path);
|
||||
if ($uri->getPath() === $this->uri->getPath()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
return new self($uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function withQuery($query): self
|
||||
{
|
||||
/** @var string $query */
|
||||
$query = $this->filterInput($query);
|
||||
if ('' === $query) {
|
||||
$query = null;
|
||||
}
|
||||
|
||||
$uri = $this->uri->withQuery($query);
|
||||
if ($uri->getQuery() === $this->uri->getQuery()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
return new self($uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function withFragment($fragment): self
|
||||
{
|
||||
/** @var string $fragment */
|
||||
$fragment = $this->filterInput($fragment);
|
||||
if ('' === $fragment) {
|
||||
$fragment = null;
|
||||
}
|
||||
|
||||
$uri = $this->uri->withFragment($fragment);
|
||||
if ($uri->getFragment() === $this->uri->getFragment()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
return new self($uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->uri->__toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function jsonSerialize(): string
|
||||
{
|
||||
return $this->uri->__toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri;
|
||||
|
||||
use Psr\Http\Message\UriFactoryInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
final class HttpFactory implements UriFactoryInterface
|
||||
{
|
||||
public function createUri(string $uri = ''): UriInterface
|
||||
{
|
||||
return Http::createFromString($uri);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,215 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri;
|
||||
|
||||
use League\Uri\Contracts\UriInterface;
|
||||
use Psr\Http\Message\UriInterface as Psr7UriInterface;
|
||||
use TypeError;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function preg_replace_callback;
|
||||
use function rawurldecode;
|
||||
use function sprintf;
|
||||
|
||||
final class UriInfo
|
||||
{
|
||||
private const REGEXP_ENCODED_CHARS = ',%(2[D|E]|3[0-9]|4[1-9|A-F]|5[0-9|AF]|6[1-9|A-F]|7[0-9|E]),i';
|
||||
|
||||
private const WHATWG_SPECIAL_SCHEMES = ['ftp' => 21, 'http' => 80, 'https' => 443, 'ws' => 80, 'wss' => 443];
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
*/
|
||||
private static function emptyComponentValue($uri): ?string
|
||||
{
|
||||
return $uri instanceof Psr7UriInterface ? '' : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the URI object.
|
||||
*
|
||||
* To be valid an URI MUST implement at least one of the following interface:
|
||||
* - League\Uri\UriInterface
|
||||
* - Psr\Http\Message\UriInterface
|
||||
*
|
||||
* @param mixed $uri the URI to validate
|
||||
*
|
||||
* @throws TypeError if the URI object does not implements the supported interfaces.
|
||||
*
|
||||
* @return Psr7UriInterface|UriInterface
|
||||
*/
|
||||
private static function filterUri($uri)
|
||||
{
|
||||
if ($uri instanceof Psr7UriInterface || $uri instanceof UriInterface) {
|
||||
return $uri;
|
||||
}
|
||||
|
||||
throw new TypeError(sprintf('The uri must be a valid URI object received `%s`', is_object($uri) ? get_class($uri) : gettype($uri)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize an URI for comparison.
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
*
|
||||
* @return Psr7UriInterface|UriInterface
|
||||
*/
|
||||
private static function normalize($uri)
|
||||
{
|
||||
$uri = self::filterUri($uri);
|
||||
$null = self::emptyComponentValue($uri);
|
||||
|
||||
$path = $uri->getPath();
|
||||
if ('/' === ($path[0] ?? '') || '' !== $uri->getScheme().$uri->getAuthority()) {
|
||||
$path = UriResolver::resolve($uri, $uri->withPath('')->withQuery($null))->getPath();
|
||||
}
|
||||
|
||||
$query = $uri->getQuery();
|
||||
$fragment = $uri->getFragment();
|
||||
$fragmentOrig = $fragment;
|
||||
$pairs = null === $query ? [] : explode('&', $query);
|
||||
sort($pairs, SORT_REGULAR);
|
||||
|
||||
$replace = static fn (array $matches): string => rawurldecode($matches[0]);
|
||||
|
||||
$retval = preg_replace_callback(self::REGEXP_ENCODED_CHARS, $replace, [$path, implode('&', $pairs), $fragment]);
|
||||
if (null !== $retval) {
|
||||
[$path, $query, $fragment] = $retval + ['', $null, $null];
|
||||
}
|
||||
|
||||
if ($null !== $uri->getAuthority() && '' === $path) {
|
||||
$path = '/';
|
||||
}
|
||||
|
||||
return $uri
|
||||
->withHost(Uri::createFromComponents(['host' => $uri->getHost()])->getHost())
|
||||
->withPath($path)
|
||||
->withQuery([] === $pairs ? $null : $query)
|
||||
->withFragment($null === $fragmentOrig ? $fragmentOrig : $fragment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell whether the URI represents an absolute URI.
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
*/
|
||||
public static function isAbsolute($uri): bool
|
||||
{
|
||||
return self::emptyComponentValue($uri) !== self::filterUri($uri)->getScheme();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell whether the URI represents a network path.
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
*/
|
||||
public static function isNetworkPath($uri): bool
|
||||
{
|
||||
$uri = self::filterUri($uri);
|
||||
$null = self::emptyComponentValue($uri);
|
||||
|
||||
return $null === $uri->getScheme() && $null !== $uri->getAuthority();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell whether the URI represents an absolute path.
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
*/
|
||||
public static function isAbsolutePath($uri): bool
|
||||
{
|
||||
$uri = self::filterUri($uri);
|
||||
$null = self::emptyComponentValue($uri);
|
||||
|
||||
return $null === $uri->getScheme()
|
||||
&& $null === $uri->getAuthority()
|
||||
&& '/' === ($uri->getPath()[0] ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell whether the URI represents a relative path.
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
*/
|
||||
public static function isRelativePath($uri): bool
|
||||
{
|
||||
$uri = self::filterUri($uri);
|
||||
$null = self::emptyComponentValue($uri);
|
||||
|
||||
return $null === $uri->getScheme()
|
||||
&& $null === $uri->getAuthority()
|
||||
&& '/' !== ($uri->getPath()[0] ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell whether both URI refers to the same document.
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
* @param Psr7UriInterface|UriInterface $base_uri
|
||||
*/
|
||||
public static function isSameDocument($uri, $base_uri): bool
|
||||
{
|
||||
$uri = self::normalize($uri);
|
||||
$base_uri = self::normalize($base_uri);
|
||||
|
||||
return (string) $uri->withFragment($uri instanceof Psr7UriInterface ? '' : null)
|
||||
=== (string) $base_uri->withFragment($base_uri instanceof Psr7UriInterface ? '' : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URI origin property as defined by WHATWG URL living standard.
|
||||
*
|
||||
* {@see https://url.spec.whatwg.org/#origin}
|
||||
*
|
||||
* For URI without a special scheme the method returns null
|
||||
* For URI with the file scheme the method will return null (as this is left to the implementation decision)
|
||||
* For URI with a special scheme the method returns the scheme followed by its authority (without the userinfo part)
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
*/
|
||||
public static function getOrigin($uri): ?string
|
||||
{
|
||||
$scheme = self::filterUri($uri)->getScheme();
|
||||
if ('blob' === $scheme) {
|
||||
$uri = Uri::createFromString($uri->getPath());
|
||||
$scheme = $uri->getScheme();
|
||||
}
|
||||
|
||||
if (null === $scheme || !array_key_exists($scheme, self::WHATWG_SPECIAL_SCHEMES)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$null = self::emptyComponentValue($uri);
|
||||
|
||||
return (string) $uri->withFragment($null)->withQuery($null)->withPath('')->withUserInfo($null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
* @param Psr7UriInterface|UriInterface $base_uri
|
||||
*/
|
||||
public static function isCrossOrigin($uri, $base_uri): bool
|
||||
{
|
||||
return null === ($uriString = self::getOrigin(Uri::createFromUri($uri)))
|
||||
|| null === ($baseUriString = self::getOrigin(Uri::createFromUri($base_uri)))
|
||||
|| $uriString !== $baseUriString;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,376 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri;
|
||||
|
||||
use League\Uri\Contracts\UriInterface;
|
||||
use Psr\Http\Message\UriInterface as Psr7UriInterface;
|
||||
use TypeError;
|
||||
use function array_pop;
|
||||
use function array_reduce;
|
||||
use function count;
|
||||
use function end;
|
||||
use function explode;
|
||||
use function gettype;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function sprintf;
|
||||
use function str_repeat;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
|
||||
final class UriResolver
|
||||
{
|
||||
/**
|
||||
* @var array<string,int>
|
||||
*/
|
||||
const DOT_SEGMENTS = ['.' => 1, '..' => 1];
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve an URI against a base URI using RFC3986 rules.
|
||||
*
|
||||
* If the first argument is a UriInterface the method returns a UriInterface object
|
||||
* If the first argument is a Psr7UriInterface the method returns a Psr7UriInterface object
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
* @param Psr7UriInterface|UriInterface $base_uri
|
||||
*
|
||||
* @return Psr7UriInterface|UriInterface
|
||||
*/
|
||||
public static function resolve($uri, $base_uri)
|
||||
{
|
||||
self::filterUri($uri);
|
||||
self::filterUri($base_uri);
|
||||
$null = $uri instanceof Psr7UriInterface ? '' : null;
|
||||
|
||||
if ($null !== $uri->getScheme()) {
|
||||
return $uri
|
||||
->withPath(self::removeDotSegments($uri->getPath()));
|
||||
}
|
||||
|
||||
if ($null !== $uri->getAuthority()) {
|
||||
return $uri
|
||||
->withScheme($base_uri->getScheme())
|
||||
->withPath(self::removeDotSegments($uri->getPath()));
|
||||
}
|
||||
|
||||
$user = $null;
|
||||
$pass = null;
|
||||
$userInfo = $base_uri->getUserInfo();
|
||||
if (null !== $userInfo) {
|
||||
[$user, $pass] = explode(':', $userInfo, 2) + [1 => null];
|
||||
}
|
||||
|
||||
[$uri_path, $uri_query] = self::resolvePathAndQuery($uri, $base_uri);
|
||||
|
||||
return $uri
|
||||
->withPath(self::removeDotSegments($uri_path))
|
||||
->withQuery($uri_query)
|
||||
->withHost($base_uri->getHost())
|
||||
->withPort($base_uri->getPort())
|
||||
->withUserInfo((string) $user, $pass)
|
||||
->withScheme($base_uri->getScheme())
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the URI object.
|
||||
*
|
||||
* @param mixed $uri an URI object
|
||||
*
|
||||
* @throws TypeError if the URI object does not implements the supported interfaces.
|
||||
*/
|
||||
private static function filterUri($uri): void
|
||||
{
|
||||
if (!$uri instanceof UriInterface && !$uri instanceof Psr7UriInterface) {
|
||||
throw new TypeError(sprintf('The uri must be a valid URI object received `%s`', gettype($uri)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove dot segments from the URI path.
|
||||
*/
|
||||
private static function removeDotSegments(string $path): string
|
||||
{
|
||||
if (false === strpos($path, '.')) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
$old_segments = explode('/', $path);
|
||||
$new_path = implode('/', array_reduce($old_segments, [UriResolver::class, 'reducer'], []));
|
||||
if (isset(self::DOT_SEGMENTS[end($old_segments)])) {
|
||||
$new_path .= '/';
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
// added because some PSR-7 implementations do not respect RFC3986
|
||||
if (0 === strpos($path, '/') && 0 !== strpos($new_path, '/')) {
|
||||
return '/'.$new_path;
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return $new_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove dot segments.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
private static function reducer(array $carry, string $segment): array
|
||||
{
|
||||
if ('..' === $segment) {
|
||||
array_pop($carry);
|
||||
|
||||
return $carry;
|
||||
}
|
||||
|
||||
if (!isset(self::DOT_SEGMENTS[$segment])) {
|
||||
$carry[] = $segment;
|
||||
}
|
||||
|
||||
return $carry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve an URI path and query component.
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
* @param Psr7UriInterface|UriInterface $base_uri
|
||||
*
|
||||
* @return array{0:string, 1:string|null}
|
||||
*/
|
||||
private static function resolvePathAndQuery($uri, $base_uri): array
|
||||
{
|
||||
$target_path = $uri->getPath();
|
||||
$target_query = $uri->getQuery();
|
||||
$null = $uri instanceof Psr7UriInterface ? '' : null;
|
||||
$baseNull = $base_uri instanceof Psr7UriInterface ? '' : null;
|
||||
|
||||
if (0 === strpos($target_path, '/')) {
|
||||
return [$target_path, $target_query];
|
||||
}
|
||||
|
||||
if ('' === $target_path) {
|
||||
if ($null === $target_query) {
|
||||
$target_query = $base_uri->getQuery();
|
||||
}
|
||||
|
||||
$target_path = $base_uri->getPath();
|
||||
//@codeCoverageIgnoreStart
|
||||
//because some PSR-7 Uri implementations allow this RFC3986 forbidden construction
|
||||
if ($baseNull !== $base_uri->getAuthority() && 0 !== strpos($target_path, '/')) {
|
||||
$target_path = '/'.$target_path;
|
||||
}
|
||||
//@codeCoverageIgnoreEnd
|
||||
|
||||
return [$target_path, $target_query];
|
||||
}
|
||||
|
||||
$base_path = $base_uri->getPath();
|
||||
if ($baseNull !== $base_uri->getAuthority() && '' === $base_path) {
|
||||
$target_path = '/'.$target_path;
|
||||
}
|
||||
|
||||
if ('' !== $base_path) {
|
||||
$segments = explode('/', $base_path);
|
||||
array_pop($segments);
|
||||
if ([] !== $segments) {
|
||||
$target_path = implode('/', $segments).'/'.$target_path;
|
||||
}
|
||||
}
|
||||
|
||||
return [$target_path, $target_query];
|
||||
}
|
||||
|
||||
/**
|
||||
* Relativize an URI according to a base URI.
|
||||
*
|
||||
* This method MUST retain the state of the submitted URI instance, and return
|
||||
* an URI instance of the same type that contains the applied modifications.
|
||||
*
|
||||
* This method MUST be transparent when dealing with error and exceptions.
|
||||
* It MUST not alter of silence them apart from validating its own parameters.
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
* @param Psr7UriInterface|UriInterface $base_uri
|
||||
*
|
||||
* @return Psr7UriInterface|UriInterface
|
||||
*/
|
||||
public static function relativize($uri, $base_uri)
|
||||
{
|
||||
self::filterUri($uri);
|
||||
self::filterUri($base_uri);
|
||||
$uri = self::formatHost($uri);
|
||||
$base_uri = self::formatHost($base_uri);
|
||||
if (!self::isRelativizable($uri, $base_uri)) {
|
||||
return $uri;
|
||||
}
|
||||
|
||||
$null = $uri instanceof Psr7UriInterface ? '' : null;
|
||||
$uri = $uri->withScheme($null)->withPort(null)->withUserInfo($null)->withHost($null);
|
||||
$target_path = $uri->getPath();
|
||||
if ($target_path !== $base_uri->getPath()) {
|
||||
return $uri->withPath(self::relativizePath($target_path, $base_uri->getPath()));
|
||||
}
|
||||
|
||||
if (self::componentEquals('getQuery', $uri, $base_uri)) {
|
||||
return $uri->withPath('')->withQuery($null);
|
||||
}
|
||||
|
||||
if ($null === $uri->getQuery()) {
|
||||
return $uri->withPath(self::formatPathWithEmptyBaseQuery($target_path));
|
||||
}
|
||||
|
||||
return $uri->withPath('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the component value from both URI object equals.
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
* @param Psr7UriInterface|UriInterface $base_uri
|
||||
*/
|
||||
private static function componentEquals(string $method, $uri, $base_uri): bool
|
||||
{
|
||||
return self::getComponent($method, $uri) === self::getComponent($method, $base_uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the component value from the submitted URI object.
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
*/
|
||||
private static function getComponent(string $method, $uri): ?string
|
||||
{
|
||||
$component = $uri->$method();
|
||||
if ($uri instanceof Psr7UriInterface && '' === $component) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the URI object.
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
*
|
||||
* @throws TypeError if the URI object does not implements the supported interfaces.
|
||||
*
|
||||
* @return Psr7UriInterface|UriInterface
|
||||
*/
|
||||
private static function formatHost($uri)
|
||||
{
|
||||
if (!$uri instanceof Psr7UriInterface) {
|
||||
return $uri;
|
||||
}
|
||||
|
||||
$host = $uri->getHost();
|
||||
if ('' === $host) {
|
||||
return $uri;
|
||||
}
|
||||
|
||||
return $uri->withHost((string) Uri::createFromComponents(['host' => $host])->getHost());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell whether the submitted URI object can be relativize.
|
||||
*
|
||||
* @param Psr7UriInterface|UriInterface $uri
|
||||
* @param Psr7UriInterface|UriInterface $base_uri
|
||||
*/
|
||||
private static function isRelativizable($uri, $base_uri): bool
|
||||
{
|
||||
return !UriInfo::isRelativePath($uri)
|
||||
&& self::componentEquals('getScheme', $uri, $base_uri)
|
||||
&& self::componentEquals('getAuthority', $uri, $base_uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Relative the URI for a authority-less target URI.
|
||||
*/
|
||||
private static function relativizePath(string $path, string $basepath): string
|
||||
{
|
||||
$base_segments = self::getSegments($basepath);
|
||||
$target_segments = self::getSegments($path);
|
||||
$target_basename = array_pop($target_segments);
|
||||
array_pop($base_segments);
|
||||
foreach ($base_segments as $offset => $segment) {
|
||||
if (!isset($target_segments[$offset]) || $segment !== $target_segments[$offset]) {
|
||||
break;
|
||||
}
|
||||
unset($base_segments[$offset], $target_segments[$offset]);
|
||||
}
|
||||
$target_segments[] = $target_basename;
|
||||
|
||||
return self::formatPath(
|
||||
str_repeat('../', count($base_segments)).implode('/', $target_segments),
|
||||
$basepath
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the path segments.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private static function getSegments(string $path): array
|
||||
{
|
||||
if ('' !== $path && '/' === $path[0]) {
|
||||
$path = substr($path, 1);
|
||||
}
|
||||
|
||||
return explode('/', $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatting the path to keep a valid URI.
|
||||
*/
|
||||
private static function formatPath(string $path, string $basepath): string
|
||||
{
|
||||
if ('' === $path) {
|
||||
return in_array($basepath, ['', '/'], true) ? $basepath : './';
|
||||
}
|
||||
|
||||
if (false === ($colon_pos = strpos($path, ':'))) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
$slash_pos = strpos($path, '/');
|
||||
if (false === $slash_pos || $colon_pos < $slash_pos) {
|
||||
return "./$path";
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatting the path to keep a resolvable URI.
|
||||
*/
|
||||
private static function formatPathWithEmptyBaseQuery(string $path): string
|
||||
{
|
||||
$target_segments = self::getSegments($path);
|
||||
/** @var string $basename */
|
||||
$basename = end($target_segments);
|
||||
|
||||
return '' === $basename ? './' : $basename;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,467 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri;
|
||||
|
||||
use League\Uri\Exceptions\IdnaConversionFailed;
|
||||
use League\Uri\Exceptions\IdnSupportMissing;
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
use League\Uri\Idna\Idna;
|
||||
use TypeError;
|
||||
use function array_merge;
|
||||
use function explode;
|
||||
use function filter_var;
|
||||
use function gettype;
|
||||
use function inet_pton;
|
||||
use function is_object;
|
||||
use function is_scalar;
|
||||
use function method_exists;
|
||||
use function preg_match;
|
||||
use function rawurldecode;
|
||||
use function sprintf;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
use const FILTER_FLAG_IPV6;
|
||||
use const FILTER_VALIDATE_IP;
|
||||
|
||||
/**
|
||||
* A class to parse a URI string according to RFC3986.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986
|
||||
* @package League\Uri
|
||||
* @author Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
* @since 6.0.0
|
||||
*/
|
||||
final class UriString
|
||||
{
|
||||
/**
|
||||
* Default URI component values.
|
||||
*/
|
||||
private const URI_COMPONENTS = [
|
||||
'scheme' => null, 'user' => null, 'pass' => null, 'host' => null,
|
||||
'port' => null, 'path' => '', 'query' => null, 'fragment' => null,
|
||||
];
|
||||
|
||||
/**
|
||||
* Simple URI which do not need any parsing.
|
||||
*/
|
||||
private const URI_SCHORTCUTS = [
|
||||
'' => [],
|
||||
'#' => ['fragment' => ''],
|
||||
'?' => ['query' => ''],
|
||||
'?#' => ['query' => '', 'fragment' => ''],
|
||||
'/' => ['path' => '/'],
|
||||
'//' => ['host' => ''],
|
||||
];
|
||||
|
||||
/**
|
||||
* Range of invalid characters in URI string.
|
||||
*/
|
||||
private const REGEXP_INVALID_URI_CHARS = '/[\x00-\x1f\x7f]/';
|
||||
|
||||
/**
|
||||
* RFC3986 regular expression URI splitter.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#appendix-B
|
||||
*/
|
||||
private const REGEXP_URI_PARTS = ',^
|
||||
(?<scheme>(?<scontent>[^:/?\#]+):)? # URI scheme component
|
||||
(?<authority>//(?<acontent>[^/?\#]*))? # URI authority part
|
||||
(?<path>[^?\#]*) # URI path component
|
||||
(?<query>\?(?<qcontent>[^\#]*))? # URI query component
|
||||
(?<fragment>\#(?<fcontent>.*))? # URI fragment component
|
||||
,x';
|
||||
|
||||
/**
|
||||
* URI scheme regular expresssion.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.1
|
||||
*/
|
||||
private const REGEXP_URI_SCHEME = '/^([a-z][a-z\d\+\.\-]*)?$/i';
|
||||
|
||||
/**
|
||||
* IPvFuture regular expression.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
*/
|
||||
private const REGEXP_IP_FUTURE = '/^
|
||||
v(?<version>[A-F0-9])+\.
|
||||
(?:
|
||||
(?<unreserved>[a-z0-9_~\-\.])|
|
||||
(?<sub_delims>[!$&\'()*+,;=:]) # also include the : character
|
||||
)+
|
||||
$/ix';
|
||||
|
||||
/**
|
||||
* General registered name regular expression.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
*/
|
||||
private const REGEXP_REGISTERED_NAME = '/(?(DEFINE)
|
||||
(?<unreserved>[a-z0-9_~\-]) # . is missing as it is used to separate labels
|
||||
(?<sub_delims>[!$&\'()*+,;=])
|
||||
(?<encoded>%[A-F0-9]{2})
|
||||
(?<reg_name>(?:(?&unreserved)|(?&sub_delims)|(?&encoded))*)
|
||||
)
|
||||
^(?:(?®_name)\.)*(?®_name)\.?$/ix';
|
||||
|
||||
/**
|
||||
* Invalid characters in host regular expression.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
*/
|
||||
private const REGEXP_INVALID_HOST_CHARS = '/
|
||||
[:\/?#\[\]@ ] # gen-delims characters as well as the space character
|
||||
/ix';
|
||||
|
||||
/**
|
||||
* Invalid path for URI without scheme and authority regular expression.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.3
|
||||
*/
|
||||
private const REGEXP_INVALID_PATH = ',^(([^/]*):)(.*)?/,';
|
||||
|
||||
/**
|
||||
* Host and Port splitter regular expression.
|
||||
*/
|
||||
private const REGEXP_HOST_PORT = ',^(?<host>\[.*\]|[^:]*)(:(?<port>.*))?$,';
|
||||
|
||||
/**
|
||||
* IDN Host detector regular expression.
|
||||
*/
|
||||
private const REGEXP_IDN_PATTERN = '/[^\x20-\x7f]/';
|
||||
|
||||
/**
|
||||
* Only the address block fe80::/10 can have a Zone ID attach to
|
||||
* let's detect the link local significant 10 bits.
|
||||
*/
|
||||
private const ZONE_ID_ADDRESS_BLOCK = "\xfe\x80";
|
||||
|
||||
/**
|
||||
* Generate an URI string representation from its parsed representation
|
||||
* returned by League\UriString::parse() or PHP's parse_url.
|
||||
*
|
||||
* If you supply your own array, you are responsible for providing
|
||||
* valid components without their URI delimiters.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-5.3
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-7.5
|
||||
*
|
||||
* @param array{
|
||||
* scheme:?string,
|
||||
* user:?string,
|
||||
* pass:?string,
|
||||
* host:?string,
|
||||
* port:?int,
|
||||
* path:?string,
|
||||
* query:?string,
|
||||
* fragment:?string
|
||||
* } $components
|
||||
*/
|
||||
public static function build(array $components): string
|
||||
{
|
||||
$result = $components['path'] ?? '';
|
||||
if (isset($components['query'])) {
|
||||
$result .= '?'.$components['query'];
|
||||
}
|
||||
|
||||
if (isset($components['fragment'])) {
|
||||
$result .= '#'.$components['fragment'];
|
||||
}
|
||||
|
||||
$scheme = null;
|
||||
if (isset($components['scheme'])) {
|
||||
$scheme = $components['scheme'].':';
|
||||
}
|
||||
|
||||
if (!isset($components['host'])) {
|
||||
return $scheme.$result;
|
||||
}
|
||||
|
||||
$scheme .= '//';
|
||||
$authority = $components['host'];
|
||||
if (isset($components['port'])) {
|
||||
$authority .= ':'.$components['port'];
|
||||
}
|
||||
|
||||
if (!isset($components['user'])) {
|
||||
return $scheme.$authority.$result;
|
||||
}
|
||||
|
||||
$authority = '@'.$authority;
|
||||
if (!isset($components['pass'])) {
|
||||
return $scheme.$components['user'].$authority.$result;
|
||||
}
|
||||
|
||||
return $scheme.$components['user'].':'.$components['pass'].$authority.$result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an URI string into its components.
|
||||
*
|
||||
* This method parses a URI and returns an associative array containing any
|
||||
* of the various components of the URI that are present.
|
||||
*
|
||||
* <code>
|
||||
* $components = (new Parser())->parse('http://foo@test.example.com:42?query#');
|
||||
* var_export($components);
|
||||
* //will display
|
||||
* array(
|
||||
* 'scheme' => 'http', // the URI scheme component
|
||||
* 'user' => 'foo', // the URI user component
|
||||
* 'pass' => null, // the URI pass component
|
||||
* 'host' => 'test.example.com', // the URI host component
|
||||
* 'port' => 42, // the URI port component
|
||||
* 'path' => '', // the URI path component
|
||||
* 'query' => 'query', // the URI query component
|
||||
* 'fragment' => '', // the URI fragment component
|
||||
* );
|
||||
* </code>
|
||||
*
|
||||
* The returned array is similar to PHP's parse_url return value with the following
|
||||
* differences:
|
||||
*
|
||||
* <ul>
|
||||
* <li>All components are always present in the returned array</li>
|
||||
* <li>Empty and undefined component are treated differently. And empty component is
|
||||
* set to the empty string while an undefined component is set to the `null` value.</li>
|
||||
* <li>The path component is never undefined</li>
|
||||
* <li>The method parses the URI following the RFC3986 rules but you are still
|
||||
* required to validate the returned components against its related scheme specific rules.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986
|
||||
*
|
||||
* @param mixed $uri any scalar or stringable object
|
||||
*
|
||||
* @throws SyntaxError if the URI contains invalid characters
|
||||
* @throws SyntaxError if the URI contains an invalid scheme
|
||||
* @throws SyntaxError if the URI contains an invalid path
|
||||
*
|
||||
* @return array{
|
||||
* scheme:?string,
|
||||
* user:?string,
|
||||
* pass:?string,
|
||||
* host:?string,
|
||||
* port:?int,
|
||||
* path:string,
|
||||
* query:?string,
|
||||
* fragment:?string
|
||||
* }
|
||||
*/
|
||||
public static function parse($uri): array
|
||||
{
|
||||
if (is_object($uri) && method_exists($uri, '__toString')) {
|
||||
$uri = (string) $uri;
|
||||
}
|
||||
|
||||
if (!is_scalar($uri)) {
|
||||
throw new TypeError(sprintf('The uri must be a scalar or a stringable object `%s` given', gettype($uri)));
|
||||
}
|
||||
|
||||
$uri = (string) $uri;
|
||||
|
||||
if (isset(self::URI_SCHORTCUTS[$uri])) {
|
||||
/** @var array{scheme:?string, user:?string, pass:?string, host:?string, port:?int, path:string, query:?string, fragment:?string} $components */
|
||||
$components = array_merge(self::URI_COMPONENTS, self::URI_SCHORTCUTS[$uri]);
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
if (1 === preg_match(self::REGEXP_INVALID_URI_CHARS, $uri)) {
|
||||
throw new SyntaxError(sprintf('The uri `%s` contains invalid characters', $uri));
|
||||
}
|
||||
|
||||
//if the first character is a known URI delimiter parsing can be simplified
|
||||
$first_char = $uri[0];
|
||||
|
||||
//The URI is made of the fragment only
|
||||
if ('#' === $first_char) {
|
||||
[, $fragment] = explode('#', $uri, 2);
|
||||
$components = self::URI_COMPONENTS;
|
||||
$components['fragment'] = $fragment;
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
//The URI is made of the query and fragment
|
||||
if ('?' === $first_char) {
|
||||
[, $partial] = explode('?', $uri, 2);
|
||||
[$query, $fragment] = explode('#', $partial, 2) + [1 => null];
|
||||
$components = self::URI_COMPONENTS;
|
||||
$components['query'] = $query;
|
||||
$components['fragment'] = $fragment;
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
//use RFC3986 URI regexp to split the URI
|
||||
preg_match(self::REGEXP_URI_PARTS, $uri, $parts);
|
||||
$parts += ['query' => '', 'fragment' => ''];
|
||||
|
||||
if (':' === $parts['scheme'] || 1 !== preg_match(self::REGEXP_URI_SCHEME, $parts['scontent'])) {
|
||||
throw new SyntaxError(sprintf('The uri `%s` contains an invalid scheme', $uri));
|
||||
}
|
||||
|
||||
if ('' === $parts['scheme'].$parts['authority'] && 1 === preg_match(self::REGEXP_INVALID_PATH, $parts['path'])) {
|
||||
throw new SyntaxError(sprintf('The uri `%s` contains an invalid path.', $uri));
|
||||
}
|
||||
|
||||
/** @var array{scheme:?string, user:?string, pass:?string, host:?string, port:?int, path:string, query:?string, fragment:?string} $components */
|
||||
$components = array_merge(
|
||||
self::URI_COMPONENTS,
|
||||
'' === $parts['authority'] ? [] : self::parseAuthority($parts['acontent']),
|
||||
[
|
||||
'path' => $parts['path'],
|
||||
'scheme' => '' === $parts['scheme'] ? null : $parts['scontent'],
|
||||
'query' => '' === $parts['query'] ? null : $parts['qcontent'],
|
||||
'fragment' => '' === $parts['fragment'] ? null : $parts['fcontent'],
|
||||
]
|
||||
);
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the URI authority part.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2
|
||||
*
|
||||
* @throws SyntaxError If the port component is invalid
|
||||
*
|
||||
* @return array{user:?string, pass:?string, host:?string, port:?int}
|
||||
*/
|
||||
private static function parseAuthority(string $authority): array
|
||||
{
|
||||
$components = ['user' => null, 'pass' => null, 'host' => '', 'port' => null];
|
||||
if ('' === $authority) {
|
||||
return $components;
|
||||
}
|
||||
|
||||
$parts = explode('@', $authority, 2);
|
||||
if (isset($parts[1])) {
|
||||
[$components['user'], $components['pass']] = explode(':', $parts[0], 2) + [1 => null];
|
||||
}
|
||||
|
||||
preg_match(self::REGEXP_HOST_PORT, $parts[1] ?? $parts[0], $matches);
|
||||
$matches += ['port' => ''];
|
||||
|
||||
$components['port'] = self::filterPort($matches['port']);
|
||||
$components['host'] = self::filterHost($matches['host']);
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter and format the port component.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
*
|
||||
* @throws SyntaxError if the registered name is invalid
|
||||
*/
|
||||
private static function filterPort(string $port): ?int
|
||||
{
|
||||
if ('' === $port) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (1 === preg_match('/^\d*$/', $port)) {
|
||||
return (int) $port;
|
||||
}
|
||||
|
||||
throw new SyntaxError(sprintf('The port `%s` is invalid', $port));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a hostname is valid.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
*
|
||||
* @throws SyntaxError if the registered name is invalid
|
||||
*/
|
||||
private static function filterHost(string $host): string
|
||||
{
|
||||
if ('' === $host) {
|
||||
return $host;
|
||||
}
|
||||
|
||||
if ('[' !== $host[0] || ']' !== substr($host, -1)) {
|
||||
return self::filterRegisteredName($host);
|
||||
}
|
||||
|
||||
if (!self::isIpHost(substr($host, 1, -1))) {
|
||||
throw new SyntaxError(sprintf('Host `%s` is invalid : the IP host is malformed', $host));
|
||||
}
|
||||
|
||||
return $host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the host is an IPv4 or a registered named.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
*
|
||||
* @throws SyntaxError if the registered name is invalid
|
||||
* @throws IdnSupportMissing if IDN support or ICU requirement are not available or met.
|
||||
*/
|
||||
private static function filterRegisteredName(string $host): string
|
||||
{
|
||||
$formatted_host = rawurldecode($host);
|
||||
if (1 === preg_match(self::REGEXP_REGISTERED_NAME, $formatted_host)) {
|
||||
return $host;
|
||||
}
|
||||
|
||||
//to test IDN host non-ascii characters must be present in the host
|
||||
if (1 !== preg_match(self::REGEXP_IDN_PATTERN, $formatted_host)) {
|
||||
throw new SyntaxError(sprintf('Host `%s` is invalid : the host is not a valid registered name', $host));
|
||||
}
|
||||
|
||||
$info = Idna::toAscii($host, Idna::IDNA2008_ASCII);
|
||||
if (0 !== $info->errors()) {
|
||||
throw IdnaConversionFailed::dueToIDNAError($host, $info);
|
||||
}
|
||||
|
||||
return $host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a IPv6/IPvfuture host.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
* @link https://tools.ietf.org/html/rfc6874#section-2
|
||||
* @link https://tools.ietf.org/html/rfc6874#section-4
|
||||
*/
|
||||
private static function isIpHost(string $ip_host): bool
|
||||
{
|
||||
if (false !== filter_var($ip_host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (1 === preg_match(self::REGEXP_IP_FUTURE, $ip_host, $matches)) {
|
||||
return !in_array($matches['version'], ['4', '6'], true);
|
||||
}
|
||||
|
||||
$pos = strpos($ip_host, '%');
|
||||
if (false === $pos || 1 === preg_match(
|
||||
self::REGEXP_INVALID_HOST_CHARS,
|
||||
rawurldecode(substr($ip_host, $pos))
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ip_host = substr($ip_host, 0, $pos);
|
||||
|
||||
return false !== filter_var($ip_host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)
|
||||
&& 0 === strpos((string) inet_pton($ip_host), self::ZONE_ID_ADDRESS_BLOCK);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri;
|
||||
|
||||
use League\Uri\Contracts\UriException;
|
||||
use League\Uri\Contracts\UriInterface;
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
use League\Uri\Exceptions\TemplateCanNotBeExpanded;
|
||||
use League\Uri\UriTemplate\Template;
|
||||
use League\Uri\UriTemplate\VariableBag;
|
||||
use TypeError;
|
||||
|
||||
/**
|
||||
* Defines the URI Template syntax and the process for expanding a URI Template into a URI reference.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc6570
|
||||
* @package League\Uri
|
||||
* @author Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
* @since 6.1.0
|
||||
*
|
||||
* Based on GuzzleHttp\UriTemplate class in Guzzle v6.5.
|
||||
* @link https://github.com/guzzle/guzzle/blob/6.5/src/UriTemplate.php
|
||||
*/
|
||||
final class UriTemplate
|
||||
{
|
||||
private Template $template;
|
||||
private VariableBag $defaultVariables;
|
||||
|
||||
/**
|
||||
* @param object|string $template a string or an object with the __toString method
|
||||
*
|
||||
* @throws TypeError if the template is not a string or an object with the __toString method
|
||||
* @throws SyntaxError if the template syntax is invalid
|
||||
* @throws TemplateCanNotBeExpanded if the template variables are invalid
|
||||
*/
|
||||
public function __construct($template, array $defaultVariables = [])
|
||||
{
|
||||
$this->template = Template::createFromString($template);
|
||||
$this->defaultVariables = $this->filterVariables($defaultVariables);
|
||||
}
|
||||
|
||||
public static function __set_state(array $properties): self
|
||||
{
|
||||
return new self($properties['template']->toString(), $properties['defaultVariables']->all());
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out variables for the given template.
|
||||
*
|
||||
* @param array<string,string|array<string>> $variables
|
||||
*/
|
||||
private function filterVariables(array $variables): VariableBag
|
||||
{
|
||||
$output = new VariableBag();
|
||||
foreach ($this->template->variableNames() as $name) {
|
||||
if (isset($variables[$name])) {
|
||||
$output->assign($name, $variables[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* The template string.
|
||||
*/
|
||||
public function getTemplate(): string
|
||||
{
|
||||
return $this->template->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of the variables in the template, in order.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getVariableNames(): array
|
||||
{
|
||||
return $this->template->variableNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default values used to expand the template.
|
||||
*
|
||||
* The returned list only contains variables whose name is part of the current template.
|
||||
*
|
||||
* @return array<string,string|array>
|
||||
*/
|
||||
public function getDefaultVariables(): array
|
||||
{
|
||||
return $this->defaultVariables->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance with the updated default variables.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the modified default variables.
|
||||
*
|
||||
* If present, variables whose name is not part of the current template
|
||||
* possible variable names are removed.
|
||||
*/
|
||||
public function withDefaultVariables(array $defaultDefaultVariables): self
|
||||
{
|
||||
return new self(
|
||||
$this->template->toString(),
|
||||
$this->filterVariables($defaultDefaultVariables)->all()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TemplateCanNotBeExpanded if the variable contains nested array values
|
||||
* @throws UriException if the resulting expansion can not be converted to a UriInterface instance
|
||||
*/
|
||||
public function expand(array $variables = []): UriInterface
|
||||
{
|
||||
return Uri::createFromString(
|
||||
$this->template->expand(
|
||||
$this->filterVariables($variables)->replace($this->defaultVariables)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,329 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\UriTemplate;
|
||||
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
use League\Uri\Exceptions\TemplateCanNotBeExpanded;
|
||||
use function array_filter;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function array_unique;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function preg_match;
|
||||
use function rawurlencode;
|
||||
use function str_replace;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
|
||||
final class Expression
|
||||
{
|
||||
/**
|
||||
* Expression regular expression pattern.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc6570#section-2.2
|
||||
*/
|
||||
private const REGEXP_EXPRESSION = '/^\{
|
||||
(?:
|
||||
(?<operator>[\.\/;\?&\=,\!@\|\+#])?
|
||||
(?<variables>[^\}]*)
|
||||
)
|
||||
\}$/x';
|
||||
|
||||
/**
|
||||
* Reserved Operator characters.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc6570#section-2.2
|
||||
*/
|
||||
private const RESERVED_OPERATOR = '=,!@|';
|
||||
|
||||
/**
|
||||
* Processing behavior according to the expression type operator.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc6570#appendix-A
|
||||
*/
|
||||
private const OPERATOR_HASH_LOOKUP = [
|
||||
'' => ['prefix' => '', 'joiner' => ',', 'query' => false],
|
||||
'+' => ['prefix' => '', 'joiner' => ',', 'query' => false],
|
||||
'#' => ['prefix' => '#', 'joiner' => ',', 'query' => false],
|
||||
'.' => ['prefix' => '.', 'joiner' => '.', 'query' => false],
|
||||
'/' => ['prefix' => '/', 'joiner' => '/', 'query' => false],
|
||||
';' => ['prefix' => ';', 'joiner' => ';', 'query' => true],
|
||||
'?' => ['prefix' => '?', 'joiner' => '&', 'query' => true],
|
||||
'&' => ['prefix' => '&', 'joiner' => '&', 'query' => true],
|
||||
];
|
||||
|
||||
private string $operator;
|
||||
/** @var array<VarSpecifier> */
|
||||
private array $varSpecifiers;
|
||||
private string $joiner;
|
||||
/** @var array<string> */
|
||||
private array $variableNames;
|
||||
private string $expressionString;
|
||||
|
||||
private function __construct(string $operator, VarSpecifier ...$varSpecifiers)
|
||||
{
|
||||
$this->operator = $operator;
|
||||
$this->varSpecifiers = $varSpecifiers;
|
||||
$this->joiner = self::OPERATOR_HASH_LOOKUP[$operator]['joiner'];
|
||||
$this->variableNames = $this->setVariableNames();
|
||||
$this->expressionString = $this->setExpressionString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
private function setVariableNames(): array
|
||||
{
|
||||
return array_unique(array_map(
|
||||
static fn (VarSpecifier $varSpecifier): string => $varSpecifier->name(),
|
||||
$this->varSpecifiers
|
||||
));
|
||||
}
|
||||
|
||||
private function setExpressionString(): string
|
||||
{
|
||||
$varSpecifierString = implode(',', array_map(
|
||||
static fn (VarSpecifier $variable): string => $variable->toString(),
|
||||
$this->varSpecifiers
|
||||
));
|
||||
|
||||
return '{'.$this->operator.$varSpecifierString.'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function __set_state(array $properties): self
|
||||
{
|
||||
return new self($properties['operator'], ...$properties['varSpecifiers']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SyntaxError if the expression is invalid
|
||||
* @throws SyntaxError if the operator used in the expression is invalid
|
||||
* @throws SyntaxError if the variable specifiers is invalid
|
||||
*/
|
||||
public static function createFromString(string $expression): self
|
||||
{
|
||||
if (1 !== preg_match(self::REGEXP_EXPRESSION, $expression, $parts)) {
|
||||
throw new SyntaxError('The expression "'.$expression.'" is invalid.');
|
||||
}
|
||||
|
||||
/** @var array{operator:string, variables:string} $parts */
|
||||
$parts = $parts + ['operator' => ''];
|
||||
if ('' !== $parts['operator'] && false !== strpos(self::RESERVED_OPERATOR, $parts['operator'])) {
|
||||
throw new SyntaxError('The operator used in the expression "'.$expression.'" is reserved.');
|
||||
}
|
||||
|
||||
return new Expression($parts['operator'], ...array_map(
|
||||
static fn (string $varSpec): VarSpecifier => VarSpecifier::createFromString($varSpec),
|
||||
explode(',', $parts['variables'])
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expression string representation.
|
||||
*
|
||||
*/
|
||||
public function toString(): string
|
||||
{
|
||||
return $this->expressionString;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
public function variableNames(): array
|
||||
{
|
||||
return $this->variableNames;
|
||||
}
|
||||
|
||||
public function expand(VariableBag $variables): string
|
||||
{
|
||||
$parts = [];
|
||||
foreach ($this->varSpecifiers as $varSpecifier) {
|
||||
$parts[] = $this->replace($varSpecifier, $variables);
|
||||
}
|
||||
|
||||
$expanded = implode($this->joiner, array_filter($parts, static fn ($value): bool => '' !== $value));
|
||||
if ('' === $expanded) {
|
||||
return $expanded;
|
||||
}
|
||||
|
||||
$prefix = self::OPERATOR_HASH_LOOKUP[$this->operator]['prefix'];
|
||||
if ('' === $prefix) {
|
||||
return $expanded;
|
||||
}
|
||||
|
||||
return $prefix.$expanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces an expression with the given variables.
|
||||
*
|
||||
* @throws TemplateCanNotBeExpanded if the variables is an array and a ":" modifier needs to be applied
|
||||
* @throws TemplateCanNotBeExpanded if the variables contains nested array values
|
||||
*/
|
||||
private function replace(VarSpecifier $varSpec, VariableBag $variables): string
|
||||
{
|
||||
$value = $variables->fetch($varSpec->name());
|
||||
if (null === $value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$useQuery = self::OPERATOR_HASH_LOOKUP[$this->operator]['query'];
|
||||
[$expanded, $actualQuery] = $this->inject($value, $varSpec, $useQuery);
|
||||
if (!$actualQuery) {
|
||||
return $expanded;
|
||||
}
|
||||
|
||||
if ('&' !== $this->joiner && '' === $expanded) {
|
||||
return $varSpec->name();
|
||||
}
|
||||
|
||||
return $varSpec->name().'='.$expanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|array<string> $value
|
||||
*
|
||||
* @return array{0:string, 1:bool}
|
||||
*/
|
||||
private function inject($value, VarSpecifier $varSpec, bool $useQuery): array
|
||||
{
|
||||
if (is_string($value)) {
|
||||
return $this->replaceString($value, $varSpec, $useQuery);
|
||||
}
|
||||
|
||||
return $this->replaceList($value, $varSpec, $useQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands an expression using a string value.
|
||||
*
|
||||
* @return array{0:string, 1:bool}
|
||||
*/
|
||||
private function replaceString(string $value, VarSpecifier $varSpec, bool $useQuery): array
|
||||
{
|
||||
if (':' === $varSpec->modifier()) {
|
||||
$value = substr($value, 0, $varSpec->position());
|
||||
}
|
||||
|
||||
$expanded = rawurlencode($value);
|
||||
if ('+' === $this->operator || '#' === $this->operator) {
|
||||
return [$this->decodeReserved($expanded), $useQuery];
|
||||
}
|
||||
|
||||
return [$expanded, $useQuery];
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands an expression using a list of values.
|
||||
*
|
||||
* @param array<string> $value
|
||||
*
|
||||
* @throws TemplateCanNotBeExpanded if the variables is an array and a ":" modifier needs to be applied
|
||||
*
|
||||
* @return array{0:string, 1:bool}
|
||||
*/
|
||||
private function replaceList(array $value, VarSpecifier $varSpec, bool $useQuery): array
|
||||
{
|
||||
if ([] === $value) {
|
||||
return ['', false];
|
||||
}
|
||||
|
||||
if (':' === $varSpec->modifier()) {
|
||||
throw TemplateCanNotBeExpanded::dueToUnableToProcessValueListWithPrefix($varSpec->name());
|
||||
}
|
||||
|
||||
$pairs = [];
|
||||
$isAssoc = $this->isAssoc($value);
|
||||
foreach ($value as $key => $var) {
|
||||
if ($isAssoc) {
|
||||
$key = rawurlencode((string) $key);
|
||||
}
|
||||
|
||||
$var = rawurlencode($var);
|
||||
if ('+' === $this->operator || '#' === $this->operator) {
|
||||
$var = $this->decodeReserved($var);
|
||||
}
|
||||
|
||||
if ('*' === $varSpec->modifier()) {
|
||||
if ($isAssoc) {
|
||||
$var = $key.'='.$var;
|
||||
} elseif ($key > 0 && $useQuery) {
|
||||
$var = $varSpec->name().'='.$var;
|
||||
}
|
||||
}
|
||||
|
||||
$pairs[$key] = $var;
|
||||
}
|
||||
|
||||
if ('*' === $varSpec->modifier()) {
|
||||
if ($isAssoc) {
|
||||
// Don't prepend the value name when using the explode
|
||||
// modifier with an associative array.
|
||||
$useQuery = false;
|
||||
}
|
||||
|
||||
return [implode($this->joiner, $pairs), $useQuery];
|
||||
}
|
||||
|
||||
if ($isAssoc) {
|
||||
// When an associative array is encountered and the
|
||||
// explode modifier is not set, then the result must be
|
||||
// a comma separated list of keys followed by their
|
||||
// respective values.
|
||||
foreach ($pairs as $offset => &$data) {
|
||||
$data = $offset.','.$data;
|
||||
}
|
||||
|
||||
unset($data);
|
||||
}
|
||||
|
||||
return [implode(',', $pairs), $useQuery];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an array is associative.
|
||||
*
|
||||
* This makes the assumption that input arrays are sequences or hashes.
|
||||
* This assumption is a trade-off for accuracy in favor of speed, but it
|
||||
* should work in almost every case where input is supplied for a URI
|
||||
* template.
|
||||
*/
|
||||
private function isAssoc(array $array): bool
|
||||
{
|
||||
return [] !== $array && 0 !== array_keys($array)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes percent encoding on reserved characters (used with + and # modifiers).
|
||||
*/
|
||||
private function decodeReserved(string $str): string
|
||||
{
|
||||
static $delimiters = [
|
||||
':', '/', '?', '#', '[', ']', '@', '!', '$',
|
||||
'&', '\'', '(', ')', '*', '+', ',', ';', '=',
|
||||
];
|
||||
|
||||
static $delimitersEncoded = [
|
||||
'%3A', '%2F', '%3F', '%23', '%5B', '%5D', '%40', '%21', '%24',
|
||||
'%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', '%3B', '%3D',
|
||||
];
|
||||
|
||||
return str_replace($delimitersEncoded, $delimiters, $str);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\UriTemplate;
|
||||
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
use League\Uri\Exceptions\TemplateCanNotBeExpanded;
|
||||
use TypeError;
|
||||
use function array_merge;
|
||||
use function array_unique;
|
||||
use function gettype;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function method_exists;
|
||||
use function preg_match_all;
|
||||
use function preg_replace;
|
||||
use function sprintf;
|
||||
use function strpos;
|
||||
use const PREG_SET_ORDER;
|
||||
|
||||
final class Template
|
||||
{
|
||||
/**
|
||||
* Expression regular expression pattern.
|
||||
*/
|
||||
private const REGEXP_EXPRESSION_DETECTOR = '/\{[^\}]*\}/x';
|
||||
|
||||
private string $template;
|
||||
/** @var array<string, Expression> */
|
||||
private array $expressions = [];
|
||||
/** @var array<string> */
|
||||
private array $variableNames;
|
||||
|
||||
private function __construct(string $template, Expression ...$expressions)
|
||||
{
|
||||
$this->template = $template;
|
||||
$variableNames = [];
|
||||
foreach ($expressions as $expression) {
|
||||
$this->expressions[$expression->toString()] = $expression;
|
||||
$variableNames[] = $expression->variableNames();
|
||||
}
|
||||
$this->variableNames = array_unique(array_merge([], ...$variableNames));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function __set_state(array $properties): self
|
||||
{
|
||||
return new self($properties['template'], ...array_values($properties['expressions']));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object|string $template a string or an object with the __toString method
|
||||
*
|
||||
* @throws TypeError if the template is not a string or an object with the __toString method
|
||||
* @throws SyntaxError if the template contains invalid expressions
|
||||
* @throws SyntaxError if the template contains invalid variable specification
|
||||
*/
|
||||
public static function createFromString($template): self
|
||||
{
|
||||
if (is_object($template) && method_exists($template, '__toString')) {
|
||||
$template = (string) $template;
|
||||
}
|
||||
|
||||
if (!is_string($template)) {
|
||||
throw new TypeError(sprintf('The template must be a string or a stringable object %s given.', gettype($template)));
|
||||
}
|
||||
|
||||
/** @var string $remainder */
|
||||
$remainder = preg_replace(self::REGEXP_EXPRESSION_DETECTOR, '', $template);
|
||||
if (false !== strpos($remainder, '{') || false !== strpos($remainder, '}')) {
|
||||
throw new SyntaxError('The template "'.$template.'" contains invalid expressions.');
|
||||
}
|
||||
|
||||
$names = [];
|
||||
preg_match_all(self::REGEXP_EXPRESSION_DETECTOR, $template, $findings, PREG_SET_ORDER);
|
||||
$arguments = [];
|
||||
foreach ($findings as $finding) {
|
||||
if (!isset($names[$finding[0]])) {
|
||||
$arguments[] = Expression::createFromString($finding[0]);
|
||||
$names[$finding[0]] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return new self($template, ...$arguments);
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
return $this->template;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
public function variableNames(): array
|
||||
{
|
||||
return $this->variableNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TemplateCanNotBeExpanded if the variables is an array and a ":" modifier needs to be applied
|
||||
* @throws TemplateCanNotBeExpanded if the variables contains nested array values
|
||||
*/
|
||||
public function expand(VariableBag $variables): string
|
||||
{
|
||||
$uriString = $this->template;
|
||||
/** @var Expression $expression */
|
||||
foreach ($this->expressions as $pattern => $expression) {
|
||||
$uriString = str_replace($pattern, $expression->expand($variables), $uriString);
|
||||
}
|
||||
|
||||
return $uriString;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\UriTemplate;
|
||||
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
use function preg_match;
|
||||
|
||||
final class VarSpecifier
|
||||
{
|
||||
/**
|
||||
* Variables specification regular expression pattern.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc6570#section-2.3
|
||||
*/
|
||||
private const REGEXP_VARSPEC = '/^
|
||||
(?<name>(?:[A-z0-9_\.]|%[0-9a-fA-F]{2})+)
|
||||
(?<modifier>\:(?<position>\d+)|\*)?
|
||||
$/x';
|
||||
|
||||
private string $name;
|
||||
private string $modifier;
|
||||
private int $position;
|
||||
|
||||
private function __construct(string $name, string $modifier, int $position)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->modifier = $modifier;
|
||||
$this->position = $position;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function __set_state(array $properties): self
|
||||
{
|
||||
return new self($properties['name'], $properties['modifier'], $properties['position']);
|
||||
}
|
||||
|
||||
public static function createFromString(string $specification): self
|
||||
{
|
||||
if (1 !== preg_match(self::REGEXP_VARSPEC, $specification, $parsed)) {
|
||||
throw new SyntaxError('The variable specification "'.$specification.'" is invalid.');
|
||||
}
|
||||
|
||||
$parsed += ['modifier' => '', 'position' => ''];
|
||||
if ('' !== $parsed['position']) {
|
||||
$parsed['position'] = (int) $parsed['position'];
|
||||
$parsed['modifier'] = ':';
|
||||
}
|
||||
|
||||
if ('' === $parsed['position']) {
|
||||
$parsed['position'] = 0;
|
||||
}
|
||||
|
||||
if (10000 <= $parsed['position']) {
|
||||
throw new SyntaxError('The variable specification "'.$specification.'" is invalid the position modifier must be lower than 10000.');
|
||||
}
|
||||
|
||||
return new self($parsed['name'], $parsed['modifier'], $parsed['position']);
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
if (0 < $this->position) {
|
||||
return $this->name.$this->modifier.$this->position;
|
||||
}
|
||||
|
||||
return $this->name.$this->modifier;
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function modifier(): string
|
||||
{
|
||||
return $this->modifier;
|
||||
}
|
||||
|
||||
public function position(): int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri\UriTemplate;
|
||||
|
||||
use League\Uri\Exceptions\TemplateCanNotBeExpanded;
|
||||
use TypeError;
|
||||
use function gettype;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_object;
|
||||
use function is_scalar;
|
||||
use function method_exists;
|
||||
use function sprintf;
|
||||
|
||||
final class VariableBag
|
||||
{
|
||||
/**
|
||||
* @var array<string,string|array<string>>
|
||||
*/
|
||||
private array $variables = [];
|
||||
|
||||
/**
|
||||
* @param iterable<string,string|bool|int|float|array<string|bool|int|float>> $variables
|
||||
*/
|
||||
public function __construct(iterable $variables = [])
|
||||
{
|
||||
foreach ($variables as $name => $value) {
|
||||
$this->assign($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
public static function __set_state(array $properties): self
|
||||
{
|
||||
return new self($properties['variables']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,string|array<string>>
|
||||
*/
|
||||
public function all(): array
|
||||
{
|
||||
return $this->variables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the variable value if none found returns null.
|
||||
*
|
||||
* @return null|string|array<string>
|
||||
*/
|
||||
public function fetch(string $name)
|
||||
{
|
||||
return $this->variables[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|bool|int|float|array<string|bool|int|float> $value
|
||||
*/
|
||||
public function assign(string $name, $value): void
|
||||
{
|
||||
$this->variables[$name] = $this->normalizeValue($value, $name, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value the value to be expanded
|
||||
*
|
||||
* @throws TemplateCanNotBeExpanded if the value contains nested list
|
||||
*
|
||||
* @return string|array<string>
|
||||
*/
|
||||
private function normalizeValue($value, string $name, bool $isNestedListAllowed)
|
||||
{
|
||||
if (is_bool($value)) {
|
||||
return true === $value ? '1' : '0';
|
||||
}
|
||||
|
||||
if (null === $value || is_scalar($value) || (is_object($value) && method_exists($value, '__toString'))) {
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
if (!is_array($value)) {
|
||||
throw new TypeError(sprintf('The variable '.$name.' must be NULL, a scalar or a stringable object `%s` given', gettype($value)));
|
||||
}
|
||||
|
||||
if (!$isNestedListAllowed) {
|
||||
throw TemplateCanNotBeExpanded::dueToNestedListOfValue($name);
|
||||
}
|
||||
|
||||
foreach ($value as &$var) {
|
||||
$var = self::normalizeValue($var, $name, false);
|
||||
}
|
||||
unset($var);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces elements from passed variables into the current instance.
|
||||
*/
|
||||
public function replace(VariableBag $variables): self
|
||||
{
|
||||
return new self($this->variables + $variables->variables);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
Matt Butcher [technosophos] <technosophos@gmail.com> (lead)
|
||||
Matt Farina [mattfarina] <matt@mattfarina.com> (lead)
|
||||
Asmir Mustafic [goetas] <goetas@lignano.it> (contributor)
|
||||
Edward Z. Yang [ezyang] <ezyang@mit.edu> (contributor)
|
||||
Geoffrey Sneddon [gsnedders] <geoffers@gmail.com> (contributor)
|
||||
Kukhar Vasily [ngreduce] <ngreduce@gmail.com> (contributor)
|
||||
Rune Christensen [MrElectronic] <mrelectronic@example.com> (contributor)
|
||||
Mišo Belica [miso-belica] <miso-belica@example.com> (contributor)
|
||||
Asmir Mustafic [goetas] <goetas@example.com> (contributor)
|
||||
KITAITI Makoto [KitaitiMakoto] <KitaitiMakoto@example.com> (contributor)
|
||||
Jacob Floyd [cognifloyd] <cognifloyd@gmail.com> (contributor)
|
|
@ -0,0 +1,66 @@
|
|||
## HTML5-PHP License
|
||||
|
||||
Copyright (c) 2013 The Authors of HTML5-PHP
|
||||
|
||||
Matt Butcher - mattbutcher@google.com
|
||||
Matt Farina - matt@mattfarina.com
|
||||
Asmir Mustafic - goetas@gmail.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
## HTML5Lib License
|
||||
|
||||
Portions of this are based on html5lib's PHP version, which was a
|
||||
sub-project of html5lib. The following is the list of contributors from
|
||||
html5lib:
|
||||
|
||||
html5lib:
|
||||
|
||||
Copyright (c) 2006-2009 The Authors
|
||||
|
||||
Contributors:
|
||||
James Graham - jg307@cam.ac.uk
|
||||
Anne van Kesteren - annevankesteren@gmail.com
|
||||
Lachlan Hunt - lachlan.hunt@lachy.id.au
|
||||
Matt McDonald - kanashii@kanashii.ca
|
||||
Sam Ruby - rubys@intertwingly.net
|
||||
Ian Hickson (Google) - ian@hixie.ch
|
||||
Thomas Broyer - t.broyer@ltgt.net
|
||||
Jacques Distler - distler@golem.ph.utexas.edu
|
||||
Henri Sivonen - hsivonen@iki.fi
|
||||
Adam Barth - abarth@webkit.org
|
||||
Eric Seidel - eric@webkit.org
|
||||
The Mozilla Foundation (contributions from Henri Sivonen since 2008)
|
||||
David Flanagan (Mozilla) - dflanagan@mozilla.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,254 @@
|
|||
# HTML5-PHP
|
||||
|
||||
HTML5 is a standards-compliant HTML5 parser and writer written entirely in PHP.
|
||||
It is stable and used in many production websites, and has
|
||||
well over [five million downloads](https://packagist.org/packages/masterminds/html5).
|
||||
|
||||
HTML5 provides the following features.
|
||||
|
||||
- An HTML5 serializer
|
||||
- Support for PHP namespaces
|
||||
- Composer support
|
||||
- Event-based (SAX-like) parser
|
||||
- A DOM tree builder
|
||||
- Interoperability with [QueryPath](https://github.com/technosophos/querypath)
|
||||
- Runs on **PHP** 5.3.0 or newer
|
||||
|
||||
[![Build Status](https://travis-ci.org/Masterminds/html5-php.png?branch=master)](https://travis-ci.org/Masterminds/html5-php)
|
||||
[![Latest Stable Version](https://poser.pugx.org/masterminds/html5/v/stable.png)](https://packagist.org/packages/masterminds/html5)
|
||||
[![Code Coverage](https://scrutinizer-ci.com/g/Masterminds/html5-php/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/Masterminds/html5-php/?branch=master)
|
||||
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/Masterminds/html5-php/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/Masterminds/html5-php/?branch=master)
|
||||
[![Stability: Sustained](https://masterminds.github.io/stability/sustained.svg)](https://masterminds.github.io/stability/sustained.html)
|
||||
|
||||
## Installation
|
||||
|
||||
Install HTML5-PHP using [composer](http://getcomposer.org/).
|
||||
|
||||
By adding the `masterminds/html5` dependency to your `composer.json` file:
|
||||
|
||||
```json
|
||||
{
|
||||
"require" : {
|
||||
"masterminds/html5": "^2.0"
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
By invoking require command via composer executable:
|
||||
|
||||
```bash
|
||||
composer require masterminds/html5
|
||||
```
|
||||
|
||||
## Basic Usage
|
||||
|
||||
HTML5-PHP has a high-level API and a low-level API.
|
||||
|
||||
Here is how you use the high-level `HTML5` library API:
|
||||
|
||||
```php
|
||||
<?php
|
||||
// Assuming you installed from Composer:
|
||||
require "vendor/autoload.php";
|
||||
|
||||
use Masterminds\HTML5;
|
||||
|
||||
// An example HTML document:
|
||||
$html = <<< 'HERE'
|
||||
<html>
|
||||
<head>
|
||||
<title>TEST</title>
|
||||
</head>
|
||||
<body id='foo'>
|
||||
<h1>Hello World</h1>
|
||||
<p>This is a test of the HTML5 parser.</p>
|
||||
</body>
|
||||
</html>
|
||||
HERE;
|
||||
|
||||
// Parse the document. $dom is a DOMDocument.
|
||||
$html5 = new HTML5();
|
||||
$dom = $html5->loadHTML($html);
|
||||
|
||||
// Render it as HTML5:
|
||||
print $html5->saveHTML($dom);
|
||||
|
||||
// Or save it to a file:
|
||||
$html5->save($dom, 'out.html');
|
||||
```
|
||||
|
||||
The `$dom` created by the parser is a full `DOMDocument` object. And the
|
||||
`save()` and `saveHTML()` methods will take any DOMDocument.
|
||||
|
||||
### Options
|
||||
|
||||
It is possible to pass in an array of configuration options when loading
|
||||
an HTML5 document.
|
||||
|
||||
```php
|
||||
// An associative array of options
|
||||
$options = array(
|
||||
'option_name' => 'option_value',
|
||||
);
|
||||
|
||||
// Provide the options to the constructor
|
||||
$html5 = new HTML5($options);
|
||||
|
||||
$dom = $html5->loadHTML($html);
|
||||
```
|
||||
|
||||
The following options are supported:
|
||||
|
||||
* `encode_entities` (boolean): Indicates that the serializer should aggressively
|
||||
encode characters as entities. Without this, it only encodes the bare
|
||||
minimum.
|
||||
* `disable_html_ns` (boolean): Prevents the parser from automatically
|
||||
assigning the HTML5 namespace to the DOM document. This is for
|
||||
non-namespace aware DOM tools.
|
||||
* `target_document` (\DOMDocument): A DOM document that will be used as the
|
||||
destination for the parsed nodes.
|
||||
* `implicit_namespaces` (array): An assoc array of namespaces that should be
|
||||
used by the parser. Name is tag prefix, value is NS URI.
|
||||
|
||||
## The Low-Level API
|
||||
|
||||
This library provides the following low-level APIs that you can use to
|
||||
create more customized HTML5 tools:
|
||||
|
||||
- A SAX-like event-based parser that you can hook into for special kinds
|
||||
of parsing.
|
||||
- A flexible error-reporting mechanism that can be tuned to document
|
||||
syntax checking.
|
||||
- A DOM implementation that uses PHP's built-in DOM library.
|
||||
|
||||
The unit tests exercise each piece of the API, and every public function
|
||||
is well-documented.
|
||||
|
||||
### Parser Design
|
||||
|
||||
The parser is designed as follows:
|
||||
|
||||
- The `Scanner` handles scanning on behalf of the parser.
|
||||
- The `Tokenizer` requests data off of the scanner, parses it, clasifies
|
||||
it, and sends it to an `EventHandler`. It is a *recursive descent parser.*
|
||||
- The `EventHandler` receives notifications and data for each specific
|
||||
semantic event that occurs during tokenization.
|
||||
- The `DOMBuilder` is an `EventHandler` that listens for tokenizing
|
||||
events and builds a document tree (`DOMDocument`) based on the events.
|
||||
|
||||
### Serializer Design
|
||||
|
||||
The serializer takes a data structure (the `DOMDocument`) and transforms
|
||||
it into a character representation -- an HTML5 document.
|
||||
|
||||
The serializer is broken into three parts:
|
||||
|
||||
- The `OutputRules` contain the rules to turn DOM elements into strings. The
|
||||
rules are an implementation of the interface `RulesInterface` allowing for
|
||||
different rule sets to be used.
|
||||
- The `Traverser`, which is a special-purpose tree walker. It visits
|
||||
each node node in the tree and uses the `OutputRules` to transform the node
|
||||
into a string.
|
||||
- `HTML5` manages the `Traverser` and stores the resultant data
|
||||
in the correct place.
|
||||
|
||||
The serializer (`save()`, `saveHTML()`) follows the
|
||||
[section 8.9 of the HTML 5.0 spec](http://www.w3.org/TR/2012/CR-html5-20121217/syntax.html#serializing-html-fragments).
|
||||
So tags are serialized according to these rules:
|
||||
|
||||
- A tag with children: <foo>CHILDREN</foo>
|
||||
- A tag that cannot have content: <foo> (no closing tag)
|
||||
- A tag that could have content, but doesn't: <foo></foo>
|
||||
|
||||
## Known Issues (Or, Things We Designed Against the Spec)
|
||||
|
||||
Please check the issue queue for a full list, but the following are
|
||||
issues known issues that are not presently on the roadmap:
|
||||
|
||||
- Namespaces: HTML5 only [supports a selected list of namespaces](http://www.w3.org/TR/html5/infrastructure.html#namespaces)
|
||||
and they do not operate in the same way as XML namespaces. A `:` has no special
|
||||
meaning.
|
||||
By default the parser does not support XML style namespaces via `:`;
|
||||
to enable the XML namespaces see the [XML Namespaces section](#xml-namespaces)
|
||||
- Scripts: This parser does not contain a JavaScript or a CSS
|
||||
interpreter. While one may be supplied, not all features will be
|
||||
supported.
|
||||
- Rentrance: The current parser is not re-entrant. (Thus you can't pause
|
||||
the parser to modify the HTML string mid-parse.)
|
||||
- Validation: The current tree builder is **not** a validating parser.
|
||||
While it will correct some HTML, it does not check that the HTML
|
||||
conforms to the standard. (Should you wish, you can build a validating
|
||||
parser by extending DOMTree or building your own EventHandler
|
||||
implementation.)
|
||||
* There is limited support for insertion modes.
|
||||
* Some autocorrection is done automatically.
|
||||
* Per the spec, many legacy tags are admitted and correctly handled,
|
||||
even though they are technically not part of HTML5.
|
||||
- Attribute names and values: Due to the implementation details of the
|
||||
PHP implementation of DOM, attribute names that do not follow the
|
||||
XML 1.0 standard are not inserted into the DOM. (Effectively, they
|
||||
are ignored.) If you've got a clever fix for this, jump in!
|
||||
- Processor Instructions: The HTML5 spec does not allow processor
|
||||
instructions. We do. Since this is a server-side library, we think
|
||||
this is useful. And that means, dear reader, that in some cases you
|
||||
can parse the HTML from a mixed PHP/HTML document. This, however,
|
||||
is an incidental feature, not a core feature.
|
||||
- HTML manifests: Unsupported.
|
||||
- PLAINTEXT: Unsupported.
|
||||
- Adoption Agency Algorithm: Not yet implemented. (8.2.5.4.7)
|
||||
|
||||
## XML Namespaces
|
||||
|
||||
To use XML style namespaces you have to configure well the main `HTML5` instance.
|
||||
|
||||
```php
|
||||
use Masterminds\HTML5;
|
||||
$html = new HTML5(array(
|
||||
"xmlNamespaces" => true
|
||||
));
|
||||
|
||||
$dom = $html->loadHTML('<t:tag xmlns:t="http://www.example.com"/>');
|
||||
|
||||
$dom->documentElement->namespaceURI; // http://www.example.com
|
||||
|
||||
```
|
||||
|
||||
You can also add some default prefixes that will not require the namespace declaration,
|
||||
but its elements will be namespaced.
|
||||
|
||||
```php
|
||||
use Masterminds\HTML5;
|
||||
$html = new HTML5(array(
|
||||
"implicitNamespaces"=>array(
|
||||
"t"=>"http://www.example.com"
|
||||
)
|
||||
));
|
||||
|
||||
$dom = $html->loadHTML('<t:tag/>');
|
||||
|
||||
$dom->documentElement->namespaceURI; // http://www.example.com
|
||||
|
||||
```
|
||||
|
||||
## Thanks to...
|
||||
|
||||
The dedicated (and patient) contributors of patches small and large,
|
||||
who have already made this library better.See the CREDITS file for
|
||||
a list of contributors.
|
||||
|
||||
We owe a huge debt of gratitude to the original authors of html5lib.
|
||||
|
||||
While not much of the original parser remains, we learned a lot from
|
||||
reading the html5lib library. And some pieces remain here. In
|
||||
particular, much of the UTF-8 and Unicode handling is derived from the
|
||||
html5lib project.
|
||||
|
||||
## License
|
||||
|
||||
This software is released under the MIT license. The original html5lib
|
||||
library was also released under the MIT license.
|
||||
|
||||
See LICENSE.txt
|
||||
|
||||
Certain files contain copyright assertions by specific individuals
|
||||
involved with html5lib. Those have been retained where appropriate.
|
|
@ -0,0 +1,153 @@
|
|||
# Release Notes
|
||||
|
||||
2.7.5 (2021-07-01)
|
||||
|
||||
- #204: Travis: Enable tests on PHP 8.0
|
||||
- #207: Fix PHP 8.1 deprecations
|
||||
|
||||
2.7.4 (2020-10-01)
|
||||
|
||||
- #191: Fix travisci build
|
||||
- #195: Add .gitattributes file with export-ignore rules
|
||||
- #194: Fix query parameter parsed as character entity
|
||||
|
||||
2.7.3 (2020-07-05)
|
||||
|
||||
- #190: mitigate cyclic reference between output rules and the traverser objects
|
||||
|
||||
2.7.2 (2020-07-01)
|
||||
|
||||
- #187: Fixed memory leak in HTML5::saveHTML()
|
||||
- #186: Add special case for end tag </br>
|
||||
|
||||
2.7.1 (2020-06-14)
|
||||
|
||||
- #171: add PHP 7.4 job
|
||||
- #178: Prevent infinite loop on un-terminated entity declaration at EOF
|
||||
|
||||
2.7.0 (2019-07-25)
|
||||
|
||||
- #164: Drop HHVM support
|
||||
- #168: Set default encoding in the DOMDocument object
|
||||
|
||||
2.6.0 (2019-03-10)
|
||||
|
||||
- #163: Allow to pass a charset to the Scanner
|
||||
|
||||
2.5.0 (2018-12-27)
|
||||
|
||||
- #162, #161, #155, #154, #153, #151: big performance improvements
|
||||
- #156: fixed typos
|
||||
- #160: adopt and enforce code style
|
||||
- #159: remove deprecated php unit base test case
|
||||
- #150: backport changes from old master branch
|
||||
|
||||
2.4.0 (2018-11-17)
|
||||
|
||||
- #148: Improve performance by moving sequence matching
|
||||
- #147: Improve the Tokenizer performance
|
||||
- #146: Improve performance by relying on a native string instead of InputStream
|
||||
- #144: Add DOM extension in composer.json
|
||||
- #145: Add more extensions on composer.json, improve phpdocs and remove dead code
|
||||
- #143: Remove experimental comment
|
||||
|
||||
2.3.1 (2018-10-18)
|
||||
|
||||
- #121: Audio is not a block tag (fixed by #141)
|
||||
- #136: Handle illegal self-closing according to spec (fixed by #137)
|
||||
- #141: Minor fixes in the README
|
||||
|
||||
2.3.0 (2017-09-04)
|
||||
|
||||
- #129: image within inline svg breaks system (fixed by #133)
|
||||
- #131: ² does not work (fixed by #132)
|
||||
- #134: Improve tokenizer performance by 20% (alternative version of #130 thanks to @MichaelHeerklotz)
|
||||
- #135: Raw & in attributes
|
||||
|
||||
2.2.2 (2016-09-22)
|
||||
|
||||
- #116: In XML mode, tags are case sensitive
|
||||
- #115: Fix PHP Notice in OutputRules
|
||||
- #112: fix parsing of options of an optgroup
|
||||
- #111: Adding test for the address tag
|
||||
|
||||
2.2.1 (2016-05-10)
|
||||
|
||||
- #109: Fixed issue where address tag could be written without closing tag (thanks sylus)
|
||||
|
||||
2.2.0 (2016-04-11)
|
||||
|
||||
- #105: Enable composer cache (for CI/CD)
|
||||
- #100: Use mb_substitute_character inset of ini_set for environments where ini_set is disable (e.g., shared hosting)
|
||||
- #98: Allow link, meta, style tags in noscript tags
|
||||
- #96: Fixed xml:href on svgs that use the "use" breaking
|
||||
- #94: Counting UTF8 characters performance improvement
|
||||
- #93: Use newer version of coveralls package
|
||||
- #90: Remove duplicate test
|
||||
- #87: Allow multiple root nodes
|
||||
|
||||
2.1.2 (2015-06-07)
|
||||
- #82: Support for PHP7
|
||||
- #84: Improved boolean attribute handling
|
||||
|
||||
2.1.1 (2015-03-23)
|
||||
- #78: Fixes bug where unmatched entity like string drops everything after &.
|
||||
|
||||
2.1.0 (2015-02-01)
|
||||
- #74: Added `disable_html_ns` and `target_doc` dom parsing options
|
||||
- Unified option names
|
||||
- #73: Fixed alphabet, ß now can be detected
|
||||
- #75 and #76: Allow whitespace in RCDATA tags
|
||||
- #77: Fixed parsing blunder for json embeds
|
||||
- #72: Add options to HTML methods
|
||||
|
||||
2.0.2 (2014-12-17)
|
||||
- #50: empty document handling
|
||||
- #63: tags with strange capitalization
|
||||
- #65: dashes and underscores as allowed characters in tag names
|
||||
- #68: Fixed issue with non-inline elements inside inline containers
|
||||
|
||||
2.0.1 (2014-09-23)
|
||||
- #59: Fixed issue parsing some fragments.
|
||||
- #56: Incorrectly saw 0 as empty string
|
||||
- Sami as new documentation generator
|
||||
|
||||
2.0.0 (2014-07-28)
|
||||
- #53: Improved boolean attributes handling
|
||||
- #52: Facebook HHVM compatibility
|
||||
- #48: Adopted PSR-2 as coding standard
|
||||
- #47: Moved everything to Masterminds namespace
|
||||
- #45: Added custom namespaces
|
||||
- #44: Added support to XML-style namespaces
|
||||
- #37: Refactored HTML5 class removing static methods
|
||||
|
||||
1.0.5 (2014-06-10)
|
||||
- #38: Set the dev-master branch as the 1.0.x branch for composer (goetas)
|
||||
- #34: Tests use PSR-4 for autoloading. (goetas)
|
||||
- #40, #41: Fix entity handling in RCDATA sections. (KitaitiMakoto)
|
||||
- #32: Fixed issue where wharacter references were being incorrectly encoded in style tags.
|
||||
|
||||
1.0.4 (2014-04-29)
|
||||
- #30/#31 Don't throw an exception for invalid tag names.
|
||||
|
||||
1.0.3 (2014-02-28)
|
||||
- #23 and #29: Ignore attributes with illegal chars in name for the PHP DOM.
|
||||
|
||||
1.0.2 (2014-02-12)
|
||||
- #23: Handle missing tag close in attribute list.
|
||||
- #25: Fixed text escaping in the serializer (HTML% 8.3).
|
||||
- #27: Fixed tests on Windows: changed "\n" -> PHP_EOL.
|
||||
- #28: Fixed infinite loop for char "&" in unquoted attribute in parser.
|
||||
- #26: Updated tag name case handling to deal with uppercase usage.
|
||||
- #24: Newlines and tabs are allowed inside quoted attributes (HTML5 8.2.4).
|
||||
- Fixed Travis CI testing.
|
||||
|
||||
1.0.1 (2013-11-07)
|
||||
- CDATA encoding is improved. (Non-standard; Issue #19)
|
||||
- Some parser rules were not returning the new current element. (Issue #20)
|
||||
- Added, to the README, details on code test coverage and to packagist version.
|
||||
- Fixed processor instructions.
|
||||
- Improved test coverage and documentation coverage.
|
||||
|
||||
1.0.0 (2013-10-02)
|
||||
- Initial release.
|
|
@ -0,0 +1,21 @@
|
|||
From 1.x to 2.x
|
||||
=================
|
||||
|
||||
- All classes uses `Masterminds` namespace.
|
||||
- All public static methods has been removed from `HTML5` class and the general API to access the HTML5 functionalities has changed.
|
||||
|
||||
Before:
|
||||
|
||||
$dom = \HTML5::loadHTML('<html>....');
|
||||
\HTML5::saveHTML($dom);
|
||||
|
||||
After:
|
||||
|
||||
use Masterminds\HTML5;
|
||||
|
||||
$html5 = new HTML5();
|
||||
|
||||
$dom = $html5->loadHTML('<html>....');
|
||||
echo $html5->saveHTML($dom);
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
/**
|
||||
* Fetch the entities.json file and convert to PHP datastructure.
|
||||
*/
|
||||
|
||||
// The URL to the official entities JSON file.
|
||||
$ENTITIES_URL = 'http://www.w3.org/TR/2012/CR-html5-20121217/entities.json';
|
||||
|
||||
$payload = file_get_contents($ENTITIES_URL);
|
||||
$json = json_decode($payload);
|
||||
|
||||
$table = array();
|
||||
foreach ($json as $name => $obj) {
|
||||
$sname = substr($name, 1, -1);
|
||||
$table[$sname] = $obj->characters;
|
||||
}
|
||||
|
||||
echo '<?php
|
||||
namespace Masterminds\\HTML5;
|
||||
/** Entity lookup tables. This class is automatically generated. */
|
||||
class Entities {
|
||||
public static $byName = ';
|
||||
var_export($table);
|
||||
echo ';
|
||||
}' . PHP_EOL;
|
||||
//print serialize($table);
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"name": "masterminds/html5",
|
||||
"description": "An HTML5 parser and serializer.",
|
||||
"type": "library",
|
||||
"homepage": "http://masterminds.github.io/html5-php",
|
||||
"license": "MIT",
|
||||
"keywords": ["xml", "html", "html5", "dom", "parser", "serializer", "querypath"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Matt Butcher",
|
||||
"email": "technosophos@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Matt Farina",
|
||||
"email": "matt@mattfarina.com"
|
||||
},
|
||||
{
|
||||
"name": "Asmir Mustafic",
|
||||
"email": "goetas@gmail.com"
|
||||
}
|
||||
],
|
||||
"require" : {
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-libxml" : "*",
|
||||
"php" : ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit" : "^4.8.35 || ^5.7.21 || ^6 || ^7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {"Masterminds\\": "src"}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {"Masterminds\\HTML5\\Tests\\": "test/HTML5"}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
<?php
|
||||
|
||||
namespace Masterminds;
|
||||
|
||||
use Masterminds\HTML5\Parser\DOMTreeBuilder;
|
||||
use Masterminds\HTML5\Parser\Scanner;
|
||||
use Masterminds\HTML5\Parser\Tokenizer;
|
||||
use Masterminds\HTML5\Serializer\OutputRules;
|
||||
use Masterminds\HTML5\Serializer\Traverser;
|
||||
|
||||
/**
|
||||
* This class offers convenience methods for parsing and serializing HTML5.
|
||||
* It is roughly designed to mirror the \DOMDocument native class.
|
||||
*/
|
||||
class HTML5
|
||||
{
|
||||
/**
|
||||
* Global options for the parser and serializer.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $defaultOptions = array(
|
||||
// Whether the serializer should aggressively encode all characters as entities.
|
||||
'encode_entities' => false,
|
||||
|
||||
// Prevents the parser from automatically assigning the HTML5 namespace to the DOM document.
|
||||
'disable_html_ns' => false,
|
||||
);
|
||||
|
||||
protected $errors = array();
|
||||
|
||||
public function __construct(array $defaultOptions = array())
|
||||
{
|
||||
$this->defaultOptions = array_merge($this->defaultOptions, $defaultOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current default options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->defaultOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and parse an HTML file.
|
||||
*
|
||||
* This will apply the HTML5 parser, which is tolerant of many
|
||||
* varieties of HTML, including XHTML 1, HTML 4, and well-formed HTML
|
||||
* 3. Note that in these cases, not all of the old data will be
|
||||
* preserved. For example, XHTML's XML declaration will be removed.
|
||||
*
|
||||
* The rules governing parsing are set out in the HTML 5 spec.
|
||||
*
|
||||
* @param string|resource $file The path to the file to parse. If this is a resource, it is
|
||||
* assumed to be an open stream whose pointer is set to the first
|
||||
* byte of input.
|
||||
* @param array $options Configuration options when parsing the HTML.
|
||||
*
|
||||
* @return \DOMDocument A DOM document. These object type is defined by the libxml
|
||||
* library, and should have been included with your version of PHP.
|
||||
*/
|
||||
public function load($file, array $options = array())
|
||||
{
|
||||
// Handle the case where file is a resource.
|
||||
if (is_resource($file)) {
|
||||
return $this->parse(stream_get_contents($file), $options);
|
||||
}
|
||||
|
||||
return $this->parse(file_get_contents($file), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a HTML Document from a string.
|
||||
*
|
||||
* Take a string of HTML 5 (or earlier) and parse it into a
|
||||
* DOMDocument.
|
||||
*
|
||||
* @param string $string A html5 document as a string.
|
||||
* @param array $options Configuration options when parsing the HTML.
|
||||
*
|
||||
* @return \DOMDocument A DOM document. DOM is part of libxml, which is included with
|
||||
* almost all distribtions of PHP.
|
||||
*/
|
||||
public function loadHTML($string, array $options = array())
|
||||
{
|
||||
return $this->parse($string, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to load an HTML file.
|
||||
*
|
||||
* This is here to provide backwards compatibility with the
|
||||
* PHP DOM implementation. It simply calls load().
|
||||
*
|
||||
* @param string $file The path to the file to parse. If this is a resource, it is
|
||||
* assumed to be an open stream whose pointer is set to the first
|
||||
* byte of input.
|
||||
* @param array $options Configuration options when parsing the HTML.
|
||||
*
|
||||
* @return \DOMDocument A DOM document. These object type is defined by the libxml
|
||||
* library, and should have been included with your version of PHP.
|
||||
*/
|
||||
public function loadHTMLFile($file, array $options = array())
|
||||
{
|
||||
return $this->load($file, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a HTML fragment from a string.
|
||||
*
|
||||
* @param string $string the HTML5 fragment as a string
|
||||
* @param array $options Configuration options when parsing the HTML
|
||||
*
|
||||
* @return \DOMDocumentFragment A DOM fragment. The DOM is part of libxml, which is included with
|
||||
* almost all distributions of PHP.
|
||||
*/
|
||||
public function loadHTMLFragment($string, array $options = array())
|
||||
{
|
||||
return $this->parseFragment($string, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all errors encountered into parsing phase.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getErrors()
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true it some errors were encountered into parsing phase.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasErrors()
|
||||
{
|
||||
return count($this->errors) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an input string.
|
||||
*
|
||||
* @param string $input
|
||||
* @param array $options
|
||||
*
|
||||
* @return \DOMDocument
|
||||
*/
|
||||
public function parse($input, array $options = array())
|
||||
{
|
||||
$this->errors = array();
|
||||
$options = array_merge($this->defaultOptions, $options);
|
||||
$events = new DOMTreeBuilder(false, $options);
|
||||
$scanner = new Scanner($input, !empty($options['encoding']) ? $options['encoding'] : 'UTF-8');
|
||||
$parser = new Tokenizer($scanner, $events, !empty($options['xmlNamespaces']) ? Tokenizer::CONFORMANT_XML : Tokenizer::CONFORMANT_HTML);
|
||||
|
||||
$parser->parse();
|
||||
$this->errors = $events->getErrors();
|
||||
|
||||
return $events->document();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an input stream where the stream is a fragment.
|
||||
*
|
||||
* Lower-level loading function. This requires an input stream instead
|
||||
* of a string, file, or resource.
|
||||
*
|
||||
* @param string $input The input data to parse in the form of a string.
|
||||
* @param array $options An array of options.
|
||||
*
|
||||
* @return \DOMDocumentFragment
|
||||
*/
|
||||
public function parseFragment($input, array $options = array())
|
||||
{
|
||||
$options = array_merge($this->defaultOptions, $options);
|
||||
$events = new DOMTreeBuilder(true, $options);
|
||||
$scanner = new Scanner($input, !empty($options['encoding']) ? $options['encoding'] : 'UTF-8');
|
||||
$parser = new Tokenizer($scanner, $events, !empty($options['xmlNamespaces']) ? Tokenizer::CONFORMANT_XML : Tokenizer::CONFORMANT_HTML);
|
||||
|
||||
$parser->parse();
|
||||
$this->errors = $events->getErrors();
|
||||
|
||||
return $events->fragment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a DOM into a given file as HTML5.
|
||||
*
|
||||
* @param mixed $dom The DOM to be serialized.
|
||||
* @param string|resource $file The filename to be written or resource to write to.
|
||||
* @param array $options Configuration options when serializing the DOM. These include:
|
||||
* - encode_entities: Text written to the output is escaped by default and not all
|
||||
* entities are encoded. If this is set to true all entities will be encoded.
|
||||
* Defaults to false.
|
||||
*/
|
||||
public function save($dom, $file, $options = array())
|
||||
{
|
||||
$close = true;
|
||||
if (is_resource($file)) {
|
||||
$stream = $file;
|
||||
$close = false;
|
||||
} else {
|
||||
$stream = fopen($file, 'wb');
|
||||
}
|
||||
$options = array_merge($this->defaultOptions, $options);
|
||||
$rules = new OutputRules($stream, $options);
|
||||
$trav = new Traverser($dom, $stream, $rules, $options);
|
||||
|
||||
$trav->walk();
|
||||
/*
|
||||
* release the traverser to avoid cyclic references and allow PHP to free memory without waiting for gc_collect_cycles
|
||||
*/
|
||||
$rules->unsetTraverser();
|
||||
if ($close) {
|
||||
fclose($stream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a DOM into an HTML5 string.
|
||||
*
|
||||
* @param mixed $dom The DOM to be serialized.
|
||||
* @param array $options Configuration options when serializing the DOM. These include:
|
||||
* - encode_entities: Text written to the output is escaped by default and not all
|
||||
* entities are encoded. If this is set to true all entities will be encoded.
|
||||
* Defaults to false.
|
||||
*
|
||||
* @return string A HTML5 documented generated from the DOM.
|
||||
*/
|
||||
public function saveHTML($dom, $options = array())
|
||||
{
|
||||
$stream = fopen('php://temp', 'wb');
|
||||
$this->save($dom, $stream, array_merge($this->defaultOptions, $options));
|
||||
|
||||
$html = stream_get_contents($stream, -1, 0);
|
||||
|
||||
fclose($stream);
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,619 @@
|
|||
<?php
|
||||
/**
|
||||
* Provide general element functions.
|
||||
*/
|
||||
|
||||
namespace Masterminds\HTML5;
|
||||
|
||||
/**
|
||||
* This class provides general information about HTML5 elements,
|
||||
* including syntactic and semantic issues.
|
||||
* Parsers and serializers can
|
||||
* use this class as a reference point for information about the rules
|
||||
* of various HTML5 elements.
|
||||
*
|
||||
* @todo consider using a bitmask table lookup. There is enough overlap in
|
||||
* naming that this could significantly shrink the size and maybe make it
|
||||
* faster. See the Go teams implementation at https://code.google.com/p/go/source/browse/html/atom.
|
||||
*/
|
||||
class Elements
|
||||
{
|
||||
/**
|
||||
* Indicates an element is described in the specification.
|
||||
*/
|
||||
const KNOWN_ELEMENT = 1;
|
||||
|
||||
// From section 8.1.2: "script", "style"
|
||||
// From 8.2.5.4.7 ("in body" insertion mode): "noembed"
|
||||
// From 8.4 "style", "xmp", "iframe", "noembed", "noframes"
|
||||
/**
|
||||
* Indicates the contained text should be processed as raw text.
|
||||
*/
|
||||
const TEXT_RAW = 2;
|
||||
|
||||
// From section 8.1.2: "textarea", "title"
|
||||
/**
|
||||
* Indicates the contained text should be processed as RCDATA.
|
||||
*/
|
||||
const TEXT_RCDATA = 4;
|
||||
|
||||
/**
|
||||
* Indicates the tag cannot have content.
|
||||
*/
|
||||
const VOID_TAG = 8;
|
||||
|
||||
// "address", "article", "aside", "blockquote", "center", "details", "dialog", "dir", "div", "dl",
|
||||
// "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu",
|
||||
// "nav", "ol", "p", "section", "summary", "ul"
|
||||
// "h1", "h2", "h3", "h4", "h5", "h6"
|
||||
// "pre", "listing"
|
||||
// "form"
|
||||
// "plaintext"
|
||||
/**
|
||||
* Indicates that if a previous event is for a P tag, that element
|
||||
* should be considered closed.
|
||||
*/
|
||||
const AUTOCLOSE_P = 16;
|
||||
|
||||
/**
|
||||
* Indicates that the text inside is plaintext (pre).
|
||||
*/
|
||||
const TEXT_PLAINTEXT = 32;
|
||||
|
||||
// See https://developer.mozilla.org/en-US/docs/HTML/Block-level_elements
|
||||
/**
|
||||
* Indicates that the tag is a block.
|
||||
*/
|
||||
const BLOCK_TAG = 64;
|
||||
|
||||
/**
|
||||
* Indicates that the tag allows only inline elements as child nodes.
|
||||
*/
|
||||
const BLOCK_ONLY_INLINE = 128;
|
||||
|
||||
/**
|
||||
* The HTML5 elements as defined in http://dev.w3.org/html5/markup/elements.html.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $html5 = array(
|
||||
'a' => 1,
|
||||
'abbr' => 1,
|
||||
'address' => 65, // NORMAL | BLOCK_TAG
|
||||
'area' => 9, // NORMAL | VOID_TAG
|
||||
'article' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'aside' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'audio' => 1, // NORMAL
|
||||
'b' => 1,
|
||||
'base' => 9, // NORMAL | VOID_TAG
|
||||
'bdi' => 1,
|
||||
'bdo' => 1,
|
||||
'blockquote' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'body' => 1,
|
||||
'br' => 9, // NORMAL | VOID_TAG
|
||||
'button' => 1,
|
||||
'canvas' => 65, // NORMAL | BLOCK_TAG
|
||||
'caption' => 1,
|
||||
'cite' => 1,
|
||||
'code' => 1,
|
||||
'col' => 9, // NORMAL | VOID_TAG
|
||||
'colgroup' => 1,
|
||||
'command' => 9, // NORMAL | VOID_TAG
|
||||
// "data" => 1, // This is highly experimental and only part of the whatwg spec (not w3c). See https://developer.mozilla.org/en-US/docs/HTML/Element/data
|
||||
'datalist' => 1,
|
||||
'dd' => 65, // NORMAL | BLOCK_TAG
|
||||
'del' => 1,
|
||||
'details' => 17, // NORMAL | AUTOCLOSE_P,
|
||||
'dfn' => 1,
|
||||
'dialog' => 17, // NORMAL | AUTOCLOSE_P,
|
||||
'div' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'dl' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'dt' => 1,
|
||||
'em' => 1,
|
||||
'embed' => 9, // NORMAL | VOID_TAG
|
||||
'fieldset' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'figcaption' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'figure' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'footer' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'form' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'h1' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'h2' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'h3' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'h4' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'h5' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'h6' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'head' => 1,
|
||||
'header' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'hgroup' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'hr' => 73, // NORMAL | VOID_TAG
|
||||
'html' => 1,
|
||||
'i' => 1,
|
||||
'iframe' => 3, // NORMAL | TEXT_RAW
|
||||
'img' => 9, // NORMAL | VOID_TAG
|
||||
'input' => 9, // NORMAL | VOID_TAG
|
||||
'kbd' => 1,
|
||||
'ins' => 1,
|
||||
'keygen' => 9, // NORMAL | VOID_TAG
|
||||
'label' => 1,
|
||||
'legend' => 1,
|
||||
'li' => 1,
|
||||
'link' => 9, // NORMAL | VOID_TAG
|
||||
'map' => 1,
|
||||
'mark' => 1,
|
||||
'menu' => 17, // NORMAL | AUTOCLOSE_P,
|
||||
'meta' => 9, // NORMAL | VOID_TAG
|
||||
'meter' => 1,
|
||||
'nav' => 17, // NORMAL | AUTOCLOSE_P,
|
||||
'noscript' => 65, // NORMAL | BLOCK_TAG
|
||||
'object' => 1,
|
||||
'ol' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'optgroup' => 1,
|
||||
'option' => 1,
|
||||
'output' => 65, // NORMAL | BLOCK_TAG
|
||||
'p' => 209, // NORMAL | AUTOCLOSE_P | BLOCK_TAG | BLOCK_ONLY_INLINE
|
||||
'param' => 9, // NORMAL | VOID_TAG
|
||||
'pre' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'progress' => 1,
|
||||
'q' => 1,
|
||||
'rp' => 1,
|
||||
'rt' => 1,
|
||||
'ruby' => 1,
|
||||
's' => 1,
|
||||
'samp' => 1,
|
||||
'script' => 3, // NORMAL | TEXT_RAW
|
||||
'section' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'select' => 1,
|
||||
'small' => 1,
|
||||
'source' => 9, // NORMAL | VOID_TAG
|
||||
'span' => 1,
|
||||
'strong' => 1,
|
||||
'style' => 3, // NORMAL | TEXT_RAW
|
||||
'sub' => 1,
|
||||
'summary' => 17, // NORMAL | AUTOCLOSE_P,
|
||||
'sup' => 1,
|
||||
'table' => 65, // NORMAL | BLOCK_TAG
|
||||
'tbody' => 1,
|
||||
'td' => 1,
|
||||
'textarea' => 5, // NORMAL | TEXT_RCDATA
|
||||
'tfoot' => 65, // NORMAL | BLOCK_TAG
|
||||
'th' => 1,
|
||||
'thead' => 1,
|
||||
'time' => 1,
|
||||
'title' => 5, // NORMAL | TEXT_RCDATA
|
||||
'tr' => 1,
|
||||
'track' => 9, // NORMAL | VOID_TAG
|
||||
'u' => 1,
|
||||
'ul' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG
|
||||
'var' => 1,
|
||||
'video' => 65, // NORMAL | BLOCK_TAG
|
||||
'wbr' => 9, // NORMAL | VOID_TAG
|
||||
|
||||
// Legacy?
|
||||
'basefont' => 8, // VOID_TAG
|
||||
'bgsound' => 8, // VOID_TAG
|
||||
'noframes' => 2, // RAW_TEXT
|
||||
'frame' => 9, // NORMAL | VOID_TAG
|
||||
'frameset' => 1,
|
||||
'center' => 16,
|
||||
'dir' => 16,
|
||||
'listing' => 16, // AUTOCLOSE_P
|
||||
'plaintext' => 48, // AUTOCLOSE_P | TEXT_PLAINTEXT
|
||||
'applet' => 0,
|
||||
'marquee' => 0,
|
||||
'isindex' => 8, // VOID_TAG
|
||||
'xmp' => 20, // AUTOCLOSE_P | VOID_TAG | RAW_TEXT
|
||||
'noembed' => 2, // RAW_TEXT
|
||||
);
|
||||
|
||||
/**
|
||||
* The MathML elements.
|
||||
* See http://www.w3.org/wiki/MathML/Elements.
|
||||
*
|
||||
* In our case we are only concerned with presentation MathML and not content
|
||||
* MathML. There is a nice list of this subset at https://developer.mozilla.org/en-US/docs/MathML/Element.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $mathml = array(
|
||||
'maction' => 1,
|
||||
'maligngroup' => 1,
|
||||
'malignmark' => 1,
|
||||
'math' => 1,
|
||||
'menclose' => 1,
|
||||
'merror' => 1,
|
||||
'mfenced' => 1,
|
||||
'mfrac' => 1,
|
||||
'mglyph' => 1,
|
||||
'mi' => 1,
|
||||
'mlabeledtr' => 1,
|
||||
'mlongdiv' => 1,
|
||||
'mmultiscripts' => 1,
|
||||
'mn' => 1,
|
||||
'mo' => 1,
|
||||
'mover' => 1,
|
||||
'mpadded' => 1,
|
||||
'mphantom' => 1,
|
||||
'mroot' => 1,
|
||||
'mrow' => 1,
|
||||
'ms' => 1,
|
||||
'mscarries' => 1,
|
||||
'mscarry' => 1,
|
||||
'msgroup' => 1,
|
||||
'msline' => 1,
|
||||
'mspace' => 1,
|
||||
'msqrt' => 1,
|
||||
'msrow' => 1,
|
||||
'mstack' => 1,
|
||||
'mstyle' => 1,
|
||||
'msub' => 1,
|
||||
'msup' => 1,
|
||||
'msubsup' => 1,
|
||||
'mtable' => 1,
|
||||
'mtd' => 1,
|
||||
'mtext' => 1,
|
||||
'mtr' => 1,
|
||||
'munder' => 1,
|
||||
'munderover' => 1,
|
||||
);
|
||||
|
||||
/**
|
||||
* The svg elements.
|
||||
*
|
||||
* The Mozilla documentation has a good list at https://developer.mozilla.org/en-US/docs/SVG/Element.
|
||||
* The w3c list appears to be lacking in some areas like filter effect elements.
|
||||
* That list can be found at http://www.w3.org/wiki/SVG/Elements.
|
||||
*
|
||||
* Note, FireFox appears to do a better job rendering filter effects than chrome.
|
||||
* While they are in the spec I'm not sure how widely implemented they are.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $svg = array(
|
||||
'a' => 1,
|
||||
'altGlyph' => 1,
|
||||
'altGlyphDef' => 1,
|
||||
'altGlyphItem' => 1,
|
||||
'animate' => 1,
|
||||
'animateColor' => 1,
|
||||
'animateMotion' => 1,
|
||||
'animateTransform' => 1,
|
||||
'circle' => 1,
|
||||
'clipPath' => 1,
|
||||
'color-profile' => 1,
|
||||
'cursor' => 1,
|
||||
'defs' => 1,
|
||||
'desc' => 1,
|
||||
'ellipse' => 1,
|
||||
'feBlend' => 1,
|
||||
'feColorMatrix' => 1,
|
||||
'feComponentTransfer' => 1,
|
||||
'feComposite' => 1,
|
||||
'feConvolveMatrix' => 1,
|
||||
'feDiffuseLighting' => 1,
|
||||
'feDisplacementMap' => 1,
|
||||
'feDistantLight' => 1,
|
||||
'feFlood' => 1,
|
||||
'feFuncA' => 1,
|
||||
'feFuncB' => 1,
|
||||
'feFuncG' => 1,
|
||||
'feFuncR' => 1,
|
||||
'feGaussianBlur' => 1,
|
||||
'feImage' => 1,
|
||||
'feMerge' => 1,
|
||||
'feMergeNode' => 1,
|
||||
'feMorphology' => 1,
|
||||
'feOffset' => 1,
|
||||
'fePointLight' => 1,
|
||||
'feSpecularLighting' => 1,
|
||||
'feSpotLight' => 1,
|
||||
'feTile' => 1,
|
||||
'feTurbulence' => 1,
|
||||
'filter' => 1,
|
||||
'font' => 1,
|
||||
'font-face' => 1,
|
||||
'font-face-format' => 1,
|
||||
'font-face-name' => 1,
|
||||
'font-face-src' => 1,
|
||||
'font-face-uri' => 1,
|
||||
'foreignObject' => 1,
|
||||
'g' => 1,
|
||||
'glyph' => 1,
|
||||
'glyphRef' => 1,
|
||||
'hkern' => 1,
|
||||
'image' => 1,
|
||||
'line' => 1,
|
||||
'linearGradient' => 1,
|
||||
'marker' => 1,
|
||||
'mask' => 1,
|
||||
'metadata' => 1,
|
||||
'missing-glyph' => 1,
|
||||
'mpath' => 1,
|
||||
'path' => 1,
|
||||
'pattern' => 1,
|
||||
'polygon' => 1,
|
||||
'polyline' => 1,
|
||||
'radialGradient' => 1,
|
||||
'rect' => 1,
|
||||
'script' => 3, // NORMAL | RAW_TEXT
|
||||
'set' => 1,
|
||||
'stop' => 1,
|
||||
'style' => 3, // NORMAL | RAW_TEXT
|
||||
'svg' => 1,
|
||||
'switch' => 1,
|
||||
'symbol' => 1,
|
||||
'text' => 1,
|
||||
'textPath' => 1,
|
||||
'title' => 1,
|
||||
'tref' => 1,
|
||||
'tspan' => 1,
|
||||
'use' => 1,
|
||||
'view' => 1,
|
||||
'vkern' => 1,
|
||||
);
|
||||
|
||||
/**
|
||||
* Some attributes in SVG are case sensitive.
|
||||
*
|
||||
* This map contains key/value pairs with the key as the lowercase attribute
|
||||
* name and the value with the correct casing.
|
||||
*/
|
||||
public static $svgCaseSensitiveAttributeMap = array(
|
||||
'attributename' => 'attributeName',
|
||||
'attributetype' => 'attributeType',
|
||||
'basefrequency' => 'baseFrequency',
|
||||
'baseprofile' => 'baseProfile',
|
||||
'calcmode' => 'calcMode',
|
||||
'clippathunits' => 'clipPathUnits',
|
||||
'contentscripttype' => 'contentScriptType',
|
||||
'contentstyletype' => 'contentStyleType',
|
||||
'diffuseconstant' => 'diffuseConstant',
|
||||
'edgemode' => 'edgeMode',
|
||||
'externalresourcesrequired' => 'externalResourcesRequired',
|
||||
'filterres' => 'filterRes',
|
||||
'filterunits' => 'filterUnits',
|
||||
'glyphref' => 'glyphRef',
|
||||
'gradienttransform' => 'gradientTransform',
|
||||
'gradientunits' => 'gradientUnits',
|
||||
'kernelmatrix' => 'kernelMatrix',
|
||||
'kernelunitlength' => 'kernelUnitLength',
|
||||
'keypoints' => 'keyPoints',
|
||||
'keysplines' => 'keySplines',
|
||||
'keytimes' => 'keyTimes',
|
||||
'lengthadjust' => 'lengthAdjust',
|
||||
'limitingconeangle' => 'limitingConeAngle',
|
||||
'markerheight' => 'markerHeight',
|
||||
'markerunits' => 'markerUnits',
|
||||
'markerwidth' => 'markerWidth',
|
||||
'maskcontentunits' => 'maskContentUnits',
|
||||
'maskunits' => 'maskUnits',
|
||||
'numoctaves' => 'numOctaves',
|
||||
'pathlength' => 'pathLength',
|
||||
'patterncontentunits' => 'patternContentUnits',
|
||||
'patterntransform' => 'patternTransform',
|
||||
'patternunits' => 'patternUnits',
|
||||
'pointsatx' => 'pointsAtX',
|
||||
'pointsaty' => 'pointsAtY',
|
||||
'pointsatz' => 'pointsAtZ',
|
||||
'preservealpha' => 'preserveAlpha',
|
||||
'preserveaspectratio' => 'preserveAspectRatio',
|
||||
'primitiveunits' => 'primitiveUnits',
|
||||
'refx' => 'refX',
|
||||
'refy' => 'refY',
|
||||
'repeatcount' => 'repeatCount',
|
||||
'repeatdur' => 'repeatDur',
|
||||
'requiredextensions' => 'requiredExtensions',
|
||||
'requiredfeatures' => 'requiredFeatures',
|
||||
'specularconstant' => 'specularConstant',
|
||||
'specularexponent' => 'specularExponent',
|
||||
'spreadmethod' => 'spreadMethod',
|
||||
'startoffset' => 'startOffset',
|
||||
'stddeviation' => 'stdDeviation',
|
||||
'stitchtiles' => 'stitchTiles',
|
||||
'surfacescale' => 'surfaceScale',
|
||||
'systemlanguage' => 'systemLanguage',
|
||||
'tablevalues' => 'tableValues',
|
||||
'targetx' => 'targetX',
|
||||
'targety' => 'targetY',
|
||||
'textlength' => 'textLength',
|
||||
'viewbox' => 'viewBox',
|
||||
'viewtarget' => 'viewTarget',
|
||||
'xchannelselector' => 'xChannelSelector',
|
||||
'ychannelselector' => 'yChannelSelector',
|
||||
'zoomandpan' => 'zoomAndPan',
|
||||
);
|
||||
|
||||
/**
|
||||
* Some SVG elements are case sensitive.
|
||||
* This map contains these.
|
||||
*
|
||||
* The map contains key/value store of the name is lowercase as the keys and
|
||||
* the correct casing as the value.
|
||||
*/
|
||||
public static $svgCaseSensitiveElementMap = array(
|
||||
'altglyph' => 'altGlyph',
|
||||
'altglyphdef' => 'altGlyphDef',
|
||||
'altglyphitem' => 'altGlyphItem',
|
||||
'animatecolor' => 'animateColor',
|
||||
'animatemotion' => 'animateMotion',
|
||||
'animatetransform' => 'animateTransform',
|
||||
'clippath' => 'clipPath',
|
||||
'feblend' => 'feBlend',
|
||||
'fecolormatrix' => 'feColorMatrix',
|
||||
'fecomponenttransfer' => 'feComponentTransfer',
|
||||
'fecomposite' => 'feComposite',
|
||||
'feconvolvematrix' => 'feConvolveMatrix',
|
||||
'fediffuselighting' => 'feDiffuseLighting',
|
||||
'fedisplacementmap' => 'feDisplacementMap',
|
||||
'fedistantlight' => 'feDistantLight',
|
||||
'feflood' => 'feFlood',
|
||||
'fefunca' => 'feFuncA',
|
||||
'fefuncb' => 'feFuncB',
|
||||
'fefuncg' => 'feFuncG',
|
||||
'fefuncr' => 'feFuncR',
|
||||
'fegaussianblur' => 'feGaussianBlur',
|
||||
'feimage' => 'feImage',
|
||||
'femerge' => 'feMerge',
|
||||
'femergenode' => 'feMergeNode',
|
||||
'femorphology' => 'feMorphology',
|
||||
'feoffset' => 'feOffset',
|
||||
'fepointlight' => 'fePointLight',
|
||||
'fespecularlighting' => 'feSpecularLighting',
|
||||
'fespotlight' => 'feSpotLight',
|
||||
'fetile' => 'feTile',
|
||||
'feturbulence' => 'feTurbulence',
|
||||
'foreignobject' => 'foreignObject',
|
||||
'glyphref' => 'glyphRef',
|
||||
'lineargradient' => 'linearGradient',
|
||||
'radialgradient' => 'radialGradient',
|
||||
'textpath' => 'textPath',
|
||||
);
|
||||
|
||||
/**
|
||||
* Check whether the given element meets the given criterion.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Elements::isA('script', Elements::TEXT_RAW); // Returns true.
|
||||
*
|
||||
* Elements::isA('script', Elements::TEXT_RCDATA); // Returns false.
|
||||
*
|
||||
* @param string $name The element name.
|
||||
* @param int $mask One of the constants on this class.
|
||||
*
|
||||
* @return bool true if the element matches the mask, false otherwise.
|
||||
*/
|
||||
public static function isA($name, $mask)
|
||||
{
|
||||
return (static::element($name) & $mask) === $mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if an element is a valid html5 element.
|
||||
*
|
||||
* @param string $name The name of the element.
|
||||
*
|
||||
* @return bool true if a html5 element and false otherwise.
|
||||
*/
|
||||
public static function isHtml5Element($name)
|
||||
{
|
||||
// html5 element names are case insensitive. Forcing lowercase for the check.
|
||||
// Do we need this check or will all data passed here already be lowercase?
|
||||
return isset(static::$html5[strtolower($name)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if an element name is a valid MathML presentation element.
|
||||
*
|
||||
* @param string $name The name of the element.
|
||||
*
|
||||
* @return bool true if a MathML name and false otherwise.
|
||||
*/
|
||||
public static function isMathMLElement($name)
|
||||
{
|
||||
// MathML is case-sensitive unlike html5 elements.
|
||||
return isset(static::$mathml[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if an element is a valid SVG element.
|
||||
*
|
||||
* @param string $name The name of the element.
|
||||
*
|
||||
* @return bool true if a SVG element and false otherise.
|
||||
*/
|
||||
public static function isSvgElement($name)
|
||||
{
|
||||
// SVG is case-sensitive unlike html5 elements.
|
||||
return isset(static::$svg[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is an element name valid in an html5 document.
|
||||
* This includes html5 elements along with other allowed embedded content
|
||||
* such as svg and mathml.
|
||||
*
|
||||
* @param string $name The name of the element.
|
||||
*
|
||||
* @return bool true if valid and false otherwise.
|
||||
*/
|
||||
public static function isElement($name)
|
||||
{
|
||||
return static::isHtml5Element($name) || static::isMathMLElement($name) || static::isSvgElement($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element mask for the given element name.
|
||||
*
|
||||
* @param string $name The name of the element.
|
||||
*
|
||||
* @return int the element mask.
|
||||
*/
|
||||
public static function element($name)
|
||||
{
|
||||
if (isset(static::$html5[$name])) {
|
||||
return static::$html5[$name];
|
||||
}
|
||||
if (isset(static::$svg[$name])) {
|
||||
return static::$svg[$name];
|
||||
}
|
||||
if (isset(static::$mathml[$name])) {
|
||||
return static::$mathml[$name];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a SVG element name to its proper case and form.
|
||||
*
|
||||
* @param string $name The name of the element.
|
||||
*
|
||||
* @return string the normalized form of the element name.
|
||||
*/
|
||||
public static function normalizeSvgElement($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
if (isset(static::$svgCaseSensitiveElementMap[$name])) {
|
||||
$name = static::$svgCaseSensitiveElementMap[$name];
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a SVG attribute name to its proper case and form.
|
||||
*
|
||||
* @param string $name The name of the attribute.
|
||||
*
|
||||
* @return string The normalized form of the attribute name.
|
||||
*/
|
||||
public static function normalizeSvgAttribute($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
if (isset(static::$svgCaseSensitiveAttributeMap[$name])) {
|
||||
$name = static::$svgCaseSensitiveAttributeMap[$name];
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a MathML attribute name to its proper case and form.
|
||||
* Note, all MathML element names are lowercase.
|
||||
*
|
||||
* @param string $name The name of the attribute.
|
||||
*
|
||||
* @return string The normalized form of the attribute name.
|
||||
*/
|
||||
public static function normalizeMathMlAttribute($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
|
||||
// Only one attribute has a mixed case form for MathML.
|
||||
if ('definitionurl' === $name) {
|
||||
$name = 'definitionURL';
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Masterminds\HTML5;
|
||||
|
||||
/**
|
||||
* The base exception for the HTML5 project.
|
||||
*/
|
||||
class Exception extends \Exception
|
||||
{
|
||||
}
|
41
plugins/af_readability/vendor/masterminds/html5/src/HTML5/InstructionProcessor.php
vendored
Normal file
41
plugins/af_readability/vendor/masterminds/html5/src/HTML5/InstructionProcessor.php
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
/**
|
||||
* A handler for processor instructions.
|
||||
*/
|
||||
|
||||
namespace Masterminds\HTML5;
|
||||
|
||||
/**
|
||||
* Provide an processor to handle embedded instructions.
|
||||
*
|
||||
* XML defines a mechanism for inserting instructions (like PHP) into a
|
||||
* document. These are called "Processor Instructions." The HTML5 parser
|
||||
* provides an opportunity to handle these processor instructions during
|
||||
* the tree-building phase (before the DOM is constructed), which makes
|
||||
* it possible to alter the document as it is being created.
|
||||
*
|
||||
* One could, for example, use this mechanism to execute well-formed PHP
|
||||
* code embedded inside of an HTML5 document.
|
||||
*/
|
||||
interface InstructionProcessor
|
||||
{
|
||||
/**
|
||||
* Process an individual processing instruction.
|
||||
*
|
||||
* The process() function is responsible for doing the following:
|
||||
* - Determining whether $name is an instruction type it can handle.
|
||||
* - Determining what to do with the data passed in.
|
||||
* - Making any subsequent modifications to the DOM by modifying the
|
||||
* DOMElement or its attached DOM tree.
|
||||
*
|
||||
* @param \DOMElement $element The parent element for the current processing instruction.
|
||||
* @param string $name The instruction's name. E.g. `<?php` has the name `php`.
|
||||
* @param string $data All of the data between the opening and closing PI marks.
|
||||
*
|
||||
* @return \DOMElement The element that should be considered "Current". This may just be
|
||||
* the element passed in, but if the processor added more elements,
|
||||
* it may choose to reset the current element to one of the elements
|
||||
* it created. (When in doubt, return the element passed in.)
|
||||
*/
|
||||
public function process(\DOMElement $element, $name, $data);
|
||||
}
|
61
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/CharacterReference.php
vendored
Normal file
61
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/CharacterReference.php
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace Masterminds\HTML5\Parser;
|
||||
|
||||
use Masterminds\HTML5\Entities;
|
||||
|
||||
/**
|
||||
* Manage entity references.
|
||||
*
|
||||
* This is a simple resolver for HTML5 character reference entitites. See Entities for the list of supported entities.
|
||||
*/
|
||||
class CharacterReference
|
||||
{
|
||||
protected static $numeric_mask = array(
|
||||
0x0,
|
||||
0x2FFFF,
|
||||
0,
|
||||
0xFFFF,
|
||||
);
|
||||
|
||||
/**
|
||||
* Given a name (e.g. 'amp'), lookup the UTF-8 character ('&').
|
||||
*
|
||||
* @param string $name The name to look up.
|
||||
*
|
||||
* @return string The character sequence. In UTF-8 this may be more than one byte.
|
||||
*/
|
||||
public static function lookupName($name)
|
||||
{
|
||||
// Do we really want to return NULL here? or FFFD
|
||||
return isset(Entities::$byName[$name]) ? Entities::$byName[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a decimal number, return the UTF-8 character.
|
||||
*
|
||||
* @param $int
|
||||
*
|
||||
* @return false|string|string[]|null
|
||||
*/
|
||||
public static function lookupDecimal($int)
|
||||
{
|
||||
$entity = '&#' . $int . ';';
|
||||
|
||||
// UNTESTED: This may fail on some planes. Couldn't find full documentation
|
||||
// on the value of the mask array.
|
||||
return mb_decode_numericentity($entity, static::$numeric_mask, 'utf-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a hexidecimal number, return the UTF-8 character.
|
||||
*
|
||||
* @param $hexdec
|
||||
*
|
||||
* @return false|string|string[]|null
|
||||
*/
|
||||
public static function lookupHex($hexdec)
|
||||
{
|
||||
return static::lookupDecimal(hexdec($hexdec));
|
||||
}
|
||||
}
|
705
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/DOMTreeBuilder.php
vendored
Normal file
705
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/DOMTreeBuilder.php
vendored
Normal file
|
@ -0,0 +1,705 @@
|
|||
<?php
|
||||
|
||||
namespace Masterminds\HTML5\Parser;
|
||||
|
||||
use Masterminds\HTML5\Elements;
|
||||
use Masterminds\HTML5\InstructionProcessor;
|
||||
|
||||
/**
|
||||
* Create an HTML5 DOM tree from events.
|
||||
*
|
||||
* This attempts to create a DOM from events emitted by a parser. This
|
||||
* attempts (but does not guarantee) to up-convert older HTML documents
|
||||
* to HTML5. It does this by applying HTML5's rules, but it will not
|
||||
* change the architecture of the document itself.
|
||||
*
|
||||
* Many of the error correction and quirks features suggested in the specification
|
||||
* are implemented herein; however, not all of them are. Since we do not
|
||||
* assume a graphical user agent, no presentation-specific logic is conducted
|
||||
* during tree building.
|
||||
*
|
||||
* FIXME: The present tree builder does not exactly follow the state machine rules
|
||||
* for insert modes as outlined in the HTML5 spec. The processor needs to be
|
||||
* re-written to accomodate this. See, for example, the Go language HTML5
|
||||
* parser.
|
||||
*/
|
||||
class DOMTreeBuilder implements EventHandler
|
||||
{
|
||||
/**
|
||||
* Defined in http://www.w3.org/TR/html51/infrastructure.html#html-namespace-0.
|
||||
*/
|
||||
const NAMESPACE_HTML = 'http://www.w3.org/1999/xhtml';
|
||||
|
||||
const NAMESPACE_MATHML = 'http://www.w3.org/1998/Math/MathML';
|
||||
|
||||
const NAMESPACE_SVG = 'http://www.w3.org/2000/svg';
|
||||
|
||||
const NAMESPACE_XLINK = 'http://www.w3.org/1999/xlink';
|
||||
|
||||
const NAMESPACE_XML = 'http://www.w3.org/XML/1998/namespace';
|
||||
|
||||
const NAMESPACE_XMLNS = 'http://www.w3.org/2000/xmlns/';
|
||||
|
||||
const OPT_DISABLE_HTML_NS = 'disable_html_ns';
|
||||
|
||||
const OPT_TARGET_DOC = 'target_document';
|
||||
|
||||
const OPT_IMPLICIT_NS = 'implicit_namespaces';
|
||||
|
||||
/**
|
||||
* Holds the HTML5 element names that causes a namespace switch.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $nsRoots = array(
|
||||
'html' => self::NAMESPACE_HTML,
|
||||
'svg' => self::NAMESPACE_SVG,
|
||||
'math' => self::NAMESPACE_MATHML,
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds the always available namespaces (which does not require the XMLNS declaration).
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $implicitNamespaces = array(
|
||||
'xml' => self::NAMESPACE_XML,
|
||||
'xmlns' => self::NAMESPACE_XMLNS,
|
||||
'xlink' => self::NAMESPACE_XLINK,
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds a stack of currently active namespaces.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $nsStack = array();
|
||||
|
||||
/**
|
||||
* Holds the number of namespaces declared by a node.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $pushes = array();
|
||||
|
||||
/**
|
||||
* Defined in 8.2.5.
|
||||
*/
|
||||
const IM_INITIAL = 0;
|
||||
|
||||
const IM_BEFORE_HTML = 1;
|
||||
|
||||
const IM_BEFORE_HEAD = 2;
|
||||
|
||||
const IM_IN_HEAD = 3;
|
||||
|
||||
const IM_IN_HEAD_NOSCRIPT = 4;
|
||||
|
||||
const IM_AFTER_HEAD = 5;
|
||||
|
||||
const IM_IN_BODY = 6;
|
||||
|
||||
const IM_TEXT = 7;
|
||||
|
||||
const IM_IN_TABLE = 8;
|
||||
|
||||
const IM_IN_TABLE_TEXT = 9;
|
||||
|
||||
const IM_IN_CAPTION = 10;
|
||||
|
||||
const IM_IN_COLUMN_GROUP = 11;
|
||||
|
||||
const IM_IN_TABLE_BODY = 12;
|
||||
|
||||
const IM_IN_ROW = 13;
|
||||
|
||||
const IM_IN_CELL = 14;
|
||||
|
||||
const IM_IN_SELECT = 15;
|
||||
|
||||
const IM_IN_SELECT_IN_TABLE = 16;
|
||||
|
||||
const IM_AFTER_BODY = 17;
|
||||
|
||||
const IM_IN_FRAMESET = 18;
|
||||
|
||||
const IM_AFTER_FRAMESET = 19;
|
||||
|
||||
const IM_AFTER_AFTER_BODY = 20;
|
||||
|
||||
const IM_AFTER_AFTER_FRAMESET = 21;
|
||||
|
||||
const IM_IN_SVG = 22;
|
||||
|
||||
const IM_IN_MATHML = 23;
|
||||
|
||||
protected $options = array();
|
||||
|
||||
protected $stack = array();
|
||||
|
||||
protected $current; // Pointer in the tag hierarchy.
|
||||
protected $rules;
|
||||
protected $doc;
|
||||
|
||||
protected $frag;
|
||||
|
||||
protected $processor;
|
||||
|
||||
protected $insertMode = 0;
|
||||
|
||||
/**
|
||||
* Track if we are in an element that allows only inline child nodes.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $onlyInline;
|
||||
|
||||
/**
|
||||
* Quirks mode is enabled by default.
|
||||
* Any document that is missing the DT will be considered to be in quirks mode.
|
||||
*/
|
||||
protected $quirks = true;
|
||||
|
||||
protected $errors = array();
|
||||
|
||||
public function __construct($isFragment = false, array $options = array())
|
||||
{
|
||||
$this->options = $options;
|
||||
|
||||
if (isset($options[self::OPT_TARGET_DOC])) {
|
||||
$this->doc = $options[self::OPT_TARGET_DOC];
|
||||
} else {
|
||||
$impl = new \DOMImplementation();
|
||||
// XXX:
|
||||
// Create the doctype. For now, we are always creating HTML5
|
||||
// documents, and attempting to up-convert any older DTDs to HTML5.
|
||||
$dt = $impl->createDocumentType('html');
|
||||
// $this->doc = \DOMImplementation::createDocument(NULL, 'html', $dt);
|
||||
$this->doc = $impl->createDocument(null, '', $dt);
|
||||
$this->doc->encoding = !empty($options['encoding']) ? $options['encoding'] : 'UTF-8';
|
||||
}
|
||||
|
||||
$this->errors = array();
|
||||
|
||||
$this->current = $this->doc; // ->documentElement;
|
||||
|
||||
// Create a rules engine for tags.
|
||||
$this->rules = new TreeBuildingRules();
|
||||
|
||||
$implicitNS = array();
|
||||
if (isset($this->options[self::OPT_IMPLICIT_NS])) {
|
||||
$implicitNS = $this->options[self::OPT_IMPLICIT_NS];
|
||||
} elseif (isset($this->options['implicitNamespaces'])) {
|
||||
$implicitNS = $this->options['implicitNamespaces'];
|
||||
}
|
||||
|
||||
// Fill $nsStack with the defalut HTML5 namespaces, plus the "implicitNamespaces" array taken form $options
|
||||
array_unshift($this->nsStack, $implicitNS + array('' => self::NAMESPACE_HTML) + $this->implicitNamespaces);
|
||||
|
||||
if ($isFragment) {
|
||||
$this->insertMode = static::IM_IN_BODY;
|
||||
$this->frag = $this->doc->createDocumentFragment();
|
||||
$this->current = $this->frag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the document.
|
||||
*/
|
||||
public function document()
|
||||
{
|
||||
return $this->doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DOM fragment for the body.
|
||||
*
|
||||
* This returns a DOMNodeList because a fragment may have zero or more
|
||||
* DOMNodes at its root.
|
||||
*
|
||||
* @see http://www.w3.org/TR/2012/CR-html5-20121217/syntax.html#concept-frag-parse-context
|
||||
*
|
||||
* @return \DOMDocumentFragment
|
||||
*/
|
||||
public function fragment()
|
||||
{
|
||||
return $this->frag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an instruction processor.
|
||||
*
|
||||
* This is used for handling Processor Instructions as they are
|
||||
* inserted. If omitted, PI's are inserted directly into the DOM tree.
|
||||
*
|
||||
* @param InstructionProcessor $proc
|
||||
*/
|
||||
public function setInstructionProcessor(InstructionProcessor $proc)
|
||||
{
|
||||
$this->processor = $proc;
|
||||
}
|
||||
|
||||
public function doctype($name, $idType = 0, $id = null, $quirks = false)
|
||||
{
|
||||
// This is used solely for setting quirks mode. Currently we don't
|
||||
// try to preserve the inbound DT. We convert it to HTML5.
|
||||
$this->quirks = $quirks;
|
||||
|
||||
if ($this->insertMode > static::IM_INITIAL) {
|
||||
$this->parseError('Illegal placement of DOCTYPE tag. Ignoring: ' . $name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->insertMode = static::IM_BEFORE_HTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the start tag.
|
||||
*
|
||||
* @todo - XMLNS namespace handling (we need to parse, even if it's not valid)
|
||||
* - XLink, MathML and SVG namespace handling
|
||||
* - Omission rules: 8.1.2.4 Optional tags
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $attributes
|
||||
* @param bool $selfClosing
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function startTag($name, $attributes = array(), $selfClosing = false)
|
||||
{
|
||||
$lname = $this->normalizeTagName($name);
|
||||
|
||||
// Make sure we have an html element.
|
||||
if (!$this->doc->documentElement && 'html' !== $name && !$this->frag) {
|
||||
$this->startTag('html');
|
||||
}
|
||||
|
||||
// Set quirks mode if we're at IM_INITIAL with no doctype.
|
||||
if ($this->insertMode === static::IM_INITIAL) {
|
||||
$this->quirks = true;
|
||||
$this->parseError('No DOCTYPE specified.');
|
||||
}
|
||||
|
||||
// SPECIAL TAG HANDLING:
|
||||
// Spec says do this, and "don't ask."
|
||||
// find the spec where this is defined... looks problematic
|
||||
if ('image' === $name && !($this->insertMode === static::IM_IN_SVG || $this->insertMode === static::IM_IN_MATHML)) {
|
||||
$name = 'img';
|
||||
}
|
||||
|
||||
// Autoclose p tags where appropriate.
|
||||
if ($this->insertMode >= static::IM_IN_BODY && Elements::isA($name, Elements::AUTOCLOSE_P)) {
|
||||
$this->autoclose('p');
|
||||
}
|
||||
|
||||
// Set insert mode:
|
||||
switch ($name) {
|
||||
case 'html':
|
||||
$this->insertMode = static::IM_BEFORE_HEAD;
|
||||
break;
|
||||
case 'head':
|
||||
if ($this->insertMode > static::IM_BEFORE_HEAD) {
|
||||
$this->parseError('Unexpected head tag outside of head context.');
|
||||
} else {
|
||||
$this->insertMode = static::IM_IN_HEAD;
|
||||
}
|
||||
break;
|
||||
case 'body':
|
||||
$this->insertMode = static::IM_IN_BODY;
|
||||
break;
|
||||
case 'svg':
|
||||
$this->insertMode = static::IM_IN_SVG;
|
||||
break;
|
||||
case 'math':
|
||||
$this->insertMode = static::IM_IN_MATHML;
|
||||
break;
|
||||
case 'noscript':
|
||||
if ($this->insertMode === static::IM_IN_HEAD) {
|
||||
$this->insertMode = static::IM_IN_HEAD_NOSCRIPT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Special case handling for SVG.
|
||||
if ($this->insertMode === static::IM_IN_SVG) {
|
||||
$lname = Elements::normalizeSvgElement($lname);
|
||||
}
|
||||
|
||||
$pushes = 0;
|
||||
// when we found a tag thats appears inside $nsRoots, we have to switch the defalut namespace
|
||||
if (isset($this->nsRoots[$lname]) && $this->nsStack[0][''] !== $this->nsRoots[$lname]) {
|
||||
array_unshift($this->nsStack, array(
|
||||
'' => $this->nsRoots[$lname],
|
||||
) + $this->nsStack[0]);
|
||||
++$pushes;
|
||||
}
|
||||
$needsWorkaround = false;
|
||||
if (isset($this->options['xmlNamespaces']) && $this->options['xmlNamespaces']) {
|
||||
// when xmlNamespaces is true a and we found a 'xmlns' or 'xmlns:*' attribute, we should add a new item to the $nsStack
|
||||
foreach ($attributes as $aName => $aVal) {
|
||||
if ('xmlns' === $aName) {
|
||||
$needsWorkaround = $aVal;
|
||||
array_unshift($this->nsStack, array(
|
||||
'' => $aVal,
|
||||
) + $this->nsStack[0]);
|
||||
++$pushes;
|
||||
} elseif ('xmlns' === (($pos = strpos($aName, ':')) ? substr($aName, 0, $pos) : '')) {
|
||||
array_unshift($this->nsStack, array(
|
||||
substr($aName, $pos + 1) => $aVal,
|
||||
) + $this->nsStack[0]);
|
||||
++$pushes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->onlyInline && Elements::isA($lname, Elements::BLOCK_TAG)) {
|
||||
$this->autoclose($this->onlyInline);
|
||||
$this->onlyInline = null;
|
||||
}
|
||||
|
||||
try {
|
||||
$prefix = ($pos = strpos($lname, ':')) ? substr($lname, 0, $pos) : '';
|
||||
|
||||
if (false !== $needsWorkaround) {
|
||||
$xml = "<$lname xmlns=\"$needsWorkaround\" " . (strlen($prefix) && isset($this->nsStack[0][$prefix]) ? ("xmlns:$prefix=\"" . $this->nsStack[0][$prefix] . '"') : '') . '/>';
|
||||
|
||||
$frag = new \DOMDocument('1.0', 'UTF-8');
|
||||
$frag->loadXML($xml);
|
||||
|
||||
$ele = $this->doc->importNode($frag->documentElement, true);
|
||||
} else {
|
||||
if (!isset($this->nsStack[0][$prefix]) || ('' === $prefix && isset($this->options[self::OPT_DISABLE_HTML_NS]) && $this->options[self::OPT_DISABLE_HTML_NS])) {
|
||||
$ele = $this->doc->createElement($lname);
|
||||
} else {
|
||||
$ele = $this->doc->createElementNS($this->nsStack[0][$prefix], $lname);
|
||||
}
|
||||
}
|
||||
} catch (\DOMException $e) {
|
||||
$this->parseError("Illegal tag name: <$lname>. Replaced with <invalid>.");
|
||||
$ele = $this->doc->createElement('invalid');
|
||||
}
|
||||
|
||||
if (Elements::isA($lname, Elements::BLOCK_ONLY_INLINE)) {
|
||||
$this->onlyInline = $lname;
|
||||
}
|
||||
|
||||
// When we add some namespacess, we have to track them. Later, when "endElement" is invoked, we have to remove them.
|
||||
// When we are on a void tag, we do not need to care about namesapce nesting.
|
||||
if ($pushes > 0 && !Elements::isA($name, Elements::VOID_TAG)) {
|
||||
// PHP tends to free the memory used by DOM,
|
||||
// to avoid spl_object_hash collisions whe have to avoid garbage collection of $ele storing it into $pushes
|
||||
// see https://bugs.php.net/bug.php?id=67459
|
||||
$this->pushes[spl_object_hash($ele)] = array($pushes, $ele);
|
||||
}
|
||||
|
||||
foreach ($attributes as $aName => $aVal) {
|
||||
// xmlns attributes can't be set
|
||||
if ('xmlns' === $aName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->insertMode === static::IM_IN_SVG) {
|
||||
$aName = Elements::normalizeSvgAttribute($aName);
|
||||
} elseif ($this->insertMode === static::IM_IN_MATHML) {
|
||||
$aName = Elements::normalizeMathMlAttribute($aName);
|
||||
}
|
||||
|
||||
$aVal = (string) $aVal;
|
||||
|
||||
try {
|
||||
$prefix = ($pos = strpos($aName, ':')) ? substr($aName, 0, $pos) : false;
|
||||
|
||||
if ('xmlns' === $prefix) {
|
||||
$ele->setAttributeNS(self::NAMESPACE_XMLNS, $aName, $aVal);
|
||||
} elseif (false !== $prefix && isset($this->nsStack[0][$prefix])) {
|
||||
$ele->setAttributeNS($this->nsStack[0][$prefix], $aName, $aVal);
|
||||
} else {
|
||||
$ele->setAttribute($aName, $aVal);
|
||||
}
|
||||
} catch (\DOMException $e) {
|
||||
$this->parseError("Illegal attribute name for tag $name. Ignoring: $aName");
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is necessary on a non-DTD schema, like HTML5.
|
||||
if ('id' === $aName) {
|
||||
$ele->setIdAttribute('id', true);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->frag !== $this->current && $this->rules->hasRules($name)) {
|
||||
// Some elements have special processing rules. Handle those separately.
|
||||
$this->current = $this->rules->evaluate($ele, $this->current);
|
||||
} else {
|
||||
// Otherwise, it's a standard element.
|
||||
$this->current->appendChild($ele);
|
||||
|
||||
if (!Elements::isA($name, Elements::VOID_TAG)) {
|
||||
$this->current = $ele;
|
||||
}
|
||||
|
||||
// Self-closing tags should only be respected on foreign elements
|
||||
// (and are implied on void elements)
|
||||
// See: https://www.w3.org/TR/html5/syntax.html#start-tags
|
||||
if (Elements::isHtml5Element($name)) {
|
||||
$selfClosing = false;
|
||||
}
|
||||
}
|
||||
|
||||
// This is sort of a last-ditch attempt to correct for cases where no head/body
|
||||
// elements are provided.
|
||||
if ($this->insertMode <= static::IM_BEFORE_HEAD && 'head' !== $name && 'html' !== $name) {
|
||||
$this->insertMode = static::IM_IN_BODY;
|
||||
}
|
||||
|
||||
// When we are on a void tag, we do not need to care about namesapce nesting,
|
||||
// but we have to remove the namespaces pushed to $nsStack.
|
||||
if ($pushes > 0 && Elements::isA($name, Elements::VOID_TAG)) {
|
||||
// remove the namespaced definded by current node
|
||||
for ($i = 0; $i < $pushes; ++$i) {
|
||||
array_shift($this->nsStack);
|
||||
}
|
||||
}
|
||||
|
||||
if ($selfClosing) {
|
||||
$this->endTag($name);
|
||||
}
|
||||
|
||||
// Return the element mask, which the tokenizer can then use to set
|
||||
// various processing rules.
|
||||
return Elements::element($name);
|
||||
}
|
||||
|
||||
public function endTag($name)
|
||||
{
|
||||
$lname = $this->normalizeTagName($name);
|
||||
|
||||
// Special case within 12.2.6.4.7: An end tag whose tag name is "br" should be treated as an opening tag
|
||||
if ('br' === $name) {
|
||||
$this->parseError('Closing tag encountered for void element br.');
|
||||
|
||||
$this->startTag('br');
|
||||
}
|
||||
// Ignore closing tags for other unary elements.
|
||||
elseif (Elements::isA($name, Elements::VOID_TAG)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->insertMode <= static::IM_BEFORE_HTML) {
|
||||
// 8.2.5.4.2
|
||||
if (in_array($name, array(
|
||||
'html',
|
||||
'br',
|
||||
'head',
|
||||
'title',
|
||||
))) {
|
||||
$this->startTag('html');
|
||||
$this->endTag($name);
|
||||
$this->insertMode = static::IM_BEFORE_HEAD;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore the tag.
|
||||
$this->parseError('Illegal closing tag at global scope.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Special case handling for SVG.
|
||||
if ($this->insertMode === static::IM_IN_SVG) {
|
||||
$lname = Elements::normalizeSvgElement($lname);
|
||||
}
|
||||
|
||||
$cid = spl_object_hash($this->current);
|
||||
|
||||
// XXX: HTML has no parent. What do we do, though,
|
||||
// if this element appears in the wrong place?
|
||||
if ('html' === $lname) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove the namespaced definded by current node
|
||||
if (isset($this->pushes[$cid])) {
|
||||
for ($i = 0; $i < $this->pushes[$cid][0]; ++$i) {
|
||||
array_shift($this->nsStack);
|
||||
}
|
||||
unset($this->pushes[$cid]);
|
||||
}
|
||||
|
||||
if (!$this->autoclose($lname)) {
|
||||
$this->parseError('Could not find closing tag for ' . $lname);
|
||||
}
|
||||
|
||||
switch ($lname) {
|
||||
case 'head':
|
||||
$this->insertMode = static::IM_AFTER_HEAD;
|
||||
break;
|
||||
case 'body':
|
||||
$this->insertMode = static::IM_AFTER_BODY;
|
||||
break;
|
||||
case 'svg':
|
||||
case 'mathml':
|
||||
$this->insertMode = static::IM_IN_BODY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function comment($cdata)
|
||||
{
|
||||
// TODO: Need to handle case where comment appears outside of the HTML tag.
|
||||
$node = $this->doc->createComment($cdata);
|
||||
$this->current->appendChild($node);
|
||||
}
|
||||
|
||||
public function text($data)
|
||||
{
|
||||
// XXX: Hmmm.... should we really be this strict?
|
||||
if ($this->insertMode < static::IM_IN_HEAD) {
|
||||
// Per '8.2.5.4.3 The "before head" insertion mode' the characters
|
||||
// " \t\n\r\f" should be ignored but no mention of a parse error. This is
|
||||
// practical as most documents contain these characters. Other text is not
|
||||
// expected here so recording a parse error is necessary.
|
||||
$dataTmp = trim($data, " \t\n\r\f");
|
||||
if (!empty($dataTmp)) {
|
||||
// fprintf(STDOUT, "Unexpected insert mode: %d", $this->insertMode);
|
||||
$this->parseError('Unexpected text. Ignoring: ' . $dataTmp);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
// fprintf(STDOUT, "Appending text %s.", $data);
|
||||
$node = $this->doc->createTextNode($data);
|
||||
$this->current->appendChild($node);
|
||||
}
|
||||
|
||||
public function eof()
|
||||
{
|
||||
// If the $current isn't the $root, do we need to do anything?
|
||||
}
|
||||
|
||||
public function parseError($msg, $line = 0, $col = 0)
|
||||
{
|
||||
$this->errors[] = sprintf('Line %d, Col %d: %s', $line, $col, $msg);
|
||||
}
|
||||
|
||||
public function getErrors()
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
public function cdata($data)
|
||||
{
|
||||
$node = $this->doc->createCDATASection($data);
|
||||
$this->current->appendChild($node);
|
||||
}
|
||||
|
||||
public function processingInstruction($name, $data = null)
|
||||
{
|
||||
// XXX: Ignore initial XML declaration, per the spec.
|
||||
if ($this->insertMode === static::IM_INITIAL && 'xml' === strtolower($name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Important: The processor may modify the current DOM tree however it sees fit.
|
||||
if ($this->processor instanceof InstructionProcessor) {
|
||||
$res = $this->processor->process($this->current, $name, $data);
|
||||
if (!empty($res)) {
|
||||
$this->current = $res;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, this is just a dumb PI element.
|
||||
$node = $this->doc->createProcessingInstruction($name, $data);
|
||||
|
||||
$this->current->appendChild($node);
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// UTILITIES
|
||||
// ==========================================================================
|
||||
|
||||
/**
|
||||
* Apply normalization rules to a tag name.
|
||||
* See sections 2.9 and 8.1.2.
|
||||
*
|
||||
* @param string $tagName
|
||||
*
|
||||
* @return string The normalized tag name.
|
||||
*/
|
||||
protected function normalizeTagName($tagName)
|
||||
{
|
||||
/*
|
||||
* Section 2.9 suggests that we should not do this. if (strpos($name, ':') !== false) { // We know from the grammar that there must be at least one other // char besides :, since : is not a legal tag start. $parts = explode(':', $name); return array_pop($parts); }
|
||||
*/
|
||||
return $tagName;
|
||||
}
|
||||
|
||||
protected function quirksTreeResolver($name)
|
||||
{
|
||||
throw new \Exception('Not implemented.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically climb the tree and close the closest node with the matching $tag.
|
||||
*
|
||||
* @param string $tagName
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function autoclose($tagName)
|
||||
{
|
||||
$working = $this->current;
|
||||
do {
|
||||
if (XML_ELEMENT_NODE !== $working->nodeType) {
|
||||
return false;
|
||||
}
|
||||
if ($working->tagName === $tagName) {
|
||||
$this->current = $working->parentNode;
|
||||
|
||||
return true;
|
||||
}
|
||||
} while ($working = $working->parentNode);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given tagname is an ancestor of the present candidate.
|
||||
*
|
||||
* If $this->current or anything above $this->current matches the given tag
|
||||
* name, this returns true.
|
||||
*
|
||||
* @param string $tagName
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isAncestor($tagName)
|
||||
{
|
||||
$candidate = $this->current;
|
||||
while (XML_ELEMENT_NODE === $candidate->nodeType) {
|
||||
if ($candidate->tagName === $tagName) {
|
||||
return true;
|
||||
}
|
||||
$candidate = $candidate->parentNode;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the immediate parent element is of the given tagname.
|
||||
*
|
||||
* @param string $tagName
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isParent($tagName)
|
||||
{
|
||||
return $this->current->tagName === $tagName;
|
||||
}
|
||||
}
|
114
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/EventHandler.php
vendored
Normal file
114
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/EventHandler.php
vendored
Normal file
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
namespace Masterminds\HTML5\Parser;
|
||||
|
||||
/**
|
||||
* Standard events for HTML5.
|
||||
*
|
||||
* This is roughly analogous to a SAX2 or expat-style interface.
|
||||
* However, it is tuned specifically for HTML5, according to section 8
|
||||
* of the HTML5 specification.
|
||||
*
|
||||
* An event handler receives parser events. For a concrete
|
||||
* implementation, see DOMTreeBuilder.
|
||||
*
|
||||
* Quirks support in the parser is limited to close-in syntax (malformed
|
||||
* tags or attributes). Higher order syntax and semantic issues with a
|
||||
* document (e.g. mismatched tags, illegal nesting, etc.) are the
|
||||
* responsibility of the event handler implementation.
|
||||
*
|
||||
* See HTML5 spec section 8.2.4
|
||||
*/
|
||||
interface EventHandler
|
||||
{
|
||||
const DOCTYPE_NONE = 0;
|
||||
|
||||
const DOCTYPE_PUBLIC = 1;
|
||||
|
||||
const DOCTYPE_SYSTEM = 2;
|
||||
|
||||
/**
|
||||
* A doctype declaration.
|
||||
*
|
||||
* @param string $name The name of the root element.
|
||||
* @param int $idType One of DOCTYPE_NONE, DOCTYPE_PUBLIC, or DOCTYPE_SYSTEM
|
||||
* @param string $id The identifier. For DOCTYPE_PUBLIC, this is the public ID. If DOCTYPE_SYSTEM,
|
||||
* then this is a system ID.
|
||||
* @param bool $quirks Indicates whether the builder should enter quirks mode.
|
||||
*/
|
||||
public function doctype($name, $idType = 0, $id = null, $quirks = false);
|
||||
|
||||
/**
|
||||
* A start tag.
|
||||
*
|
||||
* IMPORTANT: The parser watches the return value of this event. If this returns
|
||||
* an integer, the parser will switch TEXTMODE patters according to the int.
|
||||
*
|
||||
* This is how the Tree Builder can tell the Tokenizer when a certain tag should
|
||||
* cause the parser to go into RAW text mode.
|
||||
*
|
||||
* The HTML5 standard requires that the builder is the one that initiates this
|
||||
* step, and this is the only way short of a circular reference that we can
|
||||
* do that.
|
||||
*
|
||||
* Example: if a startTag even for a `script` name is fired, and the startTag()
|
||||
* implementation returns Tokenizer::TEXTMODE_RAW, then the tokenizer will
|
||||
* switch into RAW text mode and consume data until it reaches a closing
|
||||
* `script` tag.
|
||||
*
|
||||
* The textmode is automatically reset to Tokenizer::TEXTMODE_NORMAL when the
|
||||
* closing tag is encounter. **This behavior may change.**
|
||||
*
|
||||
* @param string $name The tag name.
|
||||
* @param array $attributes An array with all of the tag's attributes.
|
||||
* @param bool $selfClosing An indicator of whether or not this tag is self-closing (<foo/>).
|
||||
*
|
||||
* @return int one of the Tokenizer::TEXTMODE_* constants
|
||||
*/
|
||||
public function startTag($name, $attributes = array(), $selfClosing = false);
|
||||
|
||||
/**
|
||||
* An end-tag.
|
||||
*/
|
||||
public function endTag($name);
|
||||
|
||||
/**
|
||||
* A comment section (unparsed character data).
|
||||
*/
|
||||
public function comment($cdata);
|
||||
|
||||
/**
|
||||
* A unit of parsed character data.
|
||||
*
|
||||
* Entities in this text are *already decoded*.
|
||||
*/
|
||||
public function text($cdata);
|
||||
|
||||
/**
|
||||
* Indicates that the document has been entirely processed.
|
||||
*/
|
||||
public function eof();
|
||||
|
||||
/**
|
||||
* Emitted when the parser encounters an error condition.
|
||||
*/
|
||||
public function parseError($msg, $line, $col);
|
||||
|
||||
/**
|
||||
* A CDATA section.
|
||||
*
|
||||
* @param string $data
|
||||
* The unparsed character data
|
||||
*/
|
||||
public function cdata($data);
|
||||
|
||||
/**
|
||||
* This is a holdover from the XML spec.
|
||||
*
|
||||
* While user agents don't get PIs, server-side does.
|
||||
*
|
||||
* @param string $name The name of the processor (e.g. 'php').
|
||||
* @param string $data The unparsed data.
|
||||
*/
|
||||
public function processingInstruction($name, $data = null);
|
||||
}
|
33
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/FileInputStream.php
vendored
Normal file
33
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/FileInputStream.php
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace Masterminds\HTML5\Parser;
|
||||
|
||||
/**
|
||||
* The FileInputStream loads a file to be parsed.
|
||||
*
|
||||
* So right now we read files into strings and then process the
|
||||
* string. We chose to do this largely for the sake of expediency of
|
||||
* development, and also because we could optimize toward processing
|
||||
* arbitrarily large chunks of the input. But in the future, we'd
|
||||
* really like to rewrite this class to efficiently handle lower level
|
||||
* stream reads (and thus efficiently handle large documents).
|
||||
*
|
||||
* @deprecated since 2.4, to remove in 3.0. Use a string in the scanner instead.
|
||||
*/
|
||||
class FileInputStream extends StringInputStream implements InputStream
|
||||
{
|
||||
/**
|
||||
* Load a file input stream.
|
||||
*
|
||||
* @param string $data The file or url path to load.
|
||||
* @param string $encoding The encoding to use for the data.
|
||||
* @param string $debug A fprintf format to use to echo the data on stdout.
|
||||
*/
|
||||
public function __construct($data, $encoding = 'UTF-8', $debug = '')
|
||||
{
|
||||
// Get the contents of the file.
|
||||
$content = file_get_contents($data);
|
||||
|
||||
parent::__construct($content, $encoding, $debug);
|
||||
}
|
||||
}
|
87
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/InputStream.php
vendored
Normal file
87
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/InputStream.php
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
namespace Masterminds\HTML5\Parser;
|
||||
|
||||
/**
|
||||
* Interface for stream readers.
|
||||
*
|
||||
* The parser only reads from streams. Various input sources can write
|
||||
* an adapater to this InputStream.
|
||||
*
|
||||
* Currently provided InputStream implementations include
|
||||
* FileInputStream and StringInputStream.
|
||||
*
|
||||
* @deprecated since 2.4, to remove in 3.0. Use a string in the scanner instead.
|
||||
*/
|
||||
interface InputStream extends \Iterator
|
||||
{
|
||||
/**
|
||||
* Returns the current line that is being consumed.
|
||||
*
|
||||
* TODO: Move this to the scanner.
|
||||
*/
|
||||
public function currentLine();
|
||||
|
||||
/**
|
||||
* Returns the current column of the current line that the tokenizer is at.
|
||||
*
|
||||
* Newlines are column 0. The first char after a newline is column 1.
|
||||
*
|
||||
* @TODO Move this to the scanner.
|
||||
*
|
||||
* @return int The column number.
|
||||
*/
|
||||
public function columnOffset();
|
||||
|
||||
/**
|
||||
* Get all characters until EOF.
|
||||
*
|
||||
* This consumes characters until the EOF.
|
||||
*/
|
||||
public function remainingChars();
|
||||
|
||||
/**
|
||||
* Read to a particular match (or until $max bytes are consumed).
|
||||
*
|
||||
* This operates on byte sequences, not characters.
|
||||
*
|
||||
* Matches as far as possible until we reach a certain set of bytes
|
||||
* and returns the matched substring.
|
||||
*
|
||||
* @see strcspn
|
||||
*
|
||||
* @param string $bytes Bytes to match.
|
||||
* @param int $max Maximum number of bytes to scan.
|
||||
*
|
||||
* @return mixed Index or false if no match is found. You should use strong
|
||||
* equality when checking the result, since index could be 0.
|
||||
*/
|
||||
public function charsUntil($bytes, $max = null);
|
||||
|
||||
/**
|
||||
* Returns the string so long as $bytes matches.
|
||||
*
|
||||
* Matches as far as possible with a certain set of bytes
|
||||
* and returns the matched substring.
|
||||
*
|
||||
* @see strspn
|
||||
*
|
||||
* @param string $bytes A mask of bytes to match. If ANY byte in this mask matches the
|
||||
* current char, the pointer advances and the char is part of the
|
||||
* substring.
|
||||
* @param int $max The max number of chars to read.
|
||||
*/
|
||||
public function charsWhile($bytes, $max = null);
|
||||
|
||||
/**
|
||||
* Unconsume one character.
|
||||
*
|
||||
* @param int $howMany The number of characters to move the pointer back.
|
||||
*/
|
||||
public function unconsume($howMany = 1);
|
||||
|
||||
/**
|
||||
* Retrieve the next character without advancing the pointer.
|
||||
*/
|
||||
public function peek();
|
||||
}
|
10
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/ParseError.php
vendored
Normal file
10
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/ParseError.php
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Masterminds\HTML5\Parser;
|
||||
|
||||
/**
|
||||
* Emit when the parser has an error.
|
||||
*/
|
||||
class ParseError extends \Exception
|
||||
{
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
# The Parser Model
|
||||
|
||||
The parser model here follows the model in section
|
||||
[8.2.1](http://www.w3.org/TR/2012/CR-html5-20121217/syntax.html#parsing)
|
||||
of the HTML5 specification, though we do not assume a networking layer.
|
||||
|
||||
[ InputStream ] // Generic support for reading input.
|
||||
||
|
||||
[ Scanner ] // Breaks down the stream into characters.
|
||||
||
|
||||
[ Tokenizer ] // Groups characters into syntactic
|
||||
||
|
||||
[ Tree Builder ] // Organizes units into a tree of objects
|
||||
||
|
||||
[ DOM Document ] // The final state of the parsed document.
|
||||
|
||||
|
||||
## InputStream
|
||||
|
||||
This is an interface with at least two concrete implementations:
|
||||
|
||||
- StringInputStream: Reads an HTML5 string.
|
||||
- FileInputStream: Reads an HTML5 file.
|
||||
|
||||
## Scanner
|
||||
|
||||
This is a mechanical piece of the parser.
|
||||
|
||||
## Tokenizer
|
||||
|
||||
This follows section 8.4 of the HTML5 spec. It is (roughly) a recursive
|
||||
descent parser. (Though there are plenty of optimizations that are less
|
||||
than purely functional.
|
||||
|
||||
## EventHandler and DOMTree
|
||||
|
||||
EventHandler is the interface for tree builders. Since not all
|
||||
implementations will necessarily build trees, we've chosen a more
|
||||
generic name.
|
||||
|
||||
The event handler emits tokens during tokenization.
|
||||
|
||||
The DOMTree is an event handler that builds a DOM tree. The output of
|
||||
the DOMTree builder is a DOMDocument.
|
||||
|
||||
## DOMDocument
|
||||
|
||||
PHP has a DOMDocument class built-in (technically, it's part of libxml.)
|
||||
We use that, thus rendering the output of this process compatible with
|
||||
SimpleXML, QueryPath, and many other XML/HTML processing tools.
|
||||
|
||||
For cases where the HTML5 is a fragment of a HTML5 document a
|
||||
DOMDocumentFragment is returned instead. This is another built-in class.
|
416
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/Scanner.php
vendored
Normal file
416
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/Scanner.php
vendored
Normal file
|
@ -0,0 +1,416 @@
|
|||
<?php
|
||||
|
||||
namespace Masterminds\HTML5\Parser;
|
||||
|
||||
use Masterminds\HTML5\Exception;
|
||||
|
||||
/**
|
||||
* The scanner scans over a given data input to react appropriately to characters.
|
||||
*/
|
||||
class Scanner
|
||||
{
|
||||
const CHARS_HEX = 'abcdefABCDEF01234567890';
|
||||
const CHARS_ALNUM = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890';
|
||||
const CHARS_ALPHA = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
|
||||
/**
|
||||
* The string data we're parsing.
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* The current integer byte position we are in $data.
|
||||
*/
|
||||
private $char;
|
||||
|
||||
/**
|
||||
* Length of $data; when $char === $data, we are at the end-of-file.
|
||||
*/
|
||||
private $EOF;
|
||||
|
||||
/**
|
||||
* Parse errors.
|
||||
*/
|
||||
public $errors = array();
|
||||
|
||||
/**
|
||||
* Create a new Scanner.
|
||||
*
|
||||
* @param string $data Data to parse.
|
||||
* @param string $encoding The encoding to use for the data.
|
||||
*
|
||||
* @throws Exception If the given data cannot be encoded to UTF-8.
|
||||
*/
|
||||
public function __construct($data, $encoding = 'UTF-8')
|
||||
{
|
||||
if ($data instanceof InputStream) {
|
||||
@trigger_error('InputStream objects are deprecated since version 2.4 and will be removed in 3.0. Use strings instead.', E_USER_DEPRECATED);
|
||||
$data = (string) $data;
|
||||
}
|
||||
|
||||
$data = UTF8Utils::convertToUTF8($data, $encoding);
|
||||
|
||||
// There is good reason to question whether it makes sense to
|
||||
// do this here, since most of these checks are done during
|
||||
// parsing, and since this check doesn't actually *do* anything.
|
||||
$this->errors = UTF8Utils::checkForIllegalCodepoints($data);
|
||||
|
||||
$data = $this->replaceLinefeeds($data);
|
||||
|
||||
$this->data = $data;
|
||||
$this->char = 0;
|
||||
$this->EOF = strlen($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if upcomming chars match the given sequence.
|
||||
*
|
||||
* This will read the stream for the $sequence. If it's
|
||||
* found, this will return true. If not, return false.
|
||||
* Since this unconsumes any chars it reads, the caller
|
||||
* will still need to read the next sequence, even if
|
||||
* this returns true.
|
||||
*
|
||||
* Example: $this->scanner->sequenceMatches('</script>') will
|
||||
* see if the input stream is at the start of a
|
||||
* '</script>' string.
|
||||
*
|
||||
* @param string $sequence
|
||||
* @param bool $caseSensitive
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function sequenceMatches($sequence, $caseSensitive = true)
|
||||
{
|
||||
$portion = substr($this->data, $this->char, strlen($sequence));
|
||||
|
||||
return $caseSensitive ? $portion === $sequence : 0 === strcasecmp($portion, $sequence);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current position.
|
||||
*
|
||||
* @return int The current intiger byte position.
|
||||
*/
|
||||
public function position()
|
||||
{
|
||||
return $this->char;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a peek at the next character in the data.
|
||||
*
|
||||
* @return string The next character.
|
||||
*/
|
||||
public function peek()
|
||||
{
|
||||
if (($this->char + 1) <= $this->EOF) {
|
||||
return $this->data[$this->char + 1];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next character.
|
||||
* Note: This advances the pointer.
|
||||
*
|
||||
* @return string The next character.
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
++$this->char;
|
||||
|
||||
if ($this->char < $this->EOF) {
|
||||
return $this->data[$this->char];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current character.
|
||||
* Note, this does not advance the pointer.
|
||||
*
|
||||
* @return string The current character.
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
if ($this->char < $this->EOF) {
|
||||
return $this->data[$this->char];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Silently consume N chars.
|
||||
*
|
||||
* @param int $count
|
||||
*/
|
||||
public function consume($count = 1)
|
||||
{
|
||||
$this->char += $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unconsume some of the data.
|
||||
* This moves the data pointer backwards.
|
||||
*
|
||||
* @param int $howMany The number of characters to move the pointer back.
|
||||
*/
|
||||
public function unconsume($howMany = 1)
|
||||
{
|
||||
if (($this->char - $howMany) >= 0) {
|
||||
$this->char -= $howMany;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next group of that contains hex characters.
|
||||
* Note, along with getting the characters the pointer in the data will be
|
||||
* moved as well.
|
||||
*
|
||||
* @return string The next group that is hex characters.
|
||||
*/
|
||||
public function getHex()
|
||||
{
|
||||
return $this->doCharsWhile(static::CHARS_HEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next group of characters that are ASCII Alpha characters.
|
||||
* Note, along with getting the characters the pointer in the data will be
|
||||
* moved as well.
|
||||
*
|
||||
* @return string The next group of ASCII alpha characters.
|
||||
*/
|
||||
public function getAsciiAlpha()
|
||||
{
|
||||
return $this->doCharsWhile(static::CHARS_ALPHA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next group of characters that are ASCII Alpha characters and numbers.
|
||||
* Note, along with getting the characters the pointer in the data will be
|
||||
* moved as well.
|
||||
*
|
||||
* @return string The next group of ASCII alpha characters and numbers.
|
||||
*/
|
||||
public function getAsciiAlphaNum()
|
||||
{
|
||||
return $this->doCharsWhile(static::CHARS_ALNUM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next group of numbers.
|
||||
* Note, along with getting the characters the pointer in the data will be
|
||||
* moved as well.
|
||||
*
|
||||
* @return string The next group of numbers.
|
||||
*/
|
||||
public function getNumeric()
|
||||
{
|
||||
return $this->doCharsWhile('0123456789');
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume whitespace.
|
||||
* Whitespace in HTML5 is: formfeed, tab, newline, space.
|
||||
*
|
||||
* @return int The length of the matched whitespaces.
|
||||
*/
|
||||
public function whitespace()
|
||||
{
|
||||
if ($this->char >= $this->EOF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$len = strspn($this->data, "\n\t\f ", $this->char);
|
||||
|
||||
$this->char += $len;
|
||||
|
||||
return $len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current line that is being consumed.
|
||||
*
|
||||
* @return int The current line number.
|
||||
*/
|
||||
public function currentLine()
|
||||
{
|
||||
if (empty($this->EOF) || 0 === $this->char) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Add one to $this->char because we want the number for the next
|
||||
// byte to be processed.
|
||||
return substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read chars until something in the mask is encountered.
|
||||
*
|
||||
* @param string $mask
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function charsUntil($mask)
|
||||
{
|
||||
return $this->doCharsUntil($mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read chars as long as the mask matches.
|
||||
*
|
||||
* @param string $mask
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function charsWhile($mask)
|
||||
{
|
||||
return $this->doCharsWhile($mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current column of the current line that the tokenizer is at.
|
||||
*
|
||||
* Newlines are column 0. The first char after a newline is column 1.
|
||||
*
|
||||
* @return int The column number.
|
||||
*/
|
||||
public function columnOffset()
|
||||
{
|
||||
// Short circuit for the first char.
|
||||
if (0 === $this->char) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// strrpos is weird, and the offset needs to be negative for what we
|
||||
// want (i.e., the last \n before $this->char). This needs to not have
|
||||
// one (to make it point to the next character, the one we want the
|
||||
// position of) added to it because strrpos's behaviour includes the
|
||||
// final offset byte.
|
||||
$backwardFrom = $this->char - 1 - strlen($this->data);
|
||||
$lastLine = strrpos($this->data, "\n", $backwardFrom);
|
||||
|
||||
// However, for here we want the length up until the next byte to be
|
||||
// processed, so add one to the current byte ($this->char).
|
||||
if (false !== $lastLine) {
|
||||
$findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine);
|
||||
} else {
|
||||
// After a newline.
|
||||
$findLengthOf = substr($this->data, 0, $this->char);
|
||||
}
|
||||
|
||||
return UTF8Utils::countChars($findLengthOf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all characters until EOF.
|
||||
*
|
||||
* This consumes characters until the EOF.
|
||||
*
|
||||
* @return int The number of characters remaining.
|
||||
*/
|
||||
public function remainingChars()
|
||||
{
|
||||
if ($this->char < $this->EOF) {
|
||||
$data = substr($this->data, $this->char);
|
||||
$this->char = $this->EOF;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
return ''; // false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace linefeed characters according to the spec.
|
||||
*
|
||||
* @param $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function replaceLinefeeds($data)
|
||||
{
|
||||
/*
|
||||
* U+000D CARRIAGE RETURN (CR) characters and U+000A LINE FEED (LF) characters are treated specially.
|
||||
* Any CR characters that are followed by LF characters must be removed, and any CR characters not
|
||||
* followed by LF characters must be converted to LF characters. Thus, newlines in HTML DOMs are
|
||||
* represented by LF characters, and there are never any CR characters in the input to the tokenization
|
||||
* stage.
|
||||
*/
|
||||
$crlfTable = array(
|
||||
"\0" => "\xEF\xBF\xBD",
|
||||
"\r\n" => "\n",
|
||||
"\r" => "\n",
|
||||
);
|
||||
|
||||
return strtr($data, $crlfTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read to a particular match (or until $max bytes are consumed).
|
||||
*
|
||||
* This operates on byte sequences, not characters.
|
||||
*
|
||||
* Matches as far as possible until we reach a certain set of bytes
|
||||
* and returns the matched substring.
|
||||
*
|
||||
* @param string $bytes Bytes to match.
|
||||
* @param int $max Maximum number of bytes to scan.
|
||||
*
|
||||
* @return mixed Index or false if no match is found. You should use strong
|
||||
* equality when checking the result, since index could be 0.
|
||||
*/
|
||||
private function doCharsUntil($bytes, $max = null)
|
||||
{
|
||||
if ($this->char >= $this->EOF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 === $max || $max) {
|
||||
$len = strcspn($this->data, $bytes, $this->char, $max);
|
||||
} else {
|
||||
$len = strcspn($this->data, $bytes, $this->char);
|
||||
}
|
||||
|
||||
$string = (string) substr($this->data, $this->char, $len);
|
||||
$this->char += $len;
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string so long as $bytes matches.
|
||||
*
|
||||
* Matches as far as possible with a certain set of bytes
|
||||
* and returns the matched substring.
|
||||
*
|
||||
* @param string $bytes A mask of bytes to match. If ANY byte in this mask matches the
|
||||
* current char, the pointer advances and the char is part of the
|
||||
* substring.
|
||||
* @param int $max The max number of chars to read.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function doCharsWhile($bytes, $max = null)
|
||||
{
|
||||
if ($this->char >= $this->EOF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 === $max || $max) {
|
||||
$len = strspn($this->data, $bytes, $this->char, $max);
|
||||
} else {
|
||||
$len = strspn($this->data, $bytes, $this->char);
|
||||
}
|
||||
|
||||
$string = (string) substr($this->data, $this->char, $len);
|
||||
$this->char += $len;
|
||||
|
||||
return $string;
|
||||
}
|
||||
}
|
331
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/StringInputStream.php
vendored
Normal file
331
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/StringInputStream.php
vendored
Normal file
|
@ -0,0 +1,331 @@
|
|||
<?php
|
||||
/**
|
||||
* Loads a string to be parsed.
|
||||
*/
|
||||
|
||||
namespace Masterminds\HTML5\Parser;
|
||||
|
||||
/*
|
||||
*
|
||||
* Based on code from html5lib:
|
||||
|
||||
Copyright 2009 Geoffrey Sneddon <http://gsnedders.com/>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Some conventions:
|
||||
// - /* */ indicates verbatim text from the HTML 5 specification
|
||||
// MPB: Not sure which version of the spec. Moving from HTML5lib to
|
||||
// HTML5-PHP, I have been using this version:
|
||||
// http://www.w3.org/TR/2012/CR-html5-20121217/Overview.html#contents
|
||||
//
|
||||
// - // indicates regular comments
|
||||
|
||||
/**
|
||||
* @deprecated since 2.4, to remove in 3.0. Use a string in the scanner instead.
|
||||
*/
|
||||
class StringInputStream implements InputStream
|
||||
{
|
||||
/**
|
||||
* The string data we're parsing.
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* The current integer byte position we are in $data.
|
||||
*/
|
||||
private $char;
|
||||
|
||||
/**
|
||||
* Length of $data; when $char === $data, we are at the end-of-file.
|
||||
*/
|
||||
private $EOF;
|
||||
|
||||
/**
|
||||
* Parse errors.
|
||||
*/
|
||||
public $errors = array();
|
||||
|
||||
/**
|
||||
* Create a new InputStream wrapper.
|
||||
*
|
||||
* @param string $data Data to parse.
|
||||
* @param string $encoding The encoding to use for the data.
|
||||
* @param string $debug A fprintf format to use to echo the data on stdout.
|
||||
*/
|
||||
public function __construct($data, $encoding = 'UTF-8', $debug = '')
|
||||
{
|
||||
$data = UTF8Utils::convertToUTF8($data, $encoding);
|
||||
if ($debug) {
|
||||
fprintf(STDOUT, $debug, $data, strlen($data));
|
||||
}
|
||||
|
||||
// There is good reason to question whether it makes sense to
|
||||
// do this here, since most of these checks are done during
|
||||
// parsing, and since this check doesn't actually *do* anything.
|
||||
$this->errors = UTF8Utils::checkForIllegalCodepoints($data);
|
||||
|
||||
$data = $this->replaceLinefeeds($data);
|
||||
|
||||
$this->data = $data;
|
||||
$this->char = 0;
|
||||
$this->EOF = strlen($data);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace linefeed characters according to the spec.
|
||||
*/
|
||||
protected function replaceLinefeeds($data)
|
||||
{
|
||||
/*
|
||||
* U+000D CARRIAGE RETURN (CR) characters and U+000A LINE FEED (LF) characters are treated specially.
|
||||
* Any CR characters that are followed by LF characters must be removed, and any CR characters not
|
||||
* followed by LF characters must be converted to LF characters. Thus, newlines in HTML DOMs are
|
||||
* represented by LF characters, and there are never any CR characters in the input to the tokenization
|
||||
* stage.
|
||||
*/
|
||||
$crlfTable = array(
|
||||
"\0" => "\xEF\xBF\xBD",
|
||||
"\r\n" => "\n",
|
||||
"\r" => "\n",
|
||||
);
|
||||
|
||||
return strtr($data, $crlfTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current line that the tokenizer is at.
|
||||
*/
|
||||
public function currentLine()
|
||||
{
|
||||
if (empty($this->EOF) || 0 === $this->char) {
|
||||
return 1;
|
||||
}
|
||||
// Add one to $this->char because we want the number for the next
|
||||
// byte to be processed.
|
||||
return substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function getCurrentLine()
|
||||
{
|
||||
return $this->currentLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current column of the current line that the tokenizer is at.
|
||||
* Newlines are column 0. The first char after a newline is column 1.
|
||||
*
|
||||
* @return int The column number.
|
||||
*/
|
||||
public function columnOffset()
|
||||
{
|
||||
// Short circuit for the first char.
|
||||
if (0 === $this->char) {
|
||||
return 0;
|
||||
}
|
||||
// strrpos is weird, and the offset needs to be negative for what we
|
||||
// want (i.e., the last \n before $this->char). This needs to not have
|
||||
// one (to make it point to the next character, the one we want the
|
||||
// position of) added to it because strrpos's behaviour includes the
|
||||
// final offset byte.
|
||||
$backwardFrom = $this->char - 1 - strlen($this->data);
|
||||
$lastLine = strrpos($this->data, "\n", $backwardFrom);
|
||||
|
||||
// However, for here we want the length up until the next byte to be
|
||||
// processed, so add one to the current byte ($this->char).
|
||||
if (false !== $lastLine) {
|
||||
$findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine);
|
||||
} else {
|
||||
// After a newline.
|
||||
$findLengthOf = substr($this->data, 0, $this->char);
|
||||
}
|
||||
|
||||
return UTF8Utils::countChars($findLengthOf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function getColumnOffset()
|
||||
{
|
||||
return $this->columnOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current character.
|
||||
*
|
||||
* @return string The current character.
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->data[$this->char];
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance the pointer.
|
||||
* This is part of the Iterator interface.
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
++$this->char;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewind to the start of the string.
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->char = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the current pointer location valid.
|
||||
*
|
||||
* @return bool Whether the current pointer location is valid.
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->char < $this->EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all characters until EOF.
|
||||
*
|
||||
* This reads to the end of the file, and sets the read marker at the
|
||||
* end of the file.
|
||||
*
|
||||
* Note this performs bounds checking.
|
||||
*
|
||||
* @return string Returns the remaining text. If called when the InputStream is
|
||||
* already exhausted, it returns an empty string.
|
||||
*/
|
||||
public function remainingChars()
|
||||
{
|
||||
if ($this->char < $this->EOF) {
|
||||
$data = substr($this->data, $this->char);
|
||||
$this->char = $this->EOF;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
return ''; // false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read to a particular match (or until $max bytes are consumed).
|
||||
*
|
||||
* This operates on byte sequences, not characters.
|
||||
*
|
||||
* Matches as far as possible until we reach a certain set of bytes
|
||||
* and returns the matched substring.
|
||||
*
|
||||
* @param string $bytes Bytes to match.
|
||||
* @param int $max Maximum number of bytes to scan.
|
||||
*
|
||||
* @return mixed Index or false if no match is found. You should use strong
|
||||
* equality when checking the result, since index could be 0.
|
||||
*/
|
||||
public function charsUntil($bytes, $max = null)
|
||||
{
|
||||
if ($this->char >= $this->EOF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 === $max || $max) {
|
||||
$len = strcspn($this->data, $bytes, $this->char, $max);
|
||||
} else {
|
||||
$len = strcspn($this->data, $bytes, $this->char);
|
||||
}
|
||||
|
||||
$string = (string) substr($this->data, $this->char, $len);
|
||||
$this->char += $len;
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string so long as $bytes matches.
|
||||
*
|
||||
* Matches as far as possible with a certain set of bytes
|
||||
* and returns the matched substring.
|
||||
*
|
||||
* @param string $bytes A mask of bytes to match. If ANY byte in this mask matches the
|
||||
* current char, the pointer advances and the char is part of the
|
||||
* substring.
|
||||
* @param int $max The max number of chars to read.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function charsWhile($bytes, $max = null)
|
||||
{
|
||||
if ($this->char >= $this->EOF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 === $max || $max) {
|
||||
$len = strspn($this->data, $bytes, $this->char, $max);
|
||||
} else {
|
||||
$len = strspn($this->data, $bytes, $this->char);
|
||||
}
|
||||
$string = (string) substr($this->data, $this->char, $len);
|
||||
$this->char += $len;
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unconsume characters.
|
||||
*
|
||||
* @param int $howMany The number of characters to unconsume.
|
||||
*/
|
||||
public function unconsume($howMany = 1)
|
||||
{
|
||||
if (($this->char - $howMany) >= 0) {
|
||||
$this->char -= $howMany;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look ahead without moving cursor.
|
||||
*/
|
||||
public function peek()
|
||||
{
|
||||
if (($this->char + 1) <= $this->EOF) {
|
||||
return $this->data[$this->char + 1];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function key()
|
||||
{
|
||||
return $this->char;
|
||||
}
|
||||
}
|
1191
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/Tokenizer.php
vendored
Normal file
1191
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/Tokenizer.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
127
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php
vendored
Normal file
127
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php
vendored
Normal file
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
|
||||
namespace Masterminds\HTML5\Parser;
|
||||
|
||||
/**
|
||||
* Handles special-case rules for the DOM tree builder.
|
||||
*
|
||||
* Many tags have special rules that need to be accomodated on an
|
||||
* individual basis. This class handles those rules.
|
||||
*
|
||||
* See section 8.1.2.4 of the spec.
|
||||
*
|
||||
* @todo - colgroup and col special behaviors
|
||||
* - body and head special behaviors
|
||||
*/
|
||||
class TreeBuildingRules
|
||||
{
|
||||
protected static $tags = array(
|
||||
'li' => 1,
|
||||
'dd' => 1,
|
||||
'dt' => 1,
|
||||
'rt' => 1,
|
||||
'rp' => 1,
|
||||
'tr' => 1,
|
||||
'th' => 1,
|
||||
'td' => 1,
|
||||
'thead' => 1,
|
||||
'tfoot' => 1,
|
||||
'tbody' => 1,
|
||||
'table' => 1,
|
||||
'optgroup' => 1,
|
||||
'option' => 1,
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns true if the given tagname has special processing rules.
|
||||
*/
|
||||
public function hasRules($tagname)
|
||||
{
|
||||
return isset(static::$tags[$tagname]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the rule for the current tag name.
|
||||
*
|
||||
* This may modify the existing DOM.
|
||||
*
|
||||
* @return \DOMElement The new Current DOM element.
|
||||
*/
|
||||
public function evaluate($new, $current)
|
||||
{
|
||||
switch ($new->tagName) {
|
||||
case 'li':
|
||||
return $this->handleLI($new, $current);
|
||||
case 'dt':
|
||||
case 'dd':
|
||||
return $this->handleDT($new, $current);
|
||||
case 'rt':
|
||||
case 'rp':
|
||||
return $this->handleRT($new, $current);
|
||||
case 'optgroup':
|
||||
return $this->closeIfCurrentMatches($new, $current, array(
|
||||
'optgroup',
|
||||
));
|
||||
case 'option':
|
||||
return $this->closeIfCurrentMatches($new, $current, array(
|
||||
'option',
|
||||
));
|
||||
case 'tr':
|
||||
return $this->closeIfCurrentMatches($new, $current, array(
|
||||
'tr',
|
||||
));
|
||||
case 'td':
|
||||
case 'th':
|
||||
return $this->closeIfCurrentMatches($new, $current, array(
|
||||
'th',
|
||||
'td',
|
||||
));
|
||||
case 'tbody':
|
||||
case 'thead':
|
||||
case 'tfoot':
|
||||
case 'table': // Spec isn't explicit about this, but it's necessary.
|
||||
|
||||
return $this->closeIfCurrentMatches($new, $current, array(
|
||||
'thead',
|
||||
'tfoot',
|
||||
'tbody',
|
||||
));
|
||||
}
|
||||
|
||||
return $current;
|
||||
}
|
||||
|
||||
protected function handleLI($ele, $current)
|
||||
{
|
||||
return $this->closeIfCurrentMatches($ele, $current, array(
|
||||
'li',
|
||||
));
|
||||
}
|
||||
|
||||
protected function handleDT($ele, $current)
|
||||
{
|
||||
return $this->closeIfCurrentMatches($ele, $current, array(
|
||||
'dt',
|
||||
'dd',
|
||||
));
|
||||
}
|
||||
|
||||
protected function handleRT($ele, $current)
|
||||
{
|
||||
return $this->closeIfCurrentMatches($ele, $current, array(
|
||||
'rt',
|
||||
'rp',
|
||||
));
|
||||
}
|
||||
|
||||
protected function closeIfCurrentMatches($ele, $current, $match)
|
||||
{
|
||||
if (in_array($current->tagName, $match, true)) {
|
||||
$current->parentNode->appendChild($ele);
|
||||
} else {
|
||||
$current->appendChild($ele);
|
||||
}
|
||||
|
||||
return $ele;
|
||||
}
|
||||
}
|
183
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/UTF8Utils.php
vendored
Normal file
183
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Parser/UTF8Utils.php
vendored
Normal file
|
@ -0,0 +1,183 @@
|
|||
<?php
|
||||
|
||||
namespace Masterminds\HTML5\Parser;
|
||||
|
||||
/*
|
||||
Portions based on code from html5lib files with the following copyright:
|
||||
|
||||
Copyright 2009 Geoffrey Sneddon <http://gsnedders.com/>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
use Masterminds\HTML5\Exception;
|
||||
|
||||
class UTF8Utils
|
||||
{
|
||||
/**
|
||||
* The Unicode replacement character.
|
||||
*/
|
||||
const FFFD = "\xEF\xBF\xBD";
|
||||
|
||||
/**
|
||||
* Count the number of characters in a string.
|
||||
* UTF-8 aware. This will try (in order) iconv, MB, libxml, and finally a custom counter.
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function countChars($string)
|
||||
{
|
||||
// Get the length for the string we need.
|
||||
if (function_exists('mb_strlen')) {
|
||||
return mb_strlen($string, 'utf-8');
|
||||
}
|
||||
|
||||
if (function_exists('iconv_strlen')) {
|
||||
return iconv_strlen($string, 'utf-8');
|
||||
}
|
||||
|
||||
if (function_exists('utf8_decode')) {
|
||||
// MPB: Will this work? Won't certain decodes lead to two chars
|
||||
// extrapolated out of 2-byte chars?
|
||||
return strlen(utf8_decode($string));
|
||||
}
|
||||
|
||||
$count = count_chars($string);
|
||||
|
||||
// 0x80 = 0x7F - 0 + 1 (one added to get inclusive range)
|
||||
// 0x33 = 0xF4 - 0x2C + 1 (one added to get inclusive range)
|
||||
return array_sum(array_slice($count, 0, 0x80)) + array_sum(array_slice($count, 0xC2, 0x33));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert data from the given encoding to UTF-8.
|
||||
*
|
||||
* This has not yet been tested with charactersets other than UTF-8.
|
||||
* It should work with ISO-8859-1/-13 and standard Latin Win charsets.
|
||||
*
|
||||
* @param string $data The data to convert
|
||||
* @param string $encoding A valid encoding. Examples: http://www.php.net/manual/en/mbstring.supported-encodings.php
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function convertToUTF8($data, $encoding = 'UTF-8')
|
||||
{
|
||||
/*
|
||||
* From the HTML5 spec: Given an encoding, the bytes in the input stream must be converted
|
||||
* to Unicode characters for the tokeniser, as described by the rules for that encoding,
|
||||
* except that the leading U+FEFF BYTE ORDER MARK character, if any, must not be stripped
|
||||
* by the encoding layer (it is stripped by the rule below). Bytes or sequences of bytes
|
||||
* in the original byte stream that could not be converted to Unicode characters must be
|
||||
* converted to U+FFFD REPLACEMENT CHARACTER code points.
|
||||
*/
|
||||
|
||||
// mb_convert_encoding is chosen over iconv because of a bug. The best
|
||||
// details for the bug are on http://us1.php.net/manual/en/function.iconv.php#108643
|
||||
// which contains links to the actual but reports as well as work around
|
||||
// details.
|
||||
if (function_exists('mb_convert_encoding')) {
|
||||
// mb library has the following behaviors:
|
||||
// - UTF-16 surrogates result in false.
|
||||
// - Overlongs and outside Plane 16 result in empty strings.
|
||||
|
||||
// Before we run mb_convert_encoding we need to tell it what to do with
|
||||
// characters it does not know. This could be different than the parent
|
||||
// application executing this library so we store the value, change it
|
||||
// to our needs, and then change it back when we are done. This feels
|
||||
// a little excessive and it would be great if there was a better way.
|
||||
$save = mb_substitute_character();
|
||||
mb_substitute_character('none');
|
||||
$data = mb_convert_encoding($data, 'UTF-8', $encoding);
|
||||
mb_substitute_character($save);
|
||||
}
|
||||
// @todo Get iconv running in at least some environments if that is possible.
|
||||
elseif (function_exists('iconv') && 'auto' !== $encoding) {
|
||||
// fprintf(STDOUT, "iconv found\n");
|
||||
// iconv has the following behaviors:
|
||||
// - Overlong representations are ignored.
|
||||
// - Beyond Plane 16 is replaced with a lower char.
|
||||
// - Incomplete sequences generate a warning.
|
||||
$data = @iconv($encoding, 'UTF-8//IGNORE', $data);
|
||||
} else {
|
||||
throw new Exception('Not implemented, please install mbstring or iconv');
|
||||
}
|
||||
|
||||
/*
|
||||
* One leading U+FEFF BYTE ORDER MARK character must be ignored if any are present.
|
||||
*/
|
||||
if ("\xEF\xBB\xBF" === substr($data, 0, 3)) {
|
||||
$data = substr($data, 3);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for Unicode code points that are not valid in a document.
|
||||
*
|
||||
* @param string $data A string to analyze
|
||||
*
|
||||
* @return array An array of (string) error messages produced by the scanning
|
||||
*/
|
||||
public static function checkForIllegalCodepoints($data)
|
||||
{
|
||||
// Vestigal error handling.
|
||||
$errors = array();
|
||||
|
||||
/*
|
||||
* All U+0000 null characters in the input must be replaced by U+FFFD REPLACEMENT CHARACTERs.
|
||||
* Any occurrences of such characters is a parse error.
|
||||
*/
|
||||
for ($i = 0, $count = substr_count($data, "\0"); $i < $count; ++$i) {
|
||||
$errors[] = 'null-character';
|
||||
}
|
||||
|
||||
/*
|
||||
* Any occurrences of any characters in the ranges U+0001 to U+0008, U+000B, U+000E to U+001F, U+007F
|
||||
* to U+009F, U+D800 to U+DFFF , U+FDD0 to U+FDEF, and characters U+FFFE, U+FFFF, U+1FFFE, U+1FFFF,
|
||||
* U+2FFFE, U+2FFFF, U+3FFFE, U+3FFFF, U+4FFFE, U+4FFFF, U+5FFFE, U+5FFFF, U+6FFFE, U+6FFFF, U+7FFFE,
|
||||
* U+7FFFF, U+8FFFE, U+8FFFF, U+9FFFE, U+9FFFF, U+AFFFE, U+AFFFF, U+BFFFE, U+BFFFF, U+CFFFE, U+CFFFF,
|
||||
* U+DFFFE, U+DFFFF, U+EFFFE, U+EFFFF, U+FFFFE, U+FFFFF, U+10FFFE, and U+10FFFF are parse errors.
|
||||
* (These are all control characters or permanently undefined Unicode characters.)
|
||||
*/
|
||||
// Check PCRE is loaded.
|
||||
$count = preg_match_all(
|
||||
'/(?:
|
||||
[\x01-\x08\x0B\x0E-\x1F\x7F] # U+0001 to U+0008, U+000B, U+000E to U+001F and U+007F
|
||||
|
|
||||
\xC2[\x80-\x9F] # U+0080 to U+009F
|
||||
|
|
||||
\xED(?:\xA0[\x80-\xFF]|[\xA1-\xBE][\x00-\xFF]|\xBF[\x00-\xBF]) # U+D800 to U+DFFFF
|
||||
|
|
||||
\xEF\xB7[\x90-\xAF] # U+FDD0 to U+FDEF
|
||||
|
|
||||
\xEF\xBF[\xBE\xBF] # U+FFFE and U+FFFF
|
||||
|
|
||||
[\xF0-\xF4][\x8F-\xBF]\xBF[\xBE\xBF] # U+nFFFE and U+nFFFF (1 <= n <= 10_{16})
|
||||
)/x', $data, $matches);
|
||||
for ($i = 0; $i < $count; ++$i) {
|
||||
$errors[] = 'invalid-codepoint';
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
1533
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Serializer/HTML5Entities.php
vendored
Normal file
1533
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Serializer/HTML5Entities.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
553
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Serializer/OutputRules.php
vendored
Normal file
553
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Serializer/OutputRules.php
vendored
Normal file
|
@ -0,0 +1,553 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* The rules for generating output in the serializer.
|
||||
*
|
||||
* These output rules are likely to generate output similar to the document that
|
||||
* was parsed. It is not intended to output exactly the document that was parsed.
|
||||
*/
|
||||
|
||||
namespace Masterminds\HTML5\Serializer;
|
||||
|
||||
use Masterminds\HTML5\Elements;
|
||||
|
||||
/**
|
||||
* Generate the output html5 based on element rules.
|
||||
*/
|
||||
class OutputRules implements RulesInterface
|
||||
{
|
||||
/**
|
||||
* Defined in http://www.w3.org/TR/html51/infrastructure.html#html-namespace-0.
|
||||
*/
|
||||
const NAMESPACE_HTML = 'http://www.w3.org/1999/xhtml';
|
||||
|
||||
const NAMESPACE_MATHML = 'http://www.w3.org/1998/Math/MathML';
|
||||
|
||||
const NAMESPACE_SVG = 'http://www.w3.org/2000/svg';
|
||||
|
||||
const NAMESPACE_XLINK = 'http://www.w3.org/1999/xlink';
|
||||
|
||||
const NAMESPACE_XML = 'http://www.w3.org/XML/1998/namespace';
|
||||
|
||||
const NAMESPACE_XMLNS = 'http://www.w3.org/2000/xmlns/';
|
||||
|
||||
/**
|
||||
* Holds the HTML5 element names that causes a namespace switch.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $implicitNamespaces = array(
|
||||
self::NAMESPACE_HTML,
|
||||
self::NAMESPACE_SVG,
|
||||
self::NAMESPACE_MATHML,
|
||||
self::NAMESPACE_XML,
|
||||
self::NAMESPACE_XMLNS,
|
||||
);
|
||||
|
||||
const IM_IN_HTML = 1;
|
||||
|
||||
const IM_IN_SVG = 2;
|
||||
|
||||
const IM_IN_MATHML = 3;
|
||||
|
||||
/**
|
||||
* Used as cache to detect if is available ENT_HTML5.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $hasHTML5 = false;
|
||||
|
||||
protected $traverser;
|
||||
|
||||
protected $encode = false;
|
||||
|
||||
protected $out;
|
||||
|
||||
protected $outputMode;
|
||||
|
||||
private $xpath;
|
||||
|
||||
protected $nonBooleanAttributes = array(
|
||||
/*
|
||||
array(
|
||||
'nodeNamespace'=>'http://www.w3.org/1999/xhtml',
|
||||
'attrNamespace'=>'http://www.w3.org/1999/xhtml',
|
||||
|
||||
'nodeName'=>'img', 'nodeName'=>array('img', 'a'),
|
||||
'attrName'=>'alt', 'attrName'=>array('title', 'alt'),
|
||||
),
|
||||
*/
|
||||
array(
|
||||
'nodeNamespace' => 'http://www.w3.org/1999/xhtml',
|
||||
'attrName' => array('href',
|
||||
'hreflang',
|
||||
'http-equiv',
|
||||
'icon',
|
||||
'id',
|
||||
'keytype',
|
||||
'kind',
|
||||
'label',
|
||||
'lang',
|
||||
'language',
|
||||
'list',
|
||||
'maxlength',
|
||||
'media',
|
||||
'method',
|
||||
'name',
|
||||
'placeholder',
|
||||
'rel',
|
||||
'rows',
|
||||
'rowspan',
|
||||
'sandbox',
|
||||
'spellcheck',
|
||||
'scope',
|
||||
'seamless',
|
||||
'shape',
|
||||
'size',
|
||||
'sizes',
|
||||
'span',
|
||||
'src',
|
||||
'srcdoc',
|
||||
'srclang',
|
||||
'srcset',
|
||||
'start',
|
||||
'step',
|
||||
'style',
|
||||
'summary',
|
||||
'tabindex',
|
||||
'target',
|
||||
'title',
|
||||
'type',
|
||||
'value',
|
||||
'width',
|
||||
'border',
|
||||
'charset',
|
||||
'cite',
|
||||
'class',
|
||||
'code',
|
||||
'codebase',
|
||||
'color',
|
||||
'cols',
|
||||
'colspan',
|
||||
'content',
|
||||
'coords',
|
||||
'data',
|
||||
'datetime',
|
||||
'default',
|
||||
'dir',
|
||||
'dirname',
|
||||
'enctype',
|
||||
'for',
|
||||
'form',
|
||||
'formaction',
|
||||
'headers',
|
||||
'height',
|
||||
'accept',
|
||||
'accept-charset',
|
||||
'accesskey',
|
||||
'action',
|
||||
'align',
|
||||
'alt',
|
||||
'bgcolor',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'nodeNamespace' => 'http://www.w3.org/1999/xhtml',
|
||||
'xpath' => 'starts-with(local-name(), \'data-\')',
|
||||
),
|
||||
);
|
||||
|
||||
const DOCTYPE = '<!DOCTYPE html>';
|
||||
|
||||
public function __construct($output, $options = array())
|
||||
{
|
||||
if (isset($options['encode_entities'])) {
|
||||
$this->encode = $options['encode_entities'];
|
||||
}
|
||||
|
||||
$this->outputMode = static::IM_IN_HTML;
|
||||
$this->out = $output;
|
||||
$this->hasHTML5 = defined('ENT_HTML5');
|
||||
}
|
||||
|
||||
public function addRule(array $rule)
|
||||
{
|
||||
$this->nonBooleanAttributes[] = $rule;
|
||||
}
|
||||
|
||||
public function setTraverser(Traverser $traverser)
|
||||
{
|
||||
$this->traverser = $traverser;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function unsetTraverser()
|
||||
{
|
||||
$this->traverser = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function document($dom)
|
||||
{
|
||||
$this->doctype();
|
||||
if ($dom->documentElement) {
|
||||
foreach ($dom->childNodes as $node) {
|
||||
$this->traverser->node($node);
|
||||
}
|
||||
$this->nl();
|
||||
}
|
||||
}
|
||||
|
||||
protected function doctype()
|
||||
{
|
||||
$this->wr(static::DOCTYPE);
|
||||
$this->nl();
|
||||
}
|
||||
|
||||
public function element($ele)
|
||||
{
|
||||
$name = $ele->tagName;
|
||||
|
||||
// Per spec:
|
||||
// If the element has a declared namespace in the HTML, MathML or
|
||||
// SVG namespaces, we use the lname instead of the tagName.
|
||||
if ($this->traverser->isLocalElement($ele)) {
|
||||
$name = $ele->localName;
|
||||
}
|
||||
|
||||
// If we are in SVG or MathML there is special handling.
|
||||
// Using if/elseif instead of switch because it's faster in PHP.
|
||||
if ('svg' == $name) {
|
||||
$this->outputMode = static::IM_IN_SVG;
|
||||
$name = Elements::normalizeSvgElement($name);
|
||||
} elseif ('math' == $name) {
|
||||
$this->outputMode = static::IM_IN_MATHML;
|
||||
}
|
||||
|
||||
$this->openTag($ele);
|
||||
if (Elements::isA($name, Elements::TEXT_RAW)) {
|
||||
foreach ($ele->childNodes as $child) {
|
||||
if ($child instanceof \DOMCharacterData) {
|
||||
$this->wr($child->data);
|
||||
} elseif ($child instanceof \DOMElement) {
|
||||
$this->element($child);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Handle children.
|
||||
if ($ele->hasChildNodes()) {
|
||||
$this->traverser->children($ele->childNodes);
|
||||
}
|
||||
|
||||
// Close out the SVG or MathML special handling.
|
||||
if ('svg' == $name || 'math' == $name) {
|
||||
$this->outputMode = static::IM_IN_HTML;
|
||||
}
|
||||
}
|
||||
|
||||
// If not unary, add a closing tag.
|
||||
if (!Elements::isA($name, Elements::VOID_TAG)) {
|
||||
$this->closeTag($ele);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a text node.
|
||||
*
|
||||
* @param \DOMText $ele The text node to write.
|
||||
*/
|
||||
public function text($ele)
|
||||
{
|
||||
if (isset($ele->parentNode) && isset($ele->parentNode->tagName) && Elements::isA($ele->parentNode->localName, Elements::TEXT_RAW)) {
|
||||
$this->wr($ele->data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: This probably needs some flags set.
|
||||
$this->wr($this->enc($ele->data));
|
||||
}
|
||||
|
||||
public function cdata($ele)
|
||||
{
|
||||
// This encodes CDATA.
|
||||
$this->wr($ele->ownerDocument->saveXML($ele));
|
||||
}
|
||||
|
||||
public function comment($ele)
|
||||
{
|
||||
// These produce identical output.
|
||||
// $this->wr('<!--')->wr($ele->data)->wr('-->');
|
||||
$this->wr($ele->ownerDocument->saveXML($ele));
|
||||
}
|
||||
|
||||
public function processorInstruction($ele)
|
||||
{
|
||||
$this->wr('<?')
|
||||
->wr($ele->target)
|
||||
->wr(' ')
|
||||
->wr($ele->data)
|
||||
->wr('?>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the namespace attributes.
|
||||
*
|
||||
* @param \DOMNode $ele The element being written.
|
||||
*/
|
||||
protected function namespaceAttrs($ele)
|
||||
{
|
||||
if (!$this->xpath || $this->xpath->document !== $ele->ownerDocument) {
|
||||
$this->xpath = new \DOMXPath($ele->ownerDocument);
|
||||
}
|
||||
|
||||
foreach ($this->xpath->query('namespace::*[not(.=../../namespace::*)]', $ele) as $nsNode) {
|
||||
if (!in_array($nsNode->nodeValue, $this->implicitNamespaces)) {
|
||||
$this->wr(' ')->wr($nsNode->nodeName)->wr('="')->wr($nsNode->nodeValue)->wr('"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the opening tag.
|
||||
*
|
||||
* Tags for HTML, MathML, and SVG are in the local name. Otherwise, use the
|
||||
* qualified name (8.3).
|
||||
*
|
||||
* @param \DOMNode $ele The element being written.
|
||||
*/
|
||||
protected function openTag($ele)
|
||||
{
|
||||
$this->wr('<')->wr($this->traverser->isLocalElement($ele) ? $ele->localName : $ele->tagName);
|
||||
|
||||
$this->attrs($ele);
|
||||
$this->namespaceAttrs($ele);
|
||||
|
||||
if ($this->outputMode == static::IM_IN_HTML) {
|
||||
$this->wr('>');
|
||||
} // If we are not in html mode we are in SVG, MathML, or XML embedded content.
|
||||
else {
|
||||
if ($ele->hasChildNodes()) {
|
||||
$this->wr('>');
|
||||
} // If there are no children this is self closing.
|
||||
else {
|
||||
$this->wr(' />');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function attrs($ele)
|
||||
{
|
||||
// FIXME: Needs support for xml, xmlns, xlink, and namespaced elements.
|
||||
if (!$ele->hasAttributes()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
// TODO: Currently, this always writes name="value", and does not do
|
||||
// value-less attributes.
|
||||
$map = $ele->attributes;
|
||||
$len = $map->length;
|
||||
for ($i = 0; $i < $len; ++$i) {
|
||||
$node = $map->item($i);
|
||||
$val = $this->enc($node->value, true);
|
||||
|
||||
// XXX: The spec says that we need to ensure that anything in
|
||||
// the XML, XMLNS, or XLink NS's should use the canonical
|
||||
// prefix. It seems that DOM does this for us already, but there
|
||||
// may be exceptions.
|
||||
$name = $node->nodeName;
|
||||
|
||||
// Special handling for attributes in SVG and MathML.
|
||||
// Using if/elseif instead of switch because it's faster in PHP.
|
||||
if ($this->outputMode == static::IM_IN_SVG) {
|
||||
$name = Elements::normalizeSvgAttribute($name);
|
||||
} elseif ($this->outputMode == static::IM_IN_MATHML) {
|
||||
$name = Elements::normalizeMathMlAttribute($name);
|
||||
}
|
||||
|
||||
$this->wr(' ')->wr($name);
|
||||
|
||||
if ((isset($val) && '' !== $val) || $this->nonBooleanAttribute($node)) {
|
||||
$this->wr('="')->wr($val)->wr('"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function nonBooleanAttribute(\DOMAttr $attr)
|
||||
{
|
||||
$ele = $attr->ownerElement;
|
||||
foreach ($this->nonBooleanAttributes as $rule) {
|
||||
if (isset($rule['nodeNamespace']) && $rule['nodeNamespace'] !== $ele->namespaceURI) {
|
||||
continue;
|
||||
}
|
||||
if (isset($rule['attNamespace']) && $rule['attNamespace'] !== $attr->namespaceURI) {
|
||||
continue;
|
||||
}
|
||||
if (isset($rule['nodeName']) && !is_array($rule['nodeName']) && $rule['nodeName'] !== $ele->localName) {
|
||||
continue;
|
||||
}
|
||||
if (isset($rule['nodeName']) && is_array($rule['nodeName']) && !in_array($ele->localName, $rule['nodeName'], true)) {
|
||||
continue;
|
||||
}
|
||||
if (isset($rule['attrName']) && !is_array($rule['attrName']) && $rule['attrName'] !== $attr->localName) {
|
||||
continue;
|
||||
}
|
||||
if (isset($rule['attrName']) && is_array($rule['attrName']) && !in_array($attr->localName, $rule['attrName'], true)) {
|
||||
continue;
|
||||
}
|
||||
if (isset($rule['xpath'])) {
|
||||
$xp = $this->getXPath($attr);
|
||||
if (isset($rule['prefixes'])) {
|
||||
foreach ($rule['prefixes'] as $nsPrefix => $ns) {
|
||||
$xp->registerNamespace($nsPrefix, $ns);
|
||||
}
|
||||
}
|
||||
if (!$xp->evaluate($rule['xpath'], $attr)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getXPath(\DOMNode $node)
|
||||
{
|
||||
if (!$this->xpath) {
|
||||
$this->xpath = new \DOMXPath($node->ownerDocument);
|
||||
}
|
||||
|
||||
return $this->xpath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the closing tag.
|
||||
*
|
||||
* Tags for HTML, MathML, and SVG are in the local name. Otherwise, use the
|
||||
* qualified name (8.3).
|
||||
*
|
||||
* @param \DOMNode $ele The element being written.
|
||||
*/
|
||||
protected function closeTag($ele)
|
||||
{
|
||||
if ($this->outputMode == static::IM_IN_HTML || $ele->hasChildNodes()) {
|
||||
$this->wr('</')->wr($this->traverser->isLocalElement($ele) ? $ele->localName : $ele->tagName)->wr('>');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to the output.
|
||||
*
|
||||
* @param string $text The string to put into the output
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function wr($text)
|
||||
{
|
||||
fwrite($this->out, $text);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a new line character.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function nl()
|
||||
{
|
||||
fwrite($this->out, PHP_EOL);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode text.
|
||||
*
|
||||
* When encode is set to false, the default value, the text passed in is
|
||||
* escaped per section 8.3 of the html5 spec. For details on how text is
|
||||
* escaped see the escape() method.
|
||||
*
|
||||
* When encoding is set to true the text is converted to named character
|
||||
* references where appropriate. Section 8.1.4 Character references of the
|
||||
* html5 spec refers to using named character references. This is useful for
|
||||
* characters that can't otherwise legally be used in the text.
|
||||
*
|
||||
* The named character references are listed in section 8.5.
|
||||
*
|
||||
* @see http://www.w3.org/TR/2013/CR-html5-20130806/syntax.html#named-character-references True encoding will turn all named character references into their entities.
|
||||
* This includes such characters as +.# and many other common ones. By default
|
||||
* encoding here will just escape &'<>".
|
||||
*
|
||||
* Note, PHP 5.4+ has better html5 encoding.
|
||||
*
|
||||
* @todo Use the Entities class in php 5.3 to have html5 entities.
|
||||
*
|
||||
* @param string $text Text to encode.
|
||||
* @param bool $attribute True if we are encoding an attrubute, false otherwise.
|
||||
*
|
||||
* @return string The encoded text.
|
||||
*/
|
||||
protected function enc($text, $attribute = false)
|
||||
{
|
||||
// Escape the text rather than convert to named character references.
|
||||
if (!$this->encode) {
|
||||
return $this->escape($text, $attribute);
|
||||
}
|
||||
|
||||
// If we are in PHP 5.4+ we can use the native html5 entity functionality to
|
||||
// convert the named character references.
|
||||
|
||||
if ($this->hasHTML5) {
|
||||
return htmlentities($text, ENT_HTML5 | ENT_SUBSTITUTE | ENT_QUOTES, 'UTF-8', false);
|
||||
} // If a version earlier than 5.4 html5 entities are not entirely handled.
|
||||
// This manually handles them.
|
||||
else {
|
||||
return strtr($text, HTML5Entities::$map);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape test.
|
||||
*
|
||||
* According to the html5 spec section 8.3 Serializing HTML fragments, text
|
||||
* within tags that are not style, script, xmp, iframe, noembed, and noframes
|
||||
* need to be properly escaped.
|
||||
*
|
||||
* The & should be converted to &, no breaking space unicode characters
|
||||
* converted to , when in attribute mode the " should be converted to
|
||||
* ", and when not in attribute mode the < and > should be converted to
|
||||
* < and >.
|
||||
*
|
||||
* @see http://www.w3.org/TR/2013/CR-html5-20130806/syntax.html#escapingString
|
||||
*
|
||||
* @param string $text Text to escape.
|
||||
* @param bool $attribute True if we are escaping an attrubute, false otherwise.
|
||||
*/
|
||||
protected function escape($text, $attribute = false)
|
||||
{
|
||||
// Not using htmlspecialchars because, while it does escaping, it doesn't
|
||||
// match the requirements of section 8.5. For example, it doesn't handle
|
||||
// non-breaking spaces.
|
||||
if ($attribute) {
|
||||
$replace = array(
|
||||
'"' => '"',
|
||||
'&' => '&',
|
||||
"\xc2\xa0" => ' ',
|
||||
);
|
||||
} else {
|
||||
$replace = array(
|
||||
'<' => '<',
|
||||
'>' => '>',
|
||||
'&' => '&',
|
||||
"\xc2\xa0" => ' ',
|
||||
);
|
||||
}
|
||||
|
||||
return strtr($text, $replace);
|
||||
}
|
||||
}
|
33
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Serializer/README.md
vendored
Normal file
33
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Serializer/README.md
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
# The Serializer (Writer) Model
|
||||
|
||||
The serializer roughly follows sections _8.1 Writing HTML documents_ and section
|
||||
_8.3 Serializing HTML fragments_ by converting DOMDocument, DOMDocumentFragment,
|
||||
and DOMNodeList into HTML5.
|
||||
|
||||
[ HTML5 ] // Interface for saving.
|
||||
||
|
||||
[ Traverser ] // Walk the DOM
|
||||
||
|
||||
[ Rules ] // Convert DOM elements into strings.
|
||||
||
|
||||
[ HTML5 ] // HTML5 document or fragment in text.
|
||||
|
||||
|
||||
## HTML5 Class
|
||||
|
||||
Provides the top level interface for saving.
|
||||
|
||||
## The Traverser
|
||||
|
||||
Walks the DOM finding each element and passing it off to the output rules to
|
||||
convert to HTML5.
|
||||
|
||||
## Output Rules
|
||||
|
||||
The output rules are defined in the RulesInterface which can have multiple
|
||||
implementations. Currently, the OutputRules is the default implementation that
|
||||
converts a DOM as is into HTML5.
|
||||
|
||||
## HTML5 String
|
||||
|
||||
The output of the process it HTML5 as a string or saved to a file.
|
99
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Serializer/RulesInterface.php
vendored
Normal file
99
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Serializer/RulesInterface.php
vendored
Normal file
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* The interface definition for Rules to generate output.
|
||||
*/
|
||||
|
||||
namespace Masterminds\HTML5\Serializer;
|
||||
|
||||
/**
|
||||
* To create a new rule set for writing output the RulesInterface needs to be implemented.
|
||||
* The resulting class can be specified in the options with the key of rules.
|
||||
*
|
||||
* For an example implementation see Serializer\OutputRules.
|
||||
*/
|
||||
interface RulesInterface
|
||||
{
|
||||
/**
|
||||
* The class constructor.
|
||||
*
|
||||
* Note, before the rules can be used a traverser must be registered.
|
||||
*
|
||||
* @param mixed $output The output stream to write output to.
|
||||
* @param array $options An array of options.
|
||||
*/
|
||||
public function __construct($output, $options = array());
|
||||
|
||||
/**
|
||||
* Register the traverser used in but the rules.
|
||||
*
|
||||
* Note, only one traverser can be used by the rules.
|
||||
*
|
||||
* @param Traverser $traverser The traverser used in the rules.
|
||||
*
|
||||
* @return RulesInterface $this for the current object.
|
||||
*/
|
||||
public function setTraverser(Traverser $traverser);
|
||||
|
||||
/**
|
||||
* Write a document element (\DOMDocument).
|
||||
*
|
||||
* Instead of returning the result write it to the output stream ($output)
|
||||
* that was passed into the constructor.
|
||||
*
|
||||
* @param \DOMDocument $dom
|
||||
*/
|
||||
public function document($dom);
|
||||
|
||||
/**
|
||||
* Write an element.
|
||||
*
|
||||
* Instead of returning the result write it to the output stream ($output)
|
||||
* that was passed into the constructor.
|
||||
*
|
||||
* @param mixed $ele
|
||||
*/
|
||||
public function element($ele);
|
||||
|
||||
/**
|
||||
* Write a text node.
|
||||
*
|
||||
* Instead of returning the result write it to the output stream ($output)
|
||||
* that was passed into the constructor.
|
||||
*
|
||||
* @param mixed $ele
|
||||
*/
|
||||
public function text($ele);
|
||||
|
||||
/**
|
||||
* Write a CDATA node.
|
||||
*
|
||||
* Instead of returning the result write it to the output stream ($output)
|
||||
* that was passed into the constructor.
|
||||
*
|
||||
* @param mixed $ele
|
||||
*/
|
||||
public function cdata($ele);
|
||||
|
||||
/**
|
||||
* Write a comment node.
|
||||
*
|
||||
* Instead of returning the result write it to the output stream ($output)
|
||||
* that was passed into the constructor.
|
||||
*
|
||||
* @param mixed $ele
|
||||
*/
|
||||
public function comment($ele);
|
||||
|
||||
/**
|
||||
* Write a processor instruction.
|
||||
*
|
||||
* To learn about processor instructions see InstructionProcessor
|
||||
*
|
||||
* Instead of returning the result write it to the output stream ($output)
|
||||
* that was passed into the constructor.
|
||||
*
|
||||
* @param mixed $ele
|
||||
*/
|
||||
public function processorInstruction($ele);
|
||||
}
|
142
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Serializer/Traverser.php
vendored
Normal file
142
plugins/af_readability/vendor/masterminds/html5/src/HTML5/Serializer/Traverser.php
vendored
Normal file
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
|
||||
namespace Masterminds\HTML5\Serializer;
|
||||
|
||||
/**
|
||||
* Traverser for walking a DOM tree.
|
||||
*
|
||||
* This is a concrete traverser designed to convert a DOM tree into an
|
||||
* HTML5 document. It is not intended to be a generic DOMTreeWalker
|
||||
* implementation.
|
||||
*
|
||||
* @see http://www.w3.org/TR/2012/CR-html5-20121217/syntax.html#serializing-html-fragments
|
||||
*/
|
||||
class Traverser
|
||||
{
|
||||
/**
|
||||
* Namespaces that should be treated as "local" to HTML5.
|
||||
*/
|
||||
protected static $local_ns = array(
|
||||
'http://www.w3.org/1999/xhtml' => 'html',
|
||||
'http://www.w3.org/1998/Math/MathML' => 'math',
|
||||
'http://www.w3.org/2000/svg' => 'svg',
|
||||
);
|
||||
|
||||
protected $dom;
|
||||
|
||||
protected $options;
|
||||
|
||||
protected $encode = false;
|
||||
|
||||
protected $rules;
|
||||
|
||||
protected $out;
|
||||
|
||||
/**
|
||||
* Create a traverser.
|
||||
*
|
||||
* @param \DOMNode|\DOMNodeList $dom The document or node to traverse.
|
||||
* @param resource $out A stream that allows writing. The traverser will output into this
|
||||
* stream.
|
||||
* @param array $options An array of options for the traverser as key/value pairs. These include:
|
||||
* - encode_entities: A bool to specify if full encding should happen for all named
|
||||
* charachter references. Defaults to false which escapes &'<>".
|
||||
* - output_rules: The path to the class handling the output rules.
|
||||
*/
|
||||
public function __construct($dom, $out, RulesInterface $rules, $options = array())
|
||||
{
|
||||
$this->dom = $dom;
|
||||
$this->out = $out;
|
||||
$this->rules = $rules;
|
||||
$this->options = $options;
|
||||
|
||||
$this->rules->setTraverser($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the traverser to walk the DOM.
|
||||
*
|
||||
* @return resource $out Returns the output stream.
|
||||
*/
|
||||
public function walk()
|
||||
{
|
||||
if ($this->dom instanceof \DOMDocument) {
|
||||
$this->rules->document($this->dom);
|
||||
} elseif ($this->dom instanceof \DOMDocumentFragment) {
|
||||
// Document fragments are a special case. Only the children need to
|
||||
// be serialized.
|
||||
if ($this->dom->hasChildNodes()) {
|
||||
$this->children($this->dom->childNodes);
|
||||
}
|
||||
} // If NodeList, loop
|
||||
elseif ($this->dom instanceof \DOMNodeList) {
|
||||
// If this is a NodeList of DOMDocuments this will not work.
|
||||
$this->children($this->dom);
|
||||
} // Else assume this is a DOMNode-like datastructure.
|
||||
else {
|
||||
$this->node($this->dom);
|
||||
}
|
||||
|
||||
return $this->out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a node in the DOM.
|
||||
*
|
||||
* @param mixed $node A node implementing \DOMNode.
|
||||
*/
|
||||
public function node($node)
|
||||
{
|
||||
// A listing of types is at http://php.net/manual/en/dom.constants.php
|
||||
switch ($node->nodeType) {
|
||||
case XML_ELEMENT_NODE:
|
||||
$this->rules->element($node);
|
||||
break;
|
||||
case XML_TEXT_NODE:
|
||||
$this->rules->text($node);
|
||||
break;
|
||||
case XML_CDATA_SECTION_NODE:
|
||||
$this->rules->cdata($node);
|
||||
break;
|
||||
case XML_PI_NODE:
|
||||
$this->rules->processorInstruction($node);
|
||||
break;
|
||||
case XML_COMMENT_NODE:
|
||||
$this->rules->comment($node);
|
||||
break;
|
||||
// Currently we don't support embedding DTDs.
|
||||
default:
|
||||
//print '<!-- Skipped -->';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk through all the nodes on a node list.
|
||||
*
|
||||
* @param \DOMNodeList $nl A list of child elements to walk through.
|
||||
*/
|
||||
public function children($nl)
|
||||
{
|
||||
foreach ($nl as $node) {
|
||||
$this->node($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is an element local?
|
||||
*
|
||||
* @param mixed $ele An element that implement \DOMNode.
|
||||
*
|
||||
* @return bool true if local and false otherwise.
|
||||
*/
|
||||
public function isLocalElement($ele)
|
||||
{
|
||||
$uri = $ele->namespaceURI;
|
||||
if (empty($uri)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isset(static::$local_ns[$uri]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file, in reverse chronological order by release.
|
||||
|
||||
## 1.0.1 - 2016-08-06
|
||||
|
||||
### Added
|
||||
|
||||
- Nothing.
|
||||
|
||||
### Deprecated
|
||||
|
||||
- Nothing.
|
||||
|
||||
### Removed
|
||||
|
||||
- Nothing.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Updated all `@return self` annotation references in interfaces to use
|
||||
`@return static`, which more closelly follows the semantics of the
|
||||
specification.
|
||||
- Updated the `MessageInterface::getHeaders()` return annotation to use the
|
||||
value `string[][]`, indicating the format is a nested array of strings.
|
||||
- Updated the `@link` annotation for `RequestInterface::withRequestTarget()`
|
||||
to point to the correct section of RFC 7230.
|
||||
- Updated the `ServerRequestInterface::withUploadedFiles()` parameter annotation
|
||||
to add the parameter name (`$uploadedFiles`).
|
||||
- Updated a `@throws` annotation for the `UploadedFileInterface::moveTo()`
|
||||
method to correctly reference the method parameter (it was referencing an
|
||||
incorrect parameter name previously).
|
||||
|
||||
## 1.0.0 - 2016-05-18
|
||||
|
||||
Initial stable release; reflects accepted PSR-7 specification.
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2014 PHP Framework Interoperability Group
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,13 @@
|
|||
PSR Http Message
|
||||
================
|
||||
|
||||
This repository holds all interfaces/classes/traits related to
|
||||
[PSR-7](http://www.php-fig.org/psr/psr-7/).
|
||||
|
||||
Note that this is not a HTTP message implementation of its own. It is merely an
|
||||
interface that describes a HTTP message. See the specification for more details.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
We'll certainly need some stuff in here.
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "psr/http-message",
|
||||
"description": "Common interface for HTTP messages",
|
||||
"keywords": ["psr", "psr-7", "http", "http-message", "request", "response"],
|
||||
"homepage": "https://github.com/php-fig/http-message",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Http\\Message\\": "src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
<?php
|
||||
|
||||
namespace Psr\Http\Message;
|
||||
|
||||
/**
|
||||
* HTTP messages consist of requests from a client to a server and responses
|
||||
* from a server to a client. This interface defines the methods common to
|
||||
* each.
|
||||
*
|
||||
* Messages are considered immutable; all methods that might change state MUST
|
||||
* be implemented such that they retain the internal state of the current
|
||||
* message and return an instance that contains the changed state.
|
||||
*
|
||||
* @link http://www.ietf.org/rfc/rfc7230.txt
|
||||
* @link http://www.ietf.org/rfc/rfc7231.txt
|
||||
*/
|
||||
interface MessageInterface
|
||||
{
|
||||
/**
|
||||
* Retrieves the HTTP protocol version as a string.
|
||||
*
|
||||
* The string MUST contain only the HTTP version number (e.g., "1.1", "1.0").
|
||||
*
|
||||
* @return string HTTP protocol version.
|
||||
*/
|
||||
public function getProtocolVersion();
|
||||
|
||||
/**
|
||||
* Return an instance with the specified HTTP protocol version.
|
||||
*
|
||||
* The version string MUST contain only the HTTP version number (e.g.,
|
||||
* "1.1", "1.0").
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* new protocol version.
|
||||
*
|
||||
* @param string $version HTTP protocol version
|
||||
* @return static
|
||||
*/
|
||||
public function withProtocolVersion($version);
|
||||
|
||||
/**
|
||||
* Retrieves all message header values.
|
||||
*
|
||||
* The keys represent the header name as it will be sent over the wire, and
|
||||
* each value is an array of strings associated with the header.
|
||||
*
|
||||
* // Represent the headers as a string
|
||||
* foreach ($message->getHeaders() as $name => $values) {
|
||||
* echo $name . ": " . implode(", ", $values);
|
||||
* }
|
||||
*
|
||||
* // Emit headers iteratively:
|
||||
* foreach ($message->getHeaders() as $name => $values) {
|
||||
* foreach ($values as $value) {
|
||||
* header(sprintf('%s: %s', $name, $value), false);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* While header names are not case-sensitive, getHeaders() will preserve the
|
||||
* exact case in which headers were originally specified.
|
||||
*
|
||||
* @return string[][] Returns an associative array of the message's headers. Each
|
||||
* key MUST be a header name, and each value MUST be an array of strings
|
||||
* for that header.
|
||||
*/
|
||||
public function getHeaders();
|
||||
|
||||
/**
|
||||
* Checks if a header exists by the given case-insensitive name.
|
||||
*
|
||||
* @param string $name Case-insensitive header field name.
|
||||
* @return bool Returns true if any header names match the given header
|
||||
* name using a case-insensitive string comparison. Returns false if
|
||||
* no matching header name is found in the message.
|
||||
*/
|
||||
public function hasHeader($name);
|
||||
|
||||
/**
|
||||
* Retrieves a message header value by the given case-insensitive name.
|
||||
*
|
||||
* This method returns an array of all the header values of the given
|
||||
* case-insensitive header name.
|
||||
*
|
||||
* If the header does not appear in the message, this method MUST return an
|
||||
* empty array.
|
||||
*
|
||||
* @param string $name Case-insensitive header field name.
|
||||
* @return string[] An array of string values as provided for the given
|
||||
* header. If the header does not appear in the message, this method MUST
|
||||
* return an empty array.
|
||||
*/
|
||||
public function getHeader($name);
|
||||
|
||||
/**
|
||||
* Retrieves a comma-separated string of the values for a single header.
|
||||
*
|
||||
* This method returns all of the header values of the given
|
||||
* case-insensitive header name as a string concatenated together using
|
||||
* a comma.
|
||||
*
|
||||
* NOTE: Not all header values may be appropriately represented using
|
||||
* comma concatenation. For such headers, use getHeader() instead
|
||||
* and supply your own delimiter when concatenating.
|
||||
*
|
||||
* If the header does not appear in the message, this method MUST return
|
||||
* an empty string.
|
||||
*
|
||||
* @param string $name Case-insensitive header field name.
|
||||
* @return string A string of values as provided for the given header
|
||||
* concatenated together using a comma. If the header does not appear in
|
||||
* the message, this method MUST return an empty string.
|
||||
*/
|
||||
public function getHeaderLine($name);
|
||||
|
||||
/**
|
||||
* Return an instance with the provided value replacing the specified header.
|
||||
*
|
||||
* While header names are case-insensitive, the casing of the header will
|
||||
* be preserved by this function, and returned from getHeaders().
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* new and/or updated header and value.
|
||||
*
|
||||
* @param string $name Case-insensitive header field name.
|
||||
* @param string|string[] $value Header value(s).
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException for invalid header names or values.
|
||||
*/
|
||||
public function withHeader($name, $value);
|
||||
|
||||
/**
|
||||
* Return an instance with the specified header appended with the given value.
|
||||
*
|
||||
* Existing values for the specified header will be maintained. The new
|
||||
* value(s) will be appended to the existing list. If the header did not
|
||||
* exist previously, it will be added.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* new header and/or value.
|
||||
*
|
||||
* @param string $name Case-insensitive header field name to add.
|
||||
* @param string|string[] $value Header value(s).
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException for invalid header names or values.
|
||||
*/
|
||||
public function withAddedHeader($name, $value);
|
||||
|
||||
/**
|
||||
* Return an instance without the specified header.
|
||||
*
|
||||
* Header resolution MUST be done without case-sensitivity.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that removes
|
||||
* the named header.
|
||||
*
|
||||
* @param string $name Case-insensitive header field name to remove.
|
||||
* @return static
|
||||
*/
|
||||
public function withoutHeader($name);
|
||||
|
||||
/**
|
||||
* Gets the body of the message.
|
||||
*
|
||||
* @return StreamInterface Returns the body as a stream.
|
||||
*/
|
||||
public function getBody();
|
||||
|
||||
/**
|
||||
* Return an instance with the specified message body.
|
||||
*
|
||||
* The body MUST be a StreamInterface object.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return a new instance that has the
|
||||
* new body stream.
|
||||
*
|
||||
* @param StreamInterface $body Body.
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException When the body is not valid.
|
||||
*/
|
||||
public function withBody(StreamInterface $body);
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
|
||||
namespace Psr\Http\Message;
|
||||
|
||||
/**
|
||||
* Representation of an outgoing, client-side request.
|
||||
*
|
||||
* Per the HTTP specification, this interface includes properties for
|
||||
* each of the following:
|
||||
*
|
||||
* - Protocol version
|
||||
* - HTTP method
|
||||
* - URI
|
||||
* - Headers
|
||||
* - Message body
|
||||
*
|
||||
* During construction, implementations MUST attempt to set the Host header from
|
||||
* a provided URI if no Host header is provided.
|
||||
*
|
||||
* Requests are considered immutable; all methods that might change state MUST
|
||||
* be implemented such that they retain the internal state of the current
|
||||
* message and return an instance that contains the changed state.
|
||||
*/
|
||||
interface RequestInterface extends MessageInterface
|
||||
{
|
||||
/**
|
||||
* Retrieves the message's request target.
|
||||
*
|
||||
* Retrieves the message's request-target either as it will appear (for
|
||||
* clients), as it appeared at request (for servers), or as it was
|
||||
* specified for the instance (see withRequestTarget()).
|
||||
*
|
||||
* In most cases, this will be the origin-form of the composed URI,
|
||||
* unless a value was provided to the concrete implementation (see
|
||||
* withRequestTarget() below).
|
||||
*
|
||||
* If no URI is available, and no request-target has been specifically
|
||||
* provided, this method MUST return the string "/".
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRequestTarget();
|
||||
|
||||
/**
|
||||
* Return an instance with the specific request-target.
|
||||
*
|
||||
* If the request needs a non-origin-form request-target — e.g., for
|
||||
* specifying an absolute-form, authority-form, or asterisk-form —
|
||||
* this method may be used to create an instance with the specified
|
||||
* request-target, verbatim.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* changed request target.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc7230#section-5.3 (for the various
|
||||
* request-target forms allowed in request messages)
|
||||
* @param mixed $requestTarget
|
||||
* @return static
|
||||
*/
|
||||
public function withRequestTarget($requestTarget);
|
||||
|
||||
/**
|
||||
* Retrieves the HTTP method of the request.
|
||||
*
|
||||
* @return string Returns the request method.
|
||||
*/
|
||||
public function getMethod();
|
||||
|
||||
/**
|
||||
* Return an instance with the provided HTTP method.
|
||||
*
|
||||
* While HTTP method names are typically all uppercase characters, HTTP
|
||||
* method names are case-sensitive and thus implementations SHOULD NOT
|
||||
* modify the given string.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* changed request method.
|
||||
*
|
||||
* @param string $method Case-sensitive method.
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException for invalid HTTP methods.
|
||||
*/
|
||||
public function withMethod($method);
|
||||
|
||||
/**
|
||||
* Retrieves the URI instance.
|
||||
*
|
||||
* This method MUST return a UriInterface instance.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc3986#section-4.3
|
||||
* @return UriInterface Returns a UriInterface instance
|
||||
* representing the URI of the request.
|
||||
*/
|
||||
public function getUri();
|
||||
|
||||
/**
|
||||
* Returns an instance with the provided URI.
|
||||
*
|
||||
* This method MUST update the Host header of the returned request by
|
||||
* default if the URI contains a host component. If the URI does not
|
||||
* contain a host component, any pre-existing Host header MUST be carried
|
||||
* over to the returned request.
|
||||
*
|
||||
* You can opt-in to preserving the original state of the Host header by
|
||||
* setting `$preserveHost` to `true`. When `$preserveHost` is set to
|
||||
* `true`, this method interacts with the Host header in the following ways:
|
||||
*
|
||||
* - If the Host header is missing or empty, and the new URI contains
|
||||
* a host component, this method MUST update the Host header in the returned
|
||||
* request.
|
||||
* - If the Host header is missing or empty, and the new URI does not contain a
|
||||
* host component, this method MUST NOT update the Host header in the returned
|
||||
* request.
|
||||
* - If a Host header is present and non-empty, this method MUST NOT update
|
||||
* the Host header in the returned request.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* new UriInterface instance.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc3986#section-4.3
|
||||
* @param UriInterface $uri New request URI to use.
|
||||
* @param bool $preserveHost Preserve the original state of the Host header.
|
||||
* @return static
|
||||
*/
|
||||
public function withUri(UriInterface $uri, $preserveHost = false);
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace Psr\Http\Message;
|
||||
|
||||
/**
|
||||
* Representation of an outgoing, server-side response.
|
||||
*
|
||||
* Per the HTTP specification, this interface includes properties for
|
||||
* each of the following:
|
||||
*
|
||||
* - Protocol version
|
||||
* - Status code and reason phrase
|
||||
* - Headers
|
||||
* - Message body
|
||||
*
|
||||
* Responses are considered immutable; all methods that might change state MUST
|
||||
* be implemented such that they retain the internal state of the current
|
||||
* message and return an instance that contains the changed state.
|
||||
*/
|
||||
interface ResponseInterface extends MessageInterface
|
||||
{
|
||||
/**
|
||||
* Gets the response status code.
|
||||
*
|
||||
* The status code is a 3-digit integer result code of the server's attempt
|
||||
* to understand and satisfy the request.
|
||||
*
|
||||
* @return int Status code.
|
||||
*/
|
||||
public function getStatusCode();
|
||||
|
||||
/**
|
||||
* Return an instance with the specified status code and, optionally, reason phrase.
|
||||
*
|
||||
* If no reason phrase is specified, implementations MAY choose to default
|
||||
* to the RFC 7231 or IANA recommended reason phrase for the response's
|
||||
* status code.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* updated status and reason phrase.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc7231#section-6
|
||||
* @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
||||
* @param int $code The 3-digit integer result code to set.
|
||||
* @param string $reasonPhrase The reason phrase to use with the
|
||||
* provided status code; if none is provided, implementations MAY
|
||||
* use the defaults as suggested in the HTTP specification.
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException For invalid status code arguments.
|
||||
*/
|
||||
public function withStatus($code, $reasonPhrase = '');
|
||||
|
||||
/**
|
||||
* Gets the response reason phrase associated with the status code.
|
||||
*
|
||||
* Because a reason phrase is not a required element in a response
|
||||
* status line, the reason phrase value MAY be null. Implementations MAY
|
||||
* choose to return the default RFC 7231 recommended reason phrase (or those
|
||||
* listed in the IANA HTTP Status Code Registry) for the response's
|
||||
* status code.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc7231#section-6
|
||||
* @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
||||
* @return string Reason phrase; must return an empty string if none present.
|
||||
*/
|
||||
public function getReasonPhrase();
|
||||
}
|
261
plugins/af_readability/vendor/psr/http-message/src/ServerRequestInterface.php
vendored
Normal file
261
plugins/af_readability/vendor/psr/http-message/src/ServerRequestInterface.php
vendored
Normal file
|
@ -0,0 +1,261 @@
|
|||
<?php
|
||||
|
||||
namespace Psr\Http\Message;
|
||||
|
||||
/**
|
||||
* Representation of an incoming, server-side HTTP request.
|
||||
*
|
||||
* Per the HTTP specification, this interface includes properties for
|
||||
* each of the following:
|
||||
*
|
||||
* - Protocol version
|
||||
* - HTTP method
|
||||
* - URI
|
||||
* - Headers
|
||||
* - Message body
|
||||
*
|
||||
* Additionally, it encapsulates all data as it has arrived to the
|
||||
* application from the CGI and/or PHP environment, including:
|
||||
*
|
||||
* - The values represented in $_SERVER.
|
||||
* - Any cookies provided (generally via $_COOKIE)
|
||||
* - Query string arguments (generally via $_GET, or as parsed via parse_str())
|
||||
* - Upload files, if any (as represented by $_FILES)
|
||||
* - Deserialized body parameters (generally from $_POST)
|
||||
*
|
||||
* $_SERVER values MUST be treated as immutable, as they represent application
|
||||
* state at the time of request; as such, no methods are provided to allow
|
||||
* modification of those values. The other values provide such methods, as they
|
||||
* can be restored from $_SERVER or the request body, and may need treatment
|
||||
* during the application (e.g., body parameters may be deserialized based on
|
||||
* content type).
|
||||
*
|
||||
* Additionally, this interface recognizes the utility of introspecting a
|
||||
* request to derive and match additional parameters (e.g., via URI path
|
||||
* matching, decrypting cookie values, deserializing non-form-encoded body
|
||||
* content, matching authorization headers to users, etc). These parameters
|
||||
* are stored in an "attributes" property.
|
||||
*
|
||||
* Requests are considered immutable; all methods that might change state MUST
|
||||
* be implemented such that they retain the internal state of the current
|
||||
* message and return an instance that contains the changed state.
|
||||
*/
|
||||
interface ServerRequestInterface extends RequestInterface
|
||||
{
|
||||
/**
|
||||
* Retrieve server parameters.
|
||||
*
|
||||
* Retrieves data related to the incoming request environment,
|
||||
* typically derived from PHP's $_SERVER superglobal. The data IS NOT
|
||||
* REQUIRED to originate from $_SERVER.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getServerParams();
|
||||
|
||||
/**
|
||||
* Retrieve cookies.
|
||||
*
|
||||
* Retrieves cookies sent by the client to the server.
|
||||
*
|
||||
* The data MUST be compatible with the structure of the $_COOKIE
|
||||
* superglobal.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCookieParams();
|
||||
|
||||
/**
|
||||
* Return an instance with the specified cookies.
|
||||
*
|
||||
* The data IS NOT REQUIRED to come from the $_COOKIE superglobal, but MUST
|
||||
* be compatible with the structure of $_COOKIE. Typically, this data will
|
||||
* be injected at instantiation.
|
||||
*
|
||||
* This method MUST NOT update the related Cookie header of the request
|
||||
* instance, nor related values in the server params.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* updated cookie values.
|
||||
*
|
||||
* @param array $cookies Array of key/value pairs representing cookies.
|
||||
* @return static
|
||||
*/
|
||||
public function withCookieParams(array $cookies);
|
||||
|
||||
/**
|
||||
* Retrieve query string arguments.
|
||||
*
|
||||
* Retrieves the deserialized query string arguments, if any.
|
||||
*
|
||||
* Note: the query params might not be in sync with the URI or server
|
||||
* params. If you need to ensure you are only getting the original
|
||||
* values, you may need to parse the query string from `getUri()->getQuery()`
|
||||
* or from the `QUERY_STRING` server param.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getQueryParams();
|
||||
|
||||
/**
|
||||
* Return an instance with the specified query string arguments.
|
||||
*
|
||||
* These values SHOULD remain immutable over the course of the incoming
|
||||
* request. They MAY be injected during instantiation, such as from PHP's
|
||||
* $_GET superglobal, or MAY be derived from some other value such as the
|
||||
* URI. In cases where the arguments are parsed from the URI, the data
|
||||
* MUST be compatible with what PHP's parse_str() would return for
|
||||
* purposes of how duplicate query parameters are handled, and how nested
|
||||
* sets are handled.
|
||||
*
|
||||
* Setting query string arguments MUST NOT change the URI stored by the
|
||||
* request, nor the values in the server params.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* updated query string arguments.
|
||||
*
|
||||
* @param array $query Array of query string arguments, typically from
|
||||
* $_GET.
|
||||
* @return static
|
||||
*/
|
||||
public function withQueryParams(array $query);
|
||||
|
||||
/**
|
||||
* Retrieve normalized file upload data.
|
||||
*
|
||||
* This method returns upload metadata in a normalized tree, with each leaf
|
||||
* an instance of Psr\Http\Message\UploadedFileInterface.
|
||||
*
|
||||
* These values MAY be prepared from $_FILES or the message body during
|
||||
* instantiation, or MAY be injected via withUploadedFiles().
|
||||
*
|
||||
* @return array An array tree of UploadedFileInterface instances; an empty
|
||||
* array MUST be returned if no data is present.
|
||||
*/
|
||||
public function getUploadedFiles();
|
||||
|
||||
/**
|
||||
* Create a new instance with the specified uploaded files.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* updated body parameters.
|
||||
*
|
||||
* @param array $uploadedFiles An array tree of UploadedFileInterface instances.
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException if an invalid structure is provided.
|
||||
*/
|
||||
public function withUploadedFiles(array $uploadedFiles);
|
||||
|
||||
/**
|
||||
* Retrieve any parameters provided in the request body.
|
||||
*
|
||||
* If the request Content-Type is either application/x-www-form-urlencoded
|
||||
* or multipart/form-data, and the request method is POST, this method MUST
|
||||
* return the contents of $_POST.
|
||||
*
|
||||
* Otherwise, this method may return any results of deserializing
|
||||
* the request body content; as parsing returns structured content, the
|
||||
* potential types MUST be arrays or objects only. A null value indicates
|
||||
* the absence of body content.
|
||||
*
|
||||
* @return null|array|object The deserialized body parameters, if any.
|
||||
* These will typically be an array or object.
|
||||
*/
|
||||
public function getParsedBody();
|
||||
|
||||
/**
|
||||
* Return an instance with the specified body parameters.
|
||||
*
|
||||
* These MAY be injected during instantiation.
|
||||
*
|
||||
* If the request Content-Type is either application/x-www-form-urlencoded
|
||||
* or multipart/form-data, and the request method is POST, use this method
|
||||
* ONLY to inject the contents of $_POST.
|
||||
*
|
||||
* The data IS NOT REQUIRED to come from $_POST, but MUST be the results of
|
||||
* deserializing the request body content. Deserialization/parsing returns
|
||||
* structured data, and, as such, this method ONLY accepts arrays or objects,
|
||||
* or a null value if nothing was available to parse.
|
||||
*
|
||||
* As an example, if content negotiation determines that the request data
|
||||
* is a JSON payload, this method could be used to create a request
|
||||
* instance with the deserialized parameters.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* updated body parameters.
|
||||
*
|
||||
* @param null|array|object $data The deserialized body data. This will
|
||||
* typically be in an array or object.
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException if an unsupported argument type is
|
||||
* provided.
|
||||
*/
|
||||
public function withParsedBody($data);
|
||||
|
||||
/**
|
||||
* Retrieve attributes derived from the request.
|
||||
*
|
||||
* The request "attributes" may be used to allow injection of any
|
||||
* parameters derived from the request: e.g., the results of path
|
||||
* match operations; the results of decrypting cookies; the results of
|
||||
* deserializing non-form-encoded message bodies; etc. Attributes
|
||||
* will be application and request specific, and CAN be mutable.
|
||||
*
|
||||
* @return array Attributes derived from the request.
|
||||
*/
|
||||
public function getAttributes();
|
||||
|
||||
/**
|
||||
* Retrieve a single derived request attribute.
|
||||
*
|
||||
* Retrieves a single derived request attribute as described in
|
||||
* getAttributes(). If the attribute has not been previously set, returns
|
||||
* the default value as provided.
|
||||
*
|
||||
* This method obviates the need for a hasAttribute() method, as it allows
|
||||
* specifying a default value to return if the attribute is not found.
|
||||
*
|
||||
* @see getAttributes()
|
||||
* @param string $name The attribute name.
|
||||
* @param mixed $default Default value to return if the attribute does not exist.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAttribute($name, $default = null);
|
||||
|
||||
/**
|
||||
* Return an instance with the specified derived request attribute.
|
||||
*
|
||||
* This method allows setting a single derived request attribute as
|
||||
* described in getAttributes().
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* updated attribute.
|
||||
*
|
||||
* @see getAttributes()
|
||||
* @param string $name The attribute name.
|
||||
* @param mixed $value The value of the attribute.
|
||||
* @return static
|
||||
*/
|
||||
public function withAttribute($name, $value);
|
||||
|
||||
/**
|
||||
* Return an instance that removes the specified derived request attribute.
|
||||
*
|
||||
* This method allows removing a single derived request attribute as
|
||||
* described in getAttributes().
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that removes
|
||||
* the attribute.
|
||||
*
|
||||
* @see getAttributes()
|
||||
* @param string $name The attribute name.
|
||||
* @return static
|
||||
*/
|
||||
public function withoutAttribute($name);
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
namespace Psr\Http\Message;
|
||||
|
||||
/**
|
||||
* Describes a data stream.
|
||||
*
|
||||
* Typically, an instance will wrap a PHP stream; this interface provides
|
||||
* a wrapper around the most common operations, including serialization of
|
||||
* the entire stream to a string.
|
||||
*/
|
||||
interface StreamInterface
|
||||
{
|
||||
/**
|
||||
* Reads all data from the stream into a string, from the beginning to end.
|
||||
*
|
||||
* This method MUST attempt to seek to the beginning of the stream before
|
||||
* reading data and read the stream until the end is reached.
|
||||
*
|
||||
* Warning: This could attempt to load a large amount of data into memory.
|
||||
*
|
||||
* This method MUST NOT raise an exception in order to conform with PHP's
|
||||
* string casting operations.
|
||||
*
|
||||
* @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
|
||||
* @return string
|
||||
*/
|
||||
public function __toString();
|
||||
|
||||
/**
|
||||
* Closes the stream and any underlying resources.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function close();
|
||||
|
||||
/**
|
||||
* Separates any underlying resources from the stream.
|
||||
*
|
||||
* After the stream has been detached, the stream is in an unusable state.
|
||||
*
|
||||
* @return resource|null Underlying PHP stream, if any
|
||||
*/
|
||||
public function detach();
|
||||
|
||||
/**
|
||||
* Get the size of the stream if known.
|
||||
*
|
||||
* @return int|null Returns the size in bytes if known, or null if unknown.
|
||||
*/
|
||||
public function getSize();
|
||||
|
||||
/**
|
||||
* Returns the current position of the file read/write pointer
|
||||
*
|
||||
* @return int Position of the file pointer
|
||||
* @throws \RuntimeException on error.
|
||||
*/
|
||||
public function tell();
|
||||
|
||||
/**
|
||||
* Returns true if the stream is at the end of the stream.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function eof();
|
||||
|
||||
/**
|
||||
* Returns whether or not the stream is seekable.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSeekable();
|
||||
|
||||
/**
|
||||
* Seek to a position in the stream.
|
||||
*
|
||||
* @link http://www.php.net/manual/en/function.fseek.php
|
||||
* @param int $offset Stream offset
|
||||
* @param int $whence Specifies how the cursor position will be calculated
|
||||
* based on the seek offset. Valid values are identical to the built-in
|
||||
* PHP $whence values for `fseek()`. SEEK_SET: Set position equal to
|
||||
* offset bytes SEEK_CUR: Set position to current location plus offset
|
||||
* SEEK_END: Set position to end-of-stream plus offset.
|
||||
* @throws \RuntimeException on failure.
|
||||
*/
|
||||
public function seek($offset, $whence = SEEK_SET);
|
||||
|
||||
/**
|
||||
* Seek to the beginning of the stream.
|
||||
*
|
||||
* If the stream is not seekable, this method will raise an exception;
|
||||
* otherwise, it will perform a seek(0).
|
||||
*
|
||||
* @see seek()
|
||||
* @link http://www.php.net/manual/en/function.fseek.php
|
||||
* @throws \RuntimeException on failure.
|
||||
*/
|
||||
public function rewind();
|
||||
|
||||
/**
|
||||
* Returns whether or not the stream is writable.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isWritable();
|
||||
|
||||
/**
|
||||
* Write data to the stream.
|
||||
*
|
||||
* @param string $string The string that is to be written.
|
||||
* @return int Returns the number of bytes written to the stream.
|
||||
* @throws \RuntimeException on failure.
|
||||
*/
|
||||
public function write($string);
|
||||
|
||||
/**
|
||||
* Returns whether or not the stream is readable.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isReadable();
|
||||
|
||||
/**
|
||||
* Read data from the stream.
|
||||
*
|
||||
* @param int $length Read up to $length bytes from the object and return
|
||||
* them. Fewer than $length bytes may be returned if underlying stream
|
||||
* call returns fewer bytes.
|
||||
* @return string Returns the data read from the stream, or an empty string
|
||||
* if no bytes are available.
|
||||
* @throws \RuntimeException if an error occurs.
|
||||
*/
|
||||
public function read($length);
|
||||
|
||||
/**
|
||||
* Returns the remaining contents in a string
|
||||
*
|
||||
* @return string
|
||||
* @throws \RuntimeException if unable to read or an error occurs while
|
||||
* reading.
|
||||
*/
|
||||
public function getContents();
|
||||
|
||||
/**
|
||||
* Get stream metadata as an associative array or retrieve a specific key.
|
||||
*
|
||||
* The keys returned are identical to the keys returned from PHP's
|
||||
* stream_get_meta_data() function.
|
||||
*
|
||||
* @link http://php.net/manual/en/function.stream-get-meta-data.php
|
||||
* @param string $key Specific metadata to retrieve.
|
||||
* @return array|mixed|null Returns an associative array if no key is
|
||||
* provided. Returns a specific key value if a key is provided and the
|
||||
* value is found, or null if the key is not found.
|
||||
*/
|
||||
public function getMetadata($key = null);
|
||||
}
|
123
plugins/af_readability/vendor/psr/http-message/src/UploadedFileInterface.php
vendored
Normal file
123
plugins/af_readability/vendor/psr/http-message/src/UploadedFileInterface.php
vendored
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
namespace Psr\Http\Message;
|
||||
|
||||
/**
|
||||
* Value object representing a file uploaded through an HTTP request.
|
||||
*
|
||||
* Instances of this interface are considered immutable; all methods that
|
||||
* might change state MUST be implemented such that they retain the internal
|
||||
* state of the current instance and return an instance that contains the
|
||||
* changed state.
|
||||
*/
|
||||
interface UploadedFileInterface
|
||||
{
|
||||
/**
|
||||
* Retrieve a stream representing the uploaded file.
|
||||
*
|
||||
* This method MUST return a StreamInterface instance, representing the
|
||||
* uploaded file. The purpose of this method is to allow utilizing native PHP
|
||||
* stream functionality to manipulate the file upload, such as
|
||||
* stream_copy_to_stream() (though the result will need to be decorated in a
|
||||
* native PHP stream wrapper to work with such functions).
|
||||
*
|
||||
* If the moveTo() method has been called previously, this method MUST raise
|
||||
* an exception.
|
||||
*
|
||||
* @return StreamInterface Stream representation of the uploaded file.
|
||||
* @throws \RuntimeException in cases when no stream is available or can be
|
||||
* created.
|
||||
*/
|
||||
public function getStream();
|
||||
|
||||
/**
|
||||
* Move the uploaded file to a new location.
|
||||
*
|
||||
* Use this method as an alternative to move_uploaded_file(). This method is
|
||||
* guaranteed to work in both SAPI and non-SAPI environments.
|
||||
* Implementations must determine which environment they are in, and use the
|
||||
* appropriate method (move_uploaded_file(), rename(), or a stream
|
||||
* operation) to perform the operation.
|
||||
*
|
||||
* $targetPath may be an absolute path, or a relative path. If it is a
|
||||
* relative path, resolution should be the same as used by PHP's rename()
|
||||
* function.
|
||||
*
|
||||
* The original file or stream MUST be removed on completion.
|
||||
*
|
||||
* If this method is called more than once, any subsequent calls MUST raise
|
||||
* an exception.
|
||||
*
|
||||
* When used in an SAPI environment where $_FILES is populated, when writing
|
||||
* files via moveTo(), is_uploaded_file() and move_uploaded_file() SHOULD be
|
||||
* used to ensure permissions and upload status are verified correctly.
|
||||
*
|
||||
* If you wish to move to a stream, use getStream(), as SAPI operations
|
||||
* cannot guarantee writing to stream destinations.
|
||||
*
|
||||
* @see http://php.net/is_uploaded_file
|
||||
* @see http://php.net/move_uploaded_file
|
||||
* @param string $targetPath Path to which to move the uploaded file.
|
||||
* @throws \InvalidArgumentException if the $targetPath specified is invalid.
|
||||
* @throws \RuntimeException on any error during the move operation, or on
|
||||
* the second or subsequent call to the method.
|
||||
*/
|
||||
public function moveTo($targetPath);
|
||||
|
||||
/**
|
||||
* Retrieve the file size.
|
||||
*
|
||||
* Implementations SHOULD return the value stored in the "size" key of
|
||||
* the file in the $_FILES array if available, as PHP calculates this based
|
||||
* on the actual size transmitted.
|
||||
*
|
||||
* @return int|null The file size in bytes or null if unknown.
|
||||
*/
|
||||
public function getSize();
|
||||
|
||||
/**
|
||||
* Retrieve the error associated with the uploaded file.
|
||||
*
|
||||
* The return value MUST be one of PHP's UPLOAD_ERR_XXX constants.
|
||||
*
|
||||
* If the file was uploaded successfully, this method MUST return
|
||||
* UPLOAD_ERR_OK.
|
||||
*
|
||||
* Implementations SHOULD return the value stored in the "error" key of
|
||||
* the file in the $_FILES array.
|
||||
*
|
||||
* @see http://php.net/manual/en/features.file-upload.errors.php
|
||||
* @return int One of PHP's UPLOAD_ERR_XXX constants.
|
||||
*/
|
||||
public function getError();
|
||||
|
||||
/**
|
||||
* Retrieve the filename sent by the client.
|
||||
*
|
||||
* Do not trust the value returned by this method. A client could send
|
||||
* a malicious filename with the intention to corrupt or hack your
|
||||
* application.
|
||||
*
|
||||
* Implementations SHOULD return the value stored in the "name" key of
|
||||
* the file in the $_FILES array.
|
||||
*
|
||||
* @return string|null The filename sent by the client or null if none
|
||||
* was provided.
|
||||
*/
|
||||
public function getClientFilename();
|
||||
|
||||
/**
|
||||
* Retrieve the media type sent by the client.
|
||||
*
|
||||
* Do not trust the value returned by this method. A client could send
|
||||
* a malicious media type with the intention to corrupt or hack your
|
||||
* application.
|
||||
*
|
||||
* Implementations SHOULD return the value stored in the "type" key of
|
||||
* the file in the $_FILES array.
|
||||
*
|
||||
* @return string|null The media type sent by the client or null if none
|
||||
* was provided.
|
||||
*/
|
||||
public function getClientMediaType();
|
||||
}
|
|
@ -0,0 +1,323 @@
|
|||
<?php
|
||||
namespace Psr\Http\Message;
|
||||
|
||||
/**
|
||||
* Value object representing a URI.
|
||||
*
|
||||
* This interface is meant to represent URIs according to RFC 3986 and to
|
||||
* provide methods for most common operations. Additional functionality for
|
||||
* working with URIs can be provided on top of the interface or externally.
|
||||
* Its primary use is for HTTP requests, but may also be used in other
|
||||
* contexts.
|
||||
*
|
||||
* Instances of this interface are considered immutable; all methods that
|
||||
* might change state MUST be implemented such that they retain the internal
|
||||
* state of the current instance and return an instance that contains the
|
||||
* changed state.
|
||||
*
|
||||
* Typically the Host header will be also be present in the request message.
|
||||
* For server-side requests, the scheme will typically be discoverable in the
|
||||
* server parameters.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc3986 (the URI specification)
|
||||
*/
|
||||
interface UriInterface
|
||||
{
|
||||
/**
|
||||
* Retrieve the scheme component of the URI.
|
||||
*
|
||||
* If no scheme is present, this method MUST return an empty string.
|
||||
*
|
||||
* The value returned MUST be normalized to lowercase, per RFC 3986
|
||||
* Section 3.1.
|
||||
*
|
||||
* The trailing ":" character is not part of the scheme and MUST NOT be
|
||||
* added.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.1
|
||||
* @return string The URI scheme.
|
||||
*/
|
||||
public function getScheme();
|
||||
|
||||
/**
|
||||
* Retrieve the authority component of the URI.
|
||||
*
|
||||
* If no authority information is present, this method MUST return an empty
|
||||
* string.
|
||||
*
|
||||
* The authority syntax of the URI is:
|
||||
*
|
||||
* <pre>
|
||||
* [user-info@]host[:port]
|
||||
* </pre>
|
||||
*
|
||||
* If the port component is not set or is the standard port for the current
|
||||
* scheme, it SHOULD NOT be included.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.2
|
||||
* @return string The URI authority, in "[user-info@]host[:port]" format.
|
||||
*/
|
||||
public function getAuthority();
|
||||
|
||||
/**
|
||||
* Retrieve the user information component of the URI.
|
||||
*
|
||||
* If no user information is present, this method MUST return an empty
|
||||
* string.
|
||||
*
|
||||
* If a user is present in the URI, this will return that value;
|
||||
* additionally, if the password is also present, it will be appended to the
|
||||
* user value, with a colon (":") separating the values.
|
||||
*
|
||||
* The trailing "@" character is not part of the user information and MUST
|
||||
* NOT be added.
|
||||
*
|
||||
* @return string The URI user information, in "username[:password]" format.
|
||||
*/
|
||||
public function getUserInfo();
|
||||
|
||||
/**
|
||||
* Retrieve the host component of the URI.
|
||||
*
|
||||
* If no host is present, this method MUST return an empty string.
|
||||
*
|
||||
* The value returned MUST be normalized to lowercase, per RFC 3986
|
||||
* Section 3.2.2.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
* @return string The URI host.
|
||||
*/
|
||||
public function getHost();
|
||||
|
||||
/**
|
||||
* Retrieve the port component of the URI.
|
||||
*
|
||||
* If a port is present, and it is non-standard for the current scheme,
|
||||
* this method MUST return it as an integer. If the port is the standard port
|
||||
* used with the current scheme, this method SHOULD return null.
|
||||
*
|
||||
* If no port is present, and no scheme is present, this method MUST return
|
||||
* a null value.
|
||||
*
|
||||
* If no port is present, but a scheme is present, this method MAY return
|
||||
* the standard port for that scheme, but SHOULD return null.
|
||||
*
|
||||
* @return null|int The URI port.
|
||||
*/
|
||||
public function getPort();
|
||||
|
||||
/**
|
||||
* Retrieve the path component of the URI.
|
||||
*
|
||||
* The path can either be empty or absolute (starting with a slash) or
|
||||
* rootless (not starting with a slash). Implementations MUST support all
|
||||
* three syntaxes.
|
||||
*
|
||||
* Normally, the empty path "" and absolute path "/" are considered equal as
|
||||
* defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically
|
||||
* do this normalization because in contexts with a trimmed base path, e.g.
|
||||
* the front controller, this difference becomes significant. It's the task
|
||||
* of the user to handle both "" and "/".
|
||||
*
|
||||
* The value returned MUST be percent-encoded, but MUST NOT double-encode
|
||||
* any characters. To determine what characters to encode, please refer to
|
||||
* RFC 3986, Sections 2 and 3.3.
|
||||
*
|
||||
* As an example, if the value should include a slash ("/") not intended as
|
||||
* delimiter between path segments, that value MUST be passed in encoded
|
||||
* form (e.g., "%2F") to the instance.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-2
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.3
|
||||
* @return string The URI path.
|
||||
*/
|
||||
public function getPath();
|
||||
|
||||
/**
|
||||
* Retrieve the query string of the URI.
|
||||
*
|
||||
* If no query string is present, this method MUST return an empty string.
|
||||
*
|
||||
* The leading "?" character is not part of the query and MUST NOT be
|
||||
* added.
|
||||
*
|
||||
* The value returned MUST be percent-encoded, but MUST NOT double-encode
|
||||
* any characters. To determine what characters to encode, please refer to
|
||||
* RFC 3986, Sections 2 and 3.4.
|
||||
*
|
||||
* As an example, if a value in a key/value pair of the query string should
|
||||
* include an ampersand ("&") not intended as a delimiter between values,
|
||||
* that value MUST be passed in encoded form (e.g., "%26") to the instance.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-2
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.4
|
||||
* @return string The URI query string.
|
||||
*/
|
||||
public function getQuery();
|
||||
|
||||
/**
|
||||
* Retrieve the fragment component of the URI.
|
||||
*
|
||||
* If no fragment is present, this method MUST return an empty string.
|
||||
*
|
||||
* The leading "#" character is not part of the fragment and MUST NOT be
|
||||
* added.
|
||||
*
|
||||
* The value returned MUST be percent-encoded, but MUST NOT double-encode
|
||||
* any characters. To determine what characters to encode, please refer to
|
||||
* RFC 3986, Sections 2 and 3.5.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-2
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.5
|
||||
* @return string The URI fragment.
|
||||
*/
|
||||
public function getFragment();
|
||||
|
||||
/**
|
||||
* Return an instance with the specified scheme.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified scheme.
|
||||
*
|
||||
* Implementations MUST support the schemes "http" and "https" case
|
||||
* insensitively, and MAY accommodate other schemes if required.
|
||||
*
|
||||
* An empty scheme is equivalent to removing the scheme.
|
||||
*
|
||||
* @param string $scheme The scheme to use with the new instance.
|
||||
* @return static A new instance with the specified scheme.
|
||||
* @throws \InvalidArgumentException for invalid or unsupported schemes.
|
||||
*/
|
||||
public function withScheme($scheme);
|
||||
|
||||
/**
|
||||
* Return an instance with the specified user information.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified user information.
|
||||
*
|
||||
* Password is optional, but the user information MUST include the
|
||||
* user; an empty string for the user is equivalent to removing user
|
||||
* information.
|
||||
*
|
||||
* @param string $user The user name to use for authority.
|
||||
* @param null|string $password The password associated with $user.
|
||||
* @return static A new instance with the specified user information.
|
||||
*/
|
||||
public function withUserInfo($user, $password = null);
|
||||
|
||||
/**
|
||||
* Return an instance with the specified host.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified host.
|
||||
*
|
||||
* An empty host value is equivalent to removing the host.
|
||||
*
|
||||
* @param string $host The hostname to use with the new instance.
|
||||
* @return static A new instance with the specified host.
|
||||
* @throws \InvalidArgumentException for invalid hostnames.
|
||||
*/
|
||||
public function withHost($host);
|
||||
|
||||
/**
|
||||
* Return an instance with the specified port.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified port.
|
||||
*
|
||||
* Implementations MUST raise an exception for ports outside the
|
||||
* established TCP and UDP port ranges.
|
||||
*
|
||||
* A null value provided for the port is equivalent to removing the port
|
||||
* information.
|
||||
*
|
||||
* @param null|int $port The port to use with the new instance; a null value
|
||||
* removes the port information.
|
||||
* @return static A new instance with the specified port.
|
||||
* @throws \InvalidArgumentException for invalid ports.
|
||||
*/
|
||||
public function withPort($port);
|
||||
|
||||
/**
|
||||
* Return an instance with the specified path.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified path.
|
||||
*
|
||||
* The path can either be empty or absolute (starting with a slash) or
|
||||
* rootless (not starting with a slash). Implementations MUST support all
|
||||
* three syntaxes.
|
||||
*
|
||||
* If the path is intended to be domain-relative rather than path relative then
|
||||
* it must begin with a slash ("/"). Paths not starting with a slash ("/")
|
||||
* are assumed to be relative to some base path known to the application or
|
||||
* consumer.
|
||||
*
|
||||
* Users can provide both encoded and decoded path characters.
|
||||
* Implementations ensure the correct encoding as outlined in getPath().
|
||||
*
|
||||
* @param string $path The path to use with the new instance.
|
||||
* @return static A new instance with the specified path.
|
||||
* @throws \InvalidArgumentException for invalid paths.
|
||||
*/
|
||||
public function withPath($path);
|
||||
|
||||
/**
|
||||
* Return an instance with the specified query string.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified query string.
|
||||
*
|
||||
* Users can provide both encoded and decoded query characters.
|
||||
* Implementations ensure the correct encoding as outlined in getQuery().
|
||||
*
|
||||
* An empty query string value is equivalent to removing the query string.
|
||||
*
|
||||
* @param string $query The query string to use with the new instance.
|
||||
* @return static A new instance with the specified query string.
|
||||
* @throws \InvalidArgumentException for invalid query strings.
|
||||
*/
|
||||
public function withQuery($query);
|
||||
|
||||
/**
|
||||
* Return an instance with the specified URI fragment.
|
||||
*
|
||||
* This method MUST retain the state of the current instance, and return
|
||||
* an instance that contains the specified URI fragment.
|
||||
*
|
||||
* Users can provide both encoded and decoded fragment characters.
|
||||
* Implementations ensure the correct encoding as outlined in getFragment().
|
||||
*
|
||||
* An empty fragment value is equivalent to removing the fragment.
|
||||
*
|
||||
* @param string $fragment The fragment to use with the new instance.
|
||||
* @return static A new instance with the specified fragment.
|
||||
*/
|
||||
public function withFragment($fragment);
|
||||
|
||||
/**
|
||||
* Return the string representation as a URI reference.
|
||||
*
|
||||
* Depending on which components of the URI are present, the resulting
|
||||
* string is either a full URI or relative reference according to RFC 3986,
|
||||
* Section 4.1. The method concatenates the various components of the URI,
|
||||
* using the appropriate delimiters:
|
||||
*
|
||||
* - If a scheme is present, it MUST be suffixed by ":".
|
||||
* - If an authority is present, it MUST be prefixed by "//".
|
||||
* - The path can be concatenated without delimiters. But there are two
|
||||
* cases where the path has to be adjusted to make the URI reference
|
||||
* valid as PHP does not allow to throw an exception in __toString():
|
||||
* - If the path is rootless and an authority is present, the path MUST
|
||||
* be prefixed by "/".
|
||||
* - If the path is starting with more than one "/" and no authority is
|
||||
* present, the starting slashes MUST be reduced to one.
|
||||
* - If a query is present, it MUST be prefixed by "?".
|
||||
* - If a fragment is present, it MUST be prefixed by "#".
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc3986#section-4.1
|
||||
* @return string
|
||||
*/
|
||||
public function __toString();
|
||||
}
|
Loading…
Reference in New Issue