/** * Retrieves an instance of global definition cache factory. */ public static function instance($prototype = null) { static $instance; if ($prototype !== null) { $instance = $prototype; } elseif ($instance === null || $prototype === true) { $instance = new HTMLPurifier_DefinitionCacheFactory(); $instance->setup(); } return $instance; }
/** * Retrieves a definition * @param $type Type of definition: HTML, CSS, etc * @param $raw Whether or not definition should be returned raw */ public function getDefinition($type, $raw = false) { if (!$this->finalized) { $this->autoFinalize(); } // temporarily suspend locks, so we can handle recursive definition calls $lock = $this->lock; $this->lock = null; $factory = HTMLPurifier_DefinitionCacheFactory::instance(); $cache = $factory->create($type, $this); $this->lock = $lock; if (!$raw) { // see if we can quickly supply a definition if (!empty($this->definitions[$type])) { if (!$this->definitions[$type]->setup) { $this->definitions[$type]->setup($this); $cache->set($this->definitions[$type], $this); } return $this->definitions[$type]; } // memory check missed, try cache $this->definitions[$type] = $cache->get($this); if ($this->definitions[$type]) { // definition in cache, return it return $this->definitions[$type]; } } elseif (!empty($this->definitions[$type]) && !$this->definitions[$type]->setup) { // raw requested, raw in memory, quick return return $this->definitions[$type]; } // quick checks failed, let's create the object if ($type == 'HTML') { $this->definitions[$type] = new HTMLPurifier_HTMLDefinition(); } elseif ($type == 'CSS') { $this->definitions[$type] = new HTMLPurifier_CSSDefinition(); } elseif ($type == 'URI') { $this->definitions[$type] = new HTMLPurifier_URIDefinition(); } else { throw new HTMLPurifier_Exception("Definition of {$type} type not supported"); } // quick abort if raw if ($raw) { if (is_null($this->get($type . '.DefinitionID'))) { // fatally error out if definition ID not set throw new HTMLPurifier_Exception("Cannot retrieve raw version without specifying %{$type}.DefinitionID"); } return $this->definitions[$type]; } // set it up $this->lock = $type; $this->definitions[$type]->setup($this); $this->lock = null; // save in cache $cache->set($this->definitions[$type], $this); return $this->definitions[$type]; }
/** * Retrieves a definition * @param $type Type of definition: HTML, CSS, etc * @param $raw Whether or not definition should be returned raw * @param $optimized Only has an effect when $raw is true. Whether * or not to return null if the result is already present in * the cache. This is off by default for backwards * compatibility reasons, but you need to do things this * way in order to ensure that caching is done properly. * Check out enduser-customize.html for more details. * We probably won't ever change this default, as much as the * maybe semantics is the "right thing to do." */ public function getDefinition($type, $raw = false, $optimized = false) { if ($optimized && !$raw) { throw new HTMLPurifier_Exception("Cannot set optimized = true when raw = false"); } if (!$this->finalized) { $this->autoFinalize(); } // temporarily suspend locks, so we can handle recursive definition calls $lock = $this->lock; $this->lock = null; $factory = HTMLPurifier_DefinitionCacheFactory::instance(); $cache = $factory->create($type, $this); $this->lock = $lock; if (!$raw) { // full definition // --------------- // check if definition is in memory if (!empty($this->definitions[$type])) { $def = $this->definitions[$type]; // check if the definition is setup if ($def->setup) { return $def; } else { $def->setup($this); if ($def->optimized) { $cache->add($def, $this); } return $def; } } // check if definition is in cache $def = $cache->get($this); if ($def) { // definition in cache, save to memory and return it $this->definitions[$type] = $def; return $def; } // initialize it $def = $this->initDefinition($type); // set it up $this->lock = $type; $def->setup($this); $this->lock = null; // save in cache $cache->add($def, $this); // return it return $def; } else { // raw definition // -------------- // check preconditions $def = null; if ($optimized) { if (is_null($this->get($type . '.DefinitionID'))) { // fatally error out if definition ID not set throw new HTMLPurifier_Exception("Cannot retrieve raw version without specifying %{$type}.DefinitionID"); } } if (!empty($this->definitions[$type])) { $def = $this->definitions[$type]; if ($def->setup && !$optimized) { $extra = $this->chatty ? " (try moving this code block earlier in your initialization)" : ""; throw new HTMLPurifier_Exception("Cannot retrieve raw definition after it has already been setup" . $extra); } if ($def->optimized === null) { $extra = $this->chatty ? " (try flushing your cache)" : ""; throw new HTMLPurifier_Exception("Optimization status of definition is unknown" . $extra); } if ($def->optimized !== $optimized) { $msg = $optimized ? "optimized" : "unoptimized"; $extra = $this->chatty ? " (this backtrace is for the first inconsistent call, which was for a {$msg} raw definition)" : ""; throw new HTMLPurifier_Exception("Inconsistent use of optimized and unoptimized raw definition retrievals" . $extra); } } // check if definition was in memory if ($def) { if ($def->setup) { // invariant: $optimized === true (checked above) return null; } else { return $def; } } // if optimized, check if definition was in cache // (because we do the memory check first, this formulation // is prone to cache slamming, but I think // guaranteeing that either /all/ of the raw // setup code or /none/ of it is run is more important.) if ($optimized) { // This code path only gets run once; once we put // something in $definitions (which is guaranteed by the // trailing code), we always short-circuit above. $def = $cache->get($this); if ($def) { // save the full definition for later, but don't // return it yet $this->definitions[$type] = $def; return null; } } // check invariants for creation if (!$optimized) { if (!is_null($this->get($type . '.DefinitionID'))) { if ($this->chatty) { $this->triggerError("Due to a documentation error in previous version of HTML Purifier, your definitions are not being cached. If this is OK, you can remove the %{$type}.DefinitionRev and %{$type}.DefinitionID declaration. Otherwise, modify your code to use maybeGetRawDefinition, and test if the returned value is null before making any edits (if it is null, that means that a cached version is available, and no raw operations are necessary). See <a href='http://htmlpurifier.org/docs/enduser-customize.html#optimized'>Customize</a> for more details", E_USER_WARNING); } else { $this->triggerError("Useless DefinitionID declaration", E_USER_WARNING); } } } // initialize it $def = $this->initDefinition($type); $def->optimized = $optimized; return $def; } throw new HTMLPurifier_Exception("The impossible happened!"); }
protected function teardownCacheMock() { HTMLPurifier_DefinitionCacheFactory::instance($this->oldFactory); }
public function tearDown() { HTMLPurifier_DefinitionCacheFactory::instance($this->oldFactory); }
} $reporter = new XmlReporter(); } elseif (SimpleReporter::inCli() || $AC['txt']) { if (!SimpleReporter::inCli()) { header('Content-Type: text/plain;charset=UTF-8'); } $reporter = new HTMLPurifier_SimpleTest_TextReporter($AC); } else { $reporter = new HTMLPurifier_SimpleTest_Reporter('UTF-8', $AC); } if ($AC['flush']) { htmlpurifier_flush($AC['php'], $reporter); } // Now, userland code begins to be executed // setup special DefinitionCacheFactory decorator $factory = HTMLPurifier_DefinitionCacheFactory::instance(); $factory->addDecorator('Memory'); // since we deal with a lot of config objects if (!$AC['disable-phpt']) { $phpt = PHPT_Registry::getInstance(); $phpt->php = $AC['php']; } // load tests require 'test_files.php'; $FS = new FSTools(); // handle test dirs foreach ($test_dirs as $dir) { $raw_files = $FS->globr($dir, '*Test.php'); foreach ($raw_files as $file) { $file = str_replace('\\', '/', $file); if (isset($test_dirs_exclude[$file])) {
/** * Retrieves a definition * @param $type Type of definition: HTML, CSS, etc * @param $raw Whether or not definition should be returned raw */ function &getDefinition($type, $raw = false) { if (!$this->finalized && $this->autoFinalize) { $this->finalize(); } $factory = HTMLPurifier_DefinitionCacheFactory::instance(); $cache = $factory->create($type, $this); if (!$raw) { // see if we can quickly supply a definition if (!empty($this->definitions[$type])) { if (!$this->definitions[$type]->setup) { $this->definitions[$type]->setup($this); $cache->set($this->definitions[$type], $this); } return $this->definitions[$type]; } // memory check missed, try cache $this->definitions[$type] = $cache->get($this); if ($this->definitions[$type]) { // definition in cache, return it return $this->definitions[$type]; } } elseif (!empty($this->definitions[$type]) && !$this->definitions[$type]->setup) { // raw requested, raw in memory, quick return return $this->definitions[$type]; } // quick checks failed, let's create the object if ($type == 'HTML') { $this->definitions[$type] = new HTMLPurifier_HTMLDefinition(); } elseif ($type == 'CSS') { $this->definitions[$type] = new HTMLPurifier_CSSDefinition(); } elseif ($type == 'URI') { $this->definitions[$type] = new HTMLPurifier_URIDefinition(); } else { trigger_error("Definition of {$type} type not supported"); $false = false; return $false; } // quick abort if raw if ($raw) { if (is_null($this->get($type, 'DefinitionID'))) { // fatally error out if definition ID not set trigger_error("Cannot retrieve raw version without specifying %{$type}.DefinitionID", E_USER_ERROR); $false = new HTMLPurifier_Error(); return $false; } return $this->definitions[$type]; } // set it up $this->definitions[$type]->setup($this); // save in cache $cache->set($this->definitions[$type], $this); return $this->definitions[$type]; }
function testURIDefinitionValidation() { $parser = new HTMLPurifier_URIParser(); $uri = $parser->parse('http://example.com'); $this->config->set('URI.DefinitionID', 'HTMLPurifier_AttrDef_URITest->testURIDefinitionValidation'); generate_mock_once('HTMLPurifier_URIDefinition'); $uri_def = new HTMLPurifier_URIDefinitionMock(); $uri_def->expectOnce('filter', array($uri, '*', '*')); $uri_def->setReturnValue('filter', true, array($uri, '*', '*')); $uri_def->expectOnce('postFilter', array($uri, '*', '*')); $uri_def->setReturnValue('postFilter', true, array($uri, '*', '*')); $uri_def->setup = true; // Since definitions are no longer passed by reference, we need // to muck around with the cache to insert our mock. This is // technically a little bad, since the cache shouldn't change // behavior, but I don't feel too good about letting users // overload entire definitions. generate_mock_once('HTMLPurifier_DefinitionCache'); $cache_mock = new HTMLPurifier_DefinitionCacheMock(); $cache_mock->setReturnValue('get', $uri_def); generate_mock_once('HTMLPurifier_DefinitionCacheFactory'); $factory_mock = new HTMLPurifier_DefinitionCacheFactoryMock(); $old = HTMLPurifier_DefinitionCacheFactory::instance(); HTMLPurifier_DefinitionCacheFactory::instance($factory_mock); $factory_mock->setReturnValue('create', $cache_mock); $this->assertDef('http://example.com'); HTMLPurifier_DefinitionCacheFactory::instance($old); }