From a793f79798b4b60928db08516030833156e0030e Mon Sep 17 00:00:00 2001 From: "stephan.kasdorf" Date: Thu, 21 Mar 2024 16:25:13 +0100 Subject: [PATCH] Update database operations and form capabilities Database operations have been redefined and additional functionality has been added for handling database queries. Functions for updating rows by ID and inserting array into table have been updated for better reliability. In addition, new form attributes for managing decimal steps have been added to enhance data input capabilities. Refactoring and security improvements have also been addressed in the PDO class. --- core/a/mysql.db.php | 25 +++++++-- core/c/pdo.php | 134 +++++++++++++++++++++++++++++++++++++------- core/c/typetext.php | 6 +- core/i/db.php | 8 +++ core/i/form.php | 2 + core/i/mysql.php | 1 + 6 files changed, 147 insertions(+), 29 deletions(-) diff --git a/core/a/mysql.db.php b/core/a/mysql.db.php index 40ebe2a..0631350 100644 --- a/core/a/mysql.db.php +++ b/core/a/mysql.db.php @@ -72,9 +72,21 @@ public function selectRowsetById($id = false) } /** - * @param array $rowset - * @param bool $id - * @return mixed|void + * @desc will update the a row with the $rowset parameter by the given id + * @param array $rowData + * @param int $id + * @return bool + */ + public function updateRowById(array $rowData, int $id): bool + { + return Pdo::updateRowById( self::getTable()['table'], self::getTable()['fields'], $rowData, $id ); + } + + /** + * @desc inserts a rowset into the table, by the given nextInsertIndex return + * @param $rowset + * @param $id + * @return void */ public function insertRowsetById($rowset = array(), $id = false) { @@ -95,16 +107,17 @@ public function selectDatasetByMinMax($min = false, $max = false) * @desc inserts an array into the database as on of the fields may be encrypted, but it has to be a varbinary field * @param array $dataset * @param bool $encrypted + * @return bool */ - public function insertArrayIntoTable($dataset = array(), $encrypted = false) + public function insertArrayIntoTable($dataset = array(), $encrypted = false): bool { if($encrypted) { - Pdo::insertArrayIntoTable(self::$table['table'], $dataset, $encrypted); + return Pdo::insertArrayIntoTable(self::$table['table'], $dataset, $encrypted); } else { - Pdo::insertArrayIntoTable(self::$table['table'], $dataset); + return Pdo::insertArrayIntoTable(self::$table['table'], $dataset); } } diff --git a/core/c/pdo.php b/core/c/pdo.php index 5f92ac2..ce02b20 100755 --- a/core/c/pdo.php +++ b/core/c/pdo.php @@ -4,6 +4,7 @@ * User - stephan * Date - 01.02.17 * Time - 18:55 + * @TODO - SECURITY FIX REFACTORING NEEDED! * @author - alllinux.de GbR * @category - [PLEASE SPECIFIY] * @license - BSD License @@ -27,11 +28,37 @@ private static function getSettingsSection() { return self::$section; } - /** - * @param string $string - * - * @return array - */ + + /** + * @desc Loads all table names from the current database. + * + * @security This method is protected and intended for use within the class hierarchy. + * It fetches the names of all tables in the database to facilitate validation + * of table names in database operations. + * + * @return array An array of table names. + */ + protected static function loadTableNames(): array + { + try { + $pdo = parent::getInstance(self::getSettingsSection())->getConn(); + $query = "SHOW TABLES"; + $stmt = $pdo->prepare($query); + $stmt->execute(); + $tables = $stmt->fetchAll(\PDO::FETCH_COLUMN); + return $tables; + } catch (\PDOException $e) { + error_log($e->getMessage()); + return []; + } + } + + + /** + * @param string $string + * + * @return array + */ public static function query( $string = self::PLACE_NO_QUERY ) { @@ -64,7 +91,7 @@ public static function query( $string = self::PLACE_NO_QUERY ) /** * @return array */ - private static function convertFetchToAssociative( array $result ): array + private static function convertFetchToAssociative( array $result ): array { $resultset = []; if(array_key_exists(0, $result)) @@ -141,10 +168,10 @@ public static function selectDatasetByFieldAndValue($tablename = self::PLACE_TAB * @param string $where_value */ public static function updateColumnByFieldWhere( $tablename = self::PLACE_TABLE_NAME, - $column_name = IMysql::PLACE_COLUMN_NAME, - $parameter_name = IMysql::PLACE_SEARCH_TERM, - $field_name = IMysql::PLACE_FIELD_NAME, - $where_value = IMysql::PLACE_WHERE_VALUE ) + $column_name = IMysql::PLACE_COLUMN_NAME, + $parameter_name = IMysql::PLACE_SEARCH_TERM, + $field_name = IMysql::PLACE_FIELD_NAME, + $where_value = IMysql::PLACE_WHERE_VALUE ) { $statement = parent::getInstance( self::getSettingsSection() )->getConn(); $query = "UPDATE " . $tablename . " SET " . $column_name . " = :" . $column_name . " WHERE " . $field_name . " = :". $field_name; @@ -154,17 +181,81 @@ public static function updateColumnByFieldWhere( $tablename = self::PLACE_TABLE_ $insert->execute(); } + /** + * @desc Update a row in a database table by its primary key ID. + * + * @param string $tableName The name of the table to update. + * @param array $data An associative array where keys are column names and values are the new values for those columns. + * @param int $id The value of the primary key for the row to update. + * + * @return bool Returns true on success or false on failure. + */ + public static function updateRowById(string $tableName, array $columnNames, array $data, int $id): bool + { + try { + // Inside a method of the mysql.db.php class or its subclass + $validTables = self::loadTableNames(); + + // Validate the table name + if (!in_array($tableName, $validTables, true)) { + throw new \InvalidArgumentException("FATAL ERROR in main CORE updateRowById: Invalid table name: {$tableName}"); + } + + // Validate column names + foreach (array_keys($data) as $column) { + if (!in_array($column, $columnNames, true)) + { + throw new \InvalidArgumentException("FATAL ERROR in main CORE updateRowById: Invalid column name: {$column}"); + } + } + + // Get PDO instance + $pdo = parent::getInstance(self::getSettingsSection())->getConn(); + + // Fetch the primary key field name + $queryPrimaryKey = "SELECT COLUMN_NAME FROM information_schema.COLUMNS + WHERE TABLE_NAME = :tableName + AND COLUMN_KEY = 'PRI' LIMIT 1;"; + $stmtPrimaryKey = $pdo->prepare($queryPrimaryKey); + $stmtPrimaryKey->bindValue(':tableName', $tableName); + $stmtPrimaryKey->execute(); + $primaryKeyResult = $stmtPrimaryKey->fetch(\PDO::FETCH_ASSOC); + + if (!$primaryKeyResult) + { + throw new \RuntimeException('FATAL ERROR in main CORE updateRowById: No primary key found for table ' . $tableName); + } + $primaryKeyField = $primaryKeyResult['COLUMN_NAME']; + $query = "UPDATE " . $tableName . " SET "; + $updateParts = []; + foreach ($data as $column => $value) { + $updateParts[] = $column . " = :" . $column; + } + $query .= implode(', ', $updateParts); + $query .= " WHERE " . $primaryKeyField . " = :primaryKeyValue"; + $stmt = $pdo->prepare($query); + foreach ($data as $column => $value) { + $stmt->bindValue(':' . $column, $value); + } + $stmt->bindValue(':primaryKeyValue', $id); + return $stmt->execute(); + } catch (\PDOException $e) { + error_log($e->getMessage()); + return false; + } + } + /** * @param string $tablename * @param bool $id * @return array */ - public static function fetchRowInArrayById($tablename = self::PLACE_TABLE_NAME, $id = self::NO_ID ) - { + public static function fetchRowInArrayById($tablename = self::PLACE_TABLE_NAME, $id = self::NO_ID ) + { $result = array(); - $statement = parent::getInstance( self::getSettingsSection() )->getConn(); - $describe = $statement->query('DESC ' . $tablename); - $describe->execute(); + $statement = parent::getInstance( self::getSettingsSection() )->getConn(); + $describe = $statement->query('DESC ' . $tablename); + $describe->execute(); $tableInformation = $describe->fetchAll( \PDO::FETCH_ASSOC ); foreach ( $tableInformation as $entry ) { @@ -269,9 +360,9 @@ public static function fetchRowsInArrayByWhere($tablename = IMysql::PLACE_TABLE_ * @return int|string */ public static function getLastInsertedID() - { - return parent::getInstance( self::getSettingsSection() )->getConn()->lastInsertId(); - } + { + return parent::getInstance( self::getSettingsSection() )->getConn()->lastInsertId(); + } /** * @param string $tablename @@ -314,8 +405,9 @@ public static function fetchTableAsArray( $tablename = self::PLACE_TABLE_NAME, $ * @param string $tablename * @param string $array_name * @param bool $encrypted + * @return bool */ - public static function insertArrayIntoTable( $tablename = IMysql::PLACE_TABLE_NAME, $array_name = IMysql::PLACE_ARRAY_NAME, $encrypted = IMysql::PLACE_DES_ENCRYPT ) + public static function insertArrayIntoTable( $tablename = IMysql::PLACE_TABLE_NAME, $array_name = IMysql::PLACE_ARRAY_NAME, $encrypted = IMysql::PLACE_DES_ENCRYPT ): bool { $statement = parent::getInstance( self::getSettingsSection() )->getConn(); @@ -373,7 +465,7 @@ public static function insertArrayIntoTable( $tablename = IMysql::PLACE_TABLE_NA { $array_name['key'] = Config::getInstance()->getConfig()[View::NIBIRU_SECURITY]["password_hash"]; } - $query->execute( $entry ); + return $query->execute( $entry ); } } else @@ -426,7 +518,7 @@ public static function insertArrayIntoTable( $tablename = IMysql::PLACE_TABLE_NA { $array_name['key'] = Config::getInstance()->getConfig()[View::NIBIRU_SECURITY]["password_hash"]; } - $query->execute( $array_name ); + return $query->execute( $array_name ); } } diff --git a/core/c/typetext.php b/core/c/typetext.php index ea6ccc7..33e1683 100755 --- a/core/c/typetext.php +++ b/core/c/typetext.php @@ -21,7 +21,9 @@ class TypeText extends FormAttributes implements IForm self::FORM_ATTRIBUTE_REQUIRED => '', self::FORM_ATTRIBUTE_MAXLENGTH => '', self::FORM_ATTRIBUTE_TABINDEX => '', - self::FORM_ATTRIBUTE_DISABLED => '' + self::FORM_ATTRIBUTE_DISABLED => '', + self::FORM_ATTRIBUTE_TS_DECIMALS => '', + self::FORM_ATTRIBUTE_TS_STEPS => '' ); public function loadElement( $attributes ) @@ -37,7 +39,7 @@ public function loadElement( $attributes ) */ private function _setElement( ) { - $this->_element = '' . "\n"; + $this->_element = '' . "\n"; } diff --git a/core/i/db.php b/core/i/db.php index a4d3e4b..040daae 100755 --- a/core/i/db.php +++ b/core/i/db.php @@ -9,6 +9,14 @@ interface IDb { + /** + * @desc will update the a row with the $rowset parameter by the given id + * @param array $rowData + * @param int $id + * @return mixed + */ + public function updateRowById( array $rowData, int $id ); + /** * @desc updates a row by a given field and field where search value * @param false $wherefield diff --git a/core/i/form.php b/core/i/form.php index 11622bd..29847dc 100755 --- a/core/i/form.php +++ b/core/i/form.php @@ -52,6 +52,8 @@ interface IForm const FORM_ATTRIBUTE_PATTERN = 'pattern'; const FORM_ATTRIBUTE_ANY = 'any'; const FORM_ATTRIBUTE_HREF = 'href'; + const FORM_ATTRIBUTE_TS_DECIMALS = "data-bts-decimals"; + const FORM_ATTRIBUTE_TS_STEPS = "data-bts-step"; /** * @desc loads the current Form element to the form diff --git a/core/i/mysql.php b/core/i/mysql.php index 4559af1..98e4290 100755 --- a/core/i/mysql.php +++ b/core/i/mysql.php @@ -15,6 +15,7 @@ interface IMysql const PLACE_NO_QUERY = "NO QUERY"; const NO_ID = false; const PLACE_TABLE_NAME = "NO TABLENAME"; + const PLACE_ARRAY_NAME = "NO ARRAY"; const PLACE_QUERY_LIMIT = "NO LIMIT"; const PLACE_SORT_ORDER = "NO ORDER"; const PLACE_DSN = "NO CONNECTION STRING";