From c01a476a9a85907b74e7d838aa26554311c7c48f Mon Sep 17 00:00:00 2001 From: Dominique Fournier Date: Wed, 24 Oct 2018 12:56:55 +0000 Subject: [PATCH] dblayeroo : Add the "realTypes" support with basic associated tests. If the user want some custom tests, it must extends the class and create checkRealType_XXX tests git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@4621 bf3deb0d-5f1a-0410-827f-c0cc1f45334c --- dblayeroo.php | 384 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 368 insertions(+), 16 deletions(-) diff --git a/dblayeroo.php b/dblayeroo.php index 985402f..b383257 100644 --- a/dblayeroo.php +++ b/dblayeroo.php @@ -1,7 +1,8 @@ */ + * @package domframework + * @author Dominique Fournier + */ // dblayeroo.php @@ -42,6 +43,12 @@ class dblayeroo /** Titles */ private $titles = array (); + /** The real types of each fields. The real types are different of the SQL + * types : a "mail" type is stored in a "VARCHAR(255)" in SQL. + * The real types are optional : if not set, there is no check. + * They are more strict than the SQL types + */ + private $realTypes = array (); /** Limit to one instance of the connection to the same database */ @@ -55,8 +62,8 @@ class dblayeroo * @param string|null $password Password to connect * @param string|null $driver_options Driver options to the database */ - public function __construct ($dsn, $username=null, $password=null, - $driver_options=null) + public function __construct ($dsn, $username = null, $password = null, + $driver_options = null) { $this->connect ($dsn, $username, $password, $driver_options); } @@ -68,8 +75,8 @@ class dblayeroo * @param string|null $password Password to connect * @param string|null $driver_options Driver options to the database */ - public function connect ($dsn, $username=null, $password=null, - $driver_options=null) + public function connect ($dsn, $username = null, $password = null, + $driver_options = null) /* {{{ */ { if (! function_exists ("mb_strlen")) @@ -149,7 +156,7 @@ class dblayeroo $this->DBException ("No Database provided in DSN"); // Force the GROUP_CONCAT value max to the max allowed from the server $st = self::$instance[$this->dsn]->query ( - "SHOW VARIABLES LIKE 'max_allowed_packet'", PDO::FETCH_COLUMN, 1); + "SHOW VARIABLES LIKE 'max_allowed_packet'", \PDO::FETCH_COLUMN, 1); $rows = $st->fetchAll (); if (! isset ($rows[0])) throw new \Exception ( @@ -980,7 +987,7 @@ class dblayeroo /** Get/Set the table property * @param string|null $table The table to use */ - public function table ($table=null) + public function table ($table = null) /* {{{ */ { $this->debugLog ("Entering table (",$table,")"); @@ -998,7 +1005,7 @@ class dblayeroo /** Get/Set the tableprefix property * @param string|null $tableprefix The prefix to append */ - public function tableprefix ($tableprefix=null) + public function tableprefix ($tableprefix = null) /* {{{ */ { $this->debugLog ("Entering tableprefix (",$tableprefix,")"); @@ -1019,7 +1026,7 @@ class dblayeroo * array ("fieldName"=>array ("type"[, "not null"[, "autoincrement"]])) * @param array|null $fields The fields to define */ - public function fields ($fields=null) + public function fields ($fields = null) /* {{{ */ { $this->debugLog ("Entering fields (VALUE)"); @@ -1105,7 +1112,7 @@ class dblayeroo /** Get/Set the primary property * @param string|null $primary The primary key to use */ - public function primary ($primary=null) + public function primary ($primary = null) /* {{{ */ { $this->debugLog ("Entering primary (",$primary,")"); @@ -1125,7 +1132,7 @@ class dblayeroo /** Get/Set the unique property * @param array|null $unique The unique fields constraint to add */ - public function unique ($unique=null) + public function unique ($unique = null) /* {{{ */ { $this->debugLog ("Entering unique (VALUE)"); @@ -1171,7 +1178,7 @@ class dblayeroo * ) * Multiple field and parnentField can be provided, separated by comma */ - public function foreign ($foreign=null) + public function foreign ($foreign = null) /* {{{ */ { $this->debugLog ("Entering foreign (VALUE)"); @@ -1232,7 +1239,7 @@ class dblayeroo /** Get/Set the debug property * @param integer|null $debug Set the debug value */ - public function debug ($debug=null) + public function debug ($debug = null) /* {{{ */ { $this->debugLog ("Entering debug (",$debug,")"); @@ -1332,6 +1339,43 @@ class dblayeroo } /* }}} */ + /** Define a real type array + * Must be array ("field" => "realtype") + * @param array $realTypes The realTypes to set + * The allowed real types are defined in test method : + * checkRealType_TYPE ($val, $definition) + * The allowed real types are : mail, date, datetime, allowedchars(a23d), + * uuid, time, array('val1','val2','val3'), regex(/^[a-zA-Z]{3,}$/i) + * integer, integerPositive, + * To be done : + * integerNegative, + * php_function(), function($val) { if ($val > 0) return "MESSAGE";} + */ + public function realTypes ($realTypes = null) + // {{{ + { + if ($realTypes === null) + return $this->realTypes; + if (! is_array ($realTypes)) + $this->DBException ("Invalid setRealType provided : not an array", 500); + foreach ($realTypes as $field => $realType) + { + if (! key_exists ($field, $this->fields)) + $this->DBException ("Invalid setRealType provided : ". + "field '$field' doesn't exists"); + list ($func, $param) = explode ("(", $realType); + $func = trim ($func); + $method = "checkRealType_".$func; + if (! method_exists ($this, $method)) + $this->DBException ("Invalid setRealType provided : ". + "field '$field' : unknown realType provided '$func'"); + } + $this->realTypes = $realTypes; + return $this; + } + // }}} + + ///////////////////////////////////// /// MANAGE THE REQUEST BY OOP /// ///////////////////////////////////// @@ -2138,7 +2182,7 @@ class dblayeroo * If the parameter $full is set, add the table prefix/name to the result * @param boolean|null $full Add the table prefix/name if set */ - public function orderGet ($full=false) + public function orderGet ($full = false) /* {{{ */ { $order = array (); @@ -2189,7 +2233,7 @@ class dblayeroo * If the parameter $full is set, add the table prefix/name to the result * @param boolean|null $full Add the table prefix/name if set */ - public function groupByGet ($full=false) + public function groupByGet ($full = false) /* {{{ */ { if ($this->joinObject) @@ -2846,6 +2890,9 @@ class dblayeroo $this->debugLog ("Entering checkValues (",$update,")"); $update = !! $update; $values = $this->setValues; + $errors = $this->checkRealType ($values, $update); + if (count ($errors)) + $this->DBException (reset ($errors)); $errors = $this->verify ($values, $update); if (count ($errors)) $this->DBException (reset ($errors)); @@ -2853,6 +2900,60 @@ class dblayeroo } /* }}} */ + /** Check the types of the data against the realTypes + * Return an array with the field name in error and a message + * If allowEmpty is set, do not test the "NOT NULL" feature + * In UPDATE, the values don't need be not set : they are already in database + * so $allowEmpty is true + * @param array $values The values to test + * @param boolean|null $allowEmpty Allow the "not null" to not be set + * @return array empty array if no error + */ + public function checkRealType ($values, $allowEmpty = false) + // {{{ + { + $this->debugLog ("Entering checkRealType (",$values,",",$allowEmpty,")"); + if (! is_array ($values)) + $this->DBException ("Invalid checkRealType provided : not an array", 500); + $errors = array (); + foreach ($this->fields as $field => $params) + { + if (! key_exists ($field, $values) || trim ($values[$field]) === "") + { + if (in_array ("not null", $params) && + ! in_array ("autoincrement", $params)) + { + if ($allowEmpty === false) + $errors[$field] = dgettext ("domframework", + "The field can not be empty"); + } + else + { + // Empty value is not tested and do not generate an error + } + } + elseif (! is_string ($values[$field])) + { + $errors[$field] = dgettext ("domframework", + "The value is not a string"); + } + elseif (key_exists ($field, $this->realTypes)) + { + $val = trim ($values[$field]); + list ($func, $param) = explode ("(", $this->realTypes[$field]); + $func = trim ($func); + $method = "checkRealType_".$func; + $res = $this->$method ($val, $this->realTypes[$field]); + if (is_string ($res)) + $errors[$field] = $res; + } + } + $this->debugLog ("End checkRealType (", $values, ",", $allowEmpty, ") : ", + $errors); + return $errors; + } + // }}} + /** Execute the pre-defined query * Return the content array if SELECT command is choosed * Return the Last ID if INSERT command is choosed @@ -3083,4 +3184,255 @@ class dblayeroo echo "\n"; } /* }}} */ + + ////////////////////////////////////////////// + //// ALL THE CHECK REALTYPES METHODS //// + ////////////////////////////////////////////// + // {{{ + /** Check the type "integerPositive" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_integerPositive ($val, $definition) + // {{{ + { + if (substr ($val, 0, 1) === "-") + return dgettext ("domframework", "Invalid positive integer : ". + "can not start by minus sign"); + if (strspn ($val, "0123456789") !== strlen ($val)) + return dgettext ("domframework", "Invalid positive integer : ". + "invalid char"); + if (substr ($val, 0, 1) === "0" && $val !== "0") + return dgettext ("domframework", "Invalid positive integer : ". + "can not start by Zero"); + return; + } + // }}} + + /** Check the type "integer" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_integer ($val, $definition) + // {{{ + { + if (strspn ($val, "0123456789-") !== strlen ($val)) + return dgettext ("domframework", "Invalid integer : ". + "invalid char"); + if (substr ($val, 0, 1) === "0" && $val !== "0") + return dgettext ("domframework", "Invalid integer : ". + "can not start by Zero"); + if (substr ($val, 0, 2) === "-0") + return dgettext ("domframework", "Invalid integer : ". + "can not start by Minus Zero"); + return; + } + // }}} + + /** Check the type "allowedchars" + * the chars must be in UTF-8 + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_allowedchars ($val, $definition) + // {{{ + { + list ($func, $param) = explode ("(", $definition); + if ($param === null) + $this->DBException ("Invalid allowedchars definied : ". + "must have a starting parenthesis"); + if (substr ($param, -1) !== ")") + $this->DBException ("Invalid allowedchars definied : ". + "must have a ending parenthesis"); + $allowedChars = mb_substr ($param, 0, -1); + $allowedChars = preg_quote ($allowedChars, "#"); + preg_match ('#^['.$allowedChars.']+#u', $val, $matches); + if (isset ($matches[0]) && + mb_strlen ($matches[0]) === mb_strlen ($val)) + return; + return dgettext ("domframework", "Invalid char provided"); + } + // }}} + + /** Check the type "array" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_array ($val, $definition) + // {{{ + { + list ($func, $param) = explode ("(", $definition); + if ($param === null) + $this->DBException ("Invalid array definied : ". + "must have a starting parenthesis"); + if (substr ($param, -1) !== ")") + $this->DBException ("Invalid array definied : ". + "must have a ending parenthesis"); + $param = mb_substr ($param, 0, -1); + $array = explode (",", $param); + foreach ($array as $key => $tmp) + { + $array[$key] = mb_substr ($tmp, 1, -1); + } + if (in_array ($val, $array)) + return; + return dgettext ("domframework", "Invalid value provided : ". + "not in allowed list"); + } + // }}} + + /** Check the type "regex" + * Do not forget to add the separators, the ^ and $ + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_regex ($val, $definition) + // {{{ + { + list ($func, $param) = explode ("(", $definition); + if ($param === null) + $this->DBException ("Invalid regex definied : ". + "must have a starting parenthesis"); + if (substr ($param, -1) !== ")") + $this->DBException ("Invalid regex definied : ". + "must have a ending parenthesis"); + $param = mb_substr ($param, 0, -1); + if (@preg_match ($param, $val) === false) + $this->DBException ("Invalid regex definied : ". + "must have a ending parenthesis"); + if (preg_match ($param, $val)) + return; + return dgettext ("domframework", "Invalid value provided : ". + "do not match the regex"); + } + // }}} + + /** Check the type "mail" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_mail ($val, $definition) + // {{{ + { + if (!! filter_var ($val, FILTER_VALIDATE_EMAIL)) + return; + return dgettext ("domframework", "Invalid mail provided"); + } + // }}} + + /** Check the type "uuid" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_uuid ($val, $definition) + // {{{ + { + if (strlen ($val) !== 36) + return dgettext ("domframework", "Invalid UUID provided : ". + "invalid length"); + if (strspn ($val, "0123456789abcdefABCDEF-") !== strlen ($val)) + return dgettext ("domframework", "Invalid UUID provided : invalid char"); + if ($val[8] !== "-" || $val[13] !== "-" || $val[18] !== "-" || + $val[23] !== "-") + return dgettext ("domframework", "Invalid UUID provided : missing dash"); + } + // }}} + + /** Check the type "sqldate" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_sqldate ($val, $definition) + // {{{ + { + if (strlen ($val) !== 10) + return dgettext ("domframework", "Invalid date provided : ". + "invalid length"); + if (strspn ($val, "0123456789-") !== strlen ($val)) + return dgettext ("domframework", "Invalid date provided : ". + "invalid chars"); + $arr = \date_parse ($val); + if ($arr["warning_count"] !== 0) + return dgettext ("domframework", "Invalid date provided : ". + "can not parse the date"); + if ($arr["error_count"] !== 0) + return dgettext ("domframework", "Invalid date provided : ". + "can not parse the date"); + if (isset ($arr["tz_abbr"])) + return dgettext ("domframework", "Invalid date provided : ". + "can not parse the date"); + if (\DateTime::createFromFormat("Y-m-d", $val) === false) + return dgettext ("domframework", "Invalid date provided : ". + "the date doesn't exists"); + } + // }}} + + /** Check the type "sqltime" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_sqltime ($val, $definition) + // {{{ + { + if (strlen ($val) !== 8) + return dgettext ("domframework", "Invalid time provided : ". + "invalid length"); + if (strspn ($val, "0123456789:") !== strlen ($val)) + return dgettext ("domframework", "Invalid time provided : ". + "invalid chars"); + $arr = \date_parse ($val); + if ($arr["warning_count"] !== 0) + return dgettext ("domframework", "Invalid time provided : ". + "can not parse the time"); + if ($arr["error_count"] !== 0) + return dgettext ("domframework", "Invalid time provided : ". + "can not parse the time"); + if (isset ($arr["tz_abbr"])) + return dgettext ("domframework", "Invalid time provided : ". + "can not parse the date"); + if (\DateTime::createFromFormat("H:i:s", $val) === false) + return dgettext ("domframework", "Invalid time provided : ". + "the time doesn't exists"); + } + // }}} + + /** Check the type "sqldatetime" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_sqldatetime ($val, $definition) + // {{{ + { + if (strlen ($val) !== 19) + return dgettext ("domframework", "Invalid date and time provided : ". + "invalid length"); + if (strspn ($val, "0123456789 :-") !== strlen ($val)) + return dgettext ("domframework", "Invalid date and time provided : ". + "invalid chars"); + $arr = \date_parse ($val); + if ($arr["warning_count"] !== 0) + return dgettext ("domframework", "Invalid date and time provided : ". + "can not parse the date"); + if ($arr["error_count"] !== 0) + return dgettext ("domframework", "Invalid date and time provided : ". + "can not parse the date"); + if (isset ($arr["tz_abbr"])) + return dgettext ("domframework", "Invalid date and time provided : ". + "can not parse the date"); + if (\DateTime::createFromFormat("Y-m-d H:i:s", $val) === false) + return dgettext ("domframework", "Invalid date and time provided : ". + "the date doesn't exists"); + } + // }}} + // }}} }