1: <?php
2:
3: /**
4: * Definition that allows a set of elements, but disallows empty children.
5: */
6: class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef
7: {
8: /**
9: * Lookup table of allowed elements.
10: * @type array
11: */
12: public $elements = array();
13:
14: /**
15: * Whether or not the last passed node was all whitespace.
16: * @type bool
17: */
18: protected $whitespace = false;
19:
20: /**
21: * @param array|string $elements List of allowed element names (lowercase).
22: */
23: public function __construct($elements)
24: {
25: if (is_string($elements)) {
26: $elements = str_replace(' ', '', $elements);
27: $elements = explode('|', $elements);
28: }
29: $keys = array_keys($elements);
30: if ($keys == array_keys($keys)) {
31: $elements = array_flip($elements);
32: foreach ($elements as $i => $x) {
33: $elements[$i] = true;
34: if (empty($i)) {
35: unset($elements[$i]);
36: } // remove blank
37: }
38: }
39: $this->elements = $elements;
40: }
41:
42: /**
43: * @type bool
44: */
45: public $allow_empty = false;
46:
47: /**
48: * @type string
49: */
50: public $type = 'required';
51:
52: /**
53: * @param array $children
54: * @param HTMLPurifier_Config $config
55: * @param HTMLPurifier_Context $context
56: * @return array
57: */
58: public function validateChildren($children, $config, $context)
59: {
60: // Flag for subclasses
61: $this->whitespace = false;
62:
63: // if there are no tokens, delete parent node
64: if (empty($children)) {
65: return false;
66: }
67:
68: // the new set of children
69: $result = array();
70:
71: // whether or not parsed character data is allowed
72: // this controls whether or not we silently drop a tag
73: // or generate escaped HTML from it
74: $pcdata_allowed = isset($this->elements['#PCDATA']);
75:
76: // a little sanity check to make sure it's not ALL whitespace
77: $all_whitespace = true;
78:
79: $stack = array_reverse($children);
80: while (!empty($stack)) {
81: $node = array_pop($stack);
82: if (!empty($node->is_whitespace)) {
83: $result[] = $node;
84: continue;
85: }
86: $all_whitespace = false; // phew, we're not talking about whitespace
87:
88: if (!isset($this->elements[$node->name])) {
89: // special case text
90: // XXX One of these ought to be redundant or something
91: if ($pcdata_allowed && $node instanceof HTMLPurifier_Node_Text) {
92: $result[] = $node;
93: continue;
94: }
95: // spill the child contents in
96: // ToDo: Make configurable
97: if ($node instanceof HTMLPurifier_Node_Element) {
98: for ($i = count($node->children) - 1; $i >= 0; $i--) {
99: $stack[] = $node->children[$i];
100: }
101: continue;
102: }
103: continue;
104: }
105: $result[] = $node;
106: }
107: if (empty($result)) {
108: return false;
109: }
110: if ($all_whitespace) {
111: $this->whitespace = true;
112: return false;
113: }
114: return $result;
115: }
116: }
117:
118: // vim: et sw=4 sts=4
119: