[ Index ]
 

Code source de Symfony 1.0.0

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/lib/vendor/creole/ -> Creole.php (source)

   1  <?php
   2  /*
   3   *  $Id: Creole.php,v 1.14 2006/01/17 20:06:31 hlellelid Exp $
   4   *
   5   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   6   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   7   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   8   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   9   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  10   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  11   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  12   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  13   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  14   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  15   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16   *
  17   * This software consists of voluntary contributions made by many individuals
  18   * and is licensed under the LGPL. For more information please see
  19   * <http://creole.phpdb.org>.
  20   */
  21  
  22  include_once 'creole/SQLException.php';
  23  include_once 'creole/Connection.php';
  24  
  25  // static:
  26  // track errors is used by drivers to get better error messages
  27  // make sure it's set.
  28  
  29  @ini_set('track_errors', true);
  30  
  31  /**
  32   * This is the class that manages the database drivers.
  33   *
  34   * There are a number of default drivers (at the time of writing this comment: MySQL, MSSQL, SQLite, PgSQL, Oracle)
  35   * that are "shipped" with Creole.  You may wish to either add a new driver or swap out one of the existing drivers
  36   * for your own custom driver.  To do this you simply need to register your driver using the registerDriver() method.
  37   *
  38   * Note that you register your Connection class because the Connection class is responsible for calling the other
  39   * driver classes (e.g. ResultSet, PreparedStatement, etc.).
  40   *
  41   *
  42   * @author    Hans Lellelid <hans@xmpl.org>
  43   * @version   $Revision: 1.14 $
  44   * @package   creole
  45   */
  46  class Creole {
  47  
  48      /**
  49       * Constant that indicates a connection object should be used.
  50       */
  51      const PERSISTENT = 1;
  52  
  53      /**
  54       * Flag to pass to the connection to indicate that no case conversions
  55       * should be performed by ResultSet on keys of fetched rows.
  56       * @deprecated use COMPAT_ASSOC_LOWER
  57       */
  58      const NO_ASSOC_LOWER = 16;
  59      
  60      /**
  61       * Flag to pass to the connection to indicate that a to-lower case conversion
  62       * should be performed by ResultSet on keys of fetched rows.
  63       */
  64      const COMPAT_ASSOC_LOWER = 32;
  65  
  66      /**
  67       * Flag to pass to the connection to indicate that an rtrim() should be performed
  68       * on strings (using ResultSet->getString(), etc.).
  69       */
  70      const COMPAT_RTRIM_STRING = 64;
  71      
  72      /**
  73       * Flag to indicate that all compatibility flags should be set.
  74       */
  75      const COMPAT_ALL = 96;
  76      
  77      /**
  78       * Map of built-in drivers.
  79       * Change or add your own using registerDriver()
  80       * @see registerDriver()
  81       * @var array Hash mapping phptype => driver class (in dot-path notation, e.g. 'mysql' => 'creole.drivers.mysql.MySQLConnection').
  82       */
  83      private static $driverMap = array(  'mysql' => 'creole.drivers.mysql.MySQLConnection',
  84                                          'mysqli' => 'creole.drivers.mysqli.MySQLiConnection',
  85                                          'pgsql' => 'creole.drivers.pgsql.PgSQLConnection',
  86                                          'sqlite' => 'creole.drivers.sqlite.SQLiteConnection',
  87                                          'oracle' => 'creole.drivers.oracle.OCI8Connection',
  88                                          'mssql' => 'creole.drivers.mssql.MSSQLConnection',
  89                                          'odbc' => 'creole.drivers.odbc.ODBCConnection'
  90                                         );
  91  
  92      /**
  93       * Map of already established connections
  94       * @see getConnection()
  95       * @var array Hash mapping connection DSN => Connection instance
  96       */
  97      private static $connectionMap = array();
  98  
  99      /**
 100       * Register your own RDBMS driver class.
 101       *
 102       * You can use this to specify your own class that replaces a default driver or
 103       * adds support for a new driver.  Register your own class by specifying the
 104       * 'phptype' (e.g. mysql) and a dot-path notation to where your Connection class is
 105       * relative to any location on the include path.  You can also specify '*' as the phptype
 106       * if you want to register a driver that will handle any native type (e.g. if creating
 107       * a set of decorator classes that log SQL before calling native driver methods).  YOU CAN
 108       * ONLY REGISTER ONE CATCHALL ('*') DRIVER.
 109       * <p>
 110       * Note: the class you need to register is your Connection class because this is the
 111       * class that's responsible for instantiating the other classes that are part of your
 112       * driver.  It is possible to mix & match drivers -- i.e. to write a custom driver where
 113       * the Connection object just instantiates stock classes for ResultSet and PreparedStatement.
 114       * Note that if you wanted to "override" only the ResultSet class you would also have to override
 115       * the Connection and PreparedStatement classes so that they would return the correct ResultSet
 116       * class.  In the future we may implement a more "packaged" approach to drivers; for now we
 117       * want to keep it simple.
 118       *
 119       * @param string $phptype   The phptype (mysql, mssql, etc.). This is first part of DSN URL (e.g. mysql://localhost/...).
 120       *                          You may also specify '*' to register a driver that will "wrap" the any native drivers.
 121       * @param string $dotpath   A dot-path locating your class.  For example 'creole.drivers.mssql.MSSQLConnection'
 122       *                          will be included like: include 'creole/drivers/mssql/MSSQLConnection.php' and the
 123       *                          classname will be assumed to be 'MSSQLConnection'.
 124       * @return void
 125       */
 126      public static function registerDriver($phptype, $dotpath)
 127      {
 128          self::$driverMap[$phptype] = $dotpath;
 129      }
 130  
 131      /**
 132       * Removes the driver for a PHP type.  Note that this will remove user-registered
 133       * drivers _and_ the default drivers.
 134       * @param string $phptype The PHP type for driver to de-register.
 135       * @see registerDriver()
 136       */
 137      public static function deregisterDriver($phptype)
 138      {
 139          unset(self::$driverMap[$phptype]);
 140      }
 141  
 142      /**
 143       * Returns the class path to the driver registered for specified type.
 144       * @param string $phptype The phptype handled by driver (e.g. 'mysql', 'mssql', '*').
 145       * @return string The driver class in dot-path notation (e.g. creole.drivers.mssql.MSSQLConnection)
 146       *                  or NULL if no registered driver found.
 147       */
 148      public static function getDriver($phptype)
 149      {
 150          if (isset(self::$driverMap[$phptype])) {
 151              return self::$driverMap[$phptype];
 152          } else {
 153              return null;
 154          }
 155      }
 156  
 157      /**
 158       * Create a new DB connection object and connect to the specified
 159       * database
 160       *
 161       * @param mixed $dsn "data source name", see the self::parseDSN
 162       * method for a description of the dsn format.  Can also be
 163       * specified as an array of the format returned by DB::parseDSN().
 164  
 165       * @param int $flags Connection flags (e.g. PERSISTENT).
 166       *
 167       * @return Connection Newly created DB connection object
 168       * @throws SQLException
 169       * @see self::parseDSN()
 170       */
 171      public static function getConnection($dsn, $flags = 0)
 172      {
 173          if (is_array($dsn)) {
 174              $dsninfo = $dsn;
 175          } else {
 176              $dsninfo = self::parseDSN($dsn);
 177          }
 178          
 179          // gather any flags from the DSN
 180          if ( isset ( $dsninfo['persistent'] ) && ! empty ( $dsninfo['persistent'] ) )
 181              $flags |= Creole::PERSISTENT;
 182          if ( isset ( $dsninfo['compat_assoc_lower'] ) && ! empty ( $dsninfo['compat_assoc_lower'] ) )
 183              $flags |= Creole::COMPAT_ASSOC_LOWER;
 184          if ( isset ( $dsninfo['compat_rtrim_string'] ) && ! empty ( $dsninfo['compat_rtrim_string'] ) )
 185              $flags |= Creole::COMPAT_RTRIM_STRING;
 186          if ( isset ( $dsninfo['compat_all'] ) && ! empty ( $dsninfo['compat_all'] ) )
 187              $flags |= Creole::COMPAT_ALL;
 188          
 189          if ($flags & Creole::NO_ASSOC_LOWER) {
 190              trigger_error("The Creole::NO_ASSOC_LOWER flag has been deprecated, and is now the default behavior. Use Creole::COMPAT_ASSOC_LOWER to lowercase resulset keys.", E_USER_WARNING);
 191          }
 192  
 193          // sort $dsninfo by keys so the serialized result is always the same
 194          // for identical connection parameters, no matter what their order is
 195          ksort($dsninfo);
 196          $connectionMapKey = crc32(serialize($dsninfo + array('compat_flags' => ($flags & Creole::COMPAT_ALL))));
 197  
 198          // see if we already have a connection with these parameters cached
 199          if(isset(self::$connectionMap[$connectionMapKey]))
 200          {
 201              // persistent connections will be used if a non-persistent one was requested and is available
 202              // but a persistent connection will be created if a non-persistent one is present
 203  
 204          // TODO: impliment auto close of non persistent and replacing the
 205          // non persistent with the persistent object so as we dont have
 206          // both links open for no reason
 207  
 208              if( isset(self::$connectionMap[$connectionMapKey][1]) ) { // is persistent
 209                  // a persistent connection with these parameters is already there,
 210                  // so we return it, no matter what was specified as persistent flag
 211                  $con = self::$connectionMap[$connectionMapKey][1];
 212              } else {
 213                  // we don't have a persistent connection, and since the persistent
 214                  // flag wasn't set either, we just return the non-persistent connection
 215                  $con = self::$connectionMap[$connectionMapKey][0];
 216              }
 217  
 218              // if we're here, a non-persistent connection was already there, but
 219              // the user wants a persistent one, so it will be created
 220              
 221              if ($con->isConnected())
 222                  return $con;            
 223          }
 224  
 225          // support "catchall" drivers which will themselves handle the details of connecting
 226          // using the proper RDBMS driver.
 227          if (isset(self::$driverMap['*'])) {
 228              $type = '*';
 229          } else {
 230              $type = $dsninfo['phptype'];
 231              if (!isset(self::$driverMap[$type])) {
 232                  throw new SQLException("No driver has been registered to handle connection type: $type");
 233              }
 234          }
 235  
 236          // may need to make this more complex if we add support
 237          // for 'dbsyntax'
 238          $clazz = self::import(self::$driverMap[$type]);
 239          $obj = new $clazz();
 240  
 241          if (!($obj instanceof Connection)) {
 242              throw new SQLException("Class does not implement creole.Connection interface: $clazz");
 243          }
 244  
 245          try {
 246              $obj->connect($dsninfo, $flags);
 247          } catch(SQLException $sqle) {
 248              $sqle->setUserInfo($dsninfo);
 249              throw $sqle;
 250          }
 251          $persistent = ($flags & Creole::PERSISTENT) === Creole::PERSISTENT;
 252          return self::$connectionMap[$connectionMapKey][(int)$persistent] = $obj;
 253      }
 254  
 255      /**
 256       * Parse a data source name.
 257       *
 258       * This isn't quite as powerful as DB::parseDSN(); it's also a lot simpler, a lot faster,
 259       * and many fewer lines of code.
 260       *
 261       * A array with the following keys will be returned:
 262       *  phptype: Database backend used in PHP (mysql, odbc etc.)
 263       *  protocol: Communication protocol to use (tcp, unix etc.)
 264       *  hostspec: Host specification (hostname[:port])
 265       *  database: Database to use on the DBMS server
 266       *  username: User name for login
 267       *  password: Password for login
 268       *
 269       * The format of the supplied DSN is in its fullest form:
 270       *
 271       *  phptype://username:password@protocol+hostspec/database
 272       *
 273       * Most variations are allowed:
 274       *
 275       *  phptype://username:password@protocol+hostspec:110//usr/db_file.db
 276       *  phptype://username:password@hostspec/database_name
 277       *  phptype://username:password@hostspec
 278       *  phptype://username@hostspec
 279       *  phptype://hostspec/database
 280       *  phptype://hostspec
 281       *  phptype
 282       *
 283       * @param string $dsn Data Source Name to be parsed
 284       * @return array An associative array
 285       */
 286      public static function parseDSN($dsn)
 287      {
 288          if (is_array($dsn)) {
 289              return $dsn;
 290          }
 291  
 292          $parsed = array(
 293              'phptype'  => null,
 294              'username' => null,
 295              'password' => null,
 296              'protocol' => null,
 297              'hostspec' => null,
 298              'port'     => null,
 299              'socket'   => null,
 300              'database' => null
 301          );
 302  
 303          $info = parse_url($dsn);
 304  
 305          if (count($info) === 1) { // if there's only one element in result, then it must be the phptype
 306              $parsed['phptype'] = array_pop($info);
 307              return $parsed;
 308          }
 309  
 310          // some values can be copied directly
 311          $parsed['phptype'] = @$info['scheme'];
 312          $parsed['username'] = @$info['user'];
 313          $parsed['password'] = @$info['pass'];
 314          $parsed['port'] = @$info['port'];
 315  
 316          $host = @$info['host'];
 317          if (false !== ($pluspos = strpos($host, '+'))) {
 318              $parsed['protocol'] = substr($host,0,$pluspos);
 319              if ($parsed['protocol'] === 'unix') {
 320                  $parsed['socket'] = substr($host,$pluspos+1);
 321              } else {
 322                  $parsed['hostspec'] = substr($host,$pluspos+1);
 323              }
 324          } else {
 325              $parsed['hostspec'] = $host;
 326          }
 327  
 328          if (isset($info['path'])) {
 329              $parsed['database'] = substr($info['path'], 1); // remove first char, which is '/'
 330          }
 331  
 332          if (isset($info['query'])) {
 333                  $opts = explode('&', $info['query']);
 334                  foreach ($opts as $opt) {
 335                      list($key, $value) = explode('=', $opt);
 336                      if (!isset($parsed[$key])) { // don't allow params overwrite
 337                          $parsed[$key] = urldecode($value);
 338                      }
 339                  }
 340          }
 341  
 342          return $parsed;
 343      }
 344  
 345      /**
 346       * Include once a file specified in DOT notation.
 347       * Package notation is expected to be relative to a location
 348       * on the PHP include_path.
 349       * @param string $class
 350       * @return string unqualified classname
 351       * @throws SQLException - if class does not exist and cannot load file
 352       *                      - if after loading file class still does not exist
 353       */
 354      public static function import($class) {
 355          $pos = strrpos($class, '.');
 356          // get just classname ('path.to.ClassName' -> 'ClassName')
 357          if ($pos !== false) {
 358              $classname = substr($class, $pos + 1);
 359          }
 360          else
 361          {
 362            $classname = $class;
 363          }
 364          if (!class_exists($classname, false)) {
 365              $path = strtr($class, '.', DIRECTORY_SEPARATOR) . '.php';
 366              $ret = include_once($path);
 367              if ($ret === false) {
 368                  throw new SQLException("Unable to load driver class: " . $class);
 369              }
 370              if (!class_exists($classname)) {
 371                  throw new SQLException("Unable to find loaded class: $classname (Hint: make sure classname matches filename)");
 372              }
 373          }
 374          return $classname;
 375      }
 376  
 377  }


Généré le : Fri Mar 16 22:42:14 2007 par Balluche grâce à PHPXref 0.7