first commit
This commit is contained in:
893
classes/db/Db.php
Normal file
893
classes/db/Db.php
Normal file
@@ -0,0 +1,893 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
/**
|
||||
* Class DbCore.
|
||||
*/
|
||||
abstract class DbCore
|
||||
{
|
||||
/** @var int Constant used by insert() method */
|
||||
const INSERT = 1;
|
||||
|
||||
/** @var int Constant used by insert() method */
|
||||
const INSERT_IGNORE = 2;
|
||||
|
||||
/** @var int Constant used by insert() method */
|
||||
const REPLACE = 3;
|
||||
|
||||
/** @var int Constant used by insert() method */
|
||||
const ON_DUPLICATE_KEY = 4;
|
||||
|
||||
/** @var string Server (eg. localhost) */
|
||||
protected $server;
|
||||
|
||||
/** @var string Database user (eg. root) */
|
||||
protected $user;
|
||||
|
||||
/** @var string Database password (eg. can be empty !) */
|
||||
protected $password;
|
||||
|
||||
/** @var string Database name */
|
||||
protected $database;
|
||||
|
||||
/** @var bool */
|
||||
protected $is_cache_enabled;
|
||||
|
||||
/** @var PDO|mysqli|resource Resource link */
|
||||
protected $link;
|
||||
|
||||
/** @var PDOStatement|mysqli_result|resource|bool SQL cached result */
|
||||
protected $result;
|
||||
|
||||
/** @var array List of DB instances */
|
||||
public static $instance = [];
|
||||
|
||||
/** @var array List of server settings */
|
||||
public static $_servers = [];
|
||||
|
||||
/** @var null Flag used to load slave servers only once.
|
||||
* See loadSlaveServers() method
|
||||
*/
|
||||
public static $_slave_servers_loaded = null;
|
||||
|
||||
/**
|
||||
* Store last executed query.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $last_query;
|
||||
|
||||
/**
|
||||
* Store hash of the last executed query.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $last_query_hash;
|
||||
|
||||
/**
|
||||
* Last cached query.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $last_cached;
|
||||
|
||||
/**
|
||||
* Opens a database connection.
|
||||
*
|
||||
* @return PDO|mysqli|resource
|
||||
*/
|
||||
abstract public function connect();
|
||||
|
||||
/**
|
||||
* Closes database connection.
|
||||
*/
|
||||
abstract public function disconnect();
|
||||
|
||||
/**
|
||||
* Execute a query and get result resource.
|
||||
*
|
||||
* @param string $sql
|
||||
*
|
||||
* @return PDOStatement|mysqli_result|resource|bool
|
||||
*/
|
||||
abstract protected function _query($sql);
|
||||
|
||||
/**
|
||||
* Get number of rows in a result.
|
||||
*
|
||||
* @param mixed $result
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract protected function _numRows($result);
|
||||
|
||||
/**
|
||||
* Get the ID generated from the previous INSERT operation.
|
||||
*
|
||||
* @return int|string
|
||||
*/
|
||||
abstract public function Insert_ID();
|
||||
|
||||
/**
|
||||
* Get number of affected rows in previous database operation.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function Affected_Rows();
|
||||
|
||||
/**
|
||||
* Get next row for a query which does not return an array.
|
||||
*
|
||||
* @param PDOStatement|mysqli_result|resource|bool $result
|
||||
*
|
||||
* @return array|object|false|null
|
||||
*/
|
||||
abstract public function nextRow($result = false);
|
||||
|
||||
/**
|
||||
* Get all rows for a query which return an array.
|
||||
*
|
||||
* @param PDOStatement|mysqli_result|resource|bool|null $result
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getAll($result = false);
|
||||
|
||||
/**
|
||||
* Get database version.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getVersion();
|
||||
|
||||
/**
|
||||
* Protect string against SQL injections.
|
||||
*
|
||||
* @param string $str
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function _escape($str);
|
||||
|
||||
/**
|
||||
* Returns the text of the error message from previous database operation.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getMsgError();
|
||||
|
||||
/**
|
||||
* Returns the number of the error from previous database operation.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getNumberError();
|
||||
|
||||
/**
|
||||
* Sets the current active database on the server that's associated with the specified link identifier.
|
||||
* Do not remove, useful for some modules.
|
||||
*
|
||||
* @param string $db_name
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
abstract public function set_db($db_name);
|
||||
|
||||
/**
|
||||
* Selects best table engine.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getBestEngine();
|
||||
|
||||
/**
|
||||
* Returns database object instance.
|
||||
*
|
||||
* @param bool $master Decides whether the connection to be returned by the master server or the slave server
|
||||
*
|
||||
* @return Db Singleton instance of Db object
|
||||
*/
|
||||
public static function getInstance($master = true)
|
||||
{
|
||||
static $id = 0;
|
||||
|
||||
// This MUST not be declared with the class members because some defines (like _DB_SERVER_) may not exist yet (the constructor can be called directly with params)
|
||||
if (!self::$_servers) {
|
||||
self::$_servers = [
|
||||
['server' => _DB_SERVER_, 'user' => _DB_USER_, 'password' => _DB_PASSWD_, 'database' => _DB_NAME_], /* MySQL Master server */
|
||||
];
|
||||
}
|
||||
|
||||
if (!$master) {
|
||||
Db::loadSlaveServers();
|
||||
}
|
||||
|
||||
$total_servers = count(self::$_servers);
|
||||
if ($master || $total_servers == 1) {
|
||||
$id_server = 0;
|
||||
} else {
|
||||
++$id;
|
||||
$id_server = ($total_servers > 2 && ($id % $total_servers) != 0) ? $id % $total_servers : 1;
|
||||
}
|
||||
|
||||
if (!isset(self::$instance[$id_server])) {
|
||||
$class = Db::getClass();
|
||||
self::$instance[$id_server] = new $class(
|
||||
self::$_servers[$id_server]['server'],
|
||||
self::$_servers[$id_server]['user'],
|
||||
self::$_servers[$id_server]['password'],
|
||||
self::$_servers[$id_server]['database']
|
||||
);
|
||||
}
|
||||
|
||||
return self::$instance[$id_server];
|
||||
}
|
||||
|
||||
public function getPrefix()
|
||||
{
|
||||
return _DB_PREFIX_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $test_db Db
|
||||
* Unit testing purpose only
|
||||
*/
|
||||
public static function setInstanceForTesting($test_db)
|
||||
{
|
||||
self::$instance[0] = $test_db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit testing purpose only.
|
||||
*/
|
||||
public static function deleteTestingInstance()
|
||||
{
|
||||
self::$instance = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads configuration settings for slave servers if needed.
|
||||
*/
|
||||
protected static function loadSlaveServers()
|
||||
{
|
||||
if (self::$_slave_servers_loaded !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add here your slave(s) server(s) in this file
|
||||
if (file_exists(_PS_ROOT_DIR_ . '/config/db_slave_server.inc.php')) {
|
||||
self::$_servers = array_merge(self::$_servers, require (_PS_ROOT_DIR_ . '/config/db_slave_server.inc.php'));
|
||||
}
|
||||
|
||||
self::$_slave_servers_loaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the best child layer database class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getClass()
|
||||
{
|
||||
$class = '';
|
||||
if (PHP_VERSION_ID >= 50200 && extension_loaded('pdo_mysql')) {
|
||||
$class = 'DbPDO';
|
||||
} elseif (extension_loaded('mysqli')) {
|
||||
$class = 'DbMySQLi';
|
||||
}
|
||||
|
||||
if (empty($class)) {
|
||||
throw new PrestaShopException('Cannot select any valid SQL engine.');
|
||||
}
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a database connection.
|
||||
*
|
||||
* @param string $server Server address
|
||||
* @param string $user User login
|
||||
* @param string $password User password
|
||||
* @param string $database Database name
|
||||
* @param bool $connect If false, don't connect in constructor (since 1.5.0.1)
|
||||
*/
|
||||
public function __construct($server, $user, $password, $database, $connect = true)
|
||||
{
|
||||
$this->server = $server;
|
||||
$this->user = $user;
|
||||
$this->password = $password;
|
||||
$this->database = $database;
|
||||
$this->is_cache_enabled = (defined('_PS_CACHE_ENABLED_')) ? _PS_CACHE_ENABLED_ : false;
|
||||
|
||||
if (!defined('_PS_DEBUG_SQL_')) {
|
||||
define('_PS_DEBUG_SQL_', false);
|
||||
}
|
||||
|
||||
if ($connect) {
|
||||
$this->connect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the use of the cache.
|
||||
*/
|
||||
public function disableCache()
|
||||
{
|
||||
$this->is_cache_enabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable & flush the cache.
|
||||
*/
|
||||
public function enableCache()
|
||||
{
|
||||
$this->is_cache_enabled = true;
|
||||
Cache::getInstance()->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes connection to database.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->link) {
|
||||
$this->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a query and get result resource.
|
||||
*
|
||||
* @param string|DbQuery $sql
|
||||
*
|
||||
* @return bool|mysqli_result|PDOStatement|resource
|
||||
*
|
||||
* @throws PrestaShopDatabaseException
|
||||
*/
|
||||
public function query($sql)
|
||||
{
|
||||
if ($sql instanceof DbQuery) {
|
||||
$sql = $sql->build();
|
||||
}
|
||||
|
||||
$this->result = $this->_query($sql);
|
||||
|
||||
if (!$this->result && $this->getNumberError() == 2006) {
|
||||
if ($this->connect()) {
|
||||
$this->result = $this->_query($sql);
|
||||
}
|
||||
}
|
||||
|
||||
if (_PS_DEBUG_SQL_) {
|
||||
$this->displayError($sql);
|
||||
}
|
||||
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes an INSERT query.
|
||||
*
|
||||
* @param string $table Table name without prefix
|
||||
* @param array $data Data to insert as associative array. If $data is a list of arrays, multiple insert will be done
|
||||
* @param bool $null_values If we want to use NULL values instead of empty quotes
|
||||
* @param bool $use_cache
|
||||
* @param int $type Must be Db::INSERT or Db::INSERT_IGNORE or Db::REPLACE
|
||||
* @param bool $add_prefix Add or not _DB_PREFIX_ before table name
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws PrestaShopDatabaseException
|
||||
*/
|
||||
public function insert($table, $data, $null_values = false, $use_cache = true, $type = Db::INSERT, $add_prefix = true)
|
||||
{
|
||||
if (!$data && !$null_values) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($add_prefix) {
|
||||
$table = _DB_PREFIX_ . $table;
|
||||
}
|
||||
|
||||
if ($type == Db::INSERT) {
|
||||
$insert_keyword = 'INSERT';
|
||||
} elseif ($type == Db::INSERT_IGNORE) {
|
||||
$insert_keyword = 'INSERT IGNORE';
|
||||
} elseif ($type == Db::REPLACE) {
|
||||
$insert_keyword = 'REPLACE';
|
||||
} elseif ($type == Db::ON_DUPLICATE_KEY) {
|
||||
$insert_keyword = 'INSERT';
|
||||
} else {
|
||||
throw new PrestaShopDatabaseException('Bad keyword, must be Db::INSERT or Db::INSERT_IGNORE or Db::REPLACE');
|
||||
}
|
||||
|
||||
// Check if $data is a list of row
|
||||
$current = current($data);
|
||||
if (!is_array($current) || isset($current['type'])) {
|
||||
$data = [$data];
|
||||
}
|
||||
|
||||
$keys = [];
|
||||
$values_stringified = [];
|
||||
$first_loop = true;
|
||||
$duplicate_key_stringified = '';
|
||||
foreach ($data as $row_data) {
|
||||
$values = [];
|
||||
foreach ($row_data as $key => $value) {
|
||||
if (!$first_loop) {
|
||||
// Check if row array mapping are the same
|
||||
if (!in_array("`$key`", $keys)) {
|
||||
throw new PrestaShopDatabaseException('Keys form $data subarray don\'t match');
|
||||
}
|
||||
|
||||
if ($duplicate_key_stringified != '') {
|
||||
throw new PrestaShopDatabaseException('On duplicate key cannot be used on insert with more than 1 VALUE group');
|
||||
}
|
||||
} else {
|
||||
$keys[] = '`' . bqSQL($key) . '`';
|
||||
}
|
||||
|
||||
if (!is_array($value)) {
|
||||
$value = ['type' => 'text', 'value' => $value];
|
||||
}
|
||||
if ($value['type'] == 'sql') {
|
||||
$values[] = $string_value = $value['value'];
|
||||
} else {
|
||||
$values[] = $string_value = $null_values && ($value['value'] === '' || null === $value['value']) ? 'NULL' : "'{$value['value']}'";
|
||||
}
|
||||
|
||||
if ($type == Db::ON_DUPLICATE_KEY) {
|
||||
$duplicate_key_stringified .= '`' . bqSQL($key) . '` = ' . $string_value . ',';
|
||||
}
|
||||
}
|
||||
$first_loop = false;
|
||||
$values_stringified[] = '(' . implode(', ', $values) . ')';
|
||||
}
|
||||
$keys_stringified = implode(', ', $keys);
|
||||
|
||||
$sql = $insert_keyword . ' INTO `' . $table . '` (' . $keys_stringified . ') VALUES ' . implode(', ', $values_stringified);
|
||||
if ($type == Db::ON_DUPLICATE_KEY) {
|
||||
$sql .= ' ON DUPLICATE KEY UPDATE ' . substr($duplicate_key_stringified, 0, -1);
|
||||
}
|
||||
|
||||
return (bool) $this->q($sql, $use_cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes an UPDATE query.
|
||||
*
|
||||
* @param string $table Table name without prefix
|
||||
* @param array $data Data to insert as associative array. If $data is a list of arrays, multiple insert will be done
|
||||
* @param string $where WHERE condition
|
||||
* @param int $limit
|
||||
* @param bool $null_values If we want to use NULL values instead of empty quotes
|
||||
* @param bool $use_cache
|
||||
* @param bool $add_prefix Add or not _DB_PREFIX_ before table name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update($table, $data, $where = '', $limit = 0, $null_values = false, $use_cache = true, $add_prefix = true)
|
||||
{
|
||||
if (!$data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($add_prefix) {
|
||||
$table = _DB_PREFIX_ . $table;
|
||||
}
|
||||
|
||||
$sql = 'UPDATE `' . bqSQL($table) . '` SET ';
|
||||
foreach ($data as $key => $value) {
|
||||
if (!is_array($value)) {
|
||||
$value = ['type' => 'text', 'value' => $value];
|
||||
}
|
||||
if ($value['type'] == 'sql') {
|
||||
$sql .= '`' . bqSQL($key) . "` = {$value['value']},";
|
||||
} else {
|
||||
$sql .= ($null_values && ($value['value'] === '' || null === $value['value'])) ? '`' . bqSQL($key) . '` = NULL,' : '`' . bqSQL($key) . "` = '{$value['value']}',";
|
||||
}
|
||||
}
|
||||
|
||||
$sql = rtrim($sql, ',');
|
||||
if ($where) {
|
||||
$sql .= ' WHERE ' . $where;
|
||||
}
|
||||
if ($limit) {
|
||||
$sql .= ' LIMIT ' . (int) $limit;
|
||||
}
|
||||
|
||||
return (bool) $this->q($sql, $use_cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a DELETE query.
|
||||
*
|
||||
* @param string $table Name of the table to delete
|
||||
* @param string $where WHERE clause on query
|
||||
* @param int $limit Number max of rows to delete
|
||||
* @param bool $use_cache Use cache or not
|
||||
* @param bool $add_prefix Add or not _DB_PREFIX_ before table name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($table, $where = '', $limit = 0, $use_cache = true, $add_prefix = true)
|
||||
{
|
||||
if ($add_prefix) {
|
||||
$table = _DB_PREFIX_ . $table;
|
||||
}
|
||||
|
||||
$this->result = false;
|
||||
$sql = 'DELETE FROM `' . bqSQL($table) . '`' . ($where ? ' WHERE ' . $where : '') . ($limit ? ' LIMIT ' . (int) $limit : '');
|
||||
$res = $this->query($sql);
|
||||
if ($use_cache && $this->is_cache_enabled) {
|
||||
Cache::getInstance()->deleteQuery($sql);
|
||||
}
|
||||
|
||||
return (bool) $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a query.
|
||||
*
|
||||
* @param string|DbQuery $sql
|
||||
* @param bool $use_cache
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function execute($sql, $use_cache = true)
|
||||
{
|
||||
if ($sql instanceof DbQuery) {
|
||||
$sql = $sql->build();
|
||||
}
|
||||
|
||||
$this->result = $this->query($sql);
|
||||
if ($use_cache && $this->is_cache_enabled) {
|
||||
Cache::getInstance()->deleteQuery($sql);
|
||||
}
|
||||
|
||||
return (bool) $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes return the result of $sql as array.
|
||||
*
|
||||
* @param string|DbQuery $sql Query to execute
|
||||
* @param bool $array Return an array instead of a result object (deprecated since 1.5.0.1, use query method instead)
|
||||
* @param bool $use_cache
|
||||
*
|
||||
* @return array|false|mysqli_result|PDOStatement|resource|null
|
||||
*
|
||||
* @throws PrestaShopDatabaseException
|
||||
*/
|
||||
public function executeS($sql, $array = true, $use_cache = true)
|
||||
{
|
||||
if ($sql instanceof DbQuery) {
|
||||
$sql = $sql->build();
|
||||
}
|
||||
|
||||
$this->result = false;
|
||||
$this->last_query = $sql;
|
||||
|
||||
if ($use_cache && $this->is_cache_enabled && $array) {
|
||||
$this->last_query_hash = Cache::getInstance()->getQueryHash($sql);
|
||||
if (($result = Cache::getInstance()->get($this->last_query_hash)) !== false) {
|
||||
Cache::getInstance()->incrementQueryCounter($sql);
|
||||
$this->last_cached = true;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
// This method must be used only with queries which display results
|
||||
if (!preg_match('#^\s*\(?\s*(select|show|explain|describe|desc)\s#i', $sql)) {
|
||||
if (defined('_PS_MODE_DEV_') && _PS_MODE_DEV_) {
|
||||
throw new PrestaShopDatabaseException('Db->executeS() must be used only with select, show, explain or describe queries');
|
||||
}
|
||||
|
||||
return $this->execute($sql, $use_cache);
|
||||
}
|
||||
|
||||
$this->result = $this->query($sql);
|
||||
|
||||
if (!$this->result) {
|
||||
$result = false;
|
||||
} else {
|
||||
if (!$array) {
|
||||
$use_cache = false;
|
||||
$result = $this->result;
|
||||
} else {
|
||||
$result = $this->getAll($this->result);
|
||||
}
|
||||
}
|
||||
|
||||
$this->last_cached = false;
|
||||
if ($use_cache && $this->is_cache_enabled && $array) {
|
||||
Cache::getInstance()->setQuery($sql, $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an associative array containing the first row of the query
|
||||
* This function automatically adds "LIMIT 1" to the query.
|
||||
*
|
||||
* @param string|DbQuery $sql the select query (without "LIMIT 1")
|
||||
* @param bool $use_cache Find it in cache first
|
||||
*
|
||||
* @return array|bool|object|null
|
||||
*/
|
||||
public function getRow($sql, $use_cache = true)
|
||||
{
|
||||
if ($sql instanceof DbQuery) {
|
||||
$sql = $sql->build();
|
||||
}
|
||||
|
||||
$sql = rtrim($sql, " \t\n\r\0\x0B;") . ' LIMIT 1';
|
||||
$this->result = false;
|
||||
$this->last_query = $sql;
|
||||
|
||||
if ($use_cache && $this->is_cache_enabled) {
|
||||
$this->last_query_hash = Cache::getInstance()->getQueryHash($sql);
|
||||
if (($result = Cache::getInstance()->get($this->last_query_hash)) !== false) {
|
||||
Cache::getInstance()->incrementQueryCounter($sql);
|
||||
$this->last_cached = true;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
$this->result = $this->query($sql);
|
||||
if (!$this->result) {
|
||||
$result = false;
|
||||
} else {
|
||||
$result = $this->nextRow($this->result);
|
||||
}
|
||||
|
||||
$this->last_cached = false;
|
||||
|
||||
if (null === $result) {
|
||||
$result = false;
|
||||
}
|
||||
|
||||
if ($use_cache && $this->is_cache_enabled) {
|
||||
Cache::getInstance()->setQuery($sql, $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value from the first row, first column of a SELECT query.
|
||||
*
|
||||
* @param string|DbQuery $sql
|
||||
* @param bool $use_cache
|
||||
*
|
||||
* @return string|false Returns false if no results
|
||||
*/
|
||||
public function getValue($sql, $use_cache = true)
|
||||
{
|
||||
if ($sql instanceof DbQuery) {
|
||||
$sql = $sql->build();
|
||||
}
|
||||
|
||||
if (!$result = $this->getRow($sql, $use_cache)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array_shift($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of rows for last result.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function numRows()
|
||||
{
|
||||
if (!$this->last_cached && $this->result) {
|
||||
$nrows = $this->_numRows($this->result);
|
||||
if ($this->is_cache_enabled) {
|
||||
Cache::getInstance()->set($this->last_query_hash . '_nrows', $nrows);
|
||||
}
|
||||
|
||||
return $nrows;
|
||||
} elseif ($this->is_cache_enabled && $this->last_cached) {
|
||||
return Cache::getInstance()->get($this->last_query_hash . '_nrows');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a query.
|
||||
*
|
||||
* @param string|DbQuery $sql
|
||||
* @param bool $use_cache
|
||||
*
|
||||
* @return bool|mysqli_result|PDOStatement|resource
|
||||
*
|
||||
* @throws PrestaShopDatabaseException
|
||||
*/
|
||||
protected function q($sql, $use_cache = true)
|
||||
{
|
||||
if ($sql instanceof DbQuery) {
|
||||
$sql = $sql->build();
|
||||
}
|
||||
|
||||
$this->result = false;
|
||||
$result = $this->query($sql);
|
||||
if ($use_cache && $this->is_cache_enabled) {
|
||||
Cache::getInstance()->deleteQuery($sql);
|
||||
}
|
||||
|
||||
if (_PS_DEBUG_SQL_) {
|
||||
$this->displayError($sql);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays last SQL error.
|
||||
*
|
||||
* @param string|bool $sql
|
||||
*
|
||||
* @throws PrestaShopDatabaseException
|
||||
*/
|
||||
public function displayError($sql = false)
|
||||
{
|
||||
global $webservice_call;
|
||||
|
||||
$errno = $this->getNumberError();
|
||||
if ($webservice_call && $errno) {
|
||||
$dbg = debug_backtrace();
|
||||
WebserviceRequest::getInstance()->setError(500, '[SQL Error] ' . $this->getMsgError() . '. From ' . (isset($dbg[3]['class']) ? $dbg[3]['class'] : '') . '->' . $dbg[3]['function'] . '() Query was : ' . $sql, 97);
|
||||
} elseif (_PS_DEBUG_SQL_ && $errno && !defined('PS_INSTALLATION_IN_PROGRESS')) {
|
||||
if ($sql) {
|
||||
throw new PrestaShopDatabaseException($this->getMsgError() . '<br /><br /><pre>' . $sql . '</pre>');
|
||||
}
|
||||
|
||||
throw new PrestaShopDatabaseException($this->getMsgError());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize data which will be injected into SQL query.
|
||||
*
|
||||
* @param string $string SQL data which will be injected into SQL query
|
||||
* @param bool $html_ok Does data contain HTML code ? (optional)
|
||||
* @param bool $bq_sql Escape backticks
|
||||
*
|
||||
* @return string Sanitized data
|
||||
*/
|
||||
public function escape($string, $html_ok = false, $bq_sql = false)
|
||||
{
|
||||
if (!is_numeric($string)) {
|
||||
$string = $this->_escape($string);
|
||||
|
||||
if (!$html_ok) {
|
||||
$string = strip_tags(Tools::nl2br($string));
|
||||
}
|
||||
|
||||
if ($bq_sql === true) {
|
||||
$string = str_replace('`', '\`', $string);
|
||||
}
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try a connection to the database.
|
||||
*
|
||||
* @param string $server Server address
|
||||
* @param string $user Login for database connection
|
||||
* @param string $pwd Password for database connection
|
||||
* @param string $db Database name
|
||||
* @param bool $new_db_link
|
||||
* @param string|bool $engine
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return int Error code or 0 if connection was successful
|
||||
*/
|
||||
public static function checkConnection($server, $user, $pwd, $db, $new_db_link = true, $engine = null, $timeout = 5)
|
||||
{
|
||||
return call_user_func_array([Db::getClass(), 'tryToConnect'], [$server, $user, $pwd, $db, $new_db_link, $engine, $timeout]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try a connection to the database and set names to UTF-8.
|
||||
*
|
||||
* @param string $server Server address
|
||||
* @param string $user Login for database connection
|
||||
* @param string $pwd Password for database connection
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function checkEncoding($server, $user, $pwd)
|
||||
{
|
||||
return call_user_func_array([Db::getClass(), 'tryUTF8'], [$server, $user, $pwd]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try a connection to the database and check if at least one table with same prefix exists.
|
||||
*
|
||||
* @param string $server Server address
|
||||
* @param string $user Login for database connection
|
||||
* @param string $pwd Password for database connection
|
||||
* @param string $db Database name
|
||||
* @param string $prefix Tables prefix
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasTableWithSamePrefix($server, $user, $pwd, $db, $prefix)
|
||||
{
|
||||
return call_user_func_array([Db::getClass(), 'hasTableWithSamePrefix'], [$server, $user, $pwd, $db, $prefix]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to connect to the database and create a table (checking creation privileges).
|
||||
*
|
||||
* @param string $server
|
||||
* @param string $user
|
||||
* @param string $pwd
|
||||
* @param string $db
|
||||
* @param string $prefix
|
||||
* @param string|null $engine Table engine
|
||||
*
|
||||
* @return bool|string True, false or error
|
||||
*/
|
||||
public static function checkCreatePrivilege($server, $user, $pwd, $db, $prefix, $engine = null)
|
||||
{
|
||||
return call_user_func_array([Db::getClass(), 'checkCreatePrivilege'], [$server, $user, $pwd, $db, $prefix, $engine]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to connect to the database and select content (checking select privileges).
|
||||
*
|
||||
* @param string $server
|
||||
* @param string $user
|
||||
* @param string $pwd
|
||||
* @param string $db
|
||||
* @param string $prefix
|
||||
* @param string|null $engine Table engine
|
||||
*
|
||||
* @return bool|string True, false or error
|
||||
*/
|
||||
public static function checkSelectPrivilege($server, $user, $pwd, $db, $prefix, $engine = null)
|
||||
{
|
||||
return call_user_func_array([Db::getClass(), 'checkSelectPrivilege'], [$server, $user, $pwd, $db, $prefix, $engine]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get used link instance.
|
||||
*
|
||||
* @return PDO|mysqli|resource Resource
|
||||
*/
|
||||
public function getLink()
|
||||
{
|
||||
return $this->link;
|
||||
}
|
||||
}
|
||||
493
classes/db/DbMySQLi.php
Normal file
493
classes/db/DbMySQLi.php
Normal file
@@ -0,0 +1,493 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class DbMySQLiCore.
|
||||
*
|
||||
* @since 1.5.0,1
|
||||
*/
|
||||
class DbMySQLiCore extends Db
|
||||
{
|
||||
/** @var mysqli */
|
||||
protected $link;
|
||||
|
||||
/** @var mysqli_result */
|
||||
protected $result;
|
||||
|
||||
/**
|
||||
* Tries to connect to the database.
|
||||
*
|
||||
* @see DbCore::connect()
|
||||
*
|
||||
* @return mysqli
|
||||
*
|
||||
* @throws PrestaShopDatabaseException
|
||||
*/
|
||||
public function connect()
|
||||
{
|
||||
$socket = false;
|
||||
$port = false;
|
||||
if (Tools::strpos($this->server, ':') !== false) {
|
||||
list($server, $port) = explode(':', $this->server);
|
||||
if (is_numeric($port) === false) {
|
||||
$socket = $port;
|
||||
$port = false;
|
||||
}
|
||||
} elseif (Tools::strpos($this->server, '/') !== false) {
|
||||
$socket = $this->server;
|
||||
}
|
||||
|
||||
if ($socket) {
|
||||
$this->link = @new mysqli(null, $this->user, $this->password, $this->database, null, $socket);
|
||||
} elseif ($port) {
|
||||
$this->link = @new mysqli($server, $this->user, $this->password, $this->database, $port);
|
||||
} else {
|
||||
$this->link = @new mysqli($this->server, $this->user, $this->password, $this->database);
|
||||
}
|
||||
|
||||
// Do not use object way for error because this work bad before PHP 5.2.9
|
||||
if (mysqli_connect_error()) {
|
||||
throw new PrestaShopDatabaseException(sprintf(Tools::displayError('Link to database cannot be established: %s'), mysqli_connect_error()));
|
||||
}
|
||||
|
||||
// UTF-8 support
|
||||
if (!$this->link->query('SET NAMES utf8mb4')) {
|
||||
throw new PrestaShopDatabaseException(Tools::displayError('PrestaShop Fatal error: no utf-8 support. Please check your server configuration.'));
|
||||
}
|
||||
|
||||
$this->link->query('SET SESSION sql_mode = \'\'');
|
||||
|
||||
return $this->link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to connect and create a new database.
|
||||
*
|
||||
* @param string $host
|
||||
* @param string|null $user
|
||||
* @param string|null $password
|
||||
* @param string|null $database
|
||||
* @param bool $dropit if true, drops the created database
|
||||
*
|
||||
* @return bool|mysqli_result
|
||||
*/
|
||||
public static function createDatabase($host, $user = null, $password = null, $database = null, $dropit = false)
|
||||
{
|
||||
if (strpos($host, ':') !== false) {
|
||||
list($host, $port) = explode(':', $host);
|
||||
$link = @new mysqli($host, $user, $password, null, $port);
|
||||
} else {
|
||||
$link = @new mysqli($host, $user, $password);
|
||||
}
|
||||
$success = $link->query('CREATE DATABASE `' . str_replace('`', '\\`', $database) . '`');
|
||||
if ($dropit && ($link->query('DROP DATABASE `' . str_replace('`', '\\`', $database) . '`') !== false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the database connection link.
|
||||
*
|
||||
* @see DbCore::disconnect()
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
@$this->link->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes an SQL statement, returning a result set as a mysqli_result object or true/false.
|
||||
*
|
||||
* @see DbCore::_query()
|
||||
*
|
||||
* @param string $sql
|
||||
*
|
||||
* @return bool|mysqli_result
|
||||
*/
|
||||
protected function _query($sql)
|
||||
{
|
||||
return $this->link->query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next row from the result set.
|
||||
*
|
||||
* @see DbCore::nextRow()
|
||||
*
|
||||
* @param bool|mysqli_result $result
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function nextRow($result = false)
|
||||
{
|
||||
if (!$result) {
|
||||
$result = $this->result;
|
||||
}
|
||||
|
||||
if (!is_object($result)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $result->fetch_assoc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all rows from the result set.
|
||||
*
|
||||
* @see DbCore::getAll()
|
||||
*
|
||||
* @param bool|mysqli_result $result
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
protected function getAll($result = false)
|
||||
{
|
||||
if (!$result) {
|
||||
$result = $this->result;
|
||||
}
|
||||
|
||||
if (!is_object($result)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (method_exists($result, 'fetch_all')) {
|
||||
return $result->fetch_all(MYSQLI_ASSOC);
|
||||
} else {
|
||||
$ret = [];
|
||||
|
||||
while ($row = $this->nextRow($result)) {
|
||||
$ret[] = $row;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns row count from the result set.
|
||||
*
|
||||
* @see DbCore::_numRows()
|
||||
*
|
||||
* @param bool|mysqli_result $result
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function _numRows($result)
|
||||
{
|
||||
return $result->num_rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ID of the last inserted row.
|
||||
*
|
||||
* @see DbCore::Insert_ID()
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public function Insert_ID()
|
||||
{
|
||||
return $this->link->insert_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of rows affected by the last SQL query.
|
||||
*
|
||||
* @see DbCore::Affected_Rows()
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function Affected_Rows()
|
||||
{
|
||||
return $this->link->affected_rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns error message.
|
||||
*
|
||||
* @see DbCore::getMsgError()
|
||||
*
|
||||
* @param bool $query
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMsgError($query = false)
|
||||
{
|
||||
return $this->link->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns error code.
|
||||
*
|
||||
* @see DbCore::getNumberError()
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumberError()
|
||||
{
|
||||
return $this->link->errno;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns database server version.
|
||||
*
|
||||
* @see DbCore::getVersion()
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
return $this->getValue('SELECT VERSION()');
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes illegal characters in a string.
|
||||
*
|
||||
* @see DbCore::_escape()
|
||||
*
|
||||
* @param string $str
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function _escape($str)
|
||||
{
|
||||
return $this->link->real_escape_string($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches to a different database.
|
||||
*
|
||||
* @see DbCore::set_db()
|
||||
*
|
||||
* @param string $db_name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function set_db($db_name)
|
||||
{
|
||||
return $this->link->query('USE `' . bqSQL($db_name) . '`');
|
||||
}
|
||||
|
||||
/**
|
||||
* Try a connection to the database and check if at least one table with same prefix exists.
|
||||
*
|
||||
* @see Db::hasTableWithSamePrefix()
|
||||
*
|
||||
* @param string $server Server address
|
||||
* @param string $user Login for database connection
|
||||
* @param string $pwd Password for database connection
|
||||
* @param string $db Database name
|
||||
* @param string $prefix Tables prefix
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasTableWithSamePrefix($server, $user, $pwd, $db, $prefix)
|
||||
{
|
||||
$link = @new mysqli($server, $user, $pwd, $db);
|
||||
if (mysqli_connect_error()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = 'SHOW TABLES LIKE \'' . $prefix . '%\'';
|
||||
$result = $link->query($sql);
|
||||
|
||||
return (bool) $result->fetch_assoc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Try a connection to the database.
|
||||
*
|
||||
* @see Db::checkConnection()
|
||||
*
|
||||
* @param string $server Server address
|
||||
* @param string $user Login for database connection
|
||||
* @param string $pwd Password for database connection
|
||||
* @param string $db Database name
|
||||
* @param bool $newDbLink
|
||||
* @param string|bool $engine
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return int Error code or 0 if connection was successful
|
||||
*/
|
||||
public static function tryToConnect($server, $user, $pwd, $db, $new_db_link = true, $engine = null, $timeout = 5)
|
||||
{
|
||||
$link = mysqli_init();
|
||||
if (!$link) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!$link->options(MYSQLI_OPT_CONNECT_TIMEOUT, $timeout)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// There is an @ because mysqli throw a warning when the database does not exists
|
||||
if (!@$link->real_connect($server, $user, $pwd, $db)) {
|
||||
return (mysqli_connect_errno() == 1049) ? 2 : 1;
|
||||
}
|
||||
|
||||
$link->close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects best table engine.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBestEngine()
|
||||
{
|
||||
$value = 'InnoDB';
|
||||
|
||||
$sql = 'SHOW VARIABLES WHERE Variable_name = \'have_innodb\'';
|
||||
$result = $this->link->query($sql);
|
||||
if (!$result) {
|
||||
$value = 'MyISAM';
|
||||
}
|
||||
$row = $result->fetch_assoc();
|
||||
if (!$row || strtolower($row['Value']) != 'yes') {
|
||||
$value = 'MyISAM';
|
||||
}
|
||||
|
||||
/* MySQL >= 5.6 */
|
||||
$sql = 'SHOW ENGINES';
|
||||
$result = $this->link->query($sql);
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
if ($row['Engine'] == 'InnoDB') {
|
||||
if (in_array($row['Support'], ['DEFAULT', 'YES'])) {
|
||||
$value = 'InnoDB';
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to connect to the database and create a table (checking creation privileges).
|
||||
*
|
||||
* @param string $server
|
||||
* @param string $user
|
||||
* @param string $pwd
|
||||
* @param string $db
|
||||
* @param string $prefix
|
||||
* @param string|null $engine Table engine
|
||||
*
|
||||
* @return bool|string True, false or error
|
||||
*/
|
||||
public static function checkCreatePrivilege($server, $user, $pwd, $db, $prefix, $engine = null)
|
||||
{
|
||||
$link = @new mysqli($server, $user, $pwd, $db);
|
||||
if (mysqli_connect_error()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$enginesToTest = ['InnoDB', 'MyISAM'];
|
||||
if ($engine !== null) {
|
||||
$enginesToTest = [$engine];
|
||||
}
|
||||
|
||||
foreach ($enginesToTest as $engineToTest) {
|
||||
$result = $link->query('
|
||||
CREATE TABLE `' . $prefix . 'test` (
|
||||
`test` tinyint(1) unsigned NOT NULL
|
||||
) ENGINE=' . $engineToTest);
|
||||
|
||||
if ($result) {
|
||||
$link->query('DROP TABLE `' . $prefix . 'test`');
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return $link->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to connect to the database and select content (checking select privileges).
|
||||
*
|
||||
* @param string $server
|
||||
* @param string $user
|
||||
* @param string $pwd
|
||||
* @param string $db
|
||||
* @param string $prefix
|
||||
* @param string|null $engine Table engine
|
||||
*
|
||||
* @return bool|string True, false or error
|
||||
*/
|
||||
public static function checkSelectPrivilege($server, $user, $pwd, $db, $prefix, $engine = null)
|
||||
{
|
||||
$link = @new mysqli($server, $user, $pwd, $db);
|
||||
if (mysqli_connect_error()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($engine === null) {
|
||||
$engine = 'MyISAM';
|
||||
}
|
||||
|
||||
// Create a table
|
||||
$link->query('
|
||||
CREATE TABLE `' . $prefix . 'test` (
|
||||
`test` tinyint(1) unsigned NOT NULL
|
||||
) ENGINE=' . $engine);
|
||||
|
||||
// Select content
|
||||
$result = $link->query('SELECT * FROM `' . $prefix . 'test`');
|
||||
|
||||
// Drop the table
|
||||
$link->query('DROP TABLE `' . $prefix . 'test`');
|
||||
|
||||
if (!$result) {
|
||||
return $link->error;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try a connection to the database and set names to UTF-8.
|
||||
*
|
||||
* @see Db::checkEncoding()
|
||||
*
|
||||
* @param string $server Server address
|
||||
* @param string $user Login for database connection
|
||||
* @param string $pwd Password for database connection
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function tryUTF8($server, $user, $pwd)
|
||||
{
|
||||
$link = @new mysqli($server, $user, $pwd);
|
||||
$ret = $link->query('SET NAMES utf8mb4');
|
||||
$link->close();
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
526
classes/db/DbPDO.php
Normal file
526
classes/db/DbPDO.php
Normal file
@@ -0,0 +1,526 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class DbPDOCore.
|
||||
*
|
||||
* @since 1.5.0.1
|
||||
*/
|
||||
class DbPDOCore extends Db
|
||||
{
|
||||
/** @var PDO */
|
||||
protected $link;
|
||||
|
||||
/** @var PDOStatement */
|
||||
protected $result;
|
||||
|
||||
/**
|
||||
* Returns a new PDO object (database link).
|
||||
*
|
||||
* @deprecated use getPDO
|
||||
*
|
||||
* @param string $host
|
||||
* @param string $user
|
||||
* @param string $password
|
||||
* @param string $dbname
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return PDO
|
||||
*/
|
||||
protected static function _getPDO($host, $user, $password, $dbname, $timeout = 5)
|
||||
{
|
||||
return static::getPDO($host, $user, $host, $dbname, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new PDO object (database link).
|
||||
*
|
||||
* @param string $host
|
||||
* @param string $user
|
||||
* @param string $password
|
||||
* @param string $dbname
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return PDO
|
||||
*/
|
||||
protected static function getPDO($host, $user, $password, $dbname, $timeout = 5)
|
||||
{
|
||||
$dsn = 'mysql:';
|
||||
if ($dbname) {
|
||||
$dsn .= 'dbname=' . $dbname . ';';
|
||||
}
|
||||
if (preg_match('/^(.*):([0-9]+)$/', $host, $matches)) {
|
||||
$dsn .= 'host=' . $matches[1] . ';port=' . $matches[2];
|
||||
} elseif (preg_match('#^.*:(/.*)$#', $host, $matches)) {
|
||||
$dsn .= 'unix_socket=' . $matches[1];
|
||||
} else {
|
||||
$dsn .= 'host=' . $host;
|
||||
}
|
||||
$dsn .= ';charset=utf8mb4';
|
||||
|
||||
return new PDO(
|
||||
$dsn,
|
||||
$user,
|
||||
$password,
|
||||
[
|
||||
PDO::ATTR_TIMEOUT => $timeout,
|
||||
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to connect and create a new database.
|
||||
*
|
||||
* @param string $host
|
||||
* @param string $user
|
||||
* @param string $password
|
||||
* @param string $dbname
|
||||
* @param bool $dropit if true, drops the created database
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
public static function createDatabase($host, $user, $password, $dbname, $dropit = false)
|
||||
{
|
||||
try {
|
||||
$link = DbPDO::getPDO($host, $user, $password, false);
|
||||
$success = $link->exec('CREATE DATABASE `' . str_replace('`', '\\`', $dbname) . '`');
|
||||
if ($dropit && ($link->exec('DROP DATABASE `' . str_replace('`', '\\`', $dbname) . '`') !== false)) {
|
||||
return true;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to connect to the database.
|
||||
*
|
||||
* @see DbCore::connect()
|
||||
*
|
||||
* @return PDO
|
||||
*
|
||||
* @throws PrestaShopException
|
||||
*/
|
||||
public function connect()
|
||||
{
|
||||
try {
|
||||
$this->link = $this->getPDO($this->server, $this->user, $this->password, $this->database, 5);
|
||||
} catch (PDOException $e) {
|
||||
throw new PrestaShopException('Link to database cannot be established: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
$this->link->exec('SET SESSION sql_mode = \'\'');
|
||||
|
||||
return $this->link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the database connection link.
|
||||
*
|
||||
* @see DbCore::disconnect()
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
unset($this->link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes an SQL statement, returning a result set as a PDOStatement object or true/false.
|
||||
*
|
||||
* @see DbCore::_query()
|
||||
*
|
||||
* @param string $sql
|
||||
*
|
||||
* @return PDOStatement
|
||||
*/
|
||||
protected function _query($sql)
|
||||
{
|
||||
return $this->link->query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next row from the result set.
|
||||
*
|
||||
* @see DbCore::nextRow()
|
||||
*
|
||||
* @param bool $result
|
||||
*
|
||||
* @return array|false|null
|
||||
*/
|
||||
public function nextRow($result = false)
|
||||
{
|
||||
if (!$result) {
|
||||
$result = $this->result;
|
||||
}
|
||||
|
||||
if (!is_object($result)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $result->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all rows from the result set.
|
||||
*
|
||||
* @see DbCore::getAll()
|
||||
*
|
||||
* @param bool $result
|
||||
*
|
||||
* @return array|false|null
|
||||
*/
|
||||
protected function getAll($result = false)
|
||||
{
|
||||
if (!$result) {
|
||||
$result = $this->result;
|
||||
}
|
||||
|
||||
if (!is_object($result)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $result->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns row count from the result set.
|
||||
*
|
||||
* @see DbCore::_numRows()
|
||||
*
|
||||
* @param PDOStatement $result
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function _numRows($result)
|
||||
{
|
||||
return $result->rowCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ID of the last inserted row.
|
||||
*
|
||||
* @see DbCore::Insert_ID()
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public function Insert_ID()
|
||||
{
|
||||
return $this->link->lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of rows affected by the last SQL query.
|
||||
*
|
||||
* @see DbCore::Affected_Rows()
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function Affected_Rows()
|
||||
{
|
||||
return $this->result->rowCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns error message.
|
||||
*
|
||||
* @see DbCore::getMsgError()
|
||||
*
|
||||
* @param bool $query
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMsgError($query = false)
|
||||
{
|
||||
$error = $this->link->errorInfo();
|
||||
|
||||
return ($error[0] == '00000') ? '' : $error[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns error code.
|
||||
*
|
||||
* @see DbCore::getNumberError()
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumberError()
|
||||
{
|
||||
$error = $this->link->errorInfo();
|
||||
|
||||
return isset($error[1]) ? $error[1] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns database server version.
|
||||
*
|
||||
* @see DbCore::getVersion()
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
return $this->getValue('SELECT VERSION()');
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes illegal characters in a string.
|
||||
*
|
||||
* @see DbCore::_escape()
|
||||
*
|
||||
* @param string $str
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function _escape($str)
|
||||
{
|
||||
$search = ['\\', "\0", "\n", "\r", "\x1a", "'", '"'];
|
||||
$replace = ['\\\\', '\\0', '\\n', '\\r', "\Z", "\'", '\"'];
|
||||
|
||||
return str_replace($search, $replace, $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches to a different database.
|
||||
*
|
||||
* @see DbCore::set_db()
|
||||
*
|
||||
* @param string $db_name
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function set_db($db_name)
|
||||
{
|
||||
return $this->link->exec('USE ' . pSQL($db_name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Try a connection to the database and check if at least one table with same prefix exists.
|
||||
*
|
||||
* @see Db::hasTableWithSamePrefix()
|
||||
*
|
||||
* @param string $server Server address
|
||||
* @param string $user Login for database connection
|
||||
* @param string $pwd Password for database connection
|
||||
* @param string $db Database name
|
||||
* @param string $prefix Tables prefix
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasTableWithSamePrefix($server, $user, $pwd, $db, $prefix)
|
||||
{
|
||||
try {
|
||||
$link = DbPDO::getPDO($server, $user, $pwd, $db, 5);
|
||||
} catch (PDOException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = 'SHOW TABLES LIKE \'' . $prefix . '%\'';
|
||||
$result = $link->query($sql);
|
||||
|
||||
return (bool) $result->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to connect to the database and create a table (checking creation privileges).
|
||||
*
|
||||
* @param string $server
|
||||
* @param string $user
|
||||
* @param string $pwd
|
||||
* @param string $db
|
||||
* @param string $prefix
|
||||
* @param string|null $engine Table engine
|
||||
*
|
||||
* @return bool|string True, false or error
|
||||
*/
|
||||
public static function checkCreatePrivilege($server, $user, $pwd, $db, $prefix, $engine = null)
|
||||
{
|
||||
try {
|
||||
$link = DbPDO::getPDO($server, $user, $pwd, $db, 5);
|
||||
} catch (PDOException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$enginesToTest = ['InnoDB', 'MyISAM'];
|
||||
if ($engine !== null) {
|
||||
$enginesToTest = [$engine];
|
||||
}
|
||||
|
||||
foreach ($enginesToTest as $engineToTest) {
|
||||
$result = $link->query('
|
||||
CREATE TABLE `' . $prefix . 'test` (
|
||||
`test` tinyint(1) unsigned NOT NULL
|
||||
) ENGINE=' . $engineToTest);
|
||||
|
||||
if ($result) {
|
||||
$link->query('DROP TABLE `' . $prefix . 'test`');
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$error = $link->errorInfo();
|
||||
|
||||
return $error[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to connect to the database and select content (checking select privileges).
|
||||
*
|
||||
* @param string $server
|
||||
* @param string $user
|
||||
* @param string $pwd
|
||||
* @param string $db
|
||||
* @param string $prefix
|
||||
* @param string|null $engine Table engine
|
||||
*
|
||||
* @return bool|string True, false or error
|
||||
*/
|
||||
public static function checkSelectPrivilege($server, $user, $pwd, $db, $prefix, $engine = null)
|
||||
{
|
||||
try {
|
||||
$link = DbPDO::getPDO($server, $user, $pwd, $db, 5);
|
||||
} catch (PDOException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($engine === null) {
|
||||
$engine = 'MyISAM';
|
||||
}
|
||||
|
||||
// Create a table
|
||||
$link->query('
|
||||
CREATE TABLE `' . $prefix . 'test` (
|
||||
`test` tinyint(1) unsigned NOT NULL
|
||||
) ENGINE=' . $engine);
|
||||
|
||||
// Select content
|
||||
$result = $link->query('SELECT * FROM `' . $prefix . 'test`');
|
||||
|
||||
// Drop the table
|
||||
$link->query('DROP TABLE `' . $prefix . 'test`');
|
||||
|
||||
if (!$result) {
|
||||
$error = $link->errorInfo();
|
||||
|
||||
return $error[2];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try a connection to the database.
|
||||
*
|
||||
* @see Db::checkConnection()
|
||||
*
|
||||
* @param string $server Server address
|
||||
* @param string $user Login for database connection
|
||||
* @param string $pwd Password for database connection
|
||||
* @param string $db Database name
|
||||
* @param bool $new_db_link
|
||||
* @param string|bool $engine
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return int Error code or 0 if connection was successful
|
||||
*/
|
||||
public static function tryToConnect($server, $user, $pwd, $db, $new_db_link = true, $engine = null, $timeout = 5)
|
||||
{
|
||||
try {
|
||||
$link = DbPDO::getPDO($server, $user, $pwd, $db, $timeout);
|
||||
} catch (PDOException $e) {
|
||||
// hhvm wrongly reports error status 42000 when the database does not exist - might change in the future
|
||||
return ($e->getCode() == 1049 || (defined('HHVM_VERSION') && $e->getCode() == 42000)) ? 2 : 1;
|
||||
}
|
||||
unset($link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects best table engine.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBestEngine()
|
||||
{
|
||||
$value = 'InnoDB';
|
||||
|
||||
$sql = 'SHOW VARIABLES WHERE Variable_name = \'have_innodb\'';
|
||||
$result = $this->link->query($sql);
|
||||
|
||||
if (!$result) {
|
||||
$value = 'MyISAM';
|
||||
} else {
|
||||
$row = $result->fetch();
|
||||
if (!$row || strtolower($row['Value']) != 'yes') {
|
||||
$value = 'MyISAM';
|
||||
}
|
||||
}
|
||||
|
||||
/* MySQL >= 5.6 */
|
||||
$sql = 'SHOW ENGINES';
|
||||
$result = $this->link->query($sql);
|
||||
while ($row = $result->fetch()) {
|
||||
if ($row['Engine'] == 'InnoDB') {
|
||||
if (in_array($row['Support'], ['DEFAULT', 'YES'])) {
|
||||
$value = 'InnoDB';
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try a connection to the database and set names to UTF-8.
|
||||
*
|
||||
* @see Db::checkEncoding()
|
||||
*
|
||||
* @param string $server Server address
|
||||
* @param string $user Login for database connection
|
||||
* @param string $pwd Password for database connection
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function tryUTF8($server, $user, $pwd)
|
||||
{
|
||||
try {
|
||||
$link = DbPDO::getPDO($server, $user, $pwd, false, 5);
|
||||
} catch (PDOException $e) {
|
||||
return false;
|
||||
}
|
||||
$result = $link->exec('SET NAMES utf8mb4');
|
||||
unset($link);
|
||||
|
||||
return ($result === false) ? false : true;
|
||||
}
|
||||
}
|
||||
334
classes/db/DbQuery.php
Normal file
334
classes/db/DbQuery.php
Normal file
@@ -0,0 +1,334 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
/**
|
||||
* SQL query builder.
|
||||
*
|
||||
* @since 1.5.0.1
|
||||
*/
|
||||
class DbQueryCore
|
||||
{
|
||||
/**
|
||||
* List of data to build the query.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $query = [
|
||||
'type' => 'SELECT',
|
||||
'select' => [],
|
||||
'from' => [],
|
||||
'join' => [],
|
||||
'where' => [],
|
||||
'group' => [],
|
||||
'having' => [],
|
||||
'order' => [],
|
||||
'limit' => ['offset' => 0, 'limit' => 0],
|
||||
];
|
||||
|
||||
/**
|
||||
* Sets type of the query.
|
||||
*
|
||||
* @param string $type SELECT|DELETE
|
||||
*
|
||||
* @return DbQuery
|
||||
*/
|
||||
public function type($type)
|
||||
{
|
||||
$types = ['SELECT', 'DELETE'];
|
||||
|
||||
if (!empty($type) && in_array($type, $types)) {
|
||||
$this->query['type'] = $type;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds fields to SELECT clause.
|
||||
*
|
||||
* @param string $fields List of fields to concat to other fields
|
||||
*
|
||||
* @return DbQuery
|
||||
*/
|
||||
public function select($fields)
|
||||
{
|
||||
if (!empty($fields)) {
|
||||
$this->query['select'][] = $fields;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets table for FROM clause.
|
||||
*
|
||||
* @param string $table Table name
|
||||
* @param string|null $alias Table alias
|
||||
*
|
||||
* @return DbQuery
|
||||
*/
|
||||
public function from($table, $alias = null)
|
||||
{
|
||||
if (!empty($table)) {
|
||||
$this->query['from'][] = '`' . _DB_PREFIX_ . $table . '`' . ($alias ? ' ' . $alias : '');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds JOIN clause
|
||||
* E.g. $this->join('RIGHT JOIN '._DB_PREFIX_.'product p ON ...');.
|
||||
*
|
||||
* @param string $join Complete string
|
||||
*
|
||||
* @return DbQuery
|
||||
*/
|
||||
public function join($join)
|
||||
{
|
||||
if (!empty($join)) {
|
||||
$this->query['join'][] = $join;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a LEFT JOIN clause.
|
||||
*
|
||||
* @param string $table Table name (without prefix)
|
||||
* @param string|null $alias Table alias
|
||||
* @param string|null $on ON clause
|
||||
*
|
||||
* @return DbQuery
|
||||
*/
|
||||
public function leftJoin($table, $alias = null, $on = null)
|
||||
{
|
||||
return $this->join('LEFT JOIN `' . _DB_PREFIX_ . bqSQL($table) . '`' . ($alias ? ' `' . pSQL($alias) . '`' : '') . ($on ? ' ON ' . $on : ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an INNER JOIN clause
|
||||
* E.g. $this->innerJoin('product p ON ...').
|
||||
*
|
||||
* @param string $table Table name (without prefix)
|
||||
* @param string|null $alias Table alias
|
||||
* @param string|null $on ON clause
|
||||
*
|
||||
* @return DbQuery
|
||||
*/
|
||||
public function innerJoin($table, $alias = null, $on = null)
|
||||
{
|
||||
return $this->join('INNER JOIN `' . _DB_PREFIX_ . bqSQL($table) . '`' . ($alias ? ' `' . pSQL($alias) . '`' : '') . ($on ? ' ON ' . $on : ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a LEFT OUTER JOIN clause.
|
||||
*
|
||||
* @param string $table Table name (without prefix)
|
||||
* @param string|null $alias Table alias
|
||||
* @param string|null $on ON clause
|
||||
*
|
||||
* @return DbQuery
|
||||
*/
|
||||
public function leftOuterJoin($table, $alias = null, $on = null)
|
||||
{
|
||||
return $this->join('LEFT OUTER JOIN `' . _DB_PREFIX_ . bqSQL($table) . '`' . ($alias ? ' `' . pSQL($alias) . '`' : '') . ($on ? ' ON ' . $on : ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a NATURAL JOIN clause.
|
||||
*
|
||||
* @param string $table Table name (without prefix)
|
||||
* @param string|null $alias Table alias
|
||||
*
|
||||
* @return DbQuery
|
||||
*/
|
||||
public function naturalJoin($table, $alias = null)
|
||||
{
|
||||
return $this->join('NATURAL JOIN `' . _DB_PREFIX_ . bqSQL($table) . '`' . ($alias ? ' `' . pSQL($alias) . '`' : ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a RIGHT JOIN clause.
|
||||
*
|
||||
* @param string $table Table name (without prefix)
|
||||
* @param string|null $alias Table alias
|
||||
* @param string|null $on ON clause
|
||||
*
|
||||
* @return DbQuery
|
||||
*/
|
||||
public function rightJoin($table, $alias = null, $on = null)
|
||||
{
|
||||
return $this->join('RIGHT JOIN `' . _DB_PREFIX_ . bqSQL($table) . '`' . ($alias ? ' `' . pSQL($alias) . '`' : '') . ($on ? ' ON ' . $on : ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a restriction in WHERE clause (each restriction will be separated by AND statement).
|
||||
*
|
||||
* @param string $restriction
|
||||
*
|
||||
* @return DbQuery
|
||||
*/
|
||||
public function where($restriction)
|
||||
{
|
||||
if (!empty($restriction)) {
|
||||
$this->query['where'][] = $restriction;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a restriction in HAVING clause (each restriction will be separated by AND statement).
|
||||
*
|
||||
* @param string $restriction
|
||||
*
|
||||
* @return DbQuery
|
||||
*/
|
||||
public function having($restriction)
|
||||
{
|
||||
if (!empty($restriction)) {
|
||||
$this->query['having'][] = $restriction;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an ORDER BY restriction.
|
||||
*
|
||||
* @param string $fields List of fields to sort. E.g. $this->order('myField, b.mySecondField DESC')
|
||||
*
|
||||
* @return DbQuery
|
||||
*/
|
||||
public function orderBy($fields)
|
||||
{
|
||||
if (!empty($fields)) {
|
||||
$this->query['order'][] = $fields;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a GROUP BY restriction.
|
||||
*
|
||||
* @param string $fields List of fields to group. E.g. $this->group('myField1, myField2')
|
||||
*
|
||||
* @return DbQuery
|
||||
*/
|
||||
public function groupBy($fields)
|
||||
{
|
||||
if (!empty($fields)) {
|
||||
$this->query['group'][] = $fields;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets query offset and limit.
|
||||
*
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
*
|
||||
* @return DbQuery
|
||||
*/
|
||||
public function limit($limit, $offset = 0)
|
||||
{
|
||||
$offset = (int) $offset;
|
||||
if ($offset < 0) {
|
||||
$offset = 0;
|
||||
}
|
||||
|
||||
$this->query['limit'] = [
|
||||
'offset' => $offset,
|
||||
'limit' => (int) $limit,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates query and return SQL string.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws PrestaShopException
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
if ($this->query['type'] == 'SELECT') {
|
||||
$sql = 'SELECT ' . ((($this->query['select'])) ? implode(",\n", $this->query['select']) : '*') . "\n";
|
||||
} else {
|
||||
$sql = $this->query['type'] . ' ';
|
||||
}
|
||||
|
||||
if (!$this->query['from']) {
|
||||
throw new PrestaShopException('Table name not set in DbQuery object. Cannot build a valid SQL query.');
|
||||
}
|
||||
|
||||
$sql .= 'FROM ' . implode(', ', $this->query['from']) . "\n";
|
||||
|
||||
if ($this->query['join']) {
|
||||
$sql .= implode("\n", $this->query['join']) . "\n";
|
||||
}
|
||||
|
||||
if ($this->query['where']) {
|
||||
$sql .= 'WHERE (' . implode(') AND (', $this->query['where']) . ")\n";
|
||||
}
|
||||
|
||||
if ($this->query['group']) {
|
||||
$sql .= 'GROUP BY ' . implode(', ', $this->query['group']) . "\n";
|
||||
}
|
||||
|
||||
if ($this->query['having']) {
|
||||
$sql .= 'HAVING (' . implode(') AND (', $this->query['having']) . ")\n";
|
||||
}
|
||||
|
||||
if ($this->query['order']) {
|
||||
$sql .= 'ORDER BY ' . implode(', ', $this->query['order']) . "\n";
|
||||
}
|
||||
|
||||
if ($this->query['limit']['limit']) {
|
||||
$limit = $this->query['limit'];
|
||||
$sql .= 'LIMIT ' . ($limit['offset'] ? $limit['offset'] . ', ' : '') . $limit['limit'];
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts object to string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->build();
|
||||
}
|
||||
}
|
||||
34
classes/db/index.php
Normal file
34
classes/db/index.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
||||
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
|
||||
header('Location: ../../');
|
||||
exit;
|
||||
Reference in New Issue
Block a user