source: trunk/forum/includes/db/mysqli.php

Last change on this file was 400, checked in by george, 16 years ago
  • Přidáno: Nové forum phpBB 3.
File size: 10.1 KB
Line 
1<?php
2/**
3*
4* @package dbal
5* @version $Id: mysqli.php 8814 2008-09-04 12:01:47Z acydburn $
6* @copyright (c) 2005 phpBB Group
7* @license http://opensource.org/licenses/gpl-license.php GNU Public License
8*
9*/
10
11/**
12* @ignore
13*/
14if (!defined('IN_PHPBB'))
15{
16 exit;
17}
18
19include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
20
21/**
22* MySQLi Database Abstraction Layer
23* mysqli-extension has to be compiled with:
24* MySQL 4.1+ or MySQL 5.0+
25* @package dbal
26*/
27class dbal_mysqli extends dbal
28{
29 var $multi_insert = true;
30
31 /**
32 * Connect to server
33 */
34 function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false , $new_link = false)
35 {
36 $this->persistency = $persistency;
37 $this->user = $sqluser;
38 $this->server = $sqlserver;
39 $this->dbname = $database;
40 $port = (!$port) ? NULL : $port;
41
42 // Persistant connections not supported by the mysqli extension?
43 $this->db_connect_id = @mysqli_connect($this->server, $this->user, $sqlpassword, $this->dbname, $port);
44
45 if ($this->db_connect_id && $this->dbname != '')
46 {
47 @mysqli_query($this->db_connect_id, "SET NAMES 'utf8'");
48
49 // enforce strict mode on databases that support it
50 if (version_compare($this->sql_server_info(true), '5.0.2', '>='))
51 {
52 $result = @mysqli_query($this->db_connect_id, 'SELECT @@session.sql_mode AS sql_mode');
53 $row = @mysqli_fetch_assoc($result);
54 @mysqli_free_result($result);
55
56 $modes = array_map('trim', explode(',', $row['sql_mode']));
57
58 // TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES
59 if (!in_array('TRADITIONAL', $modes))
60 {
61 if (!in_array('STRICT_ALL_TABLES', $modes))
62 {
63 $modes[] = 'STRICT_ALL_TABLES';
64 }
65
66 if (!in_array('STRICT_TRANS_TABLES', $modes))
67 {
68 $modes[] = 'STRICT_TRANS_TABLES';
69 }
70 }
71
72 $mode = implode(',', $modes);
73 @mysqli_query($this->db_connect_id, "SET SESSION sql_mode='{$mode}'");
74 }
75 return $this->db_connect_id;
76 }
77
78 return $this->sql_error('');
79 }
80
81 /**
82 * Version information about used database
83 * @param bool $raw if true, only return the fetched sql_server_version
84 * @return string sql server version
85 */
86 function sql_server_info($raw = false)
87 {
88 global $cache;
89
90 if (empty($cache) || ($this->sql_server_version = $cache->get('mysqli_version')) === false)
91 {
92 $result = @mysqli_query($this->db_connect_id, 'SELECT VERSION() AS version');
93 $row = @mysqli_fetch_assoc($result);
94 @mysqli_free_result($result);
95
96 $this->sql_server_version = $row['version'];
97
98 if (!empty($cache))
99 {
100 $cache->put('mysqli_version', $this->sql_server_version);
101 }
102 }
103
104 return ($raw) ? $this->sql_server_version : 'MySQL(i) ' . $this->sql_server_version;
105 }
106
107 /**
108 * SQL Transaction
109 * @access private
110 */
111 function _sql_transaction($status = 'begin')
112 {
113 switch ($status)
114 {
115 case 'begin':
116 return @mysqli_autocommit($this->db_connect_id, false);
117 break;
118
119 case 'commit':
120 $result = @mysqli_commit($this->db_connect_id);
121 @mysqli_autocommit($this->db_connect_id, true);
122 return $result;
123 break;
124
125 case 'rollback':
126 $result = @mysqli_rollback($this->db_connect_id);
127 @mysqli_autocommit($this->db_connect_id, true);
128 return $result;
129 break;
130 }
131
132 return true;
133 }
134
135 /**
136 * Base query method
137 *
138 * @param string $query Contains the SQL query which shall be executed
139 * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
140 * @return mixed When casted to bool the returned value returns true on success and false on failure
141 *
142 * @access public
143 */
144 function sql_query($query = '', $cache_ttl = 0)
145 {
146 if ($query != '')
147 {
148 global $cache;
149
150 // EXPLAIN only in extra debug mode
151 if (defined('DEBUG_EXTRA'))
152 {
153 $this->sql_report('start', $query);
154 }
155
156 $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false;
157 $this->sql_add_num_queries($this->query_result);
158
159 if ($this->query_result === false)
160 {
161 if (($this->query_result = @mysqli_query($this->db_connect_id, $query)) === false)
162 {
163 $this->sql_error($query);
164 }
165
166 if (defined('DEBUG_EXTRA'))
167 {
168 $this->sql_report('stop', $query);
169 }
170
171 if ($cache_ttl && method_exists($cache, 'sql_save'))
172 {
173 $cache->sql_save($query, $this->query_result, $cache_ttl);
174 }
175 }
176 else if (defined('DEBUG_EXTRA'))
177 {
178 $this->sql_report('fromcache', $query);
179 }
180 }
181 else
182 {
183 return false;
184 }
185
186 return $this->query_result;
187 }
188
189 /**
190 * Build LIMIT query
191 */
192 function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
193 {
194 $this->query_result = false;
195
196 // if $total is set to 0 we do not want to limit the number of rows
197 if ($total == 0)
198 {
199 // MySQL 4.1+ no longer supports -1 in limit queries
200 $total = '18446744073709551615';
201 }
202
203 $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total);
204
205 return $this->sql_query($query, $cache_ttl);
206 }
207
208 /**
209 * Return number of affected rows
210 */
211 function sql_affectedrows()
212 {
213 return ($this->db_connect_id) ? @mysqli_affected_rows($this->db_connect_id) : false;
214 }
215
216 /**
217 * Fetch current row
218 */
219 function sql_fetchrow($query_id = false)
220 {
221 global $cache;
222
223 if ($query_id === false)
224 {
225 $query_id = $this->query_result;
226 }
227
228 if (!is_object($query_id) && isset($cache->sql_rowset[$query_id]))
229 {
230 return $cache->sql_fetchrow($query_id);
231 }
232
233 return ($query_id !== false) ? @mysqli_fetch_assoc($query_id) : false;
234 }
235
236 /**
237 * Seek to given row number
238 * rownum is zero-based
239 */
240 function sql_rowseek($rownum, &$query_id)
241 {
242 global $cache;
243
244 if ($query_id === false)
245 {
246 $query_id = $this->query_result;
247 }
248
249 if (!is_object($query_id) && isset($cache->sql_rowset[$query_id]))
250 {
251 return $cache->sql_rowseek($rownum, $query_id);
252 }
253
254 return ($query_id !== false) ? @mysqli_data_seek($query_id, $rownum) : false;
255 }
256
257 /**
258 * Get last inserted id after insert statement
259 */
260 function sql_nextid()
261 {
262 return ($this->db_connect_id) ? @mysqli_insert_id($this->db_connect_id) : false;
263 }
264
265 /**
266 * Free sql result
267 */
268 function sql_freeresult($query_id = false)
269 {
270 global $cache;
271
272 if ($query_id === false)
273 {
274 $query_id = $this->query_result;
275 }
276
277 if (!is_object($query_id) && isset($cache->sql_rowset[$query_id]))
278 {
279 return $cache->sql_freeresult($query_id);
280 }
281
282 return @mysqli_free_result($query_id);
283 }
284
285 /**
286 * Escape string used in sql query
287 */
288 function sql_escape($msg)
289 {
290 return @mysqli_real_escape_string($this->db_connect_id, $msg);
291 }
292
293 /**
294 * Build LIKE expression
295 * @access private
296 */
297 function _sql_like_expression($expression)
298 {
299 return $expression;
300 }
301
302 /**
303 * Build db-specific query data
304 * @access private
305 */
306 function _sql_custom_build($stage, $data)
307 {
308 switch ($stage)
309 {
310 case 'FROM':
311 $data = '(' . $data . ')';
312 break;
313 }
314
315 return $data;
316 }
317
318 /**
319 * return sql error array
320 * @access private
321 */
322 function _sql_error()
323 {
324 if (!$this->db_connect_id)
325 {
326 return array(
327 'message' => @mysqli_connect_error(),
328 'code' => @mysqli_connect_errno()
329 );
330 }
331
332 return array(
333 'message' => @mysqli_error($this->db_connect_id),
334 'code' => @mysqli_errno($this->db_connect_id)
335 );
336 }
337
338 /**
339 * Close sql connection
340 * @access private
341 */
342 function _sql_close()
343 {
344 return @mysqli_close($this->db_connect_id);
345 }
346
347 /**
348 * Build db-specific report
349 * @access private
350 */
351 function _sql_report($mode, $query = '')
352 {
353 static $test_prof;
354
355 // current detection method, might just switch to see the existance of INFORMATION_SCHEMA.PROFILING
356 if ($test_prof === null)
357 {
358 $test_prof = false;
359 if (strpos(mysqli_get_server_info($this->db_connect_id), 'community') !== false)
360 {
361 $ver = mysqli_get_server_version($this->db_connect_id);
362 if ($ver >= 50037 && $ver < 50100)
363 {
364 $test_prof = true;
365 }
366 }
367 }
368
369 switch ($mode)
370 {
371 case 'start':
372
373 $explain_query = $query;
374 if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
375 {
376 $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
377 }
378 else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
379 {
380 $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
381 }
382
383 if (preg_match('/^SELECT/', $explain_query))
384 {
385 $html_table = false;
386
387 // begin profiling
388 if ($test_prof)
389 {
390 @mysqli_query($this->db_connect_id, 'SET profiling = 1;');
391 }
392
393 if ($result = @mysqli_query($this->db_connect_id, "EXPLAIN $explain_query"))
394 {
395 while ($row = @mysqli_fetch_assoc($result))
396 {
397 $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
398 }
399 }
400 @mysqli_free_result($result);
401
402 if ($html_table)
403 {
404 $this->html_hold .= '</table>';
405 }
406
407 if ($test_prof)
408 {
409 $html_table = false;
410
411 // get the last profile
412 if ($result = @mysqli_query($this->db_connect_id, 'SHOW PROFILE ALL;'))
413 {
414 $this->html_hold .= '<br />';
415 while ($row = @mysqli_fetch_assoc($result))
416 {
417 // make <unknown> HTML safe
418 if (!empty($row['Source_function']))
419 {
420 $row['Source_function'] = str_replace(array('<', '>'), array('&lt;', '&gt;'), $row['Source_function']);
421 }
422
423 // remove unsupported features
424 foreach ($row as $key => $val)
425 {
426 if ($val === null)
427 {
428 unset($row[$key]);
429 }
430 }
431 $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
432 }
433 }
434 @mysqli_free_result($result);
435
436 if ($html_table)
437 {
438 $this->html_hold .= '</table>';
439 }
440
441 @mysqli_query($this->db_connect_id, 'SET profiling = 0;');
442 }
443 }
444
445 break;
446
447 case 'fromcache':
448 $endtime = explode(' ', microtime());
449 $endtime = $endtime[0] + $endtime[1];
450
451 $result = @mysqli_query($this->db_connect_id, $query);
452 while ($void = @mysqli_fetch_assoc($result))
453 {
454 // Take the time spent on parsing rows into account
455 }
456 @mysqli_free_result($result);
457
458 $splittime = explode(' ', microtime());
459 $splittime = $splittime[0] + $splittime[1];
460
461 $this->sql_report('record_fromcache', $query, $endtime, $splittime);
462
463 break;
464 }
465 }
466}
467
468?>
Note: See TracBrowser for help on using the repository browser.