PageRenderTime 54ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/HTML/QuickForm.php

#
PHP | 506 lines | 435 code | 43 blank | 28 comment | 60 complexity | a9ca5a935218fdeda9b22f677408e879 MD5 | raw file
Possible License(s): AGPL-3.0, GPL-2.0
  1. <?php /*-*-PHP-*-*/
  2. /*
  3. Quick HTML_QuickForm clone without the GPL-incompatible license
  4. Copyright (C) 2007, 2009 Cliss XXI
  5. Copyright (C) 2007 Sylvain Beucler
  6. This file is part of GCourrier.
  7. GCourrier is free software: you can redistribute it and/or modify
  8. it under the terms of the GNU Affero General Public License as
  9. published by the Free Software Foundation, either version 3 of the
  10. License, or (at your option) any later version.
  11. GCourrier is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU Affero General Public License for more details.
  15. You should have received a copy of the GNU Affero General Public License
  16. along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. class GPLQuickForm_Element
  19. {
  20. private $name = '';
  21. private $type = NULL;
  22. private $constant = NULL;
  23. private $default = NULL;
  24. private $value = NULL;
  25. private $frozen = false;
  26. private $label = '';
  27. private $error = '';
  28. private $select_options = array();
  29. public function __construct($type, $name, $params)
  30. {
  31. $this->type = $type;
  32. $this->name = $name;
  33. switch($this->type)
  34. {
  35. case "header":
  36. case "date":
  37. case "password":
  38. case "submit":
  39. case "text":
  40. case "checkbox":
  41. case "textarea":
  42. if (isset($params[0]))
  43. $this->label = $params[0];
  44. break;
  45. case "hidden":
  46. if (isset($params[0]))
  47. $this->default = $params[0];
  48. break;
  49. case "select":
  50. $this->label = $params[0];
  51. $this->select_options = $params[1];
  52. break;
  53. }
  54. }
  55. public function setLabel($text)
  56. {
  57. $this->label = $text;
  58. }
  59. public function setText($text)
  60. {
  61. $this->setLabel($text);
  62. }
  63. public function setError($text)
  64. {
  65. $this->error = $text;
  66. }
  67. public function getError()
  68. {
  69. return $this->error;
  70. }
  71. public function getValue()
  72. {
  73. if ($this->constant !== NULL)
  74. return $this->constant;
  75. if ($this->value !== NULL)
  76. return $this->value;
  77. return $this->default;
  78. }
  79. private function dateConvert($str)
  80. {
  81. list($year, $month, $day) = split('-', $str);
  82. return array('d' => $day, 'M' => $month, 'Y' => $year);
  83. }
  84. public function setValue($value)
  85. {
  86. if ($this->type == 'date' and is_string($value))
  87. $value = $this->dateConvert($value);
  88. $this->value = $value;
  89. }
  90. public function setDefault($default)
  91. {
  92. if ($this->type == 'date' and is_string($default))
  93. $default = $this->dateConvert($default);
  94. $this->default = $default;
  95. }
  96. public function setConstant($constant)
  97. {
  98. if ($this->type == 'date' and is_string($constant))
  99. $constant = $this->dateConvert($constant);
  100. $this->constant = $constant;
  101. }
  102. public function freeze()
  103. {
  104. $this->frozen = true;
  105. }
  106. public function display()
  107. {
  108. // Don't use $this->value directly, to take constants into account
  109. $value = $this->getValue();
  110. if ($this->type == 'header')
  111. {
  112. print "<tr><td colspan=2 style='background: lightgrey;"
  113. . " text-align: left; font-weight: bold'>"
  114. . "{$this->label}</td></tr>";
  115. }
  116. else if ($this->type == 'submit')
  117. {
  118. $disabled = "";
  119. if ($this->frozen)
  120. $disabled = 'disabled="disabled"';
  121. print "<tr><td></td><td class='element'>";
  122. print "<input type='submit'"
  123. . " name='{$this->name}' value='{$this->label}' $disabled />";
  124. print '</td></tr>';
  125. }
  126. else if ($this->type == 'hidden')
  127. {
  128. print "<input type='hidden' name='{$this->name}' value='$value' />";
  129. }
  130. else
  131. {
  132. print '<tr>';
  133. print "<td class='label'>{$this->label}</td>";
  134. print "<td class='element'>";
  135. if (!empty($this->error))
  136. print "<span class='error'>$this->error</span><br />";
  137. switch($this->type)
  138. {
  139. case 'date':
  140. if ($this->frozen)
  141. {
  142. print $value['d'];
  143. print "<input type='hidden' name='{$this->name}[d]' value='{$value['d']}' />";
  144. print " ";
  145. $month = mktime(0, 0, 0, $value['M'], 1, 2001);
  146. print strftime('%b', $month);
  147. print "<input type='hidden' name='{$this->name}[M]' value='{$value['M']}' />";
  148. print " ";
  149. print $value['Y'];
  150. print "<input type='hidden' name='{$this->name}[Y]' value='{$value['Y']}' />";
  151. }
  152. else
  153. {
  154. print "<select name='{$this->name}[d]'>";
  155. for ($i = 1; $i <= 31; $i++)
  156. {
  157. $label = $i;
  158. if ($i < 10)
  159. $label = "0$label";
  160. $selected = '';
  161. if ($i == $value['d'])
  162. $selected = 'selected="selected"';
  163. print "<option value='$i' $selected>$label</option>";
  164. }
  165. print "</select>";
  166. print "<select name='{$this->name}[M]'>";
  167. for ($i = 1; $i <= 12; $i++)
  168. {
  169. $month = mktime(0, 0, 0, $i, 1, 2001);
  170. $selected = '';
  171. if ($i == $value['M'])
  172. $selected = 'selected="selected"';
  173. print "<option value='$i' $selected>".strftime('%b', $month)."</option>";
  174. }
  175. print "</select>";
  176. print "<select name='{$this->name}[Y]'>";
  177. for ($i = 2001; $i <= intval(date('Y')) + 3; $i++)
  178. {
  179. $selected = '';
  180. if ($i == $value['Y'])
  181. $selected = 'selected="selected"';
  182. print "<option value='$i' $selected>$i</option>";
  183. }
  184. print "</select>";
  185. }
  186. break;
  187. case 'password':
  188. if ($this->frozen)
  189. print "*****";
  190. else
  191. print "<input type='password' name='{$this->name}' value='" . htmlspecialchars($value, ENT_QUOTES) . "' />";
  192. break;
  193. case 'text':
  194. if ($this->frozen)
  195. {
  196. print "$value";
  197. print "<input type='hidden' name='{$this->name}' value='" . htmlspecialchars($value, ENT_QUOTES) . "' />";
  198. }
  199. else
  200. {
  201. print "<input type='text' name='{$this->name}' value='" . htmlspecialchars($value, ENT_QUOTES) . "' />";
  202. }
  203. break;
  204. case 'select':
  205. if ($this->frozen)
  206. {
  207. if ($value != NULL)
  208. {
  209. print $this->select_options[$value];
  210. print "<input type='hidden' name='{$this->name}' value='$value' />";
  211. }
  212. }
  213. else
  214. {
  215. print "<select name='{$this->name}'>";
  216. foreach($this->select_options as $id => $text)
  217. {
  218. $selected = '';
  219. if ($id == $value)
  220. $selected = "selected='selected'";
  221. print "<option value='$id' $selected>$text</option>";
  222. }
  223. print "</select>";
  224. }
  225. break;
  226. case 'textarea':
  227. $readonly = "";
  228. if ($this->frozen)
  229. $readonly = "readonly='readonly'";
  230. print "<textarea name='{$this->name}' wrap='virtual' cols='60' rows='10' $readonly>"
  231. . htmlspecialchars($value, ENT_QUOTES)
  232. . "</textarea>";
  233. break;
  234. case 'checkbox':
  235. $checked = "";
  236. if ($value)
  237. $checked = 'checked="checked"';
  238. $disabled = "";
  239. if ($this->frozen)
  240. $disabled = 'disabled="disabled"';
  241. print "<input type='checkbox' name='{$this->name}' value='1' $checked $disabled />";
  242. break;
  243. }
  244. print '</td>';
  245. print '</tr>';
  246. }
  247. }
  248. }
  249. class GPLQuickForm
  250. {
  251. private $name = '';
  252. private $method = '';
  253. private $in = array();
  254. private $requiredNote = '<span style="font-size: smaller"><span style="color: red">*</span> required field</span>';
  255. private $jsWarnings_pref = 'The form is not valid';
  256. private $jsWarnings_post = '';
  257. private $elements = array();
  258. private $rules = array();
  259. public function __construct($name='', $method='post')
  260. {
  261. $this->name = $name;
  262. $this->method = $method;
  263. switch ($method)
  264. {
  265. case "get":
  266. $this->in = $_GET;
  267. break;
  268. case 'post':
  269. default:
  270. $this->in = $_POST;
  271. break;
  272. }
  273. }
  274. public function setRequiredNote($html_text)
  275. {
  276. $this->requiredNote = $html_text;
  277. }
  278. public function setJsWarnings($pref, $post)
  279. {
  280. $this->jsWarnings_pref = $pref;
  281. $this->jsWarnings_post = $post;
  282. }
  283. public function addElement()
  284. {
  285. $arg_list = func_get_args();
  286. $type = array_shift($arg_list);
  287. $name = array_shift($arg_list);
  288. $params = $arg_list;
  289. if (!is_string($type))
  290. throw new Exception("Adding elements as objects not supported");
  291. $this->elements_debug[$name] = array($type, $arg_list);
  292. $this->elements[$name] = new GPLQuickForm_Element($type, $name, $params);
  293. // Set the value from $_GET/$_POST if available
  294. if (isset($this->in[$name]))
  295. $this->elements[$name]->setValue($this->in[$name]);
  296. }
  297. public function getElement($name)
  298. {
  299. return $this->elements[$name];
  300. }
  301. public function getElementError($name)
  302. {
  303. return $this->elements[$name]->getError();
  304. }
  305. public function setConstants($constants)
  306. {
  307. foreach($constants as $name => $value)
  308. {
  309. if (isset($this->elements[$name]))
  310. $this->elements[$name]->setConstant($value);
  311. }
  312. }
  313. public function setDefaults($defaults)
  314. {
  315. foreach($defaults as $name => $value)
  316. {
  317. if (isset($this->elements[$name]))
  318. $this->elements[$name]->setDefault($value);
  319. }
  320. }
  321. public function exportValue($name)
  322. {
  323. return $this->elements[$name]->getValue();
  324. }
  325. public function exportValues()
  326. {
  327. $retval = array();
  328. foreach ($this->elements as $name => $object)
  329. $retval[$name] = $object->getValue();
  330. return $retval;
  331. }
  332. public function freeze($elts_to_freeze=null)
  333. {
  334. if ($elts_to_freeze == NULL)
  335. $elts_to_freeze = array_keys($this->elements);
  336. else if (!is_array($elts_to_freeze))
  337. $elts_to_freeze = array($elts_to_freeze);
  338. foreach ($elts_to_freeze as $name)
  339. $this->elements[$name]->freeze();
  340. }
  341. public function applyFilter($name, $callback)
  342. {
  343. $elt = $this->elements[$name];
  344. $old_value = $elt->getValue();
  345. if ($old_value !== NULL)
  346. {
  347. $new_value = call_user_func($callback, $old_value);
  348. $elt->setValue($new_value);
  349. }
  350. }
  351. // string $element, string $message, string $type, [string $format = null], [string $validation = 'server'], [boolean $reset = false], [boolean $force = false]
  352. public function addRule($name, $error_message, $type, $type_param=null, $side='server')
  353. {
  354. $this->rules[] = array($name, $error_message, $type, $type_param, $side);
  355. }
  356. public function validate()
  357. {
  358. $elt_is_valid = array();
  359. $form_is_valid = true;
  360. if (empty($this->in))
  361. // form not submitted yet
  362. return false;
  363. foreach($this->rules as $rule)
  364. {
  365. list ($name, $error_message, $type, $type_param, $side) = $rule;
  366. if (is_array($name))
  367. {
  368. $name_array = $name;
  369. $name = $name_array[0];
  370. }
  371. if (!isset($elt_is_valid[$name]))
  372. $elt_is_valid[$name] = true;
  373. $elt = $this->elements[$name];
  374. if ($elt_is_valid[$name])
  375. {
  376. $rule_is_valid = false;
  377. if (!is_array($name))
  378. {
  379. $value = $elt->getValue();
  380. }
  381. switch($type)
  382. {
  383. case 'callback':
  384. $callback = $type_param;
  385. $rule_is_valid = call_user_func($callback, $value);
  386. break;
  387. case 'required':
  388. $rule_is_valid = !empty($value);
  389. break;
  390. case 'regex':
  391. $pattern = $type_param;
  392. $rule_is_valid = preg_match($pattern, $value) > 0;
  393. break;
  394. case 'nonzero':
  395. $rule_is_valid = !preg_match('/^0/', $value);
  396. break;
  397. case 'lettersonly':
  398. $rule_is_valid = preg_match('/^[a-zA-Z]*$/', $value);
  399. break;
  400. case 'alphanumeric':
  401. $rule_is_valid = preg_match('/^[a-zA-Z0-9]*$/', $value);
  402. break;
  403. case 'minlength':
  404. $rule_is_valid = (strlen($value) >= $type_param);
  405. break;
  406. case 'maxlength':
  407. $rule_is_valid = (strlen($value) <= $type_param);
  408. break;
  409. case 'rangelength':
  410. $rule_is_valid = (strlen($value) >= $type_param[0]
  411. && strlen($value) <= $type_param[1]);
  412. break;
  413. case 'compare':
  414. $name2 = $name_array[1];
  415. $elt2 = $this->elements[$name2];
  416. $value2 = $elt2->getValue();
  417. $rule_is_valid = ($value == $value2);
  418. break;
  419. default:
  420. die("Unsupported rule type: $type");
  421. }
  422. if (!$rule_is_valid)
  423. {
  424. $form_is_valid = false;
  425. $elt_is_valid[$name] = false;
  426. $elt->setError($error_message);
  427. }
  428. }
  429. }
  430. return $form_is_valid;
  431. }
  432. public function display()
  433. {
  434. print "<form id='$this->name' action='{$_SERVER['PHP_SELF']}' method='$this->method'>";
  435. print "
  436. <style type='text/css'><!--
  437. #$this->name .label {
  438. text-align: right;
  439. font-weight: bold;
  440. }
  441. #$this->name .element {
  442. text-align: left;
  443. }
  444. #$this->name .error {
  445. color: red;
  446. }
  447. // -->
  448. </style>
  449. ";
  450. print '<table>';
  451. foreach ($this->elements as $element)
  452. $element->display();
  453. $there_is_a_required_field = 1;
  454. if ($there_is_a_required_field)
  455. print "<tr><td /><td class='element'>$this->requiredNote</td></tr>";
  456. print '</table>';
  457. print "</form>";
  458. }
  459. }