Files
luos/thirdparty/creole/contrib/DBArrayConnection.php

681 lines
22 KiB
PHP

<?php
require_once 'creole/Connection.php';
require_once 'creole/common/ConnectionCommon.php';
require_once 'creole/PreparedStatement.php';
require_once 'creole/common/PreparedStatementCommon.php';
require_once 'creole/ResultSet.php';
require_once 'creole/common/ResultSetCommon.php';
class DBArrayPreparedStatement extends PreparedStatementCommon implements PreparedStatement
{
/**
* Quotes string using native mysql function (mysqli_real_escape_string()).
* @param string $str
* @return string
*/
protected function escape($str)
{
return $str;
}
private function prepareStatement($sql)
{
return $sql;
}
}
class DBArrayResultSet extends ResultSetCommon implements ResultSet
{
public $dbArray = null;
public function seek($rownum)
{
$this->cursorPos = $rownum;
return true;
}
/**
* @see ResultSet::next()
*/
public function next()
{
if ($this->cursorPos == 0) {
$this->cursorPos++;
}
if ($this->cursorPos >= count($this->dbArray)) {
$this->fields = null;
return false;
} else {
$this->fields = $this->dbArray[$this->cursorPos];
$this->cursorPos++;
return true;
}
return true;
}
/**
* @see ResultSet::getRecordCount()
*/
public function getRecordCount()
{
return (int)count($this->dbArray) - 1;
}
/**
* @see ResultSet::close()
*/
public function close()
{
if (is_resource($this->result)) {
mysqli_free_result($this->result);
}
$this->fields = array();
}
/**
* Get string version of column.
* No rtrim() necessary for MySQL, as this happens natively.
* @see ResultSet::getString()
*/
public function getString($column)
{
$idx = (is_int($column) ? $column - 1 : $column);
if (is_array($this->fields) && !array_key_exists($idx, $this->fields)) {
throw new SQLException("Invalid resultset column: " . $column);
}
if ($this->fields[$idx] === null) {
return null;
}
return (string)$this->fields[$idx];
}
}
/**
* DBArray implementation of Connection.
*
*/
class DBArrayConnection implements Connection
{
/** @var Connection */
private $childConnection = null;
/** @var int */
private $numQueriesExecuted = 0;
/** @var string */
private $lastExecutedQuery = '';
/**
* @var object Instance of PEAR Log (or other class with log() method).
*/
private $logger;
private $_DBArray;
public $dataSql;
/**
* Sets a Logger class (e.g. PEAR Log) to use for logging.
* The logger class must have a log() method. All messages are logged at default log level.
* @param object $logger
*/
public function setLogger($logger)
{
krumo('DBArrayConnection setLogger ');
die;
$this->logger = $logger;
}
/**
* connect()
*/
public function connect($dsninfo, $flags = 0)
{
if (!($driver = Creole::getDriver($dsninfo['phptype']))) {
throw new SQLException("No driver has been registered to handle connection type: $type");
}
global $_DBArray;
if ((!isset($_DBArray)) && (isset($_SESSION['_DBArray']))) {
//throw new SQLException("No Database Array defined for this connection but exists in session");
//Added by JHL to avoid errors trying to execute query of a dbarray on June 25, 2011
$_DBArray = $_SESSION['_DBArray'];
}
if (!isset($_DBArray)) {
throw new SQLException("No Database Array defined for this connection");
}
$this->_DBArray = $_DBArray;
return true;
}
/**
* @see Connection::getDatabaseInfo()
*/
public function getDatabaseInfo()
{
krumo('DBArrayConnection getDatabaseInfo ');
die;
return $this->childConnection->getDatabaseInfo();
}
/**
* @see Connection::getIdGenerator()
*/
public function getIdGenerator()
{
krumo('DBArrayConnection getIdGenerator ');
die;
return $this->childConnection->getIdGenerator();
}
/**
* @see Connection::isConnected()
*/
public function isConnected()
{
return true;
krumo('DBArrayConnection isConnected ');
die;
return $this->childConnection->isConnected();
}
/**
* @see Connection::prepareStatement()
*/
public function prepareStatement($dataSql)
{
$this->dataSql = $dataSql;
return new DBArrayPreparedStatement($this, $this->dataSql);
}
/**
* @see Connection::createStatement()
*/
public function createStatement()
{
return new DBArrayPreparedStatement($this, null);
return new DBArrayPreparedStatement($this, $dataSql['sql']);
krumo('DBArrayConnection createStatement ');
die;
$obj = $this->childConnection->createStatement();
$objClass = get_class($obj);
return new $objClass($this);
}
/**
* @see Connection::applyLimit()
*/
public function applyLimit(&$sql, $offset, $limit)
{
krumo('DBArrayConnection applyLimit ');
die;
$this->log("applyLimit(): $sql, offset: $offset, limit: $limit");
return $this->childConnection->applyLimit($sql, $offset, $limit);
}
/**
* @see Connection::close()
*/
public function close()
{
krumo('DBArrayConnection connect ');
die;
$this->log("close(): Closing connection.");
return $this->childConnection->close();
}
/**
* Evaluate Clause
* @param type $clause
* @return type
*/
public function evaluateClause($clause)
{
$sqlStr = $clause;
$sqlStr = str_replace(array('\\\'', '\\"', "\r\n", "\n", "()"), array("''", '""', " ", " ", " "), $sqlStr);
$regex = "/((?:)[@A-Za-z0-9_.-]+(?:\(\s*\)){0,1})"
. "|(\+|-|\*|\/|!=|>=|<=|<>|>|<|&&|\|\||=|\^)"
. "|(\(.*?\))"
. "|('(?:[^']|'')*'+)"
. "|(\"(?:[^\"]|\"\")*\"+)"
. "|([^ ,]+)"
. "/ix";
$tokens = preg_split($regex, $sqlStr, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
return $tokens;
}
/**
* Evaluate Clause Where
* @param type $clauseWhere
* @return type
*/
public function evaluateClauseWhere($clauseWhere)
{
$aOperator = array("=", "!=", "<>", ">", "<", ">=", "<=", "LIKE", "AND", "OR", "NOT", "IN");
$evalClause = $this->evaluateClause($clauseWhere);
$pos = 0;
foreach ($evalClause as $key => $value) {
$value = strtoupper(trim($value));
$sSelect = strtoupper($this->dataSql['selectClause'][0]);
if (stripos($sSelect, $value) !== false) {
$evalClause[$key] = "\$row['" . $evalClause[$key] . "']";
}
if (in_array($value, $aOperator)) {
switch ($value) {
case "=":
$evalClause[$key] = "==";
break;
case "<>":
$evalClause[$key] = "!=";
break;
case "AND":
$evalClause[$key] = "&&";
break;
case "OR":
$evalClause[$key] = "||";
break;
case "NOT":
$evalClause[$key] = "!";
break;
case "LIKE":
$evalClause[$key] = ", ";
if (trim($evalClause[$key - 1]) !== "") {
$evalClause[$key - 1] = " stripos(" . $evalClause[$key - 1];
} else {
if (trim($evalClause[$key - 2]) !== "") {
$evalClause[$key - 2] = " stripos(" . $evalClause[$key - 2];
}
}
if (trim($evalClause[$key + 1]) !== "") {
$evalClause[$key + 1] = str_replace("%", "", $evalClause[$key + 1]);
$evalClause[$key + 1] = $evalClause[$key + 1] . ") !== false";
} else {
if (trim($evalClause[$key + 2]) !== "") {
$evalClause[$key + 2] = str_replace("%", "", $evalClause[$key + 2]);
$evalClause[$key + 2] = $evalClause[$key + 2] . ") !== false";
}
}
break;
}
}
}
$$sEvalClause = implode("", $evalClause);
return $$sEvalClause;
}
private function parseSqlString($query)
{
//we need a SQL parse, for now we only search for text 'select * from'
/* $aux = str_ireplace ( 'select * from', '', trim($query) );
$sql = array();
$sql['fromClause'][0] = trim( $aux );
$sql['limit'] = 0;
$sql['offset'] = 0; */
// if (1 === preg_match('/^\s*SELECT\s+(.+?)(?:\s+FROM\s+(.+?))(?:\s+WHERE\s+(.+?))?(?:\s+GROUP\s+BY\s+(.+?))?(?:\s+ORDER\s+BY\s+(.+?))?(?:\s+BETWEEN\s+(.+?)\s+AND\s+(.+?))?\s*$/im', $query, $matches)) {
if (1 === preg_match('/^\s*SELECT\s+([\w\W]+?)(?:\s+FROM\s+`?([^`]+?)`?)(?:\s+WHERE\s+([\w\W]+?))?(?:\s+GROUP\s+BY\s+([\w\W]+?))?(?:\s+ORDER\s+BY\s+([\w\W]+?))?(?:\s+BETWEEN\s+([\w\W]+?)\s+AND\s+([\w\W]+?))?(?:\s+LIMIT\s+(\d+)\s*,\s*(\d+))?\s*$/im', $query, $matches)) {
//$sqlSelect='SELECT '.$matches[1].(($matches[2]!='')?' FROM '.$matches[2]:'');
} else {
return;
}
$sql = array();
$sql['selectClause'][0] = isset($matches[1]) ? $matches[1] : '';//Include selectClause. By JHL
$sql['fromClause'][0] = isset($matches[2]) ? $matches[2] : '';
//$sql['whereClause'][0] = isset($matches[3]) ? $matches[3] : '';
if (isset($matches[3])) {
$sql['whereClause'][0] = $matches[3];
}
if (isset($matches[4])) {
$sql['groupByClause'][0] = $matches[4];
}
if (isset($matches[5])) {
$sql['orderByClause'][0] = $matches[5];
}
$sql['limit'] = 0;
$sql['offset'] = 0;
return $sql;
}
/**
* @see Connection::executeQuery()
*/
public function executeQuery($sql, $fetchmode = null)
{
if (!is_array($sql) && strlen($sql) > 1) {
$this->dataSql = $sql = $this->parseSqlString($sql);
}
$resultSet = new DBArrayResultSet($this, $sql, $fetchmode);
$tableName = $sql['fromClause'][0];
//the table doesnt exists
if (!isset($this->_DBArray[$tableName])) {
$resultSet->dbArray = array();
return $resultSet;
}
foreach ($this->_DBArray[$tableName] as $key => $row) {
if ($key == 0) {
continue;
}
$flag = 1;
if (isset($sql['whereClause'])) {//If there is no where then return the row
foreach ($sql['whereClause'] as $keyClause => $valClause) {
if (isset($valClause) && $flag == 1) {
//$toEval = "\$flag = ( " . ($valClause != '' ? str_replace('=', '==', $valClause): '1') . ') ?1 :0;' ;
//if the eval is EQUAL add a double Equal
if (strpos($valClause, "\$row['*'] CUSTOM'(") !== false) {
$valClause = str_replace("\$row['*'] CUSTOM'(", '', $valClause);
$words = explode(' ', $valClause);
$valClause = str_replace($words[0], "\$row['" . $words[0] . "']", $valClause);
$valClause = str_replace(")'", "", $valClause);
}
if (stripos($valClause, "\$row[") !== false) {
if (stripos($valClause, "LIKE") !== false) {
$valClause = str_replace("%", "", $valClause);
$operands = explode('LIKE', $valClause);
if ($operands[1] == ' ""') {
$toEval = "\$flag = 1;";
} else {
$toEval = "\$flag = ( stripos ( " . $operands[0] . ", " . $operands[1] . " ) !== false ? 1 : 0 ) ;";
eval($toEval);
eval('$val = ' . $operands[0] . ';');
}
} else {//this is for EQUAL, LESS_THAN_EQUAL, ETC,
$toEval = "\$flag = ( " . ($valClause != '' ? $valClause : '1') . ') ?1 :0;';
}
} else {
$valClause = $this->evaluateClauseWhere($valClause);
$toEval = "\$flag = ( " . ($valClause != '' ? $valClause : '1') . ') ?1 :0;';
}
eval($toEval);
}
}
} else {
}
if ($flag) {
$resultRow[] = $row;
}
}
if ($this->dataSql['selectClause'][0] == 'COUNT(*)') {
$rows[] = array('1' => 'integer');
if (isset($resultRow) && is_array($resultRow)) {
$rows[] = array('1' => count($resultRow));
} else {
$rows[] = array('1' => 0);
}
$resultSet->dbArray = $rows;
return $resultSet;
}
if (!isset($resultRow)) {
$resultSet->dbArray = array();
return $resultSet;
}
if (isset($this->dataSql['orderByClause']) && is_array($this->dataSql['orderByClause']) && count($this->dataSql['orderByClause']) > 0) {
foreach ($resultRow as $key => $row) {
foreach ($this->dataSql['orderByClause'] as $keyOrder => $valOrder) {
if (isset($row[$valOrder['columnName']])) {
$column[$valOrder['columnName']][$key] = strtoupper($row[$valOrder['columnName']]);
} else {
$column[$valOrder['columnName']][$key] = '';
}
}
}
foreach ($this->dataSql['orderByClause'] as $keyOrder => $valOrder) {
$direction[$keyOrder] = (trim($valOrder['direction']) != 'ASC') ? SORT_DESC : SORT_ASC;
}
$aOrderClause = $this->dataSql['orderByClause'];
switch (count($column)) {
case 1:
array_multisort($column[$aOrderClause[0]['columnName']], $direction[0], $resultRow);
break;
case 2:
array_multisort(
$column[$aOrderClause[0]['columnName']],
$direction[0],
$column[$aOrderClause[1]['columnName']],
$direction[1],
$resultRow
);
break;
case 3:
array_multisort(
$column[$aOrderClause[0]['columnName']],
$direction[0],
$column[$aOrderClause[1]['columnName']],
$direction[1],
$column[$aOrderClause[2]['columnName']],
$direction[2],
$resultRow
);
break;
case 4:
array_multisort(
$column[$aOrderClause[0]['columnName']],
$direction[0],
$column[$aOrderClause[1]['columnName']],
$direction[1],
$column[$aOrderClause[2]['columnName']],
$direction[2],
$column[$aOrderClause[3]['columnName']],
$direction[3],
$resultRow
);
break;
case 5:
array_multisort(
$column[$aOrderClause[0]['columnName']],
$direction[0],
$column[$aOrderClause[1]['columnName']],
$direction[1],
$column[$aOrderClause[2]['columnName']],
$direction[2],
$column[$aOrderClause[3]['columnName']],
$direction[3],
$column[$aOrderClause[4]['columnName']],
$direction[4],
$resultRow
);
break;
case 6:
array_multisort(
$column[$aOrderClause[0]['columnName']],
$direction[0],
$column[$aOrderClause[1]['columnName']],
$direction[1],
$column[$aOrderClause[2]['columnName']],
$direction[2],
$column[$aOrderClause[3]['columnName']],
$direction[3],
$column[$aOrderClause[4]['columnName']],
$direction[4],
$column[$aOrderClause[5]['columnName']],
$direction[5],
$resultRow
);
break;
case 7:
array_multisort(
$column[$aOrderClause[0]['columnName']],
$direction[0],
$column[$aOrderClause[1]['columnName']],
$direction[1],
$column[$aOrderClause[2]['columnName']],
$direction[2],
$column[$aOrderClause[3]['columnName']],
$direction[3],
$column[$aOrderClause[4]['columnName']],
$direction[4],
$column[$aOrderClause[5]['columnName']],
$direction[5],
$column[$aOrderClause[6]['columnName']],
$direction[6],
$resultRow
);
break;
}
}
/**
* Prepend the headers in the resultRow.
* If the null value is not taken, $resultRow will lose an element.
*/
$header = null;
if (isset($this->_DBArray[$tableName][0])) {
$header = $this->_DBArray[$tableName][0];
}
array_unshift($resultRow, $header);
/*
* Apply Limit and Offset
*/
if ($sql['limit'] > 0) {
$header = $resultRow[0];
$resultRow = array_slice($resultRow, $sql['offset'] + 1, $sql['limit']);
array_unshift($resultRow, $header);
} else {
$header = $resultRow[0];
$resultRow = array_slice($resultRow, $sql['offset'] + 1);
array_unshift($resultRow, $header);
}
$resultSet->dbArray = $resultRow;
return $resultSet;
}
/**
* @see Connection::executeUpdate()
*/
public function executeUpdate($sql)
{
krumo('DBArrayConnection executeUpdate ');
die;
$this->log("executeUpdate(): $sql");
$this->lastExecutedQuery = $sql;
$this->numQueriesExecuted++;
return $this->childConnection->executeUpdate($sql);
}
/**
* @see Connection::getUpdateCount()
*/
public function getUpdateCount()
{
krumo('DBArrayConnection getUpdateCount ');
die;
return $this->childConnection->getUpdateCount();
}
/**
* @see Connection::prepareCall()
* */
public function prepareCall($sql)
{
krumo('DBArrayConnection prepareCall ');
die;
$this->log("prepareCall(): $sql");
return $this->childConnection->prepareCall($sql);
}
/**
* @see Connection::getResource()
*/
public function getResource()
{
krumo('DBArrayConnection getResource ');
die;
return $this->childConnection->getResource();
}
/**
* @see Connection::connect()
*/
public function getDSN()
{
krumo('DBArrayConnection getDSN ');
die;
return $this->childConnection->getDSN();
}
/**
* @see Connection::getFlags()
*/
public function getFlags()
{
return;
}
/**
* @see Connection::begin()
*/
public function begin()
{
krumo('DBArrayConnection begin ');
die;
$this->log("Beginning transaction.");
return $this->childConnection->begin();
}
/**
* @see Connection::commit()
*/
public function commit()
{
krumo('DBArrayConnection commit ');
die;
$this->log("Committing transaction.");
return $this->childConnection->commit();
}
/**
* @see Connection::rollback()
*/
public function rollback()
{
krumo('DBArrayConnection rollback ');
die;
$this->log("Rolling back transaction.");
return $this->childConnection->rollback();
}
/**
* @see Connection::setAutoCommit()
*/
public function setAutoCommit($bit)
{
krumo('DBArrayConnection connect ');
die;
$this->log("Setting autocommit to: " . var_export($bit, true));
return $this->childConnection->setAutoCommit($bit);
}
/**
* @see Connection::getAutoCommit()
*/
public function getAutoCommit()
{
krumo('DBArrayConnection getAutoCommit ');
die;
return $this->childConnection->getAutoCommit();
}
/**
* Private function that logs message using specified logger (if provided).
* @param string $msg Message to log.
*/
private function log($msg)
{
krumo('DBArrayConnection log ');
die;
if ($this->logger) {
$this->logger->log($msg);
}
}
}