PageRenderTime 59ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/saf/lib/MailForm/Rule.php

https://github.com/lux/sitellite
PHP | 458 lines | 249 code | 16 blank | 193 comment | 121 complexity | ab832d5cf5cc88faa05b32b8d001c4e4 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0, GPL-3.0
  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | Sitellite Content Management System |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 2010 Sitellite.org Community |
  7. // +----------------------------------------------------------------------+
  8. // | This software is released under the GNU GPL License. |
  9. // | Please see the accompanying file docs/LICENSE for licensing details. |
  10. // | |
  11. // | You should have received a copy of the GNU GPL License |
  12. // | along with this program; if not, visit www.sitellite.org. |
  13. // | The license text is also available at the following web site |
  14. // | address: <http://www.sitellite.org/index/license |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: John Luxford <john.luxford@gmail.com> |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // Handles validation of form fields for the MailForm package.
  20. //
  21. /**
  22. * Handles validation of form fields for the MailForm package.
  23. *
  24. * Rule Format:
  25. *
  26. * type "value"
  27. *
  28. * Validation Rules:
  29. * - is "value"
  30. * - contains "some value"
  31. * - regex "some regex" -- uses ereg()
  32. * - preg "/some regex/" -- uses preg_match()
  33. * - equals "anotherfield"
  34. * - empty
  35. * - length "6+" (eg: 6, 6+, 6-12, 12-)
  36. * - gt "value"
  37. * - ge "value"
  38. * - lt "value"
  39. * - le "value"
  40. * - func "func_name" (or function "func_name")
  41. * - unique "dbtablename.columnname"
  42. * - exists "path/to/directory"
  43. * - numeric
  44. * - email
  45. * - header
  46. *
  47. * Note: Any rule may be negated by preceeding it with a 'not', for example:
  48. * - not empty
  49. * - not contains "some value"
  50. *
  51. * New in 1.2:
  52. * - Added a 'unique' rule, which compares the value against a specified field
  53. * in a database table.
  54. * - Fixed a bug in the 'length' rule evaluation.
  55. *
  56. * New in 1.4:
  57. * - Added 'exists' and 'not exists' rules, which checks if the value given
  58. * exists (or doesn't) as a file name in the path provided by the rule.
  59. *
  60. * New in 1.6:
  61. * - Abstracted 'not empty' and 'not exists' so that 'not' now negates any
  62. * rule, and 'empty' and 'exists' are ordinary rules now. This required
  63. * the addition of two new methods, _validate(), and _validateNegated(),
  64. * and a new $negated property.
  65. *
  66. * New in 1.8:
  67. * - Added warning notices when rules fail the syntax parser.
  68. * - Added new rule type "numeric", which checks the data type of the value
  69. * to see whether it is a valid number or not.
  70. *
  71. * New in 2.0:
  72. * - New rules: 'email' and 'header' which help prevent form abuse by spammers.
  73. * 'email' checks that it is a valid email, and 'header' checks that there
  74. * are no newlines in the field so that it can't pass extra headers to your
  75. * mail() function.
  76. *
  77. * New in 2.2:
  78. * - New rule 'preg' uses preg_match() instead of ereg(). Be sure to include
  79. * slashes in the regular expression now.
  80. * - Custom validation functions can receive the field name as a second parameter.
  81. * e.g. function custom_validation_rule ($values, $field) {}
  82. *
  83. * <code>
  84. * <?php
  85. *
  86. * $widget = new MF_Widget ('name');
  87. * $widget->addRule ('is "foo"', 'You must enter "foo" to pass!');
  88. *
  89. * // note: MailFormRule is never accessed directly.
  90. *
  91. * ? >
  92. * </code>
  93. *
  94. * @package MailForm
  95. * @author John Luxford <john.luxford@gmail.com>
  96. * @license http://www.sitellite.org/index/license GNU GPL License
  97. * @version 2.2, 2008-10-25, $Id: Rule.php,v 1.5 2007/10/06 00:06:30 lux Exp $
  98. * @access public
  99. *
  100. */
  101. class MailFormRule {
  102. /**
  103. * The original unmodified rule definition.
  104. *
  105. * @access public
  106. *
  107. */
  108. var $rule;
  109. /**
  110. * The name of the widget.
  111. *
  112. * @access public
  113. *
  114. */
  115. var $name;
  116. /**
  117. * The error message for this rule.
  118. *
  119. * @access public
  120. *
  121. */
  122. var $msg;
  123. /**
  124. * The rule type. Can be 'is', 'contains', 'regex', 'not empty',
  125. * 'equals', 'length', 'gt', 'ge', 'lt', 'le', or 'func'.
  126. *
  127. * @access public
  128. *
  129. */
  130. var $type;
  131. /**
  132. * The rule value. This corresponds to the part of the rule
  133. * in double quotes (ie. type "value").
  134. *
  135. * @access public
  136. *
  137. */
  138. var $value;
  139. /**
  140. * If a 'not' is present at the start of the rule, this will be
  141. * set to true, otherwise false.
  142. *
  143. * @access public
  144. *
  145. */
  146. var $negated = false;
  147. /**
  148. * Constructor Method.
  149. *
  150. * @access public
  151. * @param string $rule
  152. * @param string $name
  153. * @param string $msg
  154. *
  155. */
  156. function MailFormRule ($rule, $name, $msg = '') {
  157. $this->rule = $rule;
  158. $this->name = $name;
  159. if (! empty ($msg)) {
  160. $this->msg = $msg;
  161. } else {
  162. $this->msg = 'Oops! The following field was not filled in correctly: ' . $this->name . '. Please fix this to continue.';
  163. }
  164. $this->parseRuleStatement ($rule);
  165. }
  166. /**
  167. * Parses the original rule into the $type and $value properties.
  168. *
  169. * @access public
  170. * @param string $rule
  171. *
  172. */
  173. function parseRuleStatement ($rule) {
  174. if (preg_match ('/^(not )?(empty|length|unique|contains|func|function|regex|preg|equals|is|gt|lt|ge|le|exists|numeric|alpha|email|header|ext)( ("|\')(.*)\4)?$/', $rule, $regs)) {
  175. if ($regs[2] == 'function') {
  176. $this->type = 'func';
  177. } else {
  178. $this->type = $regs[2];
  179. }
  180. if ($regs[1] == 'not ') {
  181. $this->negated = true;
  182. }
  183. $this->value = $regs[5];
  184. } else {
  185. trigger_error ('Invalid MailForm rule (' . $this->name . '): ' . $rule, E_USER_WARNING);
  186. }
  187. }
  188. /**
  189. * Validates the value given against itself. Returns false on
  190. * failure and true on success.
  191. *
  192. * @access public
  193. * @param string $value
  194. * @param object $form
  195. * @param object $cgi
  196. * @return boolean
  197. *
  198. */
  199. function validate ($value, $form, $cgi) {
  200. if ($this->negated) {
  201. return $this->_validateNegated ($value, $form, $cgi);
  202. } else {
  203. return $this->_validate ($value, $form, $cgi);
  204. }
  205. }
  206. /**
  207. * Validates the value given against itself. Returns false on
  208. * failure and true on success.
  209. *
  210. * @access public
  211. * @param string $value
  212. * @param object $form
  213. * @param object $cgi
  214. * @return boolean
  215. *
  216. */
  217. function _validate ($value, $form, $cgi) {
  218. if ($this->type == 'empty') {
  219. if (! empty ($value)) {
  220. return false;
  221. }
  222. } elseif ($this->type == 'length') {
  223. if (preg_match ('/^([0-9]+)([+-]?)([0-9]*)$/', $this->value, $regs)) {
  224. if (! empty ($regs[3])) {
  225. if (strlen ($value) < $regs[1] || strlen ($value) > $regs[3]) {
  226. return false;
  227. }
  228. } elseif ($regs[2] == '+' && strlen ($value) < $regs[1]) {
  229. return false;
  230. } elseif ($regs[2] == '-' && strlen ($value) > $regs[1]) {
  231. return false;
  232. } elseif (empty ($regs[2]) && strlen ($value) != $regs[1]) {
  233. return false;
  234. }
  235. }
  236. } elseif ($this->type == 'unique') {
  237. list ($table, $column) = preg_split ('/[\.:\/]/', $this->value);
  238. global $db;
  239. $res = $db->fetch ('select ' . $column . ' from ' . $table . ' where ' . $column . ' = ??', $value);
  240. if ($db->rows > 0) {
  241. // it's not unique
  242. return false;
  243. } elseif (! $res && $db->error) {
  244. return false;
  245. }
  246. } elseif ($this->type == 'exists') {
  247. if (! empty ($value)) {
  248. if (! @file_exists ($this->value . '/' . $value)) {
  249. // file name does not exist
  250. return false;
  251. }
  252. }
  253. } elseif ($this->type == 'contains') {
  254. if (! stristr ($value, $this->value)) {
  255. return false;
  256. }
  257. } elseif ($this->type == 'func') {
  258. $GLOBALS['mailform_current_form'] =& $form;
  259. $func = $this->value;
  260. if (! $func ($form->getValues ($cgi), $this->name)) {
  261. return false;
  262. }
  263. } elseif ($this->type == 'regex') {
  264. // Fix for issue #185
  265. // This MIGHT introduce a new bug
  266. $new_regex = "/" . $this->value . "/";
  267. if (! preg_match ($new_regex, $value)) {
  268. return false;
  269. }
  270. } elseif ($this->type == 'preg') {
  271. if (! preg_match ($this->value, $value)) {
  272. return false;
  273. }
  274. } elseif ($this->type == 'equals') {
  275. if ($value != $form->widgets[$this->value]->getValue ($cgi)) {
  276. return false;
  277. }
  278. } elseif ($this->type == 'is') {
  279. if ($value != $this->value) {
  280. return false;
  281. }
  282. } elseif ($this->type == 'gt') {
  283. if ($value <= $this->value) {
  284. return false;
  285. }
  286. } elseif ($this->type == 'lt') {
  287. if ($value >= $this->value) {
  288. return false;
  289. }
  290. } elseif ($this->type == 'ge') {
  291. if ($value < $this->value) {
  292. return false;
  293. }
  294. } elseif ($this->type == 'le') {
  295. if ($value > $this->value) {
  296. return false;
  297. }
  298. } elseif ($this->type == 'numeric') {
  299. if (! is_numeric ($value)) {
  300. return false;
  301. }
  302. } elseif ($this->type == 'alpha') {
  303. if (!preg_match("/^([a-zA-Z]*)$/",$value)) {
  304. return false;
  305. }
  306. } elseif ($this->type == 'email') {
  307. if (strpos ($value, '.@') !== false) {
  308. return false;
  309. } elseif (preg_match ('/\.$/', $value)) {
  310. return false;
  311. } elseif (! preg_match ("/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+\.([a-zA-Z0-9\._-]+)+$/" , $value)) {
  312. return false;
  313. }
  314. } elseif ($this->type == 'header') {
  315. if (preg_match ("/[\r\n]/s" , $value)) {
  316. return false;
  317. }
  318. }
  319. elseif ($this->type == 'ext') {
  320. $compare = end(explode(".", $value->name));
  321. if ($compare != $this->value && !empty($compare)) {
  322. unset($compare);
  323. return false;
  324. }
  325. }
  326. return true;
  327. }
  328. /**
  329. * Validates the value given against itself. Returns false on
  330. * failure and true on success.
  331. *
  332. * @access public
  333. * @param string $value
  334. * @param object $form
  335. * @param object $cgi
  336. * @return boolean
  337. *
  338. */
  339. function _validateNegated ($value, $form, $cgi) {
  340. if ($this->type == 'empty') {
  341. if (empty ($value)) {
  342. return false;
  343. }
  344. } elseif ($this->type == 'length') {
  345. if (preg_match ('/^([0-9]+)([+-]?)([0-9]*)$/', $this->value, $regs)) {
  346. if (! empty ($regs[3])) {
  347. if (strlen ($value) >= $regs[1] || strlen ($value) <= $regs[3]) {
  348. return false;
  349. }
  350. } elseif ($regs[2] == '+' && strlen ($value) >= $regs[1]) {
  351. return false;
  352. } elseif ($regs[2] == '-' && strlen ($value) <= $regs[1]) {
  353. return false;
  354. } elseif (empty ($regs[2]) && strlen ($value) == $regs[1]) {
  355. return false;
  356. }
  357. }
  358. } elseif ($this->type == 'unique') {
  359. list ($table, $column) = preg_split ('/[\.:\/]/', $this->value);
  360. global $db;
  361. $res = $db->fetch ('select ' . $column . ' from ' . $table . ' where ' . $column . ' = ??', $value);
  362. if ($db->rows <= 0) {
  363. // it's not unique
  364. return false;
  365. } elseif (! $res && $db->error) {
  366. return false;
  367. }
  368. } elseif ($this->type == 'exists') {
  369. if (! empty ($value)) {
  370. if (@file_exists ($this->value . '/' . $value)) {
  371. // file name does not exist
  372. return false;
  373. }
  374. }
  375. } elseif ($this->type == 'contains') {
  376. if (stristr ($value, $this->value)) {
  377. return false;
  378. }
  379. } elseif ($this->type == 'func') {
  380. $func = $this->value;
  381. if ($func ($form->getValues ($cgi), $this->name)) {
  382. return false;
  383. }
  384. } elseif ($this->type == 'regex') {
  385. if (preg_match ($this->value, $value)) {
  386. return false;
  387. }
  388. } elseif ($this->type == 'preg') {
  389. if (preg_match ($this->value, $value)) {
  390. return false;
  391. }
  392. } elseif ($this->type == 'equals') {
  393. if ($value == $form->widgets[$this->value]->getValue ($cgi)) {
  394. return false;
  395. }
  396. } elseif ($this->type == 'is') {
  397. if ($value == $this->value) {
  398. return false;
  399. }
  400. } elseif ($this->type == 'gt') {
  401. if ($value > $this->value) {
  402. return false;
  403. }
  404. } elseif ($this->type == 'lt') {
  405. if ($value < $this->value) {
  406. return false;
  407. }
  408. } elseif ($this->type == 'ge') {
  409. if ($value >= $this->value) {
  410. return false;
  411. }
  412. } elseif ($this->type == 'le') {
  413. if ($value <= $this->value) {
  414. return false;
  415. }
  416. } elseif ($this->type == 'numeric') {
  417. if (is_numeric ($value)) {
  418. return false;
  419. }
  420. } elseif ($this->type == 'alpha') {
  421. if (preg_match("/^([a-zA-Z]*)$/",$value)) {
  422. return false;
  423. }
  424. } elseif ($this->type == 'email') {
  425. if (strpos ($value, '.@') === false && ! preg_match ('/\.$/', $value) && preg_match ("/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+\.([a-zA-Z0-9\._-]+)+$/" , $value)) {
  426. return false;
  427. }
  428. } elseif ($this->type == 'header') {
  429. if (! preg_match ("/[\r\n]/s" , $value)) {
  430. return false;
  431. }
  432. } elseif ($this->type == 'ext') {
  433. $compare = end(explode(".", $value->name));
  434. if ($compare == $this->value && !empty($compare)) {
  435. unset($compare);
  436. return false;
  437. }
  438. }
  439. return true;
  440. }
  441. }
  442. ?>