/Helios Engine/helios/ioengines/mysql.php
PHP | 306 lines | 221 code | 9 blank | 76 comment | 29 complexity | f90450fcc6dc4c3af32fb87ea3a84701 MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0
- <?php
- ############################################################################
- # Copyright (C) 2007 by Arturo Mann #
- # arturo.mann@gmail.com #
- # #
- # This program is free software; you can redistribute it and#or modify #
- # it under the terms of the GNU General Public License as published by #
- # the Free Software Foundation; either version 2 of the License, or #
- # (at your option) any later version. #
- # #
- # This program is distributed in the hope that it will be useful, #
- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
- # GNU General Public License for more details. #
- # #
- # You should have received a copy of the GNU General Public License #
- # along with this program; if not, write to the #
- # Free Software Foundation, Inc., #
- # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
- ############################################################################
- //Helios Engine, IO Engine for MYSQLi
- //MySQL IO Engine: plugin for Sakura datachains
- // Identification tag:
- $engine['name'] = "SakuraSQLCore";
- $engine['classname'] = "SakuraSQLCore";
- $engine["version"] = "0.1";
- $engine["autoload"]= true;
- $engine["objectname"] ="SQL";
- // End Tag.
- class SakuraSQLCore {
- // Variable Table
- // Version:
- private $version = "0.4";
- // Logger instance
- private $logger = NULL;
- // Configuration
- private $conf = NULL;
- // Publically visible information, for the client to access:
- public $config = NULL;
- // Query Cache
- private $query_cache = NULL;
- // Result cache
- private $result_cache = NULL;
- // MySQL instances array:
- private $connections = NULL;
- // BEGIN CONSTRUCTOR AND DECONSTRUCTOR
- // Intialisation Class: Check environment for the engine, continue loading if valid:
- public function __construct() {
- $this->conf["features"] = array();
- $this->logger = new SakuraLogger;
- $siteid = $_SESSION["siteid"];
- // Check FIRST that a siteid is set:
- if ($siteid > 0) {
- $this->logger->WriteLog(error,"SQLCore",$this->version,"E0001","No SiteID Specified.");
- trigger_error("SQLCore, E0001: No SiteID Specified.",E_USER_ERROR);
- }
- $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0001","Initialising...");
- // Setup Public conf information
- $this->config["version"] = $this->version;
- // Prvent connections at this stage.
- $this->config["state"] = NOT_READY;
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0002","Got SiteID $siteid");
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0003","Importing Configuration file...");
- require "config/config.inc.php";
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0004","Determining Features to load...");
- // Transactions are enabled by default, they can be disabled by the functions option..
- $this->conf["features"] = array(transaction);
- // Quickhack, fix this! (Add load discretion)
- if ($cfg["servers"][$id]["mysqlconfig"]["functions"] === all) {
- $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0005","Loading ALL feature plugins!");
- $this->conf["features"] = array(transaction);
- }
- $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0006","Initialising Connection(s)..");
- $i = 1;
- // STAGE 0: connect the Sakura DB
- $id = $_SESSION["siteID"];
- $database = $cfg["servers"][$id]["sakuradb"];
- $this->connections[0] = mysqli_connect($database["host"],$database["username"],$database["password"],$database["database"]);
- if (!$this->connections[0]) {
- $this->logger->WriteLog(warning,"SQLCore",$this->version,"E0002","ERROR! Connection to SakuraDB failed..");
- trigger_error("SQLCore, E0002: Failed to connect to the Sakura DB.",E_USER_ERROR);
- }
- $this->logger->WriteLog(debug,"SQLCore",$this->version,NULL,"Connection to sakuradb ready..");
- $this->conf["pool"][] = array(sakuradb,0);
- $this->conf["poolinx"][] = 0;
- // STAGE 1: connect all databases to the pool.
- // Initialise the Database connections
- foreach ($cfg["servers"][$id]["mysqlconfig"]["databases"] as $database) {
- $this->connections[$i] = mysqli_connect($database["host"],$database["username"],$database["password"],$database["database"]);
- // Catch an error!
- if (!$this->connections[$i]) {
- $this->logger->WriteLog(warning,"SQLCore",$this->version,"E0003","WARNING! Connection to ".$database["database"]."@".$database["host"]." failed..");
- trigger_error("SQLCore, E0002: Failed to connect to a specified Database.",E_USER_WARNING);
- // Purely for logging.
- $this->conf["connection_error"] = "POOL";
- }
- // Add connection to the pool list
- $this->conf["pool"][] = array($database["database"],$i);
- // Index:
- $this->conf["poolinx"][] = $i;
- $this->logger->WriteLog(debug,"SQLCore",$this->version,NULL,"Connection to ".$database["database"]."@".$database["host"]." ready..");
- $i++;
- }
- // STAGE 2: IF the transactional model is set, remove the AUTOCOMMIT to allow full ACID transactions:
- if (in_array(transaction,$this->conf["features"])) {
- $this->config["features"][] = TRANSACTION;
- // Transactional models involve the utilisation of the cache, to execute all the required queries at once.
- $this->conf["cache"] = TRUE;
- $this->config["features"][] = CACHE;
- $this->config["features"][] = NOAUTO;
- $i = 0;
- $pool = count($this->conf["pool"]);
- do {
- mysqli_autocommit($this->connections[$i],FALSE);
- $this->logger->WriteLog(debug,"SQLCore",$this->version,NULL,"Autocommit for ".$this->conf["pool"][$i][0]." disabled..");
- $i++;
- } while ($i < $pool);
- }
- // Print out a debug report:
- if ($this->conf["connection_error"] != "POOL") {
- $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0007","Pool connection complete.");
- } else {
- $count = count($this->conf["pool"]);
- if ($count < 0) {
- // Woops, POOL IS EMPTY, abort.
- $this->logger->WriteLog(error,"SQLCore",$this->version,"E0004","ALL database connections failed, pool is empty. Aborting.");
- trigger_error("SQLCore, E0003: All connections failed, Database pool is empty.",E_USER_ERROR);
- }
- $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0007","Pool connection complete, with warnings.");
- }
- // Print out POOL to trace logger.
- $this->logger->WriteLog(trace,"SQLCore",$this->version,NULL,"*** START POOL LISTING ***");
- foreach ($this->conf["pool"] as $pool) {
- $this->logger->WriteLog(trace,"SQLCore",$this->version,NULL,"Database: ". $pool[0]."");
- }
- $this->logger->WriteLog(trace,"SQLCore",$this->version,NULL,"*** END POOL LISTING ***");
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0008","Exporting Database Configuration data and setting engine to READY...");
- // Stage 3: Publish pool data for clients.
- foreach ($this->conf["pool"] as $pool) {
- $this->config["databases"][] = $pool;
- }
- $this->config["state"] = READY;
- $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0009","Init complete.");
- // Memory saving
- $_SESSION["SakuraSQLCore"] = true;
- }
- // Shutdown class:
- public function __destruct() {
- $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0010","Shutting down....");
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0011","Begin SQL shutdown: Rejecting all connections.");
- $this->config["state"] = NOT_READY;
- // Add a call to flush the cache!
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0012","Closing all pool connections.");
- foreach ($this->conf["pool"] as $pool) {
- $i = $pool[1];
- $n = $pool[0];
- if (!mysqli_close($this->connections[$i])) echo "<p> Could not close!</p>\n";
- $this->logger->WriteLog(debug,"SQLCore",$this->version,NULL,"Connection to $n closed.");
- }
- $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0013","SQLCore shutdown complete.");
- }
- // END CONSTRUCTOR AND DECONSTRUCTOR
- // QUERY RECIVING INTERFACE:
- public function query($poolid,$mode,$query) {
- // If the engine is not properly initialised, just drop the request:
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0014","Getting a query...");
- if ($this->config["state"] === NOT_READY) {
- $this->logger->WriteLog(error,"SQLCore",$this->version,"E0005","NOT ready to recieve a query.");
- return -1;
- }
- // Check for a valid pool:
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0015","Verifying pool choice...");
- if (!in_array($poolid,$this->conf["poolinx"])) {
- $this->logger->WriteLog(error,"SQLCore",$this->version,"E0006","Invalid pool selected.");
- echo "<p> Bad pool. </p>\n";
- echo "<p>Valid Pools:";
- print_r($this->conf["pool"]);
- echo "</p>\n";
- return -2;
- }
- // Store query in the cache, and mark it as NE
- $this->query_cache[] = array($poolid,$query,$mode,NE,NULL);
- $id = count($this->query_cache) - 1;
- $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0016","The query is now in cache, ready to be executed.");
- // Return the query ID.
- return $id;
- }
- // QUERY EXECUTION INTERFACE:
- public function execute($queryid,$rtype) {
- // Verify to see if query exists!
- if (empty($this->query_cache[$queryid])) {
- $this->logger->WriteLog(error,"SQLCore",$this->version,"E0007","Invalid query selected.");
- return -1;
- }
- if (($this->query_cache[$queryid][0]) < 0 ) {
- $this->logger->WriteLog(error,"SQLCore",$this->version,"E0009","BAD pool!");
- echo "<p> Bad pool. </p>\n";
- echo "<p>Valid Pools:";
- print_r($this->conf["pool"]);
- echo "</p>\n";
- return -2;
- }
- // This function makes no sense with transactional models if the query is not of type FE (fetch)...
- if ($this->query_cache[$queryid][2] != FE) {
- if (in_array(TRANSACTION,$this->config["features"])) {
- $this->logger->WriteLog(error,"SQLCore",$this->version,"E0008","execute() makes no sense with Transactions, use transaction()");
- return -2;
- }
- }
- // Prepare to execute the query
- $poolid = $this->query_cache[$queryid][0];
- $query = $this->query_cache[$queryid][1];
- // Execute the query.
- $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0021","Running query.");
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0021","Running query: ".$query.", QID = ".$queryid.", Pool =".$poolid);
- if (!$query = mysqli_query($this->connections[$poolid],$query)) {
- $this->logger->WriteLog(error,"SQLCore",$this->version,"E0009","SQL error!");
- user_error("SQL Core: MySQL reported an error: ".mysqli_error($this->connections[$poolid]),E_USER_ERROR);
- }
-
- // Fetch Result:
- if ($this->query_cache[$queryid][2] === FE) {
- switch($rtype) {
- // Associative array (complete)
- case ASSOC:
- do {
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0022","Fetching using ASSOC array.");
- $result[] = $row;
- } while ($row = mysqli_fetch_assoc($query));
- break;
- // Row:
- case ROW:
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0022","Fetching using ROW.");
- $result = mysqli_fetch_array($query);
- break;
- // Simple Array
- case AARRAY:
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0022","Fetching using ARRAY.");
- do {
- $result[] = $row;
- } while ($row = mysqli_fetch_array($query));
- break;
- }
- }
- // Set query as executed
- $this->query_cache[$queryid][4] = EX;
- $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0023","Query Executed.");
- // Return Data;
- if ($this->query_cache[$queryid][2] === FE) {
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0024","Returning result data.");
- return $result;
- } else {
- return 0;
- }
- }
- // Transactions:
- public function make_transaction($queryid) {
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0017","Starting Transaction!");
- // First, determine if an array is being used:
- if (is_array($queryid)) {
- $id = $queryid[0];
- $poolid = $this->query_cache[$id][0];
- // Start execution!
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0018","Multi-query transaction.");
- mysqli_query($this->connections[$poolid],"START TRANSACTION");
- foreach ($queryid as $queryid) {
- $query = $this->query_cache[$queryid][1];
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0019","Initialising Transaction now....");
- if (!$queryrx = mysqli_query($this->connections[$poolid],$query)) {
- echo "SQL Core: MySQL reported an error: ".mysqli_error($this->connections[$poolid]),E_USER_ERROR;
- mysqli_query($this->connections[$poolid],"ROLLBACK;");
- echo "\nSQL Core: Cleanup crew! ROLLBACK transaction and BAIL!!\n";
- $this->logger->WriteLog(error,"SQLCore",$this->version,"E0009","SQL error: ".mysqli_error($this->connections[$poolid])."!! ROLLBACK AND BAIL!");
- mysqli_close($this->connections[$poolid]);
- }}
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0020","Committing Transactions!");
- mysqli_query($this->connections[$poolid],"COMMIT");
- } else {
- // Single query mode.
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0018","One-shot transaction.");
- // Begin transaction!
- $poolid = $this->query_cache[$queryid][0];
- $query = $this->query_cache[$queryid][1];
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0019","Initialising Transaction now....");
- mysqli_query($this->connections[$poolid],"START TRANSACTION");
- $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0020","Committing Transaction!");
- if (!$queryrx = mysqli_query($this->connections[$poolid],$query)) {
- mysqli_query($this->connections[$poolid],"ROLLBACK;");
- echo "\nSQL Core: Cleanup crew! ROLLBACK transaction and BAIL!!\n";
- $this->logger->WriteLog(error,"SQLCore",$this->version,"E0009","SQL error: ".mysqli_error($this->connections[$poolid])."!! ROLLBACK AND BAIL!");
- mysqli_close($this->connections[$poolid]);
- user_error("SQL Core: MySQL reported an error: ".mysqli_error($this->connections[$poolid]),E_USER_ERROR);
- return -2;
- }
- mysqli_query($this->connections[$poolid],"COMMIT");
- return 0;
- }}
- }