Add Decorator.js to do the nav javascript stuff
[isso.git] / Db.php
1 <?php
2 /*=====================================================================*\
3 || ###################################################################
4 || # Blue Static ISSO Framework
5 || # Copyright (c)2005-2008 Blue Static
6 || #
7 || # This program is free software; you can redistribute it and/or modify
8 || # it under the terms of the GNU General Public License as published by
9 || # the Free Software Foundation; version 2 of the License.
10 || #
11 || # This program is distributed in the hope that it will be useful, but
12 || # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 || # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 || # more details.
15 || #
16 || # You should have received a copy of the GNU General Public License along
17 || # with this program; if not, write to the Free Software Foundation, Inc.,
18 || # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 || ###################################################################
20 \*=====================================================================*/
21
22 /**
23 * Abstract Database Layer (Db.php)
24 *
25 * @package ISSO
26 */
27
28 require_once(ISSO . '/Functions.php');
29
30 /**
31 * Abstract Database Layer
32 *
33 * This class provides an abstract template for all RDBMS layers. All
34 * ISSO abstraction layers should inherit this class. It provides error
35 * reporting, SQL analysis, and general connection functionality.
36 *
37 * Constants:
38 * ISSO_SHOW_QUERIES_LIVE - Show queries in page output as they are sent
39 *
40 * @author Blue Static
41 * @copyright Copyright (c)2005 - 2008, Blue Static
42 * @package ISSO
43 *
44 */
45 abstract class BSDb
46 {
47 /**
48 * Determines whether or not errors should be shown
49 * @var bool
50 */
51 public $showerrors = true;
52
53 /**
54 * Current error number
55 * @var integer
56 */
57 protected $errnum = 0;
58
59 /**
60 * Description of current error
61 * @var string
62 */
63 protected $errstr = '';
64
65 /**
66 * Currend open database connection
67 * @var integer
68 */
69 protected $dblink = null;
70
71 /**
72 * Current query ID
73 * @var integer
74 */
75 protected $result = null;
76
77 /**
78 * Current query string
79 * @var string
80 */
81 protected $querystr = '';
82
83 /**
84 * History of all executed queryies
85 * @var array
86 */
87 protected $history = array();
88
89 /**
90 * Returns the history information array
91 *
92 * @return array History record
93 */
94 public function getHistory()
95 {
96 return $this->history;
97 }
98
99 /**
100 * Connect to a the specified database
101 *
102 * @param string Server name
103 * @param string User name
104 * @param string Password
105 * @param string Database name
106 *
107 * @return bool Result of connect
108 */
109 public function connect($server, $user, $password, $database)
110 {
111 if ($this->dblink == false)
112 {
113 $this->dblink = $this->_connect($server, $user, $password, $database);
114
115 if ($this->dblink == false)
116 {
117 throw new BSDbException('Connect Failed', -1, 'DB-Link == false; connect failed');
118 return false;
119 }
120
121 return true;
122 }
123 }
124
125 /**
126 * Abstract function that returns a database link after establishing a connection. This just
127 * calls the function and does not do any checking
128 *
129 * @param string Server name
130 * @param string User name
131 * @param string Password
132 * @param string Database name
133 *
134 * @return integer Database link
135 */
136 protected abstract function _connect($server, $user, $password, $database);
137
138 /**
139 * Send a query to the open database link
140 *
141 * @param string Query string
142 *
143 * @return BSDbResult Result object, or NULL
144 */
145 public function query($string)
146 {
147 $time = microtime();
148
149 $this->querystr = $string;
150 $this->result = $this->_query($string);
151
152 if (!$this->result)
153 {
154 throw new BSDbException($this->_errorString(), $this->_errorNumber(), $string);
155 }
156
157 $this->history[] = $history = array('query' => $string, 'time' => BSFunctions::fetch_microtime_diff($time), 'trace' => BSFunctions::format_backtrace(debug_backtrace()));
158
159 if (defined('ISSO_SHOW_QUERIES_LIVE'))
160 {
161 if (constant('ISSO_SHOW_QUERIES_LIVE'))
162 {
163 print($this->_constructDebugQuery($history));
164 }
165 }
166
167 if (preg_match('/^\s*(select|describe|show|explain)/i', $string))
168 {
169 $class = get_class($this) . 'Result';
170 return new $class($this->result);
171 }
172 }
173
174 /**
175 * Abstract function that executes the query command on the database
176 *
177 * @param string Query string
178 *
179 * @return integer Result ID
180 */
181 protected abstract function _query($query);
182
183 /**
184 * Escape a string (depending on character set, if supported)
185 *
186 * @param string String to be escaped
187 *
188 * @return string Escaped string
189 */
190 public function escapeString($string)
191 {
192 return $this->_escapeString($string);
193 }
194
195 /**
196 * Abstract function that calls the escape_string() method
197 *
198 * @param string String to escape
199 *
200 * @return string Escaped string
201 */
202 protected abstract function _escapeString($string);
203
204 /**
205 * Escapes a binary string for insertion into the database
206 *
207 * @param string Unescaped data
208 *
209 * @return string Escaped binary data
210 */
211 public function escapeBinary($binary)
212 {
213 return $this->_escapeBinary($binary);
214 }
215
216 /**
217 * Abstract function that calls escape_binary()
218 *
219 * @param string Binary to escape
220 *
221 * @return string Escaped binary
222 */
223 protected abstract function _escapeBinary($string);
224
225 /**
226 * Unescapes a binary string that was fetched from the database
227 *
228 * @param string Escaped data
229 *
230 * @return string Unescaped binary data
231 */
232 public function unescapeBinary($binary)
233 {
234 return $this->_unescapeBinary($binary);
235 }
236
237 /**
238 * Abstract function that calls unescape_binary()
239 *
240 * @param string Escaped data
241 *
242 * @return string Data that has been unescaped
243 */
244 protected abstract function _unescapeBinary($string);
245
246 /**
247 * Send a query and return the first row of the results
248 *
249 * @param string Query string
250 * @param string Result return function (in the database layer)
251 *
252 * @return mixed Results in variable formats
253 */
254 public function queryFirst($string, $callback = 'fetchArray')
255 {
256 $resource = $this->query($string);
257 if ($resource)
258 {
259 $return = $resource->$callback();
260 $resource->free();
261 return $return;
262 }
263 else
264 {
265 return false;
266 }
267 }
268
269 /**
270 * Returns the errror number
271 */
272 public abstract function _errorNumber();
273
274 /**
275 * Returns the error string
276 */
277 public abstract function _errorString();
278
279 /**
280 * Fetch the unique ID of the record just inserted
281 *
282 * @return integer Insert-ID
283 */
284 public function insertId()
285 {
286 return $this->_insertID();
287 }
288
289 /**
290 * Abstract function that returns the ID of the most recently-inserted
291 * record
292 *
293 * @return integer Insertion ID
294 */
295 protected abstract function _insertId();
296
297 /**
298 * Fetch the number of rows affected by the query
299 *
300 * @param integer Result
301 *
302 * @return integer Number of affected rows
303 */
304 public function affectedRows()
305 {
306 return $this->_affectedRows($this->result);
307 }
308
309 /**
310 * Abstract function that returns the number of affected rows in the result
311 *
312 * @param integer Result ID
313 *
314 * @return integer Number of rows
315 */
316 protected abstract function _affectedRows($result);
317
318 /**
319 * Sends the command to start a transaction. This command should never
320 * be reached as it's always overridden
321 */
322 public abstract function begin();
323
324 /**
325 * Sends the command to rollback to a given savepoint. This command
326 * should never be reached as it's always overridden
327 *
328 * @param string Named savepoint
329 */
330 public abstract function rollback();
331
332 /**
333 * Sends the command to commit the entire transaction. This command
334 * should never be reached as it's always overridden
335 */
336 public abstract function commit();
337 }
338
339 /**
340 * Database Result
341 *
342 * This class holds result information for a database result
343 *
344 * @author rsesek
345 * @copyright Copyright (c)2005 - 2008, Blue Static
346 * @package ISSO
347 *
348 */
349 abstract class BSDbResult implements Iterator
350 {
351 /**
352 * The result resource
353 * @var resource
354 */
355 protected $result;
356
357 /**
358 * All the results (as used by the iterator implementation)
359 * @var string
360 */
361 protected $iterator;
362
363 /**
364 * Sets the resource and returns a result object
365 *
366 * @param resource The result of the query
367 */
368 public function __construct($result)
369 {
370 $this->result = $result;
371 }
372
373 /**
374 * Method to call on the result
375 *
376 * @param string Method name
377 *
378 * @return array Array of results
379 */
380 public function fetchAll($method = 'fetchArray')
381 {
382 $results = array();
383 while ($result = $this->$method())
384 {
385 $results[] = $result;
386 }
387 return $results;
388 }
389
390 /**
391 * Fetch the query result as an array
392 *
393 * @param integer Result
394 * @param bool Return an associative array?
395 *
396 * @return array A row of the query result
397 */
398 public function fetchArray($assoc = true)
399 {
400 return $this->{($assoc ? '_fetchAssocArray' : '_fetchRowArray')}($this->result);
401 }
402
403 /**
404 * Abstract function that returns an associative array of given result
405 *
406 * @param integer Result
407 *
408 * @return array Result array
409 */
410 protected abstract function _fetchAssocArray($result);
411
412 /**
413 * Abstract function that returns a row array of given result
414 *
415 * @param integer Result
416 *
417 * @return array Result array
418 */
419 protected abstract function _fetchRowArray($result);
420
421 /**
422 * Fetch the query result as an object
423 *
424 * @param integer Result
425 *
426 * @return object An object with the query result
427 */
428 public function fetchObject()
429 {
430 return $this->_fetchObject($this->result);
431 }
432
433 /**
434 * Abstract function that returns an object for a given result
435 *
436 * @param integer Result
437 *
438 * @return object Row object
439 */
440 public abstract function _fetchObject($result);
441
442 /**
443 * Free the current query result
444 *
445 * @param integer Result
446 */
447 public function free()
448 {
449 $this->_freeResult($this->result);
450 }
451
452 /**
453 * Abstract function that frees a given result
454 *
455 * @param integer Result ID
456 */
457 protected abstract function _freeResult($result);
458
459 /**
460 * Fetch the number of rows in the result
461 *
462 * @param integer Result
463 *
464 * @return integer Number of rows
465 */
466 public function size()
467 {
468 return $this->_numRows($this->result);
469 }
470
471 /**
472 * Abstract function that returns the number of rows in the result
473 *
474 * @param integer Result ID
475 *
476 * @return integer Number of rows
477 */
478 protected abstract function _numRows($result);
479
480 // ###################################################################
481 // # Iterator implementation
482 // ###################################################################
483 /**
484 * Rewinds the iterator by resetting the result pointer
485 *
486 * @return void
487 */
488 public function rewind()
489 {
490 if ($this->iterator == null)
491 {
492 $this->iterator = $this->fetchAll();
493 }
494 reset($this->iterator);
495 }
496
497 /**
498 * Returns the current row
499 *
500 * @return array
501 */
502 public function current()
503 {
504 return current($this->iterator);
505 }
506
507 /**
508 * Returns the key (result pointer index)
509 *
510 * @return integer
511 */
512 public function key()
513 {
514 return key($this->iterator);
515 }
516
517 /**
518 * Advances the iterator and returns the row
519 *
520 * @return array
521 */
522 public function next()
523 {
524 return next($this->iterator);
525 }
526
527 /**
528 * Checks whether the iterator is valid
529 *
530 * @return boolean
531 */
532 public function valid()
533 {
534 return ($this->current() !== false);
535 }
536 }
537
538 /**
539 * Database Exception
540 *
541 * Exception handler class for the database classes
542 *
543 * @author Blue Static
544 * @copyright Copyright (c)2005 - 2008, Blue Static
545 * @package ISSO
546 *
547 */
548 class BSDbException extends Exception
549 {
550 /**
551 * The query string that caused the error
552 * @var string
553 */
554 protected $query;
555
556 /**
557 * Initializes a new database exception
558 *
559 * @param string The error message
560 * @param ineger MySQL error code
561 * @param sring Query string that caused the error
562 */
563 public function __construct($error, $errorNum, $query)
564 {
565 $this->query = $query;
566 parent::__construct($error, $errorNum);
567 }
568
569 /**
570 * Returns the query that failed
571 *
572 * @return string
573 */
574 public function getQuery()
575 {
576 return $this->query;
577 }
578 }
579
580 ?>