You are here

class DB in Flickr API 5

Database independent query interface

The main "DB" class is simply a container class with some static methods for creating DB objects as well as some utility functions common to all parts of DB.

The object model of DB is as follows (indentation means inheritance): <pre> DB The main DB class. This is simply a utility class with some "static" methods for creating DB objects as well as common utility functions for other DB classes.

DB_common The base for each DB implementation. Provides default | implementations (in OO lingo virtual methods) for | the actual DB implementations as well as a bunch of | query utility functions. | +-DB_mysql The DB implementation for MySQL. Inherits DB_common. When calling DB::factory or DB::connect for MySQL connections, the object returned is an instance of this class. </pre>

@category Database @package DB @author Stig Bakken <ssb@php.net> @author Tomas V.V.Cox <cox@idecnet.com> @author Daniel Convissor <danielc@php.net> @copyright 1997-2005 The PHP Group @license http://www.php.net/license/3_0.txt PHP License 3.0 @version Release: @package_version@ @link http://pear.php.net/package/DB

Hierarchy

  • class \DB

Expanded class hierarchy of DB

File

phpFlickr/PEAR/DB.php, line 431

View source
class DB {

  // {{{ &factory()

  /**
   * Create a new DB object for the specified database type but don't
   * connect to the database
   *
   * @param string $type     the database type (eg "mysql")
   * @param array  $options  an associative array of option names and values
   *
   * @return object  a new DB object.  A DB_Error object on failure.
   *
   * @see DB_common::setOption()
   */
  function &factory($type, $options = false) {
    if (!is_array($options)) {
      $options = array(
        'persistent' => $options,
      );
    }
    if (isset($options['debug']) && $options['debug'] >= 2) {

      // expose php errors with sufficient debug level
      include_once "DB/{$type}.php";
    }
    else {
      @(include_once "DB/{$type}.php");
    }
    $classname = "DB_{$type}";
    if (!class_exists($classname)) {
      $tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null, "Unable to include the DB/{$type}.php" . " file for '{$dsn}'", 'DB_Error', true);
      return $tmp;
    }
    @($obj =& new $classname());
    foreach ($options as $option => $value) {
      $test = $obj
        ->setOption($option, $value);
      if (DB::isError($test)) {
        return $test;
      }
    }
    return $obj;
  }

  // }}}
  // {{{ &connect()

  /**
   * Create a new DB object including a connection to the specified database
   *
   * Example 1.
   * <code>
   * require_once 'DB.php';
   *
   * $dsn = 'pgsql://user:password@host/database';
   * $options = array(
   *     'debug'       => 2,
   *     'portability' => DB_PORTABILITY_ALL,
   * );
   *
   * $db =& DB::connect($dsn, $options);
   * if (PEAR::isError($db)) {
   *     die($db->getMessage());
   * }
   * </code>
   *
   * @param mixed $dsn      the string "data source name" or array in the
   *                         format returned by DB::parseDSN()
   * @param array $options  an associative array of option names and values
   *
   * @return object  a new DB object.  A DB_Error object on failure.
   *
   * @uses DB_dbase::connect(), DB_fbsql::connect(), DB_ibase::connect(),
   *       DB_ifx::connect(), DB_msql::connect(), DB_mssql::connect(),
   *       DB_mysql::connect(), DB_mysqli::connect(), DB_oci8::connect(),
   *       DB_odbc::connect(), DB_pgsql::connect(), DB_sqlite::connect(),
   *       DB_sybase::connect()
   *
   * @uses DB::parseDSN(), DB_common::setOption(), PEAR::isError()
   */
  function &connect($dsn, $options = []) {
    $dsninfo = DB::parseDSN($dsn);
    $type = $dsninfo['phptype'];
    if (!is_array($options)) {

      /*
       * For backwards compatibility.  $options used to be boolean,
       * indicating whether the connection should be persistent.
       */
      $options = array(
        'persistent' => $options,
      );
    }
    if (isset($options['debug']) && $options['debug'] >= 2) {

      // expose php errors with sufficient debug level
      include_once "DB/{$type}.php";
    }
    else {
      @(include_once "DB/{$type}.php");
    }
    $classname = "DB_{$type}";
    if (!class_exists($classname)) {
      $tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null, "Unable to include the DB/{$type}.php" . " file for '{$dsn}'", 'DB_Error', true);
      return $tmp;
    }
    @($obj =& new $classname());
    foreach ($options as $option => $value) {
      $test = $obj
        ->setOption($option, $value);
      if (DB::isError($test)) {
        return $test;
      }
    }
    $err = $obj
      ->connect($dsninfo, $obj
      ->getOption('persistent'));
    if (DB::isError($err)) {
      $err
        ->addUserInfo($dsn);
      return $err;
    }
    return $obj;
  }

  // }}}
  // {{{ apiVersion()

  /**
   * Return the DB API version
   *
   * @return string  the DB API version number
   */
  function apiVersion() {
    return '@package_version@';
  }

  // }}}
  // {{{ isError()

  /**
   * Determines if a variable is a DB_Error object
   *
   * @param mixed $value  the variable to check
   *
   * @return bool  whether $value is DB_Error object
   */
  function isError($value) {
    return is_a($value, 'DB_Error');
  }

  // }}}
  // {{{ isConnection()

  /**
   * Determines if a value is a DB_<driver> object
   *
   * @param mixed $value  the value to test
   *
   * @return bool  whether $value is a DB_<driver> object
   */
  function isConnection($value) {
    return is_object($value) && is_subclass_of($value, 'db_common') && method_exists($value, 'simpleQuery');
  }

  // }}}
  // {{{ isManip()

  /**
   * Tell whether a query is a data manipulation or data definition query
   *
   * Examples of data manipulation queries are INSERT, UPDATE and DELETE.
   * Examples of data definition queries are CREATE, DROP, ALTER, GRANT,
   * REVOKE.
   *
   * @param string $query  the query
   *
   * @return boolean  whether $query is a data manipulation query
   */
  function isManip($query) {
    $manips = 'INSERT|UPDATE|DELETE|REPLACE|' . 'CREATE|DROP|' . 'LOAD DATA|SELECT .* INTO|COPY|' . 'ALTER|GRANT|REVOKE|' . 'LOCK|UNLOCK';
    if (preg_match('/^\\s*"?(' . $manips . ')\\s+/i', $query)) {
      return true;
    }
    return false;
  }

  // }}}
  // {{{ errorMessage()

  /**
   * Return a textual error message for a DB error code
   *
   * @param integer $value  the DB error code
   *
   * @return string  the error message or false if the error code was
   *                  not recognized
   */
  function errorMessage($value) {
    static $errorMessages;
    if (!isset($errorMessages)) {
      $errorMessages = array(
        DB_ERROR => 'unknown error',
        DB_ERROR_ACCESS_VIOLATION => 'insufficient permissions',
        DB_ERROR_ALREADY_EXISTS => 'already exists',
        DB_ERROR_CANNOT_CREATE => 'can not create',
        DB_ERROR_CANNOT_DROP => 'can not drop',
        DB_ERROR_CONNECT_FAILED => 'connect failed',
        DB_ERROR_CONSTRAINT => 'constraint violation',
        DB_ERROR_CONSTRAINT_NOT_NULL => 'null value violates not-null constraint',
        DB_ERROR_DIVZERO => 'division by zero',
        DB_ERROR_EXTENSION_NOT_FOUND => 'extension not found',
        DB_ERROR_INVALID => 'invalid',
        DB_ERROR_INVALID_DATE => 'invalid date or time',
        DB_ERROR_INVALID_DSN => 'invalid DSN',
        DB_ERROR_INVALID_NUMBER => 'invalid number',
        DB_ERROR_MISMATCH => 'mismatch',
        DB_ERROR_NEED_MORE_DATA => 'insufficient data supplied',
        DB_ERROR_NODBSELECTED => 'no database selected',
        DB_ERROR_NOSUCHDB => 'no such database',
        DB_ERROR_NOSUCHFIELD => 'no such field',
        DB_ERROR_NOSUCHTABLE => 'no such table',
        DB_ERROR_NOT_CAPABLE => 'DB backend not capable',
        DB_ERROR_NOT_FOUND => 'not found',
        DB_ERROR_NOT_LOCKED => 'not locked',
        DB_ERROR_SYNTAX => 'syntax error',
        DB_ERROR_UNSUPPORTED => 'not supported',
        DB_ERROR_TRUNCATED => 'truncated',
        DB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row',
        DB_OK => 'no error',
      );
    }
    if (DB::isError($value)) {
      $value = $value
        ->getCode();
    }
    return isset($errorMessages[$value]) ? $errorMessages[$value] : $errorMessages[DB_ERROR];
  }

  // }}}
  // {{{ parseDSN()

  /**
   * Parse a data source name
   *
   * Additional keys can be added by appending a URI query string to the
   * end of the DSN.
   *
   * The format of the supplied DSN is in its fullest form:
   * <code>
   *  phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true
   * </code>
   *
   * Most variations are allowed:
   * <code>
   *  phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644
   *  phptype://username:password@hostspec/database_name
   *  phptype://username:password@hostspec
   *  phptype://username@hostspec
   *  phptype://hostspec/database
   *  phptype://hostspec
   *  phptype(dbsyntax)
   *  phptype
   * </code>
   *
   * @param string $dsn Data Source Name to be parsed
   *
   * @return array an associative array with the following keys:
   *  + phptype:  Database backend used in PHP (mysql, odbc etc.)
   *  + dbsyntax: Database used with regards to SQL syntax etc.
   *  + protocol: Communication protocol to use (tcp, unix etc.)
   *  + hostspec: Host specification (hostname[:port])
   *  + database: Database to use on the DBMS server
   *  + username: User name for login
   *  + password: Password for login
   */
  function parseDSN($dsn) {
    $parsed = array(
      'phptype' => false,
      'dbsyntax' => false,
      'username' => false,
      'password' => false,
      'protocol' => false,
      'hostspec' => false,
      'port' => false,
      'socket' => false,
      'database' => false,
    );
    if (is_array($dsn)) {
      $dsn = array_merge($parsed, $dsn);
      if (!$dsn['dbsyntax']) {
        $dsn['dbsyntax'] = $dsn['phptype'];
      }
      return $dsn;
    }

    // Find phptype and dbsyntax
    if (($pos = strpos($dsn, '://')) !== false) {
      $str = substr($dsn, 0, $pos);
      $dsn = substr($dsn, $pos + 3);
    }
    else {
      $str = $dsn;
      $dsn = null;
    }

    // Get phptype and dbsyntax
    // $str => phptype(dbsyntax)
    if (preg_match('|^(.+?)\\((.*?)\\)$|', $str, $arr)) {
      $parsed['phptype'] = $arr[1];
      $parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2];
    }
    else {
      $parsed['phptype'] = $str;
      $parsed['dbsyntax'] = $str;
    }
    if (!count($dsn)) {
      return $parsed;
    }

    // Get (if found): username and password
    // $dsn => username:password@protocol+hostspec/database
    if (($at = strrpos($dsn, '@')) !== false) {
      $str = substr($dsn, 0, $at);
      $dsn = substr($dsn, $at + 1);
      if (($pos = strpos($str, ':')) !== false) {
        $parsed['username'] = rawurldecode(substr($str, 0, $pos));
        $parsed['password'] = rawurldecode(substr($str, $pos + 1));
      }
      else {
        $parsed['username'] = rawurldecode($str);
      }
    }

    // Find protocol and hostspec
    if (preg_match('|^([^(]+)\\((.*?)\\)/?(.*?)$|', $dsn, $match)) {

      // $dsn => proto(proto_opts)/database
      $proto = $match[1];
      $proto_opts = $match[2] ? $match[2] : false;
      $dsn = $match[3];
    }
    else {

      // $dsn => protocol+hostspec/database (old format)
      if (strpos($dsn, '+') !== false) {
        list($proto, $dsn) = explode('+', $dsn, 2);
      }
      if (strpos($dsn, '/') !== false) {
        list($proto_opts, $dsn) = explode('/', $dsn, 2);
      }
      else {
        $proto_opts = $dsn;
        $dsn = null;
      }
    }

    // process the different protocol options
    $parsed['protocol'] = !empty($proto) ? $proto : 'tcp';
    $proto_opts = rawurldecode($proto_opts);
    if ($parsed['protocol'] == 'tcp') {
      if (strpos($proto_opts, ':') !== false) {
        list($parsed['hostspec'], $parsed['port']) = explode(':', $proto_opts);
      }
      else {
        $parsed['hostspec'] = $proto_opts;
      }
    }
    elseif ($parsed['protocol'] == 'unix') {
      $parsed['socket'] = $proto_opts;
    }

    // Get dabase if any
    // $dsn => database
    if ($dsn) {
      if (($pos = strpos($dsn, '?')) === false) {

        // /database
        $parsed['database'] = rawurldecode($dsn);
      }
      else {

        // /database?param1=value1&param2=value2
        $parsed['database'] = rawurldecode(substr($dsn, 0, $pos));
        $dsn = substr($dsn, $pos + 1);
        if (strpos($dsn, '&') !== false) {
          $opts = explode('&', $dsn);
        }
        else {

          // database?param1=value1
          $opts = array(
            $dsn,
          );
        }
        foreach ($opts as $opt) {
          list($key, $value) = explode('=', $opt);
          if (!isset($parsed[$key])) {

            // don't allow params overwrite
            $parsed[$key] = rawurldecode($value);
          }
        }
      }
    }
    return $parsed;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DB::apiVersion function Return the DB API version
DB::connect function Create a new DB object including a connection to the specified database
DB::errorMessage function Return a textual error message for a DB error code
DB::factory function Create a new DB object for the specified database type but don't connect to the database
DB::isConnection function Determines if a value is a DB_<driver> object
DB::isError function Determines if a variable is a DB_Error object
DB::isManip function Tell whether a query is a data manipulation or data definition query
DB::parseDSN function Parse a data source name