PageRenderTime 39ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/app/bundles/CoreBundle/Helper/InputHelper.php

https://gitlab.com/mautic-master/mautic
PHP | 397 lines | 215 code | 51 blank | 131 comment | 40 complexity | 40cb8ff0f03cc9e44d0a57434dae7c7b MD5 | raw file
  1. <?php
  2. /**
  3. * @package Mautic
  4. * @copyright 2014 Mautic Contributors. All rights reserved.
  5. * @author Mautic
  6. * @link http://mautic.org
  7. * @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
  8. */
  9. namespace Mautic\CoreBundle\Helper;
  10. use Joomla\Filter\InputFilter;
  11. /**
  12. * Class InputHelper
  13. */
  14. class InputHelper
  15. {
  16. /**
  17. * String filter
  18. *
  19. * @var InputFilter
  20. */
  21. private static $stringFilter;
  22. /**
  23. * HTML filter
  24. *
  25. * @var InputFilter
  26. */
  27. private static $htmlFilter;
  28. private static function getFilter($html = false)
  29. {
  30. if (empty(self::$htmlFilter)) {
  31. // Most of Mautic's HTML uses include full HTML documents so use blacklist method
  32. self::$htmlFilter = new InputFilter(array(), array(), 1, 1);
  33. self::$htmlFilter->tagBlacklist = array(
  34. 'applet',
  35. 'bgsound',
  36. 'base',
  37. 'basefont',
  38. 'embed',
  39. 'frame',
  40. 'frameset',
  41. 'ilayer',
  42. 'layer',
  43. 'object',
  44. 'xml'
  45. );
  46. self::$htmlFilter->attrBlacklist = array(
  47. 'codebase',
  48. 'dynsrc',
  49. 'lowsrc'
  50. );
  51. // Standard behavior if HTML is not specifically used
  52. self::$stringFilter = new InputFilter();
  53. }
  54. return ($html) ? self::$htmlFilter : self::$stringFilter;
  55. }
  56. /**
  57. * Wrapper to InputHelper
  58. *
  59. * @param $name
  60. * @param $arguments
  61. *
  62. * @return mixed
  63. */
  64. public static function __callStatic($name, $arguments)
  65. {
  66. return self::getFilter()->clean($arguments[0], $name);
  67. }
  68. /**
  69. * Wrapper function to clean inputs. $mask can be an array of keys as the field names and values as the cleaning
  70. * function to be used for the specific field.
  71. *
  72. * @param mixed $value
  73. * @param mixed $mask
  74. * @param bool $urldecode
  75. *
  76. * @return mixed
  77. */
  78. public static function _($value, $mask = 'clean', $urldecode = false)
  79. {
  80. if (is_array($value)) {
  81. foreach ($value as $k => &$v) {
  82. $useMask = 'filter';
  83. if (is_array($mask)) {
  84. if (array_key_exists($k, $mask)) {
  85. if (is_array($mask[$k])) {
  86. $useMask = $mask[$k];
  87. } elseif (method_exists('Mautic\CoreBundle\Helper\InputHelper', $mask[$k])) {
  88. $useMask = $mask[$k];
  89. }
  90. }
  91. } elseif (method_exists('Mautic\CoreBundle\Helper\InputHelper', $mask)) {
  92. $useMask = $mask;
  93. }
  94. if (is_array($v) && is_array($useMask)) {
  95. $v = self::_($v, $useMask, $urldecode);
  96. } elseif ($useMask == 'filter') {
  97. $v = self::getFilter()->clean($v, $useMask);
  98. } else {
  99. $v = self::$useMask($v, $urldecode);
  100. }
  101. }
  102. return $value;
  103. } elseif (is_string($mask) && method_exists('Mautic\CoreBundle\Helper\InputHelper', $mask)) {
  104. if (is_array($value)) {
  105. foreach ($value as $k => &$v) {
  106. $v = self::$mask($v, $urldecode);
  107. }
  108. return $value;
  109. } else {
  110. return self::$mask($value, $urldecode);
  111. }
  112. } else {
  113. return self::getFilter()->clean($value, $mask);
  114. }
  115. }
  116. /**
  117. * Cleans value by HTML-escaping '"<>& and characters with ASCII value less than 32
  118. *
  119. * @param $value
  120. * @param bool|false $urldecode
  121. *
  122. * @return mixed|string
  123. */
  124. public static function clean($value, $urldecode = false)
  125. {
  126. if (is_array($value)) {
  127. foreach ($value as &$v) {
  128. $v = self::clean($v, $urldecode);
  129. }
  130. return $value;
  131. } elseif ($urldecode) {
  132. $value = urldecode($value);
  133. }
  134. return filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);
  135. }
  136. /**
  137. * Strips tags
  138. *
  139. * @param $value
  140. * @param bool|false $urldecode
  141. *
  142. * @return mixed
  143. */
  144. public static function string($value, $urldecode = false)
  145. {
  146. if ($urldecode) {
  147. $value = urldecode($value);
  148. }
  149. return filter_var($value, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
  150. }
  151. /**
  152. * Strips non-alphanumeric characters
  153. *
  154. * @param $value
  155. * @param bool|false $urldecode
  156. * @param bool|false $convertSpacesTo
  157. * @param array $allowedCharacters
  158. *
  159. * @return string
  160. */
  161. public static function alphanum($value, $urldecode = false, $convertSpacesTo = false, $allowedCharacters = array())
  162. {
  163. if ($urldecode) {
  164. $value = urldecode($value);
  165. }
  166. if ($convertSpacesTo) {
  167. $value = str_replace(' ', $convertSpacesTo, $value);
  168. $allowedCharacters[] = $convertSpacesTo;
  169. }
  170. if (!empty($allowedCharacters)) {
  171. $regex = "/[^0-9a-z".implode('', $allowedCharacters)."]+/i";
  172. } else {
  173. $regex = "/[^0-9a-z]+/i";
  174. }
  175. return trim(preg_replace($regex, "", $value));
  176. }
  177. /**
  178. * Returns a satnitized string which can be used in a file system
  179. *
  180. * @param $value
  181. *
  182. * @return string
  183. */
  184. public static function filename($value)
  185. {
  186. $value = str_replace(' ', '_', $value);
  187. return preg_replace("/[^a-z0-9\.\_]/", "", strtolower($value));
  188. }
  189. /**
  190. * Returns raw value
  191. *
  192. * @param $value
  193. * @param bool|false $urldecode
  194. *
  195. * @return string
  196. */
  197. public static function raw($value, $urldecode = false)
  198. {
  199. if ($urldecode) {
  200. $value = urldecode($value);
  201. }
  202. return $value;
  203. }
  204. /**
  205. * Removes all characters except those allowed in URLs
  206. *
  207. * @param $value
  208. * @param bool|false $urldecode
  209. * @param null $allowedProtocols
  210. * @param null $defaultProtocol
  211. * @param array $removeQuery
  212. * @param bool|false $ignoreFragment
  213. *
  214. * @return mixed|string
  215. */
  216. public static function url($value, $urldecode = false, $allowedProtocols = null, $defaultProtocol = null, $removeQuery = array(), $ignoreFragment = false)
  217. {
  218. if ($urldecode) {
  219. $value = urldecode($value);
  220. }
  221. if (empty($allowedProtocols)) {
  222. $allowedProtocols = array('https', 'http', 'ftp');
  223. }
  224. if (empty($defaultProtocol)) {
  225. $defaultProtocol = 'http';
  226. }
  227. $value = filter_var($value, FILTER_SANITIZE_URL);
  228. $parts = parse_url($value);
  229. if ($parts) {
  230. if (isset($parts['scheme'])) {
  231. if (!in_array($parts['scheme'], $allowedProtocols)) {
  232. $parts['scheme'] = $defaultProtocol;
  233. }
  234. } else {
  235. $parts['scheme'] = $defaultProtocol;
  236. }
  237. if (!empty($removeQuery) && !empty($parts['query'])) {
  238. parse_str($parts['query'], $query);
  239. foreach ($removeQuery as $q) {
  240. if (isset($query[$q])) {
  241. unset($query[$q]);
  242. }
  243. }
  244. $parts['query'] = http_build_query($query);
  245. }
  246. $value =
  247. (!empty($parts["scheme"]) ? $parts["scheme"]."://" :"") .
  248. (!empty($parts["user"]) ? $parts["user"].":" :"") .
  249. (!empty($parts["pass"]) ? $parts["pass"]."@" :"") .
  250. (!empty($parts["host"]) ? $parts["host"] :"") .
  251. (!empty($parts["port"]) ? ":".$parts["port"] :"") .
  252. (!empty($parts["path"]) ? $parts["path"] :"") .
  253. (!empty($parts["query"]) ? "?".$parts["query"] :"") .
  254. (!$ignoreFragment && !empty($parts["fragment"]) ? "#".$parts["fragment"] :"");
  255. } else {
  256. //must have a really bad URL since parse_url returned false so let's just clean it
  257. $value = self::clean($value);
  258. }
  259. //since a URL allows <>, let's add a safety step to remove <script> tags
  260. $value = preg_replace('#<script(.*?)>(.*?)</script>#is', '', $value);
  261. return $value;
  262. }
  263. /**
  264. * Removes all characters except those allowed in emails
  265. *
  266. * @param $value
  267. * @param bool|false $urldecode
  268. *
  269. * @return mixed
  270. */
  271. public static function email($value, $urldecode = false)
  272. {
  273. if ($urldecode) {
  274. $value = urldecode($value);
  275. }
  276. $value = substr($value, 0, 254);
  277. return filter_var($value, FILTER_SANITIZE_EMAIL);
  278. }
  279. /**
  280. * Returns a clean array
  281. *
  282. * @param $value
  283. * @param bool|false $urldecode
  284. *
  285. * @return array|mixed|string
  286. */
  287. public static function cleanArray($value, $urldecode = false)
  288. {
  289. $value = self::clean($value, $urldecode);
  290. if (!is_array($value)) {
  291. $value = array($value);
  292. }
  293. return $value;
  294. }
  295. /**
  296. * Returns clean HTML
  297. *
  298. * @param $value
  299. *
  300. * @return mixed|string
  301. */
  302. public static function html($value)
  303. {
  304. if (is_array($value)) {
  305. foreach ($value as &$val) {
  306. $val = self::html($val);
  307. }
  308. } else {
  309. // Special handling for doctype
  310. $doctypeFound = preg_match("/(<!DOCTYPE(.*?)>)/is", $value, $doctype);
  311. // Special handling for CDATA tags
  312. $value = str_replace(array('<![CDATA[', ']]>'), array('<mcdata>', '</mcdata>'), $value, $cdataCount);
  313. // Special handling for conditional blocks
  314. $value = preg_replace("/<!--\[if(.*?)\]>(.*?)<!\[endif\]-->/is", '<mcondition><mif>$1</mif>$2</mcondition>', $value, -1, $conditionsFound);
  315. // Special handling for HTML comments
  316. $value = str_replace(array('<!--', '-->'), array('<mcomment>', '</mcomment>'), $value, $commentCount);
  317. $value = self::getFilter(true)->clean($value, 'html');
  318. // Was a doctype found?
  319. if ($doctypeFound) {
  320. $value = "$doctype[0]\n$value";
  321. }
  322. if ($cdataCount) {
  323. $value = str_replace(array('<mcdata>', '</mcdata>'), array('<![CDATA[', ']]>'), $value);
  324. }
  325. if ($conditionsFound) {
  326. // Special handling for conditional blocks
  327. $value = preg_replace("/<mcondition><mif>(.*?)<\/mif>(.*?)<\/mcondition>/is", '<!--[if$1]>$2<![endif]-->', $value);
  328. }
  329. if ($commentCount) {
  330. $value = str_replace(array('<mcomment>', '</mcomment>'), array('<!--', '-->'), $value );
  331. }
  332. }
  333. return $value;
  334. }
  335. /**
  336. * Converts UTF8 into Latin
  337. *
  338. * @param $value
  339. *
  340. * @return mixed
  341. */
  342. public static function transliterate($value)
  343. {
  344. return \URLify::transliterate($value);
  345. }
  346. }