1<?php
2
3/**
4 * Configuration definition, defines directives and their defaults.
5 */
6class HTMLPurifier_ConfigSchema
7{
8    /**
9     * Defaults of the directives and namespaces.
10     * @type array
11     * @note This shares the exact same structure as HTMLPurifier_Config::$conf
12     */
13    public $defaults = array();
14
15    /**
16     * The default property list. Do not edit this property list.
17     * @type array
18     */
19    public $defaultPlist;
20
21    /**
22     * Definition of the directives.
23     * The structure of this is:
24     *
25     *  array(
26     *      'Namespace' => array(
27     *          'Directive' => new stdclass(),
28     *      )
29     *  )
30     *
31     * The stdclass may have the following properties:
32     *
33     *  - If isAlias isn't set:
34     *      - type: Integer type of directive, see HTMLPurifier_VarParser for definitions
35     *      - allow_null: If set, this directive allows null values
36     *      - aliases: If set, an associative array of value aliases to real values
37     *      - allowed: If set, a lookup array of allowed (string) values
38     *  - If isAlias is set:
39     *      - namespace: Namespace this directive aliases to
40     *      - name: Directive name this directive aliases to
41     *
42     * In certain degenerate cases, stdclass will actually be an integer. In
43     * that case, the value is equivalent to an stdclass with the type
44     * property set to the integer. If the integer is negative, type is
45     * equal to the absolute value of integer, and allow_null is true.
46     *
47     * This class is friendly with HTMLPurifier_Config. If you need introspection
48     * about the schema, you're better of using the ConfigSchema_Interchange,
49     * which uses more memory but has much richer information.
50     * @type array
51     */
52    public $info = array();
53
54    /**
55     * Application-wide singleton
56     * @type HTMLPurifier_ConfigSchema
57     */
58    protected static $singleton;
59
60    public function __construct()
61    {
62        $this->defaultPlist = new HTMLPurifier_PropertyList();
63    }
64
65    /**
66     * Unserializes the default ConfigSchema.
67     * @return HTMLPurifier_ConfigSchema
68     */
69    public static function makeFromSerial()
70    {
71        $contents = file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema.ser');
72        $r = unserialize($contents);
73        if (!$r) {
74            $hash = sha1($contents);
75            trigger_error("Unserialization of configuration schema failed, sha1 of file was $hash", E_USER_ERROR);
76        }
77        return $r;
78    }
79
80    /**
81     * Retrieves an instance of the application-wide configuration definition.
82     * @param HTMLPurifier_ConfigSchema $prototype
83     * @return HTMLPurifier_ConfigSchema
84     */
85    public static function instance($prototype = null)
86    {
87        if ($prototype !== null) {
88            HTMLPurifier_ConfigSchema::$singleton = $prototype;
89        } elseif (HTMLPurifier_ConfigSchema::$singleton === null || $prototype === true) {
90            HTMLPurifier_ConfigSchema::$singleton = HTMLPurifier_ConfigSchema::makeFromSerial();
91        }
92        return HTMLPurifier_ConfigSchema::$singleton;
93    }
94
95    /**
96     * Defines a directive for configuration
97     * @warning Will fail of directive's namespace is defined.
98     * @warning This method's signature is slightly different from the legacy
99     *          define() static method! Beware!
100     * @param string $key Name of directive
101     * @param mixed $default Default value of directive
102     * @param string $type Allowed type of the directive. See
103     *      HTMLPurifier_DirectiveDef::$type for allowed values
104     * @param bool $allow_null Whether or not to allow null values
105     */
106    public function add($key, $default, $type, $allow_null)
107    {
108        $obj = new stdclass();
109        $obj->type = is_int($type) ? $type : HTMLPurifier_VarParser::$types[$type];
110        if ($allow_null) {
111            $obj->allow_null = true;
112        }
113        $this->info[$key] = $obj;
114        $this->defaults[$key] = $default;
115        $this->defaultPlist->set($key, $default);
116    }
117
118    /**
119     * Defines a directive value alias.
120     *
121     * Directive value aliases are convenient for developers because it lets
122     * them set a directive to several values and get the same result.
123     * @param string $key Name of Directive
124     * @param array $aliases Hash of aliased values to the real alias
125     */
126    public function addValueAliases($key, $aliases)
127    {
128        if (!isset($this->info[$key]->aliases)) {
129            $this->info[$key]->aliases = array();
130        }
131        foreach ($aliases as $alias => $real) {
132            $this->info[$key]->aliases[$alias] = $real;
133        }
134    }
135
136    /**
137     * Defines a set of allowed values for a directive.
138     * @warning This is slightly different from the corresponding static
139     *          method definition.
140     * @param string $key Name of directive
141     * @param array $allowed Lookup array of allowed values
142     */
143    public function addAllowedValues($key, $allowed)
144    {
145        $this->info[$key]->allowed = $allowed;
146    }
147
148    /**
149     * Defines a directive alias for backwards compatibility
150     * @param string $key Directive that will be aliased
151     * @param string $new_key Directive that the alias will be to
152     */
153    public function addAlias($key, $new_key)
154    {
155        $obj = new stdclass;
156        $obj->key = $new_key;
157        $obj->isAlias = true;
158        $this->info[$key] = $obj;
159    }
160
161    /**
162     * Replaces any stdclass that only has the type property with type integer.
163     */
164    public function postProcess()
165    {
166        foreach ($this->info as $key => $v) {
167            if (count((array) $v) == 1) {
168                $this->info[$key] = $v->type;
169            } elseif (count((array) $v) == 2 && isset($v->allow_null)) {
170                $this->info[$key] = -$v->type;
171            }
172        }
173    }
174}
175
176// vim: et sw=4 sts=4
177