PageRenderTime 75ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/oc-includes/osclass/db.php

https://github.com/hashemgamal/OSClass
PHP | 498 lines | 395 code | 44 blank | 59 comment | 63 complexity | 0f4102bb3e430653a1aa3b2fcafd8f6e MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, GPL-2.0
  1. <?php
  2. /*
  3. * OSCLass – software for creating and publishing online classified
  4. * advertising platforms
  5. *
  6. * Copyright (C) 2010 OSCLASS
  7. *
  8. * This program is free software: you can redistribute it and/or
  9. * modify it under the terms of the GNU Affero General Public License
  10. * as published by the Free Software Foundation, either version 3 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Affero General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public
  19. * License along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. /** Defines for DB error reporting */
  22. define('LOG_NONE', 0) ;
  23. define('LOG_WEB', 1) ;
  24. define('LOG_COMMENT', 2) ;
  25. define('DEBUG_LEVEL', LOG_NONE) ;
  26. class DB
  27. {
  28. private $db = null ;
  29. private $db_errno = 0;
  30. private $db_error = 0;
  31. private $dbHost = null ;
  32. private $dbUser = null ;
  33. private $dbPassword = null ;
  34. private $dbName = null ;
  35. private $dbLogLevel = null ;
  36. private $msg = "" ;
  37. function __construct($dbHost, $dbUser, $dbPassword, $dbName, $dbLogLevel) {
  38. $this->dbHost = $dbHost ;
  39. $this->dbUser = $dbUser ;
  40. $this->dbPassword = $dbPassword ;
  41. $this->dbName = $dbName ;
  42. $this->dbLogLevel = $dbLogLevel ;
  43. $this->db_errno = 0;
  44. $this->osc_dbConnect() ;
  45. }
  46. function __destruct() {
  47. $this->osc_dbClose() ;
  48. }
  49. //logging
  50. function debug($msg, $ok = true)
  51. {
  52. if($this->dbLogLevel != LOG_NONE) {
  53. $this->msg .= date("d/m/Y - H:i:s") . " " ;
  54. if($this->dbLogLevel == LOG_WEB) {
  55. if ($ok) $this->msg .= "<span style='background-color: #D0F5A9;' >[ OPERATION OK ] " ;
  56. else $this->msg .= "<span style='background-color: #F5A9A9;' >[ OPERATION FAILED ] " ;
  57. }
  58. $this->msg .= str_replace("\n", " ", $msg) ;
  59. if($this->dbLogLevel == LOG_WEB) { $this->msg .= '</span><br />' ; }
  60. $this->msg .= "\n" ;
  61. }
  62. }
  63. function print_debug() {
  64. switch($this->dbLogLevel) {
  65. case(LOG_WEB):
  66. if(!defined('IS_AJAX')) {
  67. echo $this->msg ;
  68. }
  69. break;
  70. case(LOG_COMMENT): echo '<!-- ' . $this->msg . ' -->' ;
  71. break;
  72. }
  73. }
  74. /**
  75. * Establish a connection to the MySQL database.
  76. *
  77. * @param string server ip or name
  78. * @param string database user
  79. * @param string database password
  80. * @param string datatabase name
  81. */
  82. function osc_dbConnect() {
  83. //echo "#" , $this->dbHost, $this->dbUser, $this->dbPassword, $this->dbName ;
  84. $this->db = new mysqli($this->dbHost, $this->dbUser, $this->dbPassword, $this->dbName);
  85. if ($this->db->connect_error) {
  86. $this->debug('Error connecting to \'' . $this->dbName . '\' (' . $this->db->connect_errno . ': ' . $this->db->connect_error . ')', false) ;
  87. }
  88. $this->db_errno = $this->db->connect_errno;
  89. $this->debug('Connected to \'' . $this->dbName . '\': [DBHOST] = ' . $this->dbHost . ' | [DBUSER] = ' . $this->dbUser) ;
  90. $this->db->set_charset('utf8') ;
  91. }
  92. /**
  93. * Close the database connection.
  94. */
  95. function osc_dbClose() {
  96. if (!$this->db->close()) {
  97. $this->debug('Error releasing the connection to \'' . $this->dbName . '\'', false) ;
  98. }
  99. $this->debug('Connection with \'' . $this->dbName . '\' released properly') ;
  100. $this->print_debug() ;
  101. }
  102. /**
  103. * Executes a SQL statement in the database.
  104. */
  105. function osc_dbExec()
  106. {
  107. $sql = null;
  108. $argv = func_get_args();
  109. switch(func_num_args()) {
  110. case 0: return; break;
  111. case 1: $sql = $argv[0]; break;
  112. default:
  113. $format = array_shift($argv);
  114. foreach($argv as &$arg)
  115. $arg = $this->db->real_escape_string($arg);
  116. unset($arg);
  117. $sql = vsprintf($format, $argv);
  118. break;
  119. }
  120. $result = $this->db->query($sql);
  121. if(!$result) {
  122. $this->debug($sql . ' | ' . $this->db->error . ' (' . $this->db->errno . ')', false) ;
  123. } else {
  124. $this->debug($sql) ;
  125. }
  126. $this->db_errno = $this->db->errno;
  127. return $result;
  128. }
  129. function osc_dbFetchValue() {
  130. $result = null;
  131. $sql = null;
  132. $argv = func_get_args();
  133. switch(func_num_args()) {
  134. case 0: return $results; break;
  135. case 1: $sql = $argv[0]; break;
  136. default:
  137. $format = array_shift($argv);
  138. $sql = vsprintf($format, $argv);
  139. break;
  140. }
  141. if($qry = $this->db->query($sql)) {
  142. $this->debug($sql) ;
  143. $row = $qry->fetch_array();
  144. $result = $row[0];
  145. $qry->free();
  146. } else {
  147. $this->debug($sql . ' | ' . $this->db->error . ' (' . $this->db->errno . ')', false) ;
  148. }
  149. $this->db_errno = $this->db->errno;
  150. return $result;
  151. }
  152. /**
  153. * @return array with values resulting of execution of query passed by parameter.
  154. */
  155. function osc_dbFetchValues() {
  156. $results = array();
  157. $sql = null;
  158. $argv = func_get_args();
  159. switch(func_num_args()) {
  160. case 0: return $results; break;
  161. case 1: $sql = $argv[0]; break;
  162. default:
  163. $format = array_shift($argv);
  164. $sql = vsprintf($format, $argv);
  165. break;
  166. }
  167. if($qry = $this->db->query($sql)) {
  168. $this->debug($sql) ;
  169. while($result = $qry->fetch_array())
  170. $results[] = $result[0];
  171. $qry->free();
  172. } else {
  173. $this->debug($sql . ' | ' . $this->db->error . ' (' . $this->db->errno . ')', false) ;
  174. }
  175. $this->db_errno = $this->db->errno;
  176. return $results;
  177. }
  178. function osc_dbFetchResult() {
  179. $result = null;
  180. $sql = null;
  181. $argv = func_get_args();
  182. switch(func_num_args()) {
  183. case 0: return $results; break;
  184. case 1: $sql = $argv[0]; break;
  185. default:
  186. $format = array_shift($argv);
  187. $sql = vsprintf($format, $argv);
  188. break;
  189. }
  190. $qry = $this->db->query($sql);
  191. if($qry) {
  192. $this->debug($sql) ;
  193. $result = $qry->fetch_assoc();
  194. $qry->free();
  195. } else {
  196. $this->debug($sql . ' | ' . $this->db->error . ' (' . $this->db->errno . ')', false) ;
  197. }
  198. $this->db_errno = $this->db->errno;
  199. return $result;
  200. }
  201. function osc_dbFetchResults() {
  202. $results = array();
  203. $sql = null;
  204. $argv = func_get_args();
  205. switch(func_num_args()) {
  206. case 0: return $results; break;
  207. case 1: $sql = $argv[0]; break;
  208. default:
  209. $format = array_shift($argv);
  210. $sql = vsprintf($format, $argv);
  211. break;
  212. }
  213. if($qry = $this->db->query($sql)) {
  214. $this->debug($sql) ;
  215. while($result = $qry->fetch_assoc())
  216. $results[] = $result;
  217. $qry->free();
  218. } else {
  219. $this->debug($sql . ' | ' . $this->db->error . ' (' . $this->db->errno . ')', false) ;
  220. }
  221. $this->db_errno = $this->db->errno;
  222. return $results;
  223. }
  224. /**
  225. * Import (executes) the SQL passed as parameter making some proper adaptations.
  226. */
  227. function osc_dbImportSQL($sql, $needle = '')
  228. {
  229. $sql = str_replace('/*TABLE_PREFIX*/', DB_TABLE_PREFIX, $sql);
  230. $sentences = explode( $needle . ';', $sql);
  231. // PREPARE THE QUERIES
  232. $var_l = count($sentences);
  233. $s_temp = '';
  234. for($var_k=0;$var_k<$var_l;$var_k++) {
  235. $s = $s_temp.$sentences[$var_k];
  236. if(!empty($s) && trim($s)!='') {
  237. $s .= $needle;
  238. $simple_comma = substr_count($s, "'");
  239. $scaped_simple_comma = substr_count($s, "\'");
  240. if(($simple_comma-$scaped_simple_comma)%2==0) {
  241. $sentences[$var_k] = $s;
  242. $s_temp = '';
  243. //echo "[OK] ".$s." <br />";
  244. } else {
  245. unset($sentences[$var_k]);
  246. $s_temp = $s.";";
  247. //echo "[FAIL] ".$s." <br />";
  248. }
  249. } else {
  250. unset($sentences[$var_k]);
  251. }
  252. }
  253. foreach($sentences as $s) {
  254. $s = trim($s);
  255. if( !empty($s) ) {
  256. $s = trim($s) ;// . $needle;
  257. if( $this->db->query($s) ) {
  258. $this->debug($s) ;
  259. } else {
  260. $this->debug($s . ' | ' . $this->db->error . ' (' . $this->db->errno . ')', false) ;
  261. }
  262. }
  263. }
  264. $this->db_errno = $this->db->errno ;
  265. if ($this->db_errno != 0) return false ;
  266. return true ;
  267. }
  268. function autocommit($b_value) {
  269. $this->db->autocommit($b_value) ;
  270. }
  271. function commit() {
  272. $this->db->commit() ;
  273. }
  274. function rollback() {
  275. $this->db->rollback() ;
  276. }
  277. function get_last_id() {
  278. return($this->db->insert_id) ;
  279. }
  280. function get_affected_rows() {
  281. return($this->db->affected_rows) ;
  282. }
  283. function get_errno() {
  284. return($this->db_errno);
  285. }
  286. /**
  287. * Given some queries, it will check against the installed database if the information is the same
  288. *
  289. * @param mixed array or string with the SQL queries.
  290. * @return BOOLEAN true on success, false on fail
  291. */
  292. function osc_updateDB($queries = '') {
  293. if(!is_array($queries)) {
  294. $queries = explode(";", $queries);
  295. }
  296. // Prepare and separate the queries
  297. $struct_queries = array();
  298. $data_queries = array();
  299. foreach($queries as $query) {
  300. if(preg_match('|CREATE DATABASE ([^ ]*)|', $query, $match)) {
  301. array_unshift($struct_queries, $query);
  302. } else if(preg_match('|CREATE TABLE ([^ ]*)|', $query, $match)) {
  303. $struct_queries[trim(strtolower($match[1]), '`')] = $query;
  304. } else if(preg_match('|INSERT INTO ([^ ]*)|', $query, $match)) {
  305. $data_queries[] = $query;
  306. } else if(preg_match('|UPDATE ([^ ]*)|', $query, $match)) {
  307. $data_queries[] = $query;
  308. }
  309. }
  310. // Get tables from DB (already installed)
  311. $tables = $this->osc_dbFetchResults('SHOW TABLES');
  312. foreach($tables as $v) {
  313. $table = current($v);
  314. if(array_key_exists(strtolower($table), $struct_queries)) {
  315. // Get the fields from the query
  316. if(preg_match('|\((.*)\)|ms', $struct_queries[strtolower($table)], $match)) {
  317. $fields = explode("\n", trim($match[1]));
  318. // Detect if it's a "normal field definition" or a index one
  319. $normal_fields = $indexes = array();
  320. foreach($fields as $field) {
  321. if(preg_match('|([^ ]+)|', trim($field), $field_name)) {
  322. switch (strtolower($field_name[1])) {
  323. case '':
  324. case 'on':
  325. case 'foreign':
  326. case 'primary':
  327. case 'index':
  328. case 'fulltext':
  329. case 'unique':
  330. case 'key':
  331. $indexes[] = trim($field, ", \n");
  332. break;
  333. default :
  334. $normal_fields[strtolower($field_name[1])] = trim($field, ", \n");
  335. break;
  336. }
  337. }
  338. }
  339. // Take fields from the DB (already installed)
  340. $tbl_fields = $this->osc_dbFetchResults('DESCRIBE '.$table);
  341. foreach($tbl_fields as $tbl_field) {
  342. //Every field should we on the definition, so else SHOULD never happen, unless a very aggressive plugin modify our tables
  343. if(array_key_exists(strtolower($tbl_field['Field']), $normal_fields)) {
  344. // Take the type of the field
  345. if(preg_match("|".$tbl_field['Field']." (ENUM\s*\(([^\)]*)\))|i", $normal_fields[strtolower($tbl_field['Field'])], $match) || preg_match("|".$tbl_field['Field']." ([^ ]*( unsigned)?)|i", $normal_fields[strtolower($tbl_field['Field'])], $match)) {
  346. $field_type = $match[1];
  347. // Are they the same?
  348. if(strtolower($field_type)!=strtolower($tbl_field['Type']) && str_replace(' ', '', strtolower($field_type))!=str_replace(' ', '', strtolower($tbl_field['Type']))) {
  349. $struct_queries[] = "ALTER TABLE ".$table." CHANGE COLUMN ".$tbl_field['Field']." ".$normal_fields[strtolower($tbl_field['Field'])];
  350. }
  351. }
  352. // Have we changed the default value?
  353. if(preg_match("| DEFAULT '(.*)'|i", $normal_fields[strtolower($tbl_field['Field'])], $default_match)) {
  354. $struct_queries[] = "ALTER TABLE ".$table." ALTER COLUMN ".$tbl_field['Field']." SET DEFAULT ".$default_match[1];
  355. }
  356. // Remove it from the list, so it will not be added
  357. unset($normal_fields[strtolower($tbl_field['Field'])]);
  358. }
  359. }
  360. // For the rest of normal fields (they are not in the table) we add them.
  361. foreach($normal_fields as $k => $v) {
  362. $struct_queries[] = "ALTER TABLE ".$table." ADD COLUMN ".$v;
  363. }
  364. // Go for the index part
  365. $tbl_indexes = $this->osc_dbFetchResults("SHOW INDEX FROM ".$table);
  366. if($tbl_indexes) {
  367. unset($indexes_array);
  368. foreach($tbl_indexes as $tbl_index) {
  369. $indexes_array[$tbl_index['Key_name']]['columns'][] = array('fieldname' => $tbl_index['Column_name'], 'subpart' => $tbl_index['Sub_part']);
  370. $indexes_array[$tbl_index['Key_name']]['unique'] = ($tbl_index['Non_unique'] == 0)?true:false;
  371. }
  372. foreach($indexes_array as $k => $v) {
  373. $string = '';
  374. if ($k=='PRIMARY') {
  375. $string .= 'PRIMARY KEY ';
  376. } else if($v['unique']) {
  377. $string .= 'UNIQUE KEY ';
  378. } else {
  379. $string .= 'INDEX ';
  380. }
  381. $columns = '';
  382. // For each column in the index
  383. foreach ($v['columns'] as $column) {
  384. if ($columns != '') $columns .= ', ';
  385. // Add the field to the column list string
  386. $columns .= $column['fieldname'];
  387. if ($column['subpart'] != '') {
  388. $columns .= '('.$column['subpart'].')';
  389. }
  390. }
  391. // Add the column list to the index create string
  392. $string .= '('.$columns.')';
  393. $var_index = array_search($string, $indexes);
  394. if (!($var_index===false)) {
  395. unset($indexes[$var_index]);
  396. } else {
  397. $var_index = array_search(str_replace(', ', ',', $string), $indexes);
  398. if (!($var_index===false)) {
  399. unset($indexes[$var_index]);
  400. }
  401. }
  402. }
  403. }
  404. // For the rest of the indexes (they are in the new definition but not in the table installed
  405. foreach($indexes as $index) {
  406. if(strtolower(substr(trim($index),0,2))!='on') {// && strtolower(substr(trim($index),0,7))!='foreign') {
  407. $struct_queries[] = "ALTER TABLE ".$table." ADD ".$index;
  408. //} else {
  409. //$struct_queries[] = "ALTER TABLE ".$table." ".$index;
  410. }
  411. }
  412. // No need to create the table, so we delete it SQL
  413. unset($struct_queries[strtolower($table)]);
  414. }
  415. }
  416. }
  417. $queries = array_merge($struct_queries, $data_queries);
  418. foreach($queries as $query) {
  419. $this->osc_dbExec($query);
  420. }
  421. return $queries;
  422. }
  423. }
  424. function getConnection($dbHost = null, $dbUser = null, $dbPassword = null, $dbName = null, $dbLogLevel = null)
  425. {
  426. static $instance ;
  427. //DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, DEBUG_LEVEL
  428. if(defined('DB_HOST') && $dbHost == null) $dbHost = DB_HOST ;
  429. if(defined('DB_USER') && $dbUser == null) $dbUser = DB_USER ;
  430. if(defined('DB_PASSWORD') && $dbPassword == null) $dbPassword = DB_PASSWORD ;
  431. if(defined('DB_NAME') && $dbName == null) $dbName = DB_NAME ;
  432. if(defined('DEBUG_LEVEL') && $dbLogLevel == null) $dbLogLevel = DEBUG_LEVEL ;
  433. if(!isset($instance[$dbName . "_" . $dbHost])) {
  434. if(!isset($instance)) {
  435. $instance = array();
  436. }
  437. $instance[$dbName . "_" . $dbHost] = new DB($dbHost, $dbUser, $dbPassword, $dbName, $dbLogLevel);
  438. }
  439. return ($instance[$dbName . "_" . $dbHost]);
  440. }