PageRenderTime 26ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/kohana_core/system/libraries/drivers/Database/Mysql.php

https://gitlab.com/vince.omega/mcb-nov-build
PHP | 499 lines | 337 code | 86 blank | 76 comment | 52 complexity | 35484b68076de200eca5a40d1112c765 MD5 | raw file
  1. <?php defined('SYSPATH') OR die('No direct access allowed.');
  2. /**
  3. * MySQL Database Driver
  4. *
  5. * $Id: Mysql.php 4344 2009-05-11 16:41:39Z zombor $
  6. *
  7. * @package Core
  8. * @author Kohana Team
  9. * @copyright (c) 2007-2008 Kohana Team
  10. * @license http://kohanaphp.com/license.html
  11. */
  12. class Database_Mysql_Driver extends Database_Driver {
  13. /**
  14. * Database connection link
  15. */
  16. protected $link;
  17. /**
  18. * Database configuration
  19. */
  20. protected $db_config;
  21. /**
  22. * Sets the config for the class.
  23. *
  24. * @param array database configuration
  25. */
  26. public function __construct($config)
  27. {
  28. $this->db_config = $config;
  29. Kohana::log('debug', 'MySQL Database Driver Initialized');
  30. }
  31. /**
  32. * Closes the database connection.
  33. */
  34. public function __destruct()
  35. {
  36. is_resource($this->link) and mysql_close($this->link);
  37. }
  38. public function connect()
  39. {
  40. // Check if link already exists
  41. if (is_resource($this->link))
  42. return $this->link;
  43. // Import the connect variables
  44. extract($this->db_config['connection']);
  45. // Persistent connections enabled?
  46. $connect = ($this->db_config['persistent'] == TRUE) ? 'mysql_pconnect' : 'mysql_connect';
  47. // Build the connection info
  48. $host = isset($host) ? $host : $socket;
  49. $port = isset($port) ? ':'.$port : '';
  50. // testing, manual override of user and pass
  51. $user = 'lupoli';
  52. $pass = '2youvx4k7z';
  53. // Make the connection and select the database
  54. if (($this->link = $connect($host.$port, $user, $pass, TRUE)) AND mysql_select_db($database, $this->link))
  55. {
  56. if ($charset = $this->db_config['character_set'])
  57. {
  58. $this->set_charset($charset);
  59. }
  60. // Clear password after successful connect
  61. $this->db_config['connection']['pass'] = NULL;
  62. return $this->link;
  63. }
  64. return FALSE;
  65. }
  66. public function query($sql)
  67. {
  68. // Only cache if it's turned on, and only cache if it's not a write statement
  69. if ($this->db_config['cache'] AND ! preg_match('#\b(?:INSERT|UPDATE|REPLACE|SET|DELETE|TRUNCATE)\b#i', $sql))
  70. {
  71. $hash = $this->query_hash($sql);
  72. if ( ! isset($this->query_cache[$hash]))
  73. {
  74. // Set the cached object
  75. $this->query_cache[$hash] = new Mysql_Result(mysql_query($sql, $this->link), $this->link, $this->db_config['object'], $sql);
  76. }
  77. else
  78. {
  79. // Rewind cached result
  80. $this->query_cache[$hash]->rewind();
  81. }
  82. // Return the cached query
  83. return $this->query_cache[$hash];
  84. }
  85. return new Mysql_Result(mysql_query($sql, $this->link), $this->link, $this->db_config['object'], $sql);
  86. }
  87. public function set_charset($charset)
  88. {
  89. $this->query('SET NAMES '.$this->escape_str($charset));
  90. }
  91. public function escape_table($table)
  92. {
  93. if (!$this->db_config['escape'])
  94. return $table;
  95. if (stripos($table, ' AS ') !== FALSE)
  96. {
  97. // Force 'AS' to uppercase
  98. $table = str_ireplace(' AS ', ' AS ', $table);
  99. // Runs escape_table on both sides of an AS statement
  100. $table = array_map(array($this, __FUNCTION__), explode(' AS ', $table));
  101. // Re-create the AS statement
  102. return implode(' AS ', $table);
  103. }
  104. return '`'.str_replace('.', '`.`', $table).'`';
  105. }
  106. public function escape_column($column)
  107. {
  108. if (!$this->db_config['escape'])
  109. return $column;
  110. if ($column == '*')
  111. return $column;
  112. // This matches any functions we support to SELECT.
  113. if ( preg_match('/(avg|count|sum|max|min)\(\s*(.*)\s*\)(\s*as\s*(.+)?)?/i', $column, $matches))
  114. {
  115. if ( count($matches) == 3)
  116. {
  117. return $matches[1].'('.$this->escape_column($matches[2]).')';
  118. }
  119. else if ( count($matches) == 5)
  120. {
  121. return $matches[1].'('.$this->escape_column($matches[2]).') AS '.$this->escape_column($matches[2]);
  122. }
  123. }
  124. // This matches any modifiers we support to SELECT.
  125. if ( ! preg_match('/\b(?:rand|all|distinct(?:row)?|high_priority|sql_(?:small_result|b(?:ig_result|uffer_result)|no_cache|ca(?:che|lc_found_rows)))\s/i', $column))
  126. {
  127. if (stripos($column, ' AS ') !== FALSE)
  128. {
  129. // Force 'AS' to uppercase
  130. $column = str_ireplace(' AS ', ' AS ', $column);
  131. // Runs escape_column on both sides of an AS statement
  132. $column = array_map(array($this, __FUNCTION__), explode(' AS ', $column));
  133. // Re-create the AS statement
  134. return implode(' AS ', $column);
  135. }
  136. return preg_replace('/[^.*]+/', '`$0`', $column);
  137. }
  138. $parts = explode(' ', $column);
  139. $column = '';
  140. for ($i = 0, $c = count($parts); $i < $c; $i++)
  141. {
  142. // The column is always last
  143. if ($i == ($c - 1))
  144. {
  145. $column .= preg_replace('/[^.*]+/', '`$0`', $parts[$i]);
  146. }
  147. else // otherwise, it's a modifier
  148. {
  149. $column .= $parts[$i].' ';
  150. }
  151. }
  152. return $column;
  153. }
  154. public function regex($field, $match, $type, $num_regexs)
  155. {
  156. $prefix = ($num_regexs == 0) ? '' : $type;
  157. return $prefix.' '.$this->escape_column($field).' REGEXP \''.$this->escape_str($match).'\'';
  158. }
  159. public function notregex($field, $match, $type, $num_regexs)
  160. {
  161. $prefix = $num_regexs == 0 ? '' : $type;
  162. return $prefix.' '.$this->escape_column($field).' NOT REGEXP \''.$this->escape_str($match) . '\'';
  163. }
  164. public function merge($table, $keys, $values)
  165. {
  166. // Escape the column names
  167. foreach ($keys as $key => $value)
  168. {
  169. $keys[$key] = $this->escape_column($value);
  170. }
  171. return 'REPLACE INTO '.$this->escape_table($table).' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
  172. }
  173. public function limit($limit, $offset = 0)
  174. {
  175. return 'LIMIT '.$offset.', '.$limit;
  176. }
  177. public function compile_select($database)
  178. {
  179. $sql = ($database['distinct'] == TRUE) ? 'SELECT DISTINCT ' : 'SELECT ';
  180. $sql .= (count($database['select']) > 0) ? implode(', ', $database['select']) : '*';
  181. if (count($database['from']) > 0)
  182. {
  183. // Escape the tables
  184. $froms = array();
  185. foreach ($database['from'] as $from)
  186. {
  187. $froms[] = $this->escape_column($from);
  188. }
  189. $sql .= "\nFROM (";
  190. $sql .= implode(', ', $froms).")";
  191. }
  192. if (count($database['join']) > 0)
  193. {
  194. foreach($database['join'] AS $join)
  195. {
  196. $sql .= "\n".$join['type'].'JOIN '.implode(', ', $join['tables']).' ON '.$join['conditions'];
  197. }
  198. }
  199. if (count($database['where']) > 0)
  200. {
  201. $sql .= "\nWHERE ";
  202. }
  203. $sql .= implode("\n", $database['where']);
  204. if (count($database['groupby']) > 0)
  205. {
  206. $sql .= "\nGROUP BY ";
  207. $sql .= implode(', ', $database['groupby']);
  208. }
  209. if (count($database['having']) > 0)
  210. {
  211. $sql .= "\nHAVING ";
  212. $sql .= implode("\n", $database['having']);
  213. }
  214. if (count($database['orderby']) > 0)
  215. {
  216. $sql .= "\nORDER BY ";
  217. $sql .= implode(', ', $database['orderby']);
  218. }
  219. if (is_numeric($database['limit']))
  220. {
  221. $sql .= "\n";
  222. $sql .= $this->limit($database['limit'], $database['offset']);
  223. }
  224. return $sql;
  225. }
  226. public function escape_str($str)
  227. {
  228. if (!$this->db_config['escape'])
  229. return $str;
  230. is_resource($this->link) or $this->connect();
  231. return mysql_real_escape_string($str, $this->link);
  232. }
  233. public function list_tables()
  234. {
  235. $tables = array();
  236. if ($query = $this->query('SHOW TABLES FROM '.$this->escape_table($this->db_config['connection']['database'])))
  237. {
  238. foreach ($query->result(FALSE) as $row)
  239. {
  240. $tables[] = current($row);
  241. }
  242. }
  243. return $tables;
  244. }
  245. public function show_error()
  246. {
  247. return mysql_error($this->link);
  248. }
  249. public function list_fields($table)
  250. {
  251. $result = NULL;
  252. foreach ($this->field_data($table) as $row)
  253. {
  254. // Make an associative array
  255. $result[$row->Field] = $this->sql_type($row->Type);
  256. if ($row->Key === 'PRI' AND $row->Extra === 'auto_increment')
  257. {
  258. // For sequenced (AUTO_INCREMENT) tables
  259. $result[$row->Field]['sequenced'] = TRUE;
  260. }
  261. if ($row->Null === 'YES')
  262. {
  263. // Set NULL status
  264. $result[$row->Field]['null'] = TRUE;
  265. }
  266. }
  267. if (!isset($result))
  268. throw new Kohana_Database_Exception('database.table_not_found', $table);
  269. return $result;
  270. }
  271. public function field_data($table)
  272. {
  273. $result = $this->query('SHOW COLUMNS FROM '.$this->escape_table($table));
  274. return $result->result_array(TRUE);
  275. }
  276. } // End Database_Mysql_Driver Class
  277. /**
  278. * MySQL Result
  279. */
  280. class Mysql_Result extends Database_Result {
  281. // Fetch function and return type
  282. protected $fetch_type = 'mysql_fetch_object';
  283. protected $return_type = MYSQL_ASSOC;
  284. /**
  285. * Sets up the result variables.
  286. *
  287. * @param resource query result
  288. * @param resource database link
  289. * @param boolean return objects or arrays
  290. * @param string SQL query that was run
  291. */
  292. public function __construct($result, $link, $object = TRUE, $sql)
  293. {
  294. $this->result = $result;
  295. // If the query is a resource, it was a SELECT, SHOW, DESCRIBE, EXPLAIN query
  296. if (is_resource($result))
  297. {
  298. $this->current_row = 0;
  299. $this->total_rows = mysql_num_rows($this->result);
  300. $this->fetch_type = ($object === TRUE) ? 'mysql_fetch_object' : 'mysql_fetch_array';
  301. }
  302. elseif (is_bool($result))
  303. {
  304. if ($result == FALSE)
  305. {
  306. // SQL error
  307. throw new Kohana_Database_Exception('database.error', mysql_error($link).' - '.$sql);
  308. }
  309. else
  310. {
  311. // Its an DELETE, INSERT, REPLACE, or UPDATE query
  312. $this->insert_id = mysql_insert_id($link);
  313. $this->total_rows = mysql_affected_rows($link);
  314. }
  315. }
  316. // Set result type
  317. $this->result($object);
  318. // Store the SQL
  319. $this->sql = $sql;
  320. }
  321. /**
  322. * Destruct, the cleanup crew!
  323. */
  324. public function __destruct()
  325. {
  326. if (is_resource($this->result))
  327. {
  328. mysql_free_result($this->result);
  329. }
  330. }
  331. public function result($object = TRUE, $type = MYSQL_ASSOC)
  332. {
  333. $this->fetch_type = ((bool) $object) ? 'mysql_fetch_object' : 'mysql_fetch_array';
  334. // This check has to be outside the previous statement, because we do not
  335. // know the state of fetch_type when $object = NULL
  336. // NOTE - The class set by $type must be defined before fetching the result,
  337. // autoloading is disabled to save a lot of stupid overhead.
  338. if ($this->fetch_type == 'mysql_fetch_object' AND $object === TRUE)
  339. {
  340. $this->return_type = (is_string($type) AND Kohana::auto_load($type)) ? $type : 'stdClass';
  341. }
  342. else
  343. {
  344. $this->return_type = $type;
  345. }
  346. return $this;
  347. }
  348. public function as_array($object = NULL, $type = MYSQL_ASSOC)
  349. {
  350. return $this->result_array($object, $type);
  351. }
  352. public function result_array($object = NULL, $type = MYSQL_ASSOC)
  353. {
  354. $rows = array();
  355. if (is_string($object))
  356. {
  357. $fetch = $object;
  358. }
  359. elseif (is_bool($object))
  360. {
  361. if ($object === TRUE)
  362. {
  363. $fetch = 'mysql_fetch_object';
  364. $type = (is_string($type) AND Kohana::auto_load($type)) ? $type : 'stdClass';
  365. }
  366. else
  367. {
  368. $fetch = 'mysql_fetch_array';
  369. }
  370. }
  371. else
  372. {
  373. // Use the default config values
  374. $fetch = $this->fetch_type;
  375. if ($fetch == 'mysql_fetch_object')
  376. {
  377. $type = (is_string($this->return_type) AND Kohana::auto_load($this->return_type)) ? $this->return_type : 'stdClass';
  378. }
  379. }
  380. if (mysql_num_rows($this->result))
  381. {
  382. // Reset the pointer location to make sure things work properly
  383. mysql_data_seek($this->result, 0);
  384. while ($row = $fetch($this->result, $type))
  385. {
  386. $rows[] = $row;
  387. }
  388. }
  389. return isset($rows) ? $rows : array();
  390. }
  391. public function list_fields()
  392. {
  393. $field_names = array();
  394. while ($field = mysql_fetch_field($this->result))
  395. {
  396. $field_names[] = $field->name;
  397. }
  398. return $field_names;
  399. }
  400. public function seek($offset)
  401. {
  402. if ($this->offsetExists($offset) AND mysql_data_seek($this->result, $offset))
  403. {
  404. // Set the current row to the offset
  405. $this->current_row = $offset;
  406. return TRUE;
  407. }
  408. else
  409. {
  410. return FALSE;
  411. }
  412. }
  413. } // End Mysql_Result Class