home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 August / PCWorld_2001-08_cd.bin / Komunikace / phptriad / phptriadsetup2-11.exe / php / pear / DB.php < prev    next >
PHP Script  |  2001-03-12  |  19KB  |  629 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4.0                                                      |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2001 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Stig Bakken <ssb@fast.no>                                   |
  17. // |          Tomas V.V.Cox <cox@idecnet.com>                             |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: DB.php,v 1.50 2001/03/11 23:26:18 jon Exp $
  21. //
  22. // Database independent query interface.
  23. //
  24.  
  25. require_once "PEAR.php";
  26.  
  27. /*
  28.  * The method mapErrorCode in each DB_dbtype implementation maps
  29.  * native error codes to one of these.
  30.  *
  31.  * If you add an error code here, make sure you also add a textual
  32.  * version of it in DB::errorMessage().
  33.  */
  34.  
  35. define("DB_OK",                         0);
  36. define("DB_ERROR",                     -1);
  37. define("DB_ERROR_SYNTAX",              -2);
  38. define("DB_ERROR_CONSTRAINT",          -3);
  39. define("DB_ERROR_NOT_FOUND",           -4);
  40. define("DB_ERROR_ALREADY_EXISTS",      -5);
  41. define("DB_ERROR_UNSUPPORTED",         -6);
  42. define("DB_ERROR_MISMATCH",            -7);
  43. define("DB_ERROR_INVALID",             -8);
  44. define("DB_ERROR_NOT_CAPABLE",         -9);
  45. define("DB_ERROR_TRUNCATED",          -10);
  46. define("DB_ERROR_INVALID_NUMBER",     -11);
  47. define("DB_ERROR_INVALID_DATE",       -12);
  48. define("DB_ERROR_DIVZERO",            -13);
  49. define("DB_ERROR_NODBSELECTED",       -14);
  50. define("DB_ERROR_CANNOT_CREATE",      -15);
  51. define("DB_ERROR_CANNOT_DELETE",      -16);
  52. define("DB_ERROR_CANNOT_DROP",        -17);
  53. define("DB_ERROR_NOSUCHTABLE",        -18);
  54. define("DB_ERROR_NOSUCHFIELD",        -19);
  55. define("DB_ERROR_NEED_MORE_DATA",     -20);
  56. define("DB_ERROR_NOT_LOCKED",         -21);
  57. define("DB_ERROR_VALUE_COUNT_ON_ROW", -22);
  58. define("DB_ERROR_INVALID_DSN",        -23);
  59.  
  60. /*
  61.  * Warnings are not detected as errors by DB::isError(), and are not
  62.  * fatal.  You can detect whether an error is in fact a warning with
  63.  * DB::isWarning().
  64.  */
  65.  
  66. define("DB_WARNING",           -1000);
  67. define("DB_WARNING_READ_ONLY", -1001);
  68.  
  69. /*
  70.  * These constants are used when storing information about prepared
  71.  * statements (using the "prepare" method in DB_dbtype).
  72.  *
  73.  * The prepare/execute model in DB is mostly borrowed from the ODBC
  74.  * extension, in a query the "?" character means a scalar parameter.
  75.  * There is one extension though, a "*" character means an opaque
  76.  * parameter.  An opaque parameter is simply a file name, the real
  77.  * data are in that file (useful for stuff like putting uploaded files
  78.  * into your database).
  79.  */
  80.  
  81. define("DB_PARAM_SCALAR", 1);
  82. define("DB_PARAM_OPAQUE", 2);
  83.  
  84. /*
  85.  * These constants define different ways of returning binary data
  86.  * from queries.  Again, this model has been borrowed from the ODBC
  87.  * extension.
  88.  *
  89.  * DB_BINMODE_PASSTHRU sends the data directly through to the browser
  90.  * when data is fetched from the database.
  91.  * DB_BINMODE_RETURN lets you return data as usual.
  92.  * DB_BINMODE_CONVERT returns data as well, only it is converted to
  93.  * hex format, for example the string "123" would become "313233".
  94.  */
  95.  
  96. define("DB_BINMODE_PASSTHRU", 1);
  97. define("DB_BINMODE_RETURN",   2);
  98. define("DB_BINMODE_CONVERT",  3);
  99.  
  100. /**
  101.  * This is a special constant that tells DB the user hasn't specified
  102.  * any particular get mode, so the default should be used.
  103.  */
  104.  
  105. define("DB_FETCHMODE_DEFAULT", 0);
  106.  
  107. /**
  108.  * Column data indexed by numbers, ordered from 0 and up
  109.  */
  110.  
  111. define("DB_FETCHMODE_ORDERED", 1);
  112.  
  113. /**
  114.  * Column data indexed by column names
  115.  */
  116.  
  117. define("DB_FETCHMODE_ASSOC", 2);
  118.  
  119. /**
  120.  * For multi-dimensional results: normally the first level of arrays
  121.  * is the row number, and the second level indexed by column number or name.
  122.  * DB_FETCHMODE_FLIPPED switches this order, so the first level of arrays
  123.  * is the column name, and the second level the row number.
  124.  */
  125.  
  126. define("DB_FETCHMODE_FLIPPED", 4);
  127.  
  128. /* for compatibility */
  129.  
  130. define("DB_GETMODE_ORDERED", DB_FETCHMODE_ORDERED);
  131. define("DB_GETMODE_ASSOC",   DB_FETCHMODE_ASSOC);
  132. define("DB_GETMODE_FLIPPED", DB_FETCHMODE_FLIPPED);
  133.  
  134. /**
  135.  * The main "DB" class is simply a container class with some static
  136.  * methods for creating DB objects as well as some utility functions
  137.  * common to all parts of DB.
  138.  *
  139.  * The object model of DB is as follows (indentation means inheritance):
  140.  *
  141.  * DB           The main DB class.  This is simply a utility class
  142.  *              with some "static" methods for creating DB objects as
  143.  *              well as common utility functions for other DB classes.
  144.  * 
  145.  * DB_common    The base for each DB implementation.  Provides default
  146.  * |            implementations (in OO lingo virtual methods) for
  147.  * |            the actual DB implementations as well as a bunch of
  148.  * |            query utility functions.
  149.  * |
  150.  * +-DB_mysql   The DB implementation for MySQL.  Inherits DB_common.
  151.  *              When calling DB::factory or DB::connect for MySQL
  152.  *              connections, the object returned is an instance of this
  153.  *              class.
  154.  *
  155.  * @version  2
  156.  * @author   Stig Bakken <ssb@fast.no>
  157.  * @since    PHP 4.0
  158.  */
  159.  
  160. class DB
  161. {
  162.     /**
  163.      * Create a new DB object for the specified database type
  164.      *
  165.      * @param $type string database type, for example "mysql"
  166.      *
  167.      * @return object a newly created DB object, or a DB error code on
  168.      * error
  169.      */
  170.  
  171.     function &factory($type)
  172.     {
  173.     @include_once("DB/${type}.php");
  174.  
  175.     $classname = "DB_${type}";
  176.     @$obj =& new $classname;
  177.  
  178.     if (!$obj) {
  179.         return new DB_Error(DB_ERROR_NOT_FOUND);
  180.     }
  181.  
  182.     return $obj;
  183.     }
  184.  
  185.     /**
  186.      * Create a new DB object and connect to the specified database
  187.      *
  188.      * @param $dsn mixed "data source name", see the DB::parseDSN
  189.      * method for a description of the dsn format.  Can also be
  190.      * specified as an array of the format returned by DB::parseDSN.
  191.      *
  192.      * @param $options mixed if boolean (or scalar), tells whether
  193.      * this connection should be persistent (for backends that support
  194.      * this).  This parameter can also be an array of options, see
  195.      * DB_common::setOption for more information on connection
  196.      * options.
  197.      *
  198.      * @return object a newly created DB object, or a DB error code on
  199.      * error
  200.      *
  201.      * @see DB::parseDSN
  202.      */
  203.     function &connect($dsn, $options = false)
  204.     {
  205.         if (is_array($dsn)) {
  206.             $dsninfo = $dsn;
  207.         } else {
  208.             $dsninfo = DB::parseDSN($dsn);
  209.         }
  210.         $type = $dsninfo["phptype"];
  211.     
  212.     @include_once "DB/${type}.php";
  213.         $classname = "DB_${type}";
  214.         @$obj =& new $classname;
  215.  
  216.         if (!$obj) {
  217.             return new DB_Error(DB_ERROR_NOT_FOUND);
  218.         }
  219.  
  220.         if (is_array($options)) {
  221.             foreach ($options as $option => $value) {
  222.                 $test = $obj->setOption($option, $value);
  223.                 if (DB::isError($test)) {
  224.                     return $test;
  225.                 }
  226.             }
  227.         } else {
  228.             $obj->setOption('persistent', $options);
  229.         }
  230.         $err = $obj->connect($dsninfo, $obj->getOption('persistent'));
  231.  
  232.         if (DB::isError($err)) {
  233.             return $err;
  234.         }
  235.  
  236.         return $obj;
  237.     }
  238.  
  239.     /**
  240.      * Return the DB API version
  241.      *
  242.      * @return int the DB API version number
  243.      */
  244.     function apiVersion()
  245.     {
  246.     return 2;
  247.     }
  248.  
  249.     /**
  250.      * Tell whether a result code from a DB method is an error
  251.      *
  252.      * @param $value int result code
  253.      *
  254.      * @return bool whether $value is an error
  255.      */
  256.     function isError($value)
  257.     {
  258.     return (is_object($value) &&
  259.         (get_class($value) == 'db_error' ||
  260.          is_subclass_of($value, 'db_error')));
  261.     }
  262.  
  263.     /**
  264.      * Tell whether a query is a data manipulation query (insert, update
  265.      * or delete).
  266.      *
  267.      * @access public
  268.      *
  269.      * @param string the query
  270.      *
  271.      * @return bool whether $query is a data manipulation query
  272.      */
  273.     function isManip($query)
  274.     {
  275.         if (preg_match('/^\s*(INSERT|UPDATE|DELETE|REPLACE)\s+/i', $query)) {
  276.             return true;
  277.         }
  278.         return false;
  279.     }
  280.  
  281.     /**
  282.      * Tell whether a result code from a DB method is a warning.
  283.      * Warnings differ from errors in that they are generated by DB,
  284.      * and are not fatal.
  285.      *
  286.      * @param $value mixed result value
  287.      *
  288.      * @return bool whether $value is a warning
  289.      */
  290.     function isWarning($value)
  291.     {
  292.     return is_object($value) &&
  293.         (get_class( $value ) == "db_warning" ||
  294.          is_subclass_of($value, "db_warning"));
  295.     }
  296.  
  297.     /**
  298.      * Return a textual error message for a DB error code
  299.      *
  300.      * @param $value int error code
  301.      *
  302.      * @return string error message, or false if the error code was
  303.      * not recognized
  304.      */
  305.     function errorMessage($value)
  306.     {
  307.     if (!isset($errorMessages)) {
  308.         $errorMessages = array(
  309.         DB_ERROR                    => "unknown error",
  310.         DB_ERROR_ALREADY_EXISTS     => "already exists",
  311.         DB_ERROR_CANNOT_CREATE      => "can not create",
  312.         DB_ERROR_CANNOT_DELETE      => "can not delete",
  313.         DB_ERROR_CANNOT_DROP        => "can not drop",
  314.         DB_ERROR_CONSTRAINT         => "constraint violation",
  315.         DB_ERROR_DIVZERO            => "division by zero",
  316.         DB_ERROR_INVALID            => "invalid",
  317.         DB_ERROR_INVALID_DATE       => "invalid date or time",
  318.         DB_ERROR_INVALID_NUMBER     => "invalid number",
  319.         DB_ERROR_MISMATCH           => "mismatch",
  320.         DB_ERROR_NODBSELECTED       => "no database selected",
  321.         DB_ERROR_NOSUCHFIELD        => "no such field",
  322.         DB_ERROR_NOSUCHTABLE        => "no such table",
  323.         DB_ERROR_NOT_CAPABLE        => "DB backend not capable",
  324.         DB_ERROR_NOT_FOUND          => "not found",
  325.         DB_ERROR_NOT_LOCKED         => "not locked",
  326.         DB_ERROR_SYNTAX             => "syntax error",
  327.         DB_ERROR_UNSUPPORTED        => "not supported",
  328.         DB_ERROR_VALUE_COUNT_ON_ROW => "value count on row",
  329.         DB_OK                       => "no error",
  330.         DB_WARNING                  => "unknown warning",
  331.         DB_WARNING_READ_ONLY        => "read only"
  332.         );
  333.     }
  334.  
  335.     if (DB::isError($value)) {
  336.         $value = $value->code;
  337.     }
  338.  
  339.     return $errorMessages[$value];
  340.     }
  341.  
  342.     /**
  343.      * Parse a data source name
  344.      *
  345.      * @param $dsn string Data Source Name to be parsed
  346.      *
  347.      * @return array an associative array with the following keys:
  348.      *
  349.      *  phptype: Database backend used in PHP (mysql, odbc etc.)
  350.      *  dbsyntax: Database used with regards to SQL syntax etc.
  351.      *  protocol: Communication protocol to use (tcp, unix etc.)
  352.      *  hostspec: Host specification (hostname[:port])
  353.      *  database: Database to use on the DBMS server
  354.      *  username: User name for login
  355.      *  password: Password for login
  356.      *
  357.      * The format of the supplied DSN is in its fullest form:
  358.      *
  359.      *  phptype(dbsyntax)://username:password@protocol+hostspec/database
  360.      *
  361.      * Most variations are allowed:
  362.      *
  363.      *  phptype://username:password@protocol+hostspec:110//usr/db_file.db
  364.      *  phptype://username:password@hostspec/database_name
  365.      *  phptype://username:password@hostspec
  366.      *  phptype://username@hostspec
  367.      *  phptype://hostspec/database
  368.      *  phptype://hostspec
  369.      *  phptype(dbsyntax)
  370.      *  phptype
  371.      *
  372.      * @author Tomas V.V.Cox <cox@idecnet.com>
  373.      */
  374.     function parseDSN($dsn)
  375.     {
  376.         if (is_array($dsn)) {
  377.             return $dsn;
  378.         }
  379.  
  380.         $parsed = array(
  381.             'phptype'  => false,
  382.             'dbsyntax' => false,
  383.             'protocol' => false,
  384.             'hostspec' => false,
  385.             'database' => false,
  386.             'username' => false,
  387.             'password' => false
  388.         );
  389.  
  390.         // Find phptype and dbsyntax
  391.         if (($pos = strpos($dsn, '://')) !== false) {
  392.             $str = substr($dsn, 0, $pos);
  393.             $dsn = substr($dsn, $pos + 3);
  394.         } else {
  395.             $str = $dsn;
  396.             $dsn = NULL;
  397.         }
  398.  
  399.         // Get phptype and dbsyntax
  400.         // $str => phptype(dbsyntax)
  401.         if (preg_match('|^([^(]+)\(([^(]*)\)$|', $str, $arr)) {
  402.             $parsed['phptype'] = $arr[1];
  403.             $parsed['dbsyntax'] = (empty($arr[2])) ? $arr[1] : $arr[2];
  404.         } else {
  405.             $parsed['phptype'] = $str;
  406.             $parsed['dbsyntax'] = $str;
  407.         }
  408.     
  409.         if (empty($dsn)) {
  410.             return $parsed;
  411.         }
  412.  
  413.         // Get (if found): username and password
  414.         // $dsn => username:password@protocol+hostspec/database
  415.         if (($at = strpos($dsn,'@')) !== false) {
  416.             $str = substr($dsn, 0, $at);
  417.             $dsn = substr($dsn, $at + 1);
  418.             if (($pos = strpos($str, ':')) !== false) {
  419.                 $parsed['username'] = urldecode(substr($str, 0, $pos));
  420.                 $parsed['password'] = urldecode(substr($str, $pos + 1));
  421.             } else {
  422.                 $parsed['username'] = urldecode($str);
  423.             }
  424.         }
  425.  
  426.         // Find protocol and hostspec
  427.         // $dsn => protocol+hostspec/database
  428.         if (($pos=strpos($dsn, '/')) !== false) {
  429.             $str = substr($dsn, 0, $pos);
  430.             $dsn = substr($dsn, $pos + 1);
  431.         } else {
  432.             $str = $dsn;
  433.             $dsn = NULL;
  434.         }
  435.  
  436.         // Get protocol + hostspec
  437.         // $str => protocol+hostspec
  438.         if (($pos=strpos($str, '+')) !== false) {
  439.             $parsed['protocol'] = substr($str, 0, $pos);
  440.             $parsed['hostspec'] = urldecode(substr($str, $pos + 1));
  441.         } else {
  442.             $parsed['hostspec'] = urldecode($str);
  443.         }
  444.  
  445.         // Get dabase if any
  446.         // $dsn => database
  447.         if (!empty($dsn)) {
  448.             $parsed['database'] = $dsn;
  449.         }
  450.  
  451.         return $parsed;
  452.     }
  453.  
  454.     /**
  455.      * Load a PHP database extension if it is not loaded already.
  456.      *
  457.      * @access public
  458.      *
  459.      * @param $name the base name of the extension (without the .so or
  460.      * .dll suffix)
  461.      *
  462.      * @return bool true if the extension was already or successfully
  463.      * loaded, false if it could not be loaded
  464.      */
  465.     function assertExtension($name)
  466.     {
  467.         if (!extension_loaded($name)) {
  468.             $dlext = (substr(PHP_OS, 0, 3) == "WIN") ? ".dll" : ".so";
  469.             @dl($name . $dlext);
  470.         }
  471.         if (!extension_loaded($name)) {
  472.             return false;
  473.         }
  474.         return true;
  475.     }
  476. }
  477.  
  478. /**
  479.  * DB_Error implements a class for reporting portable database error
  480.  * messages.
  481.  *
  482.  * @author Stig Bakken <ssb@fast.no>
  483.  */
  484. class DB_Error extends PEAR_Error
  485. {
  486.     /**
  487.      * DB_Error constructor.
  488.      *
  489.      * @param $code mixed DB error code, or string with error message.
  490.      * @param $mode int what "error mode" to operate in
  491.      * @param $level what error level to use for $mode & PEAR_ERROR_TRIGGER
  492.      * @param $debuginfo additional debug info, such as the last query
  493.      *
  494.      * @access public
  495.      *
  496.      * @see PEAR_Error
  497.      */
  498.  
  499.     function DB_Error($code = DB_ERROR, $mode = PEAR_ERROR_RETURN,
  500.               $level = E_USER_NOTICE, $debuginfo = null)
  501.     {
  502.     if (is_int($code)) {
  503.         $this->PEAR_Error("DB Error: " . DB::errorMessage( $code ), $code, $mode, $level, $debuginfo);
  504.     } else {
  505.         $this->PEAR_Error("DB Error: $code", DB_ERROR, $mode, $level, $debuginfo);
  506.     }
  507.     }
  508. }
  509.  
  510. /**
  511.  * DB_Warning implements a class for reporting portable database
  512.  * warning messages.
  513.  *
  514.  * @author Stig Bakken <ssb@fast.no>
  515.  */
  516. class DB_Warning extends PEAR_Error
  517. {
  518.     /**
  519.      * DB_Warning constructor.
  520.      *
  521.      * @param $code mixed DB error code, or string with error message.
  522.      * @param $mode int what "error mode" to operate in
  523.      * @param $level what error level to use for $mode == PEAR_ERROR_TRIGGER
  524.      * @param $debuginfo additional debug info, such as the last query
  525.      *
  526.      * @access public
  527.      *
  528.      * @see PEAR_Error
  529.      */
  530.  
  531.     function DB_Warning($code = DB_WARNING, $mode = PEAR_ERROR_RETURN,
  532.             $level = E_USER_NOTICE, $debuginfo = null)
  533.     {
  534.       if (is_int($code)) {
  535.       $this->PEAR_Error("DB Warning: " . DB::errorMessage( $code ), $code, $mode, $level, $debuginfo);
  536.       } else {
  537.       $this->PEAR_Error("DB Warning: $code", 0, $mode, $level, $debuginfo);
  538.       }
  539.     }
  540. }
  541.  
  542. /**
  543.  * This class implements a wrapper for a DB result set.
  544.  * A new instance of this class will be returned by the DB implementation
  545.  * after processing a query that returns data.
  546.  *
  547.  * @author Stig Bakken <ssb@fast.no>
  548.  */
  549.  
  550. class DB_result
  551. {
  552.     var $dbh;
  553.     var $result;
  554.  
  555.     /**
  556.      * DB_result constructor.
  557.      * @param   $dbh    DB object reference
  558.      * @param   $result result resource id
  559.      */
  560.  
  561.     function DB_result(&$dbh, $result)
  562.     {
  563.     $this->dbh = &$dbh;
  564.     $this->result = $result;
  565.     }
  566.  
  567.     /**
  568.      * Fetch and return a row of data.
  569.      * @return  array   a row of data, or false on error
  570.      */
  571.     function fetchRow($fetchmode = DB_FETCHMODE_DEFAULT)
  572.     {
  573.     if ($fetchmode == DB_FETCHMODE_DEFAULT) {
  574.         $fetchmode = $this->dbh->fetchmode;
  575.     }
  576.     return $this->dbh->fetchRow($this->result, $fetchmode);
  577.     }
  578.  
  579.     /**
  580.      * Fetch a row of data into an existing array.
  581.      *
  582.      * @param   $arr    reference to data array
  583.      * @return  int     error code
  584.      */
  585.     function fetchInto(&$arr, $fetchmode = DB_FETCHMODE_DEFAULT)
  586.     {
  587.     if ($fetchmode == DB_FETCHMODE_DEFAULT) {
  588.         $fetchmode = $this->dbh->fetchmode;
  589.     }
  590.     return $this->dbh->fetchInto($this->result, $arr, $fetchmode);
  591.     }
  592.  
  593.     /**
  594.      * Get the the number of columns in a result set.
  595.      *
  596.      * @return int the number of columns, or a DB error
  597.      */
  598.     function numCols()
  599.     {
  600.     return $this->dbh->numCols($this->result);
  601.     }
  602.  
  603.     /**
  604.      * Get the number of rows in a result set.
  605.      *
  606.      * @return int the number of rows, or a DB error
  607.      */
  608.     function numRows()
  609.     {
  610.         return $this->dbh->numRows($this->result);
  611.     }
  612.  
  613.     /**
  614.      * Frees the resources allocated for this result set.
  615.      * @return  int     error code
  616.      */
  617.     function free()
  618.     {
  619.     $err = $this->dbh->freeResult($this->result);
  620.     if(DB::isError($err)) {
  621.         return $err;
  622.     }
  623.     $this->result = false;
  624.     return true;
  625.     }
  626. }
  627.  
  628. ?>
  629.