cli = Utility::isCLI();
$defaults = [
'checkVersion' => false,
'createDb' => false, // create dbname if it does not exist?
'ct' => new ConsoleTools(),
'dbhost' => defined('DB_HOST') ? DB_HOST : '',
'dbname' => defined('DB_NAME') ? DB_NAME : '',
'dbpass' => defined('DB_PASSWORD') ? DB_PASSWORD : '',
'dbport' => defined('DB_PORT') ? DB_PORT : '',
'dbsock' => defined('DB_SOCKET') ? DB_SOCKET : '',
'dbtype' => defined('DB_TYPE') ? DB_TYPE : '',
'dbuser' => defined('DB_USER') ? DB_USER : '',
'log' => new ColorCLI(),
'persist' => false,
];
$options += $defaults;
if (!$this->cli) {
$options['log'] = null;
}
$this->opts = $options;
if (!empty($this->opts['dbtype'])) {
$this->dbSystem = strtolower($this->opts['dbtype']);
}
if (!($this->pdo instanceof \PDO)) {
$this->initialiseDatabase();
}
$this->cacheEnabled = (defined('NN_CACHE_TYPE') && (NN_CACHE_TYPE > 0) ? true : false);
if ($this->cacheEnabled) {
try {
$this->cacheServer = new Cache();
} catch (CacheException $error) {
$this->cacheEnabled = false;
$this->echoError($error->getMessage(), '__construct', 4);
}
}
$this->ct = $this->opts['ct'];
$this->log = $this->opts['log'];
$this->_debug = (NN_DEBUG || NN_LOGGING);
if ($this->_debug) {
try {
$this->debugging = new Logger(['ColorCLI' => $this->log]);
} catch (LoggerException $error) {
$this->_debug = false;
}
}
if ($this->opts['checkVersion']) {
$this->fetchDbVersion();
}
return $this->pdo;
}
public function __destruct()
{
$this->pdo = null;
}
public function checkDbExists ($name = null)
{
if (empty($name)) {
$name = $this->opts['dbname'];
}
$found = false;
$tables = self::getTableList();
foreach ($tables as $table) {
if ($table['Database'] == $name) {
$found = true;
break;
}
}
return $found;
}
/**
* Looks up info for index on table.
*
* @param $table string Table to look at.
* @param $index string Index to check.
*
* @return bool|array False on failure, associative array of SHOW data.
*/
public function checkIndex($table, $index)
{
$result = $this->pdo->query(
sprintf(
"SHOW INDEX FROM %s WHERE key_name = '%s'",
trim($table),
trim($index)
)
);
if ($result === false) {
return false;
}
return $result->fetch(\PDO::FETCH_ASSOC);
}
public function checkColumnIndex($table, $column)
{
$result = $this->pdo->query(
sprintf(
"SHOW INDEXES IN %s WHERE non_unique = 0 AND column_name = '%s'",
trim($table),
trim($column)
)
);
if ($result === false) {
return false;
}
return $result->fetchAll(\PDO::FETCH_ASSOC);
}
public function debugDisable()
{
unset($this->debugging);
$this->_debug = false;
}
public function debugEnable()
{
$this->_debug = true;
try {
$this->debugging = new Logger(['ColorCLI' => $this->log]);
} catch (LoggerException $error) {
$this->_debug = false;
}
}
public function getTableList ()
{
$query = ($this->opts['dbtype'] === 'mysql' ? 'SHOW DATABASES' : 'SELECT datname AS Database FROM pg_database');
$result = $this->pdo->query($query);
return $result->fetchAll(\PDO::FETCH_ASSOC);
}
/**
* @return bool Whether the Db is definitely on the local machine.
*/
public function isLocalDb ()
{
if (!empty($this->opts['dbsock']) || $this->opts['dbhost'] == 'localhost') {
return true;
}
preg_match_all('/inet' . '6?' . ' addr: ?([^ ]+)/', `ifconfig`, $ips);
// Check for dotted quad - if exists compare against local IP number(s)
if (preg_match('#^\d+\.\d+\.\d+\.\d+$#', $this->opts['dbhost'])) {
if (in_array($this->opts['dbhost'], $ips[1])) {
return true;
}
}
return false;
}
/**
* Init \PDO instance.
*/
private function initialiseDatabase()
{
if (!empty($this->opts['dbsock'])) {
$dsn = $this->dbSystem . ':unix_socket=' . $this->opts['dbsock'];
} else {
$dsn = $this->dbSystem . ':host=' . $this->opts['dbhost'];
if (!empty($this->opts['dbport'])) {
$dsn .= ';port=' . $this->opts['dbport'];
}
}
$dsn .= ';charset=utf8';
$options = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_TIMEOUT => 180,
\PDO::ATTR_PERSISTENT => $this->opts['persist'],
\PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8",
\PDO::MYSQL_ATTR_LOCAL_INFILE => true
];
$this->dsn = $dsn;
// removed try/catch to let the instantiating code handle the problem (Install for
// instance can output a message that connecting failed.
$this->pdo = new \PDO($dsn, $this->opts['dbuser'], $this->opts['dbpass'], $options);
if ($this->opts['dbname'] != '') {
if ($this->opts['createDb']) {
$found = self::checkDbExists();
if ($found) {
try {
$this->pdo->query("DROP DATABASE " . $this->opts['dbname']);
} catch (\Exception $e) {
throw new \RuntimeException("Error trying to drop your old database: '{$this->opts['dbname']}'", 2);
}
$found = self::checkDbExists();
}
if ($found) {
var_dump(self::getTableList());
throw new \RuntimeException("Could not drop your old database: '{$this->opts['dbname']}'", 2);
} else {
$this->pdo->query("CREATE DATABASE `{$this->opts['dbname']}` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci");
if (!self::checkDbExists()) {
throw new \RuntimeException("Could not create new database: '{$this->opts['dbname']}'", 3);
}
}
}
$this->pdo->query("USE {$this->opts['dbname']}");
}
// In case \PDO is not set to produce exceptions (PHP's default behaviour).
if ($this->pdo === false) {
$this->echoError(
"Unable to create connection to the Database!",
'initialiseDatabase',
1,
true
);
}
// For backwards compatibility, no need for a patch.
$this->pdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_LOWER);
$this->pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
$this->pdo->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
}
/**
* Echo error, optionally exit.
*
* @param string $error The error message.
* @param string $method The method where the error occured.
* @param int $severity The severity of the error.
* @param bool $exit Exit or not?
*/
protected function echoError($error, $method, $severity, $exit = false)
{
if ($this->_debug) {
$this->debugging->log(get_class(), $method, $error, $severity);
echo(
($this->cli ? $this->log->error($error) . PHP_EOL : '
' . $error . '
')
);
}
if ($exit) {
exit();
}
}
/**
* @return string mysql.
*/
public function DbSystem()
{
return $this->dbSystem;
}
/**
* Returns a string, escaped with single quotes, false on failure. http://www.php.net/manual/en/pdo.quote.php
*
* @param string $str
*
* @return string
*/
public function escapeString($str)
{
if (is_null($str)) {
return 'NULL';
}
return $this->pdo->quote($str);
}
/**
* Formats a 'like' string. ex.(LIKE '%chocolate%')
*
* @param string $str The string.
* @param bool $left Add a % to the left.
* @param bool $right Add a % to the right.
*
* @return string
*/
public function likeString($str, $left=true, $right=true)
{
return (
'LIKE ' .
$this->escapeString(
($left ? '%' : '') .
$str .
($right ? '%' : '')
)
);
}
/**
* Verify if pdo var is instance of \PDO class.
*
* @return bool
*/
public function isInitialised()
{
return ($this->pdo instanceof \PDO);
}
/**
* For inserting a row. Returns last insert id. queryExec is better if you do not need the id.
*
* @param string $query
*
* @return bool|int
*/
public function queryInsert($query)
{
if (empty($query)) {
return false;
}
if (NN_QUERY_STRIP_WHITESPACE) {
$query = Utility::collapseWhiteSpace($query);
}
$i = 2;
$error = '';
while($i < 11) {
$result = $this->queryExecHelper($query, true);
if (is_array($result) && isset($result['deadlock'])) {
$error = $result['message'];
if ($result['deadlock'] === true) {
$this->echoError("A Deadlock or lock wait timeout has occurred, sleeping.(" . ($i-1) . ")", 'queryInsert', 4);
$this->ct->showsleep($i * ($i/2));
$i++;
} else {
break;
}
} elseif ($result === false) {
$error = 'Unspecified error.';
break;
} else {
return $result;
}
}
if ($this->_debug) {
$this->echoError($error, 'queryInsert', 4);
$this->debugging->log(get_class(), __FUNCTION__, $query, Logger::LOG_SQL);
}
return false;
}
/**
* Used for deleting, updating (and inserting without needing the last insert id).
*
* @param string $query
* @param bool $silent Echo or log errors?
*
* @return bool|\PDOStatement
*/
public function queryExec($query, $silent = false)
{
if (empty($query)) {
return false;
}
if (NN_QUERY_STRIP_WHITESPACE) {
$query = Utility::collapseWhiteSpace($query);
}
$i = 2;
$error = '';
while($i < 11) {
$result = $this->queryExecHelper($query);
if (is_array($result) && isset($result['deadlock'])) {
$error = $result['message'];
if ($result['deadlock'] === true) {
$this->echoError("A Deadlock or lock wait timeout has occurred, sleeping.(" . ($i-1) . ")", 'queryExec', 4);
$this->ct->showsleep($i * ($i/2));
$i++;
} else {
break;
}
} elseif ($result === false) {
$error = 'Unspecified error.';
break;
} else {
return $result;
}
}
if ($silent === false && $this->_debug) {
$this->echoError($error, 'queryExec', 4);
$this->debugging->log(get_class(), __FUNCTION__, $query, Logger::LOG_SQL);
}
return false;
}
/**
* Helper method for queryInsert and queryExec, checks for deadlocks.
*
* @param string $query
* @param bool $insert
*
* @return array|\PDOStatement
*/
protected function queryExecHelper($query, $insert = false)
{
try {
if ($insert === false ) {
$run = $this->pdo->prepare($query);
$run->execute();
return $run;
} else {
$ins = $this->pdo->prepare($query);
$ins->execute();
return $this->pdo->lastInsertId();
}
} catch (\PDOException $e) {
// Deadlock or lock wait timeout, try 10 times.
if (
$e->errorInfo[1] == 1213 ||
$e->errorInfo[0] == 40001 ||
$e->errorInfo[1] == 1205 ||
$e->getMessage() == 'SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction'
) {
return ['deadlock' => true, 'message' => $e->getMessage()];
}
// Check if we lost connection to MySQL.
else if ($this->_checkGoneAway($e->getMessage()) !== false) {
// Reconnect to MySQL.
if ($this->_reconnect() === true) {
// If we reconnected, retry the query.
return $this->queryExecHelper($query, $insert);
}
}
return ['deadlock' => false, 'message' => $e->getMessage()];
}
}
/**
* Direct query. Return the affected row count. http://www.php.net/manual/en/pdo.exec.php
*
* @note If not "consumed", causes this error:
* 'SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active.
* Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql,
* you may enable query buffering by setting the \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.'
*
* @param string $query
* @param bool $silent Whether to skip echoing errors to the console.
*
* @return bool|int|\PDOStatement
*/
public function exec($query, $silent = false)
{
if (empty($query)) {
return false;
}
if (NN_QUERY_STRIP_WHITESPACE) {
$query = Utility::collapseWhiteSpace($query);
}
try {
return $this->pdo->exec($query);
} catch (\PDOException $e) {
// Check if we lost connection to MySQL.
if ($this->_checkGoneAway($e->getMessage()) !== false) {
// Reconnect to MySQL.
if ($this->_reconnect() === true) {
// If we reconnected, retry the query.
return $this->exec($query, $silent);
} else {
// If we are not reconnected, return false.
return false;
}
} else if (!$silent) {
$this->echoError($e->getMessage(), 'Exec', 4, false);
if ($this->_debug) {
$this->debugging->log(get_class(), __FUNCTION__, $query, Logger::LOG_SQL);
}
}
return false;
}
}
/**
* Returns an array of result (empty array if no results or an error occurs)
* Optional: Pass true to cache the result with a cache server.
*
* @param string $query SQL to execute.
* @param bool $cache Indicates if the query result should be cached.
* @param int $cacheExpiry The time in seconds before deleting the query result from the cache server.
*
* @return array Array of results (possibly empty) on success, empty array on failure.
*/
public function query($query, $cache = false, $cacheExpiry = 600)
{
if (empty($query)) {
return false;
}
if (NN_QUERY_STRIP_WHITESPACE) {
$query = Utility::collapseWhiteSpace($query);
}
if ($cache === true && $this->cacheEnabled === true) {
try {
$data = $this->cacheServer->get($this->cacheServer->createKey($query));
if ($data !== false) {
return $data;
}
} catch (CacheException $error) {
$this->echoError($error->getMessage(), 'query', 4);
}
}
$result = $this->queryArray($query);
if ($result !== false && $cache === true && $this->cacheEnabled === true) {
$this->cacheServer->set($this->cacheServer->createKey($query), $result, $cacheExpiry);
}
return ($result === false) ? [] : $result;
}
/**
* Main method for creating results as an array.
*
* @param string $query SQL to execute.
*
* @return array|boolean Array of results on success or false on failure.
*/
public function queryArray($query)
{
$result = false;
if (!empty($query)) {
$result = $this->queryDirect($query);
if (!empty($result)) {
$result = $result->fetchAll();
}
}
return $result;
}
/**
* Returns all results as an associative array.
*
* Do not use this function for large dat-asets, as it can cripple the Db server and use huge
* amounts of RAM. Instead iterate through the data.
*
* @param string $query The query to execute.
*
* @return array|boolean Array of results on success, false otherwise.
*/
public function queryAssoc($query)
{
if ($query == '') {
return false;
}
$mode = $this->pdo->getAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE);
if ($mode != \PDO::FETCH_ASSOC) {
$this->pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
}
$result = $this->queryArray($query);
if ($mode != \PDO::FETCH_ASSOC) {
$this->pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
}
return $result;
}
/**
* Fetch a assoc row from a result set
*
* @param $result
* @return array|\PDOStatement
*/
public function getAssocArray($result)
{
return $result->fetch(\PDO::FETCH_ASSOC);
}
/**
* Get the total number of rows in the result set
*
* @param $result
* @return int|\PDOStatement
*/
public function getNumRows($result)
{
return $result->rowCount();
}
/**
* Query without returning an empty array like our function query(). http://php.net/manual/en/pdo.query.php
*
* @param string $query The query to run.
* @param bool $ignore Ignore errors, do not log them?
*
* @return bool|\PDOStatement
*/
public function queryDirect($query, $ignore = false)
{
if (empty($query)) {
return false;
}
if (NN_QUERY_STRIP_WHITESPACE) {
$query = Utility::collapseWhiteSpace($query);
}
try {
$result = $this->pdo->query($query);
} catch (\PDOException $e) {
// Check if we lost connection to MySQL.
if ($this->_checkGoneAway($e->getMessage()) !== false) {
// Reconnect to MySQL.
if ($this->_reconnect() === true) {
// If we reconnected, retry the query.
$result = $this->queryDirect($query);
} else {
// If we are not reconnected, return false.
$result = false;
}
} else {
if ($ignore === false) {
$this->echoError($e->getMessage(), 'queryDirect', 4, false);
if ($this->_debug) {
$this->debugging->log(get_class(), __FUNCTION__, $query, Logger::LOG_SQL);
}
}
$result = false;
}
}
return $result;
}
/**
* Reconnect to MySQL when the connection has been lost.
*
* @see ping(), _checkGoneAway() for checking the connection.
*
* @return bool
*/
protected function _reconnect()
{
$this->initialiseDatabase();
// Check if we are really connected to MySQL.
if ($this->ping() === false) {
// If we are not reconnected, return false.
return false;
}
return true;
}
/**
* Verify that we've lost a connection to MySQL.
*
* @param string $errorMessage
*
* @return bool
*/
protected function _checkGoneAway($errorMessage)
{
if (stripos($errorMessage, 'MySQL server has gone away') !== false) {
return true;
}
return false;
}
/**
* Returns the first row of the query.
*
* @param string $query
* @param bool $appendLimit
*
* @return array|bool
*/
public function queryOneRow($query, $appendLimit = true)
{
// Force the query to only return 1 row, so queryArray doesn't potentially run out of memory on a large data set.
// First check if query already contains a LIMIT clause.
if (preg_match('#\s+LIMIT\s+(?P\d+)(,\s+(?P\d+))?(;)?$#i', $query, $matches)) {
If (!isset($matches['upper']) && isset($matches['lower']) && $matches['lower'] == 1) {
// good it's already correctly set.
} else { // We have a limit, but it's not for a single row
return false;
}
} else if ($appendLimit) {
$query .= ' LIMIT 1';
}
$rows = $this->query($query);
if (!$rows || count($rows) == 0) {
$rows = false;
}
return is_array($rows) ? $rows[0] : $rows;
}
/**
* Optimises/repairs tables on mysql.
*
* @param bool $admin If we are on web, don't echo.
* @param string $type 'full' | '' Force optimize of all tables.
* 'space' Optimise tables with 5% or more free space.
* 'analyze' Analyze tables to rebuild statistics.
* @param bool $local Only analyze local tables. Good if running replication.
* @param array $tableList (optional) Names of tables to analyze.
*
* @return int Quantity optimized/analyzed
*/
public function optimise($admin = false, $type = '', $local = false, $tableList = [])
{
$tableAnd = '';
if (count($tableList)) {
foreach ($tableList as $tableName) {
$tableAnd .= ($this->escapeString($tableName) . ',');
}
$tableAnd = (' AND name IN (' . rtrim($tableAnd, ',') . ')');
}
switch ($type) {
case 'space':
$tableArray = $this->queryDirect('SHOW TABLE STATUS WHERE Data_free / Data_length > 0.005' . $tableAnd);
$myIsamTables = $this->queryDirect("SHOW TABLE STATUS WHERE ENGINE LIKE 'myisam' AND Data_free / Data_length > 0.005" . $tableAnd);
break;
case 'analyze':
case '':
case 'full':
default:
$tableArray = $this->queryDirect('SHOW TABLE STATUS WHERE 1=1' . $tableAnd);
$myIsamTables = $this->queryDirect("SHOW TABLE STATUS WHERE ENGINE LIKE 'myisam'" . $tableAnd);
break;
}
$optimised = 0;
if ($tableArray instanceof \Traversable && $tableArray->rowCount()) {
$tableNames = '';
foreach ($tableArray as $table) {
$tableNames .= $table['name'] . ',';
}
$tableNames = rtrim($tableNames, ',');
$local = ($local ? 'LOCAL' : '');
if ($type === 'analyze') {
$this->queryExec(sprintf('ANALYZE %s TABLE %s', $local, $tableNames));
$this->logOptimize($admin, 'ANALYZE', $tableNames);
} else {
$this->queryExec(sprintf('OPTIMIZE %s TABLE %s', $local, $tableNames));
$this->logOptimize($admin, 'OPTIMIZE', $tableNames);
if ($myIsamTables instanceof \Traversable && $myIsamTables->rowCount()) {
$tableNames = '';
foreach ($myIsamTables as $table) {
$tableNames .= $table['name'] . ',';
}
$tableNames = rtrim($tableNames, ',');
$this->queryExec(sprintf('REPAIR %s TABLE %s', $local, $tableNames));
$this->logOptimize($admin, 'REPAIR', $tableNames);
}
$this->queryExec(sprintf('FLUSH %s TABLES', $local));
}
$optimised = $tableArray->rowCount();
}
return $optimised;
}
/**
* Get the amount of found rows after running a SELECT SQL_CALC_FOUND_ROWS query.
*
* @return int
* @access public
*/
public function get_Found_Rows()
{
$totalCount = $this->queryOneRow('SELECT FOUND_ROWS() AS total');
return ($totalCount === false ? 0 : $totalCount['total']);
}
/**
* Log/echo repaired/optimized/analyzed tables.
*
* @param bool $web If we are on web, don't echo.
* @param string $type ANALYZE|OPTIMIZE|REPAIR
* @param string $tables Table names.
*
* @access private
* @void
*/
private function logOptimize($web, $type, $tables)
{
$message = $type . ' (' . $tables . ')';
if ($web === false) {
echo $this->log->primary($message);
}
if ($this->_debug) {
$this->debugging->log(get_class(), __FUNCTION__, $message, Logger::LOG_INFO);
}
}
/**
* Turns off autocommit until commit() is ran. http://www.php.net/manual/en/pdo.begintransaction.php
*
* @return bool
*/
public function beginTransaction()
{
if (NN_USE_SQL_TRANSACTIONS) {
return $this->pdo->beginTransaction();
}
return true;
}
/**
* Commits a transaction. http://www.php.net/manual/en/pdo.commit.php
*
* @return bool
*/
public function Commit()
{
if (NN_USE_SQL_TRANSACTIONS) {
return $this->pdo->commit();
}
return true;
}
/**
* Rollback transcations. http://www.php.net/manual/en/pdo.rollback.php
*
* @return bool
*/
public function Rollback()
{
if (NN_USE_SQL_TRANSACTIONS) {
return $this->pdo->rollBack();
}
return true;
}
/**
* PHP interpretation of MySQL's from_unixtime method.
* @param int $utime UnixTime
*
* @return string
*/
public function from_unixtime($utime)
{
return 'FROM_UNIXTIME(' . $utime . ')';
}
/**
* PHP interpretation of mysql's unix_timestamp method.
* @param string $date
*
* @return int
*/
public function unix_timestamp($date)
{
return strtotime($date);
}
/**
* Get a string for MySQL with a column name in between
* ie: UNIX_TIMESTAMP(column_name) AS outputName
*
* @param string $column The datetime column.
* @param string $outputName The name to store the SQL data into. (the word after AS)
*
* @return string
*/
public function unix_timestamp_column($column, $outputName = 'unix_time')
{
return ('UNIX_TIMESTAMP(' . $column . ') AS ' . $outputName);
}
/**
* Interpretation of mysql's UUID method.
* Return uuid v4 string. http://www.php.net/manual/en/function.uniqid.php#94959
*
* @return string
*/
public function uuid()
{
return sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0xffff)
);
}
/**
* Checks whether the connection to the server is working. Optionally restart a new connection.
* NOTE: Restart does not happen if \PDO is not using exceptions (PHP's default configuration).
* In this case check the return value === false.
*
* @param boolean $restart Whether an attempt should be made to reinitialise the Db object on failure.
*
* @return boolean
*/
public function ping($restart = false)
{
try {
return (bool) $this->pdo->query('SELECT 1+1');
} catch (\PDOException $e) {
if ($restart == true) {
$this->initialiseDatabase();
}
return false;
}
}
/**
* Prepares a statement to be run by the Db engine.
* To run the statement use the returned $statement with ->execute();
*
* Ideally the signature would have array before $options but that causes a strict warning.
*
* @param string $query SQL query to run, with optional place holders.
* @param array $options Driver options.
*
* @return false|\PDOstatement on success false on failure.
*
* @link http://www.php.net/pdo.prepare.php
*/
public function Prepare($query, $options = [])
{
try {
$PDOstatement = $this->pdo->prepare($query, $options);
} catch (\PDOException $e) {
if ($this->_debug) {
$this->debugging->log(get_class(), __FUNCTION__, $e->getMessage(), Logger::LOG_INFO);
}
echo $this->log->error("\n" . $e->getMessage());
$PDOstatement = false;
}
return $PDOstatement;
}
/**
* Retrieve db attributes http://us3.php.net/manual/en/pdo.getattribute.php
*
* @param int $attribute
*
* @return bool|mixed
*/
public function getAttribute($attribute)
{
$result = false;
if ($attribute != '') {
try {
$result = $this->pdo->getAttribute($attribute);
} catch (\PDOException $e) {
if ($this->_debug) {
$this->debugging->log(get_class(), __FUNCTION__, $e->getMessage(), Logger::LOG_INFO);
}
echo $this->log->error("\n" . $e->getMessage());
$result = false;
}
}
return $result;
}
/**
* Returns the stored Db version string.
*
* @return string
*/
public function getDbVersion ()
{
return $this->dbVersion;
}
/**
* @param string $requiredVersion The minimum version to compare against
*
* @return bool|null TRUE if Db version is greater than or eaqual to $requiredVersion,
* false if not, and null if the version isn't available to check against.
*/
public function isDbVersionAtLeast ($requiredVersion)
{
if (empty($this->dbVersion)) {
return null;
}
return version_compare($requiredVersion, $this->dbVersion, '<=');
}
/**
* Performs the fetch from the Db server and stores the resulting Major.Minor.Version number.
*/
private function fetchDbVersion ()
{
$result = $this->queryOneRow("SELECT VERSION() AS version");
if (!empty($result)) {
$dummy = explode('-', $result['version'], 2);
$this->dbVersion = $dummy[0];
}
}
}