443
by dcoles
Added Forum application along with unmodifed version of phpBB3 "Olympus" 3.0.0 |
1 |
<?php
|
2 |
/**
|
|
3 |
*
|
|
4 |
* @package dbal
|
|
5 |
* @version $Id: dbal.php,v 1.70 2007/12/06 12:27:53 acydburn Exp $
|
|
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 |
*/
|
|
14 |
if (!defined('IN_PHPBB')) |
|
15 |
{
|
|
16 |
exit; |
|
17 |
}
|
|
18 |
||
19 |
/**
|
|
20 |
* Database Abstraction Layer
|
|
21 |
* @package dbal
|
|
22 |
*/
|
|
23 |
class dbal |
|
24 |
{
|
|
25 |
var $db_connect_id; |
|
26 |
var $query_result; |
|
27 |
var $return_on_error = false; |
|
28 |
var $transaction = false; |
|
29 |
var $sql_time = 0; |
|
30 |
var $num_queries = array(); |
|
31 |
var $open_queries = array(); |
|
32 |
||
33 |
var $curtime = 0; |
|
34 |
var $query_hold = ''; |
|
35 |
var $html_hold = ''; |
|
36 |
var $sql_report = ''; |
|
37 |
||
38 |
var $persistency = false; |
|
39 |
var $user = ''; |
|
40 |
var $server = ''; |
|
41 |
var $dbname = ''; |
|
42 |
||
43 |
// Set to true if error triggered
|
|
44 |
var $sql_error_triggered = false; |
|
45 |
||
46 |
// Holding the last sql query on sql error
|
|
47 |
var $sql_error_sql = ''; |
|
48 |
||
49 |
// Holding transaction count
|
|
50 |
var $transactions = 0; |
|
51 |
||
52 |
// Supports multi inserts?
|
|
53 |
var $multi_insert = false; |
|
54 |
||
55 |
/**
|
|
56 |
* Current sql layer
|
|
57 |
*/
|
|
58 |
var $sql_layer = ''; |
|
59 |
||
60 |
/**
|
|
61 |
* Wildcards for matching any (%) or exactly one (_) character within LIKE expressions
|
|
62 |
*/
|
|
63 |
var $any_char; |
|
64 |
var $one_char; |
|
65 |
||
66 |
/**
|
|
67 |
* Constructor
|
|
68 |
*/
|
|
69 |
function dbal() |
|
70 |
{
|
|
71 |
$this->num_queries = array( |
|
72 |
'cached' => 0, |
|
73 |
'normal' => 0, |
|
74 |
'total' => 0, |
|
75 |
);
|
|
76 |
||
77 |
// Fill default sql layer based on the class being called.
|
|
78 |
// This can be changed by the specified layer itself later if needed.
|
|
79 |
$this->sql_layer = substr(get_class($this), 5); |
|
80 |
||
81 |
// Do not change this please! This variable is used to easy the use of it - and is hardcoded.
|
|
82 |
$this->any_char = chr(0) . '%'; |
|
83 |
$this->one_char = chr(0) . '_'; |
|
84 |
}
|
|
85 |
||
86 |
/**
|
|
87 |
* return on error or display error message
|
|
88 |
*/
|
|
89 |
function sql_return_on_error($fail = false) |
|
90 |
{
|
|
91 |
$this->sql_error_triggered = false; |
|
92 |
$this->sql_error_sql = ''; |
|
93 |
||
94 |
$this->return_on_error = $fail; |
|
95 |
}
|
|
96 |
||
97 |
/**
|
|
98 |
* Return number of sql queries and cached sql queries used
|
|
99 |
*/
|
|
100 |
function sql_num_queries($cached = false) |
|
101 |
{
|
|
102 |
return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal']; |
|
103 |
}
|
|
104 |
||
105 |
/**
|
|
106 |
* Add to query count
|
|
107 |
*/
|
|
108 |
function sql_add_num_queries($cached = false) |
|
109 |
{
|
|
110 |
$this->num_queries['cached'] += ($cached !== false) ? 1 : 0; |
|
111 |
$this->num_queries['normal'] += ($cached !== false) ? 0 : 1; |
|
112 |
$this->num_queries['total'] += 1; |
|
113 |
}
|
|
114 |
||
115 |
/**
|
|
116 |
* DBAL garbage collection, close sql connection
|
|
117 |
*/
|
|
118 |
function sql_close() |
|
119 |
{
|
|
120 |
if (!$this->db_connect_id) |
|
121 |
{
|
|
122 |
return false; |
|
123 |
}
|
|
124 |
||
125 |
if ($this->transaction) |
|
126 |
{
|
|
127 |
do
|
|
128 |
{
|
|
129 |
$this->sql_transaction('commit'); |
|
130 |
}
|
|
131 |
while ($this->transaction); |
|
132 |
}
|
|
133 |
||
134 |
foreach ($this->open_queries as $query_id) |
|
135 |
{
|
|
136 |
$this->sql_freeresult($query_id); |
|
137 |
}
|
|
138 |
||
139 |
return $this->_sql_close(); |
|
140 |
}
|
|
141 |
||
142 |
/**
|
|
143 |
* Build LIMIT query
|
|
144 |
* Doing some validation here.
|
|
145 |
*/
|
|
146 |
function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) |
|
147 |
{
|
|
148 |
if (empty($query)) |
|
149 |
{
|
|
150 |
return false; |
|
151 |
}
|
|
152 |
||
153 |
// Never use a negative total or offset
|
|
154 |
$total = ($total < 0) ? 0 : $total; |
|
155 |
$offset = ($offset < 0) ? 0 : $offset; |
|
156 |
||
157 |
return $this->_sql_query_limit($query, $total, $offset, $cache_ttl); |
|
158 |
}
|
|
159 |
||
160 |
/**
|
|
161 |
* Fetch all rows
|
|
162 |
*/
|
|
163 |
function sql_fetchrowset($query_id = false) |
|
164 |
{
|
|
165 |
if ($query_id === false) |
|
166 |
{
|
|
167 |
$query_id = $this->query_result; |
|
168 |
}
|
|
169 |
||
170 |
if ($query_id !== false) |
|
171 |
{
|
|
172 |
$result = array(); |
|
173 |
while ($row = $this->sql_fetchrow($query_id)) |
|
174 |
{
|
|
175 |
$result[] = $row; |
|
176 |
}
|
|
177 |
||
178 |
return $result; |
|
179 |
}
|
|
180 |
||
181 |
return false; |
|
182 |
}
|
|
183 |
||
184 |
/**
|
|
185 |
* Fetch field
|
|
186 |
* if rownum is false, the current row is used, else it is pointing to the row (zero-based)
|
|
187 |
*/
|
|
188 |
function sql_fetchfield($field, $rownum = false, $query_id = false) |
|
189 |
{
|
|
190 |
global $cache; |
|
191 |
||
192 |
if ($query_id === false) |
|
193 |
{
|
|
194 |
$query_id = $this->query_result; |
|
195 |
}
|
|
196 |
||
197 |
if ($query_id !== false) |
|
198 |
{
|
|
199 |
if ($rownum !== false) |
|
200 |
{
|
|
201 |
$this->sql_rowseek($rownum, $query_id); |
|
202 |
}
|
|
203 |
||
204 |
if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) |
|
205 |
{
|
|
206 |
return $cache->sql_fetchfield($query_id, $field); |
|
207 |
}
|
|
208 |
||
209 |
$row = $this->sql_fetchrow($query_id); |
|
210 |
return (isset($row[$field])) ? $row[$field] : false; |
|
211 |
}
|
|
212 |
||
213 |
return false; |
|
214 |
}
|
|
215 |
||
216 |
/**
|
|
217 |
* Correctly adjust LIKE expression for special characters
|
|
218 |
* Some DBMS are handling them in a different way
|
|
219 |
*
|
|
220 |
* @param string $expression The expression to use. Every wildcard is escaped, except $this->any_char and $this->one_char
|
|
221 |
* @return string LIKE expression including the keyword!
|
|
222 |
*/
|
|
223 |
function sql_like_expression($expression) |
|
224 |
{
|
|
225 |
$expression = str_replace(array('_', '%'), array("\_", "\%"), $expression); |
|
226 |
$expression = str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); |
|
227 |
||
228 |
return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\''); |
|
229 |
}
|
|
230 |
||
231 |
/**
|
|
232 |
* SQL Transaction
|
|
233 |
* @access private
|
|
234 |
*/
|
|
235 |
function sql_transaction($status = 'begin') |
|
236 |
{
|
|
237 |
switch ($status) |
|
238 |
{
|
|
239 |
case 'begin': |
|
240 |
// If we are within a transaction we will not open another one, but enclose the current one to not loose data (prevening auto commit)
|
|
241 |
if ($this->transaction) |
|
242 |
{
|
|
243 |
$this->transactions++; |
|
244 |
return true; |
|
245 |
}
|
|
246 |
||
247 |
$result = $this->_sql_transaction('begin'); |
|
248 |
||
249 |
if (!$result) |
|
250 |
{
|
|
251 |
$this->sql_error(); |
|
252 |
}
|
|
253 |
||
254 |
$this->transaction = true; |
|
255 |
break; |
|
256 |
||
257 |
case 'commit': |
|
258 |
// If there was a previously opened transaction we do not commit yet... but count back the number of inner transactions
|
|
259 |
if ($this->transaction && $this->transactions) |
|
260 |
{
|
|
261 |
$this->transactions--; |
|
262 |
return true; |
|
263 |
}
|
|
264 |
||
265 |
$result = $this->_sql_transaction('commit'); |
|
266 |
||
267 |
if (!$result) |
|
268 |
{
|
|
269 |
$this->sql_error(); |
|
270 |
}
|
|
271 |
||
272 |
$this->transaction = false; |
|
273 |
$this->transactions = 0; |
|
274 |
break; |
|
275 |
||
276 |
case 'rollback': |
|
277 |
$result = $this->_sql_transaction('rollback'); |
|
278 |
$this->transaction = false; |
|
279 |
$this->transactions = 0; |
|
280 |
break; |
|
281 |
||
282 |
default: |
|
283 |
$result = $this->_sql_transaction($status); |
|
284 |
break; |
|
285 |
}
|
|
286 |
||
287 |
return $result; |
|
288 |
}
|
|
289 |
||
290 |
/**
|
|
291 |
* Build sql statement from array for insert/update/select statements
|
|
292 |
*
|
|
293 |
* Idea for this from Ikonboard
|
|
294 |
* Possible query values: INSERT, INSERT_SELECT, MULTI_INSERT, UPDATE, SELECT
|
|
295 |
*
|
|
296 |
*/
|
|
297 |
function sql_build_array($query, $assoc_ary = false) |
|
298 |
{
|
|
299 |
if (!is_array($assoc_ary)) |
|
300 |
{
|
|
301 |
return false; |
|
302 |
}
|
|
303 |
||
304 |
$fields = $values = array(); |
|
305 |
||
306 |
if ($query == 'INSERT' || $query == 'INSERT_SELECT') |
|
307 |
{
|
|
308 |
foreach ($assoc_ary as $key => $var) |
|
309 |
{
|
|
310 |
$fields[] = $key; |
|
311 |
||
312 |
if (is_array($var) && is_string($var[0])) |
|
313 |
{
|
|
314 |
// This is used for INSERT_SELECT(s)
|
|
315 |
$values[] = $var[0]; |
|
316 |
}
|
|
317 |
else
|
|
318 |
{
|
|
319 |
$values[] = $this->_sql_validate_value($var); |
|
320 |
}
|
|
321 |
}
|
|
322 |
||
323 |
$query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' '; |
|
324 |
}
|
|
325 |
else if ($query == 'MULTI_INSERT') |
|
326 |
{
|
|
327 |
$ary = array(); |
|
328 |
foreach ($assoc_ary as $id => $sql_ary) |
|
329 |
{
|
|
330 |
// If by accident the sql array is only one-dimensional we build a normal insert statement
|
|
331 |
if (!is_array($sql_ary)) |
|
332 |
{
|
|
333 |
return $this->sql_build_array('INSERT', $assoc_ary); |
|
334 |
}
|
|
335 |
||
336 |
$values = array(); |
|
337 |
foreach ($sql_ary as $key => $var) |
|
338 |
{
|
|
339 |
$values[] = $this->_sql_validate_value($var); |
|
340 |
}
|
|
341 |
$ary[] = '(' . implode(', ', $values) . ')'; |
|
342 |
}
|
|
343 |
||
344 |
$query = ' (' . implode(', ', array_keys($assoc_ary[0])) . ') VALUES ' . implode(', ', $ary); |
|
345 |
}
|
|
346 |
else if ($query == 'UPDATE' || $query == 'SELECT') |
|
347 |
{
|
|
348 |
$values = array(); |
|
349 |
foreach ($assoc_ary as $key => $var) |
|
350 |
{
|
|
351 |
$values[] = "$key = " . $this->_sql_validate_value($var); |
|
352 |
}
|
|
353 |
$query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); |
|
354 |
}
|
|
355 |
||
356 |
return $query; |
|
357 |
}
|
|
358 |
||
359 |
/**
|
|
360 |
* Build IN or NOT IN sql comparison string, uses <> or = on single element
|
|
361 |
* arrays to improve comparison speed
|
|
362 |
*
|
|
363 |
* @access public
|
|
364 |
* @param string $field name of the sql column that shall be compared
|
|
365 |
* @param array $array array of values that are allowed (IN) or not allowed (NOT IN)
|
|
366 |
* @param bool $negate true for NOT IN (), false for IN () (default)
|
|
367 |
* @param bool $allow_empty_set If true, allow $array to be empty, this function will return 1=1 or 1=0 then. Default to false.
|
|
368 |
*/
|
|
369 |
function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) |
|
370 |
{
|
|
371 |
if (!sizeof($array)) |
|
372 |
{
|
|
373 |
if (!$allow_empty_set) |
|
374 |
{
|
|
375 |
// Print the backtrace to help identifying the location of the problematic code
|
|
376 |
$this->sql_error('No values specified for SQL IN comparison'); |
|
377 |
}
|
|
378 |
else
|
|
379 |
{
|
|
380 |
// NOT IN () actually means everything so use a tautology
|
|
381 |
if ($negate) |
|
382 |
{
|
|
383 |
return '1=1'; |
|
384 |
}
|
|
385 |
// IN () actually means nothing so use a contradiction
|
|
386 |
else
|
|
387 |
{
|
|
388 |
return '1=0'; |
|
389 |
}
|
|
390 |
}
|
|
391 |
}
|
|
392 |
||
393 |
if (!is_array($array)) |
|
394 |
{
|
|
395 |
$array = array($array); |
|
396 |
}
|
|
397 |
||
398 |
if (sizeof($array) == 1) |
|
399 |
{
|
|
400 |
@reset($array); |
|
401 |
$var = current($array); |
|
402 |
||
403 |
return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var); |
|
404 |
}
|
|
405 |
else
|
|
406 |
{
|
|
407 |
return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')'; |
|
408 |
}
|
|
409 |
}
|
|
410 |
||
411 |
/**
|
|
412 |
* Run more than one insert statement.
|
|
413 |
*
|
|
414 |
* @param string $table table name to run the statements on
|
|
415 |
* @param array &$sql_ary multi-dimensional array holding the statement data.
|
|
416 |
*
|
|
417 |
* @return bool false if no statements were executed.
|
|
418 |
* @access public
|
|
419 |
*/
|
|
420 |
function sql_multi_insert($table, &$sql_ary) |
|
421 |
{
|
|
422 |
if (!sizeof($sql_ary)) |
|
423 |
{
|
|
424 |
return false; |
|
425 |
}
|
|
426 |
||
427 |
if ($this->multi_insert) |
|
428 |
{
|
|
429 |
$this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('MULTI_INSERT', $sql_ary)); |
|
430 |
}
|
|
431 |
else
|
|
432 |
{
|
|
433 |
foreach ($sql_ary as $ary) |
|
434 |
{
|
|
435 |
if (!is_array($ary)) |
|
436 |
{
|
|
437 |
return false; |
|
438 |
}
|
|
439 |
||
440 |
$this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary)); |
|
441 |
}
|
|
442 |
}
|
|
443 |
||
444 |
return true; |
|
445 |
}
|
|
446 |
||
447 |
/**
|
|
448 |
* Function for validating values
|
|
449 |
* @access private
|
|
450 |
*/
|
|
451 |
function _sql_validate_value($var) |
|
452 |
{
|
|
453 |
if (is_null($var)) |
|
454 |
{
|
|
455 |
return 'NULL'; |
|
456 |
}
|
|
457 |
else if (is_string($var)) |
|
458 |
{
|
|
459 |
return "'" . $this->sql_escape($var) . "'"; |
|
460 |
}
|
|
461 |
else
|
|
462 |
{
|
|
463 |
return (is_bool($var)) ? intval($var) : $var; |
|
464 |
}
|
|
465 |
}
|
|
466 |
||
467 |
/**
|
|
468 |
* Build sql statement from array for select and select distinct statements
|
|
469 |
*
|
|
470 |
* Possible query values: SELECT, SELECT_DISTINCT
|
|
471 |
*/
|
|
472 |
function sql_build_query($query, $array) |
|
473 |
{
|
|
474 |
$sql = ''; |
|
475 |
switch ($query) |
|
476 |
{
|
|
477 |
case 'SELECT': |
|
478 |
case 'SELECT_DISTINCT'; |
|
479 |
||
480 |
$sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM '; |
|
481 |
||
482 |
$table_array = array(); |
|
483 |
foreach ($array['FROM'] as $table_name => $alias) |
|
484 |
{
|
|
485 |
if (is_array($alias)) |
|
486 |
{
|
|
487 |
foreach ($alias as $multi_alias) |
|
488 |
{
|
|
489 |
$table_array[] = $table_name . ' ' . $multi_alias; |
|
490 |
}
|
|
491 |
}
|
|
492 |
else
|
|
493 |
{
|
|
494 |
$table_array[] = $table_name . ' ' . $alias; |
|
495 |
}
|
|
496 |
}
|
|
497 |
||
498 |
$sql .= $this->_sql_custom_build('FROM', implode(', ', $table_array)); |
|
499 |
||
500 |
if (!empty($array['LEFT_JOIN'])) |
|
501 |
{
|
|
502 |
foreach ($array['LEFT_JOIN'] as $join) |
|
503 |
{
|
|
504 |
$sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')'; |
|
505 |
}
|
|
506 |
}
|
|
507 |
||
508 |
if (!empty($array['WHERE'])) |
|
509 |
{
|
|
510 |
$sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']); |
|
511 |
}
|
|
512 |
||
513 |
if (!empty($array['GROUP_BY'])) |
|
514 |
{
|
|
515 |
$sql .= ' GROUP BY ' . $array['GROUP_BY']; |
|
516 |
}
|
|
517 |
||
518 |
if (!empty($array['ORDER_BY'])) |
|
519 |
{
|
|
520 |
$sql .= ' ORDER BY ' . $array['ORDER_BY']; |
|
521 |
}
|
|
522 |
||
523 |
break; |
|
524 |
}
|
|
525 |
||
526 |
return $sql; |
|
527 |
}
|
|
528 |
||
529 |
/**
|
|
530 |
* display sql error page
|
|
531 |
*/
|
|
532 |
function sql_error($sql = '') |
|
533 |
{
|
|
534 |
global $auth, $user, $config; |
|
535 |
||
536 |
// Set var to retrieve errored status
|
|
537 |
$this->sql_error_triggered = true; |
|
538 |
$this->sql_error_sql = $sql; |
|
539 |
||
540 |
$error = $this->_sql_error(); |
|
541 |
||
542 |
if (!$this->return_on_error) |
|
543 |
{
|
|
544 |
$message = 'SQL ERROR [ ' . $this->sql_layer . ' ]<br /><br />' . $error['message'] . ' [' . $error['code'] . ']'; |
|
545 |
||
546 |
// Show complete SQL error and path to administrators only
|
|
547 |
// Additionally show complete error on installation or if extended debug mode is enabled
|
|
548 |
// The DEBUG_EXTRA constant is for development only!
|
|
549 |
if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG_EXTRA')) |
|
550 |
{
|
|
551 |
// Print out a nice backtrace...
|
|
552 |
$backtrace = get_backtrace(); |
|
553 |
||
554 |
$message .= ($sql) ? '<br /><br />SQL<br /><br />' . htmlspecialchars($sql) : ''; |
|
555 |
$message .= ($backtrace) ? '<br /><br />BACKTRACE<br />' . $backtrace : ''; |
|
556 |
$message .= '<br />'; |
|
557 |
}
|
|
558 |
else
|
|
559 |
{
|
|
560 |
// If error occurs in initiating the session we need to use a pre-defined language string
|
|
561 |
// This could happen if the connection could not be established for example (then we are not able to grab the default language)
|
|
562 |
if (!isset($user->lang['SQL_ERROR_OCCURRED'])) |
|
563 |
{
|
|
564 |
$message .= '<br /><br />An sql error occurred while fetching this page. Please contact an administrator if this problem persists.'; |
|
565 |
}
|
|
566 |
else
|
|
567 |
{
|
|
568 |
if (!empty($config['board_contact'])) |
|
569 |
{
|
|
570 |
$message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'); |
|
571 |
}
|
|
572 |
else
|
|
573 |
{
|
|
574 |
$message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); |
|
575 |
}
|
|
576 |
}
|
|
577 |
}
|
|
578 |
||
579 |
if ($this->transaction) |
|
580 |
{
|
|
581 |
$this->sql_transaction('rollback'); |
|
582 |
}
|
|
583 |
||
584 |
if (strlen($message) > 1024) |
|
585 |
{
|
|
586 |
// We need to define $msg_long_text here to circumvent text stripping.
|
|
587 |
global $msg_long_text; |
|
588 |
$msg_long_text = $message; |
|
589 |
||
590 |
trigger_error(false, E_USER_ERROR); |
|
591 |
}
|
|
592 |
||
593 |
trigger_error($message, E_USER_ERROR); |
|
594 |
}
|
|
595 |
||
596 |
if ($this->transaction) |
|
597 |
{
|
|
598 |
$this->sql_transaction('rollback'); |
|
599 |
}
|
|
600 |
||
601 |
return $error; |
|
602 |
}
|
|
603 |
||
604 |
/**
|
|
605 |
* Explain queries
|
|
606 |
*/
|
|
607 |
function sql_report($mode, $query = '') |
|
608 |
{
|
|
609 |
global $cache, $starttime, $phpbb_root_path, $user; |
|
610 |
||
611 |
if (empty($_REQUEST['explain'])) |
|
612 |
{
|
|
613 |
return false; |
|
614 |
}
|
|
615 |
||
616 |
if (!$query && $this->query_hold != '') |
|
617 |
{
|
|
618 |
$query = $this->query_hold; |
|
619 |
}
|
|
620 |
||
621 |
switch ($mode) |
|
622 |
{
|
|
623 |
case 'display': |
|
624 |
if (!empty($cache)) |
|
625 |
{
|
|
626 |
$cache->unload(); |
|
627 |
}
|
|
628 |
$this->sql_close(); |
|
629 |
||
630 |
$mtime = explode(' ', microtime()); |
|
631 |
$totaltime = $mtime[0] + $mtime[1] - $starttime; |
|
632 |
||
633 |
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
|
634 |
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
|
|
635 |
<head>
|
|
636 |
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
|
637 |
<meta http-equiv="Content-Style-Type" content="text/css" />
|
|
638 |
<meta http-equiv="imagetoolbar" content="no" />
|
|
639 |
<title>SQL Report</title>
|
|
640 |
<link href="' . $phpbb_root_path . 'adm/style/admin.css" rel="stylesheet" type="text/css" media="screen" /> |
|
641 |
</head>
|
|
642 |
<body id="errorpage">
|
|
643 |
<div id="wrap">
|
|
644 |
<div id="page-header">
|
|
645 |
<a href="' . build_url('explain') . '">Return to previous page</a> |
|
646 |
</div>
|
|
647 |
<div id="page-body">
|
|
648 |
<div id="acp">
|
|
649 |
<div class="panel">
|
|
650 |
<span class="corners-top"><span></span></span>
|
|
651 |
<div id="content">
|
|
652 |
<h1>SQL Report</h1>
|
|
653 |
<br />
|
|
654 |
<p><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></p> |
|
655 |
||
656 |
<p>Time spent on ' . $this->sql_layer . ' queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></p> |
|
657 |
||
658 |
<br /><br />
|
|
659 |
' . $this->sql_report . ' |
|
660 |
</div>
|
|
661 |
<span class="corners-bottom"><span></span></span>
|
|
662 |
</div>
|
|
663 |
</div>
|
|
664 |
</div>
|
|
665 |
<div id="page-footer">
|
|
666 |
Powered by phpBB © 2000, 2002, 2005, 2007 <a href="http://www.phpbb.com/">phpBB Group</a>
|
|
667 |
</div>
|
|
668 |
</div>
|
|
669 |
</body>
|
|
670 |
</html>'; |
|
671 |
||
672 |
exit_handler(); |
|
673 |
||
674 |
break; |
|
675 |
||
676 |
case 'stop': |
|
677 |
$endtime = explode(' ', microtime()); |
|
678 |
$endtime = $endtime[0] + $endtime[1]; |
|
679 |
||
680 |
$this->sql_report .= ' |
|
681 |
||
682 |
<table cellspacing="1">
|
|
683 |
<thead>
|
|
684 |
<tr>
|
|
685 |
<th>Query #' . $this->num_queries['total'] . '</th> |
|
686 |
</tr>
|
|
687 |
</thead>
|
|
688 |
<tbody>
|
|
689 |
<tr>
|
|
690 |
<td class="row3"><textarea style="font-family:\'Courier New\',monospace;width:99%" rows="5" cols="10">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td> |
|
691 |
</tr>
|
|
692 |
</tbody>
|
|
693 |
</table>
|
|
694 |
|
|
695 |
' . $this->html_hold . ' |
|
696 |
||
697 |
<p style="text-align: center;">
|
|
698 |
'; |
|
699 |
||
700 |
if ($this->query_result) |
|
701 |
{
|
|
702 |
if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) |
|
703 |
{
|
|
704 |
$this->sql_report .= 'Affected rows: <b>' . $this->sql_affectedrows($this->query_result) . '</b> | '; |
|
705 |
}
|
|
706 |
$this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: <b>' . sprintf('%.5f', $endtime - $this->curtime) . 's</b>'; |
|
707 |
}
|
|
708 |
else
|
|
709 |
{
|
|
710 |
$error = $this->sql_error(); |
|
711 |
$this->sql_report .= '<b style="color: red">FAILED</b> - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); |
|
712 |
}
|
|
713 |
||
714 |
$this->sql_report .= '</p><br /><br />'; |
|
715 |
||
716 |
$this->sql_time += $endtime - $this->curtime; |
|
717 |
break; |
|
718 |
||
719 |
case 'start': |
|
720 |
$this->query_hold = $query; |
|
721 |
$this->html_hold = ''; |
|
722 |
||
723 |
$this->_sql_report($mode, $query); |
|
724 |
||
725 |
$this->curtime = explode(' ', microtime()); |
|
726 |
$this->curtime = $this->curtime[0] + $this->curtime[1]; |
|
727 |
||
728 |
break; |
|
729 |
||
730 |
case 'add_select_row': |
|
731 |
||
732 |
$html_table = func_get_arg(2); |
|
733 |
$row = func_get_arg(3); |
|
734 |
||
735 |
if (!$html_table && sizeof($row)) |
|
736 |
{
|
|
737 |
$html_table = true; |
|
738 |
$this->html_hold .= '<table cellspacing="1"><tr>'; |
|
739 |
||
740 |
foreach (array_keys($row) as $val) |
|
741 |
{
|
|
742 |
$this->html_hold .= '<th>' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '</th>'; |
|
743 |
}
|
|
744 |
$this->html_hold .= '</tr>'; |
|
745 |
}
|
|
746 |
$this->html_hold .= '<tr>'; |
|
747 |
||
748 |
$class = 'row1'; |
|
749 |
foreach (array_values($row) as $val) |
|
750 |
{
|
|
751 |
$class = ($class == 'row1') ? 'row2' : 'row1'; |
|
752 |
$this->html_hold .= '<td class="' . $class . '">' . (($val) ? $val : ' ') . '</td>'; |
|
753 |
}
|
|
754 |
$this->html_hold .= '</tr>'; |
|
755 |
||
756 |
return $html_table; |
|
757 |
||
758 |
break; |
|
759 |
||
760 |
case 'fromcache': |
|
761 |
||
762 |
$this->_sql_report($mode, $query); |
|
763 |
||
764 |
break; |
|
765 |
||
766 |
case 'record_fromcache': |
|
767 |
||
768 |
$endtime = func_get_arg(2); |
|
769 |
$splittime = func_get_arg(3); |
|
770 |
||
771 |
$time_cache = $endtime - $this->curtime; |
|
772 |
$time_db = $splittime - $endtime; |
|
773 |
$color = ($time_db > $time_cache) ? 'green' : 'red'; |
|
774 |
||
775 |
$this->sql_report .= '<table cellspacing="1"><thead><tr><th>Query results obtained from the cache</th></tr></thead><tbody><tr>'; |
|
776 |
$this->sql_report .= '<td class="row3"><textarea style="font-family:\'Courier New\',monospace;width:99%" rows="5" cols="10">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></tbody></table>'; |
|
777 |
$this->sql_report .= '<p style="text-align: center;">'; |
|
778 |
$this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p><br /><br />'; |
|
779 |
||
780 |
// Pad the start time to not interfere with page timing
|
|
781 |
$starttime += $time_db; |
|
782 |
||
783 |
break; |
|
784 |
||
785 |
default: |
|
786 |
||
787 |
$this->_sql_report($mode, $query); |
|
788 |
||
789 |
break; |
|
790 |
}
|
|
791 |
||
792 |
return true; |
|
793 |
}
|
|
794 |
}
|
|
795 |
||
796 |
/**
|
|
797 |
* This variable holds the class name to use later
|
|
798 |
*/
|
|
799 |
$sql_db = (!empty($dbms)) ? 'dbal_' . basename($dbms) : 'dbal'; |
|
800 |
||
801 |
?>
|