__  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ V /  | |__) | __ ___   ____ _| |_ ___  | (___ | |__   ___| | |
 | |\/| | '__|> <   |  ___/ '__| \ \ / / _` | __/ _ \  \___ \| '_ \ / _ \ | |
 | |  | | |_ / . \  | |   | |  | |\ V / (_| | ||  __/  ____) | | | |  __/ | |
 |_|  |_|_(_)_/ \_\ |_|   |_|  |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1
 if you need WebShell for Seo everyday contact me on Telegram
 Telegram Address : @jackleet
        
        
For_More_Tools: Telegram: @jackleet | Bulk Smtp support mail sender | Business Mail Collector | Mail Bouncer All Mail | Bulk Office Mail Validator | Html Letter private



Upload:

Command:

[email protected]: ~ $
<?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;

use Joomla\Database\Event\ConnectionEvent;
use Joomla\Database\Exception\ConnectionFailureException;
use Joomla\Database\Exception\ExecutionFailureException;
use Joomla\Database\Exception\PrepareStatementFailureException;
use Joomla\Event\DispatcherAwareInterface;
use Joomla\Event\DispatcherAwareTrait;
use Joomla\Event\EventInterface;

/**
 * Joomla Framework Database Driver Class
 *
 * @since  1.0
 */
abstract class DatabaseDriver implements DatabaseInterface, DispatcherAwareInterface
{
	use DispatcherAwareTrait;

	/**
	 * The name of the database.
	 *
	 * @var    string
	 * @since  1.0
	 */
	private $database;

	/**
	 * The name of the database driver.
	 *
	 * @var    string
	 * @since  1.0
	 */
	protected $name;

	/**
	 * The type of the database server family supported by this driver.
	 *
	 * @var    string
	 * @since  1.4.0
	 */
	public $serverType;

	/**
	 * The database connection resource.
	 *
	 * @var    resource
	 * @since  1.0
	 */
	protected $connection;

	/**
	 * Holds the list of available db connectors.
	 *
	 * @var    array
	 * @since  1.0
	 */
	protected static $connectors = [];

	/**
	 * The number of SQL statements executed by the database driver.
	 *
	 * @var    integer
	 * @since  1.0
	 */
	protected $count = 0;

	/**
	 * The database connection cursor from the last query.
	 *
	 * @var    resource
	 * @since  1.0
	 */
	protected $cursor;

	/**
	 * Contains the current query execution status
	 *
	 * @var    boolean
	 * @since  2.0.0
	 */
	protected $executed = false;

	/**
	 * The affected row limit for the current SQL statement.
	 *
	 * @var    integer
	 * @since  1.0
	 */
	protected $limit = 0;

	/**
	 * 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;

	/**
	 * The affected row offset to apply for the current SQL statement.
	 *
	 * @var    integer
	 * @since  1.0
	 */
	protected $offset = 0;

	/**
	 * Passed in upon instantiation and saved.
	 *
	 * @var    array
	 * @since  1.0
	 */
	protected $options;

	/**
	 * The current SQL statement to execute.
	 *
	 * @var    mixed
	 * @since  1.0
	 */
	protected $sql;

	/**
	 * The prepared statement.
	 *
	 * @var    StatementInterface
	 * @since  2.0.0
	 */
	protected $statement;

	/**
	 * The common database table prefix.
	 *
	 * @var    string
	 * @since  1.0
	 */
	protected $tablePrefix;

	/**
	 * True if the database engine supports UTF-8 character encoding.
	 *
	 * @var    boolean
	 * @since  1.0
	 */
	protected $utf = true;

	/**
	 * The database error number.
	 *
	 * @var    integer
	 * @since  1.0
	 */
	protected $errorNum = 0;

	/**
	 * The database error message.
	 *
	 * @var    string
	 * @since  1.0
	 */
	protected $errorMsg;

	/**
	 * DatabaseDriver instances container.
	 *
	 * @var    DatabaseDriver[]
	 * @since  1.0
	 * @deprecated  3.0  Singleton storage will no longer be supported.
	 */
	protected static $instances = [];

	/**
	 * The minimum supported database version.
	 *
	 * @var    string
	 * @since  1.0
	 */
	protected static $dbMinimum;

	/**
	 * The depth of the current transaction.
	 *
	 * @var    integer
	 * @since  1.0
	 */
	protected $transactionDepth = 0;

	/**
	 * DatabaseFactory object
	 *
	 * @var    DatabaseFactory
	 * @since  2.0.0
	 */
	protected $factory;

	/**
	 * Query monitor object
	 *
	 * @var    QueryMonitorInterface
	 * @since  2.0.0
	 */
	protected $monitor;

	/**
	 * Get a list of available database connectors.
	 *
	 * The list will only be populated with connectors that the class exists for and the environment supports its use.
	 * This gives us the ability to have a multitude of connector classes that are self-aware as to whether or not they
	 * are able to be used on a given system.
	 *
	 * @return  array  An array of available database connectors.
	 *
	 * @since   1.0
	 */
	public static function getConnectors()
	{
		if (empty(self::$connectors))
		{
			// Get an iterator and loop trough the driver classes.
			$dir      = __DIR__;
			$iterator = new \DirectoryIterator($dir);

			/** @var $file \DirectoryIterator */
			foreach ($iterator as $file)
			{
				// Only load for php files.
				if (!$file->isDir())
				{
					continue;
				}

				$baseName = $file->getBasename();

				// Derive the class name from the type.
				/** @var $class DatabaseDriver */
				$class = __NAMESPACE__ . '\\' . ucfirst(strtolower($baseName)) . '\\' . ucfirst(strtolower($baseName)) . 'Driver';

				// If the class doesn't exist, or if it's not supported on this system, move on to the next type.
				if (!class_exists($class) || !$class::isSupported())
				{
					continue;
				}

				// Everything looks good, add it to the list.
				self::$connectors[] = $baseName;
			}
		}

		return self::$connectors;
	}

	/**
	 * Method to return a DatabaseDriver instance based on the given options.
	 *
	 * There are three global options and then the rest are specific to the database driver.
	 *
	 * - The 'driver' option defines which DatabaseDriver class is used for the connection -- the default is 'mysqli'.
	 * - The 'database' option determines which database is to be used for the connection.
	 * - The 'select' option determines whether the connector should automatically select the chosen database.
	 *
	 * Instances are unique to the given options and new objects are only created when a unique options array is
	 * passed into the method.  This ensures that we don't end up with unnecessary database connection resources.
	 *
	 * @param   array  $options  Parameters to be passed to the database driver.
	 *
	 * @return  DatabaseDriver
	 *
	 * @since   1.0
	 * @throws  \RuntimeException
	 * @deprecated  3.0  Use DatabaseFactory::getDriver() instead
	 */
	public static function getInstance(array $options = [])
	{
		trigger_deprecation(
			'joomla/database',
			'2.0.0',
			'%s() is deprecated and will be removed in 3.0, use %s::getDriver() instead.',
			__METHOD__,
			DatabaseFactory::class
		);

		// Sanitize the database connector options.
		$options['driver']   = isset($options['driver']) ? preg_replace('/[^A-Z0-9_\.-]/i', '', $options['driver']) : 'mysqli';
		$options['database'] = $options['database'] ?? null;
		$options['select']   = $options['select'] ?? true;
		$options['factory']  = $options['factory'] ?? new DatabaseFactory;
		$options['monitor']  = $options['monitor'] ?? null;

		// Get the options signature for the database connector.
		$signature = md5(serialize($options));

		// If we already have a database connector instance for these options then just use that.
		if (empty(self::$instances[$signature]))
		{
			// Set the new connector to the global instances based on signature.
			self::$instances[$signature] = $options['factory']->getDriver($options['driver'], $options);
		}

		return self::$instances[$signature];
	}

	/**
	 * Splits a string of multiple queries into an array of individual queries.
	 *
	 * @param   string  $sql  Input SQL string with which to split into individual queries.
	 *
	 * @return  array
	 *
	 * @since   1.0
	 */
	public static function splitSql($sql)
	{
		$start     = 0;
		$open      = false;
		$comment   = false;
		$endString = '';
		$end       = \strlen($sql);
		$queries   = [];
		$query     = '';

		for ($i = 0; $i < $end; $i++)
		{
			$current      = substr($sql, $i, 1);
			$current2     = substr($sql, $i, 2);
			$current3     = substr($sql, $i, 3);
			$lenEndString = \strlen($endString);
			$testEnd      = substr($sql, $i, $lenEndString);

			if ($current === '"' || $current === "'" || $current2 === '--'
				|| ($current2 === '/*' && $current3 !== '/*!' && $current3 !== '/*+')
				|| ($current === '#' && $current3 !== '#__')
				|| ($comment && $testEnd === $endString))
			{
				// Check if quoted with previous backslash
				$n = 2;

				while (substr($sql, $i - $n + 1, 1) === '\\' && $n < $i)
				{
					$n++;
				}

				// Not quoted
				if ($n % 2 === 0)
				{
					if ($open)
					{
						if ($testEnd === $endString)
						{
							if ($comment)
							{
								$comment = false;

								if ($lenEndString > 1)
								{
									$i += ($lenEndString - 1);
									$current = substr($sql, $i, 1);
								}

								$start = $i + 1;
							}

							$open      = false;
							$endString = '';
						}
					}
					else
					{
						$open = true;

						if ($current2 === '--')
						{
							$endString = "\n";
							$comment   = true;
						}
						elseif ($current2 === '/*')
						{
							$endString = '*/';
							$comment   = true;
						}
						elseif ($current === '#')
						{
							$endString = "\n";
							$comment   = true;
						}
						else
						{
							$endString = $current;
						}

						if ($comment && $start < $i)
						{
							$query .= substr($sql, $start, $i - $start);
						}
					}
				}
			}

			if ($comment)
			{
				$start = $i + 1;
			}

			if (($current === ';' && !$open) || $i === $end - 1)
			{
				if ($start <= $i)
				{
					$query .= substr($sql, $start, $i - $start + 1);
				}

				$query = trim($query);

				if ($query)
				{
					if (($i === $end - 1) && ($current !== ';'))
					{
						$query .= ';';
					}

					$queries[] = $query;
				}

				$query = '';
				$start = $i + 1;
			}

			$endComment = false;
		}

		return $queries;
	}

	/**
	 * Magic method to access properties of the database driver.
	 *
	 * @param   string  $name  The name of the property.
	 *
	 * @return  mixed   A value if the property name is valid, null otherwise.
	 *
	 * @since       1.4.0
	 * @deprecated  3.0  This is a B/C proxy since $this->name was previously public
	 */
	public function __get($name)
	{
		switch ($name)
		{
			case 'name':
				trigger_deprecation(
					'joomla/database',
					'1.4.0',
					'Accessing the name property of %s is deprecated, use the getName() method instead.',
					self::class
				);

				return $this->getName();

			default:
				$trace = debug_backtrace();
				trigger_error(
					sprintf(
						'Undefined property via __get(): %1$s in %2$s on line %3$s',
						$name,
						$trace[0]['file'],
						$trace[0]['line']
					),
					\E_USER_NOTICE
				);
		}
	}

	/**
	 * Constructor.
	 *
	 * @param   array  $options  List of options used to configure the connection
	 *
	 * @since   1.0
	 */
	public function __construct(array $options)
	{
		// Initialise object variables.
		$this->database    = $options['database'] ?? '';
		$this->tablePrefix = $options['prefix'] ?? '';
		$this->count       = 0;
		$this->errorNum    = 0;

		// Set class options.
		$this->options = $options;

		// Register the DatabaseFactory
		$this->factory = $options['factory'] ?? new DatabaseFactory;

		// Register the query monitor if available
		$this->monitor = $options['monitor'] ?? null;
	}

	/**
	 * Destructor.
	 *
	 * @since   2.0.0
	 */
	public function __destruct()
	{
		$this->disconnect();
	}

	/**
	 * Alter database's character set.
	 *
	 * @param   string  $dbName  The database name that will be altered
	 *
	 * @return  boolean|resource
	 *
	 * @since   2.0.0
	 * @throws  \RuntimeException
	 */
	public function alterDbCharacterSet($dbName)
	{
		if ($dbName === null)
		{
			throw new \RuntimeException('Database name must not be null.');
		}

		$this->setQuery($this->getAlterDbCharacterSet($dbName));

		return $this->execute();
	}

	/**
	 * Create a new database using information from $options object.
	 *
	 * @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  boolean|resource
	 *
	 * @since   2.0.0
	 * @throws  \RuntimeException
	 */
	public function createDatabase($options, $utf = true)
	{
		if ($options === null)
		{
			throw new \RuntimeException('$options object must not be null.');
		}

		if (empty($options->db_name))
		{
			throw new \RuntimeException('$options object must have db_name set.');
		}

		if (empty($options->db_user))
		{
			throw new \RuntimeException('$options object must have db_user set.');
		}

		$this->setQuery($this->getCreateDatabaseQuery($options, $utf));

		return $this->execute();
	}

	/**
	 * Disconnects the database.
	 *
	 * @return  void
	 *
	 * @since   2.0.0
	 */
	public function disconnect()
	{
		$this->freeResult();
		$this->connection = null;

		$this->dispatchEvent(new ConnectionEvent(DatabaseEvents::POST_DISCONNECT, $this));
	}

	/**
	 * Dispatch an event.
	 *
	 * @param   EventInterface  $event  The event to dispatch
	 *
	 * @return  void
	 *
	 * @since   2.0.0
	 */
	protected function dispatchEvent(EventInterface $event)
	{
		try
		{
			$this->getDispatcher()->dispatch($event->getName(), $event);
		}
		catch (\UnexpectedValueException $exception)
		{
			// Don't error if a dispatcher hasn't been set
		}
	}

	/**
	 * Drops a table from the database.
	 *
	 * @param   string   $table     The name of the database table to drop.
	 * @param   boolean  $ifExists  Optionally specify that the table must exist before it is dropped.
	 *
	 * @return  $this
	 *
	 * @since   2.0.0
	 * @throws  \RuntimeException
	 */
	public function dropTable($table, $ifExists = true)
	{
		$this->connect();

		$this->setQuery('DROP TABLE ' . ($ifExists ? 'IF EXISTS ' : '') . $this->quoteName($table))
			->execute();

		return $this;
	}

	/**
	 * Execute the SQL statement.
	 *
	 * @return  boolean
	 *
	 * @since   2.0.0
	 * @throws  \RuntimeException
	 */
	public function execute()
	{
		$this->connect();

		// Increment the query counter.
		$this->count++;

		// Get list of bound parameters
		$bounded =& $this->sql->getBounded();

		// If there is a monitor registered, let it know we are starting this query
		if ($this->monitor)
		{
			// Take a local copy so that we don't modify the original query and cause issues later
			$sql = $this->replacePrefix((string) $this->sql);

			$this->monitor->startQuery($sql, $bounded);
		}

		// Execute the query.
		$this->executed = false;

		// Bind the variables
		foreach ($bounded as $key => $obj)
		{
			$this->statement->bindParam($key, $obj->value, $obj->dataType);
		}

		try
		{
			$this->executed = $this->statement->execute();

			// If there is a monitor registered, let it know we have finished this query
			if ($this->monitor)
			{
				$this->monitor->stopQuery();
			}

			return true;
		}
		catch (ExecutionFailureException $exception)
		{
			// If there is a monitor registered, let it know we have finished this query
			if ($this->monitor)
			{
				$this->monitor->stopQuery();
			}

			// 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 $exception;
				}

				// Since we were able to reconnect, run the query again.
				return $this->execute();
			}

			// Throw the normal query exception.
			throw $exception;
		}
	}

	/**
	 * Method to fetch a row from the result set cursor as an array.
	 *
	 * @return  mixed  Either the next row from the result set or false if there are no more rows.
	 *
	 * @since   1.0
	 */
	protected function fetchArray()
	{
		if ($this->statement)
		{
			return $this->statement->fetch(FetchMode::NUMERIC);
		}
	}

	/**
	 * Method to fetch a row from the result set cursor as an associative array.
	 *
	 * @return  mixed  Either the next row from the result set or false if there are no more rows.
	 *
	 * @since   1.0
	 */
	protected function fetchAssoc()
	{
		if ($this->statement)
		{
			return $this->statement->fetch(FetchMode::ASSOCIATIVE);
		}
	}

	/**
	 * Method to fetch a row from the result set cursor as an object.
	 *
	 * Note, the fetch mode should be configured before calling this method using `StatementInterface::setFetchMode()`.
	 *
	 * @return  mixed   Either the next row from the result set or false if there are no more rows.
	 *
	 * @since   1.0
	 */
	protected function fetchObject()
	{
		if ($this->statement)
		{
			return $this->statement->fetch();
		}
	}

	/**
	 * Method to free up the memory used for the result set.
	 *
	 * @return  void
	 *
	 * @since   1.0
	 */
	protected function freeResult()
	{
		$this->executed = false;

		if ($this->statement)
		{
			$this->statement->closeCursor();
		}
	}

	/**
	 * Get the number of affected rows for the previous executed SQL statement.
	 *
	 * @return  integer  The number of affected rows in the previous operation
	 *
	 * @since   2.0.0
	 */
	public function getAffectedRows()
	{
		$this->connect();

		if ($this->statement)
		{
			return $this->statement->rowCount();
		}

		return 0;
	}

	/**
	 * Method that provides access to the underlying database connection.
	 *
	 * @return  resource  The underlying database connection resource.
	 *
	 * @since   1.0
	 */
	public function getConnection()
	{
		return $this->connection;
	}

	/**
	 * Get the total number of SQL statements executed by the database driver.
	 *
	 * @return  integer
	 *
	 * @since   1.0
	 */
	public function getCount()
	{
		return $this->count;
	}

	/**
	 * 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   1.6.0
	 */
	protected function getAlterDbCharacterSet($dbName)
	{
		return 'ALTER DATABASE ' . $this->quoteName($dbName) . ' CHARACTER SET ' . $this->quote('UTF8');
	}

	/**
	 * 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)
	{
		return 'CREATE DATABASE ' . $this->quoteName($options->db_name);
	}

	/**
	 * Gets the name of the database used by this connection.
	 *
	 * @return  string
	 *
	 * @since   1.0
	 */
	protected function getDatabase()
	{
		return $this->database;
	}

	/**
	 * Returns a PHP date() function compliant date format for the database driver.
	 *
	 * @return  string
	 *
	 * @since   1.0
	 */
	public function getDateFormat()
	{
		return 'Y-m-d H:i:s';
	}

	/**
	 * Get the minimum supported database version.
	 *
	 * @return  string
	 *
	 * @since   1.0
	 */
	public function getMinimum()
	{
		return static::$dbMinimum;
	}

	/**
	 * Get the name of the database driver.
	 *
	 * If $this->name is not set it will try guessing the driver name from the class name.
	 *
	 * @return  string
	 *
	 * @since   1.4.0
	 */
	public function getName()
	{
		if (empty($this->name))
		{
			$reflect = new \ReflectionClass($this);

			$this->name = strtolower(str_replace('Driver', '', $reflect->getShortName()));
		}

		return $this->name;
	}

	/**
	 * Get the number of returned rows for the previous executed SQL statement.
	 *
	 * @return  integer   The number of returned rows.
	 *
	 * @since   2.0.0
	 */
	public function getNumRows()
	{
		$this->connect();

		if ($this->statement)
		{
			return $this->statement->rowCount();
		}

		return 0;
	}

	/**
	 * Get the server family type.
	 *
	 * If $this->serverType is not set it will attempt guessing the server family type from the driver name. If this is not possible the driver
	 * name will be returned instead.
	 *
	 * @return  string
	 *
	 * @since   1.4.0
	 */
	public function getServerType()
	{
		if (empty($this->serverType))
		{
			$name = $this->getName();

			if (stristr($name, 'mysql') !== false)
			{
				$this->serverType = 'mysql';
			}
			elseif (stristr($name, 'postgre') !== false)
			{
				$this->serverType = 'postgresql';
			}
			elseif (stristr($name, 'pgsql') !== false)
			{
				$this->serverType = 'postgresql';
			}
			elseif (stristr($name, 'oracle') !== false)
			{
				$this->serverType = 'oracle';
			}
			elseif (stristr($name, 'sqlite') !== false)
			{
				$this->serverType = 'sqlite';
			}
			elseif (stristr($name, 'sqlsrv') !== false)
			{
				$this->serverType = 'mssql';
			}
			elseif (stristr($name, 'sqlazure') !== false)
			{
				$this->serverType = 'mssql';
			}
			elseif (stristr($name, 'mssql') !== false)
			{
				$this->serverType = 'mssql';
			}
			else
			{
				$this->serverType = $name;
			}
		}

		return $this->serverType;
	}

	/**
	 * Get the null or zero representation of a timestamp for the database driver.
	 *
	 * @return  string
	 *
	 * @since   1.0
	 */
	public function getNullDate()
	{
		return $this->nullDate;
	}

	/**
	 * Get the common table prefix for the database driver.
	 *
	 * @return  string  The common database table prefix.
	 *
	 * @since   1.0
	 */
	public function getPrefix()
	{
		return $this->tablePrefix;
	}

	/**
	 * Gets an exporter class object.
	 *
	 * @return  DatabaseExporter  An exporter object.
	 *
	 * @since   1.0
	 * @throws  \RuntimeException
	 */
	public function getExporter()
	{
		return $this->factory->getExporter($this->name, $this);
	}

	/**
	 * Gets an importer class object.
	 *
	 * @return  DatabaseImporter
	 *
	 * @since   1.0
	 */
	public function getImporter()
	{
		return $this->factory->getImporter($this->name, $this);
	}

	/**
	 * Get the current query object or a new DatabaseQuery object.
	 *
	 * @param   boolean  $new  False to return the current query object, True to return a new DatabaseQuery object.
	 *
	 * @return  DatabaseQuery
	 *
	 * @since   1.0
	 */
	public function getQuery($new = false)
	{
		if ($new)
		{
			return $this->factory->getQuery($this->name, $this);
		}

		return $this->sql;
	}

	/**
	 * Get a new iterator on the current query.
	 *
	 * @param   string  $column  An option column to use as the iterator key.
	 * @param   string  $class   The class of object that is returned.
	 *
	 * @return  DatabaseIterator
	 *
	 * @since   1.0
	 */
	public function getIterator($column = null, $class = \stdClass::class)
	{
		if (!$this->executed)
		{
			$this->execute();
		}

		/**
		 * Calling setQuery free's the statement from the iterator which will break the iterator.
		 * So we set statement to null so that freeResult on the statement here has no affect.
		 * If you unset the iterator object then that will close the cursor and free the result.
		 */
		$iterator = $this->factory->getIterator($this->name, $this->statement, $column, $class);
		$this->statement = null;

		return $iterator;
	}

	/**
	 * 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
	 */
	abstract public function getTableCreate($tables);

	/**
	 * Determine whether or not the database engine supports UTF-8 character encoding.
	 *
	 * @return  boolean  True if the database engine supports UTF-8 character encoding.
	 *
	 * @since   1.0
	 */
	public function hasUtfSupport()
	{
		return $this->utf;
	}

	/**
	 * 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   1.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;
			}

			// 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->getQuery(true)
			->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;
	}

	/**
	 * Method to check whether the installed database version is supported by the database driver
	 *
	 * @return  boolean  True if the database version is supported
	 *
	 * @since   1.0
	 */
	public function isMinimumVersion()
	{
		return version_compare($this->getVersion(), $this->getMinimum()) >= 0;
	}

	/**
	 * Method to get the first row of the result set from the database query as an associative array of ['field_name' => 'row_value'].
	 *
	 * @return  mixed  The return value or null if the query failed.
	 *
	 * @since   1.0
	 * @throws  \RuntimeException
	 */
	public function loadAssoc()
	{
		$this->connect();

		$ret = null;

		// Execute the query and get the result set cursor.
		$this->execute();

		// Get the first row from the result set as an associative array.
		$array = $this->fetchAssoc();

		if ($array)
		{
			$ret = $array;
		}

		// Free up system resources and return.
		$this->freeResult();

		return $ret;
	}

	/**
	 * Method to get an array of the result set rows from the database query where each row is an associative array
	 * of ['field_name' => 'row_value'].  The array of rows can optionally be keyed by a field name, but defaults to
	 * a sequential numeric array.
	 *
	 * NOTE: Choosing to key the result array by a non-unique field name can result in unwanted
	 * behavior and should be avoided.
	 *
	 * @param   string  $key     The name of a field on which to key the result array.
	 * @param   string  $column  An optional column name. Instead of the whole row, only this column value will be in
	 *                           the result array.
	 *
	 * @return  mixed   The return value or null if the query failed.
	 *
	 * @since   1.0
	 * @throws  \RuntimeException
	 */
	public function loadAssocList($key = null, $column = null)
	{
		$this->connect();

		$array = [];

		// Execute the query and get the result set cursor.
		$this->execute();

		// Get all of the rows from the result set.
		while ($row = $this->fetchAssoc())
		{
			$value = $column ? ($row[$column] ?? $row) : $row;

			if ($key)
			{
				$array[$row[$key]] = $value;
			}
			else
			{
				$array[] = $value;
			}
		}

		// Free up system resources and return.
		$this->freeResult();

		return $array;
	}

	/**
	 * Method to get an array of values from the <var>$offset</var> field in each row of the result set from the database query.
	 *
	 * @param   integer  $offset  The row offset to use to build the result array.
	 *
	 * @return  mixed  The return value or null if the query failed.
	 *
	 * @since   1.0
	 * @throws  \RuntimeException
	 */
	public function loadColumn($offset = 0)
	{
		$this->connect();

		$array = [];

		// Execute the query and get the result set cursor.
		$this->execute();

		// Get all of the rows from the result set as arrays.
		while ($row = $this->fetchArray())
		{
			$array[] = $row[$offset];
		}

		// Free up system resources and return.
		$this->freeResult();

		return $array;
	}

	/**
	 * Method to get the first row of the result set from the database query as an object.
	 *
	 * @param   string  $class  The class name to use for the returned row object.
	 *
	 * @return  mixed  The return value or null if the query failed.
	 *
	 * @since   1.0
	 * @throws  \RuntimeException
	 */
	public function loadObject($class = \stdClass::class)
	{
		$this->connect();

		$ret = null;

		if ($this->statement)
		{
			$fetchMode = $class === \stdClass::class ? FetchMode::STANDARD_OBJECT : FetchMode::CUSTOM_OBJECT;

			// PDO doesn't allow extra arguments for \PDO::FETCH_CLASS, so only forward the class for the custom object mode
			if ($fetchMode === FetchMode::STANDARD_OBJECT)
			{
				$this->statement->setFetchMode($fetchMode);
			}
			else
			{
				$this->statement->setFetchMode($fetchMode, $class);
			}
		}

		// Execute the query and get the result set cursor.
		$this->execute();

		// Get the first row from the result set as an object of type $class.
		$object = $this->fetchObject();

		if ($object)
		{
			$ret = $object;
		}

		// Free up system resources and return.
		$this->freeResult();

		return $ret;
	}

	/**
	 * Method to get an array of the result set rows from the database query where each row is an object.  The array
	 * of objects can optionally be keyed by a field name, but defaults to a sequential numeric array.
	 *
	 * NOTE: Choosing to key the result array by a non-unique field name can result in unwanted behavior and should be avoided.
	 *
	 * @param   string  $key    The name of a field on which to key the result array.
	 * @param   string  $class  The class name to use for the returned row objects.
	 *
	 * @return  mixed  The return value or null if the query failed.
	 *
	 * @since   1.0
	 * @throws  \RuntimeException
	 */
	public function loadObjectList($key = '', $class = \stdClass::class)
	{
		$this->connect();

		$array = [];

		if ($this->statement)
		{
			$fetchMode = $class === \stdClass::class ? FetchMode::STANDARD_OBJECT : FetchMode::CUSTOM_OBJECT;

			// PDO doesn't allow extra arguments for \PDO::FETCH_CLASS, so only forward the class for the custom object mode
			if ($fetchMode === FetchMode::STANDARD_OBJECT)
			{
				$this->statement->setFetchMode($fetchMode);
			}
			else
			{
				$this->statement->setFetchMode($fetchMode, $class);
			}
		}

		// Execute the query and get the result set cursor.
		$this->execute();

		// Get all of the rows from the result set as objects of type $class.
		while ($row = $this->fetchObject())
		{
			if ($key)
			{
				$array[$row->$key] = $row;
			}
			else
			{
				$array[] = $row;
			}
		}

		// Free up system resources and return.
		$this->freeResult();

		return $array;
	}

	/**
	 * Method to get the first field of the first row of the result set from the database query.
	 *
	 * @return  mixed  The return value or null if the query failed.
	 *
	 * @since   1.0
	 * @throws  \RuntimeException
	 */
	public function loadResult()
	{
		$this->connect();

		$ret = null;

		// Execute the query and get the result set cursor.
		$this->execute();

		// Get the first row from the result set as an array.
		$row = $this->fetchArray();

		if ($row)
		{
			$ret = $row[0];
		}

		// Free up system resources and return.
		$this->freeResult();

		return $ret;
	}

	/**
	 * Method to get the first row of the result set from the database query as an array.
	 *
	 * Columns are indexed numerically so the first column in the result set would be accessible via <var>$row[0]</var>, etc.
	 *
	 * @return  mixed  The return value or null if the query failed.
	 *
	 * @since   1.0
	 * @throws  \RuntimeException
	 */
	public function loadRow()
	{
		$this->connect();

		$ret = null;

		// Execute the query and get the result set cursor.
		$this->execute();

		// Get the first row from the result set as an array.
		$row = $this->fetchArray();

		if ($row)
		{
			$ret = $row;
		}

		// Free up system resources and return.
		$this->freeResult();

		return $ret;
	}

	/**
	 * Method to get an array of the result set rows from the database query where each row is an array.  The array
	 * of objects can optionally be keyed by a field offset, but defaults to a sequential numeric array.
	 *
	 * NOTE: Choosing to key the result array by a non-unique field can result in unwanted behavior and should be avoided.
	 *
	 * @param   string  $key  The name of a field on which to key the result array.
	 *
	 * @return  array   An array of results.
	 *
	 * @since   1.0
	 * @throws  \RuntimeException
	 */
	public function loadRowList($key = null)
	{
		$this->connect();

		$array = [];

		// Execute the query and get the result set cursor.
		$this->execute();

		// Get all of the rows from the result set as arrays.
		while ($row = $this->fetchArray())
		{
			if ($key !== null)
			{
				$array[$row[$key]] = $row;
			}
			else
			{
				$array[] = $row;
			}
		}

		// Free up system resources and return.
		$this->freeResult();

		return $array;
	}

	/**
	 * Prepares a SQL statement for execution
	 *
	 * @param   string  $query  The SQL query to be prepared.
	 *
	 * @return  StatementInterface
	 *
	 * @since   2.0.0
	 * @throws  PrepareStatementFailureException
	 */
	abstract protected function prepareStatement(string $query): StatementInterface;

	/**
	 * Alias for quote method
	 *
	 * @param   array|string  $text    A string or an array of strings to quote.
	 * @param   boolean       $escape  True (default) to escape the string, false to leave it unchanged.
	 *
	 * @return  string  The quoted input string.
	 *
	 * @since   1.0
	 */
	public function q($text, $escape = true)
	{
		return $this->quote($text, $escape);
	}

	/**
	 * Quotes and optionally escapes a string to database requirements for use in database queries.
	 *
	 * @param   array|string  $text    A string or an array of strings to quote.
	 * @param   boolean       $escape  True (default) to escape the string, false to leave it unchanged.
	 *
	 * @return  string  The quoted input string.
	 *
	 * @since   1.0
	 */
	public function quote($text, $escape = true)
	{
		if (\is_array($text))
		{
			foreach ($text as $k => $v)
			{
				$text[$k] = $this->quote($v, $escape);
			}

			return $text;
		}

		return '\'' . ($escape ? $this->escape($text) : $text) . '\'';
	}

	/**
	 * Quotes a binary string to database requirements for use in database queries.
	 *
	 * @param   string  $data  A binary string to quote.
	 *
	 * @return  string  The binary quoted input string.
	 *
	 * @since   1.7.0
	 */
	public function quoteBinary($data)
	{
		// SQL standard syntax for hexadecimal literals
		return "X'" . bin2hex($data) . "'";
	}

	/**
	 * Replace special placeholder representing binary field with the original string.
	 *
	 * @param   string|resource  $data  Encoded string or resource.
	 *
	 * @return  string  The original string.
	 *
	 * @since   1.7.0
	 */
	public function decodeBinary($data)
	{
		return $data;
	}

	/**
	 * Alias for quoteName method
	 *
	 * @param   array|string  $name  The identifier name to wrap in quotes, or an array of identifier names to wrap in quotes.
	 *                               Each type supports dot-notation name.
	 * @param   array|string  $as    The AS query part associated to $name. It can be string or array, in latter case it has to be
	 *                               same length of $name; if is null there will not be any AS part for string or array element.
	 *
	 * @return  array|string  The quote wrapped name, same type of $name.
	 *
	 * @since   1.0
	 */
	public function qn($name, $as = null)
	{
		return $this->quoteName($name, $as);
	}

	/**
	 * Wrap an SQL statement identifier name such as column, table or database names in quotes to prevent injection
	 * risks and reserved word conflicts.
	 *
	 * @param   array|string  $name  The identifier name to wrap in quotes, or an array of identifier names to wrap in quotes.
	 *                               Each type supports dot-notation name.
	 * @param   array|string  $as    The AS query part associated to $name. It can be string or array, in latter case it has to be
	 *                               same length of $name; if is null there will not be any AS part for string or array element.
	 *
	 * @return  array|string  The quote wrapped name, same type of $name.
	 *
	 * @since   1.0
	 */
	public function quoteName($name, $as = null)
	{
		if (\is_string($name))
		{
			$name = $this->quoteNameString($name);

			if ($as !== null)
			{
				$name .= ' AS ' . $this->quoteNameString($as, true);
			}

			return $name;
		}

		$fin = [];

		if ($as === null)
		{
			foreach ($name as $str)
			{
				$fin[] = $this->quoteName($str);
			}
		}
		elseif (\is_array($name) && (\count($name) === \count($as)))
		{
			$count = \count($name);

			for ($i = 0; $i < $count; $i++)
			{
				$fin[] = $this->quoteName($name[$i], $as[$i]);
			}
		}

		return $fin;
	}

	/**
	 * Quote string coming from quoteName call.
	 *
	 * @param   string   $name          Identifier name to be quoted.
	 * @param   boolean  $asSinglePart  Treat the name as a single part of the identifier.
	 *
	 * @return  string  Quoted identifier string.
	 *
	 * @since   1.7.0
	 */
	protected function quoteNameString($name, $asSinglePart = false)
	{
		$q = $this->nameQuote . $this->nameQuote;

		// Double quote reserved keyword
		$name = str_replace($q[1], $q[1] . $q[1], $name);

		if ($asSinglePart)
		{
			return $q[0] . $name . $q[1];
		}

		return $q[0] . str_replace('.', "$q[1].$q[0]", $name) . $q[1];
	}

	/**
	 * Quote strings coming from quoteName call.
	 *
	 * @param   array  $strArr  Array of strings coming from quoteName dot-explosion.
	 *
	 * @return  string  Dot-imploded string of quoted parts.
	 *
	 * @since   1.0
	 * @deprecated  2.0  Use quoteNameString instead
	 */
	protected function quoteNameStr($strArr)
	{
		$parts = [];
		$q     = $this->nameQuote;

		foreach ($strArr as $part)
		{
			if ($part === null)
			{
				continue;
			}

			if (\strlen($q) === 1)
			{
				$parts[] = $q . $part . $q;
			}
			else
			{
				$parts[] = $q[0] . $part . $q[1];
			}
		}

		return implode('.', $parts);
	}

	/**
	 * This function replaces a string identifier with the configured table prefix.
	 *
	 * @param   string  $sql     The SQL statement to prepare.
	 * @param   string  $prefix  The table prefix.
	 *
	 * @return  string  The processed SQL statement.
	 *
	 * @since   1.0
	 */
	public function replacePrefix($sql, $prefix = '#__')
	{
		$escaped   = false;
		$startPos  = 0;
		$quoteChar = '';
		$literal   = '';

		$sql = trim($sql);
		$n   = \strlen($sql);

		while ($startPos < $n)
		{
			$ip = strpos($sql, $prefix, $startPos);

			if ($ip === false)
			{
				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;
			}

			$literal .= str_replace($prefix, $this->tablePrefix, substr($sql, $startPos, $j - $startPos));
			$startPos = $j;

			$j = $startPos + 1;

			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);
		}

		return $literal;
	}

	/**
	 * Get the query monitor.
	 *
	 * @return  QueryMonitorInterface|null  The query monitor or null if not set.
	 *
	 * @since   2.0.0
	 */
	public function getMonitor()
	{
		return $this->monitor;
	}

	/**
	 * Set a query monitor.
	 *
	 * @param   QueryMonitorInterface|null  $monitor  The query monitor.
	 *
	 * @return  $this
	 *
	 * @since   2.0.0
	 */
	public function setMonitor(QueryMonitorInterface $monitor = null)
	{
		$this->monitor = $monitor;

		return $this;
	}

	/**
	 * Sets the SQL statement string for later execution.
	 *
	 * @param   string|QueryInterface  $query   The SQL statement to set either as a Query object or a string.
	 * @param   integer                $offset  The affected row offset to set. {@deprecated 3.0 Use LimitableInterface::setLimit() instead}
	 * @param   integer                $limit   The maximum affected rows to set. {@deprecated 3.0 Use LimitableInterface::setLimit() instead}
	 *
	 * @return  $this
	 *
	 * @since   1.0
	 * @throws  \InvalidArgumentException
	 */
	public function setQuery($query, $offset = 0, $limit = 0)
	{
		$this->connect();

		$this->freeResult();

		if (\is_string($query))
		{
			// Allows taking advantage of bound variables in a direct query:
			$query = $this->getQuery(true)->setQuery($query);
		}
		elseif (!($query instanceof QueryInterface))
		{
			throw new \InvalidArgumentException(
				sprintf(
					'A query must be a string or a %s instance, a %s was given.',
					QueryInterface::class,
					\gettype($query) === 'object' ? (\get_class($query) . ' instance') : \gettype($query)
				)
			);
		}

		if ($offset > 0 || $limit > 0)
		{
			trigger_deprecation(
				'joomla/database',
				'2.0.0',
				'The "$offset" and "$limit" arguments of %s() are deprecated and will be removed in 3.0, use %s::setLimit() instead.',
				__METHOD__,
				QueryInterface::class
			);
		}

		// Check for values set on the query object and use those if there is a zero value passed here
		if ($limit === 0 && $query->limit > 0)
		{
			$limit = $query->limit;
		}

		if ($offset === 0 && $query->offset > 0)
		{
			$offset = $query->offset;
		}

		$query->setLimit($limit, $offset);

		$sql = $this->replacePrefix((string) $query);

		$this->statement = $this->prepareStatement($sql);

		$this->sql    = $query;
		$this->limit  = (int) max(0, $limit);
		$this->offset = (int) max(0, $offset);

		return $this;
	}

	/**
	 * Set the connection to use UTF-8 character encoding.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   1.0
	 */
	abstract public function setUtf();

	/**
	 * Method to truncate a table.
	 *
	 * @param   string  $table  The table to truncate
	 *
	 * @return  void
	 *
	 * @since   1.0
	 * @throws  \RuntimeException
	 */
	public function truncateTable($table)
	{
		$this->setQuery('TRUNCATE TABLE ' . $this->quoteName($table))
			->execute();
	}

	/**
	 * Updates a row in a table based on an object's properties.
	 *
	 * @param   string        $table   The name of the database table to update.
	 * @param   object        $object  A reference to an object whose public properties match the table fields.
	 * @param   array|string  $key     The name of the primary key.
	 * @param   boolean       $nulls   True to update null fields or false to ignore them.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   1.0
	 * @throws  \RuntimeException
	 */
	public function updateObject($table, &$object, $key, $nulls = false)
	{
		$fields       = [];
		$where        = [];
		$tableColumns = $this->getTableColumns($table);

		if (\is_string($key))
		{
			$key = [$key];
		}

		if (\is_object($key))
		{
			$key = (array) $key;
		}

		// Create the base update statement.
		$statement = 'UPDATE ' . $this->quoteName($table) . ' SET %s WHERE %s';

		// Iterate over the object variables to build the query fields/value pairs.
		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 scalars that are not internal fields.
			if (\is_array($v) || \is_object($v) || $k[0] === '_')
			{
				continue;
			}

			// Set the primary key to the WHERE clause instead of a field to update.
			if (\in_array($k, $key, true))
			{
				$where[] = $this->quoteName($k) . ($v === null ? ' IS NULL' : ' = ' . $this->quote($v));

				continue;
			}

			// Prepare and sanitize the fields and values for the database query.
			if ($v === null)
			{
				// If the value is null and we want to update nulls then set it.
				if ($nulls)
				{
					$val = 'NULL';
				}
				else
				{
					// If the value is null and we do not want to update nulls then ignore this field.
					continue;
				}
			}
			else
			{
				// The field is not null so we prep it for update.
				$val = $this->quote($v);
			}

			// Add the field to be updated.
			$fields[] = $this->quoteName($k) . '=' . $val;
		}

		// We don't have any fields to update.
		if (empty($fields))
		{
			return true;
		}

		// Set the query and execute the update.
		$this->setQuery(sprintf($statement, implode(',', $fields), implode(' AND ', $where)))->execute();

		return true;
	}
}

Filemanager

Name Type Size Permission Actions
Command Folder 0775
Event Folder 0775
Exception Folder 0775
Monitor Folder 0775
Mysql Folder 0775
Mysqli Folder 0775
Pdo Folder 0775
Pgsql Folder 0775
Query Folder 0775
Service Folder 0775
Sqlazure Folder 0775
Sqlite Folder 0775
Sqlsrv Folder 0775
DatabaseAwareInterface.php File 568 B 0664
DatabaseAwareTrait.php File 1.15 KB 0664
DatabaseDriver.php File 44.2 KB 0664
DatabaseEvents.php File 1.06 KB 0664
DatabaseExporter.php File 5.88 KB 0664
DatabaseFactory.php File 5.77 KB 0664
DatabaseImporter.php File 7.61 KB 0664
DatabaseInterface.php File 15.81 KB 0664
DatabaseIterator.php File 4.78 KB 0664
DatabaseQuery.php File 59.4 KB 0664
FetchMode.php File 2.24 KB 0664
FetchOrientation.php File 1.58 KB 0664
ParameterType.php File 1.07 KB 0664
QueryInterface.php File 18.98 KB 0664
QueryMonitorInterface.php File 899 B 0664
StatementInterface.php File 4.4 KB 0664
UTF8MB4SupportInterface.php File 1015 B 0664
Filemanager