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