PageRenderTime 49ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/mrbs-1.4.8/web/mysql.inc

#
PHP | 507 lines | 353 code | 70 blank | 84 comment | 24 complexity | 6831d37068549b33a95855b2373b7ce8 MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. // $Id: mysql.inc 1859 2011-08-04 11:18:11Z cimorrison $
  3. // mysql.inc - Simple PHP database support for MySQL.
  4. // The standard MRBS database connection utilises the following configuration
  5. // variables:
  6. // $db_host = The hostname of the database server
  7. // $db_login = The username to use when connecting to the database
  8. // $db_password = The database account password
  9. // $db_database = The database name.
  10. // A small utility function (not part of the DB abstraction API) to
  11. // update a connection handle to the global MRBS connection handle
  12. // if said handle is null/empty
  13. function sql_mysql_ensure_handle(&$db_conn)
  14. {
  15. if (empty($db_conn))
  16. {
  17. global $sql_mysql_conn;
  18. $db_conn = $sql_mysql_conn;
  19. }
  20. }
  21. // Free a results handle. You need not call this if you call sql_row or
  22. // sql_row_keyed until the row returns 0, since sql_row frees the results
  23. // handle when you finish reading the rows.
  24. function sql_mysql_free ($r, $db_conn = null)
  25. {
  26. sql_mysql_ensure_handle($db_conn);
  27. mysql_free_result($r);
  28. }
  29. // Execute a non-SELECT SQL command (insert/update/delete).
  30. // Returns the number of tuples affected if OK (a number >= 0).
  31. // Returns -1 on error; use sql_error to get the error message.
  32. function sql_mysql_command ($sql, $db_conn = null)
  33. {
  34. sql_mysql_ensure_handle($db_conn);
  35. if (mysql_query($sql, $db_conn))
  36. {
  37. return mysql_affected_rows($db_conn);
  38. }
  39. return -1;
  40. }
  41. // Execute an SQL query which should return a single non-negative number value.
  42. // This is a lightweight alternative to sql_query, good for use with count(*)
  43. // and similar queries. It returns -1 on error or if the query did not return
  44. // exactly one value, so error checking is somewhat limited.
  45. // It also returns -1 if the query returns a single NULL value, such as from
  46. // a MIN or MAX aggregate function applied over no rows.
  47. function sql_mysql_query1 ($sql, $db_conn = null)
  48. {
  49. sql_mysql_ensure_handle($db_conn);
  50. $r = mysql_query($sql, $db_conn);
  51. if (! $r)
  52. {
  53. return -1;
  54. }
  55. if (mysql_num_rows($r) != 1 || mysql_num_fields($r) != 1
  56. || ($result = mysql_result($r, 0, 0)) == "")
  57. {
  58. $result = -1;
  59. }
  60. mysql_free_result($r);
  61. return $result;
  62. }
  63. // Execute an SQL query. Returns a database-dependent result handle,
  64. // which should be passed back to sql_row or sql_row_keyed to get the results.
  65. // Returns 0 on error; use sql_error to get the error message.
  66. function sql_mysql_query ($sql, $db_conn = null)
  67. {
  68. sql_mysql_ensure_handle($db_conn);
  69. $r = mysql_query($sql, $db_conn);
  70. return $r;
  71. }
  72. // Return a row from a result. The first row is 0.
  73. // The row is returned as an array with index 0=first column, etc.
  74. // When called with i >= number of rows in the result, cleans up from
  75. // the query and returns 0.
  76. // Typical usage: $i = 0; while ((a = sql_row($r, $i++))) { ... }
  77. function sql_mysql_row ($r, $i, $db_conn = null)
  78. {
  79. sql_mysql_ensure_handle($db_conn);
  80. if ($i >= mysql_num_rows($r))
  81. {
  82. mysql_free_result($r);
  83. return 0;
  84. }
  85. mysql_data_seek($r, $i);
  86. return mysql_fetch_row($r);
  87. }
  88. // Return a row from a result as an associative array keyed by field name.
  89. // The first row is 0.
  90. // This is actually upward compatible with sql_row since the underlying
  91. // routing also stores the data under number indexes.
  92. // When called with i >= number of rows in the result, cleans up from
  93. // the query and returns 0.
  94. function sql_mysql_row_keyed ($r, $i, $db_conn = null)
  95. {
  96. sql_mysql_ensure_handle($db_conn);
  97. if ($i >= mysql_num_rows($r))
  98. {
  99. mysql_free_result($r);
  100. return 0;
  101. }
  102. mysql_data_seek($r, $i);
  103. // Use _array() rather _assoc() to ensure support
  104. // for as many PHP versions as possible
  105. return mysql_fetch_array($r, MYSQL_ASSOC);
  106. }
  107. // Return the number of rows returned by a result handle from sql_query.
  108. function sql_mysql_count ($r, $db_conn = null)
  109. {
  110. sql_mysql_ensure_handle($db_conn);
  111. return mysql_num_rows($r);
  112. }
  113. // Return the value of an autoincrement field from the last insert.
  114. // Must be called right after an insert on that table!
  115. function sql_mysql_insert_id($table, $field, $db_conn = null)
  116. {
  117. sql_mysql_ensure_handle($db_conn);
  118. return mysql_insert_id($db_conn);
  119. }
  120. // Return the text of the last error message.
  121. function sql_mysql_error($db_conn = null)
  122. {
  123. sql_mysql_ensure_handle($db_conn);
  124. return mysql_error($db_conn);
  125. }
  126. // Begin a transaction, if the database supports it. This is used to
  127. // improve performance for multiple insert/delete/updates.
  128. // There is no rollback support, since MySQL myisam tables don't support it.
  129. function sql_mysql_begin($db_conn = null)
  130. {
  131. sql_mysql_command("START TRANSACTION", $db_conn);
  132. }
  133. // Commit (end) a transaction. See sql_begin().
  134. function sql_mysql_commit($db_conn = null)
  135. {
  136. sql_mysql_command("COMMIT", $db_conn);
  137. }
  138. // Acquire a mutual-exclusion lock on the named table. For portability:
  139. // This will not lock out SELECTs.
  140. // It may lock out DELETE/UPDATE/INSERT or not, depending on the implementation.
  141. // It will lock out other callers of this routine with the same name argument.
  142. // It may timeout in 20 seconds and return 0, or may wait forever.
  143. // It returns 1 when the lock has been acquired.
  144. // Caller must release the lock with sql_mutex_unlock().
  145. // Caller must not have more than one mutex at any time.
  146. // Do not mix this with sql_begin()/sql_end() calls.
  147. //
  148. // In MySQL, we avoid table locks, and use low-level locks instead.
  149. function sql_mysql_mutex_lock($name, $db_conn = null)
  150. {
  151. sql_mysql_ensure_handle($db_conn);
  152. global $sql_mysql_mutex_shutdown_registered, $sql_mysql_mutex_unlock_name;
  153. if (!sql_mysql_query1("SELECT GET_LOCK('$name', 20)", $db_conn))
  154. {
  155. return 0;
  156. }
  157. $sql_mysql_mutex_unlock_name = $name;
  158. if (empty($sql_mysql_mutex_shutdown_registered))
  159. {
  160. register_shutdown_function("sql_mysql_mutex_cleanup", $db_conn);
  161. $sql_mysql_mutex_shutdown_registered = 1;
  162. }
  163. return 1;
  164. }
  165. // Release a mutual-exclusion lock on the named table. See sql_mutex_unlock.
  166. function sql_mysql_mutex_unlock($name, $db_conn = null)
  167. {
  168. sql_mysql_ensure_handle($db_conn);
  169. global $sql_mysql_mutex_unlock_name;
  170. sql_mysql_query1("SELECT RELEASE_LOCK('$name')", $db_conn);
  171. $sql_mysql_mutex_unlock_name = "";
  172. }
  173. // Shutdown function to clean up a forgotten lock. For internal use only.
  174. function sql_mysql_mutex_cleanup($db_conn)
  175. {
  176. global $sql_mysql_mutex_shutdown_registered, $sql_mysql_mutex_unlock_name;
  177. if (!empty($sql_mysql_mutex_unlock_name))
  178. {
  179. sql_mysql_mutex_unlock($sql_mysql_mutex_unlock_name, $db_conn);
  180. $sql_mysql_mutex_unlock_name = "";
  181. }
  182. }
  183. // Return a string identifying the database version:
  184. function sql_mysql_version($db_conn = null)
  185. {
  186. sql_mysql_ensure_handle($db_conn);
  187. $r = sql_mysql_query("select version()", $db_conn);
  188. $v = sql_mysql_row($r, 0, $db_conn);
  189. sql_mysql_free($r, $db_conn);
  190. return "MySQL $v[0]";
  191. }
  192. // Generate non-standard SQL for LIMIT clauses:
  193. function sql_mysql_syntax_limit($count, $offset, $db_conn = null)
  194. {
  195. sql_mysql_ensure_handle($db_conn);
  196. return " LIMIT $offset,$count ";
  197. }
  198. // Generate non-standard SQL to output a TIMESTAMP as a Unix-time:
  199. function sql_mysql_syntax_timestamp_to_unix($fieldname, $db_conn = null)
  200. {
  201. sql_mysql_ensure_handle($db_conn);
  202. return " UNIX_TIMESTAMP($fieldname) ";
  203. }
  204. // Returns the syntax for a case sensitive string "equals" function
  205. // (By default MySQL is case insensitive, so we force a binary comparison)
  206. function sql_mysql_syntax_casesensitive_equals($fieldname, $s, $db_conn = null)
  207. {
  208. sql_mysql_ensure_handle($db_conn);
  209. return " BINARY `$fieldname`='" . addslashes($s) . "'";
  210. }
  211. // Generate non-standard SQL to match a string anywhere in a field's value
  212. // in a case insensitive manner. $s is the un-escaped/un-slashed string.
  213. // In MySQL, REGEXP seems to be case sensitive, so use LIKE instead. But this
  214. // requires quoting of % and _ in addition to the usual.
  215. function sql_mysql_syntax_caseless_contains($fieldname, $s, $db_conn = null)
  216. {
  217. sql_mysql_ensure_handle($db_conn);
  218. $s = str_replace("\\", "\\\\", $s);
  219. $s = str_replace("%", "\\%", $s);
  220. $s = str_replace("_", "\\_", $s);
  221. $s = str_replace("'", "''", $s);
  222. return " $fieldname LIKE '%$s%' ";
  223. }
  224. // Generate non-standard SQL to add a table column after another specified
  225. // column
  226. function sql_mysql_syntax_addcolumn_after($fieldname, $db_conn = null)
  227. {
  228. sql_mysql_ensure_handle($db_conn);
  229. return "AFTER $fieldname";
  230. }
  231. // Generate non-standard SQL to specify a column as an auto-incrementing
  232. // integer while doing a CREATE TABLE
  233. function sql_mysql_syntax_createtable_autoincrementcolumn($db_conn = null)
  234. {
  235. sql_mysql_ensure_handle($db_conn);
  236. return "int NOT NULL auto_increment";
  237. }
  238. // Returns the syntax for a bitwise XOR operator
  239. function sql_mysql_syntax_bitwise_xor($db_conn = null)
  240. {
  241. sql_mysql_ensure_handle($db_conn);
  242. return "^";
  243. }
  244. // Returns the name of a field.
  245. function sql_mysql_field_name($result, $index, $db_conn = null)
  246. {
  247. sql_mysql_ensure_handle($db_conn);
  248. return mysql_field_name($result, $index);
  249. }
  250. // Returns the type of a field. (one of "int", "real", "string", "blob", etc...)
  251. function sql_mysql_field_type($result, $index, $db_conn = null)
  252. {
  253. sql_mysql_ensure_handle($db_conn);
  254. return mysql_field_type($result, $index);
  255. }
  256. // Returns the number of fields in a result.
  257. function sql_mysql_num_fields($result, $db_conn = null)
  258. {
  259. sql_mysql_ensure_handle($db_conn);
  260. return mysql_num_fields($result);
  261. }
  262. // Check if a table exists
  263. function sql_mysql_table_exists($table, $db_conn = null)
  264. {
  265. sql_mysql_ensure_handle($db_conn);
  266. $res = sql_mysql_query1("SHOW TABLES LIKE '".addslashes($table)."'");
  267. return ($res == -1) ? FALSE : TRUE;
  268. }
  269. // Get information about the columns in a table
  270. // Returns an array with the following indices for each column
  271. //
  272. // 'name' the column name
  273. // 'type' the type as reported by MySQL
  274. // 'nature' the type mapped onto one of a generic set of types
  275. // (boolean, integer, real, character, binary). This enables
  276. // the nature to be used by MRBS code when deciding how to
  277. // display fields, without MRBS having to worry about the
  278. // differences between MySQL and PostgreSQL type names.
  279. // 'length' the maximum length of the field in bytes, octets or characters
  280. // (Note: this could be NULL)
  281. // 'is_nullable' whether the column can be set to NULL (boolean)
  282. //
  283. // NOTE: the type mapping is incomplete and just covers the types commonly
  284. // used by MRBS
  285. function sql_mysql_field_info($table, $db_conn = null)
  286. {
  287. sql_mysql_ensure_handle($db_conn);
  288. // Map MySQL types on to a set of generic types
  289. $nature_map = array('bigint' => 'integer',
  290. 'char' => 'character',
  291. 'double' => 'real',
  292. 'float' => 'real',
  293. 'int' => 'integer',
  294. 'mediumint' => 'integer',
  295. 'smallint' => 'integer',
  296. 'text' => 'character',
  297. 'tinyint' => 'integer',
  298. 'tinytext' => 'character',
  299. 'varchar' => 'character');
  300. // Length in bytes of MySQL integer types
  301. $int_bytes = array('bigint' => 8, // bytes
  302. 'int' => 4,
  303. 'mediumint' => 3,
  304. 'smallint' => 2,
  305. 'tinyint' => 1);
  306. $res = sql_mysql_query("SHOW COLUMNS FROM $table");
  307. if ($res === FALSE)
  308. {
  309. trigger_error(mysql_error($db_conn), E_USER_WARNING);
  310. fatal_error(TRUE, get_vocab("fatal_db_error"));
  311. }
  312. else
  313. {
  314. $fields = array();
  315. for ($i = 0; ($row = sql_mysql_row_keyed($res, $i)); $i++)
  316. {
  317. $name = $row['Field'];
  318. $type = $row['Type'];
  319. // split the type (eg 'varchar(25)') around the opening '('
  320. $parts = explode('(', $type);
  321. // map the type onto one of the generic natures, if a mapping exists
  322. $nature = (array_key_exists($parts[0], $nature_map)) ? $nature_map[$parts[0]] : $parts[0];
  323. // now work out the length
  324. if ($nature == 'integer')
  325. {
  326. // if it's one of the ints, then look up the length in bytes
  327. $length = (array_key_exists($parts[0], $int_bytes)) ? $int_bytes[$parts[0]] : 0;
  328. }
  329. elseif ($nature == 'character')
  330. {
  331. // if it's a character type then use the length that was in parentheses
  332. // eg if it was a varchar(25), we want the 25
  333. if (isset($parts[1]))
  334. {
  335. $length = preg_replace('/\)/', '', $parts[1]); // strip off the closing ')'
  336. }
  337. // otherwise it could be any length (eg if it was a 'text')
  338. else
  339. {
  340. $length = defined('PHP_INT_MAX') ? PHP_INT_MAX : 9999;
  341. }
  342. }
  343. else // we're only dealing with a few simple cases at the moment
  344. {
  345. $length = NULL;
  346. }
  347. // Convert the is_nullable field to a boolean
  348. $is_nullable = (strtolower($row['Null']) == 'yes') ? TRUE : FALSE;
  349. $fields[$i]['name'] = $name;
  350. $fields[$i]['type'] = $type;
  351. $fields[$i]['nature'] = $nature;
  352. $fields[$i]['length'] = $length;
  353. $fields[$i]['is_nullable'] = $is_nullable;
  354. }
  355. return $fields;
  356. }
  357. }
  358. // Connect to a database server and select a database, optionally using
  359. // persistent connections
  360. function sql_mysql_connect($host, $username, $password, $db_name, $persist = 0)
  361. {
  362. // Establish a database connection.
  363. // On connection error, the message will be output without a proper HTML
  364. // header. There is no way I can see around this; if track_errors isn't on
  365. // there seems to be no way to supress the automatic error message output and
  366. // still be able to access the error text.
  367. if ($persist)
  368. {
  369. $db_conn = mysql_pconnect($host, $username, $password);
  370. }
  371. else
  372. {
  373. $db_conn = mysql_connect($host, $username, $password);
  374. }
  375. if (!$db_conn || !mysql_select_db ($db_name, $db_conn))
  376. {
  377. echo "\n<p>\n" . get_vocab("failed_connect_db") . "\n</p>\n";
  378. exit;
  379. }
  380. if (function_exists('mysql_set_charset'))
  381. {
  382. mysql_set_charset('utf8', $db_conn);
  383. }
  384. else
  385. {
  386. mysql_query("SET NAMES 'utf8'", $db_conn);
  387. }
  388. return $db_conn;
  389. }
  390. //
  391. function sql_mysql_default_connect()
  392. {
  393. global $sql_mysql_conn, $db_nopersist, $db_host, $db_login, $db_password,
  394. $db_database;
  395. /////////////////////////////////////////////
  396. // Open the standard MRBS database connection
  397. $persist = 1;
  398. if (!empty($db_nopersist) && $db_nopersist)
  399. {
  400. $persist = 0;
  401. }
  402. $sql_mysql_conn = sql_mysql_connect($db_host, $db_login, $db_password,
  403. $db_database, $persist);
  404. }
  405. // Close a connection
  406. function sql_mysql_close($connection)
  407. {
  408. mysql_close($connection);
  409. }
  410. ?>