File manager - Edit - /home/opticamezl/www/newok/Mysqli.zip
Back
PK .8�\����s s MysqliDriver.phpnu �[��� <?php /** * Part of the Joomla Framework Database Package * * @copyright Copyright (C) 2005 - 2021 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Database\Mysqli; use Joomla\Database\DatabaseDriver; use Joomla\Database\DatabaseEvents; use Joomla\Database\Event\ConnectionEvent; use Joomla\Database\Exception\ConnectionFailureException; use Joomla\Database\Exception\ExecutionFailureException; use Joomla\Database\Exception\PrepareStatementFailureException; use Joomla\Database\Exception\UnsupportedAdapterException; use Joomla\Database\StatementInterface; use Joomla\Database\UTF8MB4SupportInterface; /** * MySQLi Database Driver * * @link https://www.php.net/manual/en/book.mysqli.php * @since 1.0 */ class MysqliDriver extends DatabaseDriver implements UTF8MB4SupportInterface { /** * The database connection resource. * * @var \mysqli * @since 1.0 */ protected $connection; /** * The name of the database driver. * * @var string * @since 1.0 */ public $name = 'mysqli'; /** * The character(s) used to quote SQL statement names such as table names or field names, etc. * * If a single character string the same character is used for both sides of the quoted name, else the first character will be used for the * opening quote and the second for the closing quote. * * @var string * @since 1.0 */ protected $nameQuote = '`'; /** * The null or zero representation of a timestamp for the database driver. * * @var string * @since 1.0 */ protected $nullDate = '0000-00-00 00:00:00'; /** * True if the database engine supports UTF-8 Multibyte (utf8mb4) character encoding. * * @var boolean * @since 1.4.0 */ protected $utf8mb4 = false; /** * True if the database engine is MariaDB. * * @var boolean * @since 2.0.0 */ protected $mariadb = false; /** * The minimum supported MySQL database version. * * @var string * @since 1.0 */ protected static $dbMinimum = '5.6'; /** * The minimum supported MariaDB database version. * * @var string * @since 2.0.0 */ protected static $dbMinMariadb = '10.0'; /** * Constructor. * * @param array $options List of options used to configure the connection * * @since 1.0 */ public function __construct(array $options) { /** * sql_mode to MySql 5.7.8+ default strict mode minus ONLY_FULL_GROUP_BY * * @link https://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-8.html#mysqld-5-7-8-sql-mode */ $sqlModes = [ 'STRICT_TRANS_TABLES', 'ERROR_FOR_DIVISION_BY_ZERO', 'NO_ENGINE_SUBSTITUTION', ]; // Get some basic values from the options. $options['host'] = $options['host'] ?? 'localhost'; $options['user'] = $options['user'] ?? 'root'; $options['password'] = $options['password'] ?? ''; $options['database'] = $options['database'] ?? ''; $options['select'] = isset($options['select']) ? (bool) $options['select'] : true; $options['port'] = isset($options['port']) ? (int) $options['port'] : null; $options['socket'] = $options['socket'] ?? null; $options['utf8mb4'] = isset($options['utf8mb4']) ? (bool) $options['utf8mb4'] : false; $options['sqlModes'] = isset($options['sqlModes']) ? (array) $options['sqlModes'] : $sqlModes; $options['ssl'] = isset($options['ssl']) ? $options['ssl'] : []; if ($options['ssl'] !== []) { $options['ssl']['enable'] = isset($options['ssl']['enable']) ? $options['ssl']['enable'] : false; $options['ssl']['cipher'] = isset($options['ssl']['cipher']) ? $options['ssl']['cipher'] : null; $options['ssl']['ca'] = isset($options['ssl']['ca']) ? $options['ssl']['ca'] : null; $options['ssl']['capath'] = isset($options['ssl']['capath']) ? $options['ssl']['capath'] : null; $options['ssl']['key'] = isset($options['ssl']['key']) ? $options['ssl']['key'] : null; $options['ssl']['cert'] = isset($options['ssl']['cert']) ? $options['ssl']['cert'] : null; $options['ssl']['verify_server_cert'] = isset($options['ssl']['verify_server_cert']) ? $options['ssl']['verify_server_cert'] : null; } // Finalize initialisation. parent::__construct($options); } /** * Check if the database server is responsive. * * @param string $host The host name or IP address. * @param int $port The port number. Optional; default is the MySQL default. * @param int $initialWaitInSeconds The number of seconds to wait before pinging the server. Optional; default is 0 seconds. * @param int $intervalWaitInSeconds The number of seconds to wait between pinging the server. Optional; default is 3 seconds. * @param int $timeoutInSeconds The timeout in seconds for the server to respond. Optional; default is 1 second. * @param int $retries The number of retries. Optional; default is 3. * * @return boolean * @todo This should maybe be moved to the parent class. * */ public function healthCheck(string $host, int $port = 3306, int $initialWaitInSeconds = 0, int $intervalWaitInSeconds = 3, int $timeoutInSeconds = 1, int $retries = 3 ): bool { sleep($initialWaitInSeconds); for ($i = 0; $i < $retries; $i++) { $file = @fsockopen($host, $port, $errno, $errstr, $timeoutInSeconds); if ($file) { fclose($file); return true; } sleep($intervalWaitInSeconds); } return false; } /** * Connects to the database if needed. * * @return void Returns void if the database connected successfully. * * @since 1.0 * @throws \RuntimeException */ public function connect() { if ($this->connection) { return; } // Make sure the MySQLi extension for PHP is installed and enabled. if (!static::isSupported()) { throw new UnsupportedAdapterException('The MySQLi extension is not available'); } /* * Unlike mysql_connect(), mysqli_connect() takes the port and socket as separate arguments. Therefore, we * have to extract them from the host string. */ $port = isset($this->options['port']) ? $this->options['port'] : 3306; if (preg_match('/^unix:(?P<socket>[^:]+)$/', $this->options['host'], $matches)) { // UNIX socket URI, e.g. 'unix:/path/to/unix/socket.sock' $this->options['host'] = null; $this->options['socket'] = $matches['socket']; $this->options['port'] = null; } elseif (preg_match( '/^(?P<host>((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(:(?P<port>.+))?$/', $this->options['host'], $matches )) { // It's an IPv4 address with or without port $this->options['host'] = $matches['host']; if (!empty($matches['port'])) { $port = $matches['port']; } } elseif (preg_match('/^(?P<host>\[.*\])(:(?P<port>.+))?$/', $this->options['host'], $matches)) { // We assume square-bracketed IPv6 address with or without port, e.g. [fe80:102::2%eth1]:3306 $this->options['host'] = $matches['host']; if (!empty($matches['port'])) { $port = $matches['port']; } } elseif (preg_match('/^(?P<host>(\w+:\/{2,3})?[a-z0-9\.\-]+)(:(?P<port>[^:]+))?$/i', $this->options['host'], $matches)) { // Named host (e.g example.com or localhost) with or without port $this->options['host'] = $matches['host']; if (!empty($matches['port'])) { $port = $matches['port']; } } elseif (preg_match('/^:(?P<port>[^:]+)$/', $this->options['host'], $matches)) { // Empty host, just port, e.g. ':3306' $this->options['host'] = 'localhost'; $port = $matches['port']; } // ... else we assume normal (naked) IPv6 address, so host and port stay as they are or default // Get the port number or socket name if (is_numeric($port)) { $this->options['port'] = (int) $port; } else { $this->options['socket'] = $port; } $this->connection = mysqli_init(); $connectionFlags = 0; // For SSL/TLS connection encryption. if ($this->options['ssl'] !== [] && $this->options['ssl']['enable'] === true) { $connectionFlags += MYSQLI_CLIENT_SSL; // Verify server certificate is only available in PHP 5.6.16+. See https://www.php.net/ChangeLog-5.php#5.6.16 if (isset($this->options['ssl']['verify_server_cert'])) { // New constants in PHP 5.6.16+. See https://www.php.net/ChangeLog-5.php#5.6.16 if ($this->options['ssl']['verify_server_cert'] === true && defined('MYSQLI_CLIENT_SSL_VERIFY_SERVER_CERT')) { $connectionFlags += MYSQLI_CLIENT_SSL_VERIFY_SERVER_CERT; } elseif ($this->options['ssl']['verify_server_cert'] === false && defined('MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT')) { $connectionFlags += MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT; } elseif (defined('MYSQLI_OPT_SSL_VERIFY_SERVER_CERT')) { $this->connection->options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, $this->options['ssl']['verify_server_cert']); } } // Add SSL/TLS options only if changed. $this->connection->ssl_set( $this->options['ssl']['key'], $this->options['ssl']['cert'], $this->options['ssl']['ca'], $this->options['ssl']['capath'], $this->options['ssl']['cipher'] ); } // Attempt to connect to the server, use error suppression to silence warnings and allow us to throw an Exception separately. $connected = @$this->connection->real_connect( $this->options['host'], $this->options['user'], $this->options['password'], null, $this->options['port'], $this->options['socket'], $connectionFlags ); if (!$connected) { throw new ConnectionFailureException( 'Could not connect to database: ' . $this->connection->connect_error, $this->connection->connect_errno ); } // If needed, set the sql modes. if ($this->options['sqlModes'] !== []) { $this->connection->query('SET @@SESSION.sql_mode = \'' . implode(',', $this->options['sqlModes']) . '\';'); } // And read the real sql mode to mitigate changes in mysql > 5.7.+ $this->options['sqlModes'] = explode(',', $this->setQuery('SELECT @@SESSION.sql_mode;')->loadResult()); // If auto-select is enabled select the given database. if ($this->options['select'] && !empty($this->options['database'])) { $this->select($this->options['database']); } $this->mariadb = stripos($this->connection->server_info, 'mariadb') !== false; $this->utf8mb4 = $this->serverClaimsUtf8mb4Support(); // Set character sets (needed for MySQL 4.1.2+ and MariaDB). $this->utf = $this->setUtf(); $this->dispatchEvent(new ConnectionEvent(DatabaseEvents::POST_CONNECT, $this)); } /** * Automatically downgrade a CREATE TABLE or ALTER TABLE query from utf8mb4 (UTF-8 Multibyte) to plain utf8. * * Used when the server doesn't support UTF-8 Multibyte. * * @param string $query The query to convert * * @return string The converted query * * @since 1.4.0 */ public function convertUtf8mb4QueryToUtf8($query) { if ($this->utf8mb4) { return $query; } // If it's not an ALTER TABLE or CREATE TABLE command there's nothing to convert if (!preg_match('/^(ALTER|CREATE)\s+TABLE\s+/i', $query)) { return $query; } // Don't do preg replacement if string does not exist if (stripos($query, 'utf8mb4') === false) { return $query; } // Replace utf8mb4 with utf8 if not within single or double quotes or name quotes return preg_replace('/[`"\'][^`"\']*[`"\'](*SKIP)(*FAIL)|utf8mb4/i', 'utf8', $query); } /** * Disconnects the database. * * @return void * * @since 1.0 */ public function disconnect() { // Close the connection. if (\is_callable($this->connection, 'close')) { $this->connection->close(); } parent::disconnect(); } /** * Method to escape a string for usage in an SQL statement. * * @param string $text The string to be escaped. * @param boolean $extra Optional parameter to provide extra escaping. * * @return string The escaped string. * * @since 1.0 */ public function escape($text, $extra = false) { if (\is_int($text)) { return $text; } if (\is_float($text)) { // Force the dot as a decimal point. return str_replace(',', '.', (string) $text); } $this->connect(); $result = $this->connection->real_escape_string((string) $text); if ($extra) { $result = addcslashes($result, '%_'); } return $result; } /** * Test to see if the MySQLi connector is available. * * @return boolean True on success, false otherwise. * * @since 1.0 */ public static function isSupported() { return \extension_loaded('mysqli'); } /** * Determines if the connection to the server is active. * * @return boolean True if connected to the database engine. * * @since 1.0 */ public function connected() { if (\is_object($this->connection)) { return $this->connection->ping(); } return false; } /** * Return the query string to alter the database character set. * * @param string $dbName The database name * * @return string The query that alter the database query string * * @since 2.0.0 */ public function getAlterDbCharacterSet($dbName) { $charset = $this->utf8mb4 ? 'utf8mb4' : 'utf8'; return 'ALTER DATABASE ' . $this->quoteName($dbName) . ' CHARACTER SET `' . $charset . '`'; } /** * Method to get the database collation in use by sampling a text field of a table in the database. * * @return string|boolean The collation in use by the database (string) or boolean false if not supported. * * @since 1.0 * @throws \RuntimeException */ public function getCollation() { $this->connect(); return $this->setQuery('SELECT @@collation_database;')->loadResult(); } /** * Method to get the database connection collation in use by sampling a text field of a table in the database. * * @return string|boolean The collation in use by the database connection (string) or boolean false if not supported. * * @since 1.6.0 * @throws \RuntimeException */ public function getConnectionCollation() { $this->connect(); return $this->setQuery('SELECT @@collation_connection;')->loadResult(); } /** * Method to get the database encryption details (cipher and protocol) in use. * * @return string The database encryption details. * * @since 2.0.0 * @throws \RuntimeException */ public function getConnectionEncryption(): string { $this->connect(); $variables = $this->setQuery('SHOW SESSION STATUS WHERE `Variable_name` IN (\'Ssl_version\', \'Ssl_cipher\')') ->loadObjectList('Variable_name'); if (!empty($variables['Ssl_cipher']->Value)) { return $variables['Ssl_version']->Value . ' (' . $variables['Ssl_cipher']->Value . ')'; } return ''; } /** * Method to test if the database TLS connections encryption are supported. * * @return boolean Whether the database supports TLS connections encryption. * * @since 2.0.0 */ public function isConnectionEncryptionSupported(): bool { $this->connect(); $variables = $this->setQuery('SHOW SESSION VARIABLES WHERE `Variable_name` IN (\'have_ssl\')')->loadObjectList('Variable_name'); return !empty($variables['have_ssl']->Value) && $variables['have_ssl']->Value === 'YES'; } /** * Return the query string to create new Database. * * @param \stdClass $options Object used to pass user and database name to database driver. This object must have "db_name" and "db_user" set. * @param boolean $utf True if the database supports the UTF-8 character set. * * @return string The query that creates database * * @since 2.0.0 */ protected function getCreateDatabaseQuery($options, $utf) { if ($utf) { $charset = $this->utf8mb4 ? 'utf8mb4' : 'utf8'; $collation = $charset . '_unicode_ci'; return 'CREATE DATABASE ' . $this->quoteName($options->db_name) . ' CHARACTER SET `' . $charset . '` COLLATE `' . $collation . '`'; } return 'CREATE DATABASE ' . $this->quoteName($options->db_name); } /** * Shows the table CREATE statement that creates the given tables. * * @param mixed $tables A table name or a list of table names. * * @return array A list of the create SQL for the tables. * * @since 1.0 * @throws \RuntimeException */ public function getTableCreate($tables) { $this->connect(); $result = []; // Sanitize input to an array and iterate over the list. $tables = (array) $tables; foreach ($tables as $table) { // Set the query to get the table CREATE statement. $row = $this->setQuery('SHOW CREATE TABLE ' . $this->quoteName($this->escape($table)))->loadRow(); // Populate the result array based on the create statements. $result[$table] = $row[1]; } return $result; } /** * Retrieves field information about a given table. * * @param string $table The name of the database table. * @param boolean $typeOnly True to only return field types. * * @return array An array of fields for the database table. * * @since 1.0 * @throws \RuntimeException */ public function getTableColumns($table, $typeOnly = true) { $this->connect(); $result = []; // Set the query to get the table fields statement. $fields = $this->setQuery('SHOW FULL COLUMNS FROM ' . $this->quoteName($this->escape($table)))->loadObjectList(); // If we only want the type as the value add just that to the list. if ($typeOnly) { foreach ($fields as $field) { $result[$field->Field] = preg_replace('/[(0-9)]/', '', $field->Type); } } else { // If we want the whole field data object add that to the list. foreach ($fields as $field) { $result[$field->Field] = $field; } } return $result; } /** * Get the details list of keys for a table. * * @param string $table The name of the table. * * @return array An array of the column specification for the table. * * @since 1.0 * @throws \RuntimeException */ public function getTableKeys($table) { $this->connect(); // Get the details columns information. return $this->setQuery('SHOW KEYS FROM ' . $this->quoteName($table))->loadObjectList(); } /** * Method to get an array of all tables in the database. * * @return array An array of all the tables in the database. * * @since 1.0 * @throws \RuntimeException */ public function getTableList() { $this->connect(); // Set the query to get the tables statement. return $this->setQuery('SHOW TABLES')->loadColumn(); } /** * Get the version of the database connector. * * @return string The database connector version. * * @since 1.0 */ public function getVersion() { $this->connect(); if ($this->mariadb) { // MariaDB: Strip off any leading '5.5.5-', if present return preg_replace('/^5\.5\.5-/', '', $this->connection->server_info); } return $this->connection->server_info; } /** * Get the minimum supported database version. * * @return string * * @since 2.0.0 */ public function getMinimum() { return $this->mariadb ? static::$dbMinMariadb : static::$dbMinimum; } /** * Determine whether the database engine support the UTF-8 Multibyte (utf8mb4) character encoding. * * @return boolean True if the database engine supports UTF-8 Multibyte. * * @since 2.0.0 */ public function hasUTF8mb4Support() { return $this->utf8mb4; } /** * Determine if the database engine is MariaDB. * * @return boolean * * @since 2.0.0 */ public function isMariaDb(): bool { $this->connect(); return $this->mariadb; } /** * Method to get the auto-incremented value from the last INSERT statement. * * @return mixed The value of the auto-increment field from the last inserted row. * If the value is greater than maximal int value, it will return a string. * * @since 1.0 */ public function insertid() { $this->connect(); return $this->connection->insert_id; } /** * Inserts a row into a table based on an object's properties. * * @param string $table The name of the database table to insert into. * @param object $object A reference to an object whose public properties match the table fields. * @param string $key The name of the primary key. If provided the object property is updated. * * @return boolean * * @since 2.0.0 * @throws \RuntimeException */ public function insertObject($table, &$object, $key = null) { $fields = []; $values = []; $tableColumns = $this->getTableColumns($table); // Iterate over the object variables to build the query fields and values. foreach (get_object_vars($object) as $k => $v) { // Skip columns that don't exist in the table. if (!array_key_exists($k, $tableColumns)) { continue; } // Only process non-null scalars. if (\is_array($v) || \is_object($v) || $v === null) { continue; } // Ignore any internal fields. if ($k[0] === '_') { continue; } // Ignore null datetime fields. if ($tableColumns[$k] === 'datetime' && empty($v)) { continue; } // Ignore null integer fields. if (stristr($tableColumns[$k], 'int') !== false && $v === '') { continue; } // Prepare and sanitize the fields and values for the database query. $fields[] = $this->quoteName($k); $values[] = $this->quote($v); } // Create the base insert statement. $query = $this->createQuery() ->insert($this->quoteName($table)) ->columns($fields) ->values(implode(',', $values)); // Set the query and execute the insert. $this->setQuery($query)->execute(); // Update the primary key if it exists. $id = $this->insertid(); if ($key && $id && \is_string($key)) { $object->$key = $id; } return true; } /** * Locks a table in the database. * * @param string $table The name of the table to unlock. * * @return $this * * @since 1.0 * @throws \RuntimeException */ public function lockTable($table) { $this->executeUnpreparedQuery($this->replacePrefix('LOCK TABLES ' . $this->quoteName($table) . ' WRITE')); return $this; } /** * Renames a table in the database. * * @param string $oldTable The name of the table to be renamed * @param string $newTable The new name for the table. * @param string $backup Not used by MySQL. * @param string $prefix Not used by MySQL. * * @return $this * * @since 1.0 * @throws \RuntimeException */ public function renameTable($oldTable, $newTable, $backup = null, $prefix = null) { $this->setQuery('RENAME TABLE ' . $oldTable . ' TO ' . $newTable)->execute(); return $this; } /** * Select a database for use. * * @param string $database The name of the database to select for use. * * @return boolean True if the database was successfully selected. * * @since 1.0 * @throws \RuntimeException */ public function select($database) { $this->connect(); if (!$database) { return false; } if (!$this->connection->select_db($database)) { throw new ConnectionFailureException('Could not connect to database.'); } return true; } /** * Set the connection to use UTF-8 character encoding. * * @return boolean True on success. * * @since 1.0 */ public function setUtf() { // If UTF is not supported return false immediately if (!$this->utf) { return false; } // Make sure we're connected to the server $this->connect(); // Which charset should I use, plain utf8 or multibyte utf8mb4? $charset = $this->utf8mb4 && $this->options['utf8mb4'] ? 'utf8mb4' : 'utf8'; $result = @$this->connection->set_charset($charset); /* * If I could not set the utf8mb4 charset then the server doesn't support utf8mb4 despite claiming otherwise. This happens on old MySQL * server versions (less than 5.5.3) using the mysqlnd PHP driver. Since mysqlnd masks the server version and reports only its own we * can not be sure if the server actually does support UTF-8 Multibyte (i.e. it's MySQL 5.5.3 or later). Since the utf8mb4 charset is * undefined in this case we catch the error and determine that utf8mb4 is not supported! */ if (!$result && $this->utf8mb4 && $this->options['utf8mb4']) { $this->utf8mb4 = false; $result = @$this->connection->set_charset('utf8'); } return $result; } /** * Method to commit a transaction. * * @param boolean $toSavepoint If true, commit to the last savepoint. * * @return void * * @since 1.0 * @throws \RuntimeException */ public function transactionCommit($toSavepoint = false) { if (!$toSavepoint || $this->transactionDepth <= 1) { $this->connect(); if ($this->connection->commit()) { $this->transactionDepth = 0; } return; } $this->transactionDepth--; } /** * Method to roll back a transaction. * * @param boolean $toSavepoint If true, rollback to the last savepoint. * * @return void * * @since 1.0 * @throws \RuntimeException */ public function transactionRollback($toSavepoint = false) { if (!$toSavepoint || $this->transactionDepth <= 1) { $this->connect(); if ($this->connection->rollback()) { $this->transactionDepth = 0; } return; } $savepoint = 'SP_' . ($this->transactionDepth - 1); if ($this->executeUnpreparedQuery('ROLLBACK TO SAVEPOINT ' . $this->quoteName($savepoint))) { $this->transactionDepth--; } } /** * Method to initialize a transaction. * * @param boolean $asSavepoint If true and a transaction is already active, a savepoint will be created. * * @return void * * @since 1.0 * @throws \RuntimeException */ public function transactionStart($asSavepoint = false) { $this->connect(); if (!$asSavepoint || !$this->transactionDepth) { if ($this->connection->begin_transaction()) { $this->transactionDepth = 1; } return; } $savepoint = 'SP_' . $this->transactionDepth; if ($this->connection->savepoint($savepoint)) { $this->transactionDepth++; } } /** * Internal method to execute queries which cannot be run as prepared statements. * * @param string $sql SQL statement to execute. * * @return boolean * * @since 1.5.0 */ protected function executeUnpreparedQuery($sql) { $this->connect(); $cursor = $this->connection->query($sql); // If an error occurred handle it. if (!$cursor) { $errorNum = (int) $this->connection->errno; $errorMsg = (string) $this->connection->error; // Check if the server was disconnected. if (!$this->connected()) { try { // Attempt to reconnect. $this->connection = null; $this->connect(); } catch (ConnectionFailureException $e) { // If connect fails, ignore that exception and throw the normal exception. throw new ExecutionFailureException($sql, $errorMsg, $errorNum); } // Since we were able to reconnect, run the query again. return $this->executeUnpreparedQuery($sql); } // The server was not disconnected. throw new ExecutionFailureException($sql, $errorMsg, $errorNum); } $this->freeResult(); if ($cursor instanceof \mysqli_result) { $cursor->free_result(); } return true; } /** * Prepares a SQL statement for execution * * @param string $query The SQL query to be prepared. * * @return StatementInterface * * @since 2.0.0 * @throws PrepareStatementFailureException */ protected function prepareStatement(string $query): StatementInterface { return new MysqliStatement($this->connection, $query); } /** * Unlocks tables in the database. * * @return $this * * @since 1.0 * @throws \RuntimeException */ public function unlockTables() { $this->executeUnpreparedQuery('UNLOCK TABLES'); return $this; } /** * Does the database server claim to have support for UTF-8 Multibyte (utf8mb4) collation? * * libmysql supports utf8mb4 since 5.5.3 (same version as the MySQL server). mysqlnd supports utf8mb4 since 5.0.9. * * @return boolean * * @since 1.4.0 */ private function serverClaimsUtf8mb4Support() { $client_version = mysqli_get_client_info(); $server_version = $this->getVersion(); if (version_compare($server_version, '5.5.3', '<')) { return false; } if ($this->mariadb && version_compare($server_version, '10.0.0', '<')) { return false; } if (strpos($client_version, 'mysqlnd') !== false) { $client_version = preg_replace('/^\D+([\d.]+).*/', '$1', $client_version); return version_compare($client_version, '5.0.9', '>='); } return version_compare($client_version, '5.5.3', '>='); } /** * Get the null or zero representation of a timestamp for the database driver. * * @return string * * @since 2.0.0 */ public function getNullDate() { // Check the session sql mode; if (\in_array('NO_ZERO_DATE', $this->options['sqlModes']) !== false) { $this->nullDate = '1000-01-01 00:00:00'; } return $this->nullDate; } } PK .8�\e�Bl� � MysqliExporter.phpnu �[��� <?php /** * Part of the Joomla Framework Database Package * * @copyright Copyright (C) 2005 - 2021 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Database\Mysqli; use Joomla\Database\DatabaseExporter; /** * MySQLi Database Exporter. * * @since 1.0 */ class MysqliExporter extends DatabaseExporter { /** * Builds the XML data for the tables to export. * * @return string An XML string * * @since 1.0 * @throws \Exception if an error occurs. */ protected function buildXml() { $buffer = []; $buffer[] = '<?xml version="1.0"?>'; $buffer[] = '<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'; $buffer[] = ' <database name="">'; if ($this->options->withStructure) { $buffer = array_merge($buffer, $this->buildXmlStructure()); } if ($this->options->withData) { $buffer = array_merge($buffer, $this->buildXmlData()); } $buffer[] = ' </database>'; $buffer[] = '</mysqldump>'; return implode("\n", $buffer); } /** * Builds the XML structure to export. * * @return array An array of XML lines (strings). * * @since 1.0 * @throws \Exception if an error occurs. */ protected function buildXmlStructure() { $buffer = []; foreach ($this->from as $table) { // Replace the magic prefix if found. $table = $this->getGenericTableName($table); // Get the details columns information. $fields = $this->db->getTableColumns($table, false); $keys = $this->db->getTableKeys($table); $buffer[] = ' <table_structure name="' . $table . '">'; foreach ($fields as $field) { $buffer[] = ' <field Field="' . $field->Field . '" Type="' . $field->Type . '" Null="' . $field->Null . '" Key="' . $field->Key . '"' . (isset($field->Default) ? ' Default="' . $field->Default . '"' : '') . ' Extra="' . $field->Extra . '"' . ' />'; } foreach ($keys as $key) { $buffer[] = ' <key Table="' . $table . '" Non_unique="' . $key->Non_unique . '" Key_name="' . $key->Key_name . '"' . ' Seq_in_index="' . $key->Seq_in_index . '" Column_name="' . $key->Column_name . '" Collation="' . $key->Collation . '"' . ' Null="' . $key->Null . '" Index_type="' . $key->Index_type . '"' . ' Sub_part="' . $key->Sub_part . '"' . ' Comment="' . htmlspecialchars($key->Comment, \ENT_COMPAT, 'UTF-8') . '"' . ' />'; } $buffer[] = ' </table_structure>'; } return $buffer; } /** * Checks if all data and options are in order prior to exporting. * * @return $this * * @since 1.0 * @throws \RuntimeException */ public function check() { // Check if the db connector has been set. if (!($this->db instanceof MysqliDriver)) { throw new \RuntimeException('Database connection wrong type.'); } // Check if the tables have been specified. if (empty($this->from)) { throw new \RuntimeException('ERROR: No Tables Specified'); } return $this; } } PK .8�\RH �9 �9 MysqliStatement.phpnu �[��� <?php /** * Part of the Joomla Framework Database Package * * @copyright Copyright (C) 2005 - 2021 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Database\Mysqli; use Joomla\Database\Exception\ExecutionFailureException; use Joomla\Database\Exception\PrepareStatementFailureException; use Joomla\Database\FetchMode; use Joomla\Database\FetchOrientation; use Joomla\Database\ParameterType; use Joomla\Database\StatementInterface; /** * MySQLi Database Statement. * * This class is modeled on \Doctrine\DBAL\Driver\Mysqli\MysqliStatement * * @since 2.0.0 */ class MysqliStatement implements StatementInterface { /** * Values which have been bound to the statement. * * @var array * @since 2.0.0 */ protected $bindedValues; /** * Mapping between named parameters and position in query. * * @var array * @since 2.0.0 */ protected $parameterKeyMapping; /** * Mapping array for parameter types. * * @var array * @since 2.0.0 */ protected $parameterTypeMapping = [ ParameterType::BOOLEAN => 'i', ParameterType::INTEGER => 'i', ParameterType::LARGE_OBJECT => 's', ParameterType::NULL => 's', ParameterType::STRING => 's', ]; /** * Column names from the executed statement. * * @var array|boolean|null * @since 2.0.0 */ protected $columnNames; /** * The database connection resource. * * @var \mysqli * @since 2.0.0 */ protected $connection; /** * The default fetch mode for the statement. * * @var integer * @since 2.0.0 */ protected $defaultFetchStyle = FetchMode::MIXED; /** * The query string being prepared. * * @var string * @since 2.0.0 */ protected $query; /** * Internal tracking flag to set whether there is a result set available for processing * * @var boolean * @since 2.0.0 */ private $result = false; /** * Values which have been bound to the rows of each result set. * * @var array * @since 2.0.0 */ protected $rowBindedValues; /** * The prepared statement. * * @var \mysqli_stmt * @since 2.0.0 */ protected $statement; /** * Bound parameter types. * * @var array * @since 2.0.0 */ protected $typesKeyMapping; /** * Constructor. * * @param \mysqli $connection The database connection resource * @param string $query The query this statement will process * * @since 2.0.0 * @throws PrepareStatementFailureException */ public function __construct(\mysqli $connection, string $query) { $this->connection = $connection; $this->query = $query; $query = $this->prepareParameterKeyMapping($query); $this->statement = $connection->prepare($query); if (!$this->statement) { throw new PrepareStatementFailureException($this->connection->error, $this->connection->errno); } } /** * Replace named parameters with numbered parameters * * @param string $sql The SQL statement to prepare. * * @return string The processed SQL statement. * * @since 2.0.0 */ public function prepareParameterKeyMapping($sql) { $escaped = false; $startPos = 0; $quoteChar = ''; $literal = ''; $mapping = []; $replace = []; $matches = []; $pattern = '/([:][a-zA-Z0-9_]+)/'; if (!preg_match($pattern, $sql, $matches)) { return $sql; } $sql = trim($sql); $n = \strlen($sql); while ($startPos < $n) { if (!preg_match($pattern, $sql, $matches, 0, $startPos)) { break; } $j = strpos($sql, "'", $startPos); $k = strpos($sql, '"', $startPos); if (($k !== false) && (($k < $j) || ($j === false))) { $quoteChar = '"'; $j = $k; } else { $quoteChar = "'"; } if ($j === false) { $j = $n; } // Search for named prepared parameters and replace it with ? and save its position $substring = substr($sql, $startPos, $j - $startPos); if (preg_match_all($pattern, $substring, $matches, PREG_PATTERN_ORDER + PREG_OFFSET_CAPTURE)) { foreach ($matches[0] as $i => $match) { if ($i === 0) { $literal .= substr($substring, 0, $match[1]); } $mapping[$match[0]] = \count($mapping); $endOfPlaceholder = $match[1] + strlen($match[0]); $beginOfNextPlaceholder = $matches[0][$i + 1][1] ?? strlen($substring); $beginOfNextPlaceholder -= $endOfPlaceholder; $literal .= '?' . substr($substring, $endOfPlaceholder, $beginOfNextPlaceholder); } } else { $literal .= $substring; } $startPos = $j; $j++; if ($j >= $n) { break; } // Quote comes first, find end of quote while (true) { $k = strpos($sql, $quoteChar, $j); $escaped = false; if ($k === false) { break; } $l = $k - 1; while ($l >= 0 && $sql[$l] === '\\') { $l--; $escaped = !$escaped; } if ($escaped) { $j = $k + 1; continue; } break; } if ($k === false) { // Error in the query - no end quote; ignore it break; } $literal .= substr($sql, $startPos, $k - $startPos + 1); $startPos = $k + 1; } if ($startPos < $n) { $literal .= substr($sql, $startPos, $n - $startPos); } $this->parameterKeyMapping = $mapping; return $literal; } /** * Binds a parameter to the specified variable name. * * @param string|integer $parameter Parameter identifier. For a prepared statement using named placeholders, this will be a parameter * name of the form `:name`. For a prepared statement using question mark placeholders, this will be * the 1-indexed position of the parameter. * @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter. * @param integer $dataType Constant corresponding to a SQL datatype, this should be the processed type from the QueryInterface. * @param integer $length The length of the variable. Usually required for OUTPUT parameters. * @param array $driverOptions Optional driver options to be used. * * @return boolean * * @since 2.0.0 */ public function bindParam($parameter, &$variable, string $dataType = ParameterType::STRING, ?int $length = null, ?array $driverOptions = null) { $this->bindedValues[$parameter] =& $variable; // Validate parameter type if (!isset($this->parameterTypeMapping[$dataType])) { throw new \InvalidArgumentException(sprintf('Unsupported parameter type `%s`', $dataType)); } $this->typesKeyMapping[$parameter] = $this->parameterTypeMapping[$dataType]; return true; } /** * Binds a array of values to bound parameters. * * @param array $values The values to bind to the statement * * @return boolean * * @since 2.0.0 */ private function bindValues(array $values) { $params = []; $types = str_repeat('s', \count($values)); if (!empty($this->parameterKeyMapping)) { foreach ($values as $key => &$value) { $params[$this->parameterKeyMapping[$key]] =& $value; } ksort($params); } else { foreach ($values as $key => &$value) { $params[] =& $value; } } array_unshift($params, $types); return \call_user_func_array([$this->statement, 'bind_param'], $params); } /** * Closes the cursor, enabling the statement to be executed again. * * @return void * * @since 2.0.0 */ public function closeCursor(): void { $this->statement->free_result(); $this->result = false; } /** * Fetches the SQLSTATE associated with the last operation on the statement handle. * * @return string * * @since 2.0.0 */ public function errorCode() { return $this->statement->errno; } /** * Fetches extended error information associated with the last operation on the statement handle. * * @return array * * @since 2.0.0 */ public function errorInfo() { return $this->statement->error; } /** * Executes a prepared statement * * @param array|null $parameters An array of values with as many elements as there are bound parameters in the SQL statement being executed. * * @return boolean * * @since 2.0.0 */ public function execute(?array $parameters = null) { if ($this->bindedValues !== null) { $params = []; $types = []; if (!empty($this->parameterKeyMapping)) { foreach ($this->bindedValues as $key => &$value) { $params[$this->parameterKeyMapping[$key]] =& $value; $types[$this->parameterKeyMapping[$key]] = $this->typesKeyMapping[$key]; } } else { foreach ($this->bindedValues as $key => &$value) { $params[] =& $value; $types[$key] = $this->typesKeyMapping[$key]; } } ksort($params); ksort($types); array_unshift($params, implode('', $types)); if (!\call_user_func_array([$this->statement, 'bind_param'], $params)) { throw new PrepareStatementFailureException($this->statement->error, $this->statement->errno); } } elseif ($parameters !== null) { if (!$this->bindValues($parameters)) { throw new PrepareStatementFailureException($this->statement->error, $this->statement->errno); } } try { if (!$this->statement->execute()) { throw new ExecutionFailureException($this->query, $this->statement->error, $this->statement->errno); } } catch (\Throwable $e) { throw new ExecutionFailureException($this->query, $e->getMessage(), $e->getCode(), $e); } if ($this->columnNames === null) { $meta = $this->statement->result_metadata(); if ($meta !== false) { $columnNames = []; foreach ($meta->fetch_fields() as $col) { $columnNames[] = $col->name; } $meta->free(); $this->columnNames = $columnNames; } else { $this->columnNames = false; } } if ($this->columnNames !== false) { $this->statement->store_result(); $this->rowBindedValues = array_fill(0, \count($this->columnNames), null); $refs = []; foreach ($this->rowBindedValues as $key => &$value) { $refs[$key] =& $value; } if (!\call_user_func_array([$this->statement, 'bind_result'], $refs)) { throw new \RuntimeException($this->statement->error, $this->statement->errno); } } $this->result = true; return true; } /** * Fetches the next row from a result set * * @param integer|null $fetchStyle Controls how the next row will be returned to the caller. This value must be one of the * FetchMode constants, defaulting to value of FetchMode::MIXED. * @param integer $cursorOrientation For a StatementInterface object representing a scrollable cursor, this value determines which row * will be returned to the caller. This value must be one of the FetchOrientation constants, * defaulting to FetchOrientation::NEXT. * @param integer $cursorOffset For a StatementInterface object representing a scrollable cursor for which the cursorOrientation * parameter is set to FetchOrientation::ABS, this value specifies the absolute number of the row in * the result set that shall be fetched. For a StatementInterface object representing a scrollable * cursor for which the cursorOrientation parameter is set to FetchOrientation::REL, this value * specifies the row to fetch relative to the cursor position before `fetch()` was called. * * @return mixed The return value of this function on success depends on the fetch type. In all cases, boolean false is returned on failure. * * @since 2.0.0 */ public function fetch(?int $fetchStyle = null, int $cursorOrientation = FetchOrientation::NEXT, int $cursorOffset = 0) { if (!$this->result) { return false; } $fetchStyle = $fetchStyle ?: $this->defaultFetchStyle; if ($fetchStyle === FetchMode::COLUMN) { return $this->fetchColumn(); } $values = $this->fetchData(); if ($values === null) { return false; } if ($values === false) { throw new \RuntimeException($this->statement->error, $this->statement->errno); } switch ($fetchStyle) { case FetchMode::NUMERIC: return $values; case FetchMode::ASSOCIATIVE: return array_combine($this->columnNames, $values); case FetchMode::MIXED: $ret = array_combine($this->columnNames, $values); $ret += $values; return $ret; case FetchMode::STANDARD_OBJECT: return (object) array_combine($this->columnNames, $values); default: throw new \InvalidArgumentException("Unknown fetch type '{$fetchStyle}'"); } } /** * Returns a single column from the next row of a result set * * @param integer $columnIndex 0-indexed number of the column you wish to retrieve from the row. * If no value is supplied, the first column is retrieved. * * @return mixed Returns a single column from the next row of a result set or boolean false if there are no more rows. * * @since 2.0.0 */ public function fetchColumn($columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); if ($row === false) { return false; } return $row[$columnIndex] ?? null; } /** * Fetch the data from the statement. * * @return array|boolean * * @since 2.0.0 */ private function fetchData() { $return = $this->statement->fetch(); if ($return === true) { $values = []; foreach ($this->rowBindedValues as $v) { $values[] = $v; } return $values; } return $return; } /** * Returns the number of rows affected by the last SQL statement. * * @return integer * * @since 2.0.0 */ public function rowCount(): int { if ($this->columnNames === false) { return $this->statement->affected_rows; } return $this->statement->num_rows; } /** * Sets the fetch mode to use while iterating this statement. * * @param integer $fetchMode The fetch mode, must be one of the FetchMode constants. * @param mixed ...$args Optional mode-specific arguments. * * @return void * * @since 2.0.0 */ public function setFetchMode(int $fetchMode, ...$args): void { $this->defaultFetchStyle = $fetchMode; } } PK .8�\�h#. . MysqliImporter.phpnu �[��� <?php /** * Part of the Joomla Framework Database Package * * @copyright Copyright (C) 2005 - 2021 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Database\Mysqli; use Joomla\Database\DatabaseImporter; /** * MySQLi Database Importer. * * @since 1.0 */ class MysqliImporter extends DatabaseImporter { /** * Checks if all data and options are in order prior to exporting. * * @return $this * * @since 1.0 * @throws \RuntimeException */ public function check() { // Check if the db connector has been set. if (!($this->db instanceof MysqliDriver)) { throw new \RuntimeException('Database connection wrong type.'); } // Check if the tables have been specified. if (empty($this->from)) { throw new \RuntimeException('ERROR: No Tables Specified'); } return $this; } /** * Get the SQL syntax to add a table. * * @param \SimpleXMLElement $table The table information. * * @return string * * @since 1.4.0 * @throws \RuntimeException */ protected function xmlToCreate(\SimpleXMLElement $table) { $existingTables = $this->db->getTableList(); $tableName = (string) $table['name']; if (\in_array($tableName, $existingTables, true)) { throw new \RuntimeException('The table you are trying to create already exists'); } $createTableStatement = 'CREATE TABLE ' . $this->db->quoteName($tableName) . ' ('; foreach ($table->xpath('field') as $field) { $createTableStatement .= $this->getColumnSql($field) . ', '; } $newLookup = $this->getKeyLookup($table->xpath('key')); foreach ($newLookup as $key) { $createTableStatement .= $this->getKeySql($key) . ', '; } $createTableStatement = rtrim($createTableStatement, ', '); $createTableStatement .= ')'; return $createTableStatement; } /** * Get the SQL syntax to add a key. * * @param string $table The table name. * @param array $keys An array of the fields pertaining to this key. * * @return string * * @since 1.0 */ protected function getAddKeySql($table, $keys) { return 'ALTER TABLE ' . $this->db->quoteName($table) . ' ADD ' . $this->getKeySql($keys); } /** * Get alters for table if there is a difference. * * @param \SimpleXMLElement $structure The XML structure of the table. * * @return array * * @since 1.0 */ protected function getAlterTableSql(\SimpleXMLElement $structure) { $table = $this->getRealTableName($structure['name']); $oldFields = $this->db->getTableColumns($table, false); $oldKeys = $this->db->getTableKeys($table); $alters = []; // Get the fields and keys from the XML that we are aiming for. $newFields = $structure->xpath('field'); $newKeys = $structure->xpath('key'); // Loop through each field in the new structure. foreach ($newFields as $field) { $fName = (string) $field['Field']; if (isset($oldFields[$fName])) { // The field exists, check it's the same. $column = $oldFields[$fName]; // Test whether there is a change. $change = ((string) $field['Type'] !== $column->Type) || ((string) $field['Null'] !== $column->Null) || ((string) $field['Default'] !== $column->Default) || ((string) $field['Extra'] !== $column->Extra); if ($change) { $alters[] = $this->getChangeColumnSql($table, $field); } // Unset this field so that what we have left are fields that need to be removed. unset($oldFields[$fName]); } else { // The field is new. $alters[] = $this->getAddColumnSql($table, $field); } } // Any columns left are orphans foreach ($oldFields as $name => $column) { // Delete the column. $alters[] = $this->getDropColumnSql($table, $name); } // Get the lookups for the old and new keys. $oldLookup = $this->getKeyLookup($oldKeys); $newLookup = $this->getKeyLookup($newKeys); // Loop through each key in the new structure. foreach ($newLookup as $name => $keys) { // Check if there are keys on this field in the existing table. if (isset($oldLookup[$name])) { $same = true; $newCount = \count($newLookup[$name]); $oldCount = \count($oldLookup[$name]); // There is a key on this field in the old and new tables. Are they the same? if ($newCount === $oldCount) { // Need to loop through each key and do a fine grained check. for ($i = 0; $i < $newCount; $i++) { $same = (((string) $newLookup[$name][$i]['Non_unique'] === $oldLookup[$name][$i]->Non_unique) && ((string) $newLookup[$name][$i]['Column_name'] === $oldLookup[$name][$i]->Column_name) && ((string) $newLookup[$name][$i]['Seq_in_index'] === $oldLookup[$name][$i]->Seq_in_index) && ((string) $newLookup[$name][$i]['Collation'] === $oldLookup[$name][$i]->Collation) && ((string) $newLookup[$name][$i]['Sub_part'] == $oldLookup[$name][$i]->Sub_part) && ((string) $newLookup[$name][$i]['Index_type'] === $oldLookup[$name][$i]->Index_type)); /* Debug. echo '<pre>'; echo '<br>Non_unique: '. ((string) $newLookup[$name][$i]['Non_unique'] == $oldLookup[$name][$i]->Non_unique ? 'Pass' : 'Fail').' '. (string) $newLookup[$name][$i]['Non_unique'].' vs '.$oldLookup[$name][$i]->Non_unique; echo '<br>Column_name: '. ((string) $newLookup[$name][$i]['Column_name'] == $oldLookup[$name][$i]->Column_name ? 'Pass' : 'Fail').' '. (string) $newLookup[$name][$i]['Column_name'].' vs '.$oldLookup[$name][$i]->Column_name; echo '<br>Seq_in_index: '. ((string) $newLookup[$name][$i]['Seq_in_index'] == $oldLookup[$name][$i]->Seq_in_index ? 'Pass' : 'Fail').' '. (string) $newLookup[$name][$i]['Seq_in_index'].' vs '.$oldLookup[$name][$i]->Seq_in_index; echo '<br>Collation: '. ((string) $newLookup[$name][$i]['Collation'] == $oldLookup[$name][$i]->Collation ? 'Pass' : 'Fail').' '. (string) $newLookup[$name][$i]['Collation'].' vs '.$oldLookup[$name][$i]->Collation; echo '<br>Sub_part: '. ((string) $newLookup[$name][$i]['Sub_part'] == $oldLookup[$name][$i]->Sub_part ? 'Pass' : 'Fail').' '. (string) $newLookup[$name][$i]['Sub_part'].' vs '.$oldLookup[$name][$i]->Sub_part; echo '<br>Index_type: '. ((string) $newLookup[$name][$i]['Index_type'] == $oldLookup[$name][$i]->Index_type ? 'Pass' : 'Fail').' '. (string) $newLookup[$name][$i]['Index_type'].' vs '.$oldLookup[$name][$i]->Index_type; echo '<br>Same = '.($same ? 'true' : 'false'); echo '</pre>'; */ if (!$same) { // Break out of the loop. No need to check further. break; } } } else { // Count is different, just drop and add. $same = false; } if (!$same) { $alters[] = $this->getDropKeySql($table, $name); $alters[] = $this->getAddKeySql($table, $keys); } // Unset this field so that what we have left are fields that need to be removed. unset($oldLookup[$name]); } else { // This is a new key. $alters[] = $this->getAddKeySql($table, $keys); } } // Any keys left are orphans. foreach ($oldLookup as $name => $keys) { if (strtoupper($name) === 'PRIMARY') { $alters[] = $this->getDropPrimaryKeySql($table); } else { $alters[] = $this->getDropKeySql($table, $name); } } return $alters; } /** * Get the syntax to alter a column. * * @param string $table The name of the database table to alter. * @param \SimpleXMLElement $field The XML definition for the field. * * @return string * * @since 1.0 */ protected function getChangeColumnSql($table, \SimpleXMLElement $field) { return 'ALTER TABLE ' . $this->db->quoteName($table) . ' CHANGE COLUMN ' . $this->db->quoteName((string) $field['Field']) . ' ' . $this->getColumnSql($field); } /** * Get the SQL syntax for a single column that would be included in a table create or alter statement. * * @param \SimpleXMLElement $field The XML field definition. * * @return string * * @since 1.0 */ protected function getColumnSql(\SimpleXMLElement $field) { // TODO Incorporate into parent class and use $this. $blobs = ['text', 'smalltext', 'mediumtext', 'largetext']; $fName = (string) $field['Field']; $fType = (string) $field['Type']; $fNull = (string) $field['Null']; $fDefault = isset($field['Default']) ? (string) $field['Default'] : null; $fExtra = (string) $field['Extra']; $sql = $this->db->quoteName($fName) . ' ' . $fType; if ($fNull === 'NO') { if ($fDefault === null || \in_array($fType, $blobs, true)) { $sql .= ' NOT NULL'; } else { // TODO Don't quote numeric values. if (stristr($fDefault, 'CURRENT') !== false) { $sql .= ' NOT NULL DEFAULT CURRENT_TIMESTAMP()'; } else { $sql .= ' NOT NULL DEFAULT ' . $this->db->quote($fDefault); } } } else { if ($fDefault === null) { $sql .= ' DEFAULT NULL'; } else { // TODO Don't quote numeric values. $sql .= ' DEFAULT ' . $this->db->quote($fDefault); } } if ($fExtra) { // MySql 8.0 introduces DEFAULT_GENERATED in the extra column and should be replaced with the default value if (stristr($fExtra, 'DEFAULT_GENERATED') !== false) { $sql .= ' ' . strtoupper(str_ireplace('DEFAULT_GENERATED', 'DEFAULT ' . $fDefault, $fExtra)); } else { $sql .= ' ' . strtoupper($fExtra); } } return $sql; } /** * Get the SQL syntax to drop a key. * * @param string $table The table name. * @param string $name The name of the key to drop. * * @return string * * @since 1.0 */ protected function getDropKeySql($table, $name) { return 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP KEY ' . $this->db->quoteName($name); } /** * Get the SQL syntax to drop a key. * * @param string $table The table name. * * @return string * * @since 1.0 */ protected function getDropPrimaryKeySql($table) { return 'ALTER TABLE ' . $this->db->quoteName($table) . ' DROP PRIMARY KEY'; } /** * Get the details list of keys for a table. * * @param array $keys An array of objects that comprise the keys for the table. * * @return array The lookup array. array({key name} => array(object, ...)) * * @since 1.0 */ protected function getKeyLookup($keys) { // First pass, create a lookup of the keys. $lookup = []; foreach ($keys as $key) { if ($key instanceof \SimpleXMLElement) { $kName = (string) $key['Key_name']; } else { $kName = $key->Key_name; } if (empty($lookup[$kName])) { $lookup[$kName] = []; } $lookup[$kName][] = $key; } return $lookup; } /** * Get the SQL syntax for a key. * * @param array $columns An array of SimpleXMLElement objects comprising the key. * * @return string * * @since 1.0 */ protected function getKeySql($columns) { $kNonUnique = (string) $columns[0]['Non_unique']; $kName = (string) $columns[0]['Key_name']; $prefix = ''; if ($kName === 'PRIMARY') { $prefix = 'PRIMARY '; } elseif ($kNonUnique == 0) { $prefix = 'UNIQUE '; } $kColumns = []; foreach ($columns as $column) { $kLength = ''; if (!empty($column['Sub_part'])) { $kLength = '(' . $column['Sub_part'] . ')'; } $kColumns[] = $this->db->quoteName((string) $column['Column_name']) . $kLength; } return $prefix . 'KEY ' . ($kName !== 'PRIMARY' ? $this->db->quoteName($kName) : '') . ' (' . implode(',', $kColumns) . ')'; } } PK .8�\�?�� � MysqliQuery.phpnu �[��� <?php /** * Part of the Joomla Framework Database Package * * @copyright Copyright (C) 2005 - 2021 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\Database\Mysqli; use Joomla\Database\DatabaseQuery; use Joomla\Database\Query\MysqlQueryBuilder; /** * MySQLi Query Building Class. * * @since 1.0 */ class MysqliQuery extends DatabaseQuery { use MysqlQueryBuilder; /** * The list of zero or null representation of a datetime. * * @var array * @since 2.0.0 */ protected $nullDatetimeList = ['0000-00-00 00:00:00', '1000-01-01 00:00:00']; } PK .8�\����s s MysqliDriver.phpnu �[��� PK .8�\e�Bl� � Us MysqliExporter.phpnu �[��� PK .8�\RH �9 �9 u MysqliStatement.phpnu �[��� PK .8�\�h#. . g� MysqliImporter.phpnu �[��� PK .8�\�?�� � �� MysqliQuery.phpnu �[��� PK � ��
| ver. 1.4 |
Github
|
.
| PHP 8.3.23 | Generation time: 0 |
proxy
|
phpinfo
|
Settings