*/ error_reporting (E_ALL); /** This class permit to create easily some forms to HTML (or text mode in future). Each field can be checked in AJAX or HTML. */ class form { /** All the fields */ private $fields = NULL; /** The name of the form */ private $formName; /** Allow to debug the PHP */ public $debug=0; /** CSRF protection By default, the CSRF protection is active if a SESSION is active too. It can be disabled if needed. An Exception is raised if the form is send back without the token */ public $csrf=TRUE; /** Name of the CSRF hidden field in HTML page */ public $csrfField = "CSRF_TOKEN"; /** The method used to send the values */ private $method = "post"; /** Create a form @param string|null $formName The form name */ public function __construct ($formName = "form") { $this->formName = $formName; } /** Save the fields into the structure. Available : - name : name of the field in the HTML page - label : label written to the describe the field - [titles] : text written in radio/checkboxes - [defaults] : default values. Must be array for checkbox/select, and string for others - [type] : text, password, hidden, checkbox, select, radio, submit text by default - [multiple] : Multiple selection are possible (if the type supports it) - [group] : define a fieldset and define the title with groupe name Warning : all the elements of the same group must be consecutive ! - [readonly] : put a read-only flag on the field (the user see it but can't interract on it. The value will be sent to next page - [verify] : Tests to verify with error priority and associated message (%s is replaced by field selected value). Order test from main tests to minor tests. \$tmpfield can be used as a copy of the current field, to check the defaults per example - [mandatory] : boolean to add a red star at end of label @param array $fields The fields to be displayed */ public function fields ($fields) { $this->fields = $fields; } /** Return the values provided by the user. Test the CSRF before continue NEVER read the values from $_POST in your codes or CSRF will not be checked */ public function values () { $values = array (); if ($this->method === "post") { if (isset ($_POST[$this->formName])) $values = $_POST[$this->formName]; } elseif ($this->method === "get") { if (isset ($_GET[$this->formName])) $values = $_GET[$this->formName]; } else { throw new Exception (_("Unknown FORM method (GET or POST allowed)")); } if (count ($values) !== 0) { // CSRF protection try { $this->checkToken ($values[$this->csrfField]); } catch (Exception $e) { throw new Exception ($e->getMessage(), 500); } // Remove the field CSRF : can not be used outside the form unset ($values[$this->csrfField]); } return $values; } /** Return TRUE if the value associated to a field is correct. Return an array with a severity and a message to explain why a field is not correct. Fields can be an array with just one element, then only this element is checked @param array $fieldsVerify The fields to verify @param array|null $valuesVerify The values of the fields to verify */ public function verify (&$fieldsVerify, $valuesVerify = NULL) { // TODO : Remove this function or be cleaner ! die ("FORM/VERIFY : UNUSED and dirty\n"); $ret = array (); if ($this->debug) echo "
";
foreach ($fieldsVerify as $field)
{
if (!isset ($field->verify))
continue;
if (!isset ($valuesVerify[$field->name]))
throw new Exception ("No value provided for $field->name", 500);
foreach ($field->verify as $test => $message)
{
$func = sprintf ($test, addslashes ($valuesVerify[$field->name]));
if ($this->debug)
echo "VERIFY: \"$func\" => ";
$tmpfield = $field;
$res = addslashes (serialize ($tmpfield));
// TODO : http://fr2.php.net/manual/en/reflectionfunction.invokeargs.php
// to remove eval ?
$rc = eval ("\$tmpfield=unserialize(stripslashes('$res'));".
"return $func;");
if ($this->debug)
var_dump ($rc);
if ($rc !== FALSE)
{
$ret[$field->name] = $message;
$field->error = $message;
break;
}
}
}
if ($this->debug)
{
echo "RESULT: ";
var_dump ($ret);
echo "";
}
return $ret;
}
/** Return the fields in HTML code. If $values is provided, use it in place
of default values. In case of select boxes, $values are the selected
elements
$method is the method written in method field of \n";
return $res;
}
/** Check the token from the user
@param string $tokenFromUser The value form the user's token */
public function checkToken ($tokenFromUser)
{
$csrf = new csrf ();
$csrf->field = $this->csrfField;
$csrf->checkToken ($tokenFromUser);
}
}
/** the definition of a formfield */
class formfield
{
/** The name of the field */
public $name;
/** The label of the field */
public $label;
/** The titles of the field */
public $titles;
/** The defaults values of the field */
public $defaults;
/** The type of the field (text, password, checkbox, select)*/
public $type;
/** The multiplicity of selection of the field (available in select only)*/
public $multiple;
/** The name of group for the fields */
public $group;
/** The read-only feature of the field */
public $readonly;
/** The fonction used to verify the field by AJAX before submitting and
by PHP after submission*/
public $verify;
/** The statut of error of the field */
public $error;
/** When adding a field, the name and the label are the minimum mandatory
@param string $name Name of the field
@param string $label Label of the field */
function __construct ($name, $label)
{
$this->name = $name;
$this->label = $label;
}
}
/** CSRF protection
By default, the CSRF protection is active if a SESSION is active too.
It can be disabled if needed. An Exception is raised if the form is send
back without the token */
class csrf
{
/** Allow to disable the csrf protection */
public $csrf=TRUE;
/** This hidden field name in HTML */
public $field = "CSRF_TOKEN";
/** The created token */
private $csrfToken = "";
/** Timeout of the CSRF token : 3600s by default (maximum time allowed to
enter information in form and submit) */
private $csrfTimeout = 3600;
/** This function return the token */
public function createToken ()
{
$l = 30; // Number of chars in token
$c = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for ($s = '',
$cl = strlen($c)-1, $i = 0; $i < $l; $s .= $c[mt_rand(0, $cl)],
++$i);
$this->csrfToken = $s;
$_SESSION["domframework"]["form"]["csrf"] = $this->csrfToken;
$_SESSION["domframework"]["form"]["csrfStart"] = microtime (TRUE);
}
/** Check if the provided token is the right token, defined last displayed
page
@param string $tokenFromUser The value form the user's token */
public function checkToken ($tokenFromUser)
{
if ($this->csrf === FALSE )
return TRUE;
if (! isset ($_SESSION["domframework"]["form"]["csrf"]))
throw new Exception (_("No previous CSRF token : abort"));
if ($_SESSION["domframework"]["form"]["csrf"] !== $tokenFromUser)
throw new Exception (_("Invalid CSRF token provided"));
if (($_SESSION["domframework"]["form"]["csrfStart"] + $this->csrfTimeout) <
microtime (TRUE))
throw new Exception (_("Obsolete CSRF token provided"));
return TRUE;
}
/** Return the CSRF token in a hidden field */
public function displayFormCSRF ()
{
if ($this->csrfToken == "")
$this->createToken ();
$res = "