1463 changed files with 301620 additions and 0 deletions
@ -0,0 +1,55 @@ |
|||
<?php |
|||
require('./conn.php'); |
|||
require 'vendor/autoload.php'; |
|||
ini_set('data.timezone', 'Asia/Taipei'); |
|||
|
|||
use PhpOffice\PhpSpreadsheet\IOFactory; |
|||
|
|||
$filePath = './facility/facility.xlsx'; |
|||
|
|||
try { |
|||
$spreadsheet = IOFactory::load($filePath); |
|||
} catch (\PhpOffice\PhpSpreadsheet\Reader\Exception $e) { |
|||
die('Error loading file:' . $e->getMessage()); |
|||
} |
|||
|
|||
$sheet = $spreadsheet->getActiveSheet(); |
|||
|
|||
$create_at = date("Y-m-d H:i:s"); |
|||
$sql = "INSERT INTO facility_price (kind,model,seat,numberofstop,speed,price,price_mi,status,create_dt) VALUES(:kind,:model,:seat,:numberofstop,:speed,:price,:price_mi,:status,:create_dt)"; |
|||
|
|||
// 遍歷表中的每一行 |
|||
foreach ($sheet->getRowIterator() as $key => $row) { |
|||
$cellIterator = $row->getCellIterator(); |
|||
$cellIterator->setIterateOnlyExistingCells(false); |
|||
|
|||
foreach ($cellIterator as $idx => $value) { |
|||
if ($value !== null) { |
|||
if ($idx == 'A') { |
|||
$model = $value->getValue(); |
|||
if ($model != '規格') { |
|||
// 字串分離 |
|||
$model_arr = explode('-', $model); |
|||
// 抓出樓層 |
|||
$speed = explode('*', $model_arr[1]); |
|||
for ($i = 7; $i <= 30; $i++) { |
|||
$speed[1] = $i; |
|||
$speed_arr[] = $speed; |
|||
} |
|||
for ($i = 6; $i >= 2; $i--) { |
|||
$speed[1] = $i; |
|||
$speed_arr[] = $speed; |
|||
} |
|||
} |
|||
} |
|||
if ($idx == 'B') { |
|||
$price = $value->getValue(); |
|||
if ($price !== '標準價') { |
|||
$price = $price * 10000; |
|||
} |
|||
} |
|||
if ($idx == 'C') { |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,25 @@ |
|||
<?php |
|||
|
|||
// autoload.php @generated by Composer |
|||
|
|||
if (PHP_VERSION_ID < 50600) { |
|||
if (!headers_sent()) { |
|||
header('HTTP/1.1 500 Internal Server Error'); |
|||
} |
|||
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; |
|||
if (!ini_get('display_errors')) { |
|||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { |
|||
fwrite(STDERR, $err); |
|||
} elseif (!headers_sent()) { |
|||
echo $err; |
|||
} |
|||
} |
|||
trigger_error( |
|||
$err, |
|||
E_USER_ERROR |
|||
); |
|||
} |
|||
|
|||
require_once __DIR__ . '/composer/autoload_real.php'; |
|||
|
|||
return ComposerAutoloaderInitb1a92901072bcf21e948dd2e6e6b9766::getLoader(); |
@ -0,0 +1,579 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of Composer. |
|||
* |
|||
* (c) Nils Adermann <naderman@naderman.de> |
|||
* Jordi Boggiano <j.boggiano@seld.be> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Composer\Autoload; |
|||
|
|||
/** |
|||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader. |
|||
* |
|||
* $loader = new \Composer\Autoload\ClassLoader(); |
|||
* |
|||
* // register classes with namespaces |
|||
* $loader->add('Symfony\Component', __DIR__.'/component'); |
|||
* $loader->add('Symfony', __DIR__.'/framework'); |
|||
* |
|||
* // activate the autoloader |
|||
* $loader->register(); |
|||
* |
|||
* // to enable searching the include path (eg. for PEAR packages) |
|||
* $loader->setUseIncludePath(true); |
|||
* |
|||
* In this example, if you try to use a class in the Symfony\Component |
|||
* namespace or one of its children (Symfony\Component\Console for instance), |
|||
* the autoloader will first look for the class under the component/ |
|||
* directory, and it will then fallback to the framework/ directory if not |
|||
* found before giving up. |
|||
* |
|||
* This class is loosely based on the Symfony UniversalClassLoader. |
|||
* |
|||
* @author Fabien Potencier <fabien@symfony.com> |
|||
* @author Jordi Boggiano <j.boggiano@seld.be> |
|||
* @see https://www.php-fig.org/psr/psr-0/ |
|||
* @see https://www.php-fig.org/psr/psr-4/ |
|||
*/ |
|||
class ClassLoader |
|||
{ |
|||
/** @var \Closure(string):void */ |
|||
private static $includeFile; |
|||
|
|||
/** @var string|null */ |
|||
private $vendorDir; |
|||
|
|||
// PSR-4 |
|||
/** |
|||
* @var array<string, array<string, int>> |
|||
*/ |
|||
private $prefixLengthsPsr4 = array(); |
|||
/** |
|||
* @var array<string, list<string>> |
|||
*/ |
|||
private $prefixDirsPsr4 = array(); |
|||
/** |
|||
* @var list<string> |
|||
*/ |
|||
private $fallbackDirsPsr4 = array(); |
|||
|
|||
// PSR-0 |
|||
/** |
|||
* List of PSR-0 prefixes |
|||
* |
|||
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) |
|||
* |
|||
* @var array<string, array<string, list<string>>> |
|||
*/ |
|||
private $prefixesPsr0 = array(); |
|||
/** |
|||
* @var list<string> |
|||
*/ |
|||
private $fallbackDirsPsr0 = array(); |
|||
|
|||
/** @var bool */ |
|||
private $useIncludePath = false; |
|||
|
|||
/** |
|||
* @var array<string, string> |
|||
*/ |
|||
private $classMap = array(); |
|||
|
|||
/** @var bool */ |
|||
private $classMapAuthoritative = false; |
|||
|
|||
/** |
|||
* @var array<string, bool> |
|||
*/ |
|||
private $missingClasses = array(); |
|||
|
|||
/** @var string|null */ |
|||
private $apcuPrefix; |
|||
|
|||
/** |
|||
* @var array<string, self> |
|||
*/ |
|||
private static $registeredLoaders = array(); |
|||
|
|||
/** |
|||
* @param string|null $vendorDir |
|||
*/ |
|||
public function __construct($vendorDir = null) |
|||
{ |
|||
$this->vendorDir = $vendorDir; |
|||
self::initializeIncludeClosure(); |
|||
} |
|||
|
|||
/** |
|||
* @return array<string, list<string>> |
|||
*/ |
|||
public function getPrefixes() |
|||
{ |
|||
if (!empty($this->prefixesPsr0)) { |
|||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); |
|||
} |
|||
|
|||
return array(); |
|||
} |
|||
|
|||
/** |
|||
* @return array<string, list<string>> |
|||
*/ |
|||
public function getPrefixesPsr4() |
|||
{ |
|||
return $this->prefixDirsPsr4; |
|||
} |
|||
|
|||
/** |
|||
* @return list<string> |
|||
*/ |
|||
public function getFallbackDirs() |
|||
{ |
|||
return $this->fallbackDirsPsr0; |
|||
} |
|||
|
|||
/** |
|||
* @return list<string> |
|||
*/ |
|||
public function getFallbackDirsPsr4() |
|||
{ |
|||
return $this->fallbackDirsPsr4; |
|||
} |
|||
|
|||
/** |
|||
* @return array<string, string> Array of classname => path |
|||
*/ |
|||
public function getClassMap() |
|||
{ |
|||
return $this->classMap; |
|||
} |
|||
|
|||
/** |
|||
* @param array<string, string> $classMap Class to filename map |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function addClassMap(array $classMap) |
|||
{ |
|||
if ($this->classMap) { |
|||
$this->classMap = array_merge($this->classMap, $classMap); |
|||
} else { |
|||
$this->classMap = $classMap; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 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 list<string>|string $paths The PSR-0 root directories |
|||
* @param bool $prepend Whether to prepend the directories |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function add($prefix, $paths, $prepend = false) |
|||
{ |
|||
$paths = (array) $paths; |
|||
if (!$prefix) { |
|||
if ($prepend) { |
|||
$this->fallbackDirsPsr0 = array_merge( |
|||
$paths, |
|||
$this->fallbackDirsPsr0 |
|||
); |
|||
} else { |
|||
$this->fallbackDirsPsr0 = array_merge( |
|||
$this->fallbackDirsPsr0, |
|||
$paths |
|||
); |
|||
} |
|||
|
|||
return; |
|||
} |
|||
|
|||
$first = $prefix[0]; |
|||
if (!isset($this->prefixesPsr0[$first][$prefix])) { |
|||
$this->prefixesPsr0[$first][$prefix] = $paths; |
|||
|
|||
return; |
|||
} |
|||
if ($prepend) { |
|||
$this->prefixesPsr0[$first][$prefix] = array_merge( |
|||
$paths, |
|||
$this->prefixesPsr0[$first][$prefix] |
|||
); |
|||
} else { |
|||
$this->prefixesPsr0[$first][$prefix] = array_merge( |
|||
$this->prefixesPsr0[$first][$prefix], |
|||
$paths |
|||
); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 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 list<string>|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) |
|||
{ |
|||
$paths = (array) $paths; |
|||
if (!$prefix) { |
|||
// Register directories for the root namespace. |
|||
if ($prepend) { |
|||
$this->fallbackDirsPsr4 = array_merge( |
|||
$paths, |
|||
$this->fallbackDirsPsr4 |
|||
); |
|||
} else { |
|||
$this->fallbackDirsPsr4 = array_merge( |
|||
$this->fallbackDirsPsr4, |
|||
$paths |
|||
); |
|||
} |
|||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) { |
|||
// Register directories for a new namespace. |
|||
$length = strlen($prefix); |
|||
if ('\\' !== $prefix[$length - 1]) { |
|||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); |
|||
} |
|||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; |
|||
$this->prefixDirsPsr4[$prefix] = $paths; |
|||
} elseif ($prepend) { |
|||
// Prepend directories for an already registered namespace. |
|||
$this->prefixDirsPsr4[$prefix] = array_merge( |
|||
$paths, |
|||
$this->prefixDirsPsr4[$prefix] |
|||
); |
|||
} else { |
|||
// Append directories for an already registered namespace. |
|||
$this->prefixDirsPsr4[$prefix] = array_merge( |
|||
$this->prefixDirsPsr4[$prefix], |
|||
$paths |
|||
); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 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 list<string>|string $paths The PSR-0 base directories |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function set($prefix, $paths) |
|||
{ |
|||
if (!$prefix) { |
|||
$this->fallbackDirsPsr0 = (array) $paths; |
|||
} else { |
|||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 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 list<string>|string $paths The PSR-4 base directories |
|||
* |
|||
* @throws \InvalidArgumentException |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function setPsr4($prefix, $paths) |
|||
{ |
|||
if (!$prefix) { |
|||
$this->fallbackDirsPsr4 = (array) $paths; |
|||
} else { |
|||
$length = strlen($prefix); |
|||
if ('\\' !== $prefix[$length - 1]) { |
|||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); |
|||
} |
|||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; |
|||
$this->prefixDirsPsr4[$prefix] = (array) $paths; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Turns on searching the include path for class files. |
|||
* |
|||
* @param bool $useIncludePath |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function setUseIncludePath($useIncludePath) |
|||
{ |
|||
$this->useIncludePath = $useIncludePath; |
|||
} |
|||
|
|||
/** |
|||
* Can be used to check if the autoloader uses the include path to check |
|||
* for classes. |
|||
* |
|||
* @return bool |
|||
*/ |
|||
public function getUseIncludePath() |
|||
{ |
|||
return $this->useIncludePath; |
|||
} |
|||
|
|||
/** |
|||
* Turns off searching the prefix and fallback directories for classes |
|||
* that have not been registered with the class map. |
|||
* |
|||
* @param bool $classMapAuthoritative |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function setClassMapAuthoritative($classMapAuthoritative) |
|||
{ |
|||
$this->classMapAuthoritative = $classMapAuthoritative; |
|||
} |
|||
|
|||
/** |
|||
* Should class lookup fail if not found in the current class map? |
|||
* |
|||
* @return bool |
|||
*/ |
|||
public function isClassMapAuthoritative() |
|||
{ |
|||
return $this->classMapAuthoritative; |
|||
} |
|||
|
|||
/** |
|||
* 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) |
|||
{ |
|||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; |
|||
} |
|||
|
|||
/** |
|||
* The APCu prefix in use, or null if APCu caching is not enabled. |
|||
* |
|||
* @return string|null |
|||
*/ |
|||
public function getApcuPrefix() |
|||
{ |
|||
return $this->apcuPrefix; |
|||
} |
|||
|
|||
/** |
|||
* 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) { |
|||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; |
|||
} else { |
|||
unset(self::$registeredLoaders[$this->vendorDir]); |
|||
self::$registeredLoaders[$this->vendorDir] = $this; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Unregisters this instance as an autoloader. |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function unregister() |
|||
{ |
|||
spl_autoload_unregister(array($this, 'loadClass')); |
|||
|
|||
if (null !== $this->vendorDir) { |
|||
unset(self::$registeredLoaders[$this->vendorDir]); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Loads the given class or interface. |
|||
* |
|||
* @param string $class The name of the class |
|||
* @return true|null True if loaded, null otherwise |
|||
*/ |
|||
public function loadClass($class) |
|||
{ |
|||
if ($file = $this->findFile($class)) { |
|||
$includeFile = self::$includeFile; |
|||
$includeFile($file); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* Finds the path to the file where the class is defined. |
|||
* |
|||
* @param string $class The name of the class |
|||
* |
|||
* @return string|false The path if found, false otherwise |
|||
*/ |
|||
public function findFile($class) |
|||
{ |
|||
// class map lookup |
|||
if (isset($this->classMap[$class])) { |
|||
return $this->classMap[$class]; |
|||
} |
|||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { |
|||
return false; |
|||
} |
|||
if (null !== $this->apcuPrefix) { |
|||
$file = apcu_fetch($this->apcuPrefix.$class, $hit); |
|||
if ($hit) { |
|||
return $file; |
|||
} |
|||
} |
|||
|
|||
$file = $this->findFileWithExtension($class, '.php'); |
|||
|
|||
// Search for Hack files if we are running on HHVM |
|||
if (false === $file && defined('HHVM_VERSION')) { |
|||
$file = $this->findFileWithExtension($class, '.hh'); |
|||
} |
|||
|
|||
if (null !== $this->apcuPrefix) { |
|||
apcu_add($this->apcuPrefix.$class, $file); |
|||
} |
|||
|
|||
if (false === $file) { |
|||
// Remember that this class does not exist. |
|||
$this->missingClasses[$class] = true; |
|||
} |
|||
|
|||
return $file; |
|||
} |
|||
|
|||
/** |
|||
* Returns the currently registered loaders keyed by their corresponding vendor directories. |
|||
* |
|||
* @return array<string, self> |
|||
*/ |
|||
public static function getRegisteredLoaders() |
|||
{ |
|||
return self::$registeredLoaders; |
|||
} |
|||
|
|||
/** |
|||
* @param string $class |
|||
* @param string $ext |
|||
* @return string|false |
|||
*/ |
|||
private function findFileWithExtension($class, $ext) |
|||
{ |
|||
// PSR-4 lookup |
|||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; |
|||
|
|||
$first = $class[0]; |
|||
if (isset($this->prefixLengthsPsr4[$first])) { |
|||
$subPath = $class; |
|||
while (false !== $lastPos = strrpos($subPath, '\\')) { |
|||
$subPath = substr($subPath, 0, $lastPos); |
|||
$search = $subPath . '\\'; |
|||
if (isset($this->prefixDirsPsr4[$search])) { |
|||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); |
|||
foreach ($this->prefixDirsPsr4[$search] as $dir) { |
|||
if (file_exists($file = $dir . $pathEnd)) { |
|||
return $file; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// PSR-4 fallback dirs |
|||
foreach ($this->fallbackDirsPsr4 as $dir) { |
|||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { |
|||
return $file; |
|||
} |
|||
} |
|||
|
|||
// PSR-0 lookup |
|||
if (false !== $pos = strrpos($class, '\\')) { |
|||
// namespaced class name |
|||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) |
|||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); |
|||
} else { |
|||
// PEAR-like class name |
|||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; |
|||
} |
|||
|
|||
if (isset($this->prefixesPsr0[$first])) { |
|||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { |
|||
if (0 === strpos($class, $prefix)) { |
|||
foreach ($dirs as $dir) { |
|||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { |
|||
return $file; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// PSR-0 fallback dirs |
|||
foreach ($this->fallbackDirsPsr0 as $dir) { |
|||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { |
|||
return $file; |
|||
} |
|||
} |
|||
|
|||
// PSR-0 include paths. |
|||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { |
|||
return $file; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* @return void |
|||
*/ |
|||
private static function initializeIncludeClosure() |
|||
{ |
|||
if (self::$includeFile !== null) { |
|||
return; |
|||
} |
|||
|
|||
/** |
|||
* Scope isolated include. |
|||
* |
|||
* Prevents access to $this/self from included files. |
|||
* |
|||
* @param string $file |
|||
* @return void |
|||
*/ |
|||
self::$includeFile = \Closure::bind(static function($file) { |
|||
include $file; |
|||
}, null, null); |
|||
} |
|||
} |
@ -0,0 +1,359 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of Composer. |
|||
* |
|||
* (c) Nils Adermann <naderman@naderman.de> |
|||
* Jordi Boggiano <j.boggiano@seld.be> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Composer; |
|||
|
|||
use Composer\Autoload\ClassLoader; |
|||
use Composer\Semver\VersionParser; |
|||
|
|||
/** |
|||
* This class is copied in every Composer installed project and available to all |
|||
* |
|||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions |
|||
* |
|||
* To require its presence, you can require `composer-runtime-api ^2.0` |
|||
* |
|||
* @final |
|||
*/ |
|||
class InstalledVersions |
|||
{ |
|||
/** |
|||
* @var mixed[]|null |
|||
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null |
|||
*/ |
|||
private static $installed; |
|||
|
|||
/** |
|||
* @var bool|null |
|||
*/ |
|||
private static $canGetVendors; |
|||
|
|||
/** |
|||
* @var array[] |
|||
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> |
|||
*/ |
|||
private static $installedByVendor = array(); |
|||
|
|||
/** |
|||
* Returns a list of all package names which are present, either by being installed, replaced or provided |
|||
* |
|||
* @return string[] |
|||
* @psalm-return list<string> |
|||
*/ |
|||
public static function getInstalledPackages() |
|||
{ |
|||
$packages = array(); |
|||
foreach (self::getInstalled() as $installed) { |
|||
$packages[] = array_keys($installed['versions']); |
|||
} |
|||
|
|||
if (1 === \count($packages)) { |
|||
return $packages[0]; |
|||
} |
|||
|
|||
return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); |
|||
} |
|||
|
|||
/** |
|||
* Returns a list of all package names with a specific type e.g. 'library' |
|||
* |
|||
* @param string $type |
|||
* @return string[] |
|||
* @psalm-return list<string> |
|||
*/ |
|||
public static function getInstalledPackagesByType($type) |
|||
{ |
|||
$packagesByType = array(); |
|||
|
|||
foreach (self::getInstalled() as $installed) { |
|||
foreach ($installed['versions'] as $name => $package) { |
|||
if (isset($package['type']) && $package['type'] === $type) { |
|||
$packagesByType[] = $name; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return $packagesByType; |
|||
} |
|||
|
|||
/** |
|||
* Checks whether the given package is installed |
|||
* |
|||
* This also returns true if the package name is provided or replaced by another package |
|||
* |
|||
* @param string $packageName |
|||
* @param bool $includeDevRequirements |
|||
* @return bool |
|||
*/ |
|||
public static function isInstalled($packageName, $includeDevRequirements = true) |
|||
{ |
|||
foreach (self::getInstalled() as $installed) { |
|||
if (isset($installed['versions'][$packageName])) { |
|||
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Checks whether the given package satisfies a version constraint |
|||
* |
|||
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: |
|||
* |
|||
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') |
|||
* |
|||
* @param VersionParser $parser Install composer/semver to have access to this class and functionality |
|||
* @param string $packageName |
|||
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package |
|||
* @return bool |
|||
*/ |
|||
public static function satisfies(VersionParser $parser, $packageName, $constraint) |
|||
{ |
|||
$constraint = $parser->parseConstraints((string) $constraint); |
|||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName)); |
|||
|
|||
return $provided->matches($constraint); |
|||
} |
|||
|
|||
/** |
|||
* Returns a version constraint representing all the range(s) which are installed for a given package |
|||
* |
|||
* It is easier to use this via isInstalled() with the $constraint argument if you need to check |
|||
* whether a given version of a package is installed, and not just whether it exists |
|||
* |
|||
* @param string $packageName |
|||
* @return string Version constraint usable with composer/semver |
|||
*/ |
|||
public static function getVersionRanges($packageName) |
|||
{ |
|||
foreach (self::getInstalled() as $installed) { |
|||
if (!isset($installed['versions'][$packageName])) { |
|||
continue; |
|||
} |
|||
|
|||
$ranges = array(); |
|||
if (isset($installed['versions'][$packageName]['pretty_version'])) { |
|||
$ranges[] = $installed['versions'][$packageName]['pretty_version']; |
|||
} |
|||
if (array_key_exists('aliases', $installed['versions'][$packageName])) { |
|||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); |
|||
} |
|||
if (array_key_exists('replaced', $installed['versions'][$packageName])) { |
|||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); |
|||
} |
|||
if (array_key_exists('provided', $installed['versions'][$packageName])) { |
|||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); |
|||
} |
|||
|
|||
return implode(' || ', $ranges); |
|||
} |
|||
|
|||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); |
|||
} |
|||
|
|||
/** |
|||
* @param string $packageName |
|||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present |
|||
*/ |
|||
public static function getVersion($packageName) |
|||
{ |
|||
foreach (self::getInstalled() as $installed) { |
|||
if (!isset($installed['versions'][$packageName])) { |
|||
continue; |
|||
} |
|||
|
|||
if (!isset($installed['versions'][$packageName]['version'])) { |
|||
return null; |
|||
} |
|||
|
|||
return $installed['versions'][$packageName]['version']; |
|||
} |
|||
|
|||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); |
|||
} |
|||
|
|||
/** |
|||
* @param string $packageName |
|||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present |
|||
*/ |
|||
public static function getPrettyVersion($packageName) |
|||
{ |
|||
foreach (self::getInstalled() as $installed) { |
|||
if (!isset($installed['versions'][$packageName])) { |
|||
continue; |
|||
} |
|||
|
|||
if (!isset($installed['versions'][$packageName]['pretty_version'])) { |
|||
return null; |
|||
} |
|||
|
|||
return $installed['versions'][$packageName]['pretty_version']; |
|||
} |
|||
|
|||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); |
|||
} |
|||
|
|||
/** |
|||
* @param string $packageName |
|||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference |
|||
*/ |
|||
public static function getReference($packageName) |
|||
{ |
|||
foreach (self::getInstalled() as $installed) { |
|||
if (!isset($installed['versions'][$packageName])) { |
|||
continue; |
|||
} |
|||
|
|||
if (!isset($installed['versions'][$packageName]['reference'])) { |
|||
return null; |
|||
} |
|||
|
|||
return $installed['versions'][$packageName]['reference']; |
|||
} |
|||
|
|||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); |
|||
} |
|||
|
|||
/** |
|||
* @param string $packageName |
|||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. |
|||
*/ |
|||
public static function getInstallPath($packageName) |
|||
{ |
|||
foreach (self::getInstalled() as $installed) { |
|||
if (!isset($installed['versions'][$packageName])) { |
|||
continue; |
|||
} |
|||
|
|||
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; |
|||
} |
|||
|
|||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); |
|||
} |
|||
|
|||
/** |
|||
* @return array |
|||
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} |
|||
*/ |
|||
public static function getRootPackage() |
|||
{ |
|||
$installed = self::getInstalled(); |
|||
|
|||
return $installed[0]['root']; |
|||
} |
|||
|
|||
/** |
|||
* Returns the raw installed.php data for custom implementations |
|||
* |
|||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. |
|||
* @return array[] |
|||
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, 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, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> |
|||
*/ |
|||
public static function getAllRawData() |
|||
{ |
|||
return self::getInstalled(); |
|||
} |
|||
|
|||
/** |
|||
* Lets you reload the static array from another file |
|||
* |
|||
* This is only useful for complex integrations in which a project needs to use |
|||
* this class but then also needs to execute another project's autoloader in process, |
|||
* and wants to ensure both projects have access to their version of installed.php. |
|||
* |
|||
* A typical case would be PHPUnit, where it would need to make sure it reads all |
|||
* the data it needs from this class, then call reload() with |
|||
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure |
|||
* the project in which it runs can then also use this class safely, without |
|||
* interference between PHPUnit's dependencies and the project's dependencies. |
|||
* |
|||
* @param array[] $data A vendor/composer/installed.php data set |
|||
* @return void |
|||
* |
|||
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data |
|||
*/ |
|||
public static function reload($data) |
|||
{ |
|||
self::$installed = $data; |
|||
self::$installedByVendor = array(); |
|||
} |
|||
|
|||
/** |
|||
* @return array[] |
|||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> |
|||
*/ |
|||
private static function getInstalled() |
|||
{ |
|||
if (null === self::$canGetVendors) { |
|||
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); |
|||
} |
|||
|
|||
$installed = array(); |
|||
|
|||
if (self::$canGetVendors) { |
|||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { |
|||
if (isset(self::$installedByVendor[$vendorDir])) { |
|||
$installed[] = self::$installedByVendor[$vendorDir]; |
|||
} elseif (is_file($vendorDir.'/composer/installed.php')) { |
|||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ |
|||
$required = require $vendorDir.'/composer/installed.php'; |
|||
$installed[] = self::$installedByVendor[$vendorDir] = $required; |
|||
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') { |
|||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ |
|||
$required = require __DIR__ . '/installed.php'; |
|||
self::$installed = $required; |
|||
} else { |
|||
self::$installed = array(); |
|||
} |
|||
} |
|||
|
|||
if (self::$installed !== array()) { |
|||
$installed[] = self::$installed; |
|||
} |
|||
|
|||
return $installed; |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
|
|||
Copyright (c) Nils Adermann, Jordi Boggiano |
|||
|
|||
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,24 @@ |
|||
<?php |
|||
|
|||
// autoload_classmap.php @generated by Composer |
|||
|
|||
$vendorDir = dirname(__DIR__); |
|||
$baseDir = dirname($vendorDir); |
|||
|
|||
return array( |
|||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', |
|||
'Datamatrix' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/datamatrix.php', |
|||
'PDF417' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/pdf417.php', |
|||
'QRcode' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/qrcode.php', |
|||
'TCPDF' => $vendorDir . '/tecnickcom/tcpdf/tcpdf.php', |
|||
'TCPDF2DBarcode' => $vendorDir . '/tecnickcom/tcpdf/tcpdf_barcodes_2d.php', |
|||
'TCPDFBarcode' => $vendorDir . '/tecnickcom/tcpdf/tcpdf_barcodes_1d.php', |
|||
'TCPDF_COLORS' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_colors.php', |
|||
'TCPDF_FILTERS' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_filters.php', |
|||
'TCPDF_FONTS' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_fonts.php', |
|||
'TCPDF_FONT_DATA' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_font_data.php', |
|||
'TCPDF_IMAGES' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_images.php', |
|||
'TCPDF_IMPORT' => $vendorDir . '/tecnickcom/tcpdf/tcpdf_import.php', |
|||
'TCPDF_PARSER' => $vendorDir . '/tecnickcom/tcpdf/tcpdf_parser.php', |
|||
'TCPDF_STATIC' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_static.php', |
|||
); |
@ -0,0 +1,10 @@ |
|||
<?php |
|||
|
|||
// autoload_files.php @generated by Composer |
|||
|
|||
$vendorDir = dirname(__DIR__); |
|||
$baseDir = dirname($vendorDir); |
|||
|
|||
return array( |
|||
'2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', |
|||
); |
@ -0,0 +1,10 @@ |
|||
<?php |
|||
|
|||
// autoload_namespaces.php @generated by Composer |
|||
|
|||
$vendorDir = dirname(__DIR__); |
|||
$baseDir = dirname($vendorDir); |
|||
|
|||
return array( |
|||
'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'), |
|||
); |
@ -0,0 +1,17 @@ |
|||
<?php |
|||
|
|||
// autoload_psr4.php @generated by Composer |
|||
|
|||
$vendorDir = dirname(__DIR__); |
|||
$baseDir = dirname($vendorDir); |
|||
|
|||
return array( |
|||
'ZipStream\\' => array($vendorDir . '/maennchen/zipstream-php/src'), |
|||
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'), |
|||
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'), |
|||
'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'), |
|||
'PhpOffice\\PhpSpreadsheet\\' => array($vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet'), |
|||
'Matrix\\' => array($vendorDir . '/markbaker/matrix/classes/src'), |
|||
'Lo2330\\Contract\\' => array($baseDir . '/src'), |
|||
'Complex\\' => array($vendorDir . '/markbaker/complex/classes/src'), |
|||
); |
@ -0,0 +1,50 @@ |
|||
<?php |
|||
|
|||
// autoload_real.php @generated by Composer |
|||
|
|||
class ComposerAutoloaderInitb1a92901072bcf21e948dd2e6e6b9766 |
|||
{ |
|||
private static $loader; |
|||
|
|||
public static function loadClassLoader($class) |
|||
{ |
|||
if ('Composer\Autoload\ClassLoader' === $class) { |
|||
require __DIR__ . '/ClassLoader.php'; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @return \Composer\Autoload\ClassLoader |
|||
*/ |
|||
public static function getLoader() |
|||
{ |
|||
if (null !== self::$loader) { |
|||
return self::$loader; |
|||
} |
|||
|
|||
require __DIR__ . '/platform_check.php'; |
|||
|
|||
spl_autoload_register(array('ComposerAutoloaderInitb1a92901072bcf21e948dd2e6e6b9766', 'loadClassLoader'), true, true); |
|||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); |
|||
spl_autoload_unregister(array('ComposerAutoloaderInitb1a92901072bcf21e948dd2e6e6b9766', 'loadClassLoader')); |
|||
|
|||
require __DIR__ . '/autoload_static.php'; |
|||
call_user_func(\Composer\Autoload\ComposerStaticInitb1a92901072bcf21e948dd2e6e6b9766::getInitializer($loader)); |
|||
|
|||
$loader->register(true); |
|||
|
|||
$filesToLoad = \Composer\Autoload\ComposerStaticInitb1a92901072bcf21e948dd2e6e6b9766::$files; |
|||
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) { |
|||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { |
|||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; |
|||
|
|||
require $file; |
|||
} |
|||
}, null, null); |
|||
foreach ($filesToLoad as $fileIdentifier => $file) { |
|||
$requireFile($fileIdentifier, $file); |
|||
} |
|||
|
|||
return $loader; |
|||
} |
|||
} |
@ -0,0 +1,113 @@ |
|||
<?php |
|||
|
|||
// autoload_static.php @generated by Composer |
|||
|
|||
namespace Composer\Autoload; |
|||
|
|||
class ComposerStaticInitb1a92901072bcf21e948dd2e6e6b9766 |
|||
{ |
|||
public static $files = array ( |
|||
'2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', |
|||
); |
|||
|
|||
public static $prefixLengthsPsr4 = array ( |
|||
'Z' => |
|||
array ( |
|||
'ZipStream\\' => 10, |
|||
), |
|||
'P' => |
|||
array ( |
|||
'Psr\\SimpleCache\\' => 16, |
|||
'Psr\\Http\\Message\\' => 17, |
|||
'Psr\\Http\\Client\\' => 16, |
|||
'PhpOffice\\PhpSpreadsheet\\' => 25, |
|||
), |
|||
'M' => |
|||
array ( |
|||
'Matrix\\' => 7, |
|||
), |
|||
'L' => |
|||
array ( |
|||
'Lo2330\\Contract\\' => 16, |
|||
), |
|||
'C' => |
|||
array ( |
|||
'Complex\\' => 8, |
|||
), |
|||
); |
|||
|
|||
public static $prefixDirsPsr4 = array ( |
|||
'ZipStream\\' => |
|||
array ( |
|||
0 => __DIR__ . '/..' . '/maennchen/zipstream-php/src', |
|||
), |
|||
'Psr\\SimpleCache\\' => |
|||
array ( |
|||
0 => __DIR__ . '/..' . '/psr/simple-cache/src', |
|||
), |
|||
'Psr\\Http\\Message\\' => |
|||
array ( |
|||
0 => __DIR__ . '/..' . '/psr/http-message/src', |
|||
1 => __DIR__ . '/..' . '/psr/http-factory/src', |
|||
), |
|||
'Psr\\Http\\Client\\' => |
|||
array ( |
|||
0 => __DIR__ . '/..' . '/psr/http-client/src', |
|||
), |
|||
'PhpOffice\\PhpSpreadsheet\\' => |
|||
array ( |
|||
0 => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet', |
|||
), |
|||
'Matrix\\' => |
|||
array ( |
|||
0 => __DIR__ . '/..' . '/markbaker/matrix/classes/src', |
|||
), |
|||
'Lo2330\\Contract\\' => |
|||
array ( |
|||
0 => __DIR__ . '/../..' . '/src', |
|||
), |
|||
'Complex\\' => |
|||
array ( |
|||
0 => __DIR__ . '/..' . '/markbaker/complex/classes/src', |
|||
), |
|||
); |
|||
|
|||
public static $prefixesPsr0 = array ( |
|||
'H' => |
|||
array ( |
|||
'HTMLPurifier' => |
|||
array ( |
|||
0 => __DIR__ . '/..' . '/ezyang/htmlpurifier/library', |
|||
), |
|||
), |
|||
); |
|||
|
|||
public static $classMap = array ( |
|||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', |
|||
'Datamatrix' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/datamatrix.php', |
|||
'PDF417' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/pdf417.php', |
|||
'QRcode' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/qrcode.php', |
|||
'TCPDF' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf.php', |
|||
'TCPDF2DBarcode' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf_barcodes_2d.php', |
|||
'TCPDFBarcode' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf_barcodes_1d.php', |
|||
'TCPDF_COLORS' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_colors.php', |
|||
'TCPDF_FILTERS' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_filters.php', |
|||
'TCPDF_FONTS' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_fonts.php', |
|||
'TCPDF_FONT_DATA' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_font_data.php', |
|||
'TCPDF_IMAGES' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_images.php', |
|||
'TCPDF_IMPORT' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf_import.php', |
|||
'TCPDF_PARSER' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf_parser.php', |
|||
'TCPDF_STATIC' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_static.php', |
|||
); |
|||
|
|||
public static function getInitializer(ClassLoader $loader) |
|||
{ |
|||
return \Closure::bind(function () use ($loader) { |
|||
$loader->prefixLengthsPsr4 = ComposerStaticInitb1a92901072bcf21e948dd2e6e6b9766::$prefixLengthsPsr4; |
|||
$loader->prefixDirsPsr4 = ComposerStaticInitb1a92901072bcf21e948dd2e6e6b9766::$prefixDirsPsr4; |
|||
$loader->prefixesPsr0 = ComposerStaticInitb1a92901072bcf21e948dd2e6e6b9766::$prefixesPsr0; |
|||
$loader->classMap = ComposerStaticInitb1a92901072bcf21e948dd2e6e6b9766::$classMap; |
|||
|
|||
}, null, ClassLoader::class); |
|||
} |
|||
} |
@ -0,0 +1,673 @@ |
|||
{ |
|||
"packages": [ |
|||
{ |
|||
"name": "ezyang/htmlpurifier", |
|||
"version": "v4.17.0", |
|||
"version_normalized": "4.17.0.0", |
|||
"source": { |
|||
"type": "git", |
|||
"url": "https://github.com/ezyang/htmlpurifier.git", |
|||
"reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c" |
|||
}, |
|||
"dist": { |
|||
"type": "zip", |
|||
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/bbc513d79acf6691fa9cf10f192c90dd2957f18c", |
|||
"reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c", |
|||
"shasum": "" |
|||
}, |
|||
"require": { |
|||
"php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0" |
|||
}, |
|||
"require-dev": { |
|||
"cerdic/css-tidy": "^1.7 || ^2.0", |
|||
"simpletest/simpletest": "dev-master" |
|||
}, |
|||
"suggest": { |
|||
"cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", |
|||
"ext-bcmath": "Used for unit conversion and imagecrash protection", |
|||
"ext-iconv": "Converts text to and from non-UTF-8 encodings", |
|||
"ext-tidy": "Used for pretty-printing HTML" |
|||
}, |
|||
"time": "2023-11-17T15:01:25+00:00", |
|||
"type": "library", |
|||
"installation-source": "dist", |
|||
"autoload": { |
|||
"files": [ |
|||
"library/HTMLPurifier.composer.php" |
|||
], |
|||
"psr-0": { |
|||
"HTMLPurifier": "library/" |
|||
}, |
|||
"exclude-from-classmap": [ |
|||
"/library/HTMLPurifier/Language/" |
|||
] |
|||
}, |
|||
"notification-url": "https://packagist.org/downloads/", |
|||
"license": [ |
|||
"LGPL-2.1-or-later" |
|||
], |
|||
"authors": [ |
|||
{ |
|||
"name": "Edward Z. Yang", |
|||
"email": "admin@htmlpurifier.org", |
|||
"homepage": "http://ezyang.com" |
|||
} |
|||
], |
|||
"description": "Standards compliant HTML filter written in PHP", |
|||
"homepage": "http://htmlpurifier.org/", |
|||
"keywords": [ |
|||
"html" |
|||
], |
|||
"support": { |
|||
"issues": "https://github.com/ezyang/htmlpurifier/issues", |
|||
"source": "https://github.com/ezyang/htmlpurifier/tree/v4.17.0" |
|||
}, |
|||
"install-path": "../ezyang/htmlpurifier" |
|||
}, |
|||
{ |
|||
"name": "maennchen/zipstream-php", |
|||
"version": "3.1.0", |
|||
"version_normalized": "3.1.0.0", |
|||
"source": { |
|||
"type": "git", |
|||
"url": "https://github.com/maennchen/ZipStream-PHP.git", |
|||
"reference": "b8174494eda667f7d13876b4a7bfef0f62a7c0d1" |
|||
}, |
|||
"dist": { |
|||
"type": "zip", |
|||
"url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/b8174494eda667f7d13876b4a7bfef0f62a7c0d1", |
|||
"reference": "b8174494eda667f7d13876b4a7bfef0f62a7c0d1", |
|||
"shasum": "" |
|||
}, |
|||
"require": { |
|||
"ext-mbstring": "*", |
|||
"ext-zlib": "*", |
|||
"php-64bit": "^8.1" |
|||
}, |
|||
"require-dev": { |
|||
"ext-zip": "*", |
|||
"friendsofphp/php-cs-fixer": "^3.16", |
|||
"guzzlehttp/guzzle": "^7.5", |
|||
"mikey179/vfsstream": "^1.6", |
|||
"php-coveralls/php-coveralls": "^2.5", |
|||
"phpunit/phpunit": "^10.0", |
|||
"vimeo/psalm": "^5.0" |
|||
}, |
|||
"suggest": { |
|||
"guzzlehttp/psr7": "^2.4", |
|||
"psr/http-message": "^2.0" |
|||
}, |
|||
"time": "2023-06-21T14:59:35+00:00", |
|||
"type": "library", |
|||
"installation-source": "dist", |
|||
"autoload": { |
|||
"psr-4": { |
|||
"ZipStream\\": "src/" |
|||
} |
|||
}, |
|||
"notification-url": "https://packagist.org/downloads/", |
|||
"license": [ |
|||
"MIT" |
|||
], |
|||
"authors": [ |
|||
{ |
|||
"name": "Paul Duncan", |
|||
"email": "pabs@pablotron.org" |
|||
}, |
|||
{ |
|||
"name": "Jonatan Männchen", |
|||
"email": "jonatan@maennchen.ch" |
|||
}, |
|||
{ |
|||
"name": "Jesse Donat", |
|||
"email": "donatj@gmail.com" |
|||
}, |
|||
{ |
|||
"name": "András Kolesár", |
|||
"email": "kolesar@kolesar.hu" |
|||
} |
|||
], |
|||
"description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", |
|||
"keywords": [ |
|||
"stream", |
|||
"zip" |
|||
], |
|||
"support": { |
|||
"issues": "https://github.com/maennchen/ZipStream-PHP/issues", |
|||
"source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.0" |
|||
}, |
|||
"funding": [ |
|||
{ |
|||
"url": "https://github.com/maennchen", |
|||
"type": "github" |
|||
}, |
|||
{ |
|||
"url": "https://opencollective.com/zipstream", |
|||
"type": "open_collective" |
|||
} |
|||
], |
|||
"install-path": "../maennchen/zipstream-php" |
|||
}, |
|||
{ |
|||
"name": "markbaker/complex", |
|||
"version": "3.0.2", |
|||
"version_normalized": "3.0.2.0", |
|||
"source": { |
|||
"type": "git", |
|||
"url": "https://github.com/MarkBaker/PHPComplex.git", |
|||
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9" |
|||
}, |
|||
"dist": { |
|||
"type": "zip", |
|||
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9", |
|||
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9", |
|||
"shasum": "" |
|||
}, |
|||
"require": { |
|||
"php": "^7.2 || ^8.0" |
|||
}, |
|||
"require-dev": { |
|||
"dealerdirect/phpcodesniffer-composer-installer": "dev-master", |
|||
"phpcompatibility/php-compatibility": "^9.3", |
|||
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", |
|||
"squizlabs/php_codesniffer": "^3.7" |
|||
}, |
|||
"time": "2022-12-06T16:21:08+00:00", |
|||
"type": "library", |
|||
"installation-source": "dist", |
|||
"autoload": { |
|||
"psr-4": { |
|||
"Complex\\": "classes/src/" |
|||
} |
|||
}, |
|||
"notification-url": "https://packagist.org/downloads/", |
|||
"license": [ |
|||
"MIT" |
|||
], |
|||
"authors": [ |
|||
{ |
|||
"name": "Mark Baker", |
|||
"email": "mark@lange.demon.co.uk" |
|||
} |
|||
], |
|||
"description": "PHP Class for working with complex numbers", |
|||
"homepage": "https://github.com/MarkBaker/PHPComplex", |
|||
"keywords": [ |
|||
"complex", |
|||
"mathematics" |
|||
], |
|||
"support": { |
|||
"issues": "https://github.com/MarkBaker/PHPComplex/issues", |
|||
"source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2" |
|||
}, |
|||
"install-path": "../markbaker/complex" |
|||
}, |
|||
{ |
|||
"name": "markbaker/matrix", |
|||
"version": "3.0.1", |
|||
"version_normalized": "3.0.1.0", |
|||
"source": { |
|||
"type": "git", |
|||
"url": "https://github.com/MarkBaker/PHPMatrix.git", |
|||
"reference": "728434227fe21be27ff6d86621a1b13107a2562c" |
|||
}, |
|||
"dist": { |
|||
"type": "zip", |
|||
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c", |
|||
"reference": "728434227fe21be27ff6d86621a1b13107a2562c", |
|||
"shasum": "" |
|||
}, |
|||
"require": { |
|||
"php": "^7.1 || ^8.0" |
|||
}, |
|||
"require-dev": { |
|||
"dealerdirect/phpcodesniffer-composer-installer": "dev-master", |
|||
"phpcompatibility/php-compatibility": "^9.3", |
|||
"phpdocumentor/phpdocumentor": "2.*", |
|||
"phploc/phploc": "^4.0", |
|||
"phpmd/phpmd": "2.*", |
|||
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", |
|||
"sebastian/phpcpd": "^4.0", |
|||
"squizlabs/php_codesniffer": "^3.7" |
|||
}, |
|||
"time": "2022-12-02T22:17:43+00:00", |
|||
"type": "library", |
|||
"installation-source": "dist", |
|||
"autoload": { |
|||
"psr-4": { |
|||
"Matrix\\": "classes/src/" |
|||
} |
|||
}, |
|||
"notification-url": "https://packagist.org/downloads/", |
|||
"license": [ |
|||
"MIT" |
|||
], |
|||
"authors": [ |
|||
{ |
|||
"name": "Mark Baker", |
|||
"email": "mark@demon-angel.eu" |
|||
} |
|||
], |
|||
"description": "PHP Class for working with matrices", |
|||
"homepage": "https://github.com/MarkBaker/PHPMatrix", |
|||
"keywords": [ |
|||
"mathematics", |
|||
"matrix", |
|||
"vector" |
|||
], |
|||
"support": { |
|||
"issues": "https://github.com/MarkBaker/PHPMatrix/issues", |
|||
"source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1" |
|||
}, |
|||
"install-path": "../markbaker/matrix" |
|||
}, |
|||
{ |
|||
"name": "phpoffice/phpspreadsheet", |
|||
"version": "1.29.0", |
|||
"version_normalized": "1.29.0.0", |
|||
"source": { |
|||
"type": "git", |
|||
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git", |
|||
"reference": "fde2ccf55eaef7e86021ff1acce26479160a0fa0" |
|||
}, |
|||
"dist": { |
|||
"type": "zip", |
|||
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/fde2ccf55eaef7e86021ff1acce26479160a0fa0", |
|||
"reference": "fde2ccf55eaef7e86021ff1acce26479160a0fa0", |
|||
"shasum": "" |
|||
}, |
|||
"require": { |
|||
"ext-ctype": "*", |
|||
"ext-dom": "*", |
|||
"ext-fileinfo": "*", |
|||
"ext-gd": "*", |
|||
"ext-iconv": "*", |
|||
"ext-libxml": "*", |
|||
"ext-mbstring": "*", |
|||
"ext-simplexml": "*", |
|||
"ext-xml": "*", |
|||
"ext-xmlreader": "*", |
|||
"ext-xmlwriter": "*", |
|||
"ext-zip": "*", |
|||
"ext-zlib": "*", |
|||
"ezyang/htmlpurifier": "^4.15", |
|||
"maennchen/zipstream-php": "^2.1 || ^3.0", |
|||
"markbaker/complex": "^3.0", |
|||
"markbaker/matrix": "^3.0", |
|||
"php": "^7.4 || ^8.0", |
|||
"psr/http-client": "^1.0", |
|||
"psr/http-factory": "^1.0", |
|||
"psr/simple-cache": "^1.0 || ^2.0 || ^3.0" |
|||
}, |
|||
"require-dev": { |
|||
"dealerdirect/phpcodesniffer-composer-installer": "dev-main", |
|||
"dompdf/dompdf": "^1.0 || ^2.0", |
|||
"friendsofphp/php-cs-fixer": "^3.2", |
|||
"mitoteam/jpgraph": "^10.3", |
|||
"mpdf/mpdf": "^8.1.1", |
|||
"phpcompatibility/php-compatibility": "^9.3", |
|||
"phpstan/phpstan": "^1.1", |
|||
"phpstan/phpstan-phpunit": "^1.0", |
|||
"phpunit/phpunit": "^8.5 || ^9.0 || ^10.0", |
|||
"squizlabs/php_codesniffer": "^3.7", |
|||
"tecnickcom/tcpdf": "^6.5" |
|||
}, |
|||
"suggest": { |
|||
"dompdf/dompdf": "Option for rendering PDF with PDF Writer", |
|||
"ext-intl": "PHP Internationalization Functions", |
|||
"mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", |
|||
"mpdf/mpdf": "Option for rendering PDF with PDF Writer", |
|||
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" |
|||
}, |
|||
"time": "2023-06-14T22:48:31+00:00", |
|||
"type": "library", |
|||
"installation-source": "dist", |
|||
"autoload": { |
|||
"psr-4": { |
|||
"PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" |
|||
} |
|||
}, |
|||
"notification-url": "https://packagist.org/downloads/", |
|||
"license": [ |
|||
"MIT" |
|||
], |
|||
"authors": [ |
|||
{ |
|||
"name": "Maarten Balliauw", |
|||
"homepage": "https://blog.maartenballiauw.be" |
|||
}, |
|||
{ |
|||
"name": "Mark Baker", |
|||
"homepage": "https://markbakeruk.net" |
|||
}, |
|||
{ |
|||
"name": "Franck Lefevre", |
|||
"homepage": "https://rootslabs.net" |
|||
}, |
|||
{ |
|||
"name": "Erik Tilt" |
|||
}, |
|||
{ |
|||
"name": "Adrien Crivelli" |
|||
} |
|||
], |
|||
"description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", |
|||
"homepage": "https://github.com/PHPOffice/PhpSpreadsheet", |
|||
"keywords": [ |
|||
"OpenXML", |
|||
"excel", |
|||
"gnumeric", |
|||
"ods", |
|||
"php", |
|||
"spreadsheet", |
|||
"xls", |
|||
"xlsx" |
|||
], |
|||
"support": { |
|||
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", |
|||
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.29.0" |
|||
}, |
|||
"install-path": "../phpoffice/phpspreadsheet" |
|||
}, |
|||
{ |
|||
"name": "psr/http-client", |
|||
"version": "1.0.3", |
|||
"version_normalized": "1.0.3.0", |
|||
"source": { |
|||
"type": "git", |
|||
"url": "https://github.com/php-fig/http-client.git", |
|||
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" |
|||
}, |
|||
"dist": { |
|||
"type": "zip", |
|||
"url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", |
|||
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", |
|||
"shasum": "" |
|||
}, |
|||
"require": { |
|||
"php": "^7.0 || ^8.0", |
|||
"psr/http-message": "^1.0 || ^2.0" |
|||
}, |
|||
"time": "2023-09-23T14:17:50+00:00", |
|||
"type": "library", |
|||
"extra": { |
|||
"branch-alias": { |
|||
"dev-master": "1.0.x-dev" |
|||
} |
|||
}, |
|||
"installation-source": "dist", |
|||
"autoload": { |
|||
"psr-4": { |
|||
"Psr\\Http\\Client\\": "src/" |
|||
} |
|||
}, |
|||
"notification-url": "https://packagist.org/downloads/", |
|||
"license": [ |
|||
"MIT" |
|||
], |
|||
"authors": [ |
|||
{ |
|||
"name": "PHP-FIG", |
|||
"homepage": "https://www.php-fig.org/" |
|||
} |
|||
], |
|||
"description": "Common interface for HTTP clients", |
|||
"homepage": "https://github.com/php-fig/http-client", |
|||
"keywords": [ |
|||
"http", |
|||
"http-client", |
|||
"psr", |
|||
"psr-18" |
|||
], |
|||
"support": { |
|||
"source": "https://github.com/php-fig/http-client" |
|||
}, |
|||
"install-path": "../psr/http-client" |
|||
}, |
|||
{ |
|||
"name": "psr/http-factory", |
|||
"version": "1.0.2", |
|||
"version_normalized": "1.0.2.0", |
|||
"source": { |
|||
"type": "git", |
|||
"url": "https://github.com/php-fig/http-factory.git", |
|||
"reference": "e616d01114759c4c489f93b099585439f795fe35" |
|||
}, |
|||
"dist": { |
|||
"type": "zip", |
|||
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", |
|||
"reference": "e616d01114759c4c489f93b099585439f795fe35", |
|||
"shasum": "" |
|||
}, |
|||
"require": { |
|||
"php": ">=7.0.0", |
|||
"psr/http-message": "^1.0 || ^2.0" |
|||
}, |
|||
"time": "2023-04-10T20:10:41+00:00", |
|||
"type": "library", |
|||
"extra": { |
|||
"branch-alias": { |
|||
"dev-master": "1.0.x-dev" |
|||
} |
|||
}, |
|||
"installation-source": "dist", |
|||
"autoload": { |
|||
"psr-4": { |
|||
"Psr\\Http\\Message\\": "src/" |
|||
} |
|||
}, |
|||
"notification-url": "https://packagist.org/downloads/", |
|||
"license": [ |
|||
"MIT" |
|||
], |
|||
"authors": [ |
|||
{ |
|||
"name": "PHP-FIG", |
|||
"homepage": "https://www.php-fig.org/" |
|||
} |
|||
], |
|||
"description": "Common interfaces for PSR-7 HTTP message factories", |
|||
"keywords": [ |
|||
"factory", |
|||
"http", |
|||
"message", |
|||
"psr", |
|||
"psr-17", |
|||
"psr-7", |
|||
"request", |
|||
"response" |
|||
], |
|||
"support": { |
|||
"source": "https://github.com/php-fig/http-factory/tree/1.0.2" |
|||
}, |
|||
"install-path": "../psr/http-factory" |
|||
}, |
|||
{ |
|||
"name": "psr/http-message", |
|||
"version": "2.0", |
|||
"version_normalized": "2.0.0.0", |
|||
"source": { |
|||
"type": "git", |
|||
"url": "https://github.com/php-fig/http-message.git", |
|||
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" |
|||
}, |
|||
"dist": { |
|||
"type": "zip", |
|||
"url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", |
|||
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", |
|||
"shasum": "" |
|||
}, |
|||
"require": { |
|||
"php": "^7.2 || ^8.0" |
|||
}, |
|||
"time": "2023-04-04T09:54:51+00:00", |
|||
"type": "library", |
|||
"extra": { |
|||
"branch-alias": { |
|||
"dev-master": "2.0.x-dev" |
|||
} |
|||
}, |
|||
"installation-source": "dist", |
|||
"autoload": { |
|||
"psr-4": { |
|||
"Psr\\Http\\Message\\": "src/" |
|||
} |
|||
}, |
|||
"notification-url": "https://packagist.org/downloads/", |
|||
"license": [ |
|||
"MIT" |
|||
], |
|||
"authors": [ |
|||
{ |
|||
"name": "PHP-FIG", |
|||
"homepage": "https://www.php-fig.org/" |
|||
} |
|||
], |
|||
"description": "Common interface for HTTP messages", |
|||
"homepage": "https://github.com/php-fig/http-message", |
|||
"keywords": [ |
|||
"http", |
|||
"http-message", |
|||
"psr", |
|||
"psr-7", |
|||
"request", |
|||
"response" |
|||
], |
|||
"support": { |
|||
"source": "https://github.com/php-fig/http-message/tree/2.0" |
|||
}, |
|||
"install-path": "../psr/http-message" |
|||
}, |
|||
{ |
|||
"name": "psr/simple-cache", |
|||
"version": "3.0.0", |
|||
"version_normalized": "3.0.0.0", |
|||
"source": { |
|||
"type": "git", |
|||
"url": "https://github.com/php-fig/simple-cache.git", |
|||
"reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" |
|||
}, |
|||
"dist": { |
|||
"type": "zip", |
|||
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", |
|||
"reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", |
|||
"shasum": "" |
|||
}, |
|||
"require": { |
|||
"php": ">=8.0.0" |
|||
}, |
|||
"time": "2021-10-29T13:26:27+00:00", |
|||
"type": "library", |
|||
"extra": { |
|||
"branch-alias": { |
|||
"dev-master": "3.0.x-dev" |
|||
} |
|||
}, |
|||
"installation-source": "dist", |
|||
"autoload": { |
|||
"psr-4": { |
|||
"Psr\\SimpleCache\\": "src/" |
|||
} |
|||
}, |
|||
"notification-url": "https://packagist.org/downloads/", |
|||
"license": [ |
|||
"MIT" |
|||
], |
|||
"authors": [ |
|||
{ |
|||
"name": "PHP-FIG", |
|||
"homepage": "https://www.php-fig.org/" |
|||
} |
|||
], |
|||
"description": "Common interfaces for simple caching", |
|||
"keywords": [ |
|||
"cache", |
|||
"caching", |
|||
"psr", |
|||
"psr-16", |
|||
"simple-cache" |
|||
], |
|||
"support": { |
|||
"source": "https://github.com/php-fig/simple-cache/tree/3.0.0" |
|||
}, |
|||
"install-path": "../psr/simple-cache" |
|||
}, |
|||
{ |
|||
"name": "tecnickcom/tcpdf", |
|||
"version": "6.6.5", |
|||
"version_normalized": "6.6.5.0", |
|||
"source": { |
|||
"type": "git", |
|||
"url": "https://github.com/tecnickcom/TCPDF.git", |
|||
"reference": "5fce932fcee4371865314ab7f6c0d85423c5c7ce" |
|||
}, |
|||
"dist": { |
|||
"type": "zip", |
|||
"url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/5fce932fcee4371865314ab7f6c0d85423c5c7ce", |
|||
"reference": "5fce932fcee4371865314ab7f6c0d85423c5c7ce", |
|||
"shasum": "" |
|||
}, |
|||
"require": { |
|||
"php": ">=5.3.0" |
|||
}, |
|||
"time": "2023-09-06T15:09:26+00:00", |
|||
"type": "library", |
|||
"installation-source": "dist", |
|||
"autoload": { |
|||
"classmap": [ |
|||
"config", |
|||
"include", |
|||
"tcpdf.php", |
|||
"tcpdf_parser.php", |
|||
"tcpdf_import.php", |
|||
"tcpdf_barcodes_1d.php", |
|||
"tcpdf_barcodes_2d.php", |
|||
"include/tcpdf_colors.php", |
|||
"include/tcpdf_filters.php", |
|||
"include/tcpdf_font_data.php", |
|||
"include/tcpdf_fonts.php", |
|||
"include/tcpdf_images.php", |
|||
"include/tcpdf_static.php", |
|||
"include/barcodes/datamatrix.php", |
|||
"include/barcodes/pdf417.php", |
|||
"include/barcodes/qrcode.php" |
|||
] |
|||
}, |
|||
"notification-url": "https://packagist.org/downloads/", |
|||
"license": [ |
|||
"LGPL-3.0-or-later" |
|||
], |
|||
"authors": [ |
|||
{ |
|||
"name": "Nicola Asuni", |
|||
"email": "info@tecnick.com", |
|||
"role": "lead" |
|||
} |
|||
], |
|||
"description": "TCPDF is a PHP class for generating PDF documents and barcodes.", |
|||
"homepage": "http://www.tcpdf.org/", |
|||
"keywords": [ |
|||
"PDFD32000-2008", |
|||
"TCPDF", |
|||
"barcodes", |
|||
"datamatrix", |
|||
"pdf", |
|||
"pdf417", |
|||
"qrcode" |
|||
], |
|||
"support": { |
|||
"issues": "https://github.com/tecnickcom/TCPDF/issues", |
|||
"source": "https://github.com/tecnickcom/TCPDF/tree/6.6.5" |
|||
}, |
|||
"funding": [ |
|||
{ |
|||
"url": "https://www.paypal.com/cgi-bin/webscr?cmd=_donations¤cy_code=GBP&business=paypal@tecnick.com&item_name=donation%20for%20tcpdf%20project", |
|||
"type": "custom" |
|||
} |
|||
], |
|||
"install-path": "../tecnickcom/tcpdf" |
|||
} |
|||
], |
|||
"dev": true, |
|||
"dev-package-names": [] |
|||
} |
@ -0,0 +1,113 @@ |
|||
<?php return array( |
|||
'root' => array( |
|||
'name' => 'lo2330/contract', |
|||
'pretty_version' => 'dev-main', |
|||
'version' => 'dev-main', |
|||
'reference' => '2ccb0f743f7d057dcf2554b72d1ab1e3880821c2', |
|||
'type' => 'library', |
|||
'install_path' => __DIR__ . '/../../', |
|||
'aliases' => array(), |
|||
'dev' => true, |
|||
), |
|||
'versions' => array( |
|||
'ezyang/htmlpurifier' => array( |
|||
'pretty_version' => 'v4.17.0', |
|||
'version' => '4.17.0.0', |
|||
'reference' => 'bbc513d79acf6691fa9cf10f192c90dd2957f18c', |
|||
'type' => 'library', |
|||
'install_path' => __DIR__ . '/../ezyang/htmlpurifier', |
|||
'aliases' => array(), |
|||
'dev_requirement' => false, |
|||
), |
|||
'lo2330/contract' => array( |
|||
'pretty_version' => 'dev-main', |
|||
'version' => 'dev-main', |
|||
'reference' => '2ccb0f743f7d057dcf2554b72d1ab1e3880821c2', |
|||
'type' => 'library', |
|||
'install_path' => __DIR__ . '/../../', |
|||
'aliases' => array(), |
|||
'dev_requirement' => false, |
|||
), |
|||
'maennchen/zipstream-php' => array( |
|||
'pretty_version' => '3.1.0', |
|||
'version' => '3.1.0.0', |
|||
'reference' => 'b8174494eda667f7d13876b4a7bfef0f62a7c0d1', |
|||
'type' => 'library', |
|||
'install_path' => __DIR__ . '/../maennchen/zipstream-php', |
|||
'aliases' => array(), |
|||
'dev_requirement' => false, |
|||
), |
|||
'markbaker/complex' => array( |
|||
'pretty_version' => '3.0.2', |
|||
'version' => '3.0.2.0', |
|||
'reference' => '95c56caa1cf5c766ad6d65b6344b807c1e8405b9', |
|||
'type' => 'library', |
|||
'install_path' => __DIR__ . '/../markbaker/complex', |
|||
'aliases' => array(), |
|||
'dev_requirement' => false, |
|||
), |
|||
'markbaker/matrix' => array( |
|||
'pretty_version' => '3.0.1', |
|||
'version' => '3.0.1.0', |
|||
'reference' => '728434227fe21be27ff6d86621a1b13107a2562c', |
|||
'type' => 'library', |
|||
'install_path' => __DIR__ . '/../markbaker/matrix', |
|||
'aliases' => array(), |
|||
'dev_requirement' => false, |
|||
), |
|||
'phpoffice/phpspreadsheet' => array( |
|||
'pretty_version' => '1.29.0', |
|||
'version' => '1.29.0.0', |
|||
'reference' => 'fde2ccf55eaef7e86021ff1acce26479160a0fa0', |
|||
'type' => 'library', |
|||
'install_path' => __DIR__ . '/../phpoffice/phpspreadsheet', |
|||
'aliases' => array(), |
|||
'dev_requirement' => false, |
|||
), |
|||
'psr/http-client' => array( |
|||
'pretty_version' => '1.0.3', |
|||
'version' => '1.0.3.0', |
|||
'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90', |
|||
'type' => 'library', |
|||
'install_path' => __DIR__ . '/../psr/http-client', |
|||
'aliases' => array(), |
|||
'dev_requirement' => false, |
|||
), |
|||
'psr/http-factory' => array( |
|||
'pretty_version' => '1.0.2', |
|||
'version' => '1.0.2.0', |
|||
'reference' => 'e616d01114759c4c489f93b099585439f795fe35', |
|||
'type' => 'library', |
|||
'install_path' => __DIR__ . '/../psr/http-factory', |
|||
'aliases' => array(), |
|||
'dev_requirement' => false, |
|||
), |
|||
'psr/http-message' => array( |
|||
'pretty_version' => '2.0', |
|||
'version' => '2.0.0.0', |
|||
'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71', |
|||
'type' => 'library', |
|||
'install_path' => __DIR__ . '/../psr/http-message', |
|||
'aliases' => array(), |
|||
'dev_requirement' => false, |
|||
), |
|||
'psr/simple-cache' => array( |
|||
'pretty_version' => '3.0.0', |
|||
'version' => '3.0.0.0', |
|||
'reference' => '764e0b3939f5ca87cb904f570ef9be2d78a07865', |
|||
'type' => 'library', |
|||
'install_path' => __DIR__ . '/../psr/simple-cache', |
|||
'aliases' => array(), |
|||
'dev_requirement' => false, |
|||
), |
|||
'tecnickcom/tcpdf' => array( |
|||
'pretty_version' => '6.6.5', |
|||
'version' => '6.6.5.0', |
|||
'reference' => '5fce932fcee4371865314ab7f6c0d85423c5c7ce', |
|||
'type' => 'library', |
|||
'install_path' => __DIR__ . '/../tecnickcom/tcpdf', |
|||
'aliases' => array(), |
|||
'dev_requirement' => false, |
|||
), |
|||
), |
|||
); |
@ -0,0 +1,30 @@ |
|||
<?php |
|||
|
|||
// platform_check.php @generated by Composer |
|||
|
|||
$issues = array(); |
|||
|
|||
if (!(PHP_VERSION_ID >= 80100)) { |
|||
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.'; |
|||
} |
|||
|
|||
if (PHP_INT_SIZE !== 8) { |
|||
$issues[] = 'Your Composer dependencies require a 64-bit build of PHP.'; |
|||
} |
|||
|
|||
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,9 @@ |
|||
|
|||
CREDITS |
|||
|
|||
Almost everything written by Edward Z. Yang (Ambush Commander). Lots of thanks |
|||
to the DevNetwork Community for their help (see docs/ref-devnetwork.html for |
|||
more details), Feyd especially (namely IPv6 and optimization). Thanks to RSnake |
|||
for letting me package his fantastic XSS cheatsheet for a smoketest. |
|||
|
|||
vim: et sw=4 sts=4 |
@ -0,0 +1,504 @@ |
|||
GNU LESSER GENERAL PUBLIC LICENSE |
|||
Version 2.1, February 1999 |
|||
|
|||
Copyright (C) 1991, 1999 Free Software Foundation, Inc. |
|||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|||
Everyone is permitted to copy and distribute verbatim copies |
|||
of this license document, but changing it is not allowed. |
|||
|
|||
[This is the first released version of the Lesser GPL. It also counts |
|||
as the successor of the GNU Library Public License, version 2, hence |
|||
the version number 2.1.] |
|||
|
|||
Preamble |
|||
|
|||
The licenses for most software are designed to take away your |
|||
freedom to share and change it. By contrast, the GNU General Public |
|||
Licenses are intended to guarantee your freedom to share and change |
|||
free software--to make sure the software is free for all its users. |
|||
|
|||
This license, the Lesser General Public License, applies to some |
|||
specially designated software packages--typically libraries--of the |
|||
Free Software Foundation and other authors who decide to use it. You |
|||
can use it too, but we suggest you first think carefully about whether |
|||
this license or the ordinary General Public License is the better |
|||
strategy to use in any particular case, based on the explanations below. |
|||
|
|||
When we speak of free software, we are referring to freedom of use, |
|||
not price. Our General Public Licenses are designed to make sure that |
|||
you have the freedom to distribute copies of free software (and charge |
|||
for this service if you wish); that you receive source code or can get |
|||
it if you want it; that you can change the software and use pieces of |
|||
it in new free programs; and that you are informed that you can do |
|||
these things. |
|||
|
|||
To protect your rights, we need to make restrictions that forbid |
|||
distributors to deny you these rights or to ask you to surrender these |
|||
rights. These restrictions translate to certain responsibilities for |
|||
you if you distribute copies of the library or if you modify it. |
|||
|
|||
For example, if you distribute copies of the library, whether gratis |
|||
or for a fee, you must give the recipients all the rights that we gave |
|||
you. You must make sure that they, too, receive or can get the source |
|||
code. If you link other code with the library, you must provide |
|||
complete object files to the recipients, so that they can relink them |
|||
with the library after making changes to the library and recompiling |
|||
it. And you must show them these terms so they know their rights. |
|||
|
|||
We protect your rights with a two-step method: (1) we copyright the |
|||
library, and (2) we offer you this license, which gives you legal |
|||
permission to copy, distribute and/or modify the library. |
|||
|
|||
To protect each distributor, we want to make it very clear that |
|||
there is no warranty for the free library. Also, if the library is |
|||
modified by someone else and passed on, the recipients should know |
|||
that what they have is not the original version, so that the original |
|||
author's reputation will not be affected by problems that might be |
|||
introduced by others. |
|||
|
|||
Finally, software patents pose a constant threat to the existence of |
|||
any free program. We wish to make sure that a company cannot |
|||
effectively restrict the users of a free program by obtaining a |
|||
restrictive license from a patent holder. Therefore, we insist that |
|||
any patent license obtained for a version of the library must be |
|||
consistent with the full freedom of use specified in this license. |
|||
|
|||
Most GNU software, including some libraries, is covered by the |
|||
ordinary GNU General Public License. This license, the GNU Lesser |
|||
General Public License, applies to certain designated libraries, and |
|||
is quite different from the ordinary General Public License. We use |
|||
this license for certain libraries in order to permit linking those |
|||
libraries into non-free programs. |
|||
|
|||
When a program is linked with a library, whether statically or using |
|||
a shared library, the combination of the two is legally speaking a |
|||
combined work, a derivative of the original library. The ordinary |
|||
General Public License therefore permits such linking only if the |
|||
entire combination fits its criteria of freedom. The Lesser General |
|||
Public License permits more lax criteria for linking other code with |
|||
the library. |
|||
|
|||
We call this license the "Lesser" General Public License because it |
|||
does Less to protect the user's freedom than the ordinary General |
|||
Public License. It also provides other free software developers Less |
|||
of an advantage over competing non-free programs. These disadvantages |
|||
are the reason we use the ordinary General Public License for many |
|||
libraries. However, the Lesser license provides advantages in certain |
|||
special circumstances. |
|||
|
|||
For example, on rare occasions, there may be a special need to |
|||
encourage the widest possible use of a certain library, so that it becomes |
|||
a de-facto standard. To achieve this, non-free programs must be |
|||
allowed to use the library. A more frequent case is that a free |
|||
library does the same job as widely used non-free libraries. In this |
|||
case, there is little to gain by limiting the free library to free |
|||
software only, so we use the Lesser General Public License. |
|||
|
|||
In other cases, permission to use a particular library in non-free |
|||
programs enables a greater number of people to use a large body of |
|||
free software. For example, permission to use the GNU C Library in |
|||
non-free programs enables many more people to use the whole GNU |
|||
operating system, as well as its variant, the GNU/Linux operating |
|||
system. |
|||
|
|||
Although the Lesser General Public License is Less protective of the |
|||
users' freedom, it does ensure that the user of a program that is |
|||
linked with the Library has the freedom and the wherewithal to run |
|||
that program using a modified version of the Library. |
|||
|
|||
The precise terms and conditions for copying, distribution and |
|||
modification follow. Pay close attention to the difference between a |
|||
"work based on the library" and a "work that uses the library". The |
|||
former contains code derived from the library, whereas the latter must |
|||
be combined with the library in order to run. |
|||
|
|||
GNU LESSER GENERAL PUBLIC LICENSE |
|||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
|||
|
|||
0. This License Agreement applies to any software library or other |
|||
program which contains a notice placed by the copyright holder or |
|||
other authorized party saying it may be distributed under the terms of |
|||
this Lesser General Public License (also called "this License"). |
|||
Each licensee is addressed as "you". |
|||
|
|||
A "library" means a collection of software functions and/or data |
|||
prepared so as to be conveniently linked with application programs |
|||
(which use some of those functions and data) to form executables. |
|||
|
|||
The "Library", below, refers to any such software library or work |
|||
which has been distributed under these terms. A "work based on the |
|||
Library" means either the Library or any derivative work under |
|||
copyright law: that is to say, a work containing the Library or a |
|||
portion of it, either verbatim or with modifications and/or translated |
|||
straightforwardly into another language. (Hereinafter, translation is |
|||
included without limitation in the term "modification".) |
|||
|
|||
"Source code" for a work means the preferred form of the work for |
|||
making modifications to it. For a library, complete source code means |
|||
all the source code for all modules it contains, plus any associated |
|||
interface definition files, plus the scripts used to control compilation |
|||
and installation of the library. |
|||
|
|||
Activities other than copying, distribution and modification are not |
|||
covered by this License; they are outside its scope. The act of |
|||
running a program using the Library is not restricted, and output from |
|||
such a program is covered only if its contents constitute a work based |
|||
on the Library (independent of the use of the Library in a tool for |
|||
writing it). Whether that is true depends on what the Library does |
|||
and what the program that uses the Library does. |
|||
|
|||
1. You may copy and distribute verbatim copies of the Library's |
|||
complete source code as you receive it, in any medium, provided that |
|||
you conspicuously and appropriately publish on each copy an |
|||
appropriate copyright notice and disclaimer of warranty; keep intact |
|||
all the notices that refer to this License and to the absence of any |
|||
warranty; and distribute a copy of this License along with the |
|||
Library. |
|||
|
|||
You may charge a fee for the physical act of transferring a copy, |
|||
and you may at your option offer warranty protection in exchange for a |
|||
fee. |
|||
|
|||
2. You may modify your copy or copies of the Library or any portion |
|||
of it, thus forming a work based on the Library, and copy and |
|||
distribute such modifications or work under the terms of Section 1 |
|||
above, provided that you also meet all of these conditions: |
|||
|
|||
a) The modified work must itself be a software library. |
|||
|
|||
b) You must cause the files modified to carry prominent notices |
|||
stating that you changed the files and the date of any change. |
|||
|
|||
c) You must cause the whole of the work to be licensed at no |
|||
charge to all third parties under the terms of this License. |
|||
|
|||
d) If a facility in the modified Library refers to a function or a |
|||
table of data to be supplied by an application program that uses |
|||
the facility, other than as an argument passed when the facility |
|||
is invoked, then you must make a good faith effort to ensure that, |
|||
in the event an application does not supply such function or |
|||
table, the facility still operates, and performs whatever part of |
|||
its purpose remains meaningful. |
|||
|
|||
(For example, a function in a library to compute square roots has |
|||
a purpose that is entirely well-defined independent of the |
|||
application. Therefore, Subsection 2d requires that any |
|||
application-supplied function or table used by this function must |
|||
be optional: if the application does not supply it, the square |
|||
root function must still compute square roots.) |
|||
|
|||
These requirements apply to the modified work as a whole. If |
|||
identifiable sections of that work are not derived from the Library, |
|||
and can be reasonably considered independent and separate works in |
|||
themselves, then this License, and its terms, do not apply to those |
|||
sections when you distribute them as separate works. But when you |
|||
distribute the same sections as part of a whole which is a work based |
|||
on the Library, the distribution of the whole must be on the terms of |
|||
this License, whose permissions for other licensees extend to the |
|||
entire whole, and thus to each and every part regardless of who wrote |
|||
it. |
|||
|
|||
Thus, it is not the intent of this section to claim rights or contest |
|||
your rights to work written entirely by you; rather, the intent is to |
|||
exercise the right to control the distribution of derivative or |
|||
collective works based on the Library. |
|||
|
|||
In addition, mere aggregation of another work not based on the Library |
|||
with the Library (or with a work based on the Library) on a volume of |
|||
a storage or distribution medium does not bring the other work under |
|||
the scope of this License. |
|||
|
|||
3. You may opt to apply the terms of the ordinary GNU General Public |
|||
License instead of this License to a given copy of the Library. To do |
|||
this, you must alter all the notices that refer to this License, so |
|||
that they refer to the ordinary GNU General Public License, version 2, |
|||
instead of to this License. (If a newer version than version 2 of the |
|||
ordinary GNU General Public License has appeared, then you can specify |
|||
that version instead if you wish.) Do not make any other change in |
|||
these notices. |
|||
|
|||
Once this change is made in a given copy, it is irreversible for |
|||
that copy, so the ordinary GNU General Public License applies to all |
|||
subsequent copies and derivative works made from that copy. |
|||
|
|||
This option is useful when you wish to copy part of the code of |
|||
the Library into a program that is not a library. |
|||
|
|||
4. You may copy and distribute the Library (or a portion or |
|||
derivative of it, under Section 2) in object code or executable form |
|||
under the terms of Sections 1 and 2 above provided that you accompany |
|||
it with the complete corresponding machine-readable source code, which |
|||
must be distributed under the terms of Sections 1 and 2 above on a |
|||
medium customarily used for software interchange. |
|||
|
|||
If distribution of object code is made by offering access to copy |
|||
from a designated place, then offering equivalent access to copy the |
|||
source code from the same place satisfies the requirement to |
|||
distribute the source code, even though third parties are not |
|||
compelled to copy the source along with the object code. |
|||
|
|||
5. A program that contains no derivative of any portion of the |
|||
Library, but is designed to work with the Library by being compiled or |
|||
linked with it, is called a "work that uses the Library". Such a |
|||
work, in isolation, is not a derivative work of the Library, and |
|||
therefore falls outside the scope of this License. |
|||
|
|||
However, linking a "work that uses the Library" with the Library |
|||
creates an executable that is a derivative of the Library (because it |
|||
contains portions of the Library), rather than a "work that uses the |
|||
library". The executable is therefore covered by this License. |
|||
Section 6 states terms for distribution of such executables. |
|||
|
|||
When a "work that uses the Library" uses material from a header file |
|||
that is part of the Library, the object code for the work may be a |
|||
derivative work of the Library even though the source code is not. |
|||
Whether this is true is especially significant if the work can be |
|||
linked without the Library, or if the work is itself a library. The |
|||
threshold for this to be true is not precisely defined by law. |
|||
|
|||
If such an object file uses only numerical parameters, data |
|||
structure layouts and accessors, and small macros and small inline |
|||
functions (ten lines or less in length), then the use of the object |
|||
file is unrestricted, regardless of whether it is legally a derivative |
|||
work. (Executables containing this object code plus portions of the |
|||
Library will still fall under Section 6.) |
|||
|
|||
Otherwise, if the work is a derivative of the Library, you may |
|||
distribute the object code for the work under the terms of Section 6. |
|||
Any executables containing that work also fall under Section 6, |
|||
whether or not they are linked directly with the Library itself. |
|||
|
|||
6. As an exception to the Sections above, you may also combine or |
|||
link a "work that uses the Library" with the Library to produce a |
|||
work containing portions of the Library, and distribute that work |
|||
under terms of your choice, provided that the terms permit |
|||
modification of the work for the customer's own use and reverse |
|||
engineering for debugging such modifications. |
|||
|
|||
You must give prominent notice with each copy of the work that the |
|||
Library is used in it and that the Library and its use are covered by |
|||
this License. You must supply a copy of this License. If the work |
|||
during execution displays copyright notices, you must include the |
|||
copyright notice for the Library among them, as well as a reference |
|||
directing the user to the copy of this License. Also, you must do one |
|||
of these things: |
|||
|
|||
a) Accompany the work with the complete corresponding |
|||
machine-readable source code for the Library including whatever |
|||
changes were used in the work (which must be distributed under |
|||
Sections 1 and 2 above); and, if the work is an executable linked |
|||
with the Library, with the complete machine-readable "work that |
|||
uses the Library", as object code and/or source code, so that the |
|||
user can modify the Library and then relink to produce a modified |
|||
executable containing the modified Library. (It is understood |
|||
that the user who changes the contents of definitions files in the |
|||
Library will not necessarily be able to recompile the application |
|||
to use the modified definitions.) |
|||
|
|||
b) Use a suitable shared library mechanism for linking with the |
|||
Library. A suitable mechanism is one that (1) uses at run time a |
|||
copy of the library already present on the user's computer system, |
|||
rather than copying library functions into the executable, and (2) |
|||
will operate properly with a modified version of the library, if |
|||
the user installs one, as long as the modified version is |
|||
interface-compatible with the version that the work was made with. |
|||
|
|||
c) Accompany the work with a written offer, valid for at |
|||
least three years, to give the same user the materials |
|||
specified in Subsection 6a, above, for a charge no more |
|||
than the cost of performing this distribution. |
|||
|
|||
d) If distribution of the work is made by offering access to copy |
|||
from a designated place, offer equivalent access to copy the above |
|||
specified materials from the same place. |
|||
|
|||
e) Verify that the user has already received a copy of these |
|||
materials or that you have already sent this user a copy. |
|||
|
|||
For an executable, the required form of the "work that uses the |
|||
Library" must include any data and utility programs needed for |
|||
reproducing the executable from it. However, as a special exception, |
|||
the materials to be distributed need not include anything that is |
|||
normally distributed (in either source or binary form) with the major |
|||
components (compiler, kernel, and so on) of the operating system on |
|||
which the executable runs, unless that component itself accompanies |
|||
the executable. |
|||
|
|||
It may happen that this requirement contradicts the license |
|||
restrictions of other proprietary libraries that do not normally |
|||
accompany the operating system. Such a contradiction means you cannot |
|||
use both them and the Library together in an executable that you |
|||
distribute. |
|||
|
|||
7. You may place library facilities that are a work based on the |
|||
Library side-by-side in a single library together with other library |
|||
facilities not covered by this License, and distribute such a combined |
|||
library, provided that the separate distribution of the work based on |
|||
the Library and of the other library facilities is otherwise |
|||
permitted, and provided that you do these two things: |
|||
|
|||
a) Accompany the combined library with a copy of the same work |
|||
based on the Library, uncombined with any other library |
|||
facilities. This must be distributed under the terms of the |
|||
Sections above. |
|||
|
|||
b) Give prominent notice with the combined library of the fact |
|||
that part of it is a work based on the Library, and explaining |
|||
where to find the accompanying uncombined form of the same work. |
|||
|
|||
8. You may not copy, modify, sublicense, link with, or distribute |
|||
the Library except as expressly provided under this License. Any |
|||
attempt otherwise to copy, modify, sublicense, link with, or |
|||
distribute the Library is void, and will automatically terminate your |
|||
rights under this License. However, parties who have received copies, |
|||
or rights, from you under this License will not have their licenses |
|||
terminated so long as such parties remain in full compliance. |
|||
|
|||
9. You are not required to accept this License, since you have not |
|||
signed it. However, nothing else grants you permission to modify or |
|||
distribute the Library or its derivative works. These actions are |
|||
prohibited by law if you do not accept this License. Therefore, by |
|||
modifying or distributing the Library (or any work based on the |
|||
Library), you indicate your acceptance of this License to do so, and |
|||
all its terms and conditions for copying, distributing or modifying |
|||
the Library or works based on it. |
|||
|
|||
10. Each time you redistribute the Library (or any work based on the |
|||
Library), the recipient automatically receives a license from the |
|||
original licensor to copy, distribute, link with or modify the Library |
|||
subject to these terms and conditions. You may not impose any further |
|||
restrictions on the recipients' exercise of the rights granted herein. |
|||
You are not responsible for enforcing compliance by third parties with |
|||
this License. |
|||
|
|||
11. If, as a consequence of a court judgment or allegation of patent |
|||
infringement or for any other reason (not limited to patent issues), |
|||
conditions are imposed on you (whether by court order, agreement or |
|||
otherwise) that contradict the conditions of this License, they do not |
|||
excuse you from the conditions of this License. If you cannot |
|||
distribute so as to satisfy simultaneously your obligations under this |
|||
License and any other pertinent obligations, then as a consequence you |
|||
may not distribute the Library at all. For example, if a patent |
|||
license would not permit royalty-free redistribution of the Library by |
|||
all those who receive copies directly or indirectly through you, then |
|||
the only way you could satisfy both it and this License would be to |
|||
refrain entirely from distribution of the Library. |
|||
|
|||
If any portion of this section is held invalid or unenforceable under any |
|||
particular circumstance, the balance of the section is intended to apply, |
|||
and the section as a whole is intended to apply in other circumstances. |
|||
|
|||
It is not the purpose of this section to induce you to infringe any |
|||
patents or other property right claims or to contest validity of any |
|||
such claims; this section has the sole purpose of protecting the |
|||
integrity of the free software distribution system which is |
|||
implemented by public license practices. Many people have made |
|||
generous contributions to the wide range of software distributed |
|||
through that system in reliance on consistent application of that |
|||
system; it is up to the author/donor to decide if he or she is willing |
|||
to distribute software through any other system and a licensee cannot |
|||
impose that choice. |
|||
|
|||
This section is intended to make thoroughly clear what is believed to |
|||
be a consequence of the rest of this License. |
|||
|
|||
12. If the distribution and/or use of the Library is restricted in |
|||
certain countries either by patents or by copyrighted interfaces, the |
|||
original copyright holder who places the Library under this License may add |
|||
an explicit geographical distribution limitation excluding those countries, |
|||
so that distribution is permitted only in or among countries not thus |
|||
excluded. In such case, this License incorporates the limitation as if |
|||
written in the body of this License. |
|||
|
|||
13. The Free Software Foundation may publish revised and/or new |
|||
versions of the Lesser General Public License from time to time. |
|||
Such new versions will be similar in spirit to the present version, |
|||
but may differ in detail to address new problems or concerns. |
|||
|
|||
Each version is given a distinguishing version number. If the Library |
|||
specifies a version number of this License which applies to it and |
|||
"any later version", you have the option of following the terms and |
|||
conditions either of that version or of any later version published by |
|||
the Free Software Foundation. If the Library does not specify a |
|||
license version number, you may choose any version ever published by |
|||
the Free Software Foundation. |
|||
|
|||
14. If you wish to incorporate parts of the Library into other free |
|||
programs whose distribution conditions are incompatible with these, |
|||
write to the author to ask for permission. For software which is |
|||
copyrighted by the Free Software Foundation, write to the Free |
|||
Software Foundation; we sometimes make exceptions for this. Our |
|||
decision will be guided by the two goals of preserving the free status |
|||
of all derivatives of our free software and of promoting the sharing |
|||
and reuse of software generally. |
|||
|
|||
NO WARRANTY |
|||
|
|||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO |
|||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. |
|||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR |
|||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY |
|||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE |
|||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE |
|||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME |
|||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
|||
|
|||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN |
|||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY |
|||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU |
|||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR |
|||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE |
|||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING |
|||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A |
|||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF |
|||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
|||
DAMAGES. |
|||
|
|||
END OF TERMS AND CONDITIONS |
|||
|
|||
How to Apply These Terms to Your New Libraries |
|||
|
|||
If you develop a new library, and you want it to be of the greatest |
|||
possible use to the public, we recommend making it free software that |
|||
everyone can redistribute and change. You can do so by permitting |
|||
redistribution under these terms (or, alternatively, under the terms of the |
|||
ordinary General Public License). |
|||
|
|||
To apply these terms, attach the following notices to the library. It is |
|||
safest to attach them to the start of each source file to most effectively |
|||
convey the exclusion of warranty; and each file should have at least the |
|||
"copyright" line and a pointer to where the full notice is found. |
|||
|
|||
<one line to give the library's name and a brief idea of what it does.> |
|||
Copyright (C) <year> <name of author> |
|||
|
|||
This library is free software; you can redistribute it and/or |
|||
modify it under the terms of the GNU Lesser General Public |
|||
License as published by the Free Software Foundation; either |
|||
version 2.1 of the License, or (at your option) any later version. |
|||
|
|||
This library is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
Lesser General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU Lesser General Public |
|||
License along with this library; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|||
|
|||
Also add information on how to contact you by electronic and paper mail. |
|||
|
|||
You should also get your employer (if you work as a programmer) or your |
|||
school, if any, to sign a "copyright disclaimer" for the library, if |
|||
necessary. Here is a sample; alter the names: |
|||
|
|||
Yoyodyne, Inc., hereby disclaims all copyright interest in the |
|||
library `Frob' (a library for tweaking knobs) written by James Random Hacker. |
|||
|
|||
<signature of Ty Coon>, 1 April 1990 |
|||
Ty Coon, President of Vice |
|||
|
|||
That's all there is to it! |
|||
|
|||
vim: et sw=4 sts=4 |
@ -0,0 +1,29 @@ |
|||
HTML Purifier [](https://github.com/ezyang/htmlpurifier/actions/workflows/ci.yml) |
|||
============= |
|||
|
|||
HTML Purifier is an HTML filtering solution that uses a unique combination |
|||
of robust whitelists and aggressive parsing to ensure that not only are |
|||
XSS attacks thwarted, but the resulting HTML is standards compliant. |
|||
|
|||
HTML Purifier is oriented towards richly formatted documents from |
|||
untrusted sources that require CSS and a full tag-set. This library can |
|||
be configured to accept a more restrictive set of tags, but it won't be |
|||
as efficient as more bare-bones parsers. It will, however, do the job |
|||
right, which may be more important. |
|||
|
|||
Places to go: |
|||
|
|||
* See INSTALL for a quick installation guide |
|||
* See docs/ for developer-oriented documentation, code examples and |
|||
an in-depth installation guide. |
|||
* See WYSIWYG for information on editors like TinyMCE and FCKeditor |
|||
|
|||
HTML Purifier can be found on the web at: [http://htmlpurifier.org/](http://htmlpurifier.org/) |
|||
|
|||
## Installation |
|||
|
|||
Package available on [Composer](https://packagist.org/packages/ezyang/htmlpurifier). |
|||
|
|||
If you're using Composer to manage dependencies, you can use |
|||
|
|||
$ composer require ezyang/htmlpurifier |
@ -0,0 +1 @@ |
|||
4.17.0 |
@ -0,0 +1,45 @@ |
|||
{ |
|||
"name": "ezyang/htmlpurifier", |
|||
"description": "Standards compliant HTML filter written in PHP", |
|||
"type": "library", |
|||
"keywords": ["html"], |
|||
"homepage": "http://htmlpurifier.org/", |
|||
"license": "LGPL-2.1-or-later", |
|||
"authors": [ |
|||
{ |
|||
"name": "Edward Z. Yang", |
|||
"email": "admin@htmlpurifier.org", |
|||
"homepage": "http://ezyang.com" |
|||
} |
|||
], |
|||
"require": { |
|||
"php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0" |
|||
}, |
|||
"require-dev": { |
|||
"cerdic/css-tidy": "^1.7 || ^2.0", |
|||
"simpletest/simpletest": "dev-master" |
|||
}, |
|||
"autoload": { |
|||
"psr-0": { "HTMLPurifier": "library/" }, |
|||
"files": ["library/HTMLPurifier.composer.php"], |
|||
"exclude-from-classmap": [ |
|||
"/library/HTMLPurifier/Language/" |
|||
] |
|||
}, |
|||
"suggest": { |
|||
"cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", |
|||
"ext-iconv": "Converts text to and from non-UTF-8 encodings", |
|||
"ext-bcmath": "Used for unit conversion and imagecrash protection", |
|||
"ext-tidy": "Used for pretty-printing HTML" |
|||
}, |
|||
"config": { |
|||
"sort-packages": true |
|||
}, |
|||
"repositories": [ |
|||
{ |
|||
"type": "vcs", |
|||
"url": "https://github.com/ezyang/simpletest.git", |
|||
"no-api": true |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* This is a stub include that automatically configures the include path. |
|||
*/ |
|||
|
|||
set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path() ); |
|||
require_once 'HTMLPurifier/Bootstrap.php'; |
|||
require_once 'HTMLPurifier.autoload.php'; |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,14 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* @file |
|||
* Legacy autoloader for systems lacking spl_autoload_register |
|||
* |
|||
*/ |
|||
|
|||
spl_autoload_register(function($class) |
|||
{ |
|||
return HTMLPurifier_Bootstrap::autoload($class); |
|||
}); |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,25 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* @file |
|||
* Convenience file that registers autoload handler for HTML Purifier. |
|||
* It also does some sanity checks. |
|||
*/ |
|||
|
|||
if (function_exists('spl_autoload_register') && function_exists('spl_autoload_unregister')) { |
|||
// We need unregister for our pre-registering functionality |
|||
HTMLPurifier_Bootstrap::registerAutoload(); |
|||
if (function_exists('__autoload')) { |
|||
// Be polite and ensure that userland autoload gets retained |
|||
spl_autoload_register('__autoload'); |
|||
} |
|||
} elseif (!function_exists('__autoload')) { |
|||
require dirname(__FILE__) . '/HTMLPurifier.autoload-legacy.php'; |
|||
} |
|||
|
|||
// phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.zend_ze1_compatibility_modeRemoved |
|||
if (ini_get('zend.ze1_compatibility_mode')) { |
|||
trigger_error("HTML Purifier is not compatible with zend.ze1_compatibility_mode; please turn it off", E_USER_ERROR); |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,4 @@ |
|||
<?php |
|||
if (!defined('HTMLPURIFIER_PREFIX')) { |
|||
define('HTMLPURIFIER_PREFIX', dirname(__FILE__)); |
|||
} |
@ -0,0 +1,25 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* @file |
|||
* Defines a function wrapper for HTML Purifier for quick use. |
|||
* @note ''HTMLPurifier()'' is NOT the same as ''new HTMLPurifier()'' |
|||
*/ |
|||
|
|||
/** |
|||
* Purify HTML. |
|||
* @param string $html String HTML to purify |
|||
* @param mixed $config Configuration to use, can be any value accepted by |
|||
* HTMLPurifier_Config::create() |
|||
* @return string |
|||
*/ |
|||
function HTMLPurifier($html, $config = null) |
|||
{ |
|||
static $purifier = false; |
|||
if (!$purifier) { |
|||
$purifier = new HTMLPurifier(); |
|||
} |
|||
return $purifier->purify($html, $config); |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,235 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* @file |
|||
* This file was auto-generated by generate-includes.php and includes all of |
|||
* the core files required by HTML Purifier. Use this if performance is a |
|||
* primary concern and you are using an opcode cache. PLEASE DO NOT EDIT THIS |
|||
* FILE, changes will be overwritten the next time the script is run. |
|||
* |
|||
* @version 4.17.0 |
|||
* |
|||
* @warning |
|||
* You must *not* include any other HTML Purifier files before this file, |
|||
* because 'require' not 'require_once' is used. |
|||
* |
|||
* @warning |
|||
* This file requires that the include path contains the HTML Purifier |
|||
* library directory; this is not auto-set. |
|||
*/ |
|||
|
|||
require 'HTMLPurifier.php'; |
|||
require 'HTMLPurifier/Arborize.php'; |
|||
require 'HTMLPurifier/AttrCollections.php'; |
|||
require 'HTMLPurifier/AttrDef.php'; |
|||
require 'HTMLPurifier/AttrTransform.php'; |
|||
require 'HTMLPurifier/AttrTypes.php'; |
|||
require 'HTMLPurifier/AttrValidator.php'; |
|||
require 'HTMLPurifier/Bootstrap.php'; |
|||
require 'HTMLPurifier/Definition.php'; |
|||
require 'HTMLPurifier/CSSDefinition.php'; |
|||
require 'HTMLPurifier/ChildDef.php'; |
|||
require 'HTMLPurifier/Config.php'; |
|||
require 'HTMLPurifier/ConfigSchema.php'; |
|||
require 'HTMLPurifier/ContentSets.php'; |
|||
require 'HTMLPurifier/Context.php'; |
|||
require 'HTMLPurifier/DefinitionCache.php'; |
|||
require 'HTMLPurifier/DefinitionCacheFactory.php'; |
|||
require 'HTMLPurifier/Doctype.php'; |
|||
require 'HTMLPurifier/DoctypeRegistry.php'; |
|||
require 'HTMLPurifier/ElementDef.php'; |
|||
require 'HTMLPurifier/Encoder.php'; |
|||
require 'HTMLPurifier/EntityLookup.php'; |
|||
require 'HTMLPurifier/EntityParser.php'; |
|||
require 'HTMLPurifier/ErrorCollector.php'; |
|||
require 'HTMLPurifier/ErrorStruct.php'; |
|||
require 'HTMLPurifier/Exception.php'; |
|||
require 'HTMLPurifier/Filter.php'; |
|||
require 'HTMLPurifier/Generator.php'; |
|||
require 'HTMLPurifier/HTMLDefinition.php'; |
|||
require 'HTMLPurifier/HTMLModule.php'; |
|||
require 'HTMLPurifier/HTMLModuleManager.php'; |
|||
require 'HTMLPurifier/IDAccumulator.php'; |
|||
require 'HTMLPurifier/Injector.php'; |
|||
require 'HTMLPurifier/Language.php'; |
|||
require 'HTMLPurifier/LanguageFactory.php'; |
|||
require 'HTMLPurifier/Length.php'; |
|||
require 'HTMLPurifier/Lexer.php'; |
|||
require 'HTMLPurifier/Node.php'; |
|||
require 'HTMLPurifier/PercentEncoder.php'; |
|||
require 'HTMLPurifier/PropertyList.php'; |
|||
require 'HTMLPurifier/PropertyListIterator.php'; |
|||
require 'HTMLPurifier/Queue.php'; |
|||
require 'HTMLPurifier/Strategy.php'; |
|||
require 'HTMLPurifier/StringHash.php'; |
|||
require 'HTMLPurifier/StringHashParser.php'; |
|||
require 'HTMLPurifier/TagTransform.php'; |
|||
require 'HTMLPurifier/Token.php'; |
|||
require 'HTMLPurifier/TokenFactory.php'; |
|||
require 'HTMLPurifier/URI.php'; |
|||
require 'HTMLPurifier/URIDefinition.php'; |
|||
require 'HTMLPurifier/URIFilter.php'; |
|||
require 'HTMLPurifier/URIParser.php'; |
|||
require 'HTMLPurifier/URIScheme.php'; |
|||
require 'HTMLPurifier/URISchemeRegistry.php'; |
|||
require 'HTMLPurifier/UnitConverter.php'; |
|||
require 'HTMLPurifier/VarParser.php'; |
|||
require 'HTMLPurifier/VarParserException.php'; |
|||
require 'HTMLPurifier/Zipper.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS.php'; |
|||
require 'HTMLPurifier/AttrDef/Clone.php'; |
|||
require 'HTMLPurifier/AttrDef/Enum.php'; |
|||
require 'HTMLPurifier/AttrDef/Integer.php'; |
|||
require 'HTMLPurifier/AttrDef/Lang.php'; |
|||
require 'HTMLPurifier/AttrDef/Switch.php'; |
|||
require 'HTMLPurifier/AttrDef/Text.php'; |
|||
require 'HTMLPurifier/AttrDef/URI.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/Number.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/AlphaValue.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/Background.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/BackgroundPosition.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/Border.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/Color.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/Composite.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/Filter.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/Font.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/FontFamily.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/Ident.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/ImportantDecorator.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/Length.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/ListStyle.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/Multiple.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/Percentage.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/TextDecoration.php'; |
|||
require 'HTMLPurifier/AttrDef/CSS/URI.php'; |
|||
require 'HTMLPurifier/AttrDef/HTML/Bool.php'; |
|||
require 'HTMLPurifier/AttrDef/HTML/Nmtokens.php'; |
|||
require 'HTMLPurifier/AttrDef/HTML/Class.php'; |
|||
require 'HTMLPurifier/AttrDef/HTML/Color.php'; |
|||
require 'HTMLPurifier/AttrDef/HTML/ContentEditable.php'; |
|||
require 'HTMLPurifier/AttrDef/HTML/FrameTarget.php'; |
|||
require 'HTMLPurifier/AttrDef/HTML/ID.php'; |
|||
require 'HTMLPurifier/AttrDef/HTML/Pixels.php'; |
|||
require 'HTMLPurifier/AttrDef/HTML/Length.php'; |
|||
require 'HTMLPurifier/AttrDef/HTML/LinkTypes.php'; |
|||
require 'HTMLPurifier/AttrDef/HTML/MultiLength.php'; |
|||
require 'HTMLPurifier/AttrDef/URI/Email.php'; |
|||
require 'HTMLPurifier/AttrDef/URI/Host.php'; |
|||
require 'HTMLPurifier/AttrDef/URI/IPv4.php'; |
|||
require 'HTMLPurifier/AttrDef/URI/IPv6.php'; |
|||
require 'HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php'; |
|||
require 'HTMLPurifier/AttrTransform/Background.php'; |
|||
require 'HTMLPurifier/AttrTransform/BdoDir.php'; |
|||
require 'HTMLPurifier/AttrTransform/BgColor.php'; |
|||
require 'HTMLPurifier/AttrTransform/BoolToCSS.php'; |
|||
require 'HTMLPurifier/AttrTransform/Border.php'; |
|||
require 'HTMLPurifier/AttrTransform/EnumToCSS.php'; |
|||
require 'HTMLPurifier/AttrTransform/ImgRequired.php'; |
|||
require 'HTMLPurifier/AttrTransform/ImgSpace.php'; |
|||
require 'HTMLPurifier/AttrTransform/Input.php'; |
|||
require 'HTMLPurifier/AttrTransform/Lang.php'; |
|||
require 'HTMLPurifier/AttrTransform/Length.php'; |
|||
require 'HTMLPurifier/AttrTransform/Name.php'; |
|||
require 'HTMLPurifier/AttrTransform/NameSync.php'; |
|||
require 'HTMLPurifier/AttrTransform/Nofollow.php'; |
|||
require 'HTMLPurifier/AttrTransform/SafeEmbed.php'; |
|||
require 'HTMLPurifier/AttrTransform/SafeObject.php'; |
|||
require 'HTMLPurifier/AttrTransform/SafeParam.php'; |
|||
require 'HTMLPurifier/AttrTransform/ScriptRequired.php'; |
|||
require 'HTMLPurifier/AttrTransform/TargetBlank.php'; |
|||
require 'HTMLPurifier/AttrTransform/TargetNoopener.php'; |
|||
require 'HTMLPurifier/AttrTransform/TargetNoreferrer.php'; |
|||
require 'HTMLPurifier/AttrTransform/Textarea.php'; |
|||
require 'HTMLPurifier/ChildDef/Chameleon.php'; |
|||
require 'HTMLPurifier/ChildDef/Custom.php'; |
|||
require 'HTMLPurifier/ChildDef/Empty.php'; |
|||
require 'HTMLPurifier/ChildDef/List.php'; |
|||
require 'HTMLPurifier/ChildDef/Required.php'; |
|||
require 'HTMLPurifier/ChildDef/Optional.php'; |
|||
require 'HTMLPurifier/ChildDef/StrictBlockquote.php'; |
|||
require 'HTMLPurifier/ChildDef/Table.php'; |
|||
require 'HTMLPurifier/DefinitionCache/Decorator.php'; |
|||
require 'HTMLPurifier/DefinitionCache/Null.php'; |
|||
require 'HTMLPurifier/DefinitionCache/Serializer.php'; |
|||
require 'HTMLPurifier/DefinitionCache/Decorator/Cleanup.php'; |
|||
require 'HTMLPurifier/DefinitionCache/Decorator/Memory.php'; |
|||
require 'HTMLPurifier/HTMLModule/Bdo.php'; |
|||
require 'HTMLPurifier/HTMLModule/CommonAttributes.php'; |
|||
require 'HTMLPurifier/HTMLModule/Edit.php'; |
|||
require 'HTMLPurifier/HTMLModule/Forms.php'; |
|||
require 'HTMLPurifier/HTMLModule/Hypertext.php'; |
|||
require 'HTMLPurifier/HTMLModule/Iframe.php'; |
|||
require 'HTMLPurifier/HTMLModule/Image.php'; |
|||
require 'HTMLPurifier/HTMLModule/Legacy.php'; |
|||
require 'HTMLPurifier/HTMLModule/List.php'; |
|||
require 'HTMLPurifier/HTMLModule/Name.php'; |
|||
require 'HTMLPurifier/HTMLModule/Nofollow.php'; |
|||
require 'HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php'; |
|||
require 'HTMLPurifier/HTMLModule/Object.php'; |
|||
require 'HTMLPurifier/HTMLModule/Presentation.php'; |
|||
require 'HTMLPurifier/HTMLModule/Proprietary.php'; |
|||
require 'HTMLPurifier/HTMLModule/Ruby.php'; |
|||
require 'HTMLPurifier/HTMLModule/SafeEmbed.php'; |
|||
require 'HTMLPurifier/HTMLModule/SafeObject.php'; |
|||
require 'HTMLPurifier/HTMLModule/SafeScripting.php'; |
|||
require 'HTMLPurifier/HTMLModule/Scripting.php'; |
|||
require 'HTMLPurifier/HTMLModule/StyleAttribute.php'; |
|||
require 'HTMLPurifier/HTMLModule/Tables.php'; |
|||
require 'HTMLPurifier/HTMLModule/Target.php'; |
|||
require 'HTMLPurifier/HTMLModule/TargetBlank.php'; |
|||
require 'HTMLPurifier/HTMLModule/TargetNoopener.php'; |
|||
require 'HTMLPurifier/HTMLModule/TargetNoreferrer.php'; |
|||
require 'HTMLPurifier/HTMLModule/Text.php'; |
|||
require 'HTMLPurifier/HTMLModule/Tidy.php'; |
|||
require 'HTMLPurifier/HTMLModule/XMLCommonAttributes.php'; |
|||
require 'HTMLPurifier/HTMLModule/Tidy/Name.php'; |
|||
require 'HTMLPurifier/HTMLModule/Tidy/Proprietary.php'; |
|||
require 'HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php'; |
|||
require 'HTMLPurifier/HTMLModule/Tidy/Strict.php'; |
|||
require 'HTMLPurifier/HTMLModule/Tidy/Transitional.php'; |
|||
require 'HTMLPurifier/HTMLModule/Tidy/XHTML.php'; |
|||
require 'HTMLPurifier/Injector/AutoParagraph.php'; |
|||
require 'HTMLPurifier/Injector/DisplayLinkURI.php'; |
|||
require 'HTMLPurifier/Injector/Linkify.php'; |
|||
require 'HTMLPurifier/Injector/PurifierLinkify.php'; |
|||
require 'HTMLPurifier/Injector/RemoveEmpty.php'; |
|||
require 'HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php'; |
|||
require 'HTMLPurifier/Injector/SafeObject.php'; |
|||
require 'HTMLPurifier/Lexer/DOMLex.php'; |
|||
require 'HTMLPurifier/Lexer/DirectLex.php'; |
|||
require 'HTMLPurifier/Node/Comment.php'; |
|||
require 'HTMLPurifier/Node/Element.php'; |
|||
require 'HTMLPurifier/Node/Text.php'; |
|||
require 'HTMLPurifier/Strategy/Composite.php'; |
|||
require 'HTMLPurifier/Strategy/Core.php'; |
|||
require 'HTMLPurifier/Strategy/FixNesting.php'; |
|||
require 'HTMLPurifier/Strategy/MakeWellFormed.php'; |
|||
require 'HTMLPurifier/Strategy/RemoveForeignElements.php'; |
|||
require 'HTMLPurifier/Strategy/ValidateAttributes.php'; |
|||
require 'HTMLPurifier/TagTransform/Font.php'; |
|||
require 'HTMLPurifier/TagTransform/Simple.php'; |
|||
require 'HTMLPurifier/Token/Comment.php'; |
|||
require 'HTMLPurifier/Token/Tag.php'; |
|||
require 'HTMLPurifier/Token/Empty.php'; |
|||
require 'HTMLPurifier/Token/End.php'; |
|||
require 'HTMLPurifier/Token/Start.php'; |
|||
require 'HTMLPurifier/Token/Text.php'; |
|||
require 'HTMLPurifier/URIFilter/DisableExternal.php'; |
|||
require 'HTMLPurifier/URIFilter/DisableExternalResources.php'; |
|||
require 'HTMLPurifier/URIFilter/DisableResources.php'; |
|||
require 'HTMLPurifier/URIFilter/HostBlacklist.php'; |
|||
require 'HTMLPurifier/URIFilter/MakeAbsolute.php'; |
|||
require 'HTMLPurifier/URIFilter/Munge.php'; |
|||
require 'HTMLPurifier/URIFilter/SafeIframe.php'; |
|||
require 'HTMLPurifier/URIScheme/data.php'; |
|||
require 'HTMLPurifier/URIScheme/file.php'; |
|||
require 'HTMLPurifier/URIScheme/ftp.php'; |
|||
require 'HTMLPurifier/URIScheme/http.php'; |
|||
require 'HTMLPurifier/URIScheme/https.php'; |
|||
require 'HTMLPurifier/URIScheme/mailto.php'; |
|||
require 'HTMLPurifier/URIScheme/news.php'; |
|||
require 'HTMLPurifier/URIScheme/nntp.php'; |
|||
require 'HTMLPurifier/URIScheme/tel.php'; |
|||
require 'HTMLPurifier/VarParser/Flexible.php'; |
|||
require 'HTMLPurifier/VarParser/Native.php'; |
@ -0,0 +1,30 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* @file |
|||
* Emulation layer for code that used kses(), substituting in HTML Purifier. |
|||
*/ |
|||
|
|||
require_once dirname(__FILE__) . '/HTMLPurifier.auto.php'; |
|||
|
|||
function kses($string, $allowed_html, $allowed_protocols = null) |
|||
{ |
|||
$config = HTMLPurifier_Config::createDefault(); |
|||
$allowed_elements = array(); |
|||
$allowed_attributes = array(); |
|||
foreach ($allowed_html as $element => $attributes) { |
|||
$allowed_elements[$element] = true; |
|||
foreach ($attributes as $attribute => $x) { |
|||
$allowed_attributes["$element.$attribute"] = true; |
|||
} |
|||
} |
|||
$config->set('HTML.AllowedElements', $allowed_elements); |
|||
$config->set('HTML.AllowedAttributes', $allowed_attributes); |
|||
if ($allowed_protocols !== null) { |
|||
$config->set('URI.AllowedSchemes', $allowed_protocols); |
|||
} |
|||
$purifier = new HTMLPurifier($config); |
|||
return $purifier->purify($string); |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* @file |
|||
* Convenience stub file that adds HTML Purifier's library file to the path |
|||
* without any other side-effects. |
|||
*/ |
|||
|
|||
set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path() ); |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,297 @@ |
|||
<?php |
|||
|
|||
/*! @mainpage |
|||
* |
|||
* HTML Purifier is an HTML filter that will take an arbitrary snippet of |
|||
* HTML and rigorously test, validate and filter it into a version that |
|||
* is safe for output onto webpages. It achieves this by: |
|||
* |
|||
* -# Lexing (parsing into tokens) the document, |
|||
* -# Executing various strategies on the tokens: |
|||
* -# Removing all elements not in the whitelist, |
|||
* -# Making the tokens well-formed, |
|||
* -# Fixing the nesting of the nodes, and |
|||
* -# Validating attributes of the nodes; and |
|||
* -# Generating HTML from the purified tokens. |
|||
* |
|||
* However, most users will only need to interface with the HTMLPurifier |
|||
* and HTMLPurifier_Config. |
|||
*/ |
|||
|
|||
/* |
|||
HTML Purifier 4.17.0 - Standards Compliant HTML Filtering |
|||
Copyright (C) 2006-2008 Edward Z. Yang |
|||
|
|||
This library is free software; you can redistribute it and/or |
|||
modify it under the terms of the GNU Lesser General Public |
|||
License as published by the Free Software Foundation; either |
|||
version 2.1 of the License, or (at your option) any later version. |
|||
|
|||
This library is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
Lesser General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU Lesser General Public |
|||
License along with this library; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|||
*/ |
|||
|
|||
/** |
|||
* Facade that coordinates HTML Purifier's subsystems in order to purify HTML. |
|||
* |
|||
* @note There are several points in which configuration can be specified |
|||
* for HTML Purifier. The precedence of these (from lowest to |
|||
* highest) is as follows: |
|||
* -# Instance: new HTMLPurifier($config) |
|||
* -# Invocation: purify($html, $config) |
|||
* These configurations are entirely independent of each other and |
|||
* are *not* merged (this behavior may change in the future). |
|||
* |
|||
* @todo We need an easier way to inject strategies using the configuration |
|||
* object. |
|||
*/ |
|||
class HTMLPurifier |
|||
{ |
|||
|
|||
/** |
|||
* Version of HTML Purifier. |
|||
* @type string |
|||
*/ |
|||
public $version = '4.17.0'; |
|||
|
|||
/** |
|||
* Constant with version of HTML Purifier. |
|||
*/ |
|||
const VERSION = '4.17.0'; |
|||
|
|||
/** |
|||
* Global configuration object. |
|||
* @type HTMLPurifier_Config |
|||
*/ |
|||
public $config; |
|||
|
|||
/** |
|||
* Array of extra filter objects to run on HTML, |
|||
* for backwards compatibility. |
|||
* @type HTMLPurifier_Filter[] |
|||
*/ |
|||
private $filters = array(); |
|||
|
|||
/** |
|||
* Single instance of HTML Purifier. |
|||
* @type HTMLPurifier |
|||
*/ |
|||
private static $instance; |
|||
|
|||
/** |
|||
* @type HTMLPurifier_Strategy_Core |
|||
*/ |
|||
protected $strategy; |
|||
|
|||
/** |
|||
* @type HTMLPurifier_Generator |
|||
*/ |
|||
protected $generator; |
|||
|
|||
/** |
|||
* Resultant context of last run purification. |
|||
* Is an array of contexts if the last called method was purifyArray(). |
|||
* @type HTMLPurifier_Context |
|||
*/ |
|||
public $context; |
|||
|
|||
/** |
|||
* Initializes the purifier. |
|||
* |
|||
* @param HTMLPurifier_Config|mixed $config Optional HTMLPurifier_Config object |
|||
* for all instances of the purifier, if omitted, a default |
|||
* configuration is supplied (which can be overridden on a |
|||
* per-use basis). |
|||
* The parameter can also be any type that |
|||
* HTMLPurifier_Config::create() supports. |
|||
*/ |
|||
public function __construct($config = null) |
|||
{ |
|||
$this->config = HTMLPurifier_Config::create($config); |
|||
$this->strategy = new HTMLPurifier_Strategy_Core(); |
|||
} |
|||
|
|||
/** |
|||
* Adds a filter to process the output. First come first serve |
|||
* |
|||
* @param HTMLPurifier_Filter $filter HTMLPurifier_Filter object |
|||
*/ |
|||
public function addFilter($filter) |
|||
{ |
|||
trigger_error( |
|||
'HTMLPurifier->addFilter() is deprecated, use configuration directives' . |
|||
' in the Filter namespace or Filter.Custom', |
|||
E_USER_WARNING |
|||
); |
|||
$this->filters[] = $filter; |
|||
} |
|||
|
|||
/** |
|||
* Filters an HTML snippet/document to be XSS-free and standards-compliant. |
|||
* |
|||
* @param string $html String of HTML to purify |
|||
* @param HTMLPurifier_Config $config Config object for this operation, |
|||
* if omitted, defaults to the config object specified during this |
|||
* object's construction. The parameter can also be any type |
|||
* that HTMLPurifier_Config::create() supports. |
|||
* |
|||
* @return string Purified HTML |
|||
*/ |
|||
public function purify($html, $config = null) |
|||
{ |
|||
// :TODO: make the config merge in, instead of replace |
|||
$config = $config ? HTMLPurifier_Config::create($config) : $this->config; |
|||
|
|||
// implementation is partially environment dependant, partially |
|||
// configuration dependant |
|||
$lexer = HTMLPurifier_Lexer::create($config); |
|||
|
|||
$context = new HTMLPurifier_Context(); |
|||
|
|||
// setup HTML generator |
|||
$this->generator = new HTMLPurifier_Generator($config, $context); |
|||
$context->register('Generator', $this->generator); |
|||
|
|||
// set up global context variables |
|||
if ($config->get('Core.CollectErrors')) { |
|||
// may get moved out if other facilities use it |
|||
$language_factory = HTMLPurifier_LanguageFactory::instance(); |
|||
$language = $language_factory->create($config, $context); |
|||
$context->register('Locale', $language); |
|||
|
|||
$error_collector = new HTMLPurifier_ErrorCollector($context); |
|||
$context->register('ErrorCollector', $error_collector); |
|||
} |
|||
|
|||
// setup id_accumulator context, necessary due to the fact that |
|||
// AttrValidator can be called from many places |
|||
$id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); |
|||
$context->register('IDAccumulator', $id_accumulator); |
|||
|
|||
$html = HTMLPurifier_Encoder::convertToUTF8($html, $config, $context); |
|||
|
|||
// setup filters |
|||
$filter_flags = $config->getBatch('Filter'); |
|||
$custom_filters = $filter_flags['Custom']; |
|||
unset($filter_flags['Custom']); |
|||
$filters = array(); |
|||
foreach ($filter_flags as $filter => $flag) { |
|||
if (!$flag) { |
|||
continue; |
|||
} |
|||
if (strpos($filter, '.') !== false) { |
|||
continue; |
|||
} |
|||
$class = "HTMLPurifier_Filter_$filter"; |
|||
$filters[] = new $class; |
|||
} |
|||
foreach ($custom_filters as $filter) { |
|||
// maybe "HTMLPurifier_Filter_$filter", but be consistent with AutoFormat |
|||
$filters[] = $filter; |
|||
} |
|||
$filters = array_merge($filters, $this->filters); |
|||
// maybe prepare(), but later |
|||
|
|||
for ($i = 0, $filter_size = count($filters); $i < $filter_size; $i++) { |
|||
$html = $filters[$i]->preFilter($html, $config, $context); |
|||
} |
|||
|
|||
// purified HTML |
|||
$html = |
|||
$this->generator->generateFromTokens( |
|||
// list of tokens |
|||
$this->strategy->execute( |
|||
// list of un-purified tokens |
|||
$lexer->tokenizeHTML( |
|||
// un-purified HTML |
|||
$html, |
|||
$config, |
|||
$context |
|||
), |
|||
$config, |
|||
$context |
|||
) |
|||
); |
|||
|
|||
for ($i = $filter_size - 1; $i >= 0; $i--) { |
|||
$html = $filters[$i]->postFilter($html, $config, $context); |
|||
} |
|||
|
|||
$html = HTMLPurifier_Encoder::convertFromUTF8($html, $config, $context); |
|||
$this->context =& $context; |
|||
return $html; |
|||
} |
|||
|
|||
/** |
|||
* Filters an array of HTML snippets |
|||
* |
|||
* @param string[] $array_of_html Array of html snippets |
|||
* @param HTMLPurifier_Config $config Optional config object for this operation. |
|||
* See HTMLPurifier::purify() for more details. |
|||
* |
|||
* @return string[] Array of purified HTML |
|||
*/ |
|||
public function purifyArray($array_of_html, $config = null) |
|||
{ |
|||
$context_array = array(); |
|||
$array = array(); |
|||
foreach($array_of_html as $key=>$value){ |
|||
if (is_array($value)) { |
|||
$array[$key] = $this->purifyArray($value, $config); |
|||
} else { |
|||
$array[$key] = $this->purify($value, $config); |
|||
} |
|||
$context_array[$key] = $this->context; |
|||
} |
|||
$this->context = $context_array; |
|||
return $array; |
|||
} |
|||
|
|||
/** |
|||
* Singleton for enforcing just one HTML Purifier in your system |
|||
* |
|||
* @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype |
|||
* HTMLPurifier instance to overload singleton with, |
|||
* or HTMLPurifier_Config instance to configure the |
|||
* generated version with. |
|||
* |
|||
* @return HTMLPurifier |
|||
*/ |
|||
public static function instance($prototype = null) |
|||
{ |
|||
if (!self::$instance || $prototype) { |
|||
if ($prototype instanceof HTMLPurifier) { |
|||
self::$instance = $prototype; |
|||
} elseif ($prototype) { |
|||
self::$instance = new HTMLPurifier($prototype); |
|||
} else { |
|||
self::$instance = new HTMLPurifier(); |
|||
} |
|||
} |
|||
return self::$instance; |
|||
} |
|||
|
|||
/** |
|||
* Singleton for enforcing just one HTML Purifier in your system |
|||
* |
|||
* @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype |
|||
* HTMLPurifier instance to overload singleton with, |
|||
* or HTMLPurifier_Config instance to configure the |
|||
* generated version with. |
|||
* |
|||
* @return HTMLPurifier |
|||
* @note Backwards compatibility, see instance() |
|||
*/ |
|||
public static function getInstance($prototype = null) |
|||
{ |
|||
return HTMLPurifier::instance($prototype); |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,229 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* @file |
|||
* This file was auto-generated by generate-includes.php and includes all of |
|||
* the core files required by HTML Purifier. This is a convenience stub that |
|||
* includes all files using dirname(__FILE__) and require_once. PLEASE DO NOT |
|||
* EDIT THIS FILE, changes will be overwritten the next time the script is run. |
|||
* |
|||
* Changes to include_path are not necessary. |
|||
*/ |
|||
|
|||
$__dir = dirname(__FILE__); |
|||
|
|||
require_once $__dir . '/HTMLPurifier.php'; |
|||
require_once $__dir . '/HTMLPurifier/Arborize.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrCollections.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTypes.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrValidator.php'; |
|||
require_once $__dir . '/HTMLPurifier/Bootstrap.php'; |
|||
require_once $__dir . '/HTMLPurifier/Definition.php'; |
|||
require_once $__dir . '/HTMLPurifier/CSSDefinition.php'; |
|||
require_once $__dir . '/HTMLPurifier/ChildDef.php'; |
|||
require_once $__dir . '/HTMLPurifier/Config.php'; |
|||
require_once $__dir . '/HTMLPurifier/ConfigSchema.php'; |
|||
require_once $__dir . '/HTMLPurifier/ContentSets.php'; |
|||
require_once $__dir . '/HTMLPurifier/Context.php'; |
|||
require_once $__dir . '/HTMLPurifier/DefinitionCache.php'; |
|||
require_once $__dir . '/HTMLPurifier/DefinitionCacheFactory.php'; |
|||
require_once $__dir . '/HTMLPurifier/Doctype.php'; |
|||
require_once $__dir . '/HTMLPurifier/DoctypeRegistry.php'; |
|||
require_once $__dir . '/HTMLPurifier/ElementDef.php'; |
|||
require_once $__dir . '/HTMLPurifier/Encoder.php'; |
|||
require_once $__dir . '/HTMLPurifier/EntityLookup.php'; |
|||
require_once $__dir . '/HTMLPurifier/EntityParser.php'; |
|||
require_once $__dir . '/HTMLPurifier/ErrorCollector.php'; |
|||
require_once $__dir . '/HTMLPurifier/ErrorStruct.php'; |
|||
require_once $__dir . '/HTMLPurifier/Exception.php'; |
|||
require_once $__dir . '/HTMLPurifier/Filter.php'; |
|||
require_once $__dir . '/HTMLPurifier/Generator.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLDefinition.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModuleManager.php'; |
|||
require_once $__dir . '/HTMLPurifier/IDAccumulator.php'; |
|||
require_once $__dir . '/HTMLPurifier/Injector.php'; |
|||
require_once $__dir . '/HTMLPurifier/Language.php'; |
|||
require_once $__dir . '/HTMLPurifier/LanguageFactory.php'; |
|||
require_once $__dir . '/HTMLPurifier/Length.php'; |
|||
require_once $__dir . '/HTMLPurifier/Lexer.php'; |
|||
require_once $__dir . '/HTMLPurifier/Node.php'; |
|||
require_once $__dir . '/HTMLPurifier/PercentEncoder.php'; |
|||
require_once $__dir . '/HTMLPurifier/PropertyList.php'; |
|||
require_once $__dir . '/HTMLPurifier/PropertyListIterator.php'; |
|||
require_once $__dir . '/HTMLPurifier/Queue.php'; |
|||
require_once $__dir . '/HTMLPurifier/Strategy.php'; |
|||
require_once $__dir . '/HTMLPurifier/StringHash.php'; |
|||
require_once $__dir . '/HTMLPurifier/StringHashParser.php'; |
|||
require_once $__dir . '/HTMLPurifier/TagTransform.php'; |
|||
require_once $__dir . '/HTMLPurifier/Token.php'; |
|||
require_once $__dir . '/HTMLPurifier/TokenFactory.php'; |
|||
require_once $__dir . '/HTMLPurifier/URI.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIDefinition.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIFilter.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIParser.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIScheme.php'; |
|||
require_once $__dir . '/HTMLPurifier/URISchemeRegistry.php'; |
|||
require_once $__dir . '/HTMLPurifier/UnitConverter.php'; |
|||
require_once $__dir . '/HTMLPurifier/VarParser.php'; |
|||
require_once $__dir . '/HTMLPurifier/VarParserException.php'; |
|||
require_once $__dir . '/HTMLPurifier/Zipper.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/Clone.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/Enum.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/Integer.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/Lang.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/Switch.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/Text.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/URI.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Number.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/AlphaValue.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Background.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Border.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Color.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Composite.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Filter.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Font.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/FontFamily.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Ident.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Length.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/ListStyle.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Multiple.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Percentage.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/TextDecoration.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/URI.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Bool.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Nmtokens.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Class.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Color.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/ContentEditable.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/FrameTarget.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/ID.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Pixels.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Length.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/LinkTypes.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/MultiLength.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/URI/Email.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/URI/Host.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/URI/IPv4.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/URI/IPv6.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/Background.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/BdoDir.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/BgColor.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/BoolToCSS.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/Border.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/EnumToCSS.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/ImgRequired.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/ImgSpace.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/Input.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/Lang.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/Length.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/Name.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/NameSync.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/Nofollow.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeEmbed.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeObject.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeParam.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/ScriptRequired.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/TargetBlank.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/TargetNoopener.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/TargetNoreferrer.php'; |
|||
require_once $__dir . '/HTMLPurifier/AttrTransform/Textarea.php'; |
|||
require_once $__dir . '/HTMLPurifier/ChildDef/Chameleon.php'; |
|||
require_once $__dir . '/HTMLPurifier/ChildDef/Custom.php'; |
|||
require_once $__dir . '/HTMLPurifier/ChildDef/Empty.php'; |
|||
require_once $__dir . '/HTMLPurifier/ChildDef/List.php'; |
|||
require_once $__dir . '/HTMLPurifier/ChildDef/Required.php'; |
|||
require_once $__dir . '/HTMLPurifier/ChildDef/Optional.php'; |
|||
require_once $__dir . '/HTMLPurifier/ChildDef/StrictBlockquote.php'; |
|||
require_once $__dir . '/HTMLPurifier/ChildDef/Table.php'; |
|||
require_once $__dir . '/HTMLPurifier/DefinitionCache/Decorator.php'; |
|||
require_once $__dir . '/HTMLPurifier/DefinitionCache/Null.php'; |
|||
require_once $__dir . '/HTMLPurifier/DefinitionCache/Serializer.php'; |
|||
require_once $__dir . '/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php'; |
|||
require_once $__dir . '/HTMLPurifier/DefinitionCache/Decorator/Memory.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Bdo.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/CommonAttributes.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Edit.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Forms.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Hypertext.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Iframe.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Image.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Legacy.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/List.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Name.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Nofollow.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Object.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Presentation.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Proprietary.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Ruby.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/SafeEmbed.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/SafeObject.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/SafeScripting.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Scripting.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/StyleAttribute.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Tables.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Target.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/TargetBlank.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/TargetNoopener.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/TargetNoreferrer.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Text.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/XMLCommonAttributes.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Name.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Proprietary.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Strict.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Transitional.php'; |
|||
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/XHTML.php'; |
|||
require_once $__dir . '/HTMLPurifier/Injector/AutoParagraph.php'; |
|||
require_once $__dir . '/HTMLPurifier/Injector/DisplayLinkURI.php'; |
|||
require_once $__dir . '/HTMLPurifier/Injector/Linkify.php'; |
|||
require_once $__dir . '/HTMLPurifier/Injector/PurifierLinkify.php'; |
|||
require_once $__dir . '/HTMLPurifier/Injector/RemoveEmpty.php'; |
|||
require_once $__dir . '/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php'; |
|||
require_once $__dir . '/HTMLPurifier/Injector/SafeObject.php'; |
|||
require_once $__dir . '/HTMLPurifier/Lexer/DOMLex.php'; |
|||
require_once $__dir . '/HTMLPurifier/Lexer/DirectLex.php'; |
|||
require_once $__dir . '/HTMLPurifier/Node/Comment.php'; |
|||
require_once $__dir . '/HTMLPurifier/Node/Element.php'; |
|||
require_once $__dir . '/HTMLPurifier/Node/Text.php'; |
|||
require_once $__dir . '/HTMLPurifier/Strategy/Composite.php'; |
|||
require_once $__dir . '/HTMLPurifier/Strategy/Core.php'; |
|||
require_once $__dir . '/HTMLPurifier/Strategy/FixNesting.php'; |
|||
require_once $__dir . '/HTMLPurifier/Strategy/MakeWellFormed.php'; |
|||
require_once $__dir . '/HTMLPurifier/Strategy/RemoveForeignElements.php'; |
|||
require_once $__dir . '/HTMLPurifier/Strategy/ValidateAttributes.php'; |
|||
require_once $__dir . '/HTMLPurifier/TagTransform/Font.php'; |
|||
require_once $__dir . '/HTMLPurifier/TagTransform/Simple.php'; |
|||
require_once $__dir . '/HTMLPurifier/Token/Comment.php'; |
|||
require_once $__dir . '/HTMLPurifier/Token/Tag.php'; |
|||
require_once $__dir . '/HTMLPurifier/Token/Empty.php'; |
|||
require_once $__dir . '/HTMLPurifier/Token/End.php'; |
|||
require_once $__dir . '/HTMLPurifier/Token/Start.php'; |
|||
require_once $__dir . '/HTMLPurifier/Token/Text.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIFilter/DisableExternal.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIFilter/DisableExternalResources.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIFilter/DisableResources.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIFilter/HostBlacklist.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIFilter/MakeAbsolute.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIFilter/Munge.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIFilter/SafeIframe.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIScheme/data.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIScheme/file.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIScheme/ftp.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIScheme/http.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIScheme/https.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIScheme/mailto.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIScheme/news.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIScheme/nntp.php'; |
|||
require_once $__dir . '/HTMLPurifier/URIScheme/tel.php'; |
|||
require_once $__dir . '/HTMLPurifier/VarParser/Flexible.php'; |
|||
require_once $__dir . '/HTMLPurifier/VarParser/Native.php'; |
@ -0,0 +1,71 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Converts a stream of HTMLPurifier_Token into an HTMLPurifier_Node, |
|||
* and back again. |
|||
* |
|||
* @note This transformation is not an equivalence. We mutate the input |
|||
* token stream to make it so; see all [MUT] markers in code. |
|||
*/ |
|||
class HTMLPurifier_Arborize |
|||
{ |
|||
public static function arborize($tokens, $config, $context) { |
|||
$definition = $config->getHTMLDefinition(); |
|||
$parent = new HTMLPurifier_Token_Start($definition->info_parent); |
|||
$stack = array($parent->toNode()); |
|||
foreach ($tokens as $token) { |
|||
$token->skip = null; // [MUT] |
|||
$token->carryover = null; // [MUT] |
|||
if ($token instanceof HTMLPurifier_Token_End) { |
|||
$token->start = null; // [MUT] |
|||
$r = array_pop($stack); |
|||
//assert($r->name === $token->name); |
|||
//assert(empty($token->attr)); |
|||
$r->endCol = $token->col; |
|||
$r->endLine = $token->line; |
|||
$r->endArmor = $token->armor; |
|||
continue; |
|||
} |
|||
$node = $token->toNode(); |
|||
$stack[count($stack)-1]->children[] = $node; |
|||
if ($token instanceof HTMLPurifier_Token_Start) { |
|||
$stack[] = $node; |
|||
} |
|||
} |
|||
//assert(count($stack) == 1); |
|||
return $stack[0]; |
|||
} |
|||
|
|||
public static function flatten($node, $config, $context) { |
|||
$level = 0; |
|||
$nodes = array($level => new HTMLPurifier_Queue(array($node))); |
|||
$closingTokens = array(); |
|||
$tokens = array(); |
|||
do { |
|||
while (!$nodes[$level]->isEmpty()) { |
|||
$node = $nodes[$level]->shift(); // FIFO |
|||
list($start, $end) = $node->toTokenPair(); |
|||
if ($level > 0) { |
|||
$tokens[] = $start; |
|||
} |
|||
if ($end !== NULL) { |
|||
$closingTokens[$level][] = $end; |
|||
} |
|||
if ($node instanceof HTMLPurifier_Node_Element) { |
|||
$level++; |
|||
$nodes[$level] = new HTMLPurifier_Queue(); |
|||
foreach ($node->children as $childNode) { |
|||
$nodes[$level]->push($childNode); |
|||
} |
|||
} |
|||
} |
|||
$level--; |
|||
if ($level && isset($closingTokens[$level])) { |
|||
while ($token = array_pop($closingTokens[$level])) { |
|||
$tokens[] = $token; |
|||
} |
|||
} |
|||
} while ($level > 0); |
|||
return $tokens; |
|||
} |
|||
} |
@ -0,0 +1,148 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Defines common attribute collections that modules reference |
|||
*/ |
|||
|
|||
class HTMLPurifier_AttrCollections |
|||
{ |
|||
|
|||
/** |
|||
* Associative array of attribute collections, indexed by name. |
|||
* @type array |
|||
*/ |
|||
public $info = array(); |
|||
|
|||
/** |
|||
* Performs all expansions on internal data for use by other inclusions |
|||
* It also collects all attribute collection extensions from |
|||
* modules |
|||
* @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance |
|||
* @param HTMLPurifier_HTMLModule[] $modules Hash array of HTMLPurifier_HTMLModule members |
|||
*/ |
|||
public function __construct($attr_types, $modules) |
|||
{ |
|||
$this->doConstruct($attr_types, $modules); |
|||
} |
|||
|
|||
public function doConstruct($attr_types, $modules) |
|||
{ |
|||
// load extensions from the modules |
|||
foreach ($modules as $module) { |
|||
foreach ($module->attr_collections as $coll_i => $coll) { |
|||
if (!isset($this->info[$coll_i])) { |
|||
$this->info[$coll_i] = array(); |
|||
} |
|||
foreach ($coll as $attr_i => $attr) { |
|||
if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) { |
|||
// merge in includes |
|||
$this->info[$coll_i][$attr_i] = array_merge( |
|||
$this->info[$coll_i][$attr_i], |
|||
$attr |
|||
); |
|||
continue; |
|||
} |
|||
$this->info[$coll_i][$attr_i] = $attr; |
|||
} |
|||
} |
|||
} |
|||
// perform internal expansions and inclusions |
|||
foreach ($this->info as $name => $attr) { |
|||
// merge attribute collections that include others |
|||
$this->performInclusions($this->info[$name]); |
|||
// replace string identifiers with actual attribute objects |
|||
$this->expandIdentifiers($this->info[$name], $attr_types); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Takes a reference to an attribute associative array and performs |
|||
* all inclusions specified by the zero index. |
|||
* @param array &$attr Reference to attribute array |
|||
*/ |
|||
public function performInclusions(&$attr) |
|||
{ |
|||
if (!isset($attr[0])) { |
|||
return; |
|||
} |
|||
$merge = $attr[0]; |
|||
$seen = array(); // recursion guard |
|||
// loop through all the inclusions |
|||
for ($i = 0; isset($merge[$i]); $i++) { |
|||
if (isset($seen[$merge[$i]])) { |
|||
continue; |
|||
} |
|||
$seen[$merge[$i]] = true; |
|||
// foreach attribute of the inclusion, copy it over |
|||
if (!isset($this->info[$merge[$i]])) { |
|||
continue; |
|||
} |
|||
foreach ($this->info[$merge[$i]] as $key => $value) { |
|||
if (isset($attr[$key])) { |
|||
continue; |
|||
} // also catches more inclusions |
|||
$attr[$key] = $value; |
|||
} |
|||
if (isset($this->info[$merge[$i]][0])) { |
|||
// recursion |
|||
$merge = array_merge($merge, $this->info[$merge[$i]][0]); |
|||
} |
|||
} |
|||
unset($attr[0]); |
|||
} |
|||
|
|||
/** |
|||
* Expands all string identifiers in an attribute array by replacing |
|||
* them with the appropriate values inside HTMLPurifier_AttrTypes |
|||
* @param array &$attr Reference to attribute array |
|||
* @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance |
|||
*/ |
|||
public function expandIdentifiers(&$attr, $attr_types) |
|||
{ |
|||
// because foreach will process new elements we add, make sure we |
|||
// skip duplicates |
|||
$processed = array(); |
|||
|
|||
foreach ($attr as $def_i => $def) { |
|||
// skip inclusions |
|||
if ($def_i === 0) { |
|||
continue; |
|||
} |
|||
|
|||
if (isset($processed[$def_i])) { |
|||
continue; |
|||
} |
|||
|
|||
// determine whether or not attribute is required |
|||
if ($required = (strpos($def_i, '*') !== false)) { |
|||
// rename the definition |
|||
unset($attr[$def_i]); |
|||
$def_i = trim($def_i, '*'); |
|||
$attr[$def_i] = $def; |
|||
} |
|||
|
|||
$processed[$def_i] = true; |
|||
|
|||
// if we've already got a literal object, move on |
|||
if (is_object($def)) { |
|||
// preserve previous required |
|||
$attr[$def_i]->required = ($required || $attr[$def_i]->required); |
|||
continue; |
|||
} |
|||
|
|||
if ($def === false) { |
|||
unset($attr[$def_i]); |
|||
continue; |
|||
} |
|||
|
|||
if ($t = $attr_types->get($def)) { |
|||
$attr[$def_i] = $t; |
|||
$attr[$def_i]->required = $required; |
|||
} else { |
|||
unset($attr[$def_i]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,144 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Base class for all validating attribute definitions. |
|||
* |
|||
* This family of classes forms the core for not only HTML attribute validation, |
|||
* but also any sort of string that needs to be validated or cleaned (which |
|||
* means CSS properties and composite definitions are defined here too). |
|||
* Besides defining (through code) what precisely makes the string valid, |
|||
* subclasses are also responsible for cleaning the code if possible. |
|||
*/ |
|||
|
|||
abstract class HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* Tells us whether or not an HTML attribute is minimized. |
|||
* Has no meaning in other contexts. |
|||
* @type bool |
|||
*/ |
|||
public $minimized = false; |
|||
|
|||
/** |
|||
* Tells us whether or not an HTML attribute is required. |
|||
* Has no meaning in other contexts |
|||
* @type bool |
|||
*/ |
|||
public $required = false; |
|||
|
|||
/** |
|||
* Validates and cleans passed string according to a definition. |
|||
* |
|||
* @param string $string String to be validated and cleaned. |
|||
* @param HTMLPurifier_Config $config Mandatory HTMLPurifier_Config object. |
|||
* @param HTMLPurifier_Context $context Mandatory HTMLPurifier_Context object. |
|||
*/ |
|||
abstract public function validate($string, $config, $context); |
|||
|
|||
/** |
|||
* Convenience method that parses a string as if it were CDATA. |
|||
* |
|||
* This method process a string in the manner specified at |
|||
* <http://www.w3.org/TR/html4/types.html#h-6.2> by removing |
|||
* leading and trailing whitespace, ignoring line feeds, and replacing |
|||
* carriage returns and tabs with spaces. While most useful for HTML |
|||
* attributes specified as CDATA, it can also be applied to most CSS |
|||
* values. |
|||
* |
|||
* @note This method is not entirely standards compliant, as trim() removes |
|||
* more types of whitespace than specified in the spec. In practice, |
|||
* this is rarely a problem, as those extra characters usually have |
|||
* already been removed by HTMLPurifier_Encoder. |
|||
* |
|||
* @warning This processing is inconsistent with XML's whitespace handling |
|||
* as specified by section 3.3.3 and referenced XHTML 1.0 section |
|||
* 4.7. However, note that we are NOT necessarily |
|||
* parsing XML, thus, this behavior may still be correct. We |
|||
* assume that newlines have been normalized. |
|||
*/ |
|||
public function parseCDATA($string) |
|||
{ |
|||
$string = trim($string); |
|||
$string = str_replace(array("\n", "\t", "\r"), ' ', $string); |
|||
return $string; |
|||
} |
|||
|
|||
/** |
|||
* Factory method for creating this class from a string. |
|||
* @param string $string String construction info |
|||
* @return HTMLPurifier_AttrDef Created AttrDef object corresponding to $string |
|||
*/ |
|||
public function make($string) |
|||
{ |
|||
// default implementation, return a flyweight of this object. |
|||
// If $string has an effect on the returned object (i.e. you |
|||
// need to overload this method), it is best |
|||
// to clone or instantiate new copies. (Instantiation is safer.) |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* Removes spaces from rgb(0, 0, 0) so that shorthand CSS properties work |
|||
* properly. THIS IS A HACK! |
|||
* @param string $string a CSS colour definition |
|||
* @return string |
|||
*/ |
|||
protected function mungeRgb($string) |
|||
{ |
|||
$p = '\s*(\d+(\.\d+)?([%]?))\s*'; |
|||
|
|||
if (preg_match('/(rgba|hsla)\(/', $string)) { |
|||
return preg_replace('/(rgba|hsla)\('.$p.','.$p.','.$p.','.$p.'\)/', '\1(\2,\5,\8,\11)', $string); |
|||
} |
|||
|
|||
return preg_replace('/(rgb|hsl)\('.$p.','.$p.','.$p.'\)/', '\1(\2,\5,\8)', $string); |
|||
} |
|||
|
|||
/** |
|||
* Parses a possibly escaped CSS string and returns the "pure" |
|||
* version of it. |
|||
*/ |
|||
protected function expandCSSEscape($string) |
|||
{ |
|||
// flexibly parse it |
|||
$ret = ''; |
|||
for ($i = 0, $c = strlen($string); $i < $c; $i++) { |
|||
if ($string[$i] === '\\') { |
|||
$i++; |
|||
if ($i >= $c) { |
|||
$ret .= '\\'; |
|||
break; |
|||
} |
|||
if (ctype_xdigit($string[$i])) { |
|||
$code = $string[$i]; |
|||
for ($a = 1, $i++; $i < $c && $a < 6; $i++, $a++) { |
|||
if (!ctype_xdigit($string[$i])) { |
|||
break; |
|||
} |
|||
$code .= $string[$i]; |
|||
} |
|||
// We have to be extremely careful when adding |
|||
// new characters, to make sure we're not breaking |
|||
// the encoding. |
|||
$char = HTMLPurifier_Encoder::unichr(hexdec($code)); |
|||
if (HTMLPurifier_Encoder::cleanUTF8($char) === '') { |
|||
continue; |
|||
} |
|||
$ret .= $char; |
|||
if ($i < $c && trim($string[$i]) !== '') { |
|||
$i--; |
|||
} |
|||
continue; |
|||
} |
|||
if ($string[$i] === "\n") { |
|||
continue; |
|||
} |
|||
} |
|||
$ret .= $string[$i]; |
|||
} |
|||
return $ret; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,136 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates the HTML attribute style, otherwise known as CSS. |
|||
* @note We don't implement the whole CSS specification, so it might be |
|||
* difficult to reuse this component in the context of validating |
|||
* actual stylesheet declarations. |
|||
* @note If we were really serious about validating the CSS, we would |
|||
* tokenize the styles and then parse the tokens. Obviously, we |
|||
* are not doing that. Doing that could seriously harm performance, |
|||
* but would make these components a lot more viable for a CSS |
|||
* filtering solution. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* @param string $css |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($css, $config, $context) |
|||
{ |
|||
$css = $this->parseCDATA($css); |
|||
|
|||
$definition = $config->getCSSDefinition(); |
|||
$allow_duplicates = $config->get("CSS.AllowDuplicates"); |
|||
|
|||
|
|||
// According to the CSS2.1 spec, the places where a |
|||
// non-delimiting semicolon can appear are in strings |
|||
// escape sequences. So here is some dumb hack to |
|||
// handle quotes. |
|||
$len = strlen($css); |
|||
$accum = ""; |
|||
$declarations = array(); |
|||
$quoted = false; |
|||
for ($i = 0; $i < $len; $i++) { |
|||
$c = strcspn($css, ";'\"", $i); |
|||
$accum .= substr($css, $i, $c); |
|||
$i += $c; |
|||
if ($i == $len) break; |
|||
$d = $css[$i]; |
|||
if ($quoted) { |
|||
$accum .= $d; |
|||
if ($d == $quoted) { |
|||
$quoted = false; |
|||
} |
|||
} else { |
|||
if ($d == ";") { |
|||
$declarations[] = $accum; |
|||
$accum = ""; |
|||
} else { |
|||
$accum .= $d; |
|||
$quoted = $d; |
|||
} |
|||
} |
|||
} |
|||
if ($accum != "") $declarations[] = $accum; |
|||
|
|||
$propvalues = array(); |
|||
$new_declarations = ''; |
|||
|
|||
/** |
|||
* Name of the current CSS property being validated. |
|||
*/ |
|||
$property = false; |
|||
$context->register('CurrentCSSProperty', $property); |
|||
|
|||
foreach ($declarations as $declaration) { |
|||
if (!$declaration) { |
|||
continue; |
|||
} |
|||
if (!strpos($declaration, ':')) { |
|||
continue; |
|||
} |
|||
list($property, $value) = explode(':', $declaration, 2); |
|||
$property = trim($property); |
|||
$value = trim($value); |
|||
$ok = false; |
|||
do { |
|||
if (isset($definition->info[$property])) { |
|||
$ok = true; |
|||
break; |
|||
} |
|||
if (ctype_lower($property)) { |
|||
break; |
|||
} |
|||
$property = strtolower($property); |
|||
if (isset($definition->info[$property])) { |
|||
$ok = true; |
|||
break; |
|||
} |
|||
} while (0); |
|||
if (!$ok) { |
|||
continue; |
|||
} |
|||
// inefficient call, since the validator will do this again |
|||
if (strtolower(trim($value)) !== 'inherit') { |
|||
// inherit works for everything (but only on the base property) |
|||
$result = $definition->info[$property]->validate( |
|||
$value, |
|||
$config, |
|||
$context |
|||
); |
|||
} else { |
|||
$result = 'inherit'; |
|||
} |
|||
if ($result === false) { |
|||
continue; |
|||
} |
|||
if ($allow_duplicates) { |
|||
$new_declarations .= "$property:$result;"; |
|||
} else { |
|||
$propvalues[$property] = $result; |
|||
} |
|||
} |
|||
|
|||
$context->destroy('CurrentCSSProperty'); |
|||
|
|||
// procedure does not write the new CSS simultaneously, so it's |
|||
// slightly inefficient, but it's the only way of getting rid of |
|||
// duplicates. Perhaps config to optimize it, but not now. |
|||
|
|||
foreach ($propvalues as $prop => $value) { |
|||
$new_declarations .= "$prop:$value;"; |
|||
} |
|||
|
|||
return $new_declarations ? $new_declarations : false; |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,34 @@ |
|||
<?php |
|||
|
|||
class HTMLPurifier_AttrDef_CSS_AlphaValue extends HTMLPurifier_AttrDef_CSS_Number |
|||
{ |
|||
|
|||
public function __construct() |
|||
{ |
|||
parent::__construct(false); // opacity is non-negative, but we will clamp it |
|||
} |
|||
|
|||
/** |
|||
* @param string $number |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return string |
|||
*/ |
|||
public function validate($number, $config, $context) |
|||
{ |
|||
$result = parent::validate($number, $config, $context); |
|||
if ($result === false) { |
|||
return $result; |
|||
} |
|||
$float = (float)$result; |
|||
if ($float < 0.0) { |
|||
$result = '0'; |
|||
} |
|||
if ($float > 1.0) { |
|||
$result = '1'; |
|||
} |
|||
return $result; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,113 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates shorthand CSS property background. |
|||
* @warning Does not support url tokens that have internal spaces. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* Local copy of component validators. |
|||
* @type HTMLPurifier_AttrDef[] |
|||
* @note See HTMLPurifier_AttrDef_Font::$info for a similar impl. |
|||
*/ |
|||
protected $info; |
|||
|
|||
/** |
|||
* @param HTMLPurifier_Config $config |
|||
*/ |
|||
public function __construct($config) |
|||
{ |
|||
$def = $config->getCSSDefinition(); |
|||
$this->info['background-color'] = $def->info['background-color']; |
|||
$this->info['background-image'] = $def->info['background-image']; |
|||
$this->info['background-repeat'] = $def->info['background-repeat']; |
|||
$this->info['background-attachment'] = $def->info['background-attachment']; |
|||
$this->info['background-position'] = $def->info['background-position']; |
|||
$this->info['background-size'] = $def->info['background-size']; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
// regular pre-processing |
|||
$string = $this->parseCDATA($string); |
|||
if ($string === '') { |
|||
return false; |
|||
} |
|||
|
|||
// munge rgb() decl if necessary |
|||
$string = $this->mungeRgb($string); |
|||
|
|||
// assumes URI doesn't have spaces in it |
|||
$bits = explode(' ', $string); // bits to process |
|||
|
|||
$caught = array(); |
|||
$caught['color'] = false; |
|||
$caught['image'] = false; |
|||
$caught['repeat'] = false; |
|||
$caught['attachment'] = false; |
|||
$caught['position'] = false; |
|||
$caught['size'] = false; |
|||
|
|||
$i = 0; // number of catches |
|||
|
|||
foreach ($bits as $bit) { |
|||
if ($bit === '') { |
|||
continue; |
|||
} |
|||
foreach ($caught as $key => $status) { |
|||
if ($key != 'position') { |
|||
if ($status !== false) { |
|||
continue; |
|||
} |
|||
$r = $this->info['background-' . $key]->validate($bit, $config, $context); |
|||
} else { |
|||
$r = $bit; |
|||
} |
|||
if ($r === false) { |
|||
continue; |
|||
} |
|||
if ($key == 'position') { |
|||
if ($caught[$key] === false) { |
|||
$caught[$key] = ''; |
|||
} |
|||
$caught[$key] .= $r . ' '; |
|||
} else { |
|||
$caught[$key] = $r; |
|||
} |
|||
$i++; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (!$i) { |
|||
return false; |
|||
} |
|||
if ($caught['position'] !== false) { |
|||
$caught['position'] = $this->info['background-position']-> |
|||
validate($caught['position'], $config, $context); |
|||
} |
|||
|
|||
$ret = array(); |
|||
foreach ($caught as $value) { |
|||
if ($value === false) { |
|||
continue; |
|||
} |
|||
$ret[] = $value; |
|||
} |
|||
|
|||
if (empty($ret)) { |
|||
return false; |
|||
} |
|||
return implode(' ', $ret); |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,157 @@ |
|||
<?php |
|||
|
|||
/* W3C says: |
|||
[ // adjective and number must be in correct order, even if |
|||
// you could switch them without introducing ambiguity. |
|||
// some browsers support that syntax |
|||
[ |
|||
<percentage> | <length> | left | center | right |
|||
] |
|||
[ |
|||
<percentage> | <length> | top | center | bottom |
|||
]? |
|||
] | |
|||
[ // this signifies that the vertical and horizontal adjectives |
|||
// can be arbitrarily ordered, however, there can only be two, |
|||
// one of each, or none at all |
|||
[ |
|||
left | center | right |
|||
] || |
|||
[ |
|||
top | center | bottom |
|||
] |
|||
] |
|||
top, left = 0% |
|||
center, (none) = 50% |
|||
bottom, right = 100% |
|||
*/ |
|||
|
|||
/* QuirksMode says: |
|||
keyword + length/percentage must be ordered correctly, as per W3C |
|||
|
|||
Internet Explorer and Opera, however, support arbitrary ordering. We |
|||
should fix it up. |
|||
|
|||
Minor issue though, not strictly necessary. |
|||
*/ |
|||
|
|||
// control freaks may appreciate the ability to convert these to |
|||
// percentages or something, but it's not necessary |
|||
|
|||
/** |
|||
* Validates the value of background-position. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* @type HTMLPurifier_AttrDef_CSS_Length |
|||
*/ |
|||
protected $length; |
|||
|
|||
/** |
|||
* @type HTMLPurifier_AttrDef_CSS_Percentage |
|||
*/ |
|||
protected $percentage; |
|||
|
|||
public function __construct() |
|||
{ |
|||
$this->length = new HTMLPurifier_AttrDef_CSS_Length(); |
|||
$this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage(); |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$string = $this->parseCDATA($string); |
|||
$bits = explode(' ', $string); |
|||
|
|||
$keywords = array(); |
|||
$keywords['h'] = false; // left, right |
|||
$keywords['v'] = false; // top, bottom |
|||
$keywords['ch'] = false; // center (first word) |
|||
$keywords['cv'] = false; // center (second word) |
|||
$measures = array(); |
|||
|
|||
$i = 0; |
|||
|
|||
$lookup = array( |
|||
'top' => 'v', |
|||
'bottom' => 'v', |
|||
'left' => 'h', |
|||
'right' => 'h', |
|||
'center' => 'c' |
|||
); |
|||
|
|||
foreach ($bits as $bit) { |
|||
if ($bit === '') { |
|||
continue; |
|||
} |
|||
|
|||
// test for keyword |
|||
$lbit = ctype_lower($bit) ? $bit : strtolower($bit); |
|||
if (isset($lookup[$lbit])) { |
|||
$status = $lookup[$lbit]; |
|||
if ($status == 'c') { |
|||
if ($i == 0) { |
|||
$status = 'ch'; |
|||
} else { |
|||
$status = 'cv'; |
|||
} |
|||
} |
|||
$keywords[$status] = $lbit; |
|||
$i++; |
|||
} |
|||
|
|||
// test for length |
|||
$r = $this->length->validate($bit, $config, $context); |
|||
if ($r !== false) { |
|||
$measures[] = $r; |
|||
$i++; |
|||
} |
|||
|
|||
// test for percentage |
|||
$r = $this->percentage->validate($bit, $config, $context); |
|||
if ($r !== false) { |
|||
$measures[] = $r; |
|||
$i++; |
|||
} |
|||
} |
|||
|
|||
if (!$i) { |
|||
return false; |
|||
} // no valid values were caught |
|||
|
|||
$ret = array(); |
|||
|
|||
// first keyword |
|||
if ($keywords['h']) { |
|||
$ret[] = $keywords['h']; |
|||
} elseif ($keywords['ch']) { |
|||
$ret[] = $keywords['ch']; |
|||
$keywords['cv'] = false; // prevent re-use: center = center center |
|||
} elseif (count($measures)) { |
|||
$ret[] = array_shift($measures); |
|||
} |
|||
|
|||
if ($keywords['v']) { |
|||
$ret[] = $keywords['v']; |
|||
} elseif ($keywords['cv']) { |
|||
$ret[] = $keywords['cv']; |
|||
} elseif (count($measures)) { |
|||
$ret[] = array_shift($measures); |
|||
} |
|||
|
|||
if (empty($ret)) { |
|||
return false; |
|||
} |
|||
return implode(' ', $ret); |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,56 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates the border property as defined by CSS. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_Border extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* Local copy of properties this property is shorthand for. |
|||
* @type HTMLPurifier_AttrDef[] |
|||
*/ |
|||
protected $info = array(); |
|||
|
|||
/** |
|||
* @param HTMLPurifier_Config $config |
|||
*/ |
|||
public function __construct($config) |
|||
{ |
|||
$def = $config->getCSSDefinition(); |
|||
$this->info['border-width'] = $def->info['border-width']; |
|||
$this->info['border-style'] = $def->info['border-style']; |
|||
$this->info['border-top-color'] = $def->info['border-top-color']; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$string = $this->parseCDATA($string); |
|||
$string = $this->mungeRgb($string); |
|||
$bits = explode(' ', $string); |
|||
$done = array(); // segments we've finished |
|||
$ret = ''; // return value |
|||
foreach ($bits as $bit) { |
|||
foreach ($this->info as $propname => $validator) { |
|||
if (isset($done[$propname])) { |
|||
continue; |
|||
} |
|||
$r = $validator->validate($bit, $config, $context); |
|||
if ($r !== false) { |
|||
$ret .= $r . ' '; |
|||
$done[$propname] = true; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
return rtrim($ret); |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,161 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates Color as defined by CSS. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* @type HTMLPurifier_AttrDef_CSS_AlphaValue |
|||
*/ |
|||
protected $alpha; |
|||
|
|||
public function __construct() |
|||
{ |
|||
$this->alpha = new HTMLPurifier_AttrDef_CSS_AlphaValue(); |
|||
} |
|||
|
|||
/** |
|||
* @param string $color |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($color, $config, $context) |
|||
{ |
|||
static $colors = null; |
|||
if ($colors === null) { |
|||
$colors = $config->get('Core.ColorKeywords'); |
|||
} |
|||
|
|||
$color = trim($color); |
|||
if ($color === '') { |
|||
return false; |
|||
} |
|||
|
|||
$lower = strtolower($color); |
|||
if (isset($colors[$lower])) { |
|||
return $colors[$lower]; |
|||
} |
|||
|
|||
if (preg_match('#(rgb|rgba|hsl|hsla)\(#', $color, $matches) === 1) { |
|||
$length = strlen($color); |
|||
if (strpos($color, ')') !== $length - 1) { |
|||
return false; |
|||
} |
|||
|
|||
// get used function : rgb, rgba, hsl or hsla |
|||
$function = $matches[1]; |
|||
|
|||
$parameters_size = 3; |
|||
$alpha_channel = false; |
|||
if (substr($function, -1) === 'a') { |
|||
$parameters_size = 4; |
|||
$alpha_channel = true; |
|||
} |
|||
|
|||
/* |
|||
* Allowed types for values : |
|||
* parameter_position => [type => max_value] |
|||
*/ |
|||
$allowed_types = array( |
|||
1 => array('percentage' => 100, 'integer' => 255), |
|||
2 => array('percentage' => 100, 'integer' => 255), |
|||
3 => array('percentage' => 100, 'integer' => 255), |
|||
); |
|||
$allow_different_types = false; |
|||
|
|||
if (strpos($function, 'hsl') !== false) { |
|||
$allowed_types = array( |
|||
1 => array('integer' => 360), |
|||
2 => array('percentage' => 100), |
|||
3 => array('percentage' => 100), |
|||
); |
|||
$allow_different_types = true; |
|||
} |
|||
|
|||
$values = trim(str_replace($function, '', $color), ' ()'); |
|||
|
|||
$parts = explode(',', $values); |
|||
if (count($parts) !== $parameters_size) { |
|||
return false; |
|||
} |
|||
|
|||
$type = false; |
|||
$new_parts = array(); |
|||
$i = 0; |
|||
|
|||
foreach ($parts as $part) { |
|||
$i++; |
|||
$part = trim($part); |
|||
|
|||
if ($part === '') { |
|||
return false; |
|||
} |
|||
|
|||
// different check for alpha channel |
|||
if ($alpha_channel === true && $i === count($parts)) { |
|||
$result = $this->alpha->validate($part, $config, $context); |
|||
|
|||
if ($result === false) { |
|||
return false; |
|||
} |
|||
|
|||
$new_parts[] = (string)$result; |
|||
continue; |
|||
} |
|||
|
|||
if (substr($part, -1) === '%') { |
|||
$current_type = 'percentage'; |
|||
} else { |
|||
$current_type = 'integer'; |
|||
} |
|||
|
|||
if (!array_key_exists($current_type, $allowed_types[$i])) { |
|||
return false; |
|||
} |
|||
|
|||
if (!$type) { |
|||
$type = $current_type; |
|||
} |
|||
|
|||
if ($allow_different_types === false && $type != $current_type) { |
|||
return false; |
|||
} |
|||
|
|||
$max_value = $allowed_types[$i][$current_type]; |
|||
|
|||
if ($current_type == 'integer') { |
|||
// Return value between range 0 -> $max_value |
|||
$new_parts[] = (int)max(min($part, $max_value), 0); |
|||
} elseif ($current_type == 'percentage') { |
|||
$new_parts[] = (float)max(min(rtrim($part, '%'), $max_value), 0) . '%'; |
|||
} |
|||
} |
|||
|
|||
$new_values = implode(',', $new_parts); |
|||
|
|||
$color = $function . '(' . $new_values . ')'; |
|||
} else { |
|||
// hexadecimal handling |
|||
if ($color[0] === '#') { |
|||
$hex = substr($color, 1); |
|||
} else { |
|||
$hex = $color; |
|||
$color = '#' . $color; |
|||
} |
|||
$length = strlen($hex); |
|||
if ($length !== 3 && $length !== 6) { |
|||
return false; |
|||
} |
|||
if (!ctype_xdigit($hex)) { |
|||
return false; |
|||
} |
|||
} |
|||
return $color; |
|||
} |
|||
|
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,48 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Allows multiple validators to attempt to validate attribute. |
|||
* |
|||
* Composite is just what it sounds like: a composite of many validators. |
|||
* This means that multiple HTMLPurifier_AttrDef objects will have a whack |
|||
* at the string. If one of them passes, that's what is returned. This is |
|||
* especially useful for CSS values, which often are a choice between |
|||
* an enumerated set of predefined values or a flexible data type. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_Composite extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* List of objects that may process strings. |
|||
* @type HTMLPurifier_AttrDef[] |
|||
* @todo Make protected |
|||
*/ |
|||
public $defs; |
|||
|
|||
/** |
|||
* @param HTMLPurifier_AttrDef[] $defs List of HTMLPurifier_AttrDef objects |
|||
*/ |
|||
public function __construct($defs) |
|||
{ |
|||
$this->defs = $defs; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
foreach ($this->defs as $i => $def) { |
|||
$result = $this->defs[$i]->validate($string, $config, $context); |
|||
if ($result !== false) { |
|||
return $result; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,44 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Decorator which enables CSS properties to be disabled for specific elements. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_DenyElementDecorator extends HTMLPurifier_AttrDef |
|||
{ |
|||
/** |
|||
* @type HTMLPurifier_AttrDef |
|||
*/ |
|||
public $def; |
|||
/** |
|||
* @type string |
|||
*/ |
|||
public $element; |
|||
|
|||
/** |
|||
* @param HTMLPurifier_AttrDef $def Definition to wrap |
|||
* @param string $element Element to deny |
|||
*/ |
|||
public function __construct($def, $element) |
|||
{ |
|||
$this->def = $def; |
|||
$this->element = $element; |
|||
} |
|||
|
|||
/** |
|||
* Checks if CurrentToken is set and equal to $this->element |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$token = $context->get('CurrentToken', true); |
|||
if ($token && $token->name == $this->element) { |
|||
return false; |
|||
} |
|||
return $this->def->validate($string, $config, $context); |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,77 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Microsoft's proprietary filter: CSS property |
|||
* @note Currently supports the alpha filter. In the future, this will |
|||
* probably need an extensible framework |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_Filter extends HTMLPurifier_AttrDef |
|||
{ |
|||
/** |
|||
* @type HTMLPurifier_AttrDef_Integer |
|||
*/ |
|||
protected $intValidator; |
|||
|
|||
public function __construct() |
|||
{ |
|||
$this->intValidator = new HTMLPurifier_AttrDef_Integer(); |
|||
} |
|||
|
|||
/** |
|||
* @param string $value |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($value, $config, $context) |
|||
{ |
|||
$value = $this->parseCDATA($value); |
|||
if ($value === 'none') { |
|||
return $value; |
|||
} |
|||
// if we looped this we could support multiple filters |
|||
$function_length = strcspn($value, '('); |
|||
$function = trim(substr($value, 0, $function_length)); |
|||
if ($function !== 'alpha' && |
|||
$function !== 'Alpha' && |
|||
$function !== 'progid:DXImageTransform.Microsoft.Alpha' |
|||
) { |
|||
return false; |
|||
} |
|||
$cursor = $function_length + 1; |
|||
$parameters_length = strcspn($value, ')', $cursor); |
|||
$parameters = substr($value, $cursor, $parameters_length); |
|||
$params = explode(',', $parameters); |
|||
$ret_params = array(); |
|||
$lookup = array(); |
|||
foreach ($params as $param) { |
|||
list($key, $value) = explode('=', $param); |
|||
$key = trim($key); |
|||
$value = trim($value); |
|||
if (isset($lookup[$key])) { |
|||
continue; |
|||
} |
|||
if ($key !== 'opacity') { |
|||
continue; |
|||
} |
|||
$value = $this->intValidator->validate($value, $config, $context); |
|||
if ($value === false) { |
|||
continue; |
|||
} |
|||
$int = (int)$value; |
|||
if ($int > 100) { |
|||
$value = '100'; |
|||
} |
|||
if ($int < 0) { |
|||
$value = '0'; |
|||
} |
|||
$ret_params[] = "$key=$value"; |
|||
$lookup[$key] = true; |
|||
} |
|||
$ret_parameters = implode(',', $ret_params); |
|||
$ret_function = "$function($ret_parameters)"; |
|||
return $ret_function; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,176 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates shorthand CSS property font. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* Local copy of validators |
|||
* @type HTMLPurifier_AttrDef[] |
|||
* @note If we moved specific CSS property definitions to their own |
|||
* classes instead of having them be assembled at run time by |
|||
* CSSDefinition, this wouldn't be necessary. We'd instantiate |
|||
* our own copies. |
|||
*/ |
|||
protected $info = array(); |
|||
|
|||
/** |
|||
* @param HTMLPurifier_Config $config |
|||
*/ |
|||
public function __construct($config) |
|||
{ |
|||
$def = $config->getCSSDefinition(); |
|||
$this->info['font-style'] = $def->info['font-style']; |
|||
$this->info['font-variant'] = $def->info['font-variant']; |
|||
$this->info['font-weight'] = $def->info['font-weight']; |
|||
$this->info['font-size'] = $def->info['font-size']; |
|||
$this->info['line-height'] = $def->info['line-height']; |
|||
$this->info['font-family'] = $def->info['font-family']; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
static $system_fonts = array( |
|||
'caption' => true, |
|||
'icon' => true, |
|||
'menu' => true, |
|||
'message-box' => true, |
|||
'small-caption' => true, |
|||
'status-bar' => true |
|||
); |
|||
|
|||
// regular pre-processing |
|||
$string = $this->parseCDATA($string); |
|||
if ($string === '') { |
|||
return false; |
|||
} |
|||
|
|||
// check if it's one of the keywords |
|||
$lowercase_string = strtolower($string); |
|||
if (isset($system_fonts[$lowercase_string])) { |
|||
return $lowercase_string; |
|||
} |
|||
|
|||
$bits = explode(' ', $string); // bits to process |
|||
$stage = 0; // this indicates what we're looking for |
|||
$caught = array(); // which stage 0 properties have we caught? |
|||
$stage_1 = array('font-style', 'font-variant', 'font-weight'); |
|||
$final = ''; // output |
|||
|
|||
for ($i = 0, $size = count($bits); $i < $size; $i++) { |
|||
if ($bits[$i] === '') { |
|||
continue; |
|||
} |
|||
switch ($stage) { |
|||
case 0: // attempting to catch font-style, font-variant or font-weight |
|||
foreach ($stage_1 as $validator_name) { |
|||
if (isset($caught[$validator_name])) { |
|||
continue; |
|||
} |
|||
$r = $this->info[$validator_name]->validate( |
|||
$bits[$i], |
|||
$config, |
|||
$context |
|||
); |
|||
if ($r !== false) { |
|||
$final .= $r . ' '; |
|||
$caught[$validator_name] = true; |
|||
break; |
|||
} |
|||
} |
|||
// all three caught, continue on |
|||
if (count($caught) >= 3) { |
|||
$stage = 1; |
|||
} |
|||
if ($r !== false) { |
|||
break; |
|||
} |
|||
case 1: // attempting to catch font-size and perhaps line-height |
|||
$found_slash = false; |
|||
if (strpos($bits[$i], '/') !== false) { |
|||
list($font_size, $line_height) = |
|||
explode('/', $bits[$i]); |
|||
if ($line_height === '') { |
|||
// ooh, there's a space after the slash! |
|||
$line_height = false; |
|||
$found_slash = true; |
|||
} |
|||
} else { |
|||
$font_size = $bits[$i]; |
|||
$line_height = false; |
|||
} |
|||
$r = $this->info['font-size']->validate( |
|||
$font_size, |
|||
$config, |
|||
$context |
|||
); |
|||
if ($r !== false) { |
|||
$final .= $r; |
|||
// attempt to catch line-height |
|||
if ($line_height === false) { |
|||
// we need to scroll forward |
|||
for ($j = $i + 1; $j < $size; $j++) { |
|||
if ($bits[$j] === '') { |
|||
continue; |
|||
} |
|||
if ($bits[$j] === '/') { |
|||
if ($found_slash) { |
|||
return false; |
|||
} else { |
|||
$found_slash = true; |
|||
continue; |
|||
} |
|||
} |
|||
$line_height = $bits[$j]; |
|||
break; |
|||
} |
|||
} else { |
|||
// slash already found |
|||
$found_slash = true; |
|||
$j = $i; |
|||
} |
|||
if ($found_slash) { |
|||
$i = $j; |
|||
$r = $this->info['line-height']->validate( |
|||
$line_height, |
|||
$config, |
|||
$context |
|||
); |
|||
if ($r !== false) { |
|||
$final .= '/' . $r; |
|||
} |
|||
} |
|||
$final .= ' '; |
|||
$stage = 2; |
|||
break; |
|||
} |
|||
return false; |
|||
case 2: // attempting to catch font-family |
|||
$font_family = |
|||
implode(' ', array_slice($bits, $i, $size - $i)); |
|||
$r = $this->info['font-family']->validate( |
|||
$font_family, |
|||
$config, |
|||
$context |
|||
); |
|||
if ($r !== false) { |
|||
$final .= $r . ' '; |
|||
// processing completed successfully |
|||
return rtrim($final); |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,217 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates a font family list according to CSS spec |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
protected $mask = null; |
|||
|
|||
public function __construct() |
|||
{ |
|||
// Lowercase letters |
|||
$l = range('a', 'z'); |
|||
// Uppercase letters |
|||
$u = range('A', 'Z'); |
|||
// Digits |
|||
$d = range('0', '9'); |
|||
// Special bytes used by UTF-8 |
|||
$b = array_map('chr', range(0x80, 0xFF)); |
|||
// All valid characters for the mask |
|||
$c = array_merge($l, $u, $d, $b); |
|||
// Concatenate all valid characters into a string |
|||
// Use '_- ' as an initial value |
|||
$this->mask = array_reduce($c, function ($carry, $value) { |
|||
return $carry . $value; |
|||
}, '_- '); |
|||
|
|||
/* |
|||
PHP's internal strcspn implementation is |
|||
O(length of string * length of mask), making it inefficient |
|||
for large masks. However, it's still faster than |
|||
preg_match 8) |
|||
for (p = s1;;) { |
|||
spanp = s2; |
|||
do { |
|||
if (*spanp == c || p == s1_end) { |
|||
return p - s1; |
|||
} |
|||
} while (spanp++ < (s2_end - 1)); |
|||
c = *++p; |
|||
} |
|||
*/ |
|||
// possible optimization: invert the mask. |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
static $generic_names = array( |
|||
'serif' => true, |
|||
'sans-serif' => true, |
|||
'monospace' => true, |
|||
'fantasy' => true, |
|||
'cursive' => true |
|||
); |
|||
$allowed_fonts = $config->get('CSS.AllowedFonts'); |
|||
|
|||
// assume that no font names contain commas in them |
|||
$fonts = explode(',', $string); |
|||
$final = ''; |
|||
foreach ($fonts as $font) { |
|||
$font = trim($font); |
|||
if ($font === '') { |
|||
continue; |
|||
} |
|||
// match a generic name |
|||
if (isset($generic_names[$font])) { |
|||
if ($allowed_fonts === null || isset($allowed_fonts[$font])) { |
|||
$final .= $font . ', '; |
|||
} |
|||
continue; |
|||
} |
|||
// match a quoted name |
|||
if ($font[0] === '"' || $font[0] === "'") { |
|||
$length = strlen($font); |
|||
if ($length <= 2) { |
|||
continue; |
|||
} |
|||
$quote = $font[0]; |
|||
if ($font[$length - 1] !== $quote) { |
|||
continue; |
|||
} |
|||
$font = substr($font, 1, $length - 2); |
|||
} |
|||
|
|||
$font = $this->expandCSSEscape($font); |
|||
|
|||
// $font is a pure representation of the font name |
|||
|
|||
if ($allowed_fonts !== null && !isset($allowed_fonts[$font])) { |
|||
continue; |
|||
} |
|||
|
|||
if (ctype_alnum($font) && $font !== '') { |
|||
// very simple font, allow it in unharmed |
|||
$final .= $font . ', '; |
|||
continue; |
|||
} |
|||
|
|||
// bugger out on whitespace. form feed (0C) really |
|||
// shouldn't show up regardless |
|||
$font = str_replace(array("\n", "\t", "\r", "\x0C"), ' ', $font); |
|||
|
|||
// Here, there are various classes of characters which need |
|||
// to be treated differently: |
|||
// - Alphanumeric characters are essentially safe. We |
|||
// handled these above. |
|||
// - Spaces require quoting, though most parsers will do |
|||
// the right thing if there aren't any characters that |
|||
// can be misinterpreted |
|||
// - Dashes rarely occur, but they fairly unproblematic |
|||
// for parsing/rendering purposes. |
|||
// The above characters cover the majority of Western font |
|||
// names. |
|||
// - Arbitrary Unicode characters not in ASCII. Because |
|||
// most parsers give little thought to Unicode, treatment |
|||
// of these codepoints is basically uniform, even for |
|||
// punctuation-like codepoints. These characters can |
|||
// show up in non-Western pages and are supported by most |
|||
// major browsers, for example: "MS 明朝" is a |
|||
// legitimate font-name |
|||
// <http://ja.wikipedia.org/wiki/MS_明朝>. See |
|||
// the CSS3 spec for more examples: |
|||
// <http://www.w3.org/TR/2011/WD-css3-fonts-20110324/localizedfamilynames.png> |
|||
// You can see live samples of these on the Internet: |
|||
// <http://www.google.co.jp/search?q=font-family+MS+明朝|ゴシック> |
|||
// However, most of these fonts have ASCII equivalents: |
|||
// for example, 'MS Mincho', and it's considered |
|||
// professional to use ASCII font names instead of |
|||
// Unicode font names. Thanks Takeshi Terada for |
|||
// providing this information. |
|||
// The following characters, to my knowledge, have not been |
|||
// used to name font names. |
|||
// - Single quote. While theoretically you might find a |
|||
// font name that has a single quote in its name (serving |
|||
// as an apostrophe, e.g. Dave's Scribble), I haven't |
|||
// been able to find any actual examples of this. |
|||
// Internet Explorer's cssText translation (which I |
|||
// believe is invoked by innerHTML) normalizes any |
|||
// quoting to single quotes, and fails to escape single |
|||
// quotes. (Note that this is not IE's behavior for all |
|||
// CSS properties, just some sort of special casing for |
|||
// font-family). So a single quote *cannot* be used |
|||
// safely in the font-family context if there will be an |
|||
// innerHTML/cssText translation. Note that Firefox 3.x |
|||
// does this too. |
|||
// - Double quote. In IE, these get normalized to |
|||
// single-quotes, no matter what the encoding. (Fun |
|||
// fact, in IE8, the 'content' CSS property gained |
|||
// support, where they special cased to preserve encoded |
|||
// double quotes, but still translate unadorned double |
|||
// quotes into single quotes.) So, because their |
|||
// fixpoint behavior is identical to single quotes, they |
|||
// cannot be allowed either. Firefox 3.x displays |
|||
// single-quote style behavior. |
|||
// - Backslashes are reduced by one (so \\ -> \) every |
|||
// iteration, so they cannot be used safely. This shows |
|||
// up in IE7, IE8 and FF3 |
|||
// - Semicolons, commas and backticks are handled properly. |
|||
// - The rest of the ASCII punctuation is handled properly. |
|||
// We haven't checked what browsers do to unadorned |
|||
// versions, but this is not important as long as the |
|||
// browser doesn't /remove/ surrounding quotes (as IE does |
|||
// for HTML). |
|||
// |
|||
// With these results in hand, we conclude that there are |
|||
// various levels of safety: |
|||
// - Paranoid: alphanumeric, spaces and dashes(?) |
|||
// - International: Paranoid + non-ASCII Unicode |
|||
// - Edgy: Everything except quotes, backslashes |
|||
// - NoJS: Standards compliance, e.g. sod IE. Note that |
|||
// with some judicious character escaping (since certain |
|||
// types of escaping doesn't work) this is theoretically |
|||
// OK as long as innerHTML/cssText is not called. |
|||
// We believe that international is a reasonable default |
|||
// (that we will implement now), and once we do more |
|||
// extensive research, we may feel comfortable with dropping |
|||
// it down to edgy. |
|||
|
|||
// Edgy: alphanumeric, spaces, dashes, underscores and Unicode. Use of |
|||
// str(c)spn assumes that the string was already well formed |
|||
// Unicode (which of course it is). |
|||
if (strspn($font, $this->mask) !== strlen($font)) { |
|||
continue; |
|||
} |
|||
|
|||
// Historical: |
|||
// In the absence of innerHTML/cssText, these ugly |
|||
// transforms don't pose a security risk (as \\ and \" |
|||
// might--these escapes are not supported by most browsers). |
|||
// We could try to be clever and use single-quote wrapping |
|||
// when there is a double quote present, but I have choosen |
|||
// not to implement that. (NOTE: you can reduce the amount |
|||
// of escapes by one depending on what quoting style you use) |
|||
// $font = str_replace('\\', '\\5C ', $font); |
|||
// $font = str_replace('"', '\\22 ', $font); |
|||
// $font = str_replace("'", '\\27 ', $font); |
|||
|
|||
// font possibly with spaces, requires quoting |
|||
$final .= "'$font', "; |
|||
} |
|||
$final = rtrim($final, ', '); |
|||
if ($final === '') { |
|||
return false; |
|||
} |
|||
return $final; |
|||
} |
|||
|
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,32 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates based on {ident} CSS grammar production |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_Ident extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$string = trim($string); |
|||
|
|||
// early abort: '' and '0' (strings that convert to false) are invalid |
|||
if (!$string) { |
|||
return false; |
|||
} |
|||
|
|||
$pattern = '/^(-?[A-Za-z_][A-Za-z_\-0-9]*)$/'; |
|||
if (!preg_match($pattern, $string)) { |
|||
return false; |
|||
} |
|||
return $string; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,56 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Decorator which enables !important to be used in CSS values. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_ImportantDecorator extends HTMLPurifier_AttrDef |
|||
{ |
|||
/** |
|||
* @type HTMLPurifier_AttrDef |
|||
*/ |
|||
public $def; |
|||
/** |
|||
* @type bool |
|||
*/ |
|||
public $allow; |
|||
|
|||
/** |
|||
* @param HTMLPurifier_AttrDef $def Definition to wrap |
|||
* @param bool $allow Whether or not to allow !important |
|||
*/ |
|||
public function __construct($def, $allow = false) |
|||
{ |
|||
$this->def = $def; |
|||
$this->allow = $allow; |
|||
} |
|||
|
|||
/** |
|||
* Intercepts and removes !important if necessary |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
// test for ! and important tokens |
|||
$string = trim($string); |
|||
$is_important = false; |
|||
// :TODO: optimization: test directly for !important and ! important |
|||
if (strlen($string) >= 9 && substr($string, -9) === 'important') { |
|||
$temp = rtrim(substr($string, 0, -9)); |
|||
// use a temp, because we might want to restore important |
|||
if (strlen($temp) >= 1 && substr($temp, -1) === '!') { |
|||
$string = rtrim(substr($temp, 0, -1)); |
|||
$is_important = true; |
|||
} |
|||
} |
|||
$string = $this->def->validate($string, $config, $context); |
|||
if ($this->allow && $is_important) { |
|||
$string .= ' !important'; |
|||
} |
|||
return $string; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,77 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Represents a Length as defined by CSS. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_Length extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* @type HTMLPurifier_Length|string |
|||
*/ |
|||
protected $min; |
|||
|
|||
/** |
|||
* @type HTMLPurifier_Length|string |
|||
*/ |
|||
protected $max; |
|||
|
|||
/** |
|||
* @param HTMLPurifier_Length|string $min Minimum length, or null for no bound. String is also acceptable. |
|||
* @param HTMLPurifier_Length|string $max Maximum length, or null for no bound. String is also acceptable. |
|||
*/ |
|||
public function __construct($min = null, $max = null) |
|||
{ |
|||
$this->min = $min !== null ? HTMLPurifier_Length::make($min) : null; |
|||
$this->max = $max !== null ? HTMLPurifier_Length::make($max) : null; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$string = $this->parseCDATA($string); |
|||
|
|||
// Optimizations |
|||
if ($string === '') { |
|||
return false; |
|||
} |
|||
if ($string === '0') { |
|||
return '0'; |
|||
} |
|||
if (strlen($string) === 1) { |
|||
return false; |
|||
} |
|||
|
|||
$length = HTMLPurifier_Length::make($string); |
|||
if (!$length->isValid()) { |
|||
return false; |
|||
} |
|||
|
|||
if ($this->min) { |
|||
$c = $length->compareTo($this->min); |
|||
if ($c === false) { |
|||
return false; |
|||
} |
|||
if ($c < 0) { |
|||
return false; |
|||
} |
|||
} |
|||
if ($this->max) { |
|||
$c = $length->compareTo($this->max); |
|||
if ($c === false) { |
|||
return false; |
|||
} |
|||
if ($c > 0) { |
|||
return false; |
|||
} |
|||
} |
|||
return $length->toString(); |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,112 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates shorthand CSS property list-style. |
|||
* @warning Does not support url tokens that have internal spaces. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_ListStyle extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* Local copy of validators. |
|||
* @type HTMLPurifier_AttrDef[] |
|||
* @note See HTMLPurifier_AttrDef_CSS_Font::$info for a similar impl. |
|||
*/ |
|||
protected $info; |
|||
|
|||
/** |
|||
* @param HTMLPurifier_Config $config |
|||
*/ |
|||
public function __construct($config) |
|||
{ |
|||
$def = $config->getCSSDefinition(); |
|||
$this->info['list-style-type'] = $def->info['list-style-type']; |
|||
$this->info['list-style-position'] = $def->info['list-style-position']; |
|||
$this->info['list-style-image'] = $def->info['list-style-image']; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
// regular pre-processing |
|||
$string = $this->parseCDATA($string); |
|||
if ($string === '') { |
|||
return false; |
|||
} |
|||
|
|||
// assumes URI doesn't have spaces in it |
|||
$bits = explode(' ', strtolower($string)); // bits to process |
|||
|
|||
$caught = array(); |
|||
$caught['type'] = false; |
|||
$caught['position'] = false; |
|||
$caught['image'] = false; |
|||
|
|||
$i = 0; // number of catches |
|||
$none = false; |
|||
|
|||
foreach ($bits as $bit) { |
|||
if ($i >= 3) { |
|||
return; |
|||
} // optimization bit |
|||
if ($bit === '') { |
|||
continue; |
|||
} |
|||
foreach ($caught as $key => $status) { |
|||
if ($status !== false) { |
|||
continue; |
|||
} |
|||
$r = $this->info['list-style-' . $key]->validate($bit, $config, $context); |
|||
if ($r === false) { |
|||
continue; |
|||
} |
|||
if ($r === 'none') { |
|||
if ($none) { |
|||
continue; |
|||
} else { |
|||
$none = true; |
|||
} |
|||
if ($key == 'image') { |
|||
continue; |
|||
} |
|||
} |
|||
$caught[$key] = $r; |
|||
$i++; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (!$i) { |
|||
return false; |
|||
} |
|||
|
|||
$ret = array(); |
|||
|
|||
// construct type |
|||
if ($caught['type']) { |
|||
$ret[] = $caught['type']; |
|||
} |
|||
|
|||
// construct image |
|||
if ($caught['image']) { |
|||
$ret[] = $caught['image']; |
|||
} |
|||
|
|||
// construct position |
|||
if ($caught['position']) { |
|||
$ret[] = $caught['position']; |
|||
} |
|||
|
|||
if (empty($ret)) { |
|||
return false; |
|||
} |
|||
return implode(' ', $ret); |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,71 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Framework class for strings that involve multiple values. |
|||
* |
|||
* Certain CSS properties such as border-width and margin allow multiple |
|||
* lengths to be specified. This class can take a vanilla border-width |
|||
* definition and multiply it, usually into a max of four. |
|||
* |
|||
* @note Even though the CSS specification isn't clear about it, inherit |
|||
* can only be used alone: it will never manifest as part of a multi |
|||
* shorthand declaration. Thus, this class does not allow inherit. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_Multiple extends HTMLPurifier_AttrDef |
|||
{ |
|||
/** |
|||
* Instance of component definition to defer validation to. |
|||
* @type HTMLPurifier_AttrDef |
|||
* @todo Make protected |
|||
*/ |
|||
public $single; |
|||
|
|||
/** |
|||
* Max number of values allowed. |
|||
* @todo Make protected |
|||
*/ |
|||
public $max; |
|||
|
|||
/** |
|||
* @param HTMLPurifier_AttrDef $single HTMLPurifier_AttrDef to multiply |
|||
* @param int $max Max number of values allowed (usually four) |
|||
*/ |
|||
public function __construct($single, $max = 4) |
|||
{ |
|||
$this->single = $single; |
|||
$this->max = $max; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$string = $this->mungeRgb($this->parseCDATA($string)); |
|||
if ($string === '') { |
|||
return false; |
|||
} |
|||
$parts = explode(' ', $string); // parseCDATA replaced \r, \t and \n |
|||
$length = count($parts); |
|||
$final = ''; |
|||
for ($i = 0, $num = 0; $i < $length && $num < $this->max; $i++) { |
|||
if (ctype_space($parts[$i])) { |
|||
continue; |
|||
} |
|||
$result = $this->single->validate($parts[$i], $config, $context); |
|||
if ($result !== false) { |
|||
$final .= $result . ' '; |
|||
$num++; |
|||
} |
|||
} |
|||
if ($final === '') { |
|||
return false; |
|||
} |
|||
return rtrim($final); |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,90 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates a number as defined by the CSS spec. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* Indicates whether or not only positive values are allowed. |
|||
* @type bool |
|||
*/ |
|||
protected $non_negative = false; |
|||
|
|||
/** |
|||
* @param bool $non_negative indicates whether negatives are forbidden |
|||
*/ |
|||
public function __construct($non_negative = false) |
|||
{ |
|||
$this->non_negative = $non_negative; |
|||
} |
|||
|
|||
/** |
|||
* @param string $number |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return string|bool |
|||
* @warning Some contexts do not pass $config, $context. These |
|||
* variables should not be used without checking HTMLPurifier_Length |
|||
*/ |
|||
public function validate($number, $config, $context) |
|||
{ |
|||
$number = $this->parseCDATA($number); |
|||
|
|||
if ($number === '') { |
|||
return false; |
|||
} |
|||
if ($number === '0') { |
|||
return '0'; |
|||
} |
|||
|
|||
$sign = ''; |
|||
switch ($number[0]) { |
|||
case '-': |
|||
if ($this->non_negative) { |
|||
return false; |
|||
} |
|||
$sign = '-'; |
|||
case '+': |
|||
$number = substr($number, 1); |
|||
} |
|||
|
|||
if (ctype_digit($number)) { |
|||
$number = ltrim($number, '0'); |
|||
return $number ? $sign . $number : '0'; |
|||
} |
|||
|
|||
// Period is the only non-numeric character allowed |
|||
if (strpos($number, '.') === false) { |
|||
return false; |
|||
} |
|||
|
|||
list($left, $right) = explode('.', $number, 2); |
|||
|
|||
if ($left === '' && $right === '') { |
|||
return false; |
|||
} |
|||
if ($left !== '' && !ctype_digit($left)) { |
|||
return false; |
|||
} |
|||
|
|||
// Remove leading zeros until positive number or a zero stays left |
|||
if (ltrim($left, '0') != '') { |
|||
$left = ltrim($left, '0'); |
|||
} else { |
|||
$left = '0'; |
|||
} |
|||
|
|||
$right = rtrim($right, '0'); |
|||
|
|||
if ($right === '') { |
|||
return $left ? $sign . $left : '0'; |
|||
} elseif (!ctype_digit($right)) { |
|||
return false; |
|||
} |
|||
return $sign . $left . '.' . $right; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,54 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates a Percentage as defined by the CSS spec. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_Percentage extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* Instance to defer number validation to. |
|||
* @type HTMLPurifier_AttrDef_CSS_Number |
|||
*/ |
|||
protected $number_def; |
|||
|
|||
/** |
|||
* @param bool $non_negative Whether to forbid negative values |
|||
*/ |
|||
public function __construct($non_negative = false) |
|||
{ |
|||
$this->number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative); |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$string = $this->parseCDATA($string); |
|||
|
|||
if ($string === '') { |
|||
return false; |
|||
} |
|||
$length = strlen($string); |
|||
if ($length === 1) { |
|||
return false; |
|||
} |
|||
if ($string[$length - 1] !== '%') { |
|||
return false; |
|||
} |
|||
|
|||
$number = substr($string, 0, $length - 1); |
|||
$number = $this->number_def->validate($number, $config, $context); |
|||
|
|||
if ($number === false) { |
|||
return false; |
|||
} |
|||
return "$number%"; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,46 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates the value for the CSS property text-decoration |
|||
* @note This class could be generalized into a version that acts sort of |
|||
* like Enum except you can compound the allowed values. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
static $allowed_values = array( |
|||
'line-through' => true, |
|||
'overline' => true, |
|||
'underline' => true, |
|||
); |
|||
|
|||
$string = strtolower($this->parseCDATA($string)); |
|||
|
|||
if ($string === 'none') { |
|||
return $string; |
|||
} |
|||
|
|||
$parts = explode(' ', $string); |
|||
$final = ''; |
|||
foreach ($parts as $part) { |
|||
if (isset($allowed_values[$part])) { |
|||
$final .= $part . ' '; |
|||
} |
|||
} |
|||
$final = rtrim($final); |
|||
if ($final === '') { |
|||
return false; |
|||
} |
|||
return $final; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,77 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates a URI in CSS syntax, which uses url('http://example.com') |
|||
* @note While theoretically speaking a URI in a CSS document could |
|||
* be non-embedded, as of CSS2 there is no such usage so we're |
|||
* generalizing it. This may need to be changed in the future. |
|||
* @warning Since HTMLPurifier_AttrDef_CSS blindly uses semicolons as |
|||
* the separator, you cannot put a literal semicolon in |
|||
* in the URI. Try percent encoding it, in that case. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI |
|||
{ |
|||
|
|||
public function __construct() |
|||
{ |
|||
parent::__construct(true); // always embedded |
|||
} |
|||
|
|||
/** |
|||
* @param string $uri_string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($uri_string, $config, $context) |
|||
{ |
|||
// parse the URI out of the string and then pass it onto |
|||
// the parent object |
|||
|
|||
$uri_string = $this->parseCDATA($uri_string); |
|||
if (strpos($uri_string, 'url(') !== 0) { |
|||
return false; |
|||
} |
|||
$uri_string = substr($uri_string, 4); |
|||
if (strlen($uri_string) == 0) { |
|||
return false; |
|||
} |
|||
$new_length = strlen($uri_string) - 1; |
|||
if ($uri_string[$new_length] != ')') { |
|||
return false; |
|||
} |
|||
$uri = trim(substr($uri_string, 0, $new_length)); |
|||
|
|||
if (!empty($uri) && ($uri[0] == "'" || $uri[0] == '"')) { |
|||
$quote = $uri[0]; |
|||
$new_length = strlen($uri) - 1; |
|||
if ($uri[$new_length] !== $quote) { |
|||
return false; |
|||
} |
|||
$uri = substr($uri, 1, $new_length - 1); |
|||
} |
|||
|
|||
$uri = $this->expandCSSEscape($uri); |
|||
|
|||
$result = parent::validate($uri, $config, $context); |
|||
|
|||
if ($result === false) { |
|||
return false; |
|||
} |
|||
|
|||
// extra sanity check; should have been done by URI |
|||
$result = str_replace(array('"', "\\", "\n", "\x0c", "\r"), "", $result); |
|||
|
|||
// suspicious characters are ()'; we're going to percent encode |
|||
// them for safety. |
|||
$result = str_replace(array('(', ')', "'"), array('%28', '%29', '%27'), $result); |
|||
|
|||
// there's an extra bug where ampersands lose their escaping on |
|||
// an innerHTML cycle, so a very unlucky query parameter could |
|||
// then change the meaning of the URL. Unfortunately, there's |
|||
// not much we can do about that... |
|||
return "url(\"$result\")"; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,44 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Dummy AttrDef that mimics another AttrDef, BUT it generates clones |
|||
* with make. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_Clone extends HTMLPurifier_AttrDef |
|||
{ |
|||
/** |
|||
* What we're cloning. |
|||
* @type HTMLPurifier_AttrDef |
|||
*/ |
|||
protected $clone; |
|||
|
|||
/** |
|||
* @param HTMLPurifier_AttrDef $clone |
|||
*/ |
|||
public function __construct($clone) |
|||
{ |
|||
$this->clone = $clone; |
|||
} |
|||
|
|||
/** |
|||
* @param string $v |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($v, $config, $context) |
|||
{ |
|||
return $this->clone->validate($v, $config, $context); |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @return HTMLPurifier_AttrDef |
|||
*/ |
|||
public function make($string) |
|||
{ |
|||
return clone $this->clone; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,73 @@ |
|||
<?php |
|||
|
|||
// Enum = Enumerated |
|||
/** |
|||
* Validates a keyword against a list of valid values. |
|||
* @warning The case-insensitive compare of this function uses PHP's |
|||
* built-in strtolower and ctype_lower functions, which may |
|||
* cause problems with international comparisons |
|||
*/ |
|||
class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* Lookup table of valid values. |
|||
* @type array |
|||
* @todo Make protected |
|||
*/ |
|||
public $valid_values = array(); |
|||
|
|||
/** |
|||
* Bool indicating whether or not enumeration is case sensitive. |
|||
* @note In general this is always case insensitive. |
|||
*/ |
|||
protected $case_sensitive = false; // values according to W3C spec |
|||
|
|||
/** |
|||
* @param array $valid_values List of valid values |
|||
* @param bool $case_sensitive Whether or not case sensitive |
|||
*/ |
|||
public function __construct($valid_values = array(), $case_sensitive = false) |
|||
{ |
|||
$this->valid_values = array_flip($valid_values); |
|||
$this->case_sensitive = $case_sensitive; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$string = trim($string); |
|||
if (!$this->case_sensitive) { |
|||
// we may want to do full case-insensitive libraries |
|||
$string = ctype_lower($string) ? $string : strtolower($string); |
|||
} |
|||
$result = isset($this->valid_values[$string]); |
|||
|
|||
return $result ? $string : false; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string In form of comma-delimited list of case-insensitive |
|||
* valid values. Example: "foo,bar,baz". Prepend "s:" to make |
|||
* case sensitive |
|||
* @return HTMLPurifier_AttrDef_Enum |
|||
*/ |
|||
public function make($string) |
|||
{ |
|||
if (strlen($string) > 2 && $string[0] == 's' && $string[1] == ':') { |
|||
$string = substr($string, 2); |
|||
$sensitive = true; |
|||
} else { |
|||
$sensitive = false; |
|||
} |
|||
$values = explode(',', $string); |
|||
return new HTMLPurifier_AttrDef_Enum($values, $sensitive); |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,48 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates a boolean attribute |
|||
*/ |
|||
class HTMLPurifier_AttrDef_HTML_Bool extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* @type string |
|||
*/ |
|||
protected $name; |
|||
|
|||
/** |
|||
* @type bool |
|||
*/ |
|||
public $minimized = true; |
|||
|
|||
/** |
|||
* @param bool|string $name |
|||
*/ |
|||
public function __construct($name = false) |
|||
{ |
|||
$this->name = $name; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
return $this->name; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string Name of attribute |
|||
* @return HTMLPurifier_AttrDef_HTML_Bool |
|||
*/ |
|||
public function make($string) |
|||
{ |
|||
return new HTMLPurifier_AttrDef_HTML_Bool($string); |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,48 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Implements special behavior for class attribute (normally NMTOKENS) |
|||
*/ |
|||
class HTMLPurifier_AttrDef_HTML_Class extends HTMLPurifier_AttrDef_HTML_Nmtokens |
|||
{ |
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
protected function split($string, $config, $context) |
|||
{ |
|||
// really, this twiddle should be lazy loaded |
|||
$name = $config->getDefinition('HTML')->doctype->name; |
|||
if ($name == "XHTML 1.1" || $name == "XHTML 2.0") { |
|||
return parent::split($string, $config, $context); |
|||
} else { |
|||
return preg_split('/\s+/', $string); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @param array $tokens |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
protected function filter($tokens, $config, $context) |
|||
{ |
|||
$allowed = $config->get('Attr.AllowedClasses'); |
|||
$forbidden = $config->get('Attr.ForbiddenClasses'); |
|||
$ret = array(); |
|||
foreach ($tokens as $token) { |
|||
if (($allowed === null || isset($allowed[$token])) && |
|||
!isset($forbidden[$token]) && |
|||
// We need this O(n) check because of PHP's array |
|||
// implementation that casts -0 to 0. |
|||
!in_array($token, $ret, true) |
|||
) { |
|||
$ret[] = $token; |
|||
} |
|||
} |
|||
return $ret; |
|||
} |
|||
} |
@ -0,0 +1,51 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates a color according to the HTML spec. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_HTML_Color extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
static $colors = null; |
|||
if ($colors === null) { |
|||
$colors = $config->get('Core.ColorKeywords'); |
|||
} |
|||
|
|||
$string = trim($string); |
|||
|
|||
if (empty($string)) { |
|||
return false; |
|||
} |
|||
$lower = strtolower($string); |
|||
if (isset($colors[$lower])) { |
|||
return $colors[$lower]; |
|||
} |
|||
if ($string[0] === '#') { |
|||
$hex = substr($string, 1); |
|||
} else { |
|||
$hex = $string; |
|||
} |
|||
|
|||
$length = strlen($hex); |
|||
if ($length !== 3 && $length !== 6) { |
|||
return false; |
|||
} |
|||
if (!ctype_xdigit($hex)) { |
|||
return false; |
|||
} |
|||
if ($length === 3) { |
|||
$hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2]; |
|||
} |
|||
return "#$hex"; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,16 @@ |
|||
<?php |
|||
|
|||
class HTMLPurifier_AttrDef_HTML_ContentEditable extends HTMLPurifier_AttrDef |
|||
{ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$allowed = array('false'); |
|||
if ($config->get('HTML.Trusted')) { |
|||
$allowed = array('', 'true', 'false'); |
|||
} |
|||
|
|||
$enum = new HTMLPurifier_AttrDef_Enum($allowed); |
|||
|
|||
return $enum->validate($string, $config, $context); |
|||
} |
|||
} |
@ -0,0 +1,38 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Special-case enum attribute definition that lazy loads allowed frame targets |
|||
*/ |
|||
class HTMLPurifier_AttrDef_HTML_FrameTarget extends HTMLPurifier_AttrDef_Enum |
|||
{ |
|||
|
|||
/** |
|||
* @type array |
|||
*/ |
|||
public $valid_values = false; // uninitialized value |
|||
|
|||
/** |
|||
* @type bool |
|||
*/ |
|||
protected $case_sensitive = false; |
|||
|
|||
public function __construct() |
|||
{ |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
if ($this->valid_values === false) { |
|||
$this->valid_values = $config->get('Attr.AllowedFrameTargets'); |
|||
} |
|||
return parent::validate($string, $config, $context); |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,113 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates the HTML attribute ID. |
|||
* @warning Even though this is the id processor, it |
|||
* will ignore the directive Attr:IDBlacklist, since it will only |
|||
* go according to the ID accumulator. Since the accumulator is |
|||
* automatically generated, it will have already absorbed the |
|||
* blacklist. If you're hacking around, make sure you use load()! |
|||
*/ |
|||
|
|||
class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
// selector is NOT a valid thing to use for IDREFs, because IDREFs |
|||
// *must* target IDs that exist, whereas selector #ids do not. |
|||
|
|||
/** |
|||
* Determines whether or not we're validating an ID in a CSS |
|||
* selector context. |
|||
* @type bool |
|||
*/ |
|||
protected $selector; |
|||
|
|||
/** |
|||
* @param bool $selector |
|||
*/ |
|||
public function __construct($selector = false) |
|||
{ |
|||
$this->selector = $selector; |
|||
} |
|||
|
|||
/** |
|||
* @param string $id |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($id, $config, $context) |
|||
{ |
|||
if (!$this->selector && !$config->get('Attr.EnableID')) { |
|||
return false; |
|||
} |
|||
|
|||
$id = trim($id); // trim it first |
|||
|
|||
if ($id === '') { |
|||
return false; |
|||
} |
|||
|
|||
$prefix = $config->get('Attr.IDPrefix'); |
|||
if ($prefix !== '') { |
|||
$prefix .= $config->get('Attr.IDPrefixLocal'); |
|||
// prevent re-appending the prefix |
|||
if (strpos($id, $prefix) !== 0) { |
|||
$id = $prefix . $id; |
|||
} |
|||
} elseif ($config->get('Attr.IDPrefixLocal') !== '') { |
|||
trigger_error( |
|||
'%Attr.IDPrefixLocal cannot be used unless ' . |
|||
'%Attr.IDPrefix is set', |
|||
E_USER_WARNING |
|||
); |
|||
} |
|||
|
|||
if (!$this->selector) { |
|||
$id_accumulator =& $context->get('IDAccumulator'); |
|||
if (isset($id_accumulator->ids[$id])) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// we purposely avoid using regex, hopefully this is faster |
|||
|
|||
if ($config->get('Attr.ID.HTML5') === true) { |
|||
if (preg_match('/[\t\n\x0b\x0c ]/', $id)) { |
|||
return false; |
|||
} |
|||
} else { |
|||
if (ctype_alpha($id)) { |
|||
// OK |
|||
} else { |
|||
if (!ctype_alpha(@$id[0])) { |
|||
return false; |
|||
} |
|||
// primitive style of regexps, I suppose |
|||
$trim = trim( |
|||
$id, |
|||
'A..Za..z0..9:-._' |
|||
); |
|||
if ($trim !== '') { |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
|
|||
$regexp = $config->get('Attr.IDBlacklistRegexp'); |
|||
if ($regexp && preg_match($regexp, $id)) { |
|||
return false; |
|||
} |
|||
|
|||
if (!$this->selector) { |
|||
$id_accumulator->add($id); |
|||
} |
|||
|
|||
// if no change was made to the ID, return the result |
|||
// else, return the new id if stripping whitespace made it |
|||
// valid, or return false. |
|||
return $id; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,56 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates the HTML type length (not to be confused with CSS's length). |
|||
* |
|||
* This accepts integer pixels or percentages as lengths for certain |
|||
* HTML attributes. |
|||
*/ |
|||
|
|||
class HTMLPurifier_AttrDef_HTML_Length extends HTMLPurifier_AttrDef_HTML_Pixels |
|||
{ |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$string = trim($string); |
|||
if ($string === '') { |
|||
return false; |
|||
} |
|||
|
|||
$parent_result = parent::validate($string, $config, $context); |
|||
if ($parent_result !== false) { |
|||
return $parent_result; |
|||
} |
|||
|
|||
$length = strlen($string); |
|||
$last_char = $string[$length - 1]; |
|||
|
|||
if ($last_char !== '%') { |
|||
return false; |
|||
} |
|||
|
|||
$points = substr($string, 0, $length - 1); |
|||
|
|||
if (!is_numeric($points)) { |
|||
return false; |
|||
} |
|||
|
|||
$points = (int)$points; |
|||
|
|||
if ($points < 0) { |
|||
return '0%'; |
|||
} |
|||
if ($points > 100) { |
|||
return '100%'; |
|||
} |
|||
return ((string)$points) . '%'; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,72 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates a rel/rev link attribute against a directive of allowed values |
|||
* @note We cannot use Enum because link types allow multiple |
|||
* values. |
|||
* @note Assumes link types are ASCII text |
|||
*/ |
|||
class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* Name config attribute to pull. |
|||
* @type string |
|||
*/ |
|||
protected $name; |
|||
|
|||
/** |
|||
* @param string $name |
|||
*/ |
|||
public function __construct($name) |
|||
{ |
|||
$configLookup = array( |
|||
'rel' => 'AllowedRel', |
|||
'rev' => 'AllowedRev' |
|||
); |
|||
if (!isset($configLookup[$name])) { |
|||
trigger_error( |
|||
'Unrecognized attribute name for link ' . |
|||
'relationship.', |
|||
E_USER_ERROR |
|||
); |
|||
return; |
|||
} |
|||
$this->name = $configLookup[$name]; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$allowed = $config->get('Attr.' . $this->name); |
|||
if (empty($allowed)) { |
|||
return false; |
|||
} |
|||
|
|||
$string = $this->parseCDATA($string); |
|||
$parts = explode(' ', $string); |
|||
|
|||
// lookup to prevent duplicates |
|||
$ret_lookup = array(); |
|||
foreach ($parts as $part) { |
|||
$part = strtolower(trim($part)); |
|||
if (!isset($allowed[$part])) { |
|||
continue; |
|||
} |
|||
$ret_lookup[$part] = true; |
|||
} |
|||
|
|||
if (empty($ret_lookup)) { |
|||
return false; |
|||
} |
|||
$string = implode(' ', array_keys($ret_lookup)); |
|||
return $string; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,60 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates a MultiLength as defined by the HTML spec. |
|||
* |
|||
* A multilength is either a integer (pixel count), a percentage, or |
|||
* a relative number. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_HTML_MultiLength extends HTMLPurifier_AttrDef_HTML_Length |
|||
{ |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$string = trim($string); |
|||
if ($string === '') { |
|||
return false; |
|||
} |
|||
|
|||
$parent_result = parent::validate($string, $config, $context); |
|||
if ($parent_result !== false) { |
|||
return $parent_result; |
|||
} |
|||
|
|||
$length = strlen($string); |
|||
$last_char = $string[$length - 1]; |
|||
|
|||
if ($last_char !== '*') { |
|||
return false; |
|||
} |
|||
|
|||
$int = substr($string, 0, $length - 1); |
|||
|
|||
if ($int == '') { |
|||
return '*'; |
|||
} |
|||
if (!is_numeric($int)) { |
|||
return false; |
|||
} |
|||
|
|||
$int = (int)$int; |
|||
if ($int < 0) { |
|||
return false; |
|||
} |
|||
if ($int == 0) { |
|||
return '0'; |
|||
} |
|||
if ($int == 1) { |
|||
return '*'; |
|||
} |
|||
return ((string)$int) . '*'; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,70 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates contents based on NMTOKENS attribute type. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$string = trim($string); |
|||
|
|||
// early abort: '' and '0' (strings that convert to false) are invalid |
|||
if (!$string) { |
|||
return false; |
|||
} |
|||
|
|||
$tokens = $this->split($string, $config, $context); |
|||
$tokens = $this->filter($tokens, $config, $context); |
|||
if (empty($tokens)) { |
|||
return false; |
|||
} |
|||
return implode(' ', $tokens); |
|||
} |
|||
|
|||
/** |
|||
* Splits a space separated list of tokens into its constituent parts. |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
protected function split($string, $config, $context) |
|||
{ |
|||
// OPTIMIZABLE! |
|||
// do the preg_match, capture all subpatterns for reformulation |
|||
|
|||
// we don't support U+00A1 and up codepoints or |
|||
// escaping because I don't know how to do that with regexps |
|||
// and plus it would complicate optimization efforts (you never |
|||
// see that anyway). |
|||
$pattern = '/(?:(?<=\s)|\A)' . // look behind for space or string start |
|||
'((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)' . |
|||
'(?:(?=\s)|\z)/'; // look ahead for space or string end |
|||
preg_match_all($pattern, $string, $matches); |
|||
return $matches[1]; |
|||
} |
|||
|
|||
/** |
|||
* Template method for removing certain tokens based on arbitrary criteria. |
|||
* @note If we wanted to be really functional, we'd do an array_filter |
|||
* with a callback. But... we're not. |
|||
* @param array $tokens |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
protected function filter($tokens, $config, $context) |
|||
{ |
|||
return $tokens; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,76 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates an integer representation of pixels according to the HTML spec. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_HTML_Pixels extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* @type int |
|||
*/ |
|||
protected $max; |
|||
|
|||
/** |
|||
* @param int $max |
|||
*/ |
|||
public function __construct($max = null) |
|||
{ |
|||
$this->max = $max; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$string = trim($string); |
|||
if ($string === '0') { |
|||
return $string; |
|||
} |
|||
if ($string === '') { |
|||
return false; |
|||
} |
|||
$length = strlen($string); |
|||
if (substr($string, $length - 2) == 'px') { |
|||
$string = substr($string, 0, $length - 2); |
|||
} |
|||
if (!is_numeric($string)) { |
|||
return false; |
|||
} |
|||
$int = (int)$string; |
|||
|
|||
if ($int < 0) { |
|||
return '0'; |
|||
} |
|||
|
|||
// upper-bound value, extremely high values can |
|||
// crash operating systems, see <http://ha.ckers.org/imagecrash.html> |
|||
// WARNING, above link WILL crash you if you're using Windows |
|||
|
|||
if ($this->max !== null && $int > $this->max) { |
|||
return (string)$this->max; |
|||
} |
|||
return (string)$int; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @return HTMLPurifier_AttrDef |
|||
*/ |
|||
public function make($string) |
|||
{ |
|||
if ($string === '') { |
|||
$max = null; |
|||
} else { |
|||
$max = (int)$string; |
|||
} |
|||
$class = get_class($this); |
|||
return new $class($max); |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,91 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates an integer. |
|||
* @note While this class was modeled off the CSS definition, no currently |
|||
* allowed CSS uses this type. The properties that do are: widows, |
|||
* orphans, z-index, counter-increment, counter-reset. Some of the |
|||
* HTML attributes, however, find use for a non-negative version of this. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_Integer extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* Whether or not negative values are allowed. |
|||
* @type bool |
|||
*/ |
|||
protected $negative = true; |
|||
|
|||
/** |
|||
* Whether or not zero is allowed. |
|||
* @type bool |
|||
*/ |
|||
protected $zero = true; |
|||
|
|||
/** |
|||
* Whether or not positive values are allowed. |
|||
* @type bool |
|||
*/ |
|||
protected $positive = true; |
|||
|
|||
/** |
|||
* @param $negative Bool indicating whether or not negative values are allowed |
|||
* @param $zero Bool indicating whether or not zero is allowed |
|||
* @param $positive Bool indicating whether or not positive values are allowed |
|||
*/ |
|||
public function __construct($negative = true, $zero = true, $positive = true) |
|||
{ |
|||
$this->negative = $negative; |
|||
$this->zero = $zero; |
|||
$this->positive = $positive; |
|||
} |
|||
|
|||
/** |
|||
* @param string $integer |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($integer, $config, $context) |
|||
{ |
|||
$integer = $this->parseCDATA($integer); |
|||
if ($integer === '') { |
|||
return false; |
|||
} |
|||
|
|||
// we could possibly simply typecast it to integer, but there are |
|||
// certain fringe cases that must not return an integer. |
|||
|
|||
// clip leading sign |
|||
if ($this->negative && $integer[0] === '-') { |
|||
$digits = substr($integer, 1); |
|||
if ($digits === '0') { |
|||
$integer = '0'; |
|||
} // rm minus sign for zero |
|||
} elseif ($this->positive && $integer[0] === '+') { |
|||
$digits = $integer = substr($integer, 1); // rm unnecessary plus |
|||
} else { |
|||
$digits = $integer; |
|||
} |
|||
|
|||
// test if it's numeric |
|||
if (!ctype_digit($digits)) { |
|||
return false; |
|||
} |
|||
|
|||
// perform scope tests |
|||
if (!$this->zero && $integer == 0) { |
|||
return false; |
|||
} |
|||
if (!$this->positive && $integer > 0) { |
|||
return false; |
|||
} |
|||
if (!$this->negative && $integer < 0) { |
|||
return false; |
|||
} |
|||
|
|||
return $integer; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,86 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates the HTML attribute lang, effectively a language code. |
|||
* @note Built according to RFC 3066, which obsoleted RFC 1766 |
|||
*/ |
|||
class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$string = trim($string); |
|||
if (!$string) { |
|||
return false; |
|||
} |
|||
|
|||
$subtags = explode('-', $string); |
|||
$num_subtags = count($subtags); |
|||
|
|||
if ($num_subtags == 0) { // sanity check |
|||
return false; |
|||
} |
|||
|
|||
// process primary subtag : $subtags[0] |
|||
$length = strlen($subtags[0]); |
|||
switch ($length) { |
|||
case 0: |
|||
return false; |
|||
case 1: |
|||
if (!($subtags[0] == 'x' || $subtags[0] == 'i')) { |
|||
return false; |
|||
} |
|||
break; |
|||
case 2: |
|||
case 3: |
|||
if (!ctype_alpha($subtags[0])) { |
|||
return false; |
|||
} elseif (!ctype_lower($subtags[0])) { |
|||
$subtags[0] = strtolower($subtags[0]); |
|||
} |
|||
break; |
|||
default: |
|||
return false; |
|||
} |
|||
|
|||
$new_string = $subtags[0]; |
|||
if ($num_subtags == 1) { |
|||
return $new_string; |
|||
} |
|||
|
|||
// process second subtag : $subtags[1] |
|||
$length = strlen($subtags[1]); |
|||
if ($length == 0 || ($length == 1 && $subtags[1] != 'x') || $length > 8 || !ctype_alnum($subtags[1])) { |
|||
return $new_string; |
|||
} |
|||
if (!ctype_lower($subtags[1])) { |
|||
$subtags[1] = strtolower($subtags[1]); |
|||
} |
|||
|
|||
$new_string .= '-' . $subtags[1]; |
|||
if ($num_subtags == 2) { |
|||
return $new_string; |
|||
} |
|||
|
|||
// process all other subtags, index 2 and up |
|||
for ($i = 2; $i < $num_subtags; $i++) { |
|||
$length = strlen($subtags[$i]); |
|||
if ($length == 0 || $length > 8 || !ctype_alnum($subtags[$i])) { |
|||
return $new_string; |
|||
} |
|||
if (!ctype_lower($subtags[$i])) { |
|||
$subtags[$i] = strtolower($subtags[$i]); |
|||
} |
|||
$new_string .= '-' . $subtags[$i]; |
|||
} |
|||
return $new_string; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,53 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Decorator that, depending on a token, switches between two definitions. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_Switch |
|||
{ |
|||
|
|||
/** |
|||
* @type string |
|||
*/ |
|||
protected $tag; |
|||
|
|||
/** |
|||
* @type HTMLPurifier_AttrDef |
|||
*/ |
|||
protected $withTag; |
|||
|
|||
/** |
|||
* @type HTMLPurifier_AttrDef |
|||
*/ |
|||
protected $withoutTag; |
|||
|
|||
/** |
|||
* @param string $tag Tag name to switch upon |
|||
* @param HTMLPurifier_AttrDef $with_tag Call if token matches tag |
|||
* @param HTMLPurifier_AttrDef $without_tag Call if token doesn't match, or there is no token |
|||
*/ |
|||
public function __construct($tag, $with_tag, $without_tag) |
|||
{ |
|||
$this->tag = $tag; |
|||
$this->withTag = $with_tag; |
|||
$this->withoutTag = $without_tag; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$token = $context->get('CurrentToken', true); |
|||
if (!$token || $token->name !== $this->tag) { |
|||
return $this->withoutTag->validate($string, $config, $context); |
|||
} else { |
|||
return $this->withTag->validate($string, $config, $context); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,21 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates arbitrary text according to the HTML spec. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_Text extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
return $this->parseCDATA($string); |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,111 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates a URI as defined by RFC 3986. |
|||
* @note Scheme-specific mechanics deferred to HTMLPurifier_URIScheme |
|||
*/ |
|||
class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* @type HTMLPurifier_URIParser |
|||
*/ |
|||
protected $parser; |
|||
|
|||
/** |
|||
* @type bool |
|||
*/ |
|||
protected $embedsResource; |
|||
|
|||
/** |
|||
* @param bool $embeds_resource Does the URI here result in an extra HTTP request? |
|||
*/ |
|||
public function __construct($embeds_resource = false) |
|||
{ |
|||
$this->parser = new HTMLPurifier_URIParser(); |
|||
$this->embedsResource = (bool)$embeds_resource; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @return HTMLPurifier_AttrDef_URI |
|||
*/ |
|||
public function make($string) |
|||
{ |
|||
$embeds = ($string === 'embedded'); |
|||
return new HTMLPurifier_AttrDef_URI($embeds); |
|||
} |
|||
|
|||
/** |
|||
* @param string $uri |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($uri, $config, $context) |
|||
{ |
|||
if ($config->get('URI.Disable')) { |
|||
return false; |
|||
} |
|||
|
|||
$uri = $this->parseCDATA($uri); |
|||
|
|||
// parse the URI |
|||
$uri = $this->parser->parse($uri); |
|||
if ($uri === false) { |
|||
return false; |
|||
} |
|||
|
|||
// add embedded flag to context for validators |
|||
$context->register('EmbeddedURI', $this->embedsResource); |
|||
|
|||
$ok = false; |
|||
do { |
|||
|
|||
// generic validation |
|||
$result = $uri->validate($config, $context); |
|||
if (!$result) { |
|||
break; |
|||
} |
|||
|
|||
// chained filtering |
|||
$uri_def = $config->getDefinition('URI'); |
|||
$result = $uri_def->filter($uri, $config, $context); |
|||
if (!$result) { |
|||
break; |
|||
} |
|||
|
|||
// scheme-specific validation |
|||
$scheme_obj = $uri->getSchemeObj($config, $context); |
|||
if (!$scheme_obj) { |
|||
break; |
|||
} |
|||
if ($this->embedsResource && !$scheme_obj->browsable) { |
|||
break; |
|||
} |
|||
$result = $scheme_obj->validate($uri, $config, $context); |
|||
if (!$result) { |
|||
break; |
|||
} |
|||
|
|||
// Post chained filtering |
|||
$result = $uri_def->postFilter($uri, $config, $context); |
|||
if (!$result) { |
|||
break; |
|||
} |
|||
|
|||
// survived gauntlet |
|||
$ok = true; |
|||
|
|||
} while (false); |
|||
|
|||
$context->destroy('EmbeddedURI'); |
|||
if (!$ok) { |
|||
return false; |
|||
} |
|||
// back to string |
|||
return $uri->toString(); |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,20 @@ |
|||
<?php |
|||
|
|||
abstract class HTMLPurifier_AttrDef_URI_Email extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* Unpacks a mailbox into its display-name and address |
|||
* @param string $string |
|||
* @return mixed |
|||
*/ |
|||
public function unpack($string) |
|||
{ |
|||
// needs to be implemented |
|||
} |
|||
|
|||
} |
|||
|
|||
// sub-implementations |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,29 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Primitive email validation class based on the regexp found at |
|||
* http://www.regular-expressions.info/email.html |
|||
*/ |
|||
class HTMLPurifier_AttrDef_URI_Email_SimpleCheck extends HTMLPurifier_AttrDef_URI_Email |
|||
{ |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
// no support for named mailboxes i.e. "Bob <bob@example.com>" |
|||
// that needs more percent encoding to be done |
|||
if ($string == '') { |
|||
return false; |
|||
} |
|||
$string = trim($string); |
|||
$result = preg_match('/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i', $string); |
|||
return $result ? $string : false; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,142 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates a host according to the IPv4, IPv6 and DNS (future) specifications. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* IPv4 sub-validator. |
|||
* @type HTMLPurifier_AttrDef_URI_IPv4 |
|||
*/ |
|||
protected $ipv4; |
|||
|
|||
/** |
|||
* IPv6 sub-validator. |
|||
* @type HTMLPurifier_AttrDef_URI_IPv6 |
|||
*/ |
|||
protected $ipv6; |
|||
|
|||
public function __construct() |
|||
{ |
|||
$this->ipv4 = new HTMLPurifier_AttrDef_URI_IPv4(); |
|||
$this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6(); |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($string, $config, $context) |
|||
{ |
|||
$length = strlen($string); |
|||
// empty hostname is OK; it's usually semantically equivalent: |
|||
// the default host as defined by a URI scheme is used: |
|||
// |
|||
// If the URI scheme defines a default for host, then that |
|||
// default applies when the host subcomponent is undefined |
|||
// or when the registered name is empty (zero length). |
|||
if ($string === '') { |
|||
return ''; |
|||
} |
|||
if ($length > 1 && $string[0] === '[' && $string[$length - 1] === ']') { |
|||
//IPv6 |
|||
$ip = substr($string, 1, $length - 2); |
|||
$valid = $this->ipv6->validate($ip, $config, $context); |
|||
if ($valid === false) { |
|||
return false; |
|||
} |
|||
return '[' . $valid . ']'; |
|||
} |
|||
|
|||
// need to do checks on unusual encodings too |
|||
$ipv4 = $this->ipv4->validate($string, $config, $context); |
|||
if ($ipv4 !== false) { |
|||
return $ipv4; |
|||
} |
|||
|
|||
// A regular domain name. |
|||
|
|||
// This doesn't match I18N domain names, but we don't have proper IRI support, |
|||
// so force users to insert Punycode. |
|||
|
|||
// There is not a good sense in which underscores should be |
|||
// allowed, since it's technically not! (And if you go as |
|||
// far to allow everything as specified by the DNS spec... |
|||
// well, that's literally everything, modulo some space limits |
|||
// for the components and the overall name (which, by the way, |
|||
// we are NOT checking!). So we (arbitrarily) decide this: |
|||
// let's allow underscores wherever we would have allowed |
|||
// hyphens, if they are enabled. This is a pretty good match |
|||
// for browser behavior, for example, a large number of browsers |
|||
// cannot handle foo_.example.com, but foo_bar.example.com is |
|||
// fairly well supported. |
|||
$underscore = $config->get('Core.AllowHostnameUnderscore') ? '_' : ''; |
|||
|
|||
// Based off of RFC 1738, but amended so that |
|||
// as per RFC 3696, the top label need only not be all numeric. |
|||
// The productions describing this are: |
|||
$a = '[a-z]'; // alpha |
|||
$an = '[a-z0-9]'; // alphanum |
|||
$and = "[a-z0-9-$underscore]"; // alphanum | "-" |
|||
// domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum |
|||
$domainlabel = "$an(?:$and*$an)?"; |
|||
// AMENDED as per RFC 3696 |
|||
// toplabel = alphanum | alphanum *( alphanum | "-" ) alphanum |
|||
// side condition: not all numeric |
|||
$toplabel = "$an(?:$and*$an)?"; |
|||
// hostname = *( domainlabel "." ) toplabel [ "." ] |
|||
if (preg_match("/^(?:$domainlabel\.)*($toplabel)\.?$/i", $string, $matches)) { |
|||
if (!ctype_digit($matches[1])) { |
|||
return $string; |
|||
} |
|||
} |
|||
|
|||
// PHP 5.3 and later support this functionality natively |
|||
if (function_exists('idn_to_ascii')) { |
|||
if (defined('IDNA_NONTRANSITIONAL_TO_ASCII') && defined('INTL_IDNA_VARIANT_UTS46')) { |
|||
$string = idn_to_ascii($string, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46); |
|||
} else { |
|||
$string = idn_to_ascii($string); |
|||
} |
|||
|
|||
// If we have Net_IDNA2 support, we can support IRIs by |
|||
// punycoding them. (This is the most portable thing to do, |
|||
// since otherwise we have to assume browsers support |
|||
} elseif ($config->get('Core.EnableIDNA') && class_exists('Net_IDNA2')) { |
|||
$idna = new Net_IDNA2(array('encoding' => 'utf8', 'overlong' => false, 'strict' => true)); |
|||
// we need to encode each period separately |
|||
$parts = explode('.', $string); |
|||
try { |
|||
$new_parts = array(); |
|||
foreach ($parts as $part) { |
|||
$encodable = false; |
|||
for ($i = 0, $c = strlen($part); $i < $c; $i++) { |
|||
if (ord($part[$i]) > 0x7a) { |
|||
$encodable = true; |
|||
break; |
|||
} |
|||
} |
|||
if (!$encodable) { |
|||
$new_parts[] = $part; |
|||
} else { |
|||
$new_parts[] = $idna->encode($part); |
|||
} |
|||
} |
|||
$string = implode('.', $new_parts); |
|||
} catch (Exception $e) { |
|||
// XXX error reporting |
|||
} |
|||
} |
|||
// Try again |
|||
if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) { |
|||
return $string; |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,45 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates an IPv4 address |
|||
* @author Feyd @ forums.devnetwork.net (public domain) |
|||
*/ |
|||
class HTMLPurifier_AttrDef_URI_IPv4 extends HTMLPurifier_AttrDef |
|||
{ |
|||
|
|||
/** |
|||
* IPv4 regex, protected so that IPv6 can reuse it. |
|||
* @type string |
|||
*/ |
|||
protected $ip4; |
|||
|
|||
/** |
|||
* @param string $aIP |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($aIP, $config, $context) |
|||
{ |
|||
if (!$this->ip4) { |
|||
$this->_loadRegex(); |
|||
} |
|||
|
|||
if (preg_match('#^' . $this->ip4 . '$#s', $aIP)) { |
|||
return $aIP; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Lazy load function to prevent regex from being stuffed in |
|||
* cache. |
|||
*/ |
|||
protected function _loadRegex() |
|||
{ |
|||
$oct = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])'; // 0-255 |
|||
$this->ip4 = "(?:{$oct}\\.{$oct}\\.{$oct}\\.{$oct})"; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,89 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates an IPv6 address. |
|||
* @author Feyd @ forums.devnetwork.net (public domain) |
|||
* @note This function requires brackets to have been removed from address |
|||
* in URI. |
|||
*/ |
|||
class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4 |
|||
{ |
|||
|
|||
/** |
|||
* @param string $aIP |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return bool|string |
|||
*/ |
|||
public function validate($aIP, $config, $context) |
|||
{ |
|||
if (!$this->ip4) { |
|||
$this->_loadRegex(); |
|||
} |
|||
|
|||
$original = $aIP; |
|||
|
|||
$hex = '[0-9a-fA-F]'; |
|||
$blk = '(?:' . $hex . '{1,4})'; |
|||
$pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128 |
|||
|
|||
// prefix check |
|||
if (strpos($aIP, '/') !== false) { |
|||
if (preg_match('#' . $pre . '$#s', $aIP, $find)) { |
|||
$aIP = substr($aIP, 0, 0 - strlen($find[0])); |
|||
unset($find); |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// IPv4-compatiblity check |
|||
if (preg_match('#(?<=:' . ')' . $this->ip4 . '$#s', $aIP, $find)) { |
|||
$aIP = substr($aIP, 0, 0 - strlen($find[0])); |
|||
$ip = explode('.', $find[0]); |
|||
$ip = array_map('dechex', $ip); |
|||
$aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3]; |
|||
unset($find, $ip); |
|||
} |
|||
|
|||
// compression check |
|||
$aIP = explode('::', $aIP); |
|||
$c = count($aIP); |
|||
if ($c > 2) { |
|||
return false; |
|||
} elseif ($c == 2) { |
|||
list($first, $second) = $aIP; |
|||
$first = explode(':', $first); |
|||
$second = explode(':', $second); |
|||
|
|||
if (count($first) + count($second) > 8) { |
|||
return false; |
|||
} |
|||
|
|||
while (count($first) < 8) { |
|||
array_push($first, '0'); |
|||
} |
|||
|
|||
array_splice($first, 8 - count($second), 8, $second); |
|||
$aIP = $first; |
|||
unset($first, $second); |
|||
} else { |
|||
$aIP = explode(':', $aIP[0]); |
|||
} |
|||
$c = count($aIP); |
|||
|
|||
if ($c != 8) { |
|||
return false; |
|||
} |
|||
|
|||
// All the pieces should be 16-bit hex strings. Are they? |
|||
foreach ($aIP as $piece) { |
|||
if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece))) { |
|||
return false; |
|||
} |
|||
} |
|||
return $original; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,60 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Processes an entire attribute array for corrections needing multiple values. |
|||
* |
|||
* Occasionally, a certain attribute will need to be removed and popped onto |
|||
* another value. Instead of creating a complex return syntax for |
|||
* HTMLPurifier_AttrDef, we just pass the whole attribute array to a |
|||
* specialized object and have that do the special work. That is the |
|||
* family of HTMLPurifier_AttrTransform. |
|||
* |
|||
* An attribute transformation can be assigned to run before or after |
|||
* HTMLPurifier_AttrDef validation. See HTMLPurifier_HTMLDefinition for |
|||
* more details. |
|||
*/ |
|||
|
|||
abstract class HTMLPurifier_AttrTransform |
|||
{ |
|||
|
|||
/** |
|||
* Abstract: makes changes to the attributes dependent on multiple values. |
|||
* |
|||
* @param array $attr Assoc array of attributes, usually from |
|||
* HTMLPurifier_Token_Tag::$attr |
|||
* @param HTMLPurifier_Config $config Mandatory HTMLPurifier_Config object. |
|||
* @param HTMLPurifier_Context $context Mandatory HTMLPurifier_Context object |
|||
* @return array Processed attribute array. |
|||
*/ |
|||
abstract public function transform($attr, $config, $context); |
|||
|
|||
/** |
|||
* Prepends CSS properties to the style attribute, creating the |
|||
* attribute if it doesn't exist. |
|||
* @param array &$attr Attribute array to process (passed by reference) |
|||
* @param string $css CSS to prepend |
|||
*/ |
|||
public function prependCSS(&$attr, $css) |
|||
{ |
|||
$attr['style'] = isset($attr['style']) ? $attr['style'] : ''; |
|||
$attr['style'] = $css . $attr['style']; |
|||
} |
|||
|
|||
/** |
|||
* Retrieves and removes an attribute |
|||
* @param array &$attr Attribute array to process (passed by reference) |
|||
* @param mixed $key Key of attribute to confiscate |
|||
* @return mixed |
|||
*/ |
|||
public function confiscateAttr(&$attr, $key) |
|||
{ |
|||
if (!isset($attr[$key])) { |
|||
return null; |
|||
} |
|||
$value = $attr[$key]; |
|||
unset($attr[$key]); |
|||
return $value; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,28 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Pre-transform that changes proprietary background attribute to CSS. |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_Background extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (!isset($attr['background'])) { |
|||
return $attr; |
|||
} |
|||
|
|||
$background = $this->confiscateAttr($attr, 'background'); |
|||
// some validation should happen here |
|||
|
|||
$this->prependCSS($attr, "background-image:url($background);"); |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,27 @@ |
|||
<?php |
|||
|
|||
// this MUST be placed in post, as it assumes that any value in dir is valid |
|||
|
|||
/** |
|||
* Post-trasnform that ensures that bdo tags have the dir attribute set. |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_BdoDir extends HTMLPurifier_AttrTransform |
|||
{ |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (isset($attr['dir'])) { |
|||
return $attr; |
|||
} |
|||
$attr['dir'] = $config->get('Attr.DefaultTextDir'); |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,28 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Pre-transform that changes deprecated bgcolor attribute to CSS. |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_BgColor extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (!isset($attr['bgcolor'])) { |
|||
return $attr; |
|||
} |
|||
|
|||
$bgcolor = $this->confiscateAttr($attr, 'bgcolor'); |
|||
// some validation should happen here |
|||
|
|||
$this->prependCSS($attr, "background-color:$bgcolor;"); |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,47 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Pre-transform that changes converts a boolean attribute to fixed CSS |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_BoolToCSS extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* Name of boolean attribute that is trigger. |
|||
* @type string |
|||
*/ |
|||
protected $attr; |
|||
|
|||
/** |
|||
* CSS declarations to add to style, needs trailing semicolon. |
|||
* @type string |
|||
*/ |
|||
protected $css; |
|||
|
|||
/** |
|||
* @param string $attr attribute name to convert from |
|||
* @param string $css CSS declarations to add to style (needs semicolon) |
|||
*/ |
|||
public function __construct($attr, $css) |
|||
{ |
|||
$this->attr = $attr; |
|||
$this->css = $css; |
|||
} |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (!isset($attr[$this->attr])) { |
|||
return $attr; |
|||
} |
|||
unset($attr[$this->attr]); |
|||
$this->prependCSS($attr, $this->css); |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,26 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Pre-transform that changes deprecated border attribute to CSS. |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_Border extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (!isset($attr['border'])) { |
|||
return $attr; |
|||
} |
|||
$border_width = $this->confiscateAttr($attr, 'border'); |
|||
// some validation should happen here |
|||
$this->prependCSS($attr, "border:{$border_width}px solid;"); |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,68 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Generic pre-transform that converts an attribute with a fixed number of |
|||
* values (enumerated) to CSS. |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_EnumToCSS extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* Name of attribute to transform from. |
|||
* @type string |
|||
*/ |
|||
protected $attr; |
|||
|
|||
/** |
|||
* Lookup array of attribute values to CSS. |
|||
* @type array |
|||
*/ |
|||
protected $enumToCSS = array(); |
|||
|
|||
/** |
|||
* Case sensitivity of the matching. |
|||
* @type bool |
|||
* @warning Currently can only be guaranteed to work with ASCII |
|||
* values. |
|||
*/ |
|||
protected $caseSensitive = false; |
|||
|
|||
/** |
|||
* @param string $attr Attribute name to transform from |
|||
* @param array $enum_to_css Lookup array of attribute values to CSS |
|||
* @param bool $case_sensitive Case sensitivity indicator, default false |
|||
*/ |
|||
public function __construct($attr, $enum_to_css, $case_sensitive = false) |
|||
{ |
|||
$this->attr = $attr; |
|||
$this->enumToCSS = $enum_to_css; |
|||
$this->caseSensitive = (bool)$case_sensitive; |
|||
} |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (!isset($attr[$this->attr])) { |
|||
return $attr; |
|||
} |
|||
|
|||
$value = trim($attr[$this->attr]); |
|||
unset($attr[$this->attr]); |
|||
|
|||
if (!$this->caseSensitive) { |
|||
$value = strtolower($value); |
|||
} |
|||
|
|||
if (!isset($this->enumToCSS[$value])) { |
|||
return $attr; |
|||
} |
|||
$this->prependCSS($attr, $this->enumToCSS[$value]); |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,47 @@ |
|||
<?php |
|||
|
|||
// must be called POST validation |
|||
|
|||
/** |
|||
* Transform that supplies default values for the src and alt attributes |
|||
* in img tags, as well as prevents the img tag from being removed |
|||
* because of a missing alt tag. This needs to be registered as both |
|||
* a pre and post attribute transform. |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_ImgRequired extends HTMLPurifier_AttrTransform |
|||
{ |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
$src = true; |
|||
if (!isset($attr['src'])) { |
|||
if ($config->get('Core.RemoveInvalidImg')) { |
|||
return $attr; |
|||
} |
|||
$attr['src'] = $config->get('Attr.DefaultInvalidImage'); |
|||
$src = false; |
|||
} |
|||
|
|||
if (!isset($attr['alt'])) { |
|||
if ($src) { |
|||
$alt = $config->get('Attr.DefaultImageAlt'); |
|||
if ($alt === null) { |
|||
$attr['alt'] = basename($attr['src']); |
|||
} else { |
|||
$attr['alt'] = $alt; |
|||
} |
|||
} else { |
|||
$attr['alt'] = $config->get('Attr.DefaultInvalidImageAlt'); |
|||
} |
|||
} |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,61 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Pre-transform that changes deprecated hspace and vspace attributes to CSS |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_ImgSpace extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* @type string |
|||
*/ |
|||
protected $attr; |
|||
|
|||
/** |
|||
* @type array |
|||
*/ |
|||
protected $css = array( |
|||
'hspace' => array('left', 'right'), |
|||
'vspace' => array('top', 'bottom') |
|||
); |
|||
|
|||
/** |
|||
* @param string $attr |
|||
*/ |
|||
public function __construct($attr) |
|||
{ |
|||
$this->attr = $attr; |
|||
if (!isset($this->css[$attr])) { |
|||
trigger_error(htmlspecialchars($attr) . ' is not valid space attribute'); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (!isset($attr[$this->attr])) { |
|||
return $attr; |
|||
} |
|||
|
|||
$width = $this->confiscateAttr($attr, $this->attr); |
|||
// some validation could happen here |
|||
|
|||
if (!isset($this->css[$this->attr])) { |
|||
return $attr; |
|||
} |
|||
|
|||
$style = ''; |
|||
foreach ($this->css[$this->attr] as $suffix) { |
|||
$property = "margin-$suffix"; |
|||
$style .= "$property:{$width}px;"; |
|||
} |
|||
$this->prependCSS($attr, $style); |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,56 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Performs miscellaneous cross attribute validation and filtering for |
|||
* input elements. This is meant to be a post-transform. |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_Input extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* @type HTMLPurifier_AttrDef_HTML_Pixels |
|||
*/ |
|||
protected $pixels; |
|||
|
|||
public function __construct() |
|||
{ |
|||
$this->pixels = new HTMLPurifier_AttrDef_HTML_Pixels(); |
|||
} |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (!isset($attr['type'])) { |
|||
$t = 'text'; |
|||
} else { |
|||
$t = strtolower($attr['type']); |
|||
} |
|||
if (isset($attr['checked']) && $t !== 'radio' && $t !== 'checkbox') { |
|||
unset($attr['checked']); |
|||
} |
|||
if (isset($attr['maxlength']) && $t !== 'text' && $t !== 'password') { |
|||
unset($attr['maxlength']); |
|||
} |
|||
if (isset($attr['size']) && $t !== 'text' && $t !== 'password') { |
|||
$result = $this->pixels->validate($attr['size'], $config, $context); |
|||
if ($result === false) { |
|||
unset($attr['size']); |
|||
} else { |
|||
$attr['size'] = $result; |
|||
} |
|||
} |
|||
if (isset($attr['src']) && $t !== 'image') { |
|||
unset($attr['src']); |
|||
} |
|||
if (!isset($attr['value']) && ($t === 'radio' || $t === 'checkbox')) { |
|||
$attr['value'] = ''; |
|||
} |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,31 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Post-transform that copies lang's value to xml:lang (and vice-versa) |
|||
* @note Theoretically speaking, this could be a pre-transform, but putting |
|||
* post is more efficient. |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_Lang extends HTMLPurifier_AttrTransform |
|||
{ |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
$lang = isset($attr['lang']) ? $attr['lang'] : false; |
|||
$xml_lang = isset($attr['xml:lang']) ? $attr['xml:lang'] : false; |
|||
|
|||
if ($lang !== false && $xml_lang === false) { |
|||
$attr['xml:lang'] = $lang; |
|||
} elseif ($xml_lang !== false) { |
|||
$attr['lang'] = $xml_lang; |
|||
} |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,45 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Class for handling width/height length attribute transformations to CSS |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_Length extends HTMLPurifier_AttrTransform |
|||
{ |
|||
|
|||
/** |
|||
* @type string |
|||
*/ |
|||
protected $name; |
|||
|
|||
/** |
|||
* @type string |
|||
*/ |
|||
protected $cssName; |
|||
|
|||
public function __construct($name, $css_name = null) |
|||
{ |
|||
$this->name = $name; |
|||
$this->cssName = $css_name ? $css_name : $name; |
|||
} |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (!isset($attr[$this->name])) { |
|||
return $attr; |
|||
} |
|||
$length = $this->confiscateAttr($attr, $this->name); |
|||
if (ctype_digit($length)) { |
|||
$length .= 'px'; |
|||
} |
|||
$this->prependCSS($attr, $this->cssName . ":$length;"); |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,33 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Pre-transform that changes deprecated name attribute to ID if necessary |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_Name extends HTMLPurifier_AttrTransform |
|||
{ |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
// Abort early if we're using relaxed definition of name |
|||
if ($config->get('HTML.Attr.Name.UseCDATA')) { |
|||
return $attr; |
|||
} |
|||
if (!isset($attr['name'])) { |
|||
return $attr; |
|||
} |
|||
$id = $this->confiscateAttr($attr, 'name'); |
|||
if (isset($attr['id'])) { |
|||
return $attr; |
|||
} |
|||
$attr['id'] = $id; |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,46 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Post-transform that performs validation to the name attribute; if |
|||
* it is present with an equivalent id attribute, it is passed through; |
|||
* otherwise validation is performed. |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_NameSync extends HTMLPurifier_AttrTransform |
|||
{ |
|||
|
|||
/** |
|||
* @type HTMLPurifier_AttrDef_HTML_ID |
|||
*/ |
|||
public $idDef; |
|||
|
|||
public function __construct() |
|||
{ |
|||
$this->idDef = new HTMLPurifier_AttrDef_HTML_ID(); |
|||
} |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (!isset($attr['name'])) { |
|||
return $attr; |
|||
} |
|||
$name = $attr['name']; |
|||
if (isset($attr['id']) && $attr['id'] === $name) { |
|||
return $attr; |
|||
} |
|||
$result = $this->idDef->validate($name, $config, $context); |
|||
if ($result === false) { |
|||
unset($attr['name']); |
|||
} else { |
|||
$attr['name'] = $result; |
|||
} |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,52 @@ |
|||
<?php |
|||
|
|||
// must be called POST validation |
|||
|
|||
/** |
|||
* Adds rel="nofollow" to all outbound links. This transform is |
|||
* only attached if Attr.Nofollow is TRUE. |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_Nofollow extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* @type HTMLPurifier_URIParser |
|||
*/ |
|||
private $parser; |
|||
|
|||
public function __construct() |
|||
{ |
|||
$this->parser = new HTMLPurifier_URIParser(); |
|||
} |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (!isset($attr['href'])) { |
|||
return $attr; |
|||
} |
|||
|
|||
// XXX Kind of inefficient |
|||
$url = $this->parser->parse($attr['href']); |
|||
$scheme = $url->getSchemeObj($config, $context); |
|||
|
|||
if ($scheme->browsable && !$url->isLocal($config, $context)) { |
|||
if (isset($attr['rel'])) { |
|||
$rels = explode(' ', $attr['rel']); |
|||
if (!in_array('nofollow', $rels)) { |
|||
$rels[] = 'nofollow'; |
|||
} |
|||
$attr['rel'] = implode(' ', $rels); |
|||
} else { |
|||
$attr['rel'] = 'nofollow'; |
|||
} |
|||
} |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,25 @@ |
|||
<?php |
|||
|
|||
class HTMLPurifier_AttrTransform_SafeEmbed extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* @type string |
|||
*/ |
|||
public $name = "SafeEmbed"; |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
$attr['allowscriptaccess'] = 'never'; |
|||
$attr['allownetworking'] = 'internal'; |
|||
$attr['type'] = 'application/x-shockwave-flash'; |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,28 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Writes default type for all objects. Currently only supports flash. |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_SafeObject extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* @type string |
|||
*/ |
|||
public $name = "SafeObject"; |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (!isset($attr['type'])) { |
|||
$attr['type'] = 'application/x-shockwave-flash'; |
|||
} |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,84 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates name/value pairs in param tags to be used in safe objects. This |
|||
* will only allow name values it recognizes, and pre-fill certain attributes |
|||
* with required values. |
|||
* |
|||
* @note |
|||
* This class only supports Flash. In the future, Quicktime support |
|||
* may be added. |
|||
* |
|||
* @warning |
|||
* This class expects an injector to add the necessary parameters tags. |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_SafeParam extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* @type string |
|||
*/ |
|||
public $name = "SafeParam"; |
|||
|
|||
/** |
|||
* @type HTMLPurifier_AttrDef_URI |
|||
*/ |
|||
private $uri; |
|||
|
|||
/** |
|||
* @type HTMLPurifier_AttrDef_Enum |
|||
*/ |
|||
public $wmode; |
|||
|
|||
public function __construct() |
|||
{ |
|||
$this->uri = new HTMLPurifier_AttrDef_URI(true); // embedded |
|||
$this->wmode = new HTMLPurifier_AttrDef_Enum(array('window', 'opaque', 'transparent')); |
|||
} |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
// If we add support for other objects, we'll need to alter the |
|||
// transforms. |
|||
switch ($attr['name']) { |
|||
// application/x-shockwave-flash |
|||
// Keep this synchronized with Injector/SafeObject.php |
|||
case 'allowScriptAccess': |
|||
$attr['value'] = 'never'; |
|||
break; |
|||
case 'allowNetworking': |
|||
$attr['value'] = 'internal'; |
|||
break; |
|||
case 'allowFullScreen': |
|||
if ($config->get('HTML.FlashAllowFullScreen')) { |
|||
$attr['value'] = ($attr['value'] == 'true') ? 'true' : 'false'; |
|||
} else { |
|||
$attr['value'] = 'false'; |
|||
} |
|||
break; |
|||
case 'wmode': |
|||
$attr['value'] = $this->wmode->validate($attr['value'], $config, $context); |
|||
break; |
|||
case 'movie': |
|||
case 'src': |
|||
$attr['name'] = "movie"; |
|||
$attr['value'] = $this->uri->validate($attr['value'], $config, $context); |
|||
break; |
|||
case 'flashvars': |
|||
// we're going to allow arbitrary inputs to the SWF, on |
|||
// the reasoning that it could only hack the SWF, not us. |
|||
break; |
|||
// add other cases to support other param name/value pairs |
|||
default: |
|||
$attr['name'] = $attr['value'] = null; |
|||
} |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,23 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Implements required attribute stipulation for <script> |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_ScriptRequired extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (!isset($attr['type'])) { |
|||
$attr['type'] = 'text/javascript'; |
|||
} |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
// must be called POST validation |
|||
|
|||
/** |
|||
* Adds target="blank" to all outbound links. This transform is |
|||
* only attached if Attr.TargetBlank is TRUE. This works regardless |
|||
* of whether or not Attr.AllowedFrameTargets |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_TargetBlank extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* @type HTMLPurifier_URIParser |
|||
*/ |
|||
private $parser; |
|||
|
|||
public function __construct() |
|||
{ |
|||
$this->parser = new HTMLPurifier_URIParser(); |
|||
} |
|||
|
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (!isset($attr['href'])) { |
|||
return $attr; |
|||
} |
|||
|
|||
// XXX Kind of inefficient |
|||
$url = $this->parser->parse($attr['href']); |
|||
|
|||
// Ignore invalid schemes (e.g. `javascript:`) |
|||
if (!($scheme = $url->getSchemeObj($config, $context))) { |
|||
return $attr; |
|||
} |
|||
|
|||
if ($scheme->browsable && !$url->isBenign($config, $context)) { |
|||
$attr['target'] = '_blank'; |
|||
} |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,37 @@ |
|||
<?php |
|||
|
|||
// must be called POST validation |
|||
|
|||
/** |
|||
* Adds rel="noopener" to any links which target a different window |
|||
* than the current one. This is used to prevent malicious websites |
|||
* from silently replacing the original window, which could be used |
|||
* to do phishing. |
|||
* This transform is controlled by %HTML.TargetNoopener. |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_TargetNoopener extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (isset($attr['rel'])) { |
|||
$rels = explode(' ', $attr['rel']); |
|||
} else { |
|||
$rels = array(); |
|||
} |
|||
if (isset($attr['target']) && !in_array('noopener', $rels)) { |
|||
$rels[] = 'noopener'; |
|||
} |
|||
if (!empty($rels) || isset($attr['rel'])) { |
|||
$attr['rel'] = implode(' ', $rels); |
|||
} |
|||
|
|||
return $attr; |
|||
} |
|||
} |
|||
|
@ -0,0 +1,37 @@ |
|||
<?php |
|||
|
|||
// must be called POST validation |
|||
|
|||
/** |
|||
* Adds rel="noreferrer" to any links which target a different window |
|||
* than the current one. This is used to prevent malicious websites |
|||
* from silently replacing the original window, which could be used |
|||
* to do phishing. |
|||
* This transform is controlled by %HTML.TargetNoreferrer. |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_TargetNoreferrer extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
if (isset($attr['rel'])) { |
|||
$rels = explode(' ', $attr['rel']); |
|||
} else { |
|||
$rels = array(); |
|||
} |
|||
if (isset($attr['target']) && !in_array('noreferrer', $rels)) { |
|||
$rels[] = 'noreferrer'; |
|||
} |
|||
if (!empty($rels) || isset($attr['rel'])) { |
|||
$attr['rel'] = implode(' ', $rels); |
|||
} |
|||
|
|||
return $attr; |
|||
} |
|||
} |
|||
|
@ -0,0 +1,27 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Sets height/width defaults for <textarea> |
|||
*/ |
|||
class HTMLPurifier_AttrTransform_Textarea extends HTMLPurifier_AttrTransform |
|||
{ |
|||
/** |
|||
* @param array $attr |
|||
* @param HTMLPurifier_Config $config |
|||
* @param HTMLPurifier_Context $context |
|||
* @return array |
|||
*/ |
|||
public function transform($attr, $config, $context) |
|||
{ |
|||
// Calculated from Firefox |
|||
if (!isset($attr['cols'])) { |
|||
$attr['cols'] = '22'; |
|||
} |
|||
if (!isset($attr['rows'])) { |
|||
$attr['rows'] = '3'; |
|||
} |
|||
return $attr; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,97 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Provides lookup array of attribute types to HTMLPurifier_AttrDef objects |
|||
*/ |
|||
class HTMLPurifier_AttrTypes |
|||
{ |
|||
/** |
|||
* Lookup array of attribute string identifiers to concrete implementations. |
|||
* @type HTMLPurifier_AttrDef[] |
|||
*/ |
|||
protected $info = array(); |
|||
|
|||
/** |
|||
* Constructs the info array, supplying default implementations for attribute |
|||
* types. |
|||
*/ |
|||
public function __construct() |
|||
{ |
|||
// XXX This is kind of poor, since we don't actually /clone/ |
|||
// instances; instead, we use the supplied make() attribute. So, |
|||
// the underlying class must know how to deal with arguments. |
|||
// With the old implementation of Enum, that ignored its |
|||
// arguments when handling a make dispatch, the IAlign |
|||
// definition wouldn't work. |
|||
|
|||
// pseudo-types, must be instantiated via shorthand |
|||
$this->info['Enum'] = new HTMLPurifier_AttrDef_Enum(); |
|||
$this->info['Bool'] = new HTMLPurifier_AttrDef_HTML_Bool(); |
|||
|
|||
$this->info['CDATA'] = new HTMLPurifier_AttrDef_Text(); |
|||
$this->info['ID'] = new HTMLPurifier_AttrDef_HTML_ID(); |
|||
$this->info['Length'] = new HTMLPurifier_AttrDef_HTML_Length(); |
|||
$this->info['MultiLength'] = new HTMLPurifier_AttrDef_HTML_MultiLength(); |
|||
$this->info['NMTOKENS'] = new HTMLPurifier_AttrDef_HTML_Nmtokens(); |
|||
$this->info['Pixels'] = new HTMLPurifier_AttrDef_HTML_Pixels(); |
|||
$this->info['Text'] = new HTMLPurifier_AttrDef_Text(); |
|||
$this->info['URI'] = new HTMLPurifier_AttrDef_URI(); |
|||
$this->info['LanguageCode'] = new HTMLPurifier_AttrDef_Lang(); |
|||
$this->info['Color'] = new HTMLPurifier_AttrDef_HTML_Color(); |
|||
$this->info['IAlign'] = self::makeEnum('top,middle,bottom,left,right'); |
|||
$this->info['LAlign'] = self::makeEnum('top,bottom,left,right'); |
|||
$this->info['FrameTarget'] = new HTMLPurifier_AttrDef_HTML_FrameTarget(); |
|||
$this->info['ContentEditable'] = new HTMLPurifier_AttrDef_HTML_ContentEditable(); |
|||
|
|||
// unimplemented aliases |
|||
$this->info['ContentType'] = new HTMLPurifier_AttrDef_Text(); |
|||
$this->info['ContentTypes'] = new HTMLPurifier_AttrDef_Text(); |
|||
$this->info['Charsets'] = new HTMLPurifier_AttrDef_Text(); |
|||
$this->info['Character'] = new HTMLPurifier_AttrDef_Text(); |
|||
|
|||
// "proprietary" types |
|||
$this->info['Class'] = new HTMLPurifier_AttrDef_HTML_Class(); |
|||
|
|||
// number is really a positive integer (one or more digits) |
|||
// FIXME: ^^ not always, see start and value of list items |
|||
$this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true); |
|||
} |
|||
|
|||
private static function makeEnum($in) |
|||
{ |
|||
return new HTMLPurifier_AttrDef_Clone(new HTMLPurifier_AttrDef_Enum(explode(',', $in))); |
|||
} |
|||
|
|||
/** |
|||
* Retrieves a type |
|||
* @param string $type String type name |
|||
* @return HTMLPurifier_AttrDef Object AttrDef for type |
|||
*/ |
|||
public function get($type) |
|||
{ |
|||
// determine if there is any extra info tacked on |
|||
if (strpos($type, '#') !== false) { |
|||
list($type, $string) = explode('#', $type, 2); |
|||
} else { |
|||
$string = ''; |
|||
} |
|||
|
|||
if (!isset($this->info[$type])) { |
|||
trigger_error('Cannot retrieve undefined attribute type ' . $type, E_USER_ERROR); |
|||
return; |
|||
} |
|||
return $this->info[$type]->make($string); |
|||
} |
|||
|
|||
/** |
|||
* Sets a new implementation for a type |
|||
* @param string $type String type name |
|||
* @param HTMLPurifier_AttrDef $impl Object AttrDef for type |
|||
*/ |
|||
public function set($type, $impl) |
|||
{ |
|||
$this->info[$type] = $impl; |
|||
} |
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
@ -0,0 +1,178 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Validates the attributes of a token. Doesn't manage required attributes |
|||
* very well. The only reason we factored this out was because RemoveForeignElements |
|||
* also needed it besides ValidateAttributes. |
|||
*/ |
|||
class HTMLPurifier_AttrValidator |
|||
{ |
|||
|
|||
/** |
|||
* Validates the attributes of a token, mutating it as necessary. |
|||
* that has valid tokens |
|||
* @param HTMLPurifier_Token $token Token to validate. |
|||
* @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config |
|||
* @param HTMLPurifier_Context $context Instance of HTMLPurifier_Context |
|||
*/ |
|||
public function validateToken($token, $config, $context) |
|||
{ |
|||
$definition = $config->getHTMLDefinition(); |
|||
$e =& $context->get('ErrorCollector', true); |
|||
|
|||
// initialize IDAccumulator if necessary |
|||
$ok =& $context->get('IDAccumulator', true); |
|||
if (!$ok) { |
|||
$id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); |
|||
$context->register('IDAccumulator', $id_accumulator); |
|||
} |
|||
|
|||
// initialize CurrentToken if necessary |
|||
$current_token =& $context->get('CurrentToken', true); |
|||
if (!$current_token) { |
|||
$context->register('CurrentToken', $token); |
|||
} |
|||
|
|||
if (!$token instanceof HTMLPurifier_Token_Start && |
|||
!$token instanceof HTMLPurifier_Token_Empty |
|||
) { |
|||
return; |
|||
} |
|||
|
|||
// create alias to global definition array, see also $defs |
|||
// DEFINITION CALL |
|||
$d_defs = $definition->info_global_attr; |
|||
|
|||
// don't update token until the very end, to ensure an atomic update |
|||
$attr = $token->attr; |
|||
|
|||
// do global transformations (pre) |
|||
// nothing currently utilizes this |
|||
foreach ($definition->info_attr_transform_pre as $transform) { |
|||
$attr = $transform->transform($o = $attr, $config, $context); |
|||
if ($e) { |
|||
if ($attr != $o) { |
|||
$e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// do local transformations only applicable to this element (pre) |
|||
// ex. <p align="right"> to <p style="text-align:right;"> |
|||
foreach ($definition->info[$token->name]->attr_transform_pre as $transform) { |
|||
$attr = $transform->transform($o = $attr, $config, $context); |
|||
if ($e) { |
|||
if ($attr != $o) { |
|||
$e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// create alias to this element's attribute definition array, see |
|||
// also $d_defs (global attribute definition array) |
|||
// DEFINITION CALL |
|||
$defs = $definition->info[$token->name]->attr; |
|||
|
|||
$attr_key = false; |
|||
$context->register('CurrentAttr', $attr_key); |
|||
|
|||
// iterate through all the attribute keypairs |
|||
// Watch out for name collisions: $key has previously been used |
|||
foreach ($attr as $attr_key => $value) { |
|||
|
|||
// call the definition |
|||
if (isset($defs[$attr_key])) { |
|||
// there is a local definition defined |
|||
if ($defs[$attr_key] === false) { |
|||
// We've explicitly been told not to allow this element. |
|||
// This is usually when there's a global definition |
|||
// that must be overridden. |
|||
// Theoretically speaking, we could have a |
|||
// AttrDef_DenyAll, but this is faster! |
|||
$result = false; |
|||
} else { |
|||
// validate according to the element's definition |
|||
$result = $defs[$attr_key]->validate( |
|||
$value, |
|||
$config, |
|||
$context |
|||
); |
|||
} |
|||
} elseif (isset($d_defs[$attr_key])) { |
|||
// there is a global definition defined, validate according |
|||
// to the global definition |
|||
$result = $d_defs[$attr_key]->validate( |
|||
$value, |
|||
$config, |
|||
$context |
|||
); |
|||
} else { |
|||
// system never heard of the attribute? DELETE! |
|||
$result = false; |
|||
} |
|||
|
|||
// put the results into effect |
|||
if ($result === false || $result === null) { |
|||
// this is a generic error message that should replaced |
|||
// with more specific ones when possible |
|||
if ($e) { |
|||
$e->send(E_ERROR, 'AttrValidator: Attribute removed'); |
|||
} |
|||
|
|||
// remove the attribute |
|||
unset($attr[$attr_key]); |
|||
} elseif (is_string($result)) { |
|||
// generally, if a substitution is happening, there |
|||
// was some sort of implicit correction going on. We'll |
|||
// delegate it to the attribute classes to say exactly what. |
|||
|
|||
// simple substitution |
|||
$attr[$attr_key] = $result; |
|||
} else { |
|||
// nothing happens |
|||
} |
|||
|
|||
// we'd also want slightly more complicated substitution |
|||
// involving an array as the return value, |
|||
// although we're not sure how colliding attributes would |
|||
// resolve (certain ones would be completely overriden, |
|||
// others would prepend themselves). |
|||
} |
|||
|
|||
$context->destroy('CurrentAttr'); |
|||
|
|||
// post transforms |
|||
|
|||
// global (error reporting untested) |
|||
foreach ($definition->info_attr_transform_post as $transform) { |
|||
$attr = $transform->transform($o = $attr, $config, $context); |
|||
if ($e) { |
|||
if ($attr != $o) { |
|||
$e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// local (error reporting untested) |
|||
foreach ($definition->info[$token->name]->attr_transform_post as $transform) { |
|||
$attr = $transform->transform($o = $attr, $config, $context); |
|||
if ($e) { |
|||
if ($attr != $o) { |
|||
$e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); |
|||
} |
|||
} |
|||
} |
|||
|
|||
$token->attr = $attr; |
|||
|
|||
// destroy CurrentToken if we made it ourselves |
|||
if (!$current_token) { |
|||
$context->destroy('CurrentToken'); |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
} |
|||
|
|||
// vim: et sw=4 sts=4 |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue