PageRenderTime 55ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/frontend/php/include/database.php

#
PHP | 388 lines | 283 code | 37 blank | 68 comment | 49 complexity | 0c485f8cb9af357f47d93337d5c10861 MD5 | raw file
Possible License(s): AGPL-3.0
  1. <?php
  2. # Database access wrappers, with quoting/escaping
  3. # Copyright (C) 1999-2000 The SourceForge Crew
  4. # Copyright (C) 2004-2005 Elfyn McBratney <elfyn--emcb.co.uk>
  5. # Copyright (C) 2004-2005 Mathieu Roy <yeupou--gnu.org>
  6. # Copyright (C) 2000-2006 John Lim (ADOdb)
  7. # Copyright (C) 2007 Cliss XXI (GCourrier)
  8. # Copyright (C) 2006, 2007 Sylvain Beucler
  9. #
  10. # This file is part of Savane.
  11. #
  12. # Savane is free software: you can redistribute it and/or modify
  13. # it under the terms of the GNU Affero General Public License as
  14. # published by the Free Software Foundation, either version 3 of the
  15. # License, or (at your option) any later version.
  16. #
  17. # Savane is distributed in the hope that it will be useful,
  18. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. # GNU Affero General Public License for more details.
  21. #
  22. # You should have received a copy of the GNU Affero General Public License
  23. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. define('DB_AUTOQUERY_INSERT', 1);
  25. define('DB_AUTOQUERY_UPDATE', 2);
  26. function db_connect()
  27. {
  28. global $sys_dbhost,$sys_dbuser,$sys_dbpasswd,$conn,$sys_dbname;
  29. // Test the presence of php-mysql - you get a puzzling blank page
  30. // when it's not installed
  31. if (!extension_loaded('mysql')) {
  32. echo "Please install the MySQL extension for PHP:
  33. <ul>
  34. <li>Debian-based: <code>aptitude install php4-mysql</code>
  35. or <code>aptitude install php5-mysql</code></li>
  36. <li>Fedora Core: <code>yum install php-mysql</code></li>
  37. </ul>";
  38. echo "Check the <a href='{$GLOBALS['sys_url_topdir']}/testconfig.php'>configuration
  39. page</a> and the <a href='http://php.net/mysql'>PHP website</a> for
  40. more information.<br />";
  41. echo "Once the extension is installed, please restart Apache.";
  42. exit;
  43. }
  44. $conn = @mysql_connect($sys_dbhost,$sys_dbuser,$sys_dbpasswd);
  45. if (!$conn or !mysql_select_db($sys_dbname, $conn)) {
  46. echo "Failed to connect to database: " . mysql_error() . "<br />";
  47. echo "Please contact as soon as possible server administrators {$GLOBALS['sys_email_adress']}.<br />";
  48. echo "Until this problem get fixed, you will not be able to use this site.";
  49. exit;
  50. }
  51. if (version_compare(PHP_VERSION, '5.2.3', '>='))
  52. {
  53. mysql_set_charset('utf8', $conn);
  54. }
  55. else
  56. {
  57. // Not available in Etch (5.2.0 < 5.2.3...) - using a
  58. // work-around meanwhile. Apparently this means
  59. // mysql_real_escape_string() isn't aware of the charset, hence
  60. // why this isn't recommended.
  61. mysql_query('SET NAMES utf8');
  62. }
  63. }
  64. // sprinf-like function to auto-escape SQL strings
  65. // db_query_escape("SELECT * FROM user WHERE user_name='%s'", $_GET['myuser']);
  66. function db_query_escape()
  67. {
  68. $num_args = func_num_args();
  69. if ($num_args < 1)
  70. util_die(_("db_query_escape: Missing parameter"));
  71. $args = func_get_args();
  72. // Escape all params except the query itself
  73. for ($i = 1; $i < $num_args; $i++)
  74. $args[$i] = mysql_real_escape_string($args[$i]);
  75. $query = call_user_func_array('sprintf', $args);
  76. return db_query($query);
  77. }
  78. // Substitute '?' with one of the values in the $inputarr array,
  79. // properly escaped for inclusion in an SQL query
  80. function db_variable_binding($sql, $inputarr=null) {
  81. $sql_expanded = $sql;
  82. if ($inputarr) {
  83. if (!is_array($inputarr))
  84. util_die("db_variable_binding: \$inputarr is not an array. Query is: <code>"
  85. . htmlspecialchars($sql) . "</code>, \$inputarr is <code>"
  86. . print_r($inputarr, 1) . "</code>");
  87. $sql_exploded = explode('?', $sql);
  88. $i = 0;
  89. $sql_expanded = '';
  90. //Use each() instead of foreach to reduce memory usage -mikefedyk
  91. while(list(, $v) = each($inputarr)) {
  92. $sql_expanded .= $sql_exploded[$i];
  93. // from Ron Baldwin <ron.baldwin#sourceprose.com>
  94. // Only quote string types
  95. $typ = gettype($v);
  96. if ($typ == 'string')
  97. $sql_expanded .= "'" . mysql_real_escape_string($v) . "'";
  98. else if ($typ == 'double')
  99. $sql_expanded .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1
  100. else if ($typ == 'boolean')
  101. $sql_expanded .= $v ? '1' : '0';
  102. else if ($typ == 'object')
  103. util_die("Don't use db_execute with objects.");
  104. else if ($v === null)
  105. $sql_expanded .= 'NULL';
  106. else
  107. $sql_expanded .= $v;
  108. $i += 1;
  109. }
  110. $match = true;
  111. if (isset($sql_exploded[$i])) {
  112. $sql_expanded .= $sql_exploded[$i];
  113. if ($i+1 != sizeof($sql_exploded))
  114. $match = false;
  115. } else {
  116. $match = false;
  117. }
  118. if (!$match) {
  119. util_die("db_variable_binding: input array does not match query: <pre>"
  120. .htmlspecialchars($sql)
  121. ."<br />"
  122. .print_r($inputarr, true));
  123. }
  124. }
  125. return $sql_expanded;
  126. }
  127. /* Like ADOConnection->AutoExecute, without ignoring non-existing
  128. fields (you'll get a nice mysql_error() instead) and with a modified
  129. argument list to allow variable binding in the where clause
  130. This allows hopefully more reable lengthy INSERT and UPDATE queries.
  131. Check http://phplens.com/adodb/reference.functions.getupdatesql.html ,
  132. http://phplens.com/adodb/tutorial.generating.update.and.insert.sql.html
  133. and adodb.inc.php
  134. eg:
  135. $success = db_autoexecute('user', array('realname' => $newvalue),
  136. DB_AUTOQUERY_UPDATE,
  137. "user_id=?", array(user_getid()));
  138. */
  139. function db_autoexecute($table, $dict, $mode=DB_AUTOQUERY_INSERT,
  140. $where_condition=false, $where_inputarr=null)
  141. {
  142. // table name validation and quoting
  143. $tables = preg_split('/[\s,]+/', $table);
  144. $tables_string = '';
  145. $first = true;
  146. foreach ($tables as $table)
  147. {
  148. if (!preg_match('/^[a-zA-Z_][a-zA-Z0-9_]+$/', $table))
  149. util_die("db_autoexecute: invalid table name: " . htmlspecialchars($table));
  150. if ($first)
  151. {
  152. $tables_string = "`$table`";
  153. $first = false;
  154. }
  155. else
  156. {
  157. $tables_string .= ",`$table`";
  158. }
  159. }
  160. switch((string) $mode) {
  161. case 'INSERT':
  162. case '1':
  163. // Quote fields to avoid problem with reserved words (bug #8898@gna)
  164. // TODO: do connections with ANSI_QUOTES mode and use the standard
  165. // "'" field delimiter
  166. $first = true;
  167. foreach (array_keys($dict) as $field)
  168. {
  169. if ($first)
  170. {
  171. $fields = "`$field`";
  172. $first = false;
  173. }
  174. else
  175. {
  176. $fields .= ",`$field`";
  177. }
  178. }
  179. // $fields = `date`,`summary`,...
  180. $question_marks = implode(',', array_fill(0, count($dict), '?')); // ?,?,...
  181. return db_execute("INSERT INTO $tables_string ($fields) VALUES ($question_marks)",
  182. array_values($dict));
  183. break;
  184. case 'UPDATE':
  185. case '2':
  186. $sql_fields = '';
  187. $values = array();
  188. while (list($field,$value) = each($dict)) {
  189. $sql_fields .= "`$field`=?,";
  190. $values[] = $value;
  191. }
  192. $sql_fields = rtrim($sql_fields, ',');
  193. $values = array_merge($values, $where_inputarr);
  194. $where_sql = $where_condition ? "WHERE $where_condition" : '';
  195. return db_execute("UPDATE $tables_string SET $sql_fields $where_sql", $values);
  196. break;
  197. default:
  198. // no default
  199. }
  200. util_die("db_autoexecute: unknown mode=$mode");
  201. }
  202. /* Like ADOConnection->Execute, with variables binding emulation for
  203. MySQL, but simpler (not 2D-array, namely). Example:
  204. db_execute("SELECT * FROM utilisateur WHERE name=?", array("Gogol d'Algol"));
  205. 'db_autoexecute' replaces '?' with the matching parameter, taking its
  206. type into account (int -> int, string -> quoted string, float ->
  207. canonical representation, etc.)
  208. Check http://phplens.com/adodb/reference.functions.execute.html and
  209. adodb.inc.php
  210. */
  211. function db_execute($sql, $inputarr=null)
  212. {
  213. # echo a; # makes xdebug produce a stacktrace
  214. $expanded_sql = db_variable_binding($sql, $inputarr);
  215. return db_query($expanded_sql);
  216. }
  217. function db_query($qstring,$print=0)
  218. {
  219. // echo a; // makes xdebug produce a stacktrace
  220. // Store query for recap display
  221. if ($GLOBALS['sys_debug_on']) {
  222. $GLOBALS['debug_query_count']++;
  223. $backtrace = debug_backtrace();
  224. $outside = null;
  225. foreach ($backtrace as $step) {
  226. if ($step['file'] != __FILE__) {
  227. $outside = $step;
  228. break;
  229. }
  230. }
  231. // strip installation prefix
  232. $relative_path = str_replace($GLOBALS['sys_www_topdir'].'/', '', $outside['file']);
  233. $location = "$relative_path:{$outside['line']}";
  234. array_push($GLOBALS['debug_queries'], array($qstring, $location));
  235. }
  236. if ($GLOBALS['sys_debug_sqlprofiler'] && extension_loaded('XCache'))
  237. {
  238. $backtrace = debug_backtrace();
  239. $outside = null;
  240. foreach ($backtrace as $step) {
  241. if ($step['file'] != __FILE__) {
  242. $outside = $step;
  243. break;
  244. }
  245. }
  246. // strip installation prefix
  247. $relative_path = str_replace($GLOBALS['sys_www_topdir'].'/', '', $outside['file']);
  248. $location = "$relative_path:{$outside['line']}";
  249. xcache_inc($location);
  250. }
  251. if ($print)
  252. {
  253. print "<pre>[";
  254. print_r($qstring);
  255. print "</pre>]";
  256. }
  257. $GLOBALS['db_qhandle'] = mysql_query($qstring);
  258. if (!$GLOBALS['db_qhandle']) {
  259. // throw new Exception('db_query: SQL query error in ['.$qstring.']: ' . mysql_error());
  260. util_die('db_query: SQL query error ' .
  261. '<em>'.mysql_error().'</em> in ['
  262. . htmlspecialchars($qstring) . ']');
  263. }
  264. return $GLOBALS['db_qhandle'];
  265. }
  266. function db_numrows($qhandle)
  267. {
  268. # return only if qhandle exists, otherwise 0
  269. if ($qhandle) {
  270. return mysql_numrows($qhandle);
  271. } else {
  272. return 0;
  273. }
  274. }
  275. function db_free_result($qhandle)
  276. {
  277. return mysql_free_result($qhandle);
  278. }
  279. function db_result($qhandle,$row,$field)
  280. {
  281. return mysql_result($qhandle,$row,$field);
  282. }
  283. function db_numfields($lhandle)
  284. {
  285. return mysql_numfields($lhandle);
  286. }
  287. function db_fieldname($lhandle,$fnumber)
  288. {
  289. return mysql_field_name($lhandle,$fnumber);
  290. }
  291. function db_affected_rows($qhandle)
  292. {
  293. return mysql_affected_rows();
  294. }
  295. function db_fetch_array($qhandle = 0)
  296. {
  297. if ($qhandle) {
  298. return mysql_fetch_array($qhandle);
  299. } else {
  300. if (isset($GLOBALS['db_qhandle'])) {
  301. return mysql_fetch_array($GLOBALS['db_qhandle']);
  302. } else {
  303. return (array());
  304. }
  305. }
  306. }
  307. function db_insertid($qhandle)
  308. {
  309. return mysql_insert_id();
  310. }
  311. function db_error()
  312. {
  313. return mysql_error();
  314. }
  315. # Return an sql insert command taking in input a qhandle:
  316. # it is supposed to ease copy a a row into another, ignoring the autoincrement
  317. # field + replacing another field value (like group_id)
  318. function db_createinsertinto ($result, $table, $row, $autoincrement_fieldname, $replace_fieldname='zxry', $replace_value='axa')
  319. {
  320. $fields = array();
  321. for ($i = 0; $i < db_numfields($result); $i++)
  322. {
  323. $fieldname = db_fieldname($result, $i);
  324. // Create the sql by ignoring the autoincremental id
  325. if ($fieldname != $autoincrement_fieldname)
  326. {
  327. // If the value is empty
  328. if (db_result($result, $row, $fieldname) != NULL)
  329. {
  330. // Replace another field
  331. if ($fieldname == $replace_fieldname)
  332. {
  333. $fields[$fieldname] = $replace_value;
  334. }
  335. else
  336. {
  337. $fields[$fieldname] = db_result($result, $row, $fieldname);
  338. }
  339. }
  340. }
  341. }
  342. // No fields? Ignore
  343. if (count($fields) == 0)
  344. { return 0; }
  345. return db_autoexecute($table, $fields, DB_AUTOQUERY_INSERT);
  346. }