1<?php 2/** 3 * @package FrameworkOnFramework 4 * @subpackage database 5 * @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved. 6 * @license GNU General Public License version 2 or later; see LICENSE.txt 7 * @note This file has been modified by the Joomla! Project and no longer reflects the original work of its author. 8 * 9 * This file is adapted from the Joomla! Platform. It is used to iterate a database cursor returning FOFTable objects 10 * instead of plain stdClass objects 11 */ 12 13// Protect from unauthorized access 14defined('FOF_INCLUDED') or die; 15 16/** 17 * This crazy three line bit is required to convince Joomla! to load JDatabaseInterface which is on the same file as the 18 * abstract JDatabaseDriver class for reasons that beat me. It makes no sense. Furthermore, jimport on Joomla! 3.4 19 * doesn't seem to actually load the file, merely registering the association in the autoloader. Hence the class_exists 20 * in here. 21 */ 22jimport('joomla.database.driver'); 23jimport('joomla.database.driver.mysqli'); 24class_exists('JDatabaseDriver', true); 25 26/** 27 * Joomla! pass-through database driver. 28 */ 29class FOFDatabaseDriverJoomla extends FOFDatabase implements FOFDatabaseInterface 30{ 31 /** @var FOFDatabase The real database connection object */ 32 private $dbo; 33 34 /** 35 * @var string The character(s) used to quote SQL statement names such as table names or field names, 36 * etc. The child classes should define this as necessary. If a single character string the 37 * same character is used for both sides of the quoted name, else the first character will be 38 * used for the opening quote and the second for the closing quote. 39 * @since 11.1 40 */ 41 protected $nameQuote = ''; 42 43 /** 44 * Is this driver supported 45 * 46 * @since 11.2 47 */ 48 public static function isSupported() 49 { 50 return true; 51 } 52 53 /** 54 * Database object constructor 55 * 56 * @param array $options List of options used to configure the connection 57 */ 58 public function __construct($options = array()) 59 { 60 // Get best matching Akeeba Backup driver instance 61 $this->dbo = JFactory::getDbo(); 62 63 $reflection = new ReflectionClass($this->dbo); 64 65 try 66 { 67 $refProp = $reflection->getProperty('nameQuote'); 68 $refProp->setAccessible(true); 69 $this->nameQuote = $refProp->getValue($this->dbo); 70 } 71 catch (Exception $e) 72 { 73 $this->nameQuote = '`'; 74 } 75 } 76 77 public function close() 78 { 79 if (method_exists($this->dbo, 'close')) 80 { 81 $this->dbo->close(); 82 } 83 elseif (method_exists($this->dbo, 'disconnect')) 84 { 85 $this->dbo->disconnect(); 86 } 87 } 88 89 public function disconnect() 90 { 91 $this->close(); 92 } 93 94 public function open() 95 { 96 if (method_exists($this->dbo, 'open')) 97 { 98 $this->dbo->open(); 99 } 100 elseif (method_exists($this->dbo, 'connect')) 101 { 102 $this->dbo->connect(); 103 } 104 } 105 106 public function connect() 107 { 108 $this->open(); 109 } 110 111 public function connected() 112 { 113 if (method_exists($this->dbo, 'connected')) 114 { 115 return $this->dbo->connected(); 116 } 117 118 return true; 119 } 120 121 public function escape($text, $extra = false) 122 { 123 return $this->dbo->escape($text, $extra); 124 } 125 126 public function execute() 127 { 128 if (method_exists($this->dbo, 'execute')) 129 { 130 return $this->dbo->execute(); 131 } 132 133 return $this->dbo->query(); 134 } 135 136 public function getAffectedRows() 137 { 138 if (method_exists($this->dbo, 'getAffectedRows')) 139 { 140 return $this->dbo->getAffectedRows(); 141 } 142 143 return 0; 144 } 145 146 public function getCollation() 147 { 148 if (method_exists($this->dbo, 'getCollation')) 149 { 150 return $this->dbo->getCollation(); 151 } 152 153 return 'utf8_general_ci'; 154 } 155 156 public function getConnection() 157 { 158 if (method_exists($this->dbo, 'getConnection')) 159 { 160 return $this->dbo->getConnection(); 161 } 162 163 return null; 164 } 165 166 public function getCount() 167 { 168 if (method_exists($this->dbo, 'getCount')) 169 { 170 return $this->dbo->getCount(); 171 } 172 173 return 0; 174 } 175 176 public function getDateFormat() 177 { 178 if (method_exists($this->dbo, 'getDateFormat')) 179 { 180 return $this->dbo->getDateFormat(); 181 } 182 183 return 'Y-m-d H:i:s';; 184 } 185 186 public function getMinimum() 187 { 188 if (method_exists($this->dbo, 'getMinimum')) 189 { 190 return $this->dbo->getMinimum(); 191 } 192 193 return '5.0.40'; 194 } 195 196 public function getNullDate() 197 { 198 if (method_exists($this->dbo, 'getNullDate')) 199 { 200 return $this->dbo->getNullDate(); 201 } 202 203 return '0000-00-00 00:00:00'; 204 } 205 206 public function getNumRows($cursor = null) 207 { 208 if (method_exists($this->dbo, 'getNumRows')) 209 { 210 return $this->dbo->getNumRows($cursor); 211 } 212 213 return 0; 214 } 215 216 public function getQuery($new = false) 217 { 218 if (method_exists($this->dbo, 'getQuery')) 219 { 220 return $this->dbo->getQuery($new); 221 } 222 223 return null; 224 } 225 226 public function getTableColumns($table, $typeOnly = true) 227 { 228 if (method_exists($this->dbo, 'getTableColumns')) 229 { 230 return $this->dbo->getTableColumns($table, $typeOnly); 231 } 232 233 $result = $this->dbo->getTableFields(array($table), $typeOnly); 234 235 return $result[$table]; 236 } 237 238 public function getTableKeys($tables) 239 { 240 if (method_exists($this->dbo, 'getTableKeys')) 241 { 242 return $this->dbo->getTableKeys($tables); 243 } 244 245 return array(); 246 } 247 248 public function getTableList() 249 { 250 if (method_exists($this->dbo, 'getTableList')) 251 { 252 return $this->dbo->getTableList(); 253 } 254 255 return array(); 256 } 257 258 public function getVersion() 259 { 260 if (method_exists($this->dbo, 'getVersion')) 261 { 262 return $this->dbo->getVersion(); 263 } 264 265 return '5.0.40'; 266 } 267 268 public function insertid() 269 { 270 if (method_exists($this->dbo, 'insertid')) 271 { 272 return $this->dbo->insertid(); 273 } 274 275 return null; 276 } 277 278 public function insertObject($table, &$object, $key = null) 279 { 280 if (method_exists($this->dbo, 'insertObject')) 281 { 282 return $this->dbo->insertObject($table, $object, $key); 283 } 284 285 return null; 286 } 287 288 public function loadAssoc() 289 { 290 if (method_exists($this->dbo, 'loadAssoc')) 291 { 292 return $this->dbo->loadAssoc(); 293 } 294 295 return null; 296 } 297 298 public function loadAssocList($key = null, $column = null) 299 { 300 if (method_exists($this->dbo, 'loadAssocList')) 301 { 302 return $this->dbo->loadAssocList($key, $column); 303 } 304 305 return null; 306 } 307 308 public function loadObject($class = 'stdClass') 309 { 310 if (method_exists($this->dbo, 'loadObject')) 311 { 312 return $this->dbo->loadObject($class); 313 } 314 315 return null; 316 } 317 318 public function loadObjectList($key = '', $class = 'stdClass') 319 { 320 if (method_exists($this->dbo, 'loadObjectList')) 321 { 322 return $this->dbo->loadObjectList($key, $class); 323 } 324 325 return null; 326 } 327 328 public function loadResult() 329 { 330 if (method_exists($this->dbo, 'loadResult')) 331 { 332 return $this->dbo->loadResult(); 333 } 334 335 return null; 336 } 337 338 public function loadRow() 339 { 340 if (method_exists($this->dbo, 'loadRow')) 341 { 342 return $this->dbo->loadRow(); 343 } 344 345 return null; 346 } 347 348 public function loadRowList($key = null) 349 { 350 if (method_exists($this->dbo, 'loadRowList')) 351 { 352 return $this->dbo->loadRowList($key); 353 } 354 355 return null; 356 } 357 358 public function lockTable($tableName) 359 { 360 if (method_exists($this->dbo, 'lockTable')) 361 { 362 return $this->dbo->lockTable($this); 363 } 364 365 return $this; 366 } 367 368 public function quote($text, $escape = true) 369 { 370 if (method_exists($this->dbo, 'quote')) 371 { 372 return $this->dbo->quote($text, $escape); 373 } 374 375 return $text; 376 } 377 378 public function select($database) 379 { 380 if (method_exists($this->dbo, 'select')) 381 { 382 return $this->dbo->select($database); 383 } 384 385 return false; 386 } 387 388 public function setQuery($query, $offset = 0, $limit = 0) 389 { 390 if (method_exists($this->dbo, 'setQuery')) 391 { 392 return $this->dbo->setQuery($query, $offset, $limit); 393 } 394 395 return false; 396 } 397 398 public function transactionCommit($toSavepoint = false) 399 { 400 if (method_exists($this->dbo, 'transactionCommit')) 401 { 402 $this->dbo->transactionCommit($toSavepoint); 403 } 404 } 405 406 public function transactionRollback($toSavepoint = false) 407 { 408 if (method_exists($this->dbo, 'transactionRollback')) 409 { 410 $this->dbo->transactionRollback($toSavepoint); 411 } 412 } 413 414 public function transactionStart($asSavepoint = false) 415 { 416 if (method_exists($this->dbo, 'transactionStart')) 417 { 418 $this->dbo->transactionStart($asSavepoint); 419 } 420 } 421 422 public function unlockTables() 423 { 424 if (method_exists($this->dbo, 'unlockTables')) 425 { 426 return $this->dbo->unlockTables(); 427 } 428 429 return $this; 430 } 431 432 public function updateObject($table, &$object, $key, $nulls = false) 433 { 434 if (method_exists($this->dbo, 'updateObject')) 435 { 436 return $this->dbo->updateObject($table, $object, $key, $nulls); 437 } 438 439 return false; 440 } 441 442 public function getLog() 443 { 444 if (method_exists($this->dbo, 'getLog')) 445 { 446 return $this->dbo->getLog(); 447 } 448 449 return array(); 450 } 451 452 public function dropTable($table, $ifExists = true) 453 { 454 if (method_exists($this->dbo, 'dropTable')) 455 { 456 return $this->dbo->dropTable($table, $ifExists); 457 } 458 459 return $this; 460 } 461 462 public function getTableCreate($tables) 463 { 464 if (method_exists($this->dbo, 'getTableCreate')) 465 { 466 return $this->dbo->getTableCreate($tables); 467 } 468 469 return array(); 470 } 471 472 public function renameTable($oldTable, $newTable, $backup = null, $prefix = null) 473 { 474 if (method_exists($this->dbo, 'renameTable')) 475 { 476 return $this->dbo->renameTable($oldTable, $newTable, $backup, $prefix); 477 } 478 479 return $this; 480 } 481 482 public function setUtf() 483 { 484 if (method_exists($this->dbo, 'setUtf')) 485 { 486 return $this->dbo->setUtf(); 487 } 488 489 return false; 490 } 491 492 493 protected function freeResult($cursor = null) 494 { 495 return false; 496 } 497 498 /** 499 * Method to get an array of values from the <var>$offset</var> field in each row of the result set from 500 * the database query. 501 * 502 * @param integer $offset The row offset to use to build the result array. 503 * 504 * @return mixed The return value or null if the query failed. 505 * 506 * @since 11.1 507 * @throws RuntimeException 508 */ 509 public function loadColumn($offset = 0) 510 { 511 if (method_exists($this->dbo, 'loadColumn')) 512 { 513 return $this->dbo->loadColumn($offset); 514 } 515 516 return $this->dbo->loadResultArray($offset); 517 } 518 519 /** 520 * Wrap an SQL statement identifier name such as column, table or database names in quotes to prevent injection 521 * risks and reserved word conflicts. 522 * 523 * @param mixed $name The identifier name to wrap in quotes, or an array of identifier names to wrap in quotes. 524 * Each type supports dot-notation name. 525 * @param mixed $as The AS query part associated to $name. It can be string or array, in latter case it has to be 526 * same length of $name; if is null there will not be any AS part for string or array element. 527 * 528 * @return mixed The quote wrapped name, same type of $name. 529 * 530 * @since 11.1 531 */ 532 public function quoteName($name, $as = null) 533 { 534 if (is_string($name)) 535 { 536 $quotedName = $this->quoteNameStr(explode('.', $name)); 537 538 $quotedAs = ''; 539 540 if (!is_null($as)) 541 { 542 settype($as, 'array'); 543 $quotedAs .= ' AS ' . $this->quoteNameStr($as); 544 } 545 546 return $quotedName . $quotedAs; 547 } 548 else 549 { 550 $fin = array(); 551 552 if (is_null($as)) 553 { 554 foreach ($name as $str) 555 { 556 $fin[] = $this->quoteName($str); 557 } 558 } 559 elseif (is_array($name) && (count($name) == count($as))) 560 { 561 $count = count($name); 562 563 for ($i = 0; $i < $count; $i++) 564 { 565 $fin[] = $this->quoteName($name[$i], $as[$i]); 566 } 567 } 568 569 return $fin; 570 } 571 } 572 573 /** 574 * Quote strings coming from quoteName call. 575 * 576 * @param array $strArr Array of strings coming from quoteName dot-explosion. 577 * 578 * @return string Dot-imploded string of quoted parts. 579 * 580 * @since 11.3 581 */ 582 protected function quoteNameStr($strArr) 583 { 584 $parts = array(); 585 $q = $this->nameQuote; 586 587 foreach ($strArr as $part) 588 { 589 if (is_null($part)) 590 { 591 continue; 592 } 593 594 if (strlen($q) == 1) 595 { 596 $parts[] = $q . $part . $q; 597 } 598 else 599 { 600 $parts[] = $q[0] . $part . $q[1]; 601 } 602 } 603 604 return implode('.', $parts); 605 } 606 607 /** 608 * Gets the error message from the database connection. 609 * 610 * @param boolean $escaped True to escape the message string for use in JavaScript. 611 * 612 * @return string The error message for the most recent query. 613 * 614 * @since 11.1 615 */ 616 public function getErrorMsg($escaped = false) 617 { 618 if (method_exists($this->dbo, 'getErrorMsg')) 619 { 620 $errorMessage = $this->dbo->getErrorMsg(); 621 } 622 else 623 { 624 $errorMessage = $this->errorMsg; 625 } 626 627 if ($escaped) 628 { 629 return addslashes($errorMessage); 630 } 631 632 return $errorMessage; 633 } 634 635 /** 636 * Gets the error number from the database connection. 637 * 638 * @return integer The error number for the most recent query. 639 * 640 * @since 11.1 641 * @deprecated 13.3 (Platform) & 4.0 (CMS) 642 */ 643 public function getErrorNum() 644 { 645 if (method_exists($this->dbo, 'getErrorNum')) 646 { 647 $errorNum = $this->dbo->getErrorNum(); 648 } 649 else 650 { 651 $errorNum = $this->getErrorNum; 652 } 653 654 return $errorNum; 655 } 656 657 /** 658 * Return the most recent error message for the database connector. 659 * 660 * @param boolean $showSQL True to display the SQL statement sent to the database as well as the error. 661 * 662 * @return string The error message for the most recent query. 663 */ 664 public function stderr($showSQL = false) 665 { 666 if (method_exists($this->dbo, 'stderr')) 667 { 668 return $this->dbo->stderr($showSQL); 669 } 670 671 return parent::stderr($showSQL); 672 } 673 674 /** 675 * Magic method to proxy all calls to the loaded database driver object 676 */ 677 public function __call($name, array $arguments) 678 { 679 if (is_null($this->dbo)) 680 { 681 throw new Exception('FOF database driver is not loaded'); 682 } 683 684 if (method_exists($this->dbo, $name) || in_array($name, array('q', 'nq', 'qn', 'query'))) 685 { 686 switch ($name) 687 { 688 case 'execute': 689 $name = 'query'; 690 break; 691 692 case 'q': 693 $name = 'quote'; 694 break; 695 696 case 'qn': 697 case 'nq': 698 switch (count($arguments)) 699 { 700 case 0 : 701 $result = $this->quoteName(); 702 break; 703 case 1 : 704 $result = $this->quoteName($arguments[0]); 705 break; 706 case 2: 707 default: 708 $result = $this->quoteName($arguments[0], $arguments[1]); 709 break; 710 } 711 return $result; 712 713 break; 714 } 715 716 switch (count($arguments)) 717 { 718 case 0 : 719 $result = $this->dbo->$name(); 720 break; 721 case 1 : 722 $result = $this->dbo->$name($arguments[0]); 723 break; 724 case 2: 725 $result = $this->dbo->$name($arguments[0], $arguments[1]); 726 break; 727 case 3: 728 $result = $this->dbo->$name($arguments[0], $arguments[1], $arguments[2]); 729 break; 730 case 4: 731 $result = $this->dbo->$name($arguments[0], $arguments[1], $arguments[2], $arguments[3]); 732 break; 733 case 5: 734 $result = $this->dbo->$name($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4]); 735 break; 736 default: 737 // Resort to using call_user_func_array for many segments 738 $result = call_user_func_array(array($this->dbo, $name), $arguments); 739 } 740 741 if (class_exists('JDatabase') && is_object($result) && ($result instanceof JDatabase)) 742 { 743 return $this; 744 } 745 746 return $result; 747 } 748 else 749 { 750 throw new \Exception('Method ' . $name . ' not found in FOFDatabase'); 751 } 752 } 753 754 public function __get($name) 755 { 756 if (isset($this->dbo->$name) || property_exists($this->dbo, $name)) 757 { 758 return $this->dbo->$name; 759 } 760 else 761 { 762 $this->dbo->$name = null; 763 user_error('Database driver does not support property ' . $name); 764 } 765 } 766 767 public function __set($name, $value) 768 { 769 if (isset($this->dbo->name) || property_exists($this->dbo, $name)) 770 { 771 $this->dbo->$name = $value; 772 } 773 else 774 { 775 $this->dbo->$name = null; 776 user_error('Database driver not support property ' . $name); 777 } 778 } 779} 780