| [ Index ] |
|
Code source de PHP PEAR 1.4.5 |
1 <?php 2 3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 4 5 /** 6 * Database independent query interface 7 * 8 * PHP versions 4 and 5 9 * 10 * LICENSE: This source file is subject to version 3.0 of the PHP license 11 * that is available through the world-wide-web at the following URI: 12 * http://www.php.net/license/3_0.txt. If you did not receive a copy of 13 * the PHP License and are unable to obtain it through the web, please 14 * send a note to license@php.net so we can mail you a copy immediately. 15 * 16 * @category Database 17 * @package DB 18 * @author Stig Bakken <ssb@php.net> 19 * @author Tomas V.V.Cox <cox@idecnet.com> 20 * @author Daniel Convissor <danielc@php.net> 21 * @copyright 1997-2005 The PHP Group 22 * @license http://www.php.net/license/3_0.txt PHP License 3.0 23 * @version CVS: $Id: DB.php,v 1.86 2007/01/22 01:17:48 aharvey Exp $ 24 * @link http://pear.php.net/package/DB 25 */ 26 27 /** 28 * Obtain the PEAR class so it can be extended from 29 */ 30 require_once 'PEAR.php'; 31 32 33 // {{{ constants 34 // {{{ error codes 35 36 /**#@+ 37 * One of PEAR DB's portable error codes. 38 * @see DB_common::errorCode(), DB::errorMessage() 39 * 40 * {@internal If you add an error code here, make sure you also add a textual 41 * version of it in DB::errorMessage().}} 42 */ 43 44 /** 45 * The code returned by many methods upon success 46 */ 47 define('DB_OK', 1); 48 49 /** 50 * Unkown error 51 */ 52 define('DB_ERROR', -1); 53 54 /** 55 * Syntax error 56 */ 57 define('DB_ERROR_SYNTAX', -2); 58 59 /** 60 * Tried to insert a duplicate value into a primary or unique index 61 */ 62 define('DB_ERROR_CONSTRAINT', -3); 63 64 /** 65 * An identifier in the query refers to a non-existant object 66 */ 67 define('DB_ERROR_NOT_FOUND', -4); 68 69 /** 70 * Tried to create a duplicate object 71 */ 72 define('DB_ERROR_ALREADY_EXISTS', -5); 73 74 /** 75 * The current driver does not support the action you attempted 76 */ 77 define('DB_ERROR_UNSUPPORTED', -6); 78 79 /** 80 * The number of parameters does not match the number of placeholders 81 */ 82 define('DB_ERROR_MISMATCH', -7); 83 84 /** 85 * A literal submitted did not match the data type expected 86 */ 87 define('DB_ERROR_INVALID', -8); 88 89 /** 90 * The current DBMS does not support the action you attempted 91 */ 92 define('DB_ERROR_NOT_CAPABLE', -9); 93 94 /** 95 * A literal submitted was too long so the end of it was removed 96 */ 97 define('DB_ERROR_TRUNCATED', -10); 98 99 /** 100 * A literal number submitted did not match the data type expected 101 */ 102 define('DB_ERROR_INVALID_NUMBER', -11); 103 104 /** 105 * A literal date submitted did not match the data type expected 106 */ 107 define('DB_ERROR_INVALID_DATE', -12); 108 109 /** 110 * Attempt to divide something by zero 111 */ 112 define('DB_ERROR_DIVZERO', -13); 113 114 /** 115 * A database needs to be selected 116 */ 117 define('DB_ERROR_NODBSELECTED', -14); 118 119 /** 120 * Could not create the object requested 121 */ 122 define('DB_ERROR_CANNOT_CREATE', -15); 123 124 /** 125 * Could not drop the database requested because it does not exist 126 */ 127 define('DB_ERROR_CANNOT_DROP', -17); 128 129 /** 130 * An identifier in the query refers to a non-existant table 131 */ 132 define('DB_ERROR_NOSUCHTABLE', -18); 133 134 /** 135 * An identifier in the query refers to a non-existant column 136 */ 137 define('DB_ERROR_NOSUCHFIELD', -19); 138 139 /** 140 * The data submitted to the method was inappropriate 141 */ 142 define('DB_ERROR_NEED_MORE_DATA', -20); 143 144 /** 145 * The attempt to lock the table failed 146 */ 147 define('DB_ERROR_NOT_LOCKED', -21); 148 149 /** 150 * The number of columns doesn't match the number of values 151 */ 152 define('DB_ERROR_VALUE_COUNT_ON_ROW', -22); 153 154 /** 155 * The DSN submitted has problems 156 */ 157 define('DB_ERROR_INVALID_DSN', -23); 158 159 /** 160 * Could not connect to the database 161 */ 162 define('DB_ERROR_CONNECT_FAILED', -24); 163 164 /** 165 * The PHP extension needed for this DBMS could not be found 166 */ 167 define('DB_ERROR_EXTENSION_NOT_FOUND',-25); 168 169 /** 170 * The present user has inadequate permissions to perform the task requestd 171 */ 172 define('DB_ERROR_ACCESS_VIOLATION', -26); 173 174 /** 175 * The database requested does not exist 176 */ 177 define('DB_ERROR_NOSUCHDB', -27); 178 179 /** 180 * Tried to insert a null value into a column that doesn't allow nulls 181 */ 182 define('DB_ERROR_CONSTRAINT_NOT_NULL',-29); 183 /**#@-*/ 184 185 186 // }}} 187 // {{{ prepared statement-related 188 189 190 /**#@+ 191 * Identifiers for the placeholders used in prepared statements. 192 * @see DB_common::prepare() 193 */ 194 195 /** 196 * Indicates a scalar (<kbd>?</kbd>) placeholder was used 197 * 198 * Quote and escape the value as necessary. 199 */ 200 define('DB_PARAM_SCALAR', 1); 201 202 /** 203 * Indicates an opaque (<kbd>&</kbd>) placeholder was used 204 * 205 * The value presented is a file name. Extract the contents of that file 206 * and place them in this column. 207 */ 208 define('DB_PARAM_OPAQUE', 2); 209 210 /** 211 * Indicates a misc (<kbd>!</kbd>) placeholder was used 212 * 213 * The value should not be quoted or escaped. 214 */ 215 define('DB_PARAM_MISC', 3); 216 /**#@-*/ 217 218 219 // }}} 220 // {{{ binary data-related 221 222 223 /**#@+ 224 * The different ways of returning binary data from queries. 225 */ 226 227 /** 228 * Sends the fetched data straight through to output 229 */ 230 define('DB_BINMODE_PASSTHRU', 1); 231 232 /** 233 * Lets you return data as usual 234 */ 235 define('DB_BINMODE_RETURN', 2); 236 237 /** 238 * Converts the data to hex format before returning it 239 * 240 * For example the string "123" would become "313233". 241 */ 242 define('DB_BINMODE_CONVERT', 3); 243 /**#@-*/ 244 245 246 // }}} 247 // {{{ fetch modes 248 249 250 /**#@+ 251 * Fetch Modes. 252 * @see DB_common::setFetchMode() 253 */ 254 255 /** 256 * Indicates the current default fetch mode should be used 257 * @see DB_common::$fetchmode 258 */ 259 define('DB_FETCHMODE_DEFAULT', 0); 260 261 /** 262 * Column data indexed by numbers, ordered from 0 and up 263 */ 264 define('DB_FETCHMODE_ORDERED', 1); 265 266 /** 267 * Column data indexed by column names 268 */ 269 define('DB_FETCHMODE_ASSOC', 2); 270 271 /** 272 * Column data as object properties 273 */ 274 define('DB_FETCHMODE_OBJECT', 3); 275 276 /** 277 * For multi-dimensional results, make the column name the first level 278 * of the array and put the row number in the second level of the array 279 * 280 * This is flipped from the normal behavior, which puts the row numbers 281 * in the first level of the array and the column names in the second level. 282 */ 283 define('DB_FETCHMODE_FLIPPED', 4); 284 /**#@-*/ 285 286 /**#@+ 287 * Old fetch modes. Left here for compatibility. 288 */ 289 define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED); 290 define('DB_GETMODE_ASSOC', DB_FETCHMODE_ASSOC); 291 define('DB_GETMODE_FLIPPED', DB_FETCHMODE_FLIPPED); 292 /**#@-*/ 293 294 295 // }}} 296 // {{{ tableInfo() && autoPrepare()-related 297 298 299 /**#@+ 300 * The type of information to return from the tableInfo() method. 301 * 302 * Bitwised constants, so they can be combined using <kbd>|</kbd> 303 * and removed using <kbd>^</kbd>. 304 * 305 * @see DB_common::tableInfo() 306 * 307 * {@internal Since the TABLEINFO constants are bitwised, if more of them are 308 * added in the future, make sure to adjust DB_TABLEINFO_FULL accordingly.}} 309 */ 310 define('DB_TABLEINFO_ORDER', 1); 311 define('DB_TABLEINFO_ORDERTABLE', 2); 312 define('DB_TABLEINFO_FULL', 3); 313 /**#@-*/ 314 315 316 /**#@+ 317 * The type of query to create with the automatic query building methods. 318 * @see DB_common::autoPrepare(), DB_common::autoExecute() 319 */ 320 define('DB_AUTOQUERY_INSERT', 1); 321 define('DB_AUTOQUERY_UPDATE', 2); 322 /**#@-*/ 323 324 325 // }}} 326 // {{{ portability modes 327 328 329 /**#@+ 330 * Portability Modes. 331 * 332 * Bitwised constants, so they can be combined using <kbd>|</kbd> 333 * and removed using <kbd>^</kbd>. 334 * 335 * @see DB_common::setOption() 336 * 337 * {@internal Since the PORTABILITY constants are bitwised, if more of them are 338 * added in the future, make sure to adjust DB_PORTABILITY_ALL accordingly.}} 339 */ 340 341 /** 342 * Turn off all portability features 343 */ 344 define('DB_PORTABILITY_NONE', 0); 345 346 /** 347 * Convert names of tables and fields to lower case 348 * when using the get*(), fetch*() and tableInfo() methods 349 */ 350 define('DB_PORTABILITY_LOWERCASE', 1); 351 352 /** 353 * Right trim the data output by get*() and fetch*() 354 */ 355 define('DB_PORTABILITY_RTRIM', 2); 356 357 /** 358 * Force reporting the number of rows deleted 359 */ 360 define('DB_PORTABILITY_DELETE_COUNT', 4); 361 362 /** 363 * Enable hack that makes numRows() work in Oracle 364 */ 365 define('DB_PORTABILITY_NUMROWS', 8); 366 367 /** 368 * Makes certain error messages in certain drivers compatible 369 * with those from other DBMS's 370 * 371 * + mysql, mysqli: change unique/primary key constraints 372 * DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT 373 * 374 * + odbc(access): MS's ODBC driver reports 'no such field' as code 375 * 07001, which means 'too few parameters.' When this option is on 376 * that code gets mapped to DB_ERROR_NOSUCHFIELD. 377 */ 378 define('DB_PORTABILITY_ERRORS', 16); 379 380 /** 381 * Convert null values to empty strings in data output by 382 * get*() and fetch*() 383 */ 384 define('DB_PORTABILITY_NULL_TO_EMPTY', 32); 385 386 /** 387 * Turn on all portability features 388 */ 389 define('DB_PORTABILITY_ALL', 63); 390 /**#@-*/ 391 392 // }}} 393 394 395 // }}} 396 // {{{ class DB 397 398 /** 399 * Database independent query interface 400 * 401 * The main "DB" class is simply a container class with some static 402 * methods for creating DB objects as well as some utility functions 403 * common to all parts of DB. 404 * 405 * The object model of DB is as follows (indentation means inheritance): 406 * <pre> 407 * DB The main DB class. This is simply a utility class 408 * with some "static" methods for creating DB objects as 409 * well as common utility functions for other DB classes. 410 * 411 * DB_common The base for each DB implementation. Provides default 412 * | implementations (in OO lingo virtual methods) for 413 * | the actual DB implementations as well as a bunch of 414 * | query utility functions. 415 * | 416 * +-DB_mysql The DB implementation for MySQL. Inherits DB_common. 417 * When calling DB::factory or DB::connect for MySQL 418 * connections, the object returned is an instance of this 419 * class. 420 * </pre> 421 * 422 * @category Database 423 * @package DB 424 * @author Stig Bakken <ssb@php.net> 425 * @author Tomas V.V.Cox <cox@idecnet.com> 426 * @author Daniel Convissor <danielc@php.net> 427 * @copyright 1997-2005 The PHP Group 428 * @license http://www.php.net/license/3_0.txt PHP License 3.0 429 * @version Release: 1.7.9 430 * @link http://pear.php.net/package/DB 431 */ 432 class DB 433 { 434 // {{{ &factory() 435 436 /** 437 * Create a new DB object for the specified database type but don't 438 * connect to the database 439 * 440 * @param string $type the database type (eg "mysql") 441 * @param array $options an associative array of option names and values 442 * 443 * @return object a new DB object. A DB_Error object on failure. 444 * 445 * @see DB_common::setOption() 446 */ 447 function &factory($type, $options = false) 448 { 449 if (!is_array($options)) { 450 $options = array('persistent' => $options); 451 } 452 453 if (isset($options['debug']) && $options['debug'] >= 2) { 454 // expose php errors with sufficient debug level 455 include_once "DB/{$type}.php"; 456 } else { 457 @include_once "DB/{$type}.php"; 458 } 459 460 $classname = "DB_$type}"; 461 462 if (!class_exists($classname)) { 463 $tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null, 464 "Unable to include the DB/{$type}.php" 465 . " file for '$dsn'", 466 'DB_Error', true); 467 return $tmp; 468 } 469 470 @$obj =& new $classname; 471 472 foreach ($options as $option => $value) { 473 $test = $obj->setOption($option, $value); 474 if (DB::isError($test)) { 475 return $test; 476 } 477 } 478 479 return $obj; 480 } 481 482 // }}} 483 // {{{ &connect() 484 485 /** 486 * Create a new DB object including a connection to the specified database 487 * 488 * Example 1. 489 * <code> 490 * require_once 'DB.php'; 491 * 492 * $dsn = 'pgsql://user:password@host/database'; 493 * $options = array( 494 * 'debug' => 2, 495 * 'portability' => DB_PORTABILITY_ALL, 496 * ); 497 * 498 * $db =& DB::connect($dsn, $options); 499 * if (PEAR::isError($db)) { 500 * die($db->getMessage()); 501 * } 502 * </code> 503 * 504 * @param mixed $dsn the string "data source name" or array in the 505 * format returned by DB::parseDSN() 506 * @param array $options an associative array of option names and values 507 * 508 * @return object a new DB object. A DB_Error object on failure. 509 * 510 * @uses DB_dbase::connect(), DB_fbsql::connect(), DB_ibase::connect(), 511 * DB_ifx::connect(), DB_msql::connect(), DB_mssql::connect(), 512 * DB_mysql::connect(), DB_mysqli::connect(), DB_oci8::connect(), 513 * DB_odbc::connect(), DB_pgsql::connect(), DB_sqlite::connect(), 514 * DB_sybase::connect() 515 * 516 * @uses DB::parseDSN(), DB_common::setOption(), PEAR::isError() 517 */ 518 function &connect($dsn, $options = array()) 519 { 520 $dsninfo = DB::parseDSN($dsn); 521 $type = $dsninfo['phptype']; 522 523 if (!is_array($options)) { 524 /* 525 * For backwards compatibility. $options used to be boolean, 526 * indicating whether the connection should be persistent. 527 */ 528 $options = array('persistent' => $options); 529 } 530 531 if (isset($options['debug']) && $options['debug'] >= 2) { 532 // expose php errors with sufficient debug level 533 include_once "DB/$type}.php"; 534 } else { 535 @include_once "DB/$type}.php"; 536 } 537 538 $classname = "DB_$type}"; 539 if (!class_exists($classname)) { 540 $tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null, 541 "Unable to include the DB/{$type}.php" 542 . " file for '$dsn'", 543 'DB_Error', true); 544 return $tmp; 545 } 546 547 @$obj =& new $classname; 548 549 foreach ($options as $option => $value) { 550 $test = $obj->setOption($option, $value); 551 if (DB::isError($test)) { 552 return $test; 553 } 554 } 555 556 $err = $obj->connect($dsninfo, $obj->getOption('persistent')); 557 if (DB::isError($err)) { 558 if (is_array($dsn)) { 559 $err->addUserInfo(DB::getDSNString($dsn, true)); 560 } else { 561 $err->addUserInfo($dsn); 562 } 563 return $err; 564 } 565 566 return $obj; 567 } 568 569 // }}} 570 // {{{ apiVersion() 571 572 /** 573 * Return the DB API version 574 * 575 * @return string the DB API version number 576 */ 577 function apiVersion() 578 { 579 return '1.7.9'; 580 } 581 582 // }}} 583 // {{{ isError() 584 585 /** 586 * Determines if a variable is a DB_Error object 587 * 588 * @param mixed $value the variable to check 589 * 590 * @return bool whether $value is DB_Error object 591 */ 592 function isError($value) 593 { 594 return is_a($value, 'DB_Error'); 595 } 596 597 // }}} 598 // {{{ isConnection() 599 600 /** 601 * Determines if a value is a DB_<driver> object 602 * 603 * @param mixed $value the value to test 604 * 605 * @return bool whether $value is a DB_<driver> object 606 */ 607 function isConnection($value) 608 { 609 return (is_object($value) && 610 is_subclass_of($value, 'db_common') && 611 method_exists($value, 'simpleQuery')); 612 } 613 614 // }}} 615 // {{{ isManip() 616 617 /** 618 * Tell whether a query is a data manipulation or data definition query 619 * 620 * Examples of data manipulation queries are INSERT, UPDATE and DELETE. 621 * Examples of data definition queries are CREATE, DROP, ALTER, GRANT, 622 * REVOKE. 623 * 624 * @param string $query the query 625 * 626 * @return boolean whether $query is a data manipulation query 627 */ 628 function isManip($query) 629 { 630 $manips = 'INSERT|UPDATE|DELETE|REPLACE|' 631 . 'CREATE|DROP|' 632 . 'LOAD DATA|SELECT .* INTO .* FROM|COPY|' 633 . 'ALTER|GRANT|REVOKE|' 634 . 'LOCK|UNLOCK'; 635 if (preg_match('/^\s*"?(' . $manips . ')\s+/i', $query)) { 636 return true; 637 } 638 return false; 639 } 640 641 // }}} 642 // {{{ errorMessage() 643 644 /** 645 * Return a textual error message for a DB error code 646 * 647 * @param integer $value the DB error code 648 * 649 * @return string the error message or false if the error code was 650 * not recognized 651 */ 652 function errorMessage($value) 653 { 654 static $errorMessages; 655 if (!isset($errorMessages)) { 656 $errorMessages = array( 657 DB_ERROR => 'unknown error', 658 DB_ERROR_ACCESS_VIOLATION => 'insufficient permissions', 659 DB_ERROR_ALREADY_EXISTS => 'already exists', 660 DB_ERROR_CANNOT_CREATE => 'can not create', 661 DB_ERROR_CANNOT_DROP => 'can not drop', 662 DB_ERROR_CONNECT_FAILED => 'connect failed', 663 DB_ERROR_CONSTRAINT => 'constraint violation', 664 DB_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint', 665 DB_ERROR_DIVZERO => 'division by zero', 666 DB_ERROR_EXTENSION_NOT_FOUND=> 'extension not found', 667 DB_ERROR_INVALID => 'invalid', 668 DB_ERROR_INVALID_DATE => 'invalid date or time', 669 DB_ERROR_INVALID_DSN => 'invalid DSN', 670 DB_ERROR_INVALID_NUMBER => 'invalid number', 671 DB_ERROR_MISMATCH => 'mismatch', 672 DB_ERROR_NEED_MORE_DATA => 'insufficient data supplied', 673 DB_ERROR_NODBSELECTED => 'no database selected', 674 DB_ERROR_NOSUCHDB => 'no such database', 675 DB_ERROR_NOSUCHFIELD => 'no such field', 676 DB_ERROR_NOSUCHTABLE => 'no such table', 677 DB_ERROR_NOT_CAPABLE => 'DB backend not capable', 678 DB_ERROR_NOT_FOUND => 'not found', 679 DB_ERROR_NOT_LOCKED => 'not locked', 680 DB_ERROR_SYNTAX => 'syntax error', 681 DB_ERROR_UNSUPPORTED => 'not supported', 682 DB_ERROR_TRUNCATED => 'truncated', 683 DB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row', 684 DB_OK => 'no error', 685 ); 686 } 687 688 if (DB::isError($value)) { 689 $value = $value->getCode(); 690 } 691 692 return isset($errorMessages[$value]) ? $errorMessages[$value] 693 : $errorMessages[DB_ERROR]; 694 } 695 696 // }}} 697 // {{{ parseDSN() 698 699 /** 700 * Parse a data source name 701 * 702 * Additional keys can be added by appending a URI query string to the 703 * end of the DSN. 704 * 705 * The format of the supplied DSN is in its fullest form: 706 * <code> 707 * phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true 708 * </code> 709 * 710 * Most variations are allowed: 711 * <code> 712 * phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644 713 * phptype://username:password@hostspec/database_name 714 * phptype://username:password@hostspec 715 * phptype://username@hostspec 716 * phptype://hostspec/database 717 * phptype://hostspec 718 * phptype(dbsyntax) 719 * phptype 720 * </code> 721 * 722 * @param string $dsn Data Source Name to be parsed 723 * 724 * @return array an associative array with the following keys: 725 * + phptype: Database backend used in PHP (mysql, odbc etc.) 726 * + dbsyntax: Database used with regards to SQL syntax etc. 727 * + protocol: Communication protocol to use (tcp, unix etc.) 728 * + hostspec: Host specification (hostname[:port]) 729 * + database: Database to use on the DBMS server 730 * + username: User name for login 731 * + password: Password for login 732 */ 733 function parseDSN($dsn) 734 { 735 $parsed = array( 736 'phptype' => false, 737 'dbsyntax' => false, 738 'username' => false, 739 'password' => false, 740 'protocol' => false, 741 'hostspec' => false, 742 'port' => false, 743 'socket' => false, 744 'database' => false, 745 ); 746 747 if (is_array($dsn)) { 748 $dsn = array_merge($parsed, $dsn); 749 if (!$dsn['dbsyntax']) { 750 $dsn['dbsyntax'] = $dsn['phptype']; 751 } 752 return $dsn; 753 } 754 755 // Find phptype and dbsyntax 756 if (($pos = strpos($dsn, '://')) !== false) { 757 $str = substr($dsn, 0, $pos); 758 $dsn = substr($dsn, $pos + 3); 759 } else { 760 $str = $dsn; 761 $dsn = null; 762 } 763 764 // Get phptype and dbsyntax 765 // $str => phptype(dbsyntax) 766 if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) { 767 $parsed['phptype'] = $arr[1]; 768 $parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2]; 769 } else { 770 $parsed['phptype'] = $str; 771 $parsed['dbsyntax'] = $str; 772 } 773 774 if (!count($dsn)) { 775 return $parsed; 776 } 777 778 // Get (if found): username and password 779 // $dsn => username:password@protocol+hostspec/database 780 if (($at = strrpos($dsn,'@')) !== false) { 781 $str = substr($dsn, 0, $at); 782 $dsn = substr($dsn, $at + 1); 783 if (($pos = strpos($str, ':')) !== false) { 784 $parsed['username'] = rawurldecode(substr($str, 0, $pos)); 785 $parsed['password'] = rawurldecode(substr($str, $pos + 1)); 786 } else { 787 $parsed['username'] = rawurldecode($str); 788 } 789 } 790 791 // Find protocol and hostspec 792 793 if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) { 794 // $dsn => proto(proto_opts)/database 795 $proto = $match[1]; 796 $proto_opts = $match[2] ? $match[2] : false; 797 $dsn = $match[3]; 798 799 } else { 800 // $dsn => protocol+hostspec/database (old format) 801 if (strpos($dsn, '+') !== false) { 802 list($proto, $dsn) = explode('+', $dsn, 2); 803 } 804 if (strpos($dsn, '/') !== false) { 805 list($proto_opts, $dsn) = explode('/', $dsn, 2); 806 } else { 807 $proto_opts = $dsn; 808 $dsn = null; 809 } 810 } 811 812 // process the different protocol options 813 $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp'; 814 $proto_opts = rawurldecode($proto_opts); 815 if (strpos($proto_opts, ':') !== false) { 816 list($proto_opts, $parsed['port']) = explode(':', $proto_opts); 817 } 818 if ($parsed['protocol'] == 'tcp') { 819 $parsed['hostspec'] = $proto_opts; 820 } elseif ($parsed['protocol'] == 'unix') { 821 $parsed['socket'] = $proto_opts; 822 } 823 824 // Get dabase if any 825 // $dsn => database 826 if ($dsn) { 827 if (($pos = strpos($dsn, '?')) === false) { 828 // /database 829 $parsed['database'] = rawurldecode($dsn); 830 } else { 831 // /database?param1=value1¶m2=value2 832 $parsed['database'] = rawurldecode(substr($dsn, 0, $pos)); 833 $dsn = substr($dsn, $pos + 1); 834 if (strpos($dsn, '&') !== false) { 835 $opts = explode('&', $dsn); 836 } else { // database?param1=value1 837 $opts = array($dsn); 838 } 839 foreach ($opts as $opt) { 840 list($key, $value) = explode('=', $opt); 841 if (!isset($parsed[$key])) { 842 // don't allow params overwrite 843 $parsed[$key] = rawurldecode($value); 844 } 845 } 846 } 847 } 848 849 return $parsed; 850 } 851 852 // }}} 853 // {{{ getDSNString() 854 855 /** 856 * Returns the given DSN in a string format suitable for output. 857 * 858 * @param array|string the DSN to parse and format 859 * @param boolean true to hide the password, false to include it 860 * @return string 861 */ 862 function getDSNString($dsn, $hidePassword) { 863 /* Calling parseDSN will ensure that we have all the array elements 864 * defined, and means that we deal with strings and array in the same 865 * manner. */ 866 $dsnArray = DB::parseDSN($dsn); 867 868 if ($hidePassword) { 869 $dsnArray['password'] = 'PASSWORD'; 870 } 871 872 /* Protocol is special-cased, as using the default "tcp" along with an 873 * Oracle TNS connection string fails. */ 874 if (is_string($dsn) && strpos($dsn, 'tcp') === false && $dsnArray['protocol'] == 'tcp') { 875 $dsnArray['protocol'] = false; 876 } 877 878 // Now we just have to construct the actual string. This is ugly. 879 $dsnString = $dsnArray['phptype']; 880 if ($dsnArray['dbsyntax']) { 881 $dsnString .= '('.$dsnArray['dbsyntax'].')'; 882 } 883 $dsnString .= '://' 884 .$dsnArray['username'] 885 .':' 886 .$dsnArray['password'] 887 .'@' 888 .$dsnArray['protocol']; 889 if ($dsnArray['socket']) { 890 $dsnString .= '('.$dsnArray['socket'].')'; 891 } 892 if ($dsnArray['protocol'] && $dsnArray['hostspec']) { 893 $dsnString .= '+'; 894 } 895 $dsnString .= $dsnArray['hostspec']; 896 if ($dsnArray['port']) { 897 $dsnString .= ':'.$dsnArray['port']; 898 } 899 $dsnString .= '/'.$dsnArray['database']; 900 901 /* Option handling. Unfortunately, parseDSN simply places options into 902 * the top-level array, so we'll first get rid of the fields defined by 903 * DB and see what's left. */ 904 unset($dsnArray['phptype'], 905 $dsnArray['dbsyntax'], 906 $dsnArray['username'], 907 $dsnArray['password'], 908 $dsnArray['protocol'], 909 $dsnArray['socket'], 910 $dsnArray['hostspec'], 911 $dsnArray['port'], 912 $dsnArray['database'] 913 ); 914 if (count($dsnArray) > 0) { 915 $dsnString .= '?'; 916 $i = 0; 917 foreach ($dsnArray as $key => $value) { 918 if (++$i > 1) { 919 $dsnString .= '&'; 920 } 921 $dsnString .= $key.'='.$value; 922 } 923 } 924 925 return $dsnString; 926 } 927 928 // }}} 929 } 930 931 // }}} 932 // {{{ class DB_Error 933 934 /** 935 * DB_Error implements a class for reporting portable database error 936 * messages 937 * 938 * @category Database 939 * @package DB 940 * @author Stig Bakken <ssb@php.net> 941 * @copyright 1997-2005 The PHP Group 942 * @license http://www.php.net/license/3_0.txt PHP License 3.0 943 * @version Release: 1.7.9 944 * @link http://pear.php.net/package/DB 945 */ 946 class DB_Error extends PEAR_Error 947 { 948 // {{{ constructor 949 950 /** 951 * DB_Error constructor 952 * 953 * @param mixed $code DB error code, or string with error message 954 * @param int $mode what "error mode" to operate in 955 * @param int $level what error level to use for $mode & 956 * PEAR_ERROR_TRIGGER 957 * @param mixed $debuginfo additional debug info, such as the last query 958 * 959 * @see PEAR_Error 960 */ 961 function DB_Error($code = DB_ERROR, $mode = PEAR_ERROR_RETURN, 962 $level = E_USER_NOTICE, $debuginfo = null) 963 { 964 if (is_int($code)) { 965 $this->PEAR_Error('DB Error: ' . DB::errorMessage($code), $code, 966 $mode, $level, $debuginfo); 967 } else { 968 $this->PEAR_Error("DB Error: $code", DB_ERROR, 969 $mode, $level, $debuginfo); 970 } 971 } 972 973 // }}} 974 } 975 976 // }}} 977 // {{{ class DB_result 978 979 /** 980 * This class implements a wrapper for a DB result set 981 * 982 * A new instance of this class will be returned by the DB implementation 983 * after processing a query that returns data. 984 * 985 * @category Database 986 * @package DB 987 * @author Stig Bakken <ssb@php.net> 988 * @copyright 1997-2005 The PHP Group 989 * @license http://www.php.net/license/3_0.txt PHP License 3.0 990 * @version Release: 1.7.9 991 * @link http://pear.php.net/package/DB 992 */ 993 class DB_result 994 { 995 // {{{ properties 996 997 /** 998 * Should results be freed automatically when there are no more rows? 999 * @var boolean 1000 * @see DB_common::$options 1001 */ 1002 var $autofree; 1003 1004 /** 1005 * A reference to the DB_<driver> object 1006 * @var object 1007 */ 1008 var $dbh; 1009 1010 /** 1011 * The current default fetch mode 1012 * @var integer 1013 * @see DB_common::$fetchmode 1014 */ 1015 var $fetchmode; 1016 1017 /** 1018 * The name of the class into which results should be fetched when 1019 * DB_FETCHMODE_OBJECT is in effect 1020 * 1021 * @var string 1022 * @see DB_common::$fetchmode_object_class 1023 */ 1024 var $fetchmode_object_class; 1025 1026 /** 1027 * The number of rows to fetch from a limit query 1028 * @var integer 1029 */ 1030 var $limit_count = null; 1031 1032 /** 1033 * The row to start fetching from in limit queries 1034 * @var integer 1035 */ 1036 var $limit_from = null; 1037 1038 /** 1039 * The execute parameters that created this result 1040 * @var array 1041 * @since Property available since Release 1.7.0 1042 */ 1043 var $parameters; 1044 1045 /** 1046 * The query string that created this result 1047 * 1048 * Copied here incase it changes in $dbh, which is referenced 1049 * 1050 * @var string 1051 * @since Property available since Release 1.7.0 1052 */ 1053 var $query; 1054 1055 /** 1056 * The query result resource id created by PHP 1057 * @var resource 1058 */ 1059 var $result; 1060 1061 /** 1062 * The present row being dealt with 1063 * @var integer 1064 */ 1065 var $row_counter = null; 1066 1067 /** 1068 * The prepared statement resource id created by PHP in $dbh 1069 * 1070 * This resource is only available when the result set was created using 1071 * a driver's native execute() method, not PEAR DB's emulated one. 1072 * 1073 * Copied here incase it changes in $dbh, which is referenced 1074 * 1075 * {@internal Mainly here because the InterBase/Firebird API is only 1076 * able to retrieve data from result sets if the statemnt handle is 1077 * still in scope.}} 1078 * 1079 * @var resource 1080 * @since Property available since Release 1.7.0 1081 */ 1082 var $statement; 1083 1084 1085 // }}} 1086 // {{{ constructor 1087 1088 /** 1089 * This constructor sets the object's properties 1090 * 1091 * @param object &$dbh the DB object reference 1092 * @param resource $result the result resource id 1093 * @param array $options an associative array with result options 1094 * 1095 * @return void 1096 */ 1097 function DB_result(&$dbh, $result, $options = array()) 1098 { 1099 $this->autofree = $dbh->options['autofree']; 1100 $this->dbh = &$dbh; 1101 $this->fetchmode = $dbh->fetchmode; 1102 $this->fetchmode_object_class = $dbh->fetchmode_object_class; 1103 $this->parameters = $dbh->last_parameters; 1104 $this->query = $dbh->last_query; 1105 $this->result = $result; 1106 $this->statement = empty($dbh->last_stmt) ? null : $dbh->last_stmt; 1107 foreach ($options as $key => $value) { 1108 $this->setOption($key, $value); 1109 } 1110 } 1111 1112 /** 1113 * Set options for the DB_result object 1114 * 1115 * @param string $key the option to set 1116 * @param mixed $value the value to set the option to 1117 * 1118 * @return void 1119 */ 1120 function setOption($key, $value = null) 1121 { 1122 switch ($key) { 1123 case 'limit_from': 1124 $this->limit_from = $value; 1125 break; 1126 case 'limit_count': 1127 $this->limit_count = $value; 1128 } 1129 } 1130 1131 // }}} 1132 // {{{ fetchRow() 1133 1134 /** 1135 * Fetch a row of data and return it by reference into an array 1136 * 1137 * The type of array returned can be controlled either by setting this 1138 * method's <var>$fetchmode</var> parameter or by changing the default 1139 * fetch mode setFetchMode() before calling this method. 1140 * 1141 * There are two options for standardizing the information returned 1142 * from databases, ensuring their values are consistent when changing 1143 * DBMS's. These portability options can be turned on when creating a 1144 * new DB object or by using setOption(). 1145 * 1146 * + <var>DB_PORTABILITY_LOWERCASE</var> 1147 * convert names of fields to lower case 1148 * 1149 * + <var>DB_PORTABILITY_RTRIM</var> 1150 * right trim the data 1151 * 1152 * @param int $fetchmode the constant indicating how to format the data 1153 * @param int $rownum the row number to fetch (index starts at 0) 1154 * 1155 * @return mixed an array or object containing the row's data, 1156 * NULL when the end of the result set is reached 1157 * or a DB_Error object on failure. 1158 * 1159 * @see DB_common::setOption(), DB_common::setFetchMode() 1160 */ 1161 function &fetchRow($fetchmode = DB_FETCHMODE_DEFAULT, $rownum = null) 1162 { 1163 if ($fetchmode === DB_FETCHMODE_DEFAULT) { 1164 $fetchmode = $this->fetchmode; 1165 } 1166 if ($fetchmode === DB_FETCHMODE_OBJECT) { 1167 $fetchmode = DB_FETCHMODE_ASSOC; 1168 $object_class = $this->fetchmode_object_class; 1169 } 1170 if (is_null($rownum) && $this->limit_from !== null) { 1171 if ($this->row_counter === null) { 1172 $this->row_counter = $this->limit_from; 1173 // Skip rows 1174 if ($this->dbh->features['limit'] === false) { 1175 $i = 0; 1176 while ($i++ < $this->limit_from) { 1177 $this->dbh->fetchInto($this->result, $arr, $fetchmode); 1178 } 1179 } 1180 } 1181 if ($this->row_counter >= ($this->limit_from + $this->limit_count)) 1182 { 1183 if ($this->autofree) { 1184 $this->free(); 1185 } 1186 $tmp = null; 1187 return $tmp; 1188 } 1189 if ($this->dbh->features['limit'] === 'emulate') { 1190 $rownum = $this->row_counter; 1191 } 1192 $this->row_counter++; 1193 } 1194 $res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum); 1195 if ($res === DB_OK) { 1196 if (isset($object_class)) { 1197 // The default mode is specified in the 1198 // DB_common::fetchmode_object_class property 1199 if ($object_class == 'stdClass') { 1200 $arr = (object) $arr; 1201 } else { 1202 $arr = &new $object_class($arr); 1203 } 1204 } 1205 return $arr; 1206 } 1207 if ($res == null && $this->autofree) { 1208 $this->free(); 1209 } 1210 return $res; 1211 } 1212 1213 // }}} 1214 // {{{ fetchInto() 1215 1216 /** 1217 * Fetch a row of data into an array which is passed by reference 1218 * 1219 * The type of array returned can be controlled either by setting this 1220 * method's <var>$fetchmode</var> parameter or by changing the default 1221 * fetch mode setFetchMode() before calling this method. 1222 * 1223 * There are two options for standardizing the information returned 1224 * from databases, ensuring their values are consistent when changing 1225 * DBMS's. These portability options can be turned on when creating a 1226 * new DB object or by using setOption(). 1227 * 1228 * + <var>DB_PORTABILITY_LOWERCASE</var> 1229 * convert names of fields to lower case 1230 * 1231 * + <var>DB_PORTABILITY_RTRIM</var> 1232 * right trim the data 1233 * 1234 * @param array &$arr the variable where the data should be placed 1235 * @param int $fetchmode the constant indicating how to format the data 1236 * @param int $rownum the row number to fetch (index starts at 0) 1237 * 1238 * @return mixed DB_OK if a row is processed, NULL when the end of the 1239 * result set is reached or a DB_Error object on failure 1240 * 1241 * @see DB_common::setOption(), DB_common::setFetchMode() 1242 */ 1243 function fetchInto(&$arr, $fetchmode = DB_FETCHMODE_DEFAULT, $rownum = null) 1244 { 1245 if ($fetchmode === DB_FETCHMODE_DEFAULT) { 1246 $fetchmode = $this->fetchmode; 1247 } 1248 if ($fetchmode === DB_FETCHMODE_OBJECT) { 1249 $fetchmode = DB_FETCHMODE_ASSOC; 1250 $object_class = $this->fetchmode_object_class; 1251 } 1252 if (is_null($rownum) && $this->limit_from !== null) { 1253 if ($this->row_counter === null) { 1254 $this->row_counter = $this->limit_from; 1255 // Skip rows 1256 if ($this->dbh->features['limit'] === false) { 1257 $i = 0; 1258 while ($i++ < $this->limit_from) { 1259 $this->dbh->fetchInto($this->result, $arr, $fetchmode); 1260 } 1261 } 1262 } 1263 if ($this->row_counter >= ( 1264 $this->limit_from + $this->limit_count)) 1265 { 1266 if ($this->autofree) { 1267 $this->free(); 1268 } 1269 return null; 1270 } 1271 if ($this->dbh->features['limit'] === 'emulate') { 1272 $rownum = $this->row_counter; 1273 } 1274 1275 $this->row_counter++; 1276 } 1277 $res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum); 1278 if ($res === DB_OK) { 1279 if (isset($object_class)) { 1280 // default mode specified in the 1281 // DB_common::fetchmode_object_class property 1282 if ($object_class == 'stdClass') { 1283 $arr = (object) $arr; 1284 } else { 1285 $arr = new $object_class($arr); 1286 } 1287 } 1288 return DB_OK; 1289 } 1290 if ($res == null && $this->autofree) { 1291 $this->free(); 1292 } 1293 return $res; 1294 } 1295 1296 // }}} 1297 // {{{ numCols() 1298 1299 /** 1300 * Get the the number of columns in a result set 1301 * 1302 * @return int the number of columns. A DB_Error object on failure. 1303 */ 1304 function numCols() 1305 { 1306 return $this->dbh->numCols($this->result); 1307 } 1308 1309 // }}} 1310 // {{{ numRows() 1311 1312 /** 1313 * Get the number of rows in a result set 1314 * 1315 * @return int the number of rows. A DB_Error object on failure. 1316 */ 1317 function numRows() 1318 { 1319 if ($this->dbh->features['numrows'] === 'emulate' 1320 && $this->dbh->options['portability'] & DB_PORTABILITY_NUMROWS) 1321 { 1322 if ($this->dbh->features['prepare']) { 1323 $res = $this->dbh->query($this->query, $this->parameters); 1324 } else { 1325 $res = $this->dbh->query($this->query); 1326 } 1327 if (DB::isError($res)) { 1328 return $res; 1329 } 1330 $i = 0; 1331 while ($res->fetchInto($tmp, DB_FETCHMODE_ORDERED)) { 1332 $i++; 1333 } 1334 $count = $i; 1335 } else { 1336 $count = $this->dbh->numRows($this->result); 1337 } 1338 1339 /* fbsql is checked for here because limit queries are implemented 1340 * using a TOP() function, which results in fbsql_num_rows still 1341 * returning the total number of rows that would have been returned, 1342 * rather than the real number. As a result, we'll just do the limit 1343 * calculations for fbsql in the same way as a database with emulated 1344 * limits. Unfortunately, we can't just do this in DB_fbsql::numRows() 1345 * because that only gets the result resource, rather than the full 1346 * DB_Result object. */ 1347 if (($this->dbh->features['limit'] === 'emulate' 1348 && $this->limit_from !== null) 1349 || $this->dbh->phptype == 'fbsql') { 1350 $limit_count = is_null($this->limit_count) ? $count : $this->limit_count; 1351 if ($count < $this->limit_from) { 1352 $count = 0; 1353 } elseif ($count < ($this->limit_from + $limit_count)) { 1354 $count -= $this->limit_from; 1355 } else { 1356 $count = $limit_count; 1357 } 1358 } 1359 1360 return $count; 1361 } 1362 1363 // }}} 1364 // {{{ nextResult() 1365 1366 /** 1367 * Get the next result if a batch of queries was executed 1368 * 1369 * @return bool true if a new result is available or false if not 1370 */ 1371 function nextResult() 1372 { 1373 return $this->dbh->nextResult($this->result); 1374 } 1375 1376 // }}} 1377 // {{{ free() 1378 1379 /** 1380 * Frees the resources allocated for this result set 1381 * 1382 * @return bool true on success. A DB_Error object on failure. 1383 */ 1384 function free() 1385 { 1386 $err = $this->dbh->freeResult($this->result); 1387 if (DB::isError($err)) { 1388 return $err; 1389 } 1390 $this->result = false; 1391 $this->statement = false; 1392 return true; 1393 } 1394 1395 // }}} 1396 // {{{ tableInfo() 1397 1398 /** 1399 * @see DB_common::tableInfo() 1400 * @deprecated Method deprecated some time before Release 1.2 1401 */ 1402 function tableInfo($mode = null) 1403 { 1404 if (is_string($mode)) { 1405 return $this->dbh->raiseError(DB_ERROR_NEED_MORE_DATA); 1406 } 1407 return $this->dbh->tableInfo($this, $mode); 1408 } 1409 1410 // }}} 1411 // {{{ getQuery() 1412 1413 /** 1414 * Determine the query string that created this result 1415 * 1416 * @return string the query string 1417 * 1418 * @since Method available since Release 1.7.0 1419 */ 1420 function getQuery() 1421 { 1422 return $this->query; 1423 } 1424 1425 // }}} 1426 // {{{ getRowCounter() 1427 1428 /** 1429 * Tells which row number is currently being processed 1430 * 1431 * @return integer the current row being looked at. Starts at 1. 1432 */ 1433 function getRowCounter() 1434 { 1435 return $this->row_counter; 1436 } 1437 1438 // }}} 1439 } 1440 1441 // }}} 1442 // {{{ class DB_row 1443 1444 /** 1445 * PEAR DB Row Object 1446 * 1447 * The object contains a row of data from a result set. Each column's data 1448 * is placed in a property named for the column. 1449 * 1450 * @category Database 1451 * @package DB 1452 * @author Stig Bakken <ssb@php.net> 1453 * @copyright 1997-2005 The PHP Group 1454 * @license http://www.php.net/license/3_0.txt PHP License 3.0 1455 * @version Release: 1.7.9 1456 * @link http://pear.php.net/package/DB 1457 * @see DB_common::setFetchMode() 1458 */ 1459 class DB_row 1460 { 1461 // {{{ constructor 1462 1463 /** 1464 * The constructor places a row's data into properties of this object 1465 * 1466 * @param array the array containing the row's data 1467 * 1468 * @return void 1469 */ 1470 function DB_row(&$arr) 1471 { 1472 foreach ($arr as $key => $value) { 1473 $this->$key = &$arr[$key]; 1474 } 1475 } 1476 1477 // }}} 1478 } 1479 1480 // }}} 1481 1482 /* 1483 * Local variables: 1484 * tab-width: 4 1485 * c-basic-offset: 4 1486 * End: 1487 */ 1488 1489 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sun Feb 25 14:08:00 2007 | par Balluche grâce à PHPXref 0.7 |