| [ Index ] | PHP Cross Reference of Mambo 4.6.5 |
|
| [ Variables ] [ Functions ] [ Classes ] [ Constants ] [ Statistics ] | ||
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * @package Mambo 4 * @subpackage Database 5 * @author Mambo Foundation Inc see README.php 6 * @copyright (C) 2000 - 2009 Mambo Foundation Inc. 7 * See COPYRIGHT.php for copyright notices and details. 8 * @license GNU/GPL Version 2, see LICENSE.php 9 * 10 * Redistributions of files must retain the above copyright notice. 11 * 12 * Mambo is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; version 2 of the License. 15 */ 16 17 /** 18 * Database connector class 19 */ 20 class database { 21 /** @var string Internal variable to hold the query sql */ 22 var $_sql=''; 23 /** @var int Internal variable to hold the database error number */ 24 var $_errorNum=0; 25 /** @var string Internal variable to hold the database error message */ 26 var $_errorMsg=''; 27 /** @var string Internal variable to hold the prefix used on all database tables */ 28 var $_table_prefix=''; 29 /** @var Internal variable to hold the connector resource */ 30 var $_resource=''; 31 /** @var Internal variable to hold the last query cursor */ 32 var $_cursor=null; 33 /** @var boolean Debug option */ 34 var $_debug=0; 35 /** @var array A log of queries */ 36 var $_log=array(); 37 /** @var string Null date */ 38 var $_null_date='0000-00-00 00:00:00'; 39 40 /** 41 * Database object constructor 42 * @param string Database host 43 * @param string Database user name 44 * @param string Database user password 45 * @param string Database name 46 * @param string Common prefix for all tables 47 */ 48 function database( $host='localhost', $user, $pass, $db, $table_prefix ) { 49 global $configuration,$charset; 50 // perform a number of fatality checks, then die gracefully 51 if (!function_exists( 'mysql_connect' )) $this->forceOffline(1); 52 if (!($this->_resource = @mysql_connect( $host, $user, $pass ))) $this->forceOffline(2); 53 if (!mysql_select_db($db)) $this->forceOffline(3); 54 $this->_table_prefix = $table_prefix; 55 if(floatval(mysql_get_client_info())>=4.1){ 56 $mysql_charsets = $this->getCharsets(); 57 $charset = isset($charset) ? trim($charset) : ''; 58 $charset = isset($configuration)?$configuration->mosConfig_charset:$charset; 59 $charset = in_array($charset, array_keys($mysql_charsets)) ? $charset : $this->getCharsetFromDb(); 60 $charset = in_array($charset, array_keys($mysql_charsets)) ? $charset : 'utf-8'; 61 $cs=$mysql_charsets[$charset]; 62 mysql_query( "SET CHARSET '" .$cs. "'" ); 63 } 64 } 65 66 function getCharsetFromDb() { 67 static $charset_from_db; 68 if (!isset($charset_from_db)) { 69 //retrieve from database 70 $query = 'show variables like "character_set_database";'; 71 $this->setQuery( $query ); 72 $results = $this->loadObjectList(); 73 $charset_from_db = $results[0]->Value; 74 } 75 return $charset_from_db; 76 } 77 78 function getCharsets() { 79 static $mysql_charsets; 80 if (!isset($mysql_charsets)) { 81 $mysql_charsets = array(); 82 $mysql_charsets['utf-8']='utf8'; 83 $mysql_charsets['iso-8859-1']='latin1'; 84 $mysql_charsets['iso-8859-15']='latin1'; 85 $mysql_charsets['koi8-r']='koi8r'; 86 $mysql_charsets['windows-1251']='cp1251'; 87 $mysql_charsets['cp1251']='cp1251'; 88 $mysql_charsets['gb2312']='gb2312'; 89 $mysql_charsets['gb18030']='gb2312'; 90 $mysql_charsets['gbk']='gb2312'; 91 $mysql_charsets['big5-hkscs']='big5'; 92 $mysql_charsets['big5']='big5'; 93 $mysql_charsets['euc-tw']='gb2312'; 94 $mysql_charsets['iso-8859-2']='latin2'; 95 $mysql_charsets['windows-1250']='latin2'; 96 $mysql_charsets['iso-8859-7']='latin7'; 97 $mysql_charsets['iso-8859-8-i']='hebrew'; 98 $mysql_charsets['iso-8859-8']='hebrew'; 99 $mysql_charsets['sjis']='sjis'; 100 $mysql_charsets['windows-1257']='latin7'; 101 $mysql_charsets['iso-8859-13']='latin7'; 102 $mysql_charsets['cp-866']='cp1251'; 103 $mysql_charsets['iso-8859-5']='latin5'; 104 $mysql_charsets['koi8-u']='koi8r'; 105 $mysql_charsets['windows-1252']='latin1'; 106 $mysql_charsets['tis-620']='tis620'; 107 $mysql_charsets['iso-8859-9']='latin5'; 108 $mysql_charsets['windows-1256']='cp1256'; 109 $mysql_charsets['georgian-ps']='geostd8'; 110 $mysql_charsets['euc-jp']='eucjpms'; 111 $mysql_charsets['euc-kr']='euckr'; 112 $mysql_charsets['iso-8859-6']='cp1256'; 113 $mysql_charsets['windows-1258']='latin1'; //No better match 114 } 115 return $mysql_charsets; 116 } 117 118 function forceOffline ($error_number) { 119 $mosSystemError = $error_number; 120 $basePath = dirname( __FILE__ ); 121 include $basePath . '/../configuration.php'; 122 include $basePath . '/../offline.php'; 123 exit(); 124 } 125 126 function getNullDate () { 127 return $this->_null_date; 128 } 129 /** 130 * @param int 131 */ 132 function debug( $level ) { 133 $this->_debug = intval( $level ); 134 } 135 136 function debug_trace () { 137 trigger_error( $this->_errorNum, E_USER_NOTICE ); 138 //echo "<pre>" . $this->_sql . "</pre>\n"; 139 if (function_exists('debug_backtrace')) { 140 foreach(debug_backtrace() as $back) { 141 if (@$back['file']) { 142 echo '<br />'.$back['file'].':'.$back['line']; 143 } 144 } 145 } 146 } 147 /** 148 * @return int The error number for the most recent query 149 */ 150 function getErrorNum() { 151 return $this->_errorNum; 152 } 153 /** 154 * @return string The error message for the most recent query 155 */ 156 function getErrorMsg() { 157 return str_replace( array( "\n", "'" ), array( '\n', "\'" ), $this->_errorMsg ); 158 } 159 /** 160 * Get a database escaped string 161 * @return string 162 */ 163 function getEscaped( $text ) { 164 if (phpversion() < '4.3.0') { 165 return mysql_escape_string( $text ); 166 } else { 167 return mysql_real_escape_string( $text ); 168 } 169 } 170 /** 171 * Get a quoted database escaped string 172 * @return string 173 */ 174 function Quote( $text ) { 175 if (phpversion() < '4.3.0') { 176 return '\'' . mysql_escape_string( $text ) . '\''; 177 } else { 178 return '\'' . mysql_real_escape_string( $text ) . '\''; 179 } 180 } 181 /** 182 * Sets the SQL query string for later execution. 183 * 184 * @param string The SQL query 185 */ 186 function setBareQuery ($sql) { 187 $this->_sql = $sql; 188 } 189 /** 190 * Sets the SQL query string for later execution. 191 * 192 * This function replaces a string identifier <var>$prefix</var> with the 193 * string held is the <var>_table_prefix</var> class variable. 194 * 195 * @param string The SQL query 196 * @param string The common table prefix 197 */ 198 function setQuery( $sql, $prefix='#__' ) { 199 $this->setBareQuery ($this->replacePrefix($sql, $prefix)); 200 // This is maintenance code for catching particular SQL statements 201 // if (strpos($this->_sql,'SELECT menutype') === 0) debug_print_backtrace(); 202 } 203 204 /** 205 * This function replaces a string identifier <var>$prefix</var> with the 206 * string held is the <var>_table_prefix</var> class variable. 207 * 208 * @param string The SQL query 209 * @param string The common table prefix 210 * @author thede, David McKinnis 211 */ 212 function replacePrefix ($sql, $prefix='#__') { 213 $done = ''; 214 while (strlen($sql)) { 215 $single = preg_match("/\'([^\\\']|\\.)*'/", $sql,$matches_single,PREG_OFFSET_CAPTURE); 216 if ($double = preg_match('/\"([^\\\"]|\\.)*"/', $sql,$matches_double,PREG_OFFSET_CAPTURE) OR $single) { 217 if ($single == 0 OR ($double AND $matches_double[0][1] < $matches_single[0][1])) { 218 $done .= str_replace($prefix, $this->_table_prefix, substr($sql,0,$matches_double[0][1])).$matches_double[0][0]; 219 $sql = substr($sql,$matches_double[0][1]+strlen($matches_double[0][0])); 220 } 221 else { 222 $done .= str_replace($prefix, $this->_table_prefix, substr($sql,0,$matches_single[0][1])).$matches_single[0][0]; 223 $sql = substr($sql,$matches_single[0][1]+strlen($matches_single[0][0])); 224 } 225 } 226 else return $done.str_replace($prefix, $this->_table_prefix,$sql); 227 } 228 return $done; 229 } 230 /** 231 * @return string The current value of the internal SQL vairable 232 */ 233 function getQuery($sql='') { 234 if ($sql == '') $sql = $this->_sql; 235 return "<pre>" . htmlspecialchars( $sql ) . "</pre>"; 236 } 237 /** 238 * Execute the query 239 * @return mixed A database resource if successful, FALSE if not. 240 */ 241 function query($sql = '') { 242 global $mosConfig_debug; 243 if ($sql == '') $sql = $this->_sql; 244 if ($this->_debug) $this->_log[] = $sql; 245 if ($this->_cursor = mysql_query($sql, $this->_resource)) { 246 $this->_errorNum = 0; 247 $this->_errorMsg = ''; 248 return $this->_cursor; 249 } 250 else { 251 $this->_errorNum = mysql_errno( $this->_resource ); 252 $this->_errorMsg = mysql_error( $this->_resource )." SQL=$sql"; 253 if ($this->_debug) $this->debug_trace(); 254 return false; 255 } 256 } 257 258 function query_batch( $abort_on_error=true, $p_transaction_safe = false) { 259 $this->_errorNum = 0; 260 $this->_errorMsg = ''; 261 if ($p_transaction_safe) { 262 $si = mysql_get_server_info(); 263 preg_match_all( "/(\d+)\.(\d+)\.(\d+)/i", $si, $m ); 264 $prefix = ''; 265 if ($m[1] >= 4) $prefix = 'START TRANSACTION; '; 266 elseif ($m[2] >= 23) { 267 if ($m[3] >= 19) $prefix = 'BEGIN WORK; '; 268 elseif ($m[3] >= 17) $prefix = 'BEGIN; '; 269 } 270 if ($prefix) $this->_sql = $prefix.$this->_sql.'; COMMIT;'; 271 } 272 $query_split = preg_split ("/[;]+/", $this->_sql); 273 $error = 0; 274 foreach ($query_split as $command_line) { 275 $command_line = trim( $command_line ); 276 if ($command_line != '') { 277 if (!$this->query($command_line)) { 278 $error = 1; 279 if ($abort_on_error) { 280 return $this->_cursor; 281 } 282 } 283 } 284 } 285 return $error ? false : true; 286 } 287 288 /** 289 * Diagnostic function 290 */ 291 function explain() { 292 if (!($cur = $this->query("EXPLAIN ".$this->_sql))) return null; 293 $headline = $header = $body = ''; 294 $buf = '<table cellspacing="1" cellpadding="2" border="0" bgcolor="#000000" align="center">'; 295 $buf .= $this->getQuery("EXPLAIN ".$this->_sql); 296 while ($row = mysql_fetch_assoc($cur)) { 297 $body .= "<tr>"; 298 foreach ($row as $k=>$v) { 299 if ($headline == '') $header .= "<th bgcolor=\"#ffffff\">$k</th>"; 300 $body .= "<td bgcolor=\"#ffffff\">$v</td>"; 301 } 302 $headline = $header; 303 $body .= "</tr>"; 304 } 305 $buf .= "<tr>$headline</tr>$body</table><br /> "; 306 mysql_free_result( $cur ); 307 return "<div style=\"background-color:#FFFFCC\" align=\"left\">$buf</div>"; 308 } 309 /** 310 * @return int The number of rows returned from the most recent query - SELECT only 311 */ 312 function getNumRows( $cur=null ) { 313 return mysql_num_rows( $cur ? $cur : $this->_cursor ); 314 } 315 316 /** 317 * @return int The number of rows affected by the most recent query - INSERT, UPDATE, DELETE 318 */ 319 function getAffectedRows( ) { 320 return mysql_affected_rows( $this->_resource ); 321 } 322 323 /** 324 * Load an array of retrieved database objects or values 325 * @param int Database cursor 326 * @param string The field name of a primary key 327 * @return array If <var>key</var> is empty as sequential list of returned records. 328 * If <var>key</var> is not empty then the returned array is indexed by the value 329 * the database key. Returns <var>null</var> if the query fails. 330 */ 331 function &retrieveResults ($key='', $max=0, $result_type='row') { 332 $results = array(); 333 $sql_function = 'mysql_fetch_'.$result_type; 334 if ($cur = $this->query()) { 335 while ($row = $sql_function($cur)) { 336 if ($key != '') { 337 if ( is_array($row) ) { 338 $results[$row[$key]] = $row; 339 } else { 340 $results[$row->$key] = $row; 341 } 342 } else { 343 $results[] = $row; 344 } 345 if ($max AND count($results) >= $max) break; 346 } 347 mysql_free_result($cur); 348 } 349 return $results; 350 } 351 /** 352 * This method loads the first field of the first row returned by the query. 353 * 354 * @return The value returned in the query or null if the query failed. 355 */ 356 function loadResult() { 357 $results =& $this->retrieveResults('', 1, 'row'); 358 if (count($results)) return $results[0][0]; 359 else return null; 360 } 361 362 /** 363 * Load an array of single field results into an array 364 */ 365 function loadResultArray($numinarray = 0) { 366 $results =& $this->retrieveResults('', 0, 'row'); 367 $values = array(); 368 foreach ($results as $result) $values[] = $result[$numinarray]; 369 if (count($values)) return $values; 370 else return null; 371 } 372 /** 373 * Load a assoc list of database rows 374 * @param string The field name of a primary key 375 * @return array If <var>key</var> is empty as sequential list of returned records. 376 */ 377 function loadAssocList( $key='' ) { 378 $results =& $this->retrieveResults($key, 0, 'assoc'); 379 if (count($results)) return $results; 380 else return null; 381 } 382 /** 383 * Copy the named array content into the object as properties 384 * only existing properties of object are filled. when undefined in hash, properties wont be deleted 385 * @param array the input array 386 * @param obj byref the object to fill of any class 387 * @param string 388 * @param boolean 389 */ 390 function mosBindArrayToObject( $array, &$obj, $ignore='', $prefix=NULL, $checkSlashes=true ) { 391 if (!is_array($array) OR !is_object($obj)) return false; 392 if ($prefix == null) $prefix = ''; 393 foreach (get_object_vars($obj) as $k => $v) { 394 if( substr( $k, 0, 1 ) != '_' AND strpos($ignore, $k) === false) { 395 if (isset($array[$prefix.$k])) { 396 $obj->$k = ($checkSlashes AND get_magic_quotes_gpc()) ? $this->mosStripslashes( $array[$prefix.$k] ) : $array[$prefix.$k]; 397 } 398 } 399 } 400 return true; 401 } 402 403 /** 404 * Strip slashes from strings or arrays of strings 405 * @param value the input string or array 406 */ 407 function mosStripslashes(&$value) { 408 if (is_string($value)) $ret = stripslashes($value); 409 else { 410 if (is_array($value)) { 411 $ret = array(); 412 while (list($key,$val) = each($value)) { 413 $ret[$key] = $this->mosStripslashes($val); 414 } // while 415 } else $ret = $value; 416 } // if 417 return $ret; 418 } // mosStripSlashes 419 420 /** 421 * This global function loads the first row of a query into an object 422 * 423 * If an object is passed to this function, the returned row is bound to the existing elements of <var>object</var>. 424 * If <var>object</var> has a value of null, then all of the returned query fields returned in the object. 425 * @param string The SQL query 426 * @param object The address of variable 427 */ 428 function loadObject( &$object ) { 429 if ($object != null) { 430 $results =& $this->retrieveResults('', 1, 'assoc'); 431 if (count($results)) { 432 $this->mosBindArrayToObject($results[0], $object, null, null, false); 433 return true; 434 } 435 } 436 else { 437 $results =& $this->retrieveResults('', 1, 'object'); 438 if (count($results)) { 439 $object = $results[0]; 440 return true; 441 } 442 else $object = null; 443 } 444 return false; 445 } 446 /** 447 * Load a list of database objects 448 * @param string The field name of a primary key 449 * @return array If <var>key</var> is empty as sequential list of returned records. 450 * If <var>key</var> is not empty then the returned array is indexed by the value 451 * the database key. Returns <var>null</var> if the query fails. 452 */ 453 function loadObjectList( $key='' ) { 454 $results =& $this->retrieveResults($key, 0, 'object'); 455 if (count($results)) return $results; 456 else return null; 457 } 458 /** 459 * @return The first row of the query. 460 */ 461 function loadRow() { 462 $results =& $this->retrieveResults('', 1, 'row'); 463 if (count($results)) return $results[0]; 464 else return null; 465 } 466 /** 467 * Load a list of database rows (numeric column indexing) 468 * @param string The field name of a primary key 469 * @return array If <var>key</var> is empty as sequential list of returned records. 470 * If <var>key</var> is not empty then the returned array is indexed by the value 471 * the database key. Returns <var>null</var> if the query fails. 472 */ 473 function loadRowList( $key='' ) { 474 $results =& $this->retrieveResults('', 0, 'row'); 475 if (count($results)) return $results; 476 else return null; 477 } 478 479 /** 480 * Document::db_insertObject() 481 * 482 * { Description } 483 * 484 * @param [type] $keyName 485 * @param [type] $verbose 486 */ 487 function insertObject( $table, &$object, $keyName = NULL, $verbose=false ) { 488 $fmtsql = "INSERT INTO $table ( %s ) VALUES ( %s ) "; 489 $fmtsql = $this->replacePrefix($fmtsql); 490 $fields = array(); 491 foreach (get_object_vars( $object ) as $k => $v) { 492 if (is_array($v) OR is_object($v) OR $v === NULL OR $k[0] == '_') continue; 493 $fields[] = "`$k`"; 494 $values[] = "'" . $this->getEscaped( $v ) . "'"; 495 } 496 if (!isset($fields)) die ('class database method insertObject - no fields'); 497 $this->setBareQuery( sprintf( $fmtsql, implode( ",", $fields ), implode( ",", $values ) ) ); 498 ($verbose) && print "$sql<br />\n"; 499 if (!$this->query()) return false; 500 $id = mysql_insert_id(); 501 ($verbose) && print "id=[$id]<br />\n"; 502 if ($keyName && $id) $object->$keyName = $id; 503 return true; 504 } 505 506 /** 507 * Document::db_updateObject() 508 * 509 * { Description } 510 * 511 * @param [type] $updateNulls 512 */ 513 function updateObject( $table, &$object, $keyName, $updateNulls=true ) { 514 $fmtsql = "UPDATE $table SET %s WHERE %s"; 515 $fmtsql = $this->replacePrefix($fmtsql); 516 $tmp = array(); 517 foreach (get_object_vars( $object ) as $k => $v) { 518 if (is_array($v) OR is_object($v) OR $k[0] == '_' OR ($v === null AND !$updateNulls)) continue; 519 if( $k == $keyName ) { // PK not to be updated 520 $where = "$keyName='" . $this->getEscaped( $v ) . "'"; 521 continue; 522 } 523 if ($v) $v = $this->getEscaped($v); 524 $tmp[] = "`$k`='$v'"; 525 } 526 if (!isset($tmp)) return true; 527 if (!isset($where)) die ('database class updateObject method - no key value'); 528 $this->setBareQuery( sprintf( $fmtsql, implode( ",", $tmp ) , $where ) ); 529 return $this->query(); 530 } 531 532 /** 533 * @param boolean If TRUE, displays the last SQL statement sent to the database 534 * @return string A standised error message 535 */ 536 function stderr( $showSQL = false ) { 537 return "DB function failed with error number $this->_errorNum" 538 ."<br /><font color=\"red\">$this->_errorMsg</font>" 539 .($showSQL ? "<br />SQL = <pre>$this->_sql</pre>" : ''); 540 } 541 542 function insertid() 543 { 544 return mysql_insert_id(); 545 } 546 547 function getVersion() 548 { 549 return mysql_get_server_info(); 550 } 551 552 /** 553 * Fudge method for ADOdb compatibility 554 */ 555 function GenID( $foo1=null, $foo2=null ) { 556 return '0'; 557 } 558 /** 559 * @return array A list of all the tables in the database 560 */ 561 function getTableList() { 562 $this->setQuery( 'SHOW tables' ); 563 $this->query(); 564 return $this->loadResultArray(); 565 } 566 /** 567 * @param array A list of table names 568 * @return array A list the create SQL for the tables 569 */ 570 function getTableCreate( $tables ) { 571 $result = array(); 572 573 foreach ($tables as $tblval) { 574 $this->setQuery( 'SHOW CREATE table ' . $tblval ); 575 $this->query(); 576 $result[$tblval] = $this->loadResultArray( 1 ); 577 } 578 579 return $result; 580 } 581 /** 582 * @param array A list of table names 583 * @return array An array of fields by table 584 */ 585 function getTableFields( $tables ) { 586 $result = array(); 587 588 foreach ($tables as $tblval) { 589 $this->setQuery( 'SHOW FIELDS FROM ' . $tblval ); 590 $this->query(); 591 $fields = $this->loadObjectList(); 592 foreach ($fields as $field) { 593 $result[$tblval][$field->Field] = preg_replace("/[(0-9)]/",'', $field->Type ); 594 } 595 } 596 597 return $result; 598 } 599 600 function displayLogged () { 601 echo count($this->_log).' queries executed'; 602 echo '<pre>'; 603 foreach ($this->_log as $k=>$sql) { 604 echo $k+1 . "\n" . $sql . '<hr />'; 605 } 606 } 607 608 /* Helper method - maybe should go into database itself */ 609 function doSQL ($sql) { 610 $this->setQuery($sql); 611 if (!$this->query()) { 612 echo "<script> alert('".$this->getErrorMsg()."'); window.history.go(-1); </script>\n"; 613 exit(); 614 } 615 } 616 617 /* Helper method - maybe could go into database itself */ 618 function &doSQLget ($sql, $classname) { 619 $this->setQuery($sql); 620 $rows = $this->loadObjectList(); 621 $target = get_class_vars($classname); 622 if ($rows) { 623 foreach ($rows as $row) { 624 $next = new $classname(0); 625 foreach ($target as $field=>$value) { 626 if (isset($row->$field)) $next->$field = $row->$field; 627 } 628 $result[] = $next; 629 } 630 } 631 else $result = array(); 632 return $result; 633 } 634 635 636 } 637 638 class mamboDatabase extends database { 639 640 function mamboDatabase () { 641 $host = mamboCore::get('mosConfig_host'); 642 $user = mamboCore::get('mosConfig_user'); 643 $pw = mamboCore::get('mosConfig_password'); 644 $db = mamboCore::get('mosConfig_db'); 645 $prefix = mamboCore::get('mosConfig_dbprefix'); 646 parent::database($host, $user, $pw, $db, $prefix); 647 } 648 649 function &getInstance () { 650 static $instance; 651 if (!is_object($instance)) $instance = new mamboDatabase(); 652 return $instance; 653 } 654 } 655 656 /** 657 * mosDBAbstractRow Abstract Class. 658 * @abstract 659 * @package Mambo 660 * @subpackage Database 661 * 662 * Parent classes to all database derived objects. Customisation will generally 663 * not involve tampering with this object. 664 * @package Mambo 665 * @author Martin Brampton counterpoint@mambo-foundation.org 666 */ 667 class mosDBAbstractRow { 668 /** @var string Name of the table in the db schema relating to child class */ 669 var $_tbl = ''; 670 /** @var string Name of the primary key field in the table */ 671 var $_tbl_key = ''; 672 /** @var string Error message */ 673 var $_error = ''; 674 675 /** 676 * Object constructor to set table and key field 677 * 678 * Can be overloaded/supplemented by the child class 679 * @param string $table name of the table in the db schema relating to child class 680 * @param string $key name of the primary key field in the table 681 */ 682 function mosDBAbstractRow ($table='', $keyname='id', $db='') { 683 if ($table) $this->_tbl = $table; 684 else $this->_tbl = $this->tableName(); 685 $this->_tbl_key = $keyname; 686 if (is_object($db)) $this->_db = $db; 687 } 688 689 /** 690 * generic check method 691 * 692 * can be overloaded/supplemented by the child class 693 * @return boolean True if the object is ok 694 */ 695 function check() { 696 return true; 697 } 698 699 /** 700 * Checks if this object lacks the property given by the parameter 701 * @param string The name of the property 702 * @return bool 703 */ 704 function lacks( $property ) { 705 $thisclass = get_class($this); 706 if (array_key_exists( $property, get_class_vars($thisclass) )) return false; 707 $this->_error = T_(sprintf('WARNING: %s does not support %s.', $thisclass, $property)); 708 return true; 709 } 710 711 /** 712 /* Move a database row object up or down through the ordering 713 /* @param int positive to move up, negative to move down 714 /* @param string Additional conditions on the WHERE clause to limit the effect 715 */ 716 function move( $direction, $where='' ) { 717 $compops = array (-1 => '<', 0 => '=', 1 => '>'); 718 $relation = $compops[($direction>0)-($direction<0)]; 719 $ordering = ($relation == '<' ? 'DESC' : 'ASC'); 720 $k = $this->_tbl_key; 721 $o1 = $this->ordering; 722 $k1 = $this->$k; 723 $database = isset($this->_db) ? $this->_db : mamboDatabase::getInstance(); 724 $sql = "SELECT $k, ordering FROM $this->_tbl WHERE ordering $relation $o1"; 725 $sql .= ($where ? "\n AND $where" : '').' ORDER BY ordering '.$ordering.' LIMIT 1'; 726 $database->setQuery( $sql ); 727 if ($database->loadObject($row)) { 728 $o2 = $row->ordering; 729 $k2 = $row->$k; 730 $sql = "UPDATE $this->_tbl SET ordering = (ordering=$o1)*$o2 + (ordering=$o2)*$o1 WHERE $k = $k1 OR $k = $k2"; 731 $database->doSQL($sql); 732 } 733 } 734 /** 735 * Compacts the ordering sequence of the selected records 736 * @param string Additional conditions on WHERE clause to limit ordering to a particular subset of records 737 */ 738 function updateOrder( $where='', $cfid=null, $order=null ) { 739 if ($this->lacks('ordering')) return false; 740 $k = $this->_tbl_key; 741 if ($this->_tbl == "#__content_frontpage") $order2 = ", content_id DESC"; 742 else $order2 = ""; 743 744 $database = isset($this->_db) ? $this->_db : mamboDatabase::getInstance(); 745 746 if (!is_null($cfid) AND !is_null($order)) { 747 foreach ($cfid as $i=>$id) { 748 $o = intval($order[$i]); 749 $set[] = "(id=$id)*$o"; 750 } 751 $sql = "UPDATE $this->_tbl SET ordering = ".implode(' + ', $set).' WHERE id IN ('.implode(',', $cfid).')'; 752 $database->doSQL($sql); 753 } 754 755 $sql = "SELECT $k, ordering FROM $this->_tbl " 756 . ($where ? "\nWHERE $where" : '') 757 . "\nORDER BY ordering$order2"; 758 $database->setQuery($sql); 759 if (!$rows = $database->loadObjectList()) { 760 $this->_error = $database->getErrorMsg(); 761 return false; 762 } 763 $i = 1; 764 foreach ($rows as $row) { 765 $sql = "UPDATE $this->_tbl SET ordering=$i WHERE $k = ".$row->$k; 766 $database->doSQL($sql); 767 $i++; 768 } 769 return true; 770 } 771 772 } 773 774 775 /** 776 * mosDBTable Abstract Class. 777 * @abstract 778 * @package Mambo 779 * @subpackage Database 780 * 781 * Parent classes to all database derived objects. Customisation will generally 782 * not involve tampering with this object. 783 * @package Mambo 784 * @author Andrew Eddie <eddieajau@users.sourceforge.net 785 */ 786 class mosDBTable extends mosDBAbstractRow { 787 /** @var mosDatabase Database connector */ 788 var $_db = null; 789 790 /** 791 * @return bool True if DB query failed. Sets the error message 792 */ 793 function queryTestFailure () { 794 if ($this->_db->query()) return false; 795 $this->_error = $this->_db->getErrorMsg(); 796 return true; 797 } 798 /** 799 * Filters public properties 800 * @access protected 801 * @param array List of fields to ignore 802 */ 803 function filter( $ignoreList=null ) { 804 $callcheck = array('InputFilter', 'process'); 805 if (!is_callable($callcheck)) require_once(mamboCore::get('mosConfig_absolute_path').'/includes/phpInputFilter/class.inputfilter.php'); 806 // specific filters 807 // $iFilter =& new InputFilter(); - previous call to original Php Input Filter 808 $iFilter =& mosInputFilter::getInstance(); // use extended Php Input Filter class from mambo.php 809 if (is_array($ignoreList)) foreach ($this->getPublicProperties() as $k) { 810 if (!in_array($k, $ignoreList)) $this->$k = $iFilter->process($this->$k); 811 } 812 else foreach ($this->getPublicProperties() as $k) $this->$k = $iFilter->process($this->$k); 813 } 814 /** 815 * @return string Returns the error message 816 */ 817 function getError() { 818 return $this->_error; 819 } 820 /** 821 * Gets the value of the class variable 822 * @param string The name of the class variable 823 * @return mixed The value of the class var (or null if no var of that name exists) 824 */ 825 function get( $_property ) { 826 if(isset( $this->$_property )) return $this->$_property; 827 else return null; 828 } 829 /** 830 * Returns an array of public properties 831 * @return array 832 */ 833 function getPublicProperties() { 834 static $cache = null; 835 if (is_null( $cache )) { 836 $cache = array(); 837 foreach (get_class_vars( get_class( $this ) ) as $key=>$val) { 838 if (substr( $key, 0, 1 ) != '_') { 839 $cache[] = $key; 840 } 841 } 842 } 843 return $cache; 844 } 845 /** 846 * Set the value of the class variable 847 * @param string The name of the class variable 848 * @param mixed The value to assign to the variable 849 */ 850 function set( $_property, $_value ) { 851 $this->$_property = $_value; 852 } 853 /** 854 * binds a named array/hash to this object 855 * 856 * can be overloaded/supplemented by the child class 857 * @param array $hash named array 858 * @return null|string null is operation was satisfactory, otherwise returns an error 859 */ 860 function bind( $array, $ignore="" ) { 861 $database =& mamboDatabase::getInstance(); 862 if (is_array($array)) return $database->mosBindArrayToObject($array, $this, $ignore); 863 $this->_error = strtolower(get_class( $this ))."::bind failed."; 864 return false; 865 } 866 867 /** 868 * binds an array/hash to this object 869 * @param int $oid optional argument, if not specifed then the value of current key is used 870 * @return any result from the database operation 871 */ 872 function load( $oid=null ) { 873 $k = $this->_tbl_key; 874 if ($oid !== null) { 875 $this->$k = $this->_db->getEscaped($oid); 876 } 877 if ($this->$k === null) return false; 878 $this->_db->setQuery("SELECT * FROM $this->_tbl WHERE $this->_tbl_key='".$this->$k."'" ); 879 return $this->_db->loadObject($this); 880 } 881 882 /** 883 * Inserts a new row if id is zero or updates an existing row in the database table 884 * 885 * Can be overloaded/supplemented by the child class 886 * @param boolean If false, null object variables are not updated 887 * @return null|string null if successful otherwise returns and error message 888 */ 889 function store( $updateNulls=false ) { 890 $k = $this->_tbl_key; 891 global $migrate; 892 if( $this->$k && !$migrate) $ret = $this->_db->updateObject( $this->_tbl, $this, $this->_tbl_key, $updateNulls ); 893 else $ret = $this->_db->insertObject( $this->_tbl, $this, $this->_tbl_key ); 894 if( !$ret ) { 895 $this->_error = strtolower(get_class( $this ))."::store failed <br />" . $this->_db->getErrorMsg(); 896 return false; 897 } else return true; 898 } 899 900 /** 901 * Default delete method 902 * 903 * can be overloaded/supplemented by the child class 904 * @return true if successful otherwise returns and error message 905 */ 906 function delete( $oid=null ) { 907 $k = $this->_tbl_key; 908 if ($oid) $this->$k = intval( $oid ); 909 $this->_db->setQuery( "DELETE FROM $this->_tbl WHERE $this->_tbl_key = '".$this->$k."'" ); 910 if ($this->queryTestFailure()) return false; 911 return true; 912 } 913 914 function checkout( $who, $oid=null ) { 915 if ($this->lacks('checked_out')) return false; 916 $k = $this->_tbl_key; 917 if ($oid !== null) $this->$k = $oid; 918 $time = date( "Y-m-d H:i:s" ); 919 if (intval( $who )) { 920 // new way of storing editor, by id 921 $this->_db->setQuery( "UPDATE $this->_tbl" 922 . "\nSET checked_out='$who', checked_out_time='$time'" 923 . "\nWHERE $this->_tbl_key='".$this->$k."'" 924 ); 925 } else { 926 // old way of storing editor, by name 927 $this->_db->setQuery( "UPDATE $this->_tbl" 928 . "\nSET checked_out='1', checked_out_time='$time', editor='".$who."' " 929 . "\nWHERE $this->_tbl_key='".$this->$k."'" 930 ); 931 } 932 return $this->_db->query(); 933 } 934 935 function checkin( $oid=null ) { 936 if ($this->lacks('checked_out')) return false; 937 $k = $this->_tbl_key; 938 if ($oid !== null) $this->$k = $oid; 939 $time = date("H:i:s"); 940 $this->_db->setQuery( "UPDATE $this->_tbl" 941 . "\nSET checked_out='0', checked_out_time='0000-00-00 00:00:00'" 942 . "\nWHERE $this->_tbl_key='".$this->$k."'" 943 ); 944 return $this->_db->query(); 945 } 946 947 function hit( $oid=null ) { 948 $k = $this->_tbl_key; 949 if ($oid !== null) $this->$k = intval( $oid ); 950 $key = $this->$k; 951 $this->_db->setQuery( "UPDATE $this->_tbl SET hits=(hits+1) WHERE $this->_tbl_key='$key'" ); 952 $this->_db->query(); 953 954 if (mamboCore::get('mosConfig_enable_log_items')) { 955 $now = date( "Y-m-d" ); 956 $this->_db->setQuery( "SELECT hits" 957 . "\nFROM #__core_log_items" 958 . "\nWHERE time_stamp='$now' AND item_table='$this->_tbl' AND item_id='$key'" 959 ); 960 $hits = intval( $this->_db->loadResult() ); 961 if ($hits) $this->_db->setQuery( "UPDATE #__core_log_items SET hits=(hits+1)" 962 . "\nWHERE time_stamp='$now' AND item_table='$this->_tbl' AND item_id='".$this->$k."'" 963 ); 964 else $this->_db->setQuery( "INSERT INTO #__core_log_items VALUES" 965 . "\n('$now','$this->_tbl','".$this->$k."','1')" 966 ); 967 $this->_db->query(); 968 } 969 } 970 971 /** 972 * Generic save function 973 * @param array Source array for binding to class vars 974 * @param string Filter for the order updating 975 * @returns TRUE if completely successful, FALSE if partially or not succesful. 976 */ 977 function save( $source, $order_filter ) { 978 if (!$this->bind($_POST) OR !$this->check() OR !$this->store()OR !$this->checkin()) return false; 979 $filter_value = $this->$order_filter; 980 $this->updateOrder( $order_filter ? "`$order_filter`='$filter_value'" : "" ); 981 $this->_error = ''; 982 return true; 983 } 984 985 /** 986 * Generic Publish/Unpublish function 987 * @param array An array of id numbers 988 * @param integer 0 if unpublishing, 1 if publishing 989 * @param integer The id of the user performnig the operation 990 */ 991 function publish_array( $cid=null, $publish=1, $myid=0 ) { 992 if (!is_array( $cid ) OR count( $cid ) < 1) { 993 $this->_error = "No items selected."; 994 return false; 995 } 996 $cids = implode( ',', $cid ); 997 $this->_db->setQuery( "UPDATE $this->_tbl SET published='$publish'" 998 . "\nWHERE $this->_tbl_key IN ($cids) AND (checked_out=0 OR checked_out='$myid')" 999 ); 1000 if ($this->queryTestFailure()) return false; 1001 if (count( $cid ) == 1) $this->checkin( $cid[0] ); 1002 return true; 1003 } 1004 1005 /** 1006 * Export item list to xml 1007 * @param boolean Map foreign keys to text values 1008 */ 1009 function toXML( $mapKeysToText=false ) { 1010 $xml = '<record table="' . $this->_tbl . '"'; 1011 if ($mapKeysToText) $xml .= ' mapkeystotext="true"'; 1012 $xml .= '>'; 1013 foreach (get_object_vars($this) as $k => $v) { 1014 if ($v === null OR is_array($v) OR is_object($v)) continue; 1015 if ($k[0] == '_') continue; // internal field 1016 $xml .= '<' . $k . '><![CDATA[' . $v . ']]></' . $k . '>'; 1017 } 1018 $xml .= '</record>'; 1019 return $xml; 1020 } 1021 } 1022 1023 /** 1024 * Abstract class for classes where the objects of the class can be relatively easily 1025 * stored in a single database table. Can usually be adapted to more complex cases. 1026 * Requires child classes to implement: tableName(), notSQL(). 1027 * tableName() must return the name of the database table, using #__ in the usual Mambo way 1028 * notSQL() must return an array of strings, where each string is the name of a 1029 * variable that is NOT in the database table, or is not written explicitly, 1030 * e.g. the auto-increment key. If this is the ONLY non-SQL field, then the 1031 * child class need not implement it, as that it is already in the abstract class. 1032 * Child classes may implement timeStampField, in which case it must return the name 1033 * of a field that will have a timestamp placed in it whenever the DB is written. 1034 */ 1035 1036 class mosTableEntry extends mosDBAbstractRow { 1037 1038 /* Stores all POST data where the name matches an object variable name */ 1039 function addPostData () { 1040 foreach (get_class_vars(get_class($this)) as $field=>$value) { 1041 if ($field!='id' AND $field[1] != '_' AND isset($_POST[$field])) { 1042 $this->$field = trim($_POST[$field]); 1043 } 1044 } 1045 $this->forceBools(); 1046 } 1047 1048 /* Provided in case child class does not implement it. Can force any values */ 1049 /* within some limited range. In particular, can force bools to be 0 or 1 */ 1050 function forceBools () { 1051 return; 1052 } 1053 1054 /* Updates an existing DB entry with the object's current values */ 1055 function updateObjectDB () { 1056 $this->prepareValues(); 1057 $database = mamboDatabase::getInstance(); 1058 $database->doSQL($this->updateSQL()); 1059 } 1060 1061 /* Deletes the current object from the DB */ 1062 function delete () { 1063 $table = $this->tableName(); 1064 $sql = "DELETE FROM $table WHERE id=$this->id"; 1065 $database = mamboDatabase::getInstance(); 1066 $database->doSQL($sql); 1067 } 1068 1069 /* Provided in case the child class does not provide a method for timeStampField */ 1070 function timeStampField () { 1071 return ''; 1072 } 1073 1074 /* Provides SQL for updating the DB with the contents of the current object */ 1075 function updateSQL () { 1076 $tabname = $this->tableName(); 1077 $sql = "UPDATE $tabname SET %s WHERE id=$this->id"; 1078 $exclude = $this->notSQL(); 1079 foreach (get_class_vars(get_class($this)) as $field=>$value) { 1080 if (!in_array($field,$exclude) AND $field[0] != '_') $setter[] = $field."='".$this->$field."'"; 1081 } 1082 $timestamp = $this->timeStampField(); 1083 if ($timestamp) $setter[] = $timestamp."='".date('Y-m-d H:i:s')."'"; 1084 return sprintf($sql,implode(',', $setter)); 1085 } 1086 1087 /* Default method for identifying fields not to be written to the DB */ 1088 /* The child classes may override this and return more items in the array */ 1089 function notSQL () { 1090 return array ('id'); 1091 } 1092 1093 /* Provides SQL to insert the current object into the DB */ 1094 function insertSQL () { 1095 $tabname = $this->tableName(); 1096 $sql = "INSERT INTO $tabname (%s) VALUES (%s)"; 1097 $exclude = $this->notSQL(); 1098 foreach (get_class_vars(get_class($this)) as $field=>$value) { 1099 if (!in_array($field,$exclude) AND $field[0] != '_') { 1100 $infields[] = $field; 1101 $values[] = "'".$this->$field."'"; 1102 } 1103 } 1104 $timestamp = $this->timeStampField(); 1105 if ($timestamp) { 1106 $infields[] = $timestamp; 1107 $values[] = "'".date('Y-m-d H:i:s')."'"; 1108 } 1109 return sprintf($sql, implode(',', $infields), implode(',', $values)); 1110 } 1111 1112 /* Copies any matching fields from some arbitrary object into the current object */ 1113 function setValues (&$anObject) { 1114 foreach (get_class_vars(get_class($this)) as $field=>$value) { 1115 if ($field != 'id' AND isset($anObject->$field)) $this->$field = $anObject->$field; 1116 } 1117 } 1118 1119 /* Ensures values can safely be written to DB; assumes magic quotes forced off */ 1120 function prepareValues () { 1121 $database = mamboDatabase::getInstance(); 1122 foreach (get_class_vars(get_class($this)) as $field=>$value) { 1123 if (!is_numeric($this->$field) AND is_string($this->$field)) $this->$field = $database->getEscaped($this->$field); 1124 } 1125 } 1126 1127 /* Takes some arbitrary SELECT type SQL and places the first or only result into the current object */ 1128 function readDataBase($sql) { 1129 $database = mamboDatabase::getInstance(); 1130 $database->setQuery( $sql ); 1131 if (!$database->loadObject($this)) $this->id = 0; 1132 } 1133 1134 } 1135 1136 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Feb 8 00:05:01 2012 | Cross-referenced by PHPXref 0.7 |
| Mambo API: Mambo is Free software released under the GNU/General Public License, Version 2 |