PageRenderTime 20ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/monica/monica/vendor/zendframework/zendframework/library/Zend/Filter/StripTags.php

https://bitbucket.org/alexandretaz/maniac_divers
PHP | 288 lines | 145 code | 36 blank | 107 comment | 30 complexity | 5e93fff0e10b122bfa7d56aca196b008 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Filter;
  10. use Traversable;
  11. use Zend\Stdlib\ArrayUtils;
  12. class StripTags extends AbstractFilter
  13. {
  14. /**
  15. * Unique ID prefix used for allowing comments
  16. */
  17. const UNIQUE_ID_PREFIX = '__Zend_Filter_StripTags__';
  18. /**
  19. * Array of allowed tags and allowed attributes for each allowed tag
  20. *
  21. * Tags are stored in the array keys, and the array values are themselves
  22. * arrays of the attributes allowed for the corresponding tag.
  23. *
  24. * @var array
  25. */
  26. protected $tagsAllowed = array();
  27. /**
  28. * Array of allowed attributes for all allowed tags
  29. *
  30. * Attributes stored here are allowed for all of the allowed tags.
  31. *
  32. * @var array
  33. */
  34. protected $attributesAllowed = array();
  35. /**
  36. * Sets the filter options
  37. * Allowed options are
  38. * 'allowTags' => Tags which are allowed
  39. * 'allowAttribs' => Attributes which are allowed
  40. * 'allowComments' => Are comments allowed ?
  41. *
  42. * @param string|array|Traversable $options
  43. */
  44. public function __construct($options = null)
  45. {
  46. if ($options instanceof Traversable) {
  47. $options = ArrayUtils::iteratorToArray($options);
  48. }
  49. if ((!is_array($options)) || (is_array($options) && !array_key_exists('allowTags', $options) &&
  50. !array_key_exists('allowAttribs', $options) && !array_key_exists('allowComments', $options))) {
  51. $options = func_get_args();
  52. $temp['allowTags'] = array_shift($options);
  53. if (!empty($options)) {
  54. $temp['allowAttribs'] = array_shift($options);
  55. }
  56. if (!empty($options)) {
  57. $temp['allowComments'] = array_shift($options);
  58. }
  59. $options = $temp;
  60. }
  61. if (array_key_exists('allowTags', $options)) {
  62. $this->setTagsAllowed($options['allowTags']);
  63. }
  64. if (array_key_exists('allowAttribs', $options)) {
  65. $this->setAttributesAllowed($options['allowAttribs']);
  66. }
  67. }
  68. /**
  69. * Returns the tagsAllowed option
  70. *
  71. * @return array
  72. */
  73. public function getTagsAllowed()
  74. {
  75. return $this->tagsAllowed;
  76. }
  77. /**
  78. * Sets the tagsAllowed option
  79. *
  80. * @param array|string $tagsAllowed
  81. * @return StripTags Provides a fluent interface
  82. */
  83. public function setTagsAllowed($tagsAllowed)
  84. {
  85. if (!is_array($tagsAllowed)) {
  86. $tagsAllowed = array($tagsAllowed);
  87. }
  88. foreach ($tagsAllowed as $index => $element) {
  89. // If the tag was provided without attributes
  90. if (is_int($index) && is_string($element)) {
  91. // Canonicalize the tag name
  92. $tagName = strtolower($element);
  93. // Store the tag as allowed with no attributes
  94. $this->tagsAllowed[$tagName] = array();
  95. }
  96. // Otherwise, if a tag was provided with attributes
  97. elseif (is_string($index) && (is_array($element) || is_string($element))) {
  98. // Canonicalize the tag name
  99. $tagName = strtolower($index);
  100. // Canonicalize the attributes
  101. if (is_string($element)) {
  102. $element = array($element);
  103. }
  104. // Store the tag as allowed with the provided attributes
  105. $this->tagsAllowed[$tagName] = array();
  106. foreach ($element as $attribute) {
  107. if (is_string($attribute)) {
  108. // Canonicalize the attribute name
  109. $attributeName = strtolower($attribute);
  110. $this->tagsAllowed[$tagName][$attributeName] = null;
  111. }
  112. }
  113. }
  114. }
  115. return $this;
  116. }
  117. /**
  118. * Returns the attributesAllowed option
  119. *
  120. * @return array
  121. */
  122. public function getAttributesAllowed()
  123. {
  124. return $this->attributesAllowed;
  125. }
  126. /**
  127. * Sets the attributesAllowed option
  128. *
  129. * @param array|string $attributesAllowed
  130. * @return StripTags Provides a fluent interface
  131. */
  132. public function setAttributesAllowed($attributesAllowed)
  133. {
  134. if (!is_array($attributesAllowed)) {
  135. $attributesAllowed = array($attributesAllowed);
  136. }
  137. // Store each attribute as allowed
  138. foreach ($attributesAllowed as $attribute) {
  139. if (is_string($attribute)) {
  140. // Canonicalize the attribute name
  141. $attributeName = strtolower($attribute);
  142. $this->attributesAllowed[$attributeName] = null;
  143. }
  144. }
  145. return $this;
  146. }
  147. /**
  148. * Defined by Zend\Filter\FilterInterface
  149. *
  150. * @todo improve docblock descriptions
  151. *
  152. * @param string $value
  153. * @return string
  154. */
  155. public function filter($value)
  156. {
  157. $value = (string) $value;
  158. // Strip HTML comments first
  159. while (strpos($value, '<!--') !== false) {
  160. $pos = strrpos($value, '<!--');
  161. $start = substr($value, 0, $pos);
  162. $value = substr($value, $pos);
  163. // If there is no comment closing tag, strip whole text
  164. if (!preg_match('/--\s*>/s', $value)) {
  165. $value = '';
  166. } else {
  167. $value = preg_replace('/<(?:!(?:--[\s\S]*?--\s*)?(>))/s', '', $value);
  168. }
  169. $value = $start . $value;
  170. }
  171. // Initialize accumulator for filtered data
  172. $dataFiltered = '';
  173. // Parse the input data iteratively as regular pre-tag text followed by a
  174. // tag; either may be empty strings
  175. preg_match_all('/([^<]*)(<?[^>]*>?)/', (string) $value, $matches);
  176. // Iterate over each set of matches
  177. foreach ($matches[1] as $index => $preTag) {
  178. // If the pre-tag text is non-empty, strip any ">" characters from it
  179. if (strlen($preTag)) {
  180. $preTag = str_replace('>', '', $preTag);
  181. }
  182. // If a tag exists in this match, then filter the tag
  183. $tag = $matches[2][$index];
  184. if (strlen($tag)) {
  185. $tagFiltered = $this->_filterTag($tag);
  186. } else {
  187. $tagFiltered = '';
  188. }
  189. // Add the filtered pre-tag text and filtered tag to the data buffer
  190. $dataFiltered .= $preTag . $tagFiltered;
  191. }
  192. // Return the filtered data
  193. return $dataFiltered;
  194. }
  195. /**
  196. * Filters a single tag against the current option settings
  197. *
  198. * @param string $tag
  199. * @return string
  200. */
  201. protected function _filterTag($tag)
  202. {
  203. // Parse the tag into:
  204. // 1. a starting delimiter (mandatory)
  205. // 2. a tag name (if available)
  206. // 3. a string of attributes (if available)
  207. // 4. an ending delimiter (if available)
  208. $isMatch = preg_match('~(</?)(\w*)((/(?!>)|[^/>])*)(/?>)~', $tag, $matches);
  209. // If the tag does not match, then strip the tag entirely
  210. if (!$isMatch) {
  211. return '';
  212. }
  213. // Save the matches to more meaningfully named variables
  214. $tagStart = $matches[1];
  215. $tagName = strtolower($matches[2]);
  216. $tagAttributes = $matches[3];
  217. $tagEnd = $matches[5];
  218. // If the tag is not an allowed tag, then remove the tag entirely
  219. if (!isset($this->tagsAllowed[$tagName])) {
  220. return '';
  221. }
  222. // Trim the attribute string of whitespace at the ends
  223. $tagAttributes = trim($tagAttributes);
  224. // If there are non-whitespace characters in the attribute string
  225. if (strlen($tagAttributes)) {
  226. // Parse iteratively for well-formed attributes
  227. preg_match_all('/([\w-]+)\s*=\s*(?:(")(.*?)"|(\')(.*?)\')/s', $tagAttributes, $matches);
  228. // Initialize valid attribute accumulator
  229. $tagAttributes = '';
  230. // Iterate over each matched attribute
  231. foreach ($matches[1] as $index => $attributeName) {
  232. $attributeName = strtolower($attributeName);
  233. $attributeDelimiter = empty($matches[2][$index]) ? $matches[4][$index] : $matches[2][$index];
  234. $attributeValue = empty($matches[3][$index]) ? $matches[5][$index] : $matches[3][$index];
  235. // If the attribute is not allowed, then remove it entirely
  236. if (!array_key_exists($attributeName, $this->tagsAllowed[$tagName])
  237. && !array_key_exists($attributeName, $this->attributesAllowed)) {
  238. continue;
  239. }
  240. // Add the attribute to the accumulator
  241. $tagAttributes .= " $attributeName=" . $attributeDelimiter
  242. . $attributeValue . $attributeDelimiter;
  243. }
  244. }
  245. // Reconstruct tags ending with "/>" as backwards-compatible XHTML tag
  246. if (strpos($tagEnd, '/') !== false) {
  247. $tagEnd = " $tagEnd";
  248. }
  249. // Return the filtered tag
  250. return $tagStart . $tagName . $tagAttributes . $tagEnd;
  251. }
  252. }