diff --git a/src/bootstrap/safer_io.php b/src/bootstrap/safer_io.php index f8a93d9..30cf92e 100644 --- a/src/bootstrap/safer_io.php +++ b/src/bootstrap/safer_io.php @@ -322,111 +322,210 @@ final class safer_io { return $data; } + /** + * Initialize JSON post data into static array, if used.... + * @param int $levels_deep are JSON Levels to use + */ + + public static function init_json(int $levels_deep = 512): void { + self::$JSON_POST_DATA = self::get_json_post_data(true, $levels_deep); + } + /** * Sanitize the inputs based on the rules an optionally trim the string - * @param array $inputs [input, field, html, rule, message, skip_db] * @param FIELD_FILTER $default_filter FILTER_SANITIZE_STRING * @param bool $trim * @return array [meta, fields, html, errors] */ - public static function sanitize( - array $inputs, + private static function sanitize_helper( + string $from, + string $input_field_name, + array $a, FIELD_FILTER $default_filter = FIELD_FILTER::raw_string, bool $trim = true, - int $levels_deep = 512 // JSON Levels ) : array { - - self::$JSON_POST_DATA = self::get_json_post_data(true, $levels_deep); $meta = []; $meta['missing'] = []; - $safer_data = []; - $safer_db_data = []; - $safer_html_data = []; + $safer_data = ""; $rules = []; $messages = []; - foreach ($inputs as $input_field_name => $a) { - if (isset($a['field']) && $a['field'] instanceof \UnitEnum) { - $field_type = $a['field']; - } else { - $field_type = $default_filter; - } - if (isset($a['input']) && $a['input'] instanceof \UnitEnum) { - $user_text = self::get_input_by_type($input_field_name, $a['input'], $field_type); - } else { - $meta['missing'][] = $input_field_name; - continue; - } - - $safer_data[$input_field_name] = false; // needs to be false to fail the validator - $safer_html_data[$input_field_name] = null; // should be null for ?? operator to work with it.... - - if (isset($a['rule'])) { - $rules[$input_field_name] = $a['rule']; - } - - if (isset($a['message']) && isset($a['rule'])) { - $messages[$input_field_name] = $a['message']; - } + if (isset($a['field']) && $a['field'] instanceof \UnitEnum) { + $field_type = $a['field']; + } else { + $field_type = $default_filter; + } - $db = (isset($a['skip_db'])) ? $a['skip_db'] : false; - $meta[$input_field_name]['type'] = $field_type->name; - $meta[$input_field_name]['skip_db'] = $db; - - if ($user_text === null) { - continue; - } - + if (isset($a['input']) && $a['input'] instanceof \UnitEnum) { + $user_text = self::get_input_by_type($input_field_name, $a['input'], $field_type); + } else { + $ret['name'] = $input_field_name; + $ret['meta']['missing'][] = $input_field_name; + $ret['errors'][$input_field_name] = "Missing Field $input_field_name"; + $ret['html'] = null; + $ret['db'] = false; + $ret['logic'] = false; + return $ret; + } + + $safer_data = false; // needs to be false to fail the validator + $safer_html_data = null; // should be null for ?? operator to work with it.... + + if (isset($a['rule'])) { + $rules[$input_field_name] = $a['rule']; + } + + if (isset($a['message']) && isset($a['rule'])) { + $messages[$input_field_name] = $a['message']; + } + + $db = (isset($a['skip_db'])) ? $a['skip_db'] : false; + $meta[$input_field_name]['type'] = $field_type->name; + $meta[$input_field_name]['skip_db'] = $db; + + if ($user_text === null) { + $safer_data = null; + $safer_db_data = null; + $safer_html_data = null; + } else { $field_filter_resolved = $field_type->resolve(); - $safer_data[$input_field_name] = $user_text; + $safer_data = $user_text; if ($field_type == FIELD_FILTER::email) { - $safer_data[$input_field_name] = substr($safer_data[$input_field_name], 0, 254); + $safer_data = substr($safer_data, 0, 254); } - $safer_data[$input_field_name] = filter_var($safer_data[$input_field_name], FILTER_DEFAULT, $field_filter_resolved); + $safer_data = filter_var($safer_data, FILTER_DEFAULT, $field_filter_resolved); // FallBack: These field types should never allow arrays anyways if ($field_type == FIELD_FILTER::raw_string || $field_type == FIELD_FILTER::raw ) { - if (\tts\common::get_count($safer_data[$input_field_name])) { - $safer_data[$input_field_name] = $safer_data[$input_field_name][0]; + if (\tts\common::get_count($safer_data)) { + $safer_data = $safer_data[0]; } } - $safer_html = self::get_safer_html($safer_data[$input_field_name], $a); - if ($safer_html !== false) { - $safer_html_data[$input_field_name] = $safer_html; - } + if ($from === "html") { + $safer_html = self::get_safer_html($safer_data, $a); + if ($safer_html !== false) { + $safer_html_data = $safer_html; + } - $safer_data[$input_field_name] = self::t($safer_data[$input_field_name], $trim); - if (isset($safer_html_data[$input_field_name])) { - $safer_html_data[$input_field_name] = self::t($safer_html_data[$input_field_name], $trim); + if (isset($safer_html_data)) { + $safer_html_data = self::t($safer_html_data, $trim); + } + } else { + $safer_data = self::t($safer_data, $trim); } - + if ($field_type == FIELD_FILTER::integer_number) { - $safer_data[$input_field_name] = intval($safer_data[$input_field_name]); + $safer_data = intval($safer_data); } if ($field_type == FIELD_FILTER::floating_point) { - $safer_data[$input_field_name] = floatval($safer_data[$input_field_name]); + $safer_data = floatval($safer_data); } - if ($field_type == FIELD_FILTER::integer_number || $field_type == FIELD_FILTER::floating_point) { - $safer_db_data[$input_field_name] = $safer_data[$input_field_name]; - } else { - if (isset($a['db']) && $a['db'] == DB_FILTER::ON) { - $safe_for_db = \tts\safer_sql::get_safer_sql_text($safer_data[$input_field_name]); - $text = $safe_for_db["text"]; + if ($from === "db") { + if ($field_type == FIELD_FILTER::integer_number || $field_type == FIELD_FILTER::floating_point) { + $safer_db_data = $safer_data; } else { - $text = $safer_data[$input_field_name]; + if (isset($a['db']) && $a['db'] == DB_FILTER::ON) { + $safe_for_db = \tts\safer_sql::get_safer_sql_text($safer_data); + $text = $safe_for_db["text"]; + } else { + $text = $safer_data; + } + $safer_db_data = $text; } - $safer_db_data[$input_field_name] = $text; } - + } + $ret['name'] = $input_field_name; + $ret['meta'] = $meta; + if ($from === "db") { + $ret['db'] = $safer_db_data; + $data[$input_field_name] = $safer_db_data; + } elseif ($from === "logic") { + $ret['logic'] = $safer_data; + $data[$input_field_name] = $safer_data; + } elseif ($from === "html") { + $ret['html'] = $safer_html_data; + $data[$input_field_name] = $safer_html_data; } - $errors = (count($rules)) ? \tts\validator::validate($safer_data, $rules, $messages) : []; + $ret['errors'] = (count($rules)) ? \tts\validator::validate($data, $rules, $messages) : []; + return $ret; + } + - return ['meta' => $meta, 'fields' => $safer_data, 'db'=>$safer_db_data, 'html' => $safer_html_data, 'errors' => $errors]; + /** + * Sanitize the inputs based on the rules an optionally trim the string + * @param array $inputs [input, field, html, rule, message, skip_db, db] + * @param FIELD_FILTER $default_filter FILTER_SANITIZE_STRING + * @param bool $trim + * @return Generator + */ + public static function db_sanitize( + array $inputs, + FIELD_FILTER $default_filter = FIELD_FILTER::raw_string, + bool $trim = true, + ) : \Generator { + foreach ($inputs as $input_field_name => $a) { + $yield = static::sanitize_helper( + "db", + $input_field_name, + $a, + $default_filter, + $trim + ); + yield $yield; + } + } + + /** + * Sanitize the inputs based on the rules an optionally trim the string + * @param array $inputs [input, field, html, rule, message, skip_db, db] + * @param FIELD_FILTER $default_filter FILTER_SANITIZE_STRING + * @param bool $trim + * @return Generator + */ + public static function logic_sanitize( + array $inputs, + FIELD_FILTER $default_filter = FIELD_FILTER::raw_string, + bool $trim = true, + ) : \Generator { + foreach ($inputs as $input_field_name => $a) { + $yield = static::sanitize_helper( + "logic", + $input_field_name, + $a, + $default_filter, + $trim + ); + yield $yield; + } + } + + /** + * Sanitize the inputs based on the rules an optionally trim the string + * @param array $inputs [input, field, html, rule, message, skip_db, db] + * @param FIELD_FILTER $default_filter FILTER_SANITIZE_STRING + * @param bool $trim + * @return Generator + */ + public static function html_sanitize( + array $inputs, + FIELD_FILTER $default_filter = FIELD_FILTER::raw_string, + bool $trim = true, + ) : \Generator { + foreach ($inputs as $input_field_name => $a) { + $yield = static::sanitize_helper( + "html", + $input_field_name, + $a, + $default_filter, + $trim + ); + yield $yield; + } } -} \ No newline at end of file +} diff --git a/src/classes/database/help_load.php b/src/classes/database/help_load.php index 0b1d7ae..c20611f 100644 --- a/src/classes/database/help_load.php +++ b/src/classes/database/help_load.php @@ -16,7 +16,7 @@ class help_load { * @param \PDOStatement $stmt * @return \Generator */ - public static function fetch_lazy(\PDOStatement $stmt): \Generator { + public static function pdo_fetch_lazy(\PDOStatement $stmt): \Generator { foreach($stmt as $record) { yield $record; } diff --git a/src/classes/database/help_save.php b/src/classes/database/help_save.php index db72a9e..687b5e0 100644 --- a/src/classes/database/help_save.php +++ b/src/classes/database/help_save.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace tts\database; +use \tts\safer_io as SafeIO; + final class help_save { use \tts\traits\database\run_sql; @@ -22,6 +24,7 @@ final class help_save { private $error_message; private $pdo; private $primary_key = 'id'; + private $db_skiped = []; public function __construct($pdo, $table) { $this->pdo = $pdo; @@ -59,6 +62,10 @@ final class help_save { unset($diff[$key]); // Who cares about IDs } + foreach($this->db_skiped as $skip) { + unset($diff[$skip]); + } + if (count($diff)) { echo "Diff on fields:
" . PHP_EOL; $this->do_dump($diff); @@ -77,35 +84,45 @@ final class help_save { $this->primary_key = $key; } - /** - * @param array $data [fields=[key=>value]] - */ - public function set_members_by_array(array $data): bool { - $error_count = (isset($data['errors'])) ? count($data['errors']) : 0; - if ($error_count) { - return false; - } - - if (count($data['meta']['missing'])) { - $this->missing = $data['meta']['missing']; - } - - if (count($data['db'])) { - foreach($data['db'] as $key => $value) { - $meta = $data['meta'][$key] ?? false; - if ($meta !== false) { - $skip_db = $meta['skip_db'] ?? false; - if ($skip_db === true) { - continue; // Skip Field - } + public function set_members_by_generator(array $input): bool { + $good = true; + foreach(SafeIO::db_sanitize($input) as $data) { + $key = $data['name'] ?? false; + $value = $data['db'] ?? null; + $error_count = (isset($data['errors'])) ? \tts\common::get_count($data['errors']) : 0; + if ($error_count) { + return false; + } + + if (isset($data['meta']['missing']) && \tts\common::get_count($data['meta']['missing'])) { + $this->missing = $data['meta']['missing']; + } + + $meta = $data['meta'][$key] ?? false; + if ($meta !== false) { + $skip_db = $meta['skip_db'] ?? false; + if ($skip_db === true) { + $this->db_skiped[$key] = true; + continue; // Skip Field } + } + if ($key !== false) { $this->members[$key] = $value; + } else { + $good = false; } } - return true; + return $good; } + /** + * Do not use this one in production! AS anyone can override + * the DB security and Inject stuff into the DB via POST, etc... + */ public function auto_set_members(array $post = [], array $skip = ['route', 'm'], array $only_these = []): void { + if (\tts\main\configure::get('tts', 'live') === true) { + return; // Bail if LIVE + } if (isset($post['json'])) { $globals = \tts\safer_io::get_json_post_data(); } else { diff --git a/src/classes/html.php b/src/classes/html.php index ee5216f..5ddfe0a 100644 --- a/src/classes/html.php +++ b/src/classes/html.php @@ -90,7 +90,6 @@ final class html { */ public static function show_table_from_generator( array $header_fields, - array $db_field_names, \Iterator $records, bool $escape = true ): void { @@ -102,11 +101,14 @@ final class html { echo "\t\t{$field}{$nl}"; } echo "\t{$nl}"; - + foreach($records as $record) { echo "\t{$nl}"; - foreach($db_field_names as $field_name) { - $td = $record[$field_name] ?? ""; + foreach($record as $key => $value) { + if (! is_string($key)) { + continue; // Remove Duplicate records + } + $td = $value ?? ""; if (is_string($td)) { $cell = ($escape) ? \tts\safer_io::h($td) : $td; } else {