vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php line 473

Open in your IDE?
  1. <?php
  2. /**
  3.  * Configuration object that triggers customizable behavior.
  4.  *
  5.  * @warning This class is strongly defined: that means that the class
  6.  *          will fail if an undefined directive is retrieved or set.
  7.  *
  8.  * @note Many classes that could (although many times don't) use the
  9.  *       configuration object make it a mandatory parameter.  This is
  10.  *       because a configuration object should always be forwarded,
  11.  *       otherwise, you run the risk of missing a parameter and then
  12.  *       being stumped when a configuration directive doesn't work.
  13.  *
  14.  * @todo Reconsider some of the public member variables
  15.  */
  16. class HTMLPurifier_Config
  17. {
  18.     /**
  19.      * HTML Purifier's version
  20.      * @type string
  21.      */
  22.     public $version '4.13.0';
  23.     /**
  24.      * Whether or not to automatically finalize
  25.      * the object if a read operation is done.
  26.      * @type bool
  27.      */
  28.     public $autoFinalize true;
  29.     // protected member variables
  30.     /**
  31.      * Namespace indexed array of serials for specific namespaces.
  32.      * @see getSerial() for more info.
  33.      * @type string[]
  34.      */
  35.     protected $serials = array();
  36.     /**
  37.      * Serial for entire configuration object.
  38.      * @type string
  39.      */
  40.     protected $serial;
  41.     /**
  42.      * Parser for variables.
  43.      * @type HTMLPurifier_VarParser_Flexible
  44.      */
  45.     protected $parser null;
  46.     /**
  47.      * Reference HTMLPurifier_ConfigSchema for value checking.
  48.      * @type HTMLPurifier_ConfigSchema
  49.      * @note This is public for introspective purposes. Please don't
  50.      *       abuse!
  51.      */
  52.     public $def;
  53.     /**
  54.      * Indexed array of definitions.
  55.      * @type HTMLPurifier_Definition[]
  56.      */
  57.     protected $definitions;
  58.     /**
  59.      * Whether or not config is finalized.
  60.      * @type bool
  61.      */
  62.     protected $finalized false;
  63.     /**
  64.      * Property list containing configuration directives.
  65.      * @type array
  66.      */
  67.     protected $plist;
  68.     /**
  69.      * Whether or not a set is taking place due to an alias lookup.
  70.      * @type bool
  71.      */
  72.     private $aliasMode;
  73.     /**
  74.      * Set to false if you do not want line and file numbers in errors.
  75.      * (useful when unit testing).  This will also compress some errors
  76.      * and exceptions.
  77.      * @type bool
  78.      */
  79.     public $chatty true;
  80.     /**
  81.      * Current lock; only gets to this namespace are allowed.
  82.      * @type string
  83.      */
  84.     private $lock;
  85.     /**
  86.      * Constructor
  87.      * @param HTMLPurifier_ConfigSchema $definition ConfigSchema that defines
  88.      * what directives are allowed.
  89.      * @param HTMLPurifier_PropertyList $parent
  90.      */
  91.     public function __construct($definition$parent null)
  92.     {
  93.         $parent $parent $parent $definition->defaultPlist;
  94.         $this->plist = new HTMLPurifier_PropertyList($parent);
  95.         $this->def $definition// keep a copy around for checking
  96.         $this->parser = new HTMLPurifier_VarParser_Flexible();
  97.     }
  98.     /**
  99.      * Convenience constructor that creates a config object based on a mixed var
  100.      * @param mixed $config Variable that defines the state of the config
  101.      *                      object. Can be: a HTMLPurifier_Config() object,
  102.      *                      an array of directives based on loadArray(),
  103.      *                      or a string filename of an ini file.
  104.      * @param HTMLPurifier_ConfigSchema $schema Schema object
  105.      * @return HTMLPurifier_Config Configured object
  106.      */
  107.     public static function create($config$schema null)
  108.     {
  109.         if ($config instanceof HTMLPurifier_Config) {
  110.             // pass-through
  111.             return $config;
  112.         }
  113.         if (!$schema) {
  114.             $ret HTMLPurifier_Config::createDefault();
  115.         } else {
  116.             $ret = new HTMLPurifier_Config($schema);
  117.         }
  118.         if (is_string($config)) {
  119.             $ret->loadIni($config);
  120.         } elseif (is_array($config)) $ret->loadArray($config);
  121.         return $ret;
  122.     }
  123.     /**
  124.      * Creates a new config object that inherits from a previous one.
  125.      * @param HTMLPurifier_Config $config Configuration object to inherit from.
  126.      * @return HTMLPurifier_Config object with $config as its parent.
  127.      */
  128.     public static function inherit(HTMLPurifier_Config $config)
  129.     {
  130.         return new HTMLPurifier_Config($config->def$config->plist);
  131.     }
  132.     /**
  133.      * Convenience constructor that creates a default configuration object.
  134.      * @return HTMLPurifier_Config default object.
  135.      */
  136.     public static function createDefault()
  137.     {
  138.         $definition HTMLPurifier_ConfigSchema::instance();
  139.         $config = new HTMLPurifier_Config($definition);
  140.         return $config;
  141.     }
  142.     /**
  143.      * Retrieves a value from the configuration.
  144.      *
  145.      * @param string $key String key
  146.      * @param mixed $a
  147.      *
  148.      * @return mixed
  149.      */
  150.     public function get($key$a null)
  151.     {
  152.         if ($a !== null) {
  153.             $this->triggerError(
  154.                 "Using deprecated API: use \$config->get('$key.$a') instead",
  155.                 E_USER_WARNING
  156.             );
  157.             $key "$key.$a";
  158.         }
  159.         if (!$this->finalized) {
  160.             $this->autoFinalize();
  161.         }
  162.         if (!isset($this->def->info[$key])) {
  163.             // can't add % due to SimpleTest bug
  164.             $this->triggerError(
  165.                 'Cannot retrieve value of undefined directive ' htmlspecialchars($key),
  166.                 E_USER_WARNING
  167.             );
  168.             return;
  169.         }
  170.         if (isset($this->def->info[$key]->isAlias)) {
  171.             $d $this->def->info[$key];
  172.             $this->triggerError(
  173.                 'Cannot get value from aliased directive, use real name ' $d->key,
  174.                 E_USER_ERROR
  175.             );
  176.             return;
  177.         }
  178.         if ($this->lock) {
  179.             list($ns) = explode('.'$key);
  180.             if ($ns !== $this->lock) {
  181.                 $this->triggerError(
  182.                     'Cannot get value of namespace ' $ns ' when lock for ' .
  183.                     $this->lock .
  184.                     ' is active, this probably indicates a Definition setup method ' .
  185.                     'is accessing directives that are not within its namespace',
  186.                     E_USER_ERROR
  187.                 );
  188.                 return;
  189.             }
  190.         }
  191.         return $this->plist->get($key);
  192.     }
  193.     /**
  194.      * Retrieves an array of directives to values from a given namespace
  195.      *
  196.      * @param string $namespace String namespace
  197.      *
  198.      * @return array
  199.      */
  200.     public function getBatch($namespace)
  201.     {
  202.         if (!$this->finalized) {
  203.             $this->autoFinalize();
  204.         }
  205.         $full $this->getAll();
  206.         if (!isset($full[$namespace])) {
  207.             $this->triggerError(
  208.                 'Cannot retrieve undefined namespace ' .
  209.                 htmlspecialchars($namespace),
  210.                 E_USER_WARNING
  211.             );
  212.             return;
  213.         }
  214.         return $full[$namespace];
  215.     }
  216.     /**
  217.      * Returns a SHA-1 signature of a segment of the configuration object
  218.      * that uniquely identifies that particular configuration
  219.      *
  220.      * @param string $namespace Namespace to get serial for
  221.      *
  222.      * @return string
  223.      * @note Revision is handled specially and is removed from the batch
  224.      *       before processing!
  225.      */
  226.     public function getBatchSerial($namespace)
  227.     {
  228.         if (empty($this->serials[$namespace])) {
  229.             $batch $this->getBatch($namespace);
  230.             unset($batch['DefinitionRev']);
  231.             $this->serials[$namespace] = sha1(serialize($batch));
  232.         }
  233.         return $this->serials[$namespace];
  234.     }
  235.     /**
  236.      * Returns a SHA-1 signature for the entire configuration object
  237.      * that uniquely identifies that particular configuration
  238.      *
  239.      * @return string
  240.      */
  241.     public function getSerial()
  242.     {
  243.         if (empty($this->serial)) {
  244.             $this->serial sha1(serialize($this->getAll()));
  245.         }
  246.         return $this->serial;
  247.     }
  248.     /**
  249.      * Retrieves all directives, organized by namespace
  250.      *
  251.      * @warning This is a pretty inefficient function, avoid if you can
  252.      */
  253.     public function getAll()
  254.     {
  255.         if (!$this->finalized) {
  256.             $this->autoFinalize();
  257.         }
  258.         $ret = array();
  259.         foreach ($this->plist->squash() as $name => $value) {
  260.             list($ns$key) = explode('.'$name2);
  261.             $ret[$ns][$key] = $value;
  262.         }
  263.         return $ret;
  264.     }
  265.     /**
  266.      * Sets a value to configuration.
  267.      *
  268.      * @param string $key key
  269.      * @param mixed $value value
  270.      * @param mixed $a
  271.      */
  272.     public function set($key$value$a null)
  273.     {
  274.         if (strpos($key'.') === false) {
  275.             $namespace $key;
  276.             $directive $value;
  277.             $value $a;
  278.             $key "$key.$directive";
  279.             $this->triggerError("Using deprecated API: use \$config->set('$key', ...) instead"E_USER_NOTICE);
  280.         } else {
  281.             list($namespace) = explode('.'$key);
  282.         }
  283.         if ($this->isFinalized('Cannot set directive after finalization')) {
  284.             return;
  285.         }
  286.         if (!isset($this->def->info[$key])) {
  287.             $this->triggerError(
  288.                 'Cannot set undefined directive ' htmlspecialchars($key) . ' to value',
  289.                 E_USER_WARNING
  290.             );
  291.             return;
  292.         }
  293.         $def $this->def->info[$key];
  294.         if (isset($def->isAlias)) {
  295.             if ($this->aliasMode) {
  296.                 $this->triggerError(
  297.                     'Double-aliases not allowed, please fix '.
  298.                     'ConfigSchema bug with' $key,
  299.                     E_USER_ERROR
  300.                 );
  301.                 return;
  302.             }
  303.             $this->aliasMode true;
  304.             $this->set($def->key$value);
  305.             $this->aliasMode false;
  306.             $this->triggerError("$key is an alias, preferred directive name is {$def->key}"E_USER_NOTICE);
  307.             return;
  308.         }
  309.         // Raw type might be negative when using the fully optimized form
  310.         // of stdClass, which indicates allow_null == true
  311.         $rtype is_int($def) ? $def $def->type;
  312.         if ($rtype 0) {
  313.             $type = -$rtype;
  314.             $allow_null true;
  315.         } else {
  316.             $type $rtype;
  317.             $allow_null = isset($def->allow_null);
  318.         }
  319.         try {
  320.             $value $this->parser->parse($value$type$allow_null);
  321.         } catch (HTMLPurifier_VarParserException $e) {
  322.             $this->triggerError(
  323.                 'Value for ' $key ' is of invalid type, should be ' .
  324.                 HTMLPurifier_VarParser::getTypeName($type),
  325.                 E_USER_WARNING
  326.             );
  327.             return;
  328.         }
  329.         if (is_string($value) && is_object($def)) {
  330.             // resolve value alias if defined
  331.             if (isset($def->aliases[$value])) {
  332.                 $value $def->aliases[$value];
  333.             }
  334.             // check to see if the value is allowed
  335.             if (isset($def->allowed) && !isset($def->allowed[$value])) {
  336.                 $this->triggerError(
  337.                     'Value not supported, valid values are: ' .
  338.                     $this->_listify($def->allowed),
  339.                     E_USER_WARNING
  340.                 );
  341.                 return;
  342.             }
  343.         }
  344.         $this->plist->set($key$value);
  345.         // reset definitions if the directives they depend on changed
  346.         // this is a very costly process, so it's discouraged
  347.         // with finalization
  348.         if ($namespace == 'HTML' || $namespace == 'CSS' || $namespace == 'URI') {
  349.             $this->definitions[$namespace] = null;
  350.         }
  351.         $this->serials[$namespace] = false;
  352.     }
  353.     /**
  354.      * Convenience function for error reporting
  355.      *
  356.      * @param array $lookup
  357.      *
  358.      * @return string
  359.      */
  360.     private function _listify($lookup)
  361.     {
  362.         $list = array();
  363.         foreach ($lookup as $name => $b) {
  364.             $list[] = $name;
  365.         }
  366.         return implode(', '$list);
  367.     }
  368.     /**
  369.      * Retrieves object reference to the HTML definition.
  370.      *
  371.      * @param bool $raw Return a copy that has not been setup yet. Must be
  372.      *             called before it's been setup, otherwise won't work.
  373.      * @param bool $optimized If true, this method may return null, to
  374.      *             indicate that a cached version of the modified
  375.      *             definition object is available and no further edits
  376.      *             are necessary.  Consider using
  377.      *             maybeGetRawHTMLDefinition, which is more explicitly
  378.      *             named, instead.
  379.      *
  380.      * @return HTMLPurifier_HTMLDefinition|null
  381.      */
  382.     public function getHTMLDefinition($raw false$optimized false)
  383.     {
  384.         return $this->getDefinition('HTML'$raw$optimized);
  385.     }
  386.     /**
  387.      * Retrieves object reference to the CSS definition
  388.      *
  389.      * @param bool $raw Return a copy that has not been setup yet. Must be
  390.      *             called before it's been setup, otherwise won't work.
  391.      * @param bool $optimized If true, this method may return null, to
  392.      *             indicate that a cached version of the modified
  393.      *             definition object is available and no further edits
  394.      *             are necessary.  Consider using
  395.      *             maybeGetRawCSSDefinition, which is more explicitly
  396.      *             named, instead.
  397.      *
  398.      * @return HTMLPurifier_CSSDefinition|null
  399.      */
  400.     public function getCSSDefinition($raw false$optimized false)
  401.     {
  402.         return $this->getDefinition('CSS'$raw$optimized);
  403.     }
  404.     /**
  405.      * Retrieves object reference to the URI definition
  406.      *
  407.      * @param bool $raw Return a copy that has not been setup yet. Must be
  408.      *             called before it's been setup, otherwise won't work.
  409.      * @param bool $optimized If true, this method may return null, to
  410.      *             indicate that a cached version of the modified
  411.      *             definition object is available and no further edits
  412.      *             are necessary.  Consider using
  413.      *             maybeGetRawURIDefinition, which is more explicitly
  414.      *             named, instead.
  415.      *
  416.      * @return HTMLPurifier_URIDefinition|null
  417.      */
  418.     public function getURIDefinition($raw false$optimized false)
  419.     {
  420.         return $this->getDefinition('URI'$raw$optimized);
  421.     }
  422.     /**
  423.      * Retrieves a definition
  424.      *
  425.      * @param string $type Type of definition: HTML, CSS, etc
  426.      * @param bool $raw Whether or not definition should be returned raw
  427.      * @param bool $optimized Only has an effect when $raw is true.  Whether
  428.      *        or not to return null if the result is already present in
  429.      *        the cache.  This is off by default for backwards
  430.      *        compatibility reasons, but you need to do things this
  431.      *        way in order to ensure that caching is done properly.
  432.      *        Check out enduser-customize.html for more details.
  433.      *        We probably won't ever change this default, as much as the
  434.      *        maybe semantics is the "right thing to do."
  435.      *
  436.      * @throws HTMLPurifier_Exception
  437.      * @return HTMLPurifier_Definition|null
  438.      */
  439.     public function getDefinition($type$raw false$optimized false)
  440.     {
  441.         if ($optimized && !$raw) {
  442.             throw new HTMLPurifier_Exception("Cannot set optimized = true when raw = false");
  443.         }
  444.         if (!$this->finalized) {
  445.             $this->autoFinalize();
  446.         }
  447.         // temporarily suspend locks, so we can handle recursive definition calls
  448.         $lock $this->lock;
  449.         $this->lock null;
  450.         $factory HTMLPurifier_DefinitionCacheFactory::instance();
  451.         $cache $factory->create($type$this);
  452.         $this->lock $lock;
  453.         if (!$raw) {
  454.             // full definition
  455.             // ---------------
  456.             // check if definition is in memory
  457.             if (!empty($this->definitions[$type])) {
  458.                 $def $this->definitions[$type];
  459.                 // check if the definition is setup
  460.                 if ($def->setup) {
  461.                     return $def;
  462.                 } else {
  463.                     $def->setup($this);
  464.                     if ($def->optimized) {
  465.                         $cache->add($def$this);
  466.                     }
  467.                     return $def;
  468.                 }
  469.             }
  470.             // check if definition is in cache
  471.             $def $cache->get($this);
  472.             if ($def) {
  473.                 // definition in cache, save to memory and return it
  474.                 $this->definitions[$type] = $def;
  475.                 return $def;
  476.             }
  477.             // initialize it
  478.             $def $this->initDefinition($type);
  479.             // set it up
  480.             $this->lock $type;
  481.             $def->setup($this);
  482.             $this->lock null;
  483.             // save in cache
  484.             $cache->add($def$this);
  485.             // return it
  486.             return $def;
  487.         } else {
  488.             // raw definition
  489.             // --------------
  490.             // check preconditions
  491.             $def null;
  492.             if ($optimized) {
  493.                 if (is_null($this->get($type '.DefinitionID'))) {
  494.                     // fatally error out if definition ID not set
  495.                     throw new HTMLPurifier_Exception(
  496.                         "Cannot retrieve raw version without specifying %$type.DefinitionID"
  497.                     );
  498.                 }
  499.             }
  500.             if (!empty($this->definitions[$type])) {
  501.                 $def $this->definitions[$type];
  502.                 if ($def->setup && !$optimized) {
  503.                     $extra $this->chatty ?
  504.                         " (try moving this code block earlier in your initialization)" :
  505.                         "";
  506.                     throw new HTMLPurifier_Exception(
  507.                         "Cannot retrieve raw definition after it has already been setup" .
  508.                         $extra
  509.                     );
  510.                 }
  511.                 if ($def->optimized === null) {
  512.                     $extra $this->chatty " (try flushing your cache)" "";
  513.                     throw new HTMLPurifier_Exception(
  514.                         "Optimization status of definition is unknown" $extra
  515.                     );
  516.                 }
  517.                 if ($def->optimized !== $optimized) {
  518.                     $msg $optimized "optimized" "unoptimized";
  519.                     $extra $this->chatty ?
  520.                         " (this backtrace is for the first inconsistent call, which was for a $msg raw definition)"
  521.                         "";
  522.                     throw new HTMLPurifier_Exception(
  523.                         "Inconsistent use of optimized and unoptimized raw definition retrievals" $extra
  524.                     );
  525.                 }
  526.             }
  527.             // check if definition was in memory
  528.             if ($def) {
  529.                 if ($def->setup) {
  530.                     // invariant: $optimized === true (checked above)
  531.                     return null;
  532.                 } else {
  533.                     return $def;
  534.                 }
  535.             }
  536.             // if optimized, check if definition was in cache
  537.             // (because we do the memory check first, this formulation
  538.             // is prone to cache slamming, but I think
  539.             // guaranteeing that either /all/ of the raw
  540.             // setup code or /none/ of it is run is more important.)
  541.             if ($optimized) {
  542.                 // This code path only gets run once; once we put
  543.                 // something in $definitions (which is guaranteed by the
  544.                 // trailing code), we always short-circuit above.
  545.                 $def $cache->get($this);
  546.                 if ($def) {
  547.                     // save the full definition for later, but don't
  548.                     // return it yet
  549.                     $this->definitions[$type] = $def;
  550.                     return null;
  551.                 }
  552.             }
  553.             // check invariants for creation
  554.             if (!$optimized) {
  555.                 if (!is_null($this->get($type '.DefinitionID'))) {
  556.                     if ($this->chatty) {
  557.                         $this->triggerError(
  558.                             'Due to a documentation error in previous version of HTML Purifier, your ' .
  559.                             'definitions are not being cached.  If this is OK, you can remove the ' .
  560.                             '%$type.DefinitionRev and %$type.DefinitionID declaration.  Otherwise, ' .
  561.                             'modify your code to use maybeGetRawDefinition, and test if the returned ' .
  562.                             'value is null before making any edits (if it is null, that means that a ' .
  563.                             'cached version is available, and no raw operations are necessary).  See ' .
  564.                             '<a href="http://htmlpurifier.org/docs/enduser-customize.html#optimized">' .
  565.                             'Customize</a> for more details',
  566.                             E_USER_WARNING
  567.                         );
  568.                     } else {
  569.                         $this->triggerError(
  570.                             "Useless DefinitionID declaration",
  571.                             E_USER_WARNING
  572.                         );
  573.                     }
  574.                 }
  575.             }
  576.             // initialize it
  577.             $def $this->initDefinition($type);
  578.             $def->optimized $optimized;
  579.             return $def;
  580.         }
  581.         throw new HTMLPurifier_Exception("The impossible happened!");
  582.     }
  583.     /**
  584.      * Initialise definition
  585.      *
  586.      * @param string $type What type of definition to create
  587.      *
  588.      * @return HTMLPurifier_CSSDefinition|HTMLPurifier_HTMLDefinition|HTMLPurifier_URIDefinition
  589.      * @throws HTMLPurifier_Exception
  590.      */
  591.     private function initDefinition($type)
  592.     {
  593.         // quick checks failed, let's create the object
  594.         if ($type == 'HTML') {
  595.             $def = new HTMLPurifier_HTMLDefinition();
  596.         } elseif ($type == 'CSS') {
  597.             $def = new HTMLPurifier_CSSDefinition();
  598.         } elseif ($type == 'URI') {
  599.             $def = new HTMLPurifier_URIDefinition();
  600.         } else {
  601.             throw new HTMLPurifier_Exception(
  602.                 "Definition of $type type not supported"
  603.             );
  604.         }
  605.         $this->definitions[$type] = $def;
  606.         return $def;
  607.     }
  608.     public function maybeGetRawDefinition($name)
  609.     {
  610.         return $this->getDefinition($nametruetrue);
  611.     }
  612.     /**
  613.      * @return HTMLPurifier_HTMLDefinition|null
  614.      */
  615.     public function maybeGetRawHTMLDefinition()
  616.     {
  617.         return $this->getDefinition('HTML'truetrue);
  618.     }
  619.     
  620.     /**
  621.      * @return HTMLPurifier_CSSDefinition|null
  622.      */
  623.     public function maybeGetRawCSSDefinition()
  624.     {
  625.         return $this->getDefinition('CSS'truetrue);
  626.     }
  627.     
  628.     /**
  629.      * @return HTMLPurifier_URIDefinition|null
  630.      */
  631.     public function maybeGetRawURIDefinition()
  632.     {
  633.         return $this->getDefinition('URI'truetrue);
  634.     }
  635.     /**
  636.      * Loads configuration values from an array with the following structure:
  637.      * Namespace.Directive => Value
  638.      *
  639.      * @param array $config_array Configuration associative array
  640.      */
  641.     public function loadArray($config_array)
  642.     {
  643.         if ($this->isFinalized('Cannot load directives after finalization')) {
  644.             return;
  645.         }
  646.         foreach ($config_array as $key => $value) {
  647.             $key str_replace('_''.'$key);
  648.             if (strpos($key'.') !== false) {
  649.                 $this->set($key$value);
  650.             } else {
  651.                 $namespace $key;
  652.                 $namespace_values $value;
  653.                 foreach ($namespace_values as $directive => $value2) {
  654.                     $this->set($namespace .'.'$directive$value2);
  655.                 }
  656.             }
  657.         }
  658.     }
  659.     /**
  660.      * Returns a list of array(namespace, directive) for all directives
  661.      * that are allowed in a web-form context as per an allowed
  662.      * namespaces/directives list.
  663.      *
  664.      * @param array $allowed List of allowed namespaces/directives
  665.      * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy
  666.      *
  667.      * @return array
  668.      */
  669.     public static function getAllowedDirectivesForForm($allowed$schema null)
  670.     {
  671.         if (!$schema) {
  672.             $schema HTMLPurifier_ConfigSchema::instance();
  673.         }
  674.         if ($allowed !== true) {
  675.             if (is_string($allowed)) {
  676.                 $allowed = array($allowed);
  677.             }
  678.             $allowed_ns = array();
  679.             $allowed_directives = array();
  680.             $blacklisted_directives = array();
  681.             foreach ($allowed as $ns_or_directive) {
  682.                 if (strpos($ns_or_directive'.') !== false) {
  683.                     // directive
  684.                     if ($ns_or_directive[0] == '-') {
  685.                         $blacklisted_directives[substr($ns_or_directive1)] = true;
  686.                     } else {
  687.                         $allowed_directives[$ns_or_directive] = true;
  688.                     }
  689.                 } else {
  690.                     // namespace
  691.                     $allowed_ns[$ns_or_directive] = true;
  692.                 }
  693.             }
  694.         }
  695.         $ret = array();
  696.         foreach ($schema->info as $key => $def) {
  697.             list($ns$directive) = explode('.'$key2);
  698.             if ($allowed !== true) {
  699.                 if (isset($blacklisted_directives["$ns.$directive"])) {
  700.                     continue;
  701.                 }
  702.                 if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) {
  703.                     continue;
  704.                 }
  705.             }
  706.             if (isset($def->isAlias)) {
  707.                 continue;
  708.             }
  709.             if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') {
  710.                 continue;
  711.             }
  712.             $ret[] = array($ns$directive);
  713.         }
  714.         return $ret;
  715.     }
  716.     /**
  717.      * Loads configuration values from $_GET/$_POST that were posted
  718.      * via ConfigForm
  719.      *
  720.      * @param array $array $_GET or $_POST array to import
  721.      * @param string|bool $index Index/name that the config variables are in
  722.      * @param array|bool $allowed List of allowed namespaces/directives
  723.      * @param bool $mq_fix Boolean whether or not to enable magic quotes fix
  724.      * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy
  725.      *
  726.      * @return mixed
  727.      */
  728.     public static function loadArrayFromForm($array$index false$allowed true$mq_fix true$schema null)
  729.     {
  730.         $ret HTMLPurifier_Config::prepareArrayFromForm($array$index$allowed$mq_fix$schema);
  731.         $config HTMLPurifier_Config::create($ret$schema);
  732.         return $config;
  733.     }
  734.     /**
  735.      * Merges in configuration values from $_GET/$_POST to object. NOT STATIC.
  736.      *
  737.      * @param array $array $_GET or $_POST array to import
  738.      * @param string|bool $index Index/name that the config variables are in
  739.      * @param array|bool $allowed List of allowed namespaces/directives
  740.      * @param bool $mq_fix Boolean whether or not to enable magic quotes fix
  741.      */
  742.     public function mergeArrayFromForm($array$index false$allowed true$mq_fix true)
  743.     {
  744.          $ret HTMLPurifier_Config::prepareArrayFromForm($array$index$allowed$mq_fix$this->def);
  745.          $this->loadArray($ret);
  746.     }
  747.     /**
  748.      * Prepares an array from a form into something usable for the more
  749.      * strict parts of HTMLPurifier_Config
  750.      *
  751.      * @param array $array $_GET or $_POST array to import
  752.      * @param string|bool $index Index/name that the config variables are in
  753.      * @param array|bool $allowed List of allowed namespaces/directives
  754.      * @param bool $mq_fix Boolean whether or not to enable magic quotes fix
  755.      * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy
  756.      *
  757.      * @return array
  758.      */
  759.     public static function prepareArrayFromForm($array$index false$allowed true$mq_fix true$schema null)
  760.     {
  761.         if ($index !== false) {
  762.             $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array();
  763.         }
  764.         $mq $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc();
  765.         $allowed HTMLPurifier_Config::getAllowedDirectivesForForm($allowed$schema);
  766.         $ret = array();
  767.         foreach ($allowed as $key) {
  768.             list($ns$directive) = $key;
  769.             $skey "$ns.$directive";
  770.             if (!empty($array["Null_$skey"])) {
  771.                 $ret[$ns][$directive] = null;
  772.                 continue;
  773.             }
  774.             if (!isset($array[$skey])) {
  775.                 continue;
  776.             }
  777.             $value $mq stripslashes($array[$skey]) : $array[$skey];
  778.             $ret[$ns][$directive] = $value;
  779.         }
  780.         return $ret;
  781.     }
  782.     /**
  783.      * Loads configuration values from an ini file
  784.      *
  785.      * @param string $filename Name of ini file
  786.      */
  787.     public function loadIni($filename)
  788.     {
  789.         if ($this->isFinalized('Cannot load directives after finalization')) {
  790.             return;
  791.         }
  792.         $array parse_ini_file($filenametrue);
  793.         $this->loadArray($array);
  794.     }
  795.     /**
  796.      * Checks whether or not the configuration object is finalized.
  797.      *
  798.      * @param string|bool $error String error message, or false for no error
  799.      *
  800.      * @return bool
  801.      */
  802.     public function isFinalized($error false)
  803.     {
  804.         if ($this->finalized && $error) {
  805.             $this->triggerError($errorE_USER_ERROR);
  806.         }
  807.         return $this->finalized;
  808.     }
  809.     /**
  810.      * Finalizes configuration only if auto finalize is on and not
  811.      * already finalized
  812.      */
  813.     public function autoFinalize()
  814.     {
  815.         if ($this->autoFinalize) {
  816.             $this->finalize();
  817.         } else {
  818.             $this->plist->squash(true);
  819.         }
  820.     }
  821.     /**
  822.      * Finalizes a configuration object, prohibiting further change
  823.      */
  824.     public function finalize()
  825.     {
  826.         $this->finalized true;
  827.         $this->parser null;
  828.     }
  829.     /**
  830.      * Produces a nicely formatted error message by supplying the
  831.      * stack frame information OUTSIDE of HTMLPurifier_Config.
  832.      *
  833.      * @param string $msg An error message
  834.      * @param int $no An error number
  835.      */
  836.     protected function triggerError($msg$no)
  837.     {
  838.         // determine previous stack frame
  839.         $extra '';
  840.         if ($this->chatty) {
  841.             $trace debug_backtrace();
  842.             // zip(tail(trace), trace) -- but PHP is not Haskell har har
  843.             for ($i 0$c count($trace); $i $c 1$i++) {
  844.                 // XXX this is not correct on some versions of HTML Purifier
  845.                 if (isset($trace[$i 1]['class']) && $trace[$i 1]['class'] === 'HTMLPurifier_Config') {
  846.                     continue;
  847.                 }
  848.                 $frame $trace[$i];
  849.                 $extra " invoked on line {$frame['line']} in file {$frame['file']}";
  850.                 break;
  851.             }
  852.         }
  853.         trigger_error($msg $extra$no);
  854.     }
  855.     /**
  856.      * Returns a serialized form of the configuration object that can
  857.      * be reconstituted.
  858.      *
  859.      * @return string
  860.      */
  861.     public function serialize()
  862.     {
  863.         $this->getDefinition('HTML');
  864.         $this->getDefinition('CSS');
  865.         $this->getDefinition('URI');
  866.         return serialize($this);
  867.     }
  868. }
  869. // vim: et sw=4 sts=4