|
1 <?php |
|
2 /** |
|
3 * The SlideshowPluginSecurity class contains functions for sanitizing in- and output. |
|
4 * |
|
5 * @author Stefan Boonstra |
|
6 * @since 2.1.16 |
|
7 * @updated 2.1.16 |
|
8 */ |
|
9 class SlideshowPluginSecurity { |
|
10 |
|
11 /** |
|
12 * @since 2.1.16 |
|
13 * @var array List of allowed element tags |
|
14 */ |
|
15 private static $allowedElements = array( |
|
16 'b' => array('endTag' => true, 'attributes' => 'default'), |
|
17 'br' => array('endTag' => false), |
|
18 'div' => array('endTag' => true, 'attributes' => 'default'), |
|
19 'h1' => array('endTag' => true, 'attributes' => 'default'), |
|
20 'h2' => array('endTag' => true, 'attributes' => 'default'), |
|
21 'h3' => array('endTag' => true, 'attributes' => 'default'), |
|
22 'h4' => array('endTag' => true, 'attributes' => 'default'), |
|
23 'h5' => array('endTag' => true, 'attributes' => 'default'), |
|
24 'h6' => array('endTag' => true, 'attributes' => 'default'), |
|
25 'i' => array('endTag' => true, 'attributes' => 'default'), |
|
26 'li' => array('endTag' => true, 'attributes' => 'default'), |
|
27 'ol' => array('endTag' => true, 'attributes' => 'default'), |
|
28 'p' => array('endTag' => true, 'attributes' => 'default'), |
|
29 'span' => array('endTag' => true, 'attributes' => 'default'), |
|
30 'strong' => array('endTag' => true, 'attributes' => 'default'), |
|
31 'sub' => array('endTag' => true, 'attributes' => 'default'), |
|
32 'sup' => array('endTag' => true, 'attributes' => 'default'), |
|
33 'table' => array('endTag' => true, 'attributes' => 'default'), |
|
34 'tbody' => array('endTag' => true, 'attributes' => 'default'), |
|
35 'td' => array('endTag' => true, 'attributes' => 'default'), |
|
36 'tfoot' => array('endTag' => true, 'attributes' => 'default'), |
|
37 'th' => array('endTag' => true, 'attributes' => 'default'), |
|
38 'thead' => array('endTag' => true, 'attributes' => 'default'), |
|
39 'tr' => array('endTag' => true, 'attributes' => 'default'), |
|
40 'ul' => array('endTag' => true, 'attributes' => 'default') |
|
41 ); |
|
42 |
|
43 /** |
|
44 * @since 2.1.16 |
|
45 * @var array List of attributes allowed in the tags |
|
46 */ |
|
47 private static $defaultAllowedAttributes = array( |
|
48 'class', |
|
49 'id', |
|
50 'style' |
|
51 ); |
|
52 |
|
53 /** |
|
54 * Similar to the htmlspecialchars($text) function, except this function |
|
55 * allows the exceptions defined in this class. |
|
56 * |
|
57 * @since 2.1.16 |
|
58 * @updated 2.1.16 |
|
59 */ |
|
60 static function htmlspecialchars_allow_exceptions($text){ |
|
61 $text = htmlspecialchars(htmlspecialchars_decode($text)); |
|
62 |
|
63 $allowedElements = self::$allowedElements; |
|
64 |
|
65 // Loop through allowed elements decoding their HTML special chars and allowed attributes. |
|
66 if(is_array($allowedElements) && count($allowedElements) > 0){ |
|
67 foreach($allowedElements as $element => $attributes){ |
|
68 |
|
69 $position = 0; |
|
70 |
|
71 while(($position = stripos($text, $element, $position)) !== false){ // While element tags found |
|
72 |
|
73 $openingTag = '<'; |
|
74 $encodedOpeningTag = htmlspecialchars($openingTag); |
|
75 |
|
76 if(substr($text, $position - strlen($encodedOpeningTag), strlen($encodedOpeningTag)) == $encodedOpeningTag){ // Check if an opening tag '<' can be found before the tag name |
|
77 |
|
78 // Replace encoded opening tag |
|
79 $text = substr_replace($text, '<', $position - strlen($encodedOpeningTag), strlen($encodedOpeningTag)); |
|
80 $position -= strlen($encodedOpeningTag) - strlen($openingTag); |
|
81 |
|
82 // Get the position of the first element closing tag |
|
83 $closingTag = '>'; |
|
84 $encodedClosingTag = htmlspecialchars($closingTag); |
|
85 $closingTagPosition = stripos($text, $encodedClosingTag, $position); |
|
86 |
|
87 // Replace encoded closing tag |
|
88 if($closingTagPosition !== false) |
|
89 $text = substr_replace($text, '>', $closingTagPosition, strlen($encodedClosingTag)); |
|
90 |
|
91 $elementAttributes = null; |
|
92 if(isset($attributes['attributes']) && is_array($attributes['attributes'])) |
|
93 $elementAttributes = $attributes['attributes']; |
|
94 elseif(isset($attributes['attributes']) && $attributes['attributes'] == 'default') |
|
95 $elementAttributes = self::$defaultAllowedAttributes; |
|
96 else |
|
97 continue; |
|
98 |
|
99 if(!is_array($elementAttributes)) |
|
100 continue; |
|
101 |
|
102 $tagText = substr($text, $position, $closingTagPosition - $position); |
|
103 |
|
104 // Decode allowed attributes |
|
105 foreach($elementAttributes as $attribute){ |
|
106 |
|
107 $attributeOpener = $attribute . '=' . htmlspecialchars('"'); |
|
108 |
|
109 $attributePosition = 0; |
|
110 if(($attributePosition = stripos($tagText, $attributeOpener, $attributePosition)) !== false){ // Attribute was found |
|
111 |
|
112 $attributeClosingPosition = 0; |
|
113 if(($attributeClosingPosition = stripos($tagText, htmlspecialchars('"'), $attributePosition + strlen($attributeOpener))) === false) // If no closing position of attribute was found, skip. |
|
114 continue; |
|
115 |
|
116 // Open the attribute |
|
117 $tagText = str_ireplace($attributeOpener, $attribute . '="', $tagText); |
|
118 |
|
119 // Close the attribute |
|
120 $attributeClosingPosition -= strlen($attributeOpener) - strlen($attribute . '="'); |
|
121 $tagText = substr_replace($tagText, '"', $attributeClosingPosition, strlen(htmlspecialchars('"'))); |
|
122 } |
|
123 |
|
124 } |
|
125 |
|
126 // Put the attributes of the tag back in place |
|
127 $text = substr_replace($text, $tagText, $position, $closingTagPosition - $position); |
|
128 } |
|
129 |
|
130 $position++; |
|
131 } |
|
132 |
|
133 // Decode closing tags |
|
134 if(isset($attributes['endTag']) && $attributes['endTag']) |
|
135 $text = str_ireplace(htmlspecialchars('</' . $element . '>'), '</' . $element . '>', $text); |
|
136 } |
|
137 } |
|
138 |
|
139 return $text; |
|
140 } |
|
141 } |