diff --git a/core/a/mysql.db.php b/core/a/mysql.db.php old mode 100644 new mode 100755 index 91a8f61..1e01a1e --- a/core/a/mysql.db.php +++ b/core/a/mysql.db.php @@ -169,5 +169,13 @@ public function selectRowByFieldWhere( $field = array() ) return Pdo::fetchRowInArrayByWhere(self::$table['table'], $field['field'], $field['value']); } - + /** + * @desc Deletes a row from the database table by id. + * @param int $id The id of the row to delete. + * @return bool Returns true if the deletion is successful, otherwise false. + */ + public function deleteRowById(int $id = 0): bool + { + Pdo::deleteRowById( self::getTable()['table'], $id ); + } } \ No newline at end of file diff --git a/core/c/auto.php b/core/c/auto.php old mode 100644 new mode 100755 diff --git a/core/c/formattributes.php b/core/c/formattributes.php index 8a52ade..0332b30 100755 --- a/core/c/formattributes.php +++ b/core/c/formattributes.php @@ -73,6 +73,9 @@ protected function _setAttributes( $attributes ) $this->_element = str_replace(' min="MIN"', '', $this->_element); $this->_element = str_replace(' max="MAX"', '', $this->_element); $this->_element = str_replace(' href="HREF"', '', $this->_element); + $this->_element = str_replace(' src="SRC"', '', $this->_element); + $this->_element = str_replace(' alt="ALT"', '', $this->_element); + $this->_element = str_replace(' style="STYLE"', '', $this->_element); $this->_element = str_replace(' step="STEP"', '', $this->_element); $this->_element = str_replace(' tabindex="TABINDEX"', '', $this->_element); $this->_element = str_replace(' SPEECH', '', $this->_element); @@ -95,6 +98,8 @@ protected function _setAttributes( $attributes ) $this->_element = str_replace(' VALUE', '', $this->_element); $this->_element = str_replace(' PATTERN', '', $this->_element); $this->_element = str_replace('ANY', '', $this->_element); + $this->_element = str_replace('data-sitekey="DATA-SITEKEY"', '', $this->_element); + $this->_element = str_replace('role="ROLE"', '', $this->_element); } /** diff --git a/core/c/nibiru.php b/core/c/nibiru.php old mode 100644 new mode 100755 diff --git a/core/c/pdo.php b/core/c/pdo.php index aa1646b..5ce477e 100755 --- a/core/c/pdo.php +++ b/core/c/pdo.php @@ -9,7 +9,7 @@ * @category - [PLEASE SPECIFIY] * @license - BSD License */ -final class pdo extends Mysql implements IPdo +final class Pdo extends Mysql implements IPdo { private static $section = false; @@ -55,11 +55,10 @@ protected static function loadTableNames(): array /** - * @param string $string - * - * @return array|bool - */ - public static function query( $string = self::PLACE_NO_QUERY ): array|bool + * @param string $string + * @return mixed + */ + public static function query( $string = self::PLACE_NO_QUERY ): mixed { if(!strstr($string, IOdbc::PLACE_SQL_UPDATE)) @@ -91,7 +90,7 @@ public static function query( $string = self::PLACE_NO_QUERY ): array|bool /** * @return array */ - private static function convertFetchToAssociative( array $result ): array + private static function convertFetchToAssociative( array $result ): array { $resultset = []; if(array_key_exists(0, $result)) @@ -169,10 +168,10 @@ public static function selectDatasetByFieldAndValue($tablename = self::PLACE_TAB * @return bool */ 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 ): bool + $column_name = IMysql::PLACE_COLUMN_NAME, + $parameter_name = IMysql::PLACE_SEARCH_TERM, + $field_name = IMysql::PLACE_FIELD_NAME, + $where_value = IMysql::PLACE_WHERE_VALUE ): bool { $statement = parent::getInstance( self::getSettingsSection() )->getConn(); $query = "UPDATE " . $tablename . " SET " . $column_name . " = :" . $column_name . " WHERE " . $field_name . " = :". $field_name; @@ -264,12 +263,12 @@ public static function updateRowById(string $tableName, array $columnNames, arra * @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 ) { @@ -374,9 +373,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 @@ -413,6 +412,63 @@ public static function fetchTableAsArray( $tablename = self::PLACE_TABLE_NAME, $ return $result; } + /** + * @desc Deletes a row from the specified table by its ID. + * @param string $tablename The name of the table from which to delete the row. If empty, uses the default table. + * @param int $id The ID of the row to delete. + * @return bool Returns true if the deletion was successful, false otherwise. + */ + public static function deleteRowById(string $tablename = '', int $id = 0): bool + { + try { + // Validate that id is a valid number + if (!is_numeric($id) || $id <= 0) + { + throw new \InvalidArgumentException("FATAL ERROR in main CORE deleteRowById: Invalid ID value. Must be a positive number."); + } + + // Validate table name + $validTables = self::loadTableNames(); + if (!in_array($tablename, $validTables, true)) + { + throw new \InvalidArgumentException("FATAL ERROR in main CORE deleteRowById: Invalid table name: {$tablename}"); + } + + // 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 deleteRowById: No primary key found for table ' . $tablename); + } + + $primaryKeyField = $primaryKeyResult['COLUMN_NAME']; + + // Prepare and execute DELETE statement + $query = "DELETE FROM " . $tablename . " WHERE " . $primaryKeyField . " = :id"; + $stmt = $pdo->prepare($query); + $stmt->bindValue(':id', $id, \PDO::PARAM_INT); + + return $stmt->execute(); + } catch (\PDOException $e) { + error_log($e->getMessage()); + return false; + } catch (\Exception $e) { + error_log($e->getMessage()); + return false; + } + } + + /** * @desc will insert the array with fieldnames into the database, if the last parameter is set it should be a string containing the * fieldname that should be encrypted @@ -421,7 +477,7 @@ public static function fetchTableAsArray( $tablename = self::PLACE_TABLE_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 ): bool + 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(); diff --git a/core/c/router.php b/core/c/router.php index 41f71c2..3335162 100755 --- a/core/c/router.php +++ b/core/c/router.php @@ -142,7 +142,7 @@ protected static function getCurPage() return self::$_cur_page; } - /** + /** * @desc sets the current page route in the router */ private static function setCurPage( ) @@ -150,14 +150,17 @@ private static function setCurPage( ) $params = false; $param_parts = explode('?', $_SERVER["REQUEST_URI"]); $uri_parts = explode('/', $param_parts[0]); - + if(is_array($uri_parts)) { + // FIRST: Check for SEO URLs before standard processing if (self::handleSeoUrls($uri_parts)) { // SEO URL was handled, skip normal processing return; } + + // STANDARD PROCESSING (UNCHANGED) if($uri_parts[1] == "") { self::$_cur_page = "index"; @@ -252,6 +255,17 @@ private static function setPageParams( $uri_parts ) } } + else + { + // Handle single trailing URL segments (e.g., /admin/adwordsgenerator/machines) + if(!is_numeric($uri_parts[$i]) && !empty($uri_parts[$i])) + { + if(!array_key_exists($uri_parts[$i], $_REQUEST)) + { + $_REQUEST[$uri_parts[$i]] = ''; + } + } + } } } } @@ -269,64 +283,60 @@ public function currentPage() return self::getCurPage(); } - /** - * @desc Generic SEO URL handler for framework-wide SEO-friendly URLs - * @param array $uri_parts The URI parts from the request - * @return bool Returns true if SEO URL was handled, false otherwise - */ - private static function handleSeoUrls($uri_parts) - { - // Check if we have the minimum required parts for SEO URL: /controller/slug/id - if (!is_array($uri_parts) || count($uri_parts) < 4) - { - return false; - } + /** + * @desc Generic SEO URL handler for framework-wide SEO-friendly URLs + * @param array $uri_parts The URI parts from the request + * @return bool Returns true if SEO URL was handled, false otherwise + */ + private static function handleSeoUrls($uri_parts) + { + // Check if we have the minimum required parts for SEO URL: /controller/slug/id + if (!is_array($uri_parts) || count($uri_parts) < 4) { + return false; + } - // Extract components - $controller = $uri_parts[1] ?? ''; - $slug = $uri_parts[2] ?? ''; - $possibleId = $uri_parts[3] ?? ''; + // Extract components + $controller = $uri_parts[1] ?? ''; + $slug = $uri_parts[2] ?? ''; + $possibleId = $uri_parts[3] ?? ''; - // Validate that the last part is numeric (ID) - if (!is_numeric($possibleId)) - { - return false; - } - - // Validate that the slug contains non-numeric characters (to differentiate from traditional URLs) - if (is_numeric($slug)) - { - return false; - } + // Validate that the last part is numeric (ID) + if (!is_numeric($possibleId)) { + return false; + } - // Validate that the slug is not an existing action name - if (self::isExistingAction($controller, $slug)) - { - return false; - } + // Validate that the slug contains non-numeric characters (to differentiate from traditional URLs) + if (is_numeric($slug)) { + return false; + } - // SEO URL detected - transform it to standard routing - self::$_cur_page = $controller; - self::setAction('detail'); // Default action for SEO URLs - $_REQUEST['id'] = $possibleId; - $_REQUEST['slug'] = $slug; // Preserve slug for potential use in controllers + // Validate that the slug is not an existing action name + if (self::isExistingAction($controller, $slug)) { + return false; + } - return true; - } + // SEO URL detected - transform it to standard routing + self::$_cur_page = $controller; + self::setAction('detail'); // Default action for SEO URLs + $_REQUEST['id'] = $possibleId; + $_REQUEST['slug'] = $slug; // Preserve slug for potential use in controllers - /** - * @desc Check if a slug matches an existing controller action - * @param string $controller The controller name - * @param string $slug The potential action/slug - * @return bool Returns true if it's an existing action - */ - private static function isExistingAction($controller, $slug) - { - // List of common actions that should not be treated as SEO slugs - $commonActions = ['detail', 'list', 'edit', 'delete', 'create', 'update', 'page', 'navigation', 'requestForm']; + return true; + } - return in_array($slug, $commonActions, true); - } + /** + * @desc Check if a slug matches an existing controller action + * @param string $controller The controller name + * @param string $slug The potential action/slug + * @return bool Returns true if it's an existing action + */ + private static function isExistingAction($controller, $slug) + { + // List of common actions that should not be treated as SEO slugs + $commonActions = ['detail', 'list', 'edit', 'delete', 'create', 'update', 'page', 'navigation', 'requestForm']; + + return in_array($slug, $commonActions, true); + } public static function RouterDebug($value) { diff --git a/core/c/typeopenany.php b/core/c/typeopenany.php index ce4c083..7d38189 100755 --- a/core/c/typeopenany.php +++ b/core/c/typeopenany.php @@ -11,11 +11,17 @@ class TypeOpenAny extends FormAttributes implements IForm { private $_attributes = array( - self::FORM_VALUE => '', - self::FORM_ATTRIBUTE_ID => '', - self::FORM_ATTRIBUTE_CLASS => '', - self::FORM_ATTRIBUTE_ANY => '', - self::FORM_ATTRIBUTE_HREF => '' + self::FORM_VALUE => '', + self::FORM_ATTRIBUTE_ID => '', + self::FORM_ATTRIBUTE_CLASS => '', + self::FORM_ATTRIBUTE_ANY => '', + self::FORM_ATTRIBUTE_HREF => '', + self::FORM_ATTRIBUTE_SRC => '', + self::FORM_ATTRIBUTE_ALT => '', + self::FROM_ATTRIBUTE_STYLE => '', + self::FORM_ATTRIBUTE_DATA_SITEKEY => '', + self::FORM_ATTRIBUTE_TYPE => '', + self::FORM_ATTRIBUTE_ROLE => '' ); /** @@ -35,6 +41,6 @@ public function loadElement($attributes) */ private function _setElement( ) { - $this->_element = '' . 'VALUE' . "\n"; + $this->_element = '' . 'VALUE' . "\n"; } } diff --git a/core/c/typeswitch.php b/core/c/typeswitch.php old mode 100644 new mode 100755 diff --git a/core/i/IDb.php b/core/i/IDb.php index 0e8ff35..306bf75 100755 --- a/core/i/IDb.php +++ b/core/i/IDb.php @@ -100,4 +100,11 @@ public function nextInsertIndex(); * @return mixed */ public function loadPasswordByUsername( $user_name = false ); + + /** + * @desc Deletes a row from the database by its ID. + * @param int $id The ID of the row to be deleted. Defaults to 0. + * @return bool Returns true if the deletion was successful, false otherwise. + */ + public function deleteRowById( int $id = 0 ): bool; } \ No newline at end of file diff --git a/core/i/IForm.php b/core/i/IForm.php index 29847dc..ef5bcfa 100755 --- a/core/i/IForm.php +++ b/core/i/IForm.php @@ -33,6 +33,7 @@ interface IForm const FORM_ATTRIBUTE_ALT = 'alt'; const FORM_ATTRIBUTE_ID = 'id'; const FORM_ATTRIBUTE_CLASS = 'class'; + const FORM_ATTRIBUTE_MULTIPLE = 'multiple'; const FORM_ATTRIBUTE_FOR = 'for'; const FORM_ATTRIBUTE_FORM = 'form'; const FORM_ATTRIBUTE_PLACEHOLDER = 'placeholder'; @@ -43,6 +44,7 @@ interface IForm const FORM_ATTRIBUTE_ONBLUR = 'onblur'; const FORM_ATTRIBUTE_ONFOCUS = 'onfocus'; const FORM_ATTRIBUTE_ONCLICK = 'onclick'; + const FORM_ATTRIBUTE_DATA = 'data'; const FORM_ATTRIBUTE_SELECTED = 'selected'; const FORM_ATTRIBUTE_CONTEXT = 'context'; const FORM_ATTRIBUTE_CHECKED = 'checked'; @@ -54,6 +56,8 @@ interface IForm const FORM_ATTRIBUTE_HREF = 'href'; const FORM_ATTRIBUTE_TS_DECIMALS = "data-bts-decimals"; const FORM_ATTRIBUTE_TS_STEPS = "data-bts-step"; + const FROM_ATTRIBUTE_STYLE = 'style'; + const FORM_ATTRIBUTE_DATA_SITEKEY = 'data-sitekey'; /** * @desc loads the current Form element to the form