PageRenderTime 28ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/library/classes/Filtreatment_class.php

https://github.com/md-tech/openemr
PHP | 483 lines | 179 code | 61 blank | 243 comment | 55 complexity | 2968dc9beab1be34a8be082fa4cb91ff MD5 | raw file
  1. <?php
  2. /**
  3. * FILTREATMENT CLASS FILE
  4. *
  5. *
  6. * @author Cristian Năvălici {@link http://www.lemonsoftware.eu} lemonsoftware [at] gmail [.] com
  7. * @version 1.31 17 March 2008
  8. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  9. * @package Filtreatment
  10. *
  11. */
  12. //error_reporting(E_ALL);
  13. /**
  14. * constant used in float comparisions
  15. */
  16. define('EPSILON', 1.0e-8);
  17. /**
  18. * CLASS DEFINITION
  19. *
  20. * This class can be used to sanitize user inputs and prevent
  21. * most of known vulnerabilities
  22. * it requires at least PHP 5.0
  23. *
  24. * @package Filtreatment
  25. */
  26. class Filtreatment {
  27. var $minval = 0;
  28. var $maxval = 0;
  29. var $error = '';
  30. /**
  31. * CONSTRUCTOR
  32. *
  33. * do some settings at init
  34. *
  35. * @param none
  36. * @return void
  37. */
  38. function __construct() {
  39. if ( get_magic_quotes_gpc() ) {
  40. if ( !defined('MAGICQUOTES') ) define ('MAGICQUOTES', TRUE);
  41. } else {
  42. if ( !defined('MAGICQUOTES') ) define ('MAGICQUOTES', FALSE);
  43. }
  44. }
  45. //-----------------------------------------------------------------------------
  46. /**
  47. * CHECKS FOR AN INTEGER
  48. *
  49. * if the $minval and|or $maxval are set, a comparison will be performed
  50. *
  51. * NOTE: because the function can return 0 also as a valid result, check with === the return value
  52. * @param int $input - what to check/transform
  53. * @return int|bool
  54. */
  55. function ft_integer($input) {
  56. $input_c = (int)$input;
  57. $mnval = (int)$this->minval;
  58. $mxval = (int)$this->maxval;
  59. if ( !$mnval && !$mxval ) {
  60. return $input_c;
  61. } else if ( $mnval && $mxval ) {
  62. // check if they are in order (min < max)
  63. if ( $mnval > $mxval ) {
  64. $temp = $mnval;
  65. $mnval = $mxval;
  66. $mxval = $temp;
  67. }
  68. // and then check if the value is between these values
  69. return (($input >= $mnval) && ($input <= $mxval)) ? $input_c : FALSE;
  70. } else {
  71. // only one value set
  72. if ( $mnval ) return (($input >= $mnval) ? $input_c : FALSE );
  73. if ( $mxval ) return (($input <= $mxval) ? $input_c : FALSE );
  74. }
  75. }
  76. //-----------------------------------------------------------------------------
  77. /**
  78. * CHECKS FOR A FLOAT
  79. *
  80. * if the $minval and|or $maxval are set, a comparison will be performed
  81. *
  82. * @param int $input - what to check/transform
  83. * @return int|bool
  84. */
  85. function ft_float($input) {
  86. $input_c = (float)$input;
  87. $mnval = (float)$this->minval;
  88. $mxval = (float)$this->maxval;
  89. if ( !$mnval && !$mxval ) {
  90. return $input_c;
  91. } else if ( $mnval && $mxval ) {
  92. // check if they are in order (min < max)
  93. if ( $this->ft_realcmp($mnval, $mxval) > 0 ) {
  94. $temp = $mnval;
  95. $mnval = $mxval;
  96. $mxval = $temp;
  97. }
  98. // and then check if the value is between these values
  99. $lt = $this->ft_realcmp($input, $mxval); //-1 or 0 for true
  100. if ( $lt === -1 || $lt === 0 ) $lt = $input_c; else $lt = FALSE;
  101. $gt = $this->ft_realcmp($input, $mnval); //1 or 0 for true
  102. if ( $gt === 1 || $gt === 0 ) $gt = TRUE; else $gt = FALSE;
  103. return (( $lt && $gt ) ? $input_c : FALSE);
  104. } else {
  105. // only one value set
  106. if ( $mnval ) {
  107. $gt = $this->ft_realcmp($input, $mnval); //1 or 0 for true
  108. return ( $gt === 1 || $gt === 0 ) ? $input_c : FALSE;
  109. }
  110. if ( $mxval ) {
  111. $lt = $this->ft_realcmp($input, $mxval); //-1 or 0 for true
  112. return ( $lt === -1 || $lt === 0 ) ? $input_c : FALSE;
  113. }
  114. }
  115. }
  116. //-----------------------------------------------------------------------------
  117. /**
  118. * VALIDATES A DATE
  119. *
  120. * must be in YYYY-MM-DD format
  121. *
  122. * @param string $str - date in requested format
  123. * @return string|bool - the string itselfs only for valid date
  124. */
  125. function ft_validdate($str) {
  126. if ( preg_match("/([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})/", $str) ) {
  127. $arr = split("-",$str); // splitting the array
  128. $yy = $arr[0]; // first element of the array is year
  129. $mm = $arr[1]; // second element is month
  130. $dd = $arr[2]; // third element is days
  131. return ( checkdate($mm, $dd, $yy) ? $str : FALSE );
  132. } else {
  133. return FALSE;
  134. }
  135. }
  136. //-----------------------------------------------------------------------------
  137. /**
  138. * VALIDATES AN EMAIL
  139. *
  140. * implies RFC 2822
  141. *
  142. * @param string $str - email to validate
  143. * @return string|bool - the string itselfs only for valid email
  144. */
  145. function ft_email($email) {
  146. if (MAGICQUOTES) {
  147. $value = stripslashes($email);
  148. }
  149. // check for @ symbol and maximum allowed lengths
  150. if (!ereg("^[^@]{1,64}@[^@]{1,255}$", $email)) { return FALSE; }
  151. // split for sections
  152. $email_array = explode("@", $email);
  153. $local_array = explode(".", $email_array[0]);
  154. for ($i = 0; $i < sizeof($local_array); $i++) {
  155. if ( !ereg("^(([A-Za-z0-9!#$%&'*+/=?^_`{|}~-][A-Za-z0-9!#$%&'*+/=?^_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$", $local_array[$i]) ) {
  156. return FALSE;
  157. }
  158. }
  159. if (!ereg("^\[?[0-9\.]+\]?$", $email_array[1])) {
  160. // verify if domain is IP. If not, it must be a valid domain name
  161. $domain_array = explode(".", $email_array[1]);
  162. if (sizeof($domain_array) < 2) { return FALSE; }
  163. for ($i = 0; $i < sizeof($domain_array); $i++) {
  164. if (!ereg("^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$", $domain_array[$i])) {
  165. return false;
  166. }
  167. }
  168. } // if
  169. return $email;
  170. }
  171. //-----------------------------------------------------------------------------
  172. /**
  173. * PREPARES THE INPUT FOR DATABASE
  174. *
  175. * works with mysql/postgresql
  176. * NOTE: mysql_real_escape_string() requires that a valid mysql connection (mysql_connect()) exists to work
  177. *
  178. * @param string $value - email to validate
  179. * @param string $db_type - allow two constants MYSQL | PGSQL
  180. * @return string|bool $value sanitized value
  181. */
  182. function ft_dbsql($value, $db_type = 'MYSQL') {
  183. if (MAGICQUOTES) {
  184. $value = stripslashes($value);
  185. }
  186. // Quote if not a number or a numeric string
  187. if (!is_numeric($value)) {
  188. /*switch ($db_type) {
  189. case 'MYSQL': $value = "'" . mysql_real_escape_string($value) . "'"; break;
  190. case 'PGSQL': $value = "'" . pg_escape_string($value) . "'"; break;
  191. }*/
  192. // trick to not modify the openemr genuine code who put the string (already quoted) in quotes!
  193. switch ($db_type) {
  194. case 'MYSQL': $value = mysql_real_escape_string($value); break;
  195. case 'PGSQL': $value = pg_escape_string($value); break;
  196. }
  197. }
  198. return $value;
  199. }
  200. //-----------------------------------------------------------------------------
  201. /**
  202. * WORKS ON A STRING WITH REGEX EXPRESSION
  203. *
  204. * checks a string for specified characters
  205. *
  206. * @param string $value - variable to sanitize
  207. * @param string $regex - is in a special form detailed below:
  208. * it contains ONLY allowed characters, ANY other characters making invalid string
  209. * it must NOT contain begin/end delimitators /[... ]/
  210. * eg: 0-9, 0-9A-Za-z, AERS
  211. * @param int $cv - 1 or 2
  212. * @return string|bool return string if check succeed ($cv = 1) or string with replaced chars
  213. */
  214. function ft_strregex($value, $regex, $cv = 1) {
  215. $s = TRUE; //var control
  216. $regexfull = "/[^" . $regex . "]/";
  217. // function of $cv might be a clean up operation, or just verifying
  218. switch ($cv) {
  219. // verify the string
  220. case '1':
  221. $s = ( preg_match($regexfull, $value) ? FALSE : TRUE );
  222. break;
  223. // cleanup the string
  224. case '2':
  225. $value = preg_replace($regexfull,'',$value);
  226. break;
  227. // if $cv is not specified or it's wrong
  228. default: if ( preg_match($regexfull, $value) ) $s = FALSE;
  229. }
  230. return ( $s ? $value : FALSE );
  231. }
  232. //-----------------------------------------------------------------------------
  233. /**
  234. * CLEANS AGAINST XSS
  235. *
  236. * NOTE all credits goes to codeigniter.com
  237. * @param string $str - string to check
  238. * @param string $charset - character set (default ISO-8859-1)
  239. * @return string|bool $value sanitized string
  240. */
  241. function ft_xss($str, $charset = 'ISO-8859-1') {
  242. /*
  243. * Remove Null Characters
  244. *
  245. * This prevents sandwiching null characters
  246. * between ascii characters, like Java\0script.
  247. *
  248. */
  249. $str = preg_replace('/\0+/', '', $str);
  250. $str = preg_replace('/(\\\\0)+/', '', $str);
  251. /*
  252. * Validate standard character entities
  253. *
  254. * Add a semicolon if missing. We do this to enable
  255. * the conversion of entities to ASCII later.
  256. *
  257. */
  258. $str = preg_replace('#(&\#*\w+)[\x00-\x20]+;#u',"\\1;",$str);
  259. /*
  260. * Validate UTF16 two byte encoding (x00)
  261. *
  262. * Just as above, adds a semicolon if missing.
  263. *
  264. */
  265. $str = preg_replace('#(&\#x*)([0-9A-F]+);*#iu',"\\1\\2;",$str);
  266. /*
  267. * URL Decode
  268. *
  269. * Just in case stuff like this is submitted:
  270. *
  271. * <a href="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">Google</a>
  272. *
  273. * Note: Normally urldecode() would be easier but it removes plus signs
  274. *
  275. */
  276. $str = preg_replace("/%u0([a-z0-9]{3})/i", "&#x\\1;", $str);
  277. $str = preg_replace("/%([a-z0-9]{2})/i", "&#x\\1;", $str);
  278. /*
  279. * Convert character entities to ASCII
  280. *
  281. * This permits our tests below to work reliably.
  282. * We only convert entities that are within tags since
  283. * these are the ones that will pose security problems.
  284. *
  285. */
  286. if (preg_match_all("/<(.+?)>/si", $str, $matches)) {
  287. for ($i = 0; $i < count($matches['0']); $i++) {
  288. $str = str_replace($matches['1'][$i],
  289. html_entity_decode($matches['1'][$i], ENT_COMPAT, $charset), $str);
  290. }
  291. }
  292. /*
  293. * Convert all tabs to spaces
  294. *
  295. * This prevents strings like this: ja vascript
  296. * Note: we deal with spaces between characters later.
  297. *
  298. */
  299. $str = preg_replace("#\t+#", " ", $str);
  300. /*
  301. * Makes PHP tags safe
  302. *
  303. * Note: XML tags are inadvertently replaced too:
  304. *
  305. * <?xml
  306. *
  307. * But it doesn't seem to pose a problem.
  308. *
  309. */
  310. $str = str_replace(array('<?php', '<?PHP', '<?', '?>'), array('&lt;?php', '&lt;?PHP', '&lt;?', '?&gt;'), $str);
  311. /*
  312. * Compact any exploded words
  313. *
  314. * This corrects words like: j a v a s c r i p t
  315. * These words are compacted back to their correct state.
  316. *
  317. */
  318. $words = array('javascript', 'vbscript', 'script', 'applet', 'alert', 'document', 'write', 'cookie', 'window');
  319. foreach ($words as $word) {
  320. $temp = '';
  321. for ($i = 0; $i < strlen($word); $i++) {
  322. $temp .= substr($word, $i, 1)."\s*";
  323. }
  324. $temp = substr($temp, 0, -3);
  325. $str = preg_replace('#'.$temp.'#s', $word, $str);
  326. $str = preg_replace('#'.ucfirst($temp).'#s', ucfirst($word), $str);
  327. }
  328. /*
  329. * Remove disallowed Javascript in links or img tags
  330. */
  331. $str = preg_replace("#<a.+?href=.*?(alert\(|alert&\#40;|javascript\:|window\.|document\.|\.cookie|<script|<xss).*?\>.*?</a>#si", "", $str);
  332. $str = preg_replace("#<img.+?src=.*?(alert\(|alert&\#40;|javascript\:|window\.|document\.|\.cookie|<script|<xss).*?\>#si","", $str);
  333. $str = preg_replace("#<(script|xss).*?\>#si", "", $str);
  334. /*
  335. * Remove JavaScript Event Handlers
  336. *
  337. * Note: This code is a little blunt. It removes
  338. * the event handler and anything up to the closing >,
  339. * but it's unlikely to be a problem.
  340. *
  341. */
  342. $str = preg_replace('#(<[^>]+.*?)(onblur|onchange|onclick|onfocus|onload|onmouseover|onmouseup|onmousedown|onselect|onsubmit|onunload|onkeypress|onkeydown|onkeyup|onresize)[^>]*>#iU',"\\1>",$str);
  343. /*
  344. * Sanitize naughty HTML elements
  345. *
  346. * If a tag containing any of the words in the list
  347. * below is found, the tag gets converted to entities.
  348. *
  349. * So this: <blink>
  350. * Becomes: &lt;blink&gt;
  351. *
  352. */
  353. $str = preg_replace('#<(/*\s*)(alert|applet|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|layer|link|meta|object|plaintext|style|script|textarea|title|xml|xss)([^>]*)>#is', "&lt;\\1\\2\\3&gt;", $str);
  354. /*
  355. * Sanitize naughty scripting elements
  356. *
  357. * Similar to above, only instead of looking for
  358. * tags it looks for PHP and JavaScript commands
  359. * that are disallowed. Rather than removing the
  360. * code, it simply converts the parenthesis to entities
  361. * rendering the code un-executable.
  362. *
  363. * For example: eval('some code')
  364. * Becomes: eval&#40;'some code'&#41;
  365. *
  366. */
  367. $str = preg_replace('#(alert|cmd|passthru|eval|exec|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2&#40;\\3&#41;", $str);
  368. /*
  369. * Final clean up
  370. *
  371. * This adds a bit of extra precaution in case
  372. * something got through the above filters
  373. *
  374. */
  375. $bad = array(
  376. 'document.cookie' => '',
  377. 'document.write' => '',
  378. 'window.location' => '',
  379. "javascript\s*:" => '',
  380. "Redirect\s+302" => '',
  381. '<!--' => '&lt;!--',
  382. '-->' => '--&gt;'
  383. );
  384. foreach ($bad as $key => $val) {
  385. $str = preg_replace("#".$key."#i", $val, $str);
  386. }
  387. return $str;
  388. }
  389. //-----------------------------------------------------------------------------
  390. /**
  391. * DISPLAY ERRORS
  392. *
  393. * @param int $mode - if 1 then echo the string; if 2 then echo the string
  394. * @return void
  395. */
  396. function display_error($mode = 1) {
  397. $errstr = ( $this->error ) ? $this->error : '';
  398. if ( $mode == 1 ) {
  399. echo '<br />' .$this->ft_xss($errstr) . '<br />';
  400. } else {
  401. return $this->ft_xss($errstr);
  402. }
  403. }
  404. //-----------------------------------------------------------------------------
  405. /**
  406. * REAL COMPARASION BETWEEN FLOATS
  407. *
  408. * 0 - for ==, 1 for r1 > r2, -1 for r1 '<' r2
  409. *
  410. * @param float $r1
  411. * @param float $r2
  412. * @return int
  413. */
  414. function ft_realcmp($r1, $r2) {
  415. $diff = $r1 - $r2;
  416. if ( abs($diff) < EPSILON ) return 0;
  417. else return $diff < 0 ? -1 : 1;
  418. }
  419. //-----------------------------------------------------------------------------
  420. } // class
  421. ?>