PageRenderTime 27ms CodeModel.GetById 4ms RepoModel.GetById 0ms app.codeStats 0ms

/Helios Engine/helios/ioengines/mysql.php

https://code.google.com/p/prjtest00/
PHP | 306 lines | 221 code | 9 blank | 76 comment | 29 complexity | f90450fcc6dc4c3af32fb87ea3a84701 MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0
  1. <?php
  2. ############################################################################
  3. # Copyright (C) 2007 by Arturo Mann #
  4. # arturo.mann@gmail.com #
  5. # #
  6. # This program is free software; you can redistribute it and#or modify #
  7. # it under the terms of the GNU General Public License as published by #
  8. # the Free Software Foundation; either version 2 of the License, or #
  9. # (at your option) any later version. #
  10. # #
  11. # This program is distributed in the hope that it will be useful, #
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of #
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
  14. # GNU General Public License for more details. #
  15. # #
  16. # You should have received a copy of the GNU General Public License #
  17. # along with this program; if not, write to the #
  18. # Free Software Foundation, Inc., #
  19. # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
  20. ############################################################################
  21. //Helios Engine, IO Engine for MYSQLi
  22. //MySQL IO Engine: plugin for Sakura datachains
  23. // Identification tag:
  24. $engine['name'] = "SakuraSQLCore";
  25. $engine['classname'] = "SakuraSQLCore";
  26. $engine["version"] = "0.1";
  27. $engine["autoload"]= true;
  28. $engine["objectname"] ="SQL";
  29. // End Tag.
  30. class SakuraSQLCore {
  31. // Variable Table
  32. // Version:
  33. private $version = "0.4";
  34. // Logger instance
  35. private $logger = NULL;
  36. // Configuration
  37. private $conf = NULL;
  38. // Publically visible information, for the client to access:
  39. public $config = NULL;
  40. // Query Cache
  41. private $query_cache = NULL;
  42. // Result cache
  43. private $result_cache = NULL;
  44. // MySQL instances array:
  45. private $connections = NULL;
  46. // BEGIN CONSTRUCTOR AND DECONSTRUCTOR
  47. // Intialisation Class: Check environment for the engine, continue loading if valid:
  48. public function __construct() {
  49. $this->conf["features"] = array();
  50. $this->logger = new SakuraLogger;
  51. $siteid = $_SESSION["siteid"];
  52. // Check FIRST that a siteid is set:
  53. if ($siteid > 0) {
  54. $this->logger->WriteLog(error,"SQLCore",$this->version,"E0001","No SiteID Specified.");
  55. trigger_error("SQLCore, E0001: No SiteID Specified.",E_USER_ERROR);
  56. }
  57. $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0001","Initialising...");
  58. // Setup Public conf information
  59. $this->config["version"] = $this->version;
  60. // Prvent connections at this stage.
  61. $this->config["state"] = NOT_READY;
  62. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0002","Got SiteID $siteid");
  63. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0003","Importing Configuration file...");
  64. require "config/config.inc.php";
  65. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0004","Determining Features to load...");
  66. // Transactions are enabled by default, they can be disabled by the functions option..
  67. $this->conf["features"] = array(transaction);
  68. // Quickhack, fix this! (Add load discretion)
  69. if ($cfg["servers"][$id]["mysqlconfig"]["functions"] === all) {
  70. $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0005","Loading ALL feature plugins!");
  71. $this->conf["features"] = array(transaction);
  72. }
  73. $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0006","Initialising Connection(s)..");
  74. $i = 1;
  75. // STAGE 0: connect the Sakura DB
  76. $id = $_SESSION["siteID"];
  77. $database = $cfg["servers"][$id]["sakuradb"];
  78. $this->connections[0] = mysqli_connect($database["host"],$database["username"],$database["password"],$database["database"]);
  79. if (!$this->connections[0]) {
  80. $this->logger->WriteLog(warning,"SQLCore",$this->version,"E0002","ERROR! Connection to SakuraDB failed..");
  81. trigger_error("SQLCore, E0002: Failed to connect to the Sakura DB.",E_USER_ERROR);
  82. }
  83. $this->logger->WriteLog(debug,"SQLCore",$this->version,NULL,"Connection to sakuradb ready..");
  84. $this->conf["pool"][] = array(sakuradb,0);
  85. $this->conf["poolinx"][] = 0;
  86. // STAGE 1: connect all databases to the pool.
  87. // Initialise the Database connections
  88. foreach ($cfg["servers"][$id]["mysqlconfig"]["databases"] as $database) {
  89. $this->connections[$i] = mysqli_connect($database["host"],$database["username"],$database["password"],$database["database"]);
  90. // Catch an error!
  91. if (!$this->connections[$i]) {
  92. $this->logger->WriteLog(warning,"SQLCore",$this->version,"E0003","WARNING! Connection to ".$database["database"]."@".$database["host"]." failed..");
  93. trigger_error("SQLCore, E0002: Failed to connect to a specified Database.",E_USER_WARNING);
  94. // Purely for logging.
  95. $this->conf["connection_error"] = "POOL";
  96. }
  97. // Add connection to the pool list
  98. $this->conf["pool"][] = array($database["database"],$i);
  99. // Index:
  100. $this->conf["poolinx"][] = $i;
  101. $this->logger->WriteLog(debug,"SQLCore",$this->version,NULL,"Connection to ".$database["database"]."@".$database["host"]." ready..");
  102. $i++;
  103. }
  104. // STAGE 2: IF the transactional model is set, remove the AUTOCOMMIT to allow full ACID transactions:
  105. if (in_array(transaction,$this->conf["features"])) {
  106. $this->config["features"][] = TRANSACTION;
  107. // Transactional models involve the utilisation of the cache, to execute all the required queries at once.
  108. $this->conf["cache"] = TRUE;
  109. $this->config["features"][] = CACHE;
  110. $this->config["features"][] = NOAUTO;
  111. $i = 0;
  112. $pool = count($this->conf["pool"]);
  113. do {
  114. mysqli_autocommit($this->connections[$i],FALSE);
  115. $this->logger->WriteLog(debug,"SQLCore",$this->version,NULL,"Autocommit for ".$this->conf["pool"][$i][0]." disabled..");
  116. $i++;
  117. } while ($i < $pool);
  118. }
  119. // Print out a debug report:
  120. if ($this->conf["connection_error"] != "POOL") {
  121. $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0007","Pool connection complete.");
  122. } else {
  123. $count = count($this->conf["pool"]);
  124. if ($count < 0) {
  125. // Woops, POOL IS EMPTY, abort.
  126. $this->logger->WriteLog(error,"SQLCore",$this->version,"E0004","ALL database connections failed, pool is empty. Aborting.");
  127. trigger_error("SQLCore, E0003: All connections failed, Database pool is empty.",E_USER_ERROR);
  128. }
  129. $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0007","Pool connection complete, with warnings.");
  130. }
  131. // Print out POOL to trace logger.
  132. $this->logger->WriteLog(trace,"SQLCore",$this->version,NULL,"*** START POOL LISTING ***");
  133. foreach ($this->conf["pool"] as $pool) {
  134. $this->logger->WriteLog(trace,"SQLCore",$this->version,NULL,"Database: ". $pool[0]."");
  135. }
  136. $this->logger->WriteLog(trace,"SQLCore",$this->version,NULL,"*** END POOL LISTING ***");
  137. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0008","Exporting Database Configuration data and setting engine to READY...");
  138. // Stage 3: Publish pool data for clients.
  139. foreach ($this->conf["pool"] as $pool) {
  140. $this->config["databases"][] = $pool;
  141. }
  142. $this->config["state"] = READY;
  143. $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0009","Init complete.");
  144. // Memory saving
  145. $_SESSION["SakuraSQLCore"] = true;
  146. }
  147. // Shutdown class:
  148. public function __destruct() {
  149. $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0010","Shutting down....");
  150. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0011","Begin SQL shutdown: Rejecting all connections.");
  151. $this->config["state"] = NOT_READY;
  152. // Add a call to flush the cache!
  153. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0012","Closing all pool connections.");
  154. foreach ($this->conf["pool"] as $pool) {
  155. $i = $pool[1];
  156. $n = $pool[0];
  157. if (!mysqli_close($this->connections[$i])) echo "<p> Could not close!</p>\n";
  158. $this->logger->WriteLog(debug,"SQLCore",$this->version,NULL,"Connection to $n closed.");
  159. }
  160. $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0013","SQLCore shutdown complete.");
  161. }
  162. // END CONSTRUCTOR AND DECONSTRUCTOR
  163. // QUERY RECIVING INTERFACE:
  164. public function query($poolid,$mode,$query) {
  165. // If the engine is not properly initialised, just drop the request:
  166. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0014","Getting a query...");
  167. if ($this->config["state"] === NOT_READY) {
  168. $this->logger->WriteLog(error,"SQLCore",$this->version,"E0005","NOT ready to recieve a query.");
  169. return -1;
  170. }
  171. // Check for a valid pool:
  172. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0015","Verifying pool choice...");
  173. if (!in_array($poolid,$this->conf["poolinx"])) {
  174. $this->logger->WriteLog(error,"SQLCore",$this->version,"E0006","Invalid pool selected.");
  175. echo "<p> Bad pool. </p>\n";
  176. echo "<p>Valid Pools:";
  177. print_r($this->conf["pool"]);
  178. echo "</p>\n";
  179. return -2;
  180. }
  181. // Store query in the cache, and mark it as NE
  182. $this->query_cache[] = array($poolid,$query,$mode,NE,NULL);
  183. $id = count($this->query_cache) - 1;
  184. $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0016","The query is now in cache, ready to be executed.");
  185. // Return the query ID.
  186. return $id;
  187. }
  188. // QUERY EXECUTION INTERFACE:
  189. public function execute($queryid,$rtype) {
  190. // Verify to see if query exists!
  191. if (empty($this->query_cache[$queryid])) {
  192. $this->logger->WriteLog(error,"SQLCore",$this->version,"E0007","Invalid query selected.");
  193. return -1;
  194. }
  195. if (($this->query_cache[$queryid][0]) < 0 ) {
  196. $this->logger->WriteLog(error,"SQLCore",$this->version,"E0009","BAD pool!");
  197. echo "<p> Bad pool. </p>\n";
  198. echo "<p>Valid Pools:";
  199. print_r($this->conf["pool"]);
  200. echo "</p>\n";
  201. return -2;
  202. }
  203. // This function makes no sense with transactional models if the query is not of type FE (fetch)...
  204. if ($this->query_cache[$queryid][2] != FE) {
  205. if (in_array(TRANSACTION,$this->config["features"])) {
  206. $this->logger->WriteLog(error,"SQLCore",$this->version,"E0008","execute() makes no sense with Transactions, use transaction()");
  207. return -2;
  208. }
  209. }
  210. // Prepare to execute the query
  211. $poolid = $this->query_cache[$queryid][0];
  212. $query = $this->query_cache[$queryid][1];
  213. // Execute the query.
  214. $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0021","Running query.");
  215. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0021","Running query: ".$query.", QID = ".$queryid.", Pool =".$poolid);
  216. if (!$query = mysqli_query($this->connections[$poolid],$query)) {
  217. $this->logger->WriteLog(error,"SQLCore",$this->version,"E0009","SQL error!");
  218. user_error("SQL Core: MySQL reported an error: ".mysqli_error($this->connections[$poolid]),E_USER_ERROR);
  219. }
  220. // Fetch Result:
  221. if ($this->query_cache[$queryid][2] === FE) {
  222. switch($rtype) {
  223. // Associative array (complete)
  224. case ASSOC:
  225. do {
  226. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0022","Fetching using ASSOC array.");
  227. $result[] = $row;
  228. } while ($row = mysqli_fetch_assoc($query));
  229. break;
  230. // Row:
  231. case ROW:
  232. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0022","Fetching using ROW.");
  233. $result = mysqli_fetch_array($query);
  234. break;
  235. // Simple Array
  236. case AARRAY:
  237. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0022","Fetching using ARRAY.");
  238. do {
  239. $result[] = $row;
  240. } while ($row = mysqli_fetch_array($query));
  241. break;
  242. }
  243. }
  244. // Set query as executed
  245. $this->query_cache[$queryid][4] = EX;
  246. $this->logger->WriteLog(debug,"SQLCore",$this->version,"I0023","Query Executed.");
  247. // Return Data;
  248. if ($this->query_cache[$queryid][2] === FE) {
  249. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0024","Returning result data.");
  250. return $result;
  251. } else {
  252. return 0;
  253. }
  254. }
  255. // Transactions:
  256. public function make_transaction($queryid) {
  257. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0017","Starting Transaction!");
  258. // First, determine if an array is being used:
  259. if (is_array($queryid)) {
  260. $id = $queryid[0];
  261. $poolid = $this->query_cache[$id][0];
  262. // Start execution!
  263. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0018","Multi-query transaction.");
  264. mysqli_query($this->connections[$poolid],"START TRANSACTION");
  265. foreach ($queryid as $queryid) {
  266. $query = $this->query_cache[$queryid][1];
  267. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0019","Initialising Transaction now....");
  268. if (!$queryrx = mysqli_query($this->connections[$poolid],$query)) {
  269. echo "SQL Core: MySQL reported an error: ".mysqli_error($this->connections[$poolid]),E_USER_ERROR;
  270. mysqli_query($this->connections[$poolid],"ROLLBACK;");
  271. echo "\nSQL Core: Cleanup crew! ROLLBACK transaction and BAIL!!\n";
  272. $this->logger->WriteLog(error,"SQLCore",$this->version,"E0009","SQL error: ".mysqli_error($this->connections[$poolid])."!! ROLLBACK AND BAIL!");
  273. mysqli_close($this->connections[$poolid]);
  274. }}
  275. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0020","Committing Transactions!");
  276. mysqli_query($this->connections[$poolid],"COMMIT");
  277. } else {
  278. // Single query mode.
  279. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0018","One-shot transaction.");
  280. // Begin transaction!
  281. $poolid = $this->query_cache[$queryid][0];
  282. $query = $this->query_cache[$queryid][1];
  283. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0019","Initialising Transaction now....");
  284. mysqli_query($this->connections[$poolid],"START TRANSACTION");
  285. $this->logger->WriteLog(trace,"SQLCore",$this->version,"I0020","Committing Transaction!");
  286. if (!$queryrx = mysqli_query($this->connections[$poolid],$query)) {
  287. mysqli_query($this->connections[$poolid],"ROLLBACK;");
  288. echo "\nSQL Core: Cleanup crew! ROLLBACK transaction and BAIL!!\n";
  289. $this->logger->WriteLog(error,"SQLCore",$this->version,"E0009","SQL error: ".mysqli_error($this->connections[$poolid])."!! ROLLBACK AND BAIL!");
  290. mysqli_close($this->connections[$poolid]);
  291. user_error("SQL Core: MySQL reported an error: ".mysqli_error($this->connections[$poolid]),E_USER_ERROR);
  292. return -2;
  293. }
  294. mysqli_query($this->connections[$poolid],"COMMIT");
  295. return 0;
  296. }}
  297. }