| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 | <?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
 |