[ Index ] |
|
Code source de Joomla 1.0.13 |
1 <?php 2 /** 3 * @version $Id: database.mysqli.php 4994 2006-09-10 15:04:50Z friesengeist $ 4 * @package Joomla 5 * @subpackage Database 6 * @copyright Copyright (C) 2005 Open Source Matters. All rights reserved. 7 * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.php 8 * Joomla! is free software. This version may have been modified pursuant 9 * to the GNU General Public License, and as distributed it includes or 10 * is derivative of works licensed under the GNU General Public License or 11 * other free or open source software licenses. 12 * See COPYRIGHT.php for copyright notices and details. 13 */ 14 15 // no direct access 16 defined( '_VALID_MOS' ) or die( 'Restricted access' ); 17 18 /** 19 * Database connector class 20 * @subpackage Database 21 * @package Joomla 22 */ 23 class database { 24 /** @var string Internal variable to hold the query sql */ 25 var $_sql = ''; 26 /** @var int Internal variable to hold the database error number */ 27 var $_errorNum = 0; 28 /** @var string Internal variable to hold the database error message */ 29 var $_errorMsg = ''; 30 /** @var string Internal variable to hold the prefix used on all database tables */ 31 var $_table_prefix = ''; 32 /** @var Internal variable to hold the connector resource */ 33 var $_resource = ''; 34 /** @var Internal variable to hold the last query cursor */ 35 var $_cursor = null; 36 /** @var boolean Debug option */ 37 var $_debug = 0; 38 /** @var int The limit for the query */ 39 var $_limit = 0; 40 /** @var int The for offset for the limit */ 41 var $_offset = 0; 42 /** @var int A counter for the number of queries performed by the object instance */ 43 var $_ticker = 0; 44 /** @var array A log of queries */ 45 var $_log = null; 46 /** @var string The null/zero date string */ 47 var $_nullDate = '0000-00-00 00:00:00'; 48 /** @var string Quote for named objects */ 49 var $_nameQuote = '`'; 50 51 /** 52 * Database object constructor 53 * @param string Database host 54 * @param string Database user name 55 * @param string Database user password 56 * @param string Database name 57 * @param string Common prefix for all tables 58 * @param boolean If true and there is an error, go offline 59 */ 60 function database( $host='localhost', $user, $pass, $db='', $table_prefix='', $goOffline=true ) { 61 // perform a number of fatality checks, then die gracefully 62 if (!function_exists( 'mysqli_connect' )) { 63 $mosSystemError = 1; 64 if ($goOffline) { 65 $basePath = dirname( __FILE__ ); 66 include $basePath . '/../configuration.php'; 67 include $basePath . '/../offline.php'; 68 exit(); 69 } 70 } 71 if (!($this->_resource = @mysqli_connect( $host, $user, $pass ))) { 72 $mosSystemError = 2; 73 if ($goOffline) { 74 $basePath = dirname( __FILE__ ); 75 include $basePath . '/../configuration.php'; 76 include $basePath . '/../offline.php'; 77 exit(); 78 } 79 } 80 if ($db != '' && !mysqli_select_db($this->_resource, $db)) { 81 $mosSystemError = 3; 82 if ($goOffline) { 83 $basePath = dirname( __FILE__ ); 84 include $basePath . '/../configuration.php'; 85 include $basePath . '/../offline.php'; 86 exit(); 87 } 88 } 89 $this->_table_prefix = $table_prefix; 90 $this->_ticker = 0; 91 $this->_log = array(); 92 } 93 /** 94 * @param int 95 */ 96 function debug( $level ) { 97 $this->_debug = intval( $level ); 98 } 99 /** 100 * @return int The error number for the most recent query 101 */ 102 function getErrorNum() { 103 return $this->_errorNum; 104 } 105 /** 106 * @return string The error message for the most recent query 107 */ 108 function getErrorMsg() { 109 return str_replace( array( "\n", "'" ), array( '\n', "\'" ), $this->_errorMsg ); 110 } 111 /** 112 * Get a database escaped string 113 * @return string 114 */ 115 function getEscaped( $text ) { 116 return mysqli_real_escape_string( $this->_resource, $text ); 117 } 118 /** 119 * Get a quoted database escaped string 120 * @return string 121 */ 122 function Quote( $text ) { 123 return '\'' . $this->getEscaped( $text ) . '\''; 124 } 125 /** 126 * Quote an identifier name (field, table, etc) 127 * @param string The name 128 * @return string The quoted name 129 */ 130 function NameQuote( $s ) { 131 $q = $this->_nameQuote; 132 if (strlen( $q ) == 1) { 133 return $q . $s . $q; 134 } else { 135 return $q{0} . $s . $q{1}; 136 } 137 } 138 /** 139 * @return string The database prefix 140 */ 141 function getPrefix() { 142 return $this->_table_prefix; 143 } 144 /** 145 * @return string Quoted null/zero date string 146 */ 147 function getNullDate() { 148 return $this->_nullDate; 149 } 150 /** 151 * Sets the SQL query string for later execution. 152 * 153 * This function replaces a string identifier <var>$prefix</var> with the 154 * string held is the <var>_table_prefix</var> class variable. 155 * 156 * @param string The SQL query 157 * @param string The offset to start selection 158 * @param string The number of results to return 159 * @param string The common table prefix 160 */ 161 function setQuery( $sql, $offset = 0, $limit = 0, $prefix='#__' ) { 162 $this->_sql = $this->replacePrefix( $sql, $prefix ); 163 $this->_limit = intval( $limit ); 164 $this->_offset = intval( $offset ); 165 } 166 167 /** 168 * This function replaces a string identifier <var>$prefix</var> with the 169 * string held is the <var>_table_prefix</var> class variable. 170 * 171 * @param string The SQL query 172 * @param string The common table prefix 173 * @author thede, David McKinnis 174 */ 175 function replacePrefix( $sql, $prefix='#__' ) { 176 $sql = trim( $sql ); 177 178 $escaped = false; 179 $quoteChar = ''; 180 181 $n = strlen( $sql ); 182 183 $startPos = 0; 184 $literal = ''; 185 while ($startPos < $n) { 186 $ip = strpos($sql, $prefix, $startPos); 187 if ($ip === false) { 188 break; 189 } 190 191 $j = strpos( $sql, "'", $startPos ); 192 $k = strpos( $sql, '"', $startPos ); 193 if (($k !== FALSE) && (($k < $j) || ($j === FALSE))) { 194 $quoteChar = '"'; 195 $j = $k; 196 } else { 197 $quoteChar = "'"; 198 } 199 200 if ($j === false) { 201 $j = $n; 202 } 203 204 $literal .= str_replace( $prefix, $this->_table_prefix, substr( $sql, $startPos, $j - $startPos ) ); 205 $startPos = $j; 206 207 $j = $startPos + 1; 208 209 if ($j >= $n) { 210 break; 211 } 212 213 // quote comes first, find end of quote 214 while (TRUE) { 215 $k = strpos( $sql, $quoteChar, $j ); 216 $escaped = false; 217 if ($k === false) { 218 break; 219 } 220 $l = $k - 1; 221 while ($l >= 0 && $sql{$l} == '\\') { 222 $l--; 223 $escaped = !$escaped; 224 } 225 if ($escaped) { 226 $j = $k+1; 227 continue; 228 } 229 break; 230 } 231 if ($k === FALSE) { 232 // error in the query - no end quote; ignore it 233 break; 234 } 235 $literal .= substr( $sql, $startPos, $k - $startPos + 1 ); 236 $startPos = $k+1; 237 } 238 if ($startPos < $n) { 239 $literal .= substr( $sql, $startPos, $n - $startPos ); 240 } 241 return $literal; 242 } 243 /** 244 * @return string The current value of the internal SQL vairable 245 */ 246 function getQuery() { 247 return "<pre>" . htmlspecialchars( $this->_sql ) . "</pre>"; 248 } 249 /** 250 * Execute the query 251 * @return mixed A database resource if successful, FALSE if not. 252 */ 253 function query() { 254 global $mosConfig_debug; 255 if ($this->_limit > 0 || $this->_offset > 0) { 256 $this->_sql .= "\nLIMIT $this->_offset, $this->_limit"; 257 } 258 if ($this->_debug) { 259 $this->_ticker++; 260 $this->_log[] = $this->_sql; 261 } 262 $this->_errorNum = 0; 263 $this->_errorMsg = ''; 264 $this->_cursor = mysqli_query( $this->_resource, $this->_sql ); 265 if (!$this->_cursor) { 266 $this->_errorNum = mysqli_errno( $this->_resource ); 267 $this->_errorMsg = mysqli_error( $this->_resource ) . " SQL=$this->_sql"; 268 if ($this->_debug) { 269 trigger_error( mysqli_error( $this->_resource ), E_USER_NOTICE ); 270 //echo "<pre>" . $this->_sql . "</pre>\n"; 271 if (function_exists( 'debug_backtrace' )) { 272 foreach( debug_backtrace() as $back) { 273 if (@$back['file']) { 274 echo '<br />'.$back['file'].':'.$back['line']; 275 } 276 } 277 } 278 } 279 return false; 280 } 281 return $this->_cursor; 282 } 283 284 /** 285 * @return int The number of affected rows in the previous operation 286 */ 287 function getAffectedRows() { 288 return mysqli_affected_rows( $this->_resource ); 289 } 290 291 function query_batch( $abort_on_error=true, $p_transaction_safe = false) { 292 $this->_errorNum = 0; 293 $this->_errorMsg = ''; 294 if ($p_transaction_safe) { 295 $si = mysqli_get_server_info(); 296 preg_match_all( "/(\d+)\.(\d+)\.(\d+)/i", $si, $m ); 297 if ($m[1] >= 4) { 298 $this->_sql = 'START TRANSACTION;' . $this->_sql . '; COMMIT;'; 299 } else if ($m[2] >= 23 && $m[3] >= 19) { 300 $this->_sql = 'BEGIN WORK;' . $this->_sql . '; COMMIT;'; 301 } else if ($m[2] >= 23 && $m[3] >= 17) { 302 $this->_sql = 'BEGIN;' . $this->_sql . '; COMMIT;'; 303 } 304 } 305 $query_split = preg_split ("/[;]+/", $this->_sql); 306 $error = 0; 307 foreach ($query_split as $command_line) { 308 $command_line = trim( $command_line ); 309 if ($command_line != '') { 310 $this->_cursor = mysqli_query( $command_line, $this->_resource ); 311 if (!$this->_cursor) { 312 $error = 1; 313 $this->_errorNum .= mysqli_errno( $this->_resource ) . ' '; 314 $this->_errorMsg .= mysqli_error( $this->_resource )." SQL=$command_line <br />"; 315 if ($abort_on_error) { 316 return $this->_cursor; 317 } 318 } 319 } 320 } 321 return $error ? false : true; 322 } 323 324 /** 325 * Diagnostic function 326 */ 327 function explain() { 328 $temp = $this->_sql; 329 $this->_sql = "EXPLAIN $this->_sql"; 330 $this->query(); 331 332 if (!($cur = $this->query())) { 333 return null; 334 } 335 $first = true; 336 337 $buf = "<table cellspacing=\"1\" cellpadding=\"2\" border=\"0\" bgcolor=\"#000000\" align=\"center\">"; 338 $buf .= $this->getQuery(); 339 while ($row = mysqli_fetch_assoc( $cur )) { 340 if ($first) { 341 $buf .= "<tr>"; 342 foreach ($row as $k=>$v) { 343 $buf .= "<th bgcolor=\"#ffffff\">$k</th>"; 344 } 345 $buf .= "</tr>"; 346 $first = false; 347 } 348 $buf .= "<tr>"; 349 foreach ($row as $k=>$v) { 350 $buf .= "<td bgcolor=\"#ffffff\">$v</td>"; 351 } 352 $buf .= "</tr>"; 353 } 354 $buf .= "</table><br /> "; 355 mysqli_free_result( $cur ); 356 357 $this->_sql = $temp; 358 359 return "<div style=\"background-color:#FFFFCC\" align=\"left\">$buf</div>"; 360 } 361 /** 362 * @return int The number of rows returned from the most recent query. 363 */ 364 function getNumRows( $cur=null ) { 365 return mysqli_num_rows( $cur ? $cur : $this->_cursor ); 366 } 367 368 /** 369 * This method loads the first field of the first row returned by the query. 370 * 371 * @return The value returned in the query or null if the query failed. 372 */ 373 function loadResult() { 374 if (!($cur = $this->query())) { 375 return null; 376 } 377 $ret = null; 378 if ($row = mysqli_fetch_row( $cur )) { 379 $ret = $row[0]; 380 } 381 mysqli_free_result( $cur ); 382 return $ret; 383 } 384 /** 385 * Load an array of single field results into an array 386 */ 387 function loadResultArray($numinarray = 0) { 388 if (!($cur = $this->query())) { 389 return null; 390 } 391 $array = array(); 392 while ($row = mysqli_fetch_row( $cur )) { 393 $array[] = $row[$numinarray]; 394 } 395 mysqli_free_result( $cur ); 396 return $array; 397 } 398 /** 399 * Load a assoc list of database rows 400 * @param string The field name of a primary key 401 * @return array If <var>key</var> is empty as sequential list of returned records. 402 */ 403 function loadAssocList( $key='' ) { 404 if (!($cur = $this->query())) { 405 return null; 406 } 407 $array = array(); 408 while ($row = mysqli_fetch_assoc( $cur )) { 409 if ($key) { 410 $array[$row[$key]] = $row; 411 } else { 412 $array[] = $row; 413 } 414 } 415 mysqli_free_result( $cur ); 416 return $array; 417 } 418 /** 419 * This global function loads the first row of a query into an object 420 * 421 * If an object is passed to this function, the returned row is bound to the existing elements of <var>object</var>. 422 * If <var>object</var> has a value of null, then all of the returned query fields returned in the object. 423 * @param string The SQL query 424 * @param object The address of variable 425 */ 426 function loadObject( &$object ) { 427 if ($object != null) { 428 if (!($cur = $this->query())) { 429 return false; 430 } 431 if ($array = mysqli_fetch_assoc( $cur )) { 432 mysqli_free_result( $cur ); 433 mosBindArrayToObject( $array, $object, null, null, false ); 434 return true; 435 } else { 436 return false; 437 } 438 } else { 439 if ($cur = $this->query()) { 440 if ($object = mysqli_fetch_object( $cur )) { 441 mysqli_free_result( $cur ); 442 return true; 443 } else { 444 $object = null; 445 return false; 446 } 447 } else { 448 return false; 449 } 450 } 451 } 452 /** 453 * Load a list of database objects 454 * @param string The field name of a primary key 455 * @return array If <var>key</var> is empty as sequential list of returned records. 456 * If <var>key</var> is not empty then the returned array is indexed by the value 457 * the database key. Returns <var>null</var> if the query fails. 458 */ 459 function loadObjectList( $key='' ) { 460 if (!($cur = $this->query())) { 461 return null; 462 } 463 $array = array(); 464 while ($row = mysqli_fetch_object( $cur )) { 465 if ($key) { 466 $array[$row->$key] = $row; 467 } else { 468 $array[] = $row; 469 } 470 } 471 mysqli_free_result( $cur ); 472 return $array; 473 } 474 /** 475 * @return The first row of the query. 476 */ 477 function loadRow() { 478 if (!($cur = $this->query())) { 479 return null; 480 } 481 $ret = null; 482 if ($row = mysqli_fetch_row( $cur )) { 483 $ret = $row; 484 } 485 mysqli_free_result( $cur ); 486 return $ret; 487 } 488 /** 489 * Load a list of database rows (numeric column indexing) 490 * @param string The field name of a primary key 491 * @return array If <var>key</var> is empty as sequential list of returned records. 492 * If <var>key</var> is not empty then the returned array is indexed by the value 493 * the database key. Returns <var>null</var> if the query fails. 494 */ 495 function loadRowList( $key='' ) { 496 if (!($cur = $this->query())) { 497 return null; 498 } 499 $array = array(); 500 while ($row = mysqli_fetch_row( $cur )) { 501 if ($key) { 502 $array[$row[$key]] = $row; 503 } else { 504 $array[] = $row; 505 } 506 } 507 mysqli_free_result( $cur ); 508 return $array; 509 } 510 /** 511 * Document::db_insertObject() 512 * 513 * { Description } 514 * 515 * @param string $table This is expected to be a valid (and safe!) table name 516 * @param [type] $keyName 517 * @param [type] $verbose 518 */ 519 function insertObject( $table, &$object, $keyName = NULL, $verbose=false ) { 520 $fmtsql = "INSERT INTO $table ( %s ) VALUES ( %s ) "; 521 $fields = array(); 522 foreach (get_object_vars( $object ) as $k => $v) { 523 if (is_array($v) or is_object($v) or $v === NULL) { 524 continue; 525 } 526 if ($k[0] == '_') { // internal field 527 continue; 528 } 529 $fields[] = $this->NameQuote( $k ); 530 $values[] = $this->Quote( $v ); 531 } 532 $this->setQuery( sprintf( $fmtsql, implode( ",", $fields ) , implode( ",", $values ) ) ); 533 ($verbose) && print "$sql<br />\n"; 534 if (!$this->query()) { 535 return false; 536 } 537 $id = mysqli_insert_id( $this->_resource ); 538 ($verbose) && print "id=[$id]<br />\n"; 539 if ($keyName && $id) { 540 $object->$keyName = $id; 541 } 542 return true; 543 } 544 545 /** 546 * Document::db_updateObject() 547 * 548 * { Description } 549 * 550 * @param string $table This is expected to be a valid (and safe!) table name 551 * @param [type] $updateNulls 552 */ 553 function updateObject( $table, &$object, $keyName, $updateNulls=true ) { 554 $fmtsql = "UPDATE $table SET %s WHERE %s"; 555 $tmp = array(); 556 foreach (get_object_vars( $object ) as $k => $v) { 557 if( is_array($v) or is_object($v) or $k[0] == '_' ) { // internal or NA field 558 continue; 559 } 560 if( $k == $keyName ) { // PK not to be updated 561 $where = $keyName . '=' . $this->Quote( $v ); 562 continue; 563 } 564 if ($v === NULL && !$updateNulls) { 565 continue; 566 } 567 if( $v == '' ) { 568 $val = "''"; 569 } else { 570 $val = $this->Quote( $v ); 571 } 572 $tmp[] = $this->NameQuote( $k ) . '=' . $val; 573 } 574 $this->setQuery( sprintf( $fmtsql, implode( ",", $tmp ) , $where ) ); 575 return $this->query(); 576 } 577 578 /** 579 * @param boolean If TRUE, displays the last SQL statement sent to the database 580 * @return string A standised error message 581 */ 582 function stderr( $showSQL = false ) { 583 return "DB function failed with error number $this->_errorNum" 584 ."<br /><font color=\"red\">$this->_errorMsg</font>" 585 .($showSQL ? "<br />SQL = <pre>$this->_sql</pre>" : ''); 586 } 587 588 function insertid() { 589 return mysqli_insert_id( $this->_resource ); 590 } 591 592 function getVersion() { 593 return mysqli_get_server_info( $this->_resource ); 594 } 595 596 /** 597 * @return array A list of all the tables in the database 598 */ 599 function getTableList() { 600 $this->setQuery( 'SHOW TABLES' ); 601 return $this->loadResultArray(); 602 } 603 /** 604 * @param array A list of valid (and safe!) table names 605 * @return array A list the create SQL for the tables 606 */ 607 function getTableCreate( $tables ) { 608 $result = array(); 609 610 foreach ($tables as $tblval) { 611 $this->setQuery( 'SHOW CREATE table ' . $this->getEscaped( $tblval ) ); 612 $rows = $this->loadRowList(); 613 foreach ($rows as $row) { 614 $result[$tblval] = $row[1]; 615 } 616 } 617 618 return $result; 619 } 620 /** 621 * @param array A list of valid (and safe!) table names 622 * @return array An array of fields by table 623 */ 624 function getTableFields( $tables ) { 625 $result = array(); 626 627 foreach ($tables as $tblval) { 628 $this->setQuery( 'SHOW FIELDS FROM ' . $tblval ); 629 $fields = $this->loadObjectList(); 630 foreach ($fields as $field) { 631 $result[$tblval][$field->Field] = preg_replace("/[(0-9)]/",'', $field->Type ); 632 } 633 } 634 635 return $result; 636 } 637 638 /** 639 * Fudge method for ADOdb compatibility 640 */ 641 function GenID( $foo1=null, $foo2=null ) { 642 return '0'; 643 } 644 } 645 646 /** 647 * mosDBTable Abstract Class. 648 * @abstract 649 * @package Joomla 650 * @subpackage Database 651 * 652 * Parent classes to all database derived objects. Customisation will generally 653 * not involve tampering with this object. 654 * @package Joomla 655 * @author Andrew Eddie <eddieajau@users.sourceforge.net 656 */ 657 class mosDBTable { 658 /** @var string Name of the table in the db schema relating to child class */ 659 var $_tbl = ''; 660 /** @var string Name of the primary key field in the table */ 661 var $_tbl_key = ''; 662 /** @var string Error message */ 663 var $_error = ''; 664 /** @var mosDatabase Database connector */ 665 var $_db = null; 666 667 /** 668 * Object constructor to set table and key field 669 * 670 * Can be overloaded/supplemented by the child class 671 * @param string $table name of the table in the db schema relating to child class 672 * @param string $key name of the primary key field in the table 673 */ 674 function mosDBTable( $table, $key, &$db ) { 675 $this->_tbl = $table; 676 $this->_tbl_key = $key; 677 $this->_db =& $db; 678 } 679 680 /** 681 * Returns an array of public properties 682 * @return array 683 */ 684 function getPublicProperties() { 685 static $cache = null; 686 if (is_null( $cache )) { 687 $cache = array(); 688 foreach (get_class_vars( get_class( $this ) ) as $key=>$val) { 689 if (substr( $key, 0, 1 ) != '_') { 690 $cache[] = $key; 691 } 692 } 693 } 694 return $cache; 695 } 696 /** 697 * Filters public properties 698 * @access protected 699 * @param array List of fields to ignore 700 */ 701 function filter( $ignoreList=null ) { 702 $ignore = is_array( $ignoreList ); 703 704 $iFilter = new InputFilter(); 705 foreach ($this->getPublicProperties() as $k) { 706 if ($ignore && in_array( $k, $ignoreList ) ) { 707 continue; 708 } 709 $this->$k = $iFilter->process( $this->$k ); 710 } 711 } 712 /** 713 * @return string Returns the error message 714 */ 715 function getError() { 716 return $this->_error; 717 } 718 /** 719 * Gets the value of the class variable 720 * @param string The name of the class variable 721 * @return mixed The value of the class var (or null if no var of that name exists) 722 */ 723 function get( $_property ) { 724 if(isset( $this->$_property )) { 725 return $this->$_property; 726 } else { 727 return null; 728 } 729 } 730 731 /** 732 * Set the value of the class variable 733 * @param string The name of the class variable 734 * @param mixed The value to assign to the variable 735 */ 736 function set( $_property, $_value ) { 737 $this->$_property = $_value; 738 } 739 740 /** 741 * Resets public properties 742 * @param mixed The value to set all properties to, default is null 743 */ 744 function reset( $value=null ) { 745 $keys = $this->getPublicProperties(); 746 foreach ($keys as $k) { 747 $this->$k = $value; 748 } 749 } 750 /** 751 * binds a named array/hash to this object 752 * 753 * can be overloaded/supplemented by the child class 754 * @param array $hash named array 755 * @return null|string null is operation was satisfactory, otherwise returns an error 756 */ 757 function bind( $array, $ignore='' ) { 758 if (!is_array( $array )) { 759 $this->_error = strtolower(get_class( $this ))."::bind failed."; 760 return false; 761 } else { 762 return mosBindArrayToObject( $array, $this, $ignore ); 763 } 764 } 765 766 /** 767 * binds an array/hash to this object 768 * @param int $oid optional argument, if not specifed then the value of current key is used 769 * @return any result from the database operation 770 */ 771 function load( $oid=null ) { 772 $k = $this->_tbl_key; 773 774 if ($oid !== null) { 775 $this->$k = $oid; 776 } 777 778 $oid = $this->$k; 779 780 if ($oid === null) { 781 return false; 782 } 783 //Note: Prior to PHP 4.2.0, Uninitialized class variables will not be reported by get_class_vars(). 784 $class_vars = get_class_vars(get_class($this)); 785 foreach ($class_vars as $name => $value) { 786 if (($name != $k) and ($name != "_db") and ($name != "_tbl") and ($name != "_tbl_key")) { 787 $this->$name = $value; 788 } 789 } 790 791 $this->reset(); 792 793 $query = "SELECT *" 794 . "\n FROM $this->_tbl" 795 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $oid ) 796 ; 797 $this->_db->setQuery( $query ); 798 799 return $this->_db->loadObject( $this ); 800 } 801 802 /** 803 * generic check method 804 * 805 * can be overloaded/supplemented by the child class 806 * @return boolean True if the object is ok 807 */ 808 function check() { 809 return true; 810 } 811 812 /** 813 * Inserts a new row if id is zero or updates an existing row in the database table 814 * 815 * Can be overloaded/supplemented by the child class 816 * @param boolean If false, null object variables are not updated 817 * @return null|string null if successful otherwise returns and error message 818 */ 819 function store( $updateNulls=false ) { 820 $k = $this->_tbl_key; 821 822 if ($this->$k) { 823 $ret = $this->_db->updateObject( $this->_tbl, $this, $this->_tbl_key, $updateNulls ); 824 } else { 825 $ret = $this->_db->insertObject( $this->_tbl, $this, $this->_tbl_key ); 826 } 827 if( !$ret ) { 828 $this->_error = strtolower(get_class( $this ))."::store failed <br />" . $this->_db->getErrorMsg(); 829 return false; 830 } else { 831 return true; 832 } 833 } 834 /** 835 * @param string $where This is expected to be a valid (and safe!) SQL expression 836 */ 837 function move( $dirn, $where='' ) { 838 $k = $this->_tbl_key; 839 840 $sql = "SELECT $this->_tbl_key, ordering FROM $this->_tbl"; 841 842 if ($dirn < 0) { 843 $sql .= "\n WHERE ordering < " . (int) $this->ordering; 844 $sql .= ($where ? "\n AND $where" : ''); 845 $sql .= "\n ORDER BY ordering DESC"; 846 $sql .= "\n LIMIT 1"; 847 } else if ($dirn > 0) { 848 $sql .= "\n WHERE ordering > " . (int) $this->ordering; 849 $sql .= ($where ? "\n AND $where" : ''); 850 $sql .= "\n ORDER BY ordering"; 851 $sql .= "\n LIMIT 1"; 852 } else { 853 $sql .= "\nWHERE ordering = " . (int) $this->ordering; 854 $sql .= ($where ? "\n AND $where" : ''); 855 $sql .= "\n ORDER BY ordering"; 856 $sql .= "\n LIMIT 1"; 857 } 858 859 $this->_db->setQuery( $sql ); 860 //echo 'A: ' . $this->_db->getQuery(); 861 862 863 $row = null; 864 if ($this->_db->loadObject( $row )) { 865 $query = "UPDATE $this->_tbl" 866 . "\n SET ordering = " . (int) $row->ordering 867 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->$k ) 868 ; 869 $this->_db->setQuery( $query ); 870 871 if (!$this->_db->query()) { 872 $err = $this->_db->getErrorMsg(); 873 die( $err ); 874 } 875 //echo 'B: ' . $this->_db->getQuery(); 876 877 $query = "UPDATE $this->_tbl" 878 . "\n SET ordering = " . (int) $this->ordering 879 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $row->$k ) 880 ; 881 $this->_db->setQuery( $query ); 882 //echo 'C: ' . $this->_db->getQuery(); 883 884 if (!$this->_db->query()) { 885 $err = $this->_db->getErrorMsg(); 886 die( $err ); 887 } 888 889 $this->ordering = $row->ordering; 890 } else { 891 $query = "UPDATE $this->_tbl" 892 . "\n SET ordering = " . (int) $this->ordering 893 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->$k ) 894 ; 895 $this->_db->setQuery( $query ); 896 //echo 'D: ' . $this->_db->getQuery(); 897 898 899 if (!$this->_db->query()) { 900 $err = $this->_db->getErrorMsg(); 901 die( $err ); 902 } 903 } 904 } 905 /** 906 * Compacts the ordering sequence of the selected records 907 * @param string Additional where query to limit ordering to a particular subset of records. This is expected to be a valid (and safe!) SQL expression 908 */ 909 function updateOrder( $where='' ) { 910 $k = $this->_tbl_key; 911 912 if (!array_key_exists( 'ordering', get_class_vars( strtolower(get_class( $this )) ) )) { 913 $this->_error = "WARNING: ".strtolower(get_class( $this ))." does not support ordering."; 914 return false; 915 } 916 917 if ($this->_tbl == "#__content_frontpage") { 918 $order2 = ", content_id DESC"; 919 } else { 920 $order2 = ''; 921 } 922 923 $query = "SELECT $this->_tbl_key, ordering" 924 . "\n FROM $this->_tbl" 925 . ( $where ? "\n WHERE $where" : '' ) 926 . "\n ORDER BY ordering$order2 " 927 ; 928 $this->_db->setQuery( $query ); 929 if (!($orders = $this->_db->loadObjectList())) { 930 $this->_error = $this->_db->getErrorMsg(); 931 return false; 932 } 933 // first pass, compact the ordering numbers 934 for ($i=0, $n=count( $orders ); $i < $n; $i++) { 935 if ($orders[$i]->ordering >= 0) { 936 $orders[$i]->ordering = $i+1; 937 } 938 } 939 940 $shift = 0; 941 $n=count( $orders ); 942 for ($i=0; $i < $n; $i++) { 943 //echo "i=$i id=".$orders[$i]->$k." order=".$orders[$i]->ordering; 944 if ($orders[$i]->$k == $this->$k) { 945 // place 'this' record in the desired location 946 $orders[$i]->ordering = min( $this->ordering, $n ); 947 $shift = 1; 948 } else if ($orders[$i]->ordering >= $this->ordering && $this->ordering > 0) { 949 $orders[$i]->ordering++; 950 } 951 } 952 //echo '<pre>';print_r($orders);echo '</pre>'; 953 // compact once more until I can find a better algorithm 954 for ($i=0, $n=count( $orders ); $i < $n; $i++) { 955 if ($orders[$i]->ordering >= 0) { 956 $orders[$i]->ordering = $i+1; 957 $query = "UPDATE $this->_tbl" 958 . "\n SET ordering = " . (int) $orders[$i]->ordering 959 . "\n WHERE $k = " . $this->_db->Quote( $orders[$i]->$k ) 960 ; 961 $this->_db->setQuery( $query); 962 $this->_db->query(); 963 //echo '<br />'.$this->_db->getQuery(); 964 } 965 } 966 967 // if we didn't reorder the current record, make it last 968 if ($shift == 0) { 969 $order = $n+1; 970 $query = "UPDATE $this->_tbl" 971 . "\n SET ordering = " . (int) $order 972 . "\n WHERE $k = " . $this->_db->Quote( $this->$k ) 973 ; 974 $this->_db->setQuery( $query ); 975 $this->_db->query(); 976 //echo '<br />'.$this->_db->getQuery(); 977 } 978 return true; 979 } 980 /** 981 * Generic check for whether dependancies exist for this object in the db schema 982 * 983 * can be overloaded/supplemented by the child class 984 * @param string $msg Error message returned 985 * @param int Optional key index 986 * @param array Optional array to compiles standard joins: format [label=>'Label',name=>'table name',idfield=>'field',joinfield=>'field']. This is expected to hold only valid (and safe!) SQL expressions 987 * @return true|false 988 */ 989 function canDelete( $oid=null, $joins=null ) { 990 $k = $this->_tbl_key; 991 if ($oid) { 992 $this->$k = $oid; 993 } 994 if (is_array( $joins )) { 995 $select = $k; 996 $join = ''; 997 foreach( $joins as $table ) { 998 $tblName = $this->getEscaped( $table['name'] ); 999 $idField = $this->getEscaped( $table['idfield'] ); 1000 $jnField = $this->getEscaped( $table['joinfield'] ); 1001 $select .= ",\n COUNT(DISTINCT `$tblName`.`$idField`) AS `count_".substr($tblName, 3)."_$idField`"; 1002 $join .= "\n LEFT JOIN `$tblName` ON `$tblName`.`$jnField` = `$this->_tbl`.`$k`"; 1003 } 1004 1005 $query = "SELECT $select" 1006 . "\n FROM `$this->_tbl`" 1007 . $join 1008 . "\n WHERE `$this->_tbl`.`$k` = ". (int) $this->$k 1009 . "\n GROUP BY `$this->_tbl`.`$k`" 1010 ; 1011 $this->_db->setQuery( $query ); 1012 1013 $obj = null; 1014 if (!$this->_db->loadObject($obj)) { 1015 $this->_error = $this->_db->getErrorMsg(); 1016 return false; 1017 } 1018 $msg = array(); 1019 foreach( $joins as $table ) { 1020 $tblName = $this->getEscaped( $table['name'] ); 1021 $idField = $this->getEscaped( $table['idfield'] ); 1022 $k = 'count_'.substr($tblName, 3).'_'.$idField; 1023 if ($obj->$k) { 1024 $msg[] = $table['label']; 1025 } 1026 } 1027 1028 if (count( $msg )) { 1029 $this->_error = "noDeleteRecord" . ": " . implode( ', ', $msg ); 1030 return false; 1031 } else { 1032 return true; 1033 } 1034 } 1035 1036 return true; 1037 } 1038 1039 /** 1040 * Default delete method 1041 * 1042 * can be overloaded/supplemented by the child class 1043 * @return true if successful otherwise returns and error message 1044 */ 1045 function delete( $oid=null ) { 1046 //if (!$this->canDelete( $msg )) { 1047 // return $msg; 1048 //} 1049 1050 $k = $this->_tbl_key; 1051 if ($oid) { 1052 $this->$k = intval( $oid ); 1053 } 1054 1055 $query = "DELETE FROM $this->_tbl" 1056 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->$k ) 1057 ; 1058 $this->_db->setQuery( $query ); 1059 1060 if ($this->_db->query()) { 1061 return true; 1062 } else { 1063 $this->_error = $this->_db->getErrorMsg(); 1064 return false; 1065 } 1066 } 1067 1068 /** 1069 * Checks out an object 1070 * @param int User id 1071 * @param int Object id 1072 */ 1073 function checkout( $user_id, $oid=null ) { 1074 if (!array_key_exists( 'checked_out', get_class_vars( strtolower(get_class( $this )) ) )) { 1075 $this->_error = "WARNING: ".strtolower(get_class( $this ))." does not support checkouts."; 1076 return false; 1077 } 1078 $k = $this->_tbl_key; 1079 if ($oid !== null) { 1080 $this->$k = $oid; 1081 } 1082 1083 $time = date( 'Y-m-d H:i:s' ); 1084 if (intval( $user_id )) { 1085 $user_id = intval( $user_id ); 1086 // new way of storing editor, by id 1087 $query = "UPDATE $this->_tbl" 1088 . "\n SET checked_out = $user_id, checked_out_time = " . $this->_db->Quote( $time ) 1089 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->$k ) 1090 ; 1091 $this->_db->setQuery( $query ); 1092 1093 $this->checked_out = $user_id; 1094 $this->checked_out_time = $time; 1095 } else { 1096 $user_id = $this->_db->Quote( $user_id ); 1097 // old way of storing editor, by name 1098 $query = "UPDATE $this->_tbl" 1099 . "\n SET checked_out = 1, checked_out_time = " . $this->_db->Quote( $time ) . ", editor = $user_id" 1100 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->$k ) 1101 ; 1102 $this->_db->setQuery( $query ); 1103 1104 $this->checked_out = 1; 1105 $this->checked_out_time = $time; 1106 $this->checked_out_editor = $user_id; 1107 } 1108 1109 return $this->_db->query(); 1110 } 1111 1112 /** 1113 * Checks in an object 1114 * @param int Object id 1115 */ 1116 function checkin( $oid=null ) { 1117 if (!array_key_exists( 'checked_out', get_class_vars( strtolower(get_class( $this )) ) )) { 1118 $this->_error = "WARNING: ".strtolower(get_class( $this ))." does not support checkin."; 1119 return false; 1120 } 1121 1122 $k = $this->_tbl_key; 1123 $nullDate = $this->_db->getNullDate(); 1124 1125 if ($oid !== null) { 1126 $this->$k = intval( $oid ); 1127 } 1128 if ($this->$k == NULL) { 1129 return false; 1130 } 1131 1132 $query = "UPDATE $this->_tbl" 1133 . "\n SET checked_out = 0, checked_out_time = " . $this->_db->Quote( $nullDate ) 1134 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->$k ) 1135 ; 1136 $this->_db->setQuery( $query ); 1137 1138 $this->checked_out = 0; 1139 $this->checked_out_time = ''; 1140 1141 return $this->_db->query(); 1142 } 1143 1144 /** 1145 * Increments the hit counter for an object 1146 * @param int Object id 1147 */ 1148 function hit( $oid=null ) { 1149 global $mosConfig_enable_log_items; 1150 1151 $k = $this->_tbl_key; 1152 if ($oid !== null) { 1153 $this->$k = intval( $oid ); 1154 } 1155 1156 $query = "UPDATE $this->_tbl" 1157 . "\n SET hits = ( hits + 1 )" 1158 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->id ) 1159 ; 1160 $this->_db->setQuery( $query ); 1161 $this->_db->query(); 1162 1163 if (@$mosConfig_enable_log_items) { 1164 $now = date( 'Y-m-d' ); 1165 $query = "SELECT hits" 1166 . "\n FROM #__core_log_items" 1167 . "\n WHERE time_stamp = " . $this->_db->Quote( $now ) 1168 . "\n AND item_table = " . $this->_db->Quote( $this->_tbl ) 1169 . "\n AND item_id = " . $this->_db->Quote( $this->$k ) 1170 ; 1171 $this->_db->setQuery( $query ); 1172 $hits = intval( $this->_db->loadResult() ); 1173 if ($hits) { 1174 $query = "UPDATE #__core_log_items" 1175 . "\n SET hits = ( hits + 1 )" 1176 . "\n WHERE time_stamp = " . $this->_db->Quote( $now ) 1177 . "\n AND item_table = " . $this->_db->Quote( $this->_tbl ) 1178 . "\n AND item_id = " . $this->_db->Quote( $this->$k ) 1179 ; 1180 $this->_db->setQuery( $query ); 1181 $this->_db->query(); 1182 } else { 1183 $query = "INSERT INTO #__core_log_items" 1184 . "\n VALUES ( " . $this->_db->Quote( $now ) . ", " . $this->_db->Quote( $this->_tbl ) . ", " . $this->_db->Quote( $this->$k ) . ", 1 )" 1185 ; 1186 $this->_db->setQuery( $query ); 1187 $this->_db->query(); 1188 } 1189 } 1190 } 1191 1192 /** 1193 * Tests if item is checked out 1194 * @param int A user id 1195 * @return boolean 1196 */ 1197 function isCheckedOut( $user_id=0 ) { 1198 if ($user_id) { 1199 return ($this->checked_out && $this->checked_out != $user_id); 1200 } else { 1201 return $this->checked_out; 1202 } 1203 } 1204 1205 /** 1206 * Generic save function 1207 * @param array Source array for binding to class vars 1208 * @param string Filter for the order updating. This is expected to be a valid (and safe!) SQL expression 1209 * @returns TRUE if completely successful, FALSE if partially or not succesful 1210 * NOTE: Filter will be deprecated in verion 1.1 1211 */ 1212 function save( $source, $order_filter='' ) { 1213 if (!$this->bind( $source )) { 1214 return false; 1215 } 1216 if (!$this->check()) { 1217 return false; 1218 } 1219 if (!$this->store()) { 1220 return false; 1221 } 1222 if (!$this->checkin()) { 1223 return false; 1224 } 1225 1226 if ($order_filter) { 1227 $filter_value = $this->$order_filter; 1228 $this->updateOrder( $order_filter ? "`$order_filter` = " . $this->_db->Quote( $filter_value ) : '' ); 1229 } 1230 $this->_error = ''; 1231 return true; 1232 } 1233 1234 /** 1235 * @deprecated As of 1.0.3, replaced by publish 1236 */ 1237 function publish_array( $cid=null, $publish=1, $user_id=0 ) { 1238 $this->publish( $cid, $publish, $user_id ); 1239 } 1240 1241 /** 1242 * Generic Publish/Unpublish function 1243 * @param array An array of id numbers 1244 * @param integer 0 if unpublishing, 1 if publishing 1245 * @param integer The id of the user performnig the operation 1246 * @since 1.0.4 1247 */ 1248 function publish( $cid=null, $publish=1, $user_id=0 ) { 1249 mosArrayToInts( $cid, array() ); 1250 $user_id = (int) $user_id; 1251 $publish = (int) $publish; 1252 $k = $this->_tbl_key; 1253 1254 if (count( $cid ) < 1) { 1255 $this->_error = "No items selected."; 1256 return false; 1257 } 1258 1259 $cids = $this->_tbl_key . '=' . implode( ' OR ' . $this->_tbl_key . '=', $cid ); 1260 1261 $query = "UPDATE $this->_tbl" 1262 . "\n SET published = " . (int) $publish 1263 . "\n WHERE ($cids)" 1264 . "\n AND (checked_out = 0 OR checked_out = " . (int) $user_id . ")" 1265 ; 1266 $this->_db->setQuery( $query ); 1267 if (!$this->_db->query()) { 1268 $this->_error = $this->_db->getErrorMsg(); 1269 return false; 1270 } 1271 1272 if (count( $cid ) == 1) { 1273 $this->checkin( $cid[0] ); 1274 } 1275 $this->_error = ''; 1276 return true; 1277 } 1278 1279 /** 1280 * Export item list to xml 1281 * @param boolean Map foreign keys to text values 1282 */ 1283 function toXML( $mapKeysToText=false ) { 1284 $xml = '<record table="' . $this->_tbl . '"'; 1285 1286 if ($mapKeysToText) { 1287 $xml .= ' mapkeystotext="true"'; 1288 } 1289 $xml .= '>'; 1290 foreach (get_object_vars( $this ) as $k => $v) { 1291 if (is_array($v) or is_object($v) or $v === NULL) { 1292 continue; 1293 } 1294 if ($k[0] == '_') { // internal field 1295 continue; 1296 } 1297 $xml .= '<' . $k . '><![CDATA[' . $v . ']]></' . $k . '>'; 1298 } 1299 $xml .= '</record>'; 1300 1301 return $xml; 1302 } 1303 } 1304 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Wed Nov 21 14:43:32 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |