diff options
Diffstat (limited to 'library/HTMLPurifier/DefinitionCache')
7 files changed, 412 insertions, 0 deletions
diff --git a/library/HTMLPurifier/DefinitionCache/Decorator.php b/library/HTMLPurifier/DefinitionCache/Decorator.php new file mode 100644 index 000000000..b0fb6d0cd --- /dev/null +++ b/library/HTMLPurifier/DefinitionCache/Decorator.php @@ -0,0 +1,62 @@ +<?php + +class HTMLPurifier_DefinitionCache_Decorator extends HTMLPurifier_DefinitionCache +{ + + /** + * Cache object we are decorating + */ + public $cache; + + public function __construct() {} + + /** + * Lazy decorator function + * @param $cache Reference to cache object to decorate + */ + public function decorate(&$cache) { + $decorator = $this->copy(); + // reference is necessary for mocks in PHP 4 + $decorator->cache =& $cache; + $decorator->type = $cache->type; + return $decorator; + } + + /** + * Cross-compatible clone substitute + */ + public function copy() { + return new HTMLPurifier_DefinitionCache_Decorator(); + } + + public function add($def, $config) { + return $this->cache->add($def, $config); + } + + public function set($def, $config) { + return $this->cache->set($def, $config); + } + + public function replace($def, $config) { + return $this->cache->replace($def, $config); + } + + public function get($config) { + return $this->cache->get($config); + } + + public function remove($config) { + return $this->cache->remove($config); + } + + public function flush($config) { + return $this->cache->flush($config); + } + + public function cleanup($config) { + return $this->cache->cleanup($config); + } + +} + +// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php b/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php new file mode 100644 index 000000000..d4cc35c4b --- /dev/null +++ b/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php @@ -0,0 +1,43 @@ +<?php + +/** + * Definition cache decorator class that cleans up the cache + * whenever there is a cache miss. + */ +class HTMLPurifier_DefinitionCache_Decorator_Cleanup extends + HTMLPurifier_DefinitionCache_Decorator +{ + + public $name = 'Cleanup'; + + public function copy() { + return new HTMLPurifier_DefinitionCache_Decorator_Cleanup(); + } + + public function add($def, $config) { + $status = parent::add($def, $config); + if (!$status) parent::cleanup($config); + return $status; + } + + public function set($def, $config) { + $status = parent::set($def, $config); + if (!$status) parent::cleanup($config); + return $status; + } + + public function replace($def, $config) { + $status = parent::replace($def, $config); + if (!$status) parent::cleanup($config); + return $status; + } + + public function get($config) { + $ret = parent::get($config); + if (!$ret) parent::cleanup($config); + return $ret; + } + +} + +// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php b/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php new file mode 100644 index 000000000..18f16d32b --- /dev/null +++ b/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php @@ -0,0 +1,46 @@ +<?php + +/** + * Definition cache decorator class that saves all cache retrievals + * to PHP's memory; good for unit tests or circumstances where + * there are lots of configuration objects floating around. + */ +class HTMLPurifier_DefinitionCache_Decorator_Memory extends + HTMLPurifier_DefinitionCache_Decorator +{ + + protected $definitions; + public $name = 'Memory'; + + public function copy() { + return new HTMLPurifier_DefinitionCache_Decorator_Memory(); + } + + public function add($def, $config) { + $status = parent::add($def, $config); + if ($status) $this->definitions[$this->generateKey($config)] = $def; + return $status; + } + + public function set($def, $config) { + $status = parent::set($def, $config); + if ($status) $this->definitions[$this->generateKey($config)] = $def; + return $status; + } + + public function replace($def, $config) { + $status = parent::replace($def, $config); + if ($status) $this->definitions[$this->generateKey($config)] = $def; + return $status; + } + + public function get($config) { + $key = $this->generateKey($config); + if (isset($this->definitions[$key])) return $this->definitions[$key]; + $this->definitions[$key] = parent::get($config); + return $this->definitions[$key]; + } + +} + +// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in b/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in new file mode 100644 index 000000000..21a8fcfda --- /dev/null +++ b/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in @@ -0,0 +1,47 @@ +<?php + +require_once 'HTMLPurifier/DefinitionCache/Decorator.php'; + +/** + * Definition cache decorator template. + */ +class HTMLPurifier_DefinitionCache_Decorator_Template extends + HTMLPurifier_DefinitionCache_Decorator +{ + + var $name = 'Template'; // replace this + + function copy() { + // replace class name with yours + return new HTMLPurifier_DefinitionCache_Decorator_Template(); + } + + // remove methods you don't need + + function add($def, $config) { + return parent::add($def, $config); + } + + function set($def, $config) { + return parent::set($def, $config); + } + + function replace($def, $config) { + return parent::replace($def, $config); + } + + function get($config) { + return parent::get($config); + } + + function flush() { + return parent::flush(); + } + + function cleanup($config) { + return parent::cleanup($config); + } + +} + +// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/DefinitionCache/Null.php b/library/HTMLPurifier/DefinitionCache/Null.php new file mode 100644 index 000000000..41d97e734 --- /dev/null +++ b/library/HTMLPurifier/DefinitionCache/Null.php @@ -0,0 +1,39 @@ +<?php + +/** + * Null cache object to use when no caching is on. + */ +class HTMLPurifier_DefinitionCache_Null extends HTMLPurifier_DefinitionCache +{ + + public function add($def, $config) { + return false; + } + + public function set($def, $config) { + return false; + } + + public function replace($def, $config) { + return false; + } + + public function remove($config) { + return false; + } + + public function get($config) { + return false; + } + + public function flush($config) { + return false; + } + + public function cleanup($config) { + return false; + } + +} + +// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/DefinitionCache/Serializer.php b/library/HTMLPurifier/DefinitionCache/Serializer.php new file mode 100644 index 000000000..7a6aa93f0 --- /dev/null +++ b/library/HTMLPurifier/DefinitionCache/Serializer.php @@ -0,0 +1,172 @@ +<?php + +class HTMLPurifier_DefinitionCache_Serializer extends + HTMLPurifier_DefinitionCache +{ + + public function add($def, $config) { + if (!$this->checkDefType($def)) return; + $file = $this->generateFilePath($config); + if (file_exists($file)) return false; + if (!$this->_prepareDir($config)) return false; + return $this->_write($file, serialize($def)); + } + + public function set($def, $config) { + if (!$this->checkDefType($def)) return; + $file = $this->generateFilePath($config); + if (!$this->_prepareDir($config)) return false; + return $this->_write($file, serialize($def)); + } + + public function replace($def, $config) { + if (!$this->checkDefType($def)) return; + $file = $this->generateFilePath($config); + if (!file_exists($file)) return false; + if (!$this->_prepareDir($config)) return false; + return $this->_write($file, serialize($def)); + } + + public function get($config) { + $file = $this->generateFilePath($config); + if (!file_exists($file)) return false; + return unserialize(file_get_contents($file)); + } + + public function remove($config) { + $file = $this->generateFilePath($config); + if (!file_exists($file)) return false; + return unlink($file); + } + + public function flush($config) { + if (!$this->_prepareDir($config)) return false; + $dir = $this->generateDirectoryPath($config); + $dh = opendir($dir); + while (false !== ($filename = readdir($dh))) { + if (empty($filename)) continue; + if ($filename[0] === '.') continue; + unlink($dir . '/' . $filename); + } + } + + public function cleanup($config) { + if (!$this->_prepareDir($config)) return false; + $dir = $this->generateDirectoryPath($config); + $dh = opendir($dir); + while (false !== ($filename = readdir($dh))) { + if (empty($filename)) continue; + if ($filename[0] === '.') continue; + $key = substr($filename, 0, strlen($filename) - 4); + if ($this->isOld($key, $config)) unlink($dir . '/' . $filename); + } + } + + /** + * Generates the file path to the serial file corresponding to + * the configuration and definition name + * @todo Make protected + */ + public function generateFilePath($config) { + $key = $this->generateKey($config); + return $this->generateDirectoryPath($config) . '/' . $key . '.ser'; + } + + /** + * Generates the path to the directory contain this cache's serial files + * @note No trailing slash + * @todo Make protected + */ + public function generateDirectoryPath($config) { + $base = $this->generateBaseDirectoryPath($config); + return $base . '/' . $this->type; + } + + /** + * Generates path to base directory that contains all definition type + * serials + * @todo Make protected + */ + public function generateBaseDirectoryPath($config) { + $base = $config->get('Cache.SerializerPath'); + $base = is_null($base) ? HTMLPURIFIER_PREFIX . '/HTMLPurifier/DefinitionCache/Serializer' : $base; + return $base; + } + + /** + * Convenience wrapper function for file_put_contents + * @param $file File name to write to + * @param $data Data to write into file + * @return Number of bytes written if success, or false if failure. + */ + private function _write($file, $data) { + return file_put_contents($file, $data); + } + + /** + * Prepares the directory that this type stores the serials in + * @return True if successful + */ + private function _prepareDir($config) { + $directory = $this->generateDirectoryPath($config); + if (!is_dir($directory)) { + $base = $this->generateBaseDirectoryPath($config); + if (!is_dir($base)) { + trigger_error('Base directory '.$base.' does not exist, + please create or change using %Cache.SerializerPath', + E_USER_WARNING); + return false; + } elseif (!$this->_testPermissions($base)) { + return false; + } + $old = umask(0022); // disable group and world writes + mkdir($directory); + umask($old); + } elseif (!$this->_testPermissions($directory)) { + return false; + } + return true; + } + + /** + * Tests permissions on a directory and throws out friendly + * error messages and attempts to chmod it itself if possible + */ + private function _testPermissions($dir) { + // early abort, if it is writable, everything is hunky-dory + if (is_writable($dir)) return true; + if (!is_dir($dir)) { + // generally, you'll want to handle this beforehand + // so a more specific error message can be given + trigger_error('Directory '.$dir.' does not exist', + E_USER_WARNING); + return false; + } + if (function_exists('posix_getuid')) { + // POSIX system, we can give more specific advice + if (fileowner($dir) === posix_getuid()) { + // we can chmod it ourselves + chmod($dir, 0755); + return true; + } elseif (filegroup($dir) === posix_getgid()) { + $chmod = '775'; + } else { + // PHP's probably running as nobody, so we'll + // need to give global permissions + $chmod = '777'; + } + trigger_error('Directory '.$dir.' not writable, '. + 'please chmod to ' . $chmod, + E_USER_WARNING); + } else { + // generic error message + trigger_error('Directory '.$dir.' not writable, '. + 'please alter file permissions', + E_USER_WARNING); + } + return false; + } + +} + +// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/DefinitionCache/Serializer/README b/library/HTMLPurifier/DefinitionCache/Serializer/README new file mode 100755 index 000000000..2e35c1c3d --- /dev/null +++ b/library/HTMLPurifier/DefinitionCache/Serializer/README @@ -0,0 +1,3 @@ +This is a dummy file to prevent Git from ignoring this empty directory. + + vim: et sw=4 sts=4 |