The TryingToScale PHP framework.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

204 lines
8.3 KiB

<?php
declare(strict_types=1);
/**
* @author Robert Strutts <Robert@TryingToScale.com>
* @copyright Copyright (c) 2022, Robert Strutts.
* @license https://mit-license.org/
*/
namespace tts\traits\database;
trait validation {
/**
* Validate current class members
* @retval bool true valid, false failed tests
*/
public function validate_mysql(): bool {
$tbl = (\bs_tts\common::is_string_found($this->table, "`")) ? $this->table : "`{$this->table}`";
foreach ($this->members as $field => $value) {
if ($field == $this->primary_key) {
continue;
}
$validation_field = $this->get_vaildation_member($field);
if (isset($validation_field['native_type']) && isset($validation_field['len'])) {
$type = strtoupper($validation_field['native_type']);
$len = intval($validation_field['len']);
$meta = $validation_field;
} else {
$meta = $this->get_MySQL_meta_field($field, $this->table);
$type = (isset($meta['native_type']) ? $meta['native_type'] : '');
$len = $meta['len'];
}
switch ($type) { //This should be all uppercase input.
case 'SHORT': //Small INT
case 'INT24': //MED INT
case 'LONGLONG': //BIG INT or SERIAL is an alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE.
case 'LONG': // Integers
if (!preg_match('/^[0-9]*$/', $value)) {
$this->do_verr("Failed Validation: NOT a digit {$type} {$field}");
return false;
} // Does not allow decimal numbers!!
if (strlen($value) > $len) {
$this->do_verr("Failed Validation: too long {$type} {$field}");
return false;
}
break;
case 'FLOAT':
if (strlen($value) > $len) {
$this->do_verr("Failed Validation: too long {$type} {$field}");
return false;
}
if (!is_float($value)) {
$this->do_verr("Failed Validation: NOT a float {$type} {$field}");
return false;
}
break;
case 'NEWDECIMAL':
$prec = intval($meta['precision']);
$maxlen = $len - $prec;
if (!\bs_tts\common::is_string_found($value, '.')) {
$this->do_verr("Failed Validation: No Decimal Found in field {$field}");
return false;
}
$x = explode('.', $value);
if (strlen($x[0]) >= ($maxlen - 1) || strlen($x[1]) > $prec) {
$this->do_verr("Failed Validation: too long {$type} {$field}");
return false;
}
break;
case 'DOUBLE':
if (strlen($value) > $len) {
$this->do_verr("Failed Validation: too long {$type} {$field}");
return false;
}
if (!is_double($value)) {
$this->do_verr("Failed Validation: NOT a double {$type} {$field}");
return false;
}
break;
case 'BLOB': // Text
if ($len == '4294967295' || $len == '16777215')
continue 2; //Too Big to process, 16777215 MEDIUMTEXT
if (strlen($value) > $len) {
$this->do_verr("Failed Validation: too long {$type} {$field}");
return false;
}
break;
case 'VAR_STRING': // VARCHAR or VARBINARY
case 'STRING': //CHAR or BINARY
if (strlen($value) > $len) {
$this->do_verr("Failed Validation: too long {$type} {$field}");
return false;
}
break;
case 'DATE':
if (!$this->is_valid_mysql_date($value)) {
$this->do_verr("Failed Validation: invalid date in {$field}");
return false;
}
break;
case 'TIME':
if (!$this->is_valid_mysql_time($value)) {
$this->do_verr("Failed Validation: invalid time in {$field}");
return false;
}
break;
case 'TIMESTAMP':
case 'DATETIME':
if (strlen($value) > $len) {
$this->do_verr("Failed Validation: too long {$type} {$field}");
return false;
}
if (!$this->is_valid_mysql_timestamp($value)) {
$this->do_verr("Failed Validation: invalid timestamp in {$field}");
return false;
}
break;
default: //TINYINT, Bit, Bool, or Year is the default for no meta data
//if (!is_Digits($value)) return false; //This fails so its commented out.
if ($len == 3) { // Tiny INT
if (intval($value) > 255) {
$this->do_verr("Failed Validation: too long {$type} {$field}");
return false;
}
if (intval($value) < -127) {
$this->do_verr("Failed Validation: too short {$type} {$field}");
return false;
}
} elseif ($len == 1) { // Bit or Bool
if (intval($value) > 9) {
$this->do_verr("Failed Validation: too long {$type} {$field}");
return false;
}
if (intval($value) < 0) {
$this->do_verr("Failed Validation: too short {$type} {$field}");
return false;
}
}
break;
}
}
return true;
}
public function get_MySQL_meta_field(string $field, string $table): array {
$query = "SELECT `{$field}` FROM {$table} LIMIT 1";
$pdo_stmt = $this->pdo->prepare($query);
$pdo_stmt->execute();
return $pdo_stmt->getColumnMeta(0);
}
/**
* Check if valid timestamp/datetime
* @param type $Str
* @return type
*/
public function is_valid_mysql_timestamp(string $Str): bool {
$Stamp = strtotime($Str);
$Month = date('m', $Stamp);
$Day = date('d', $Stamp);
$Year = date('Y', $Stamp);
return checkdate($Month, $Day, $Year);
}
public function is_valid_mysql_date(string $str): bool {
$date_parts = explode('-', $str);
if (\main_tts\common::count($date_parts) != 3)
return false;
if ((strlen($date_parts[0]) != 4) || (!is_numeric($date_parts[0])))
return false;
if ((strlen($date_parts[1]) != 2) || (!is_numeric($date_parts[1])))
return false;
if ((strlen($date_parts[2]) != 2) || (!is_numeric($date_parts[2])))
return false;
if (!checkdate($date_parts[1], $date_parts[2], $date_parts[0]))
return false;
return true;
}
public function is_valid_mysql_time(string $str): bool {
return (strtotime($str) === false) ? false : true;
}
/**
* Helper function for validate mysql
* Will echo if not live error message
* If enabled will also log the error.
* @param string $msg error message
*/
private function do_verr(string $msg): void {
$this->error_message = $msg;
$exists = \main_tts\registry::get('di')->exists('log');
if ($exists && \main_tts\configure::get('database', 'log_validation_errors') === true) {
$log = \main_tts\registry::get('di')->get_service('log', ['validation_errors']);
$log->write($msg);
}
}
}