File indexing completed on 2025-03-02 05:29:17
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Db 0017 * @subpackage Adapter 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 0024 /** 0025 * @see Zend_Db_Adapter_Abstract 0026 */ 0027 // require_once 'Zend/Db/Adapter/Abstract.php'; 0028 0029 0030 /** 0031 * @see Zend_Db_Statement_Pdo 0032 */ 0033 // require_once 'Zend/Db/Statement/Pdo.php'; 0034 0035 0036 /** 0037 * Class for connecting to SQL databases and performing common operations using PDO. 0038 * 0039 * @category Zend 0040 * @package Zend_Db 0041 * @subpackage Adapter 0042 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0043 * @license http://framework.zend.com/license/new-bsd New BSD License 0044 */ 0045 abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract 0046 { 0047 0048 /** 0049 * Default class name for a DB statement. 0050 * 0051 * @var string 0052 */ 0053 protected $_defaultStmtClass = 'Zend_Db_Statement_Pdo'; 0054 0055 /** 0056 * Creates a PDO DSN for the adapter from $this->_config settings. 0057 * 0058 * @return string 0059 */ 0060 protected function _dsn() 0061 { 0062 // baseline of DSN parts 0063 $dsn = $this->_config; 0064 0065 // don't pass the username, password, charset, persistent and driver_options in the DSN 0066 unset($dsn['username']); 0067 unset($dsn['password']); 0068 unset($dsn['options']); 0069 unset($dsn['charset']); 0070 unset($dsn['persistent']); 0071 unset($dsn['driver_options']); 0072 0073 // use all remaining parts in the DSN 0074 foreach ($dsn as $key => $val) { 0075 $dsn[$key] = "$key=$val"; 0076 } 0077 0078 return $this->_pdoType . ':' . implode(';', $dsn); 0079 } 0080 0081 /** 0082 * Creates a PDO object and connects to the database. 0083 * 0084 * @return void 0085 * @throws Zend_Db_Adapter_Exception 0086 */ 0087 protected function _connect() 0088 { 0089 // if we already have a PDO object, no need to re-connect. 0090 if ($this->_connection) { 0091 return; 0092 } 0093 0094 // get the dsn first, because some adapters alter the $_pdoType 0095 $dsn = $this->_dsn(); 0096 0097 // check for PDO extension 0098 if (!extension_loaded('pdo')) { 0099 /** 0100 * @see Zend_Db_Adapter_Exception 0101 */ 0102 // require_once 'Zend/Db/Adapter/Exception.php'; 0103 throw new Zend_Db_Adapter_Exception('The PDO extension is required for this adapter but the extension is not loaded'); 0104 } 0105 0106 // check the PDO driver is available 0107 if (!in_array($this->_pdoType, PDO::getAvailableDrivers())) { 0108 /** 0109 * @see Zend_Db_Adapter_Exception 0110 */ 0111 // require_once 'Zend/Db/Adapter/Exception.php'; 0112 throw new Zend_Db_Adapter_Exception('The ' . $this->_pdoType . ' driver is not currently installed'); 0113 } 0114 0115 // create PDO connection 0116 $q = $this->_profiler->queryStart('connect', Zend_Db_Profiler::CONNECT); 0117 0118 // add the persistence flag if we find it in our config array 0119 if (isset($this->_config['persistent']) && ($this->_config['persistent'] == true)) { 0120 $this->_config['driver_options'][PDO::ATTR_PERSISTENT] = true; 0121 } 0122 0123 try { 0124 $this->_connection = new PDO( 0125 $dsn, 0126 $this->_config['username'], 0127 $this->_config['password'], 0128 $this->_config['driver_options'] 0129 ); 0130 0131 $this->_profiler->queryEnd($q); 0132 0133 // set the PDO connection to perform case-folding on array keys, or not 0134 $this->_connection->setAttribute(PDO::ATTR_CASE, $this->_caseFolding); 0135 0136 // always use exceptions. 0137 $this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 0138 0139 } catch (PDOException $e) { 0140 /** 0141 * @see Zend_Db_Adapter_Exception 0142 */ 0143 // require_once 'Zend/Db/Adapter/Exception.php'; 0144 throw new Zend_Db_Adapter_Exception($e->getMessage(), $e->getCode(), $e); 0145 } 0146 0147 } 0148 0149 /** 0150 * Test if a connection is active 0151 * 0152 * @return boolean 0153 */ 0154 public function isConnected() 0155 { 0156 return ((bool) ($this->_connection instanceof PDO)); 0157 } 0158 0159 /** 0160 * Force the connection to close. 0161 * 0162 * @return void 0163 */ 0164 public function closeConnection() 0165 { 0166 $this->_connection = null; 0167 } 0168 0169 /** 0170 * Prepares an SQL statement. 0171 * 0172 * @param string $sql The SQL statement with placeholders. 0173 * @param array $bind An array of data to bind to the placeholders. 0174 * @return PDOStatement 0175 */ 0176 public function prepare($sql) 0177 { 0178 $this->_connect(); 0179 $stmtClass = $this->_defaultStmtClass; 0180 if (!class_exists($stmtClass)) { 0181 // require_once 'Zend/Loader.php'; 0182 Zend_Loader::loadClass($stmtClass); 0183 } 0184 $stmt = new $stmtClass($this, $sql); 0185 $stmt->setFetchMode($this->_fetchMode); 0186 return $stmt; 0187 } 0188 0189 /** 0190 * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. 0191 * 0192 * As a convention, on RDBMS brands that support sequences 0193 * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence 0194 * from the arguments and returns the last id generated by that sequence. 0195 * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method 0196 * returns the last value generated for such a column, and the table name 0197 * argument is disregarded. 0198 * 0199 * On RDBMS brands that don't support sequences, $tableName and $primaryKey 0200 * are ignored. 0201 * 0202 * @param string $tableName OPTIONAL Name of table. 0203 * @param string $primaryKey OPTIONAL Name of primary key column. 0204 * @return string 0205 */ 0206 public function lastInsertId($tableName = null, $primaryKey = null) 0207 { 0208 $this->_connect(); 0209 return $this->_connection->lastInsertId(); 0210 } 0211 0212 /** 0213 * Special handling for PDO query(). 0214 * All bind parameter names must begin with ':' 0215 * 0216 * @param string|Zend_Db_Select $sql The SQL statement with placeholders. 0217 * @param array $bind An array of data to bind to the placeholders. 0218 * @return Zend_Db_Statement_Pdo 0219 * @throws Zend_Db_Adapter_Exception To re-throw PDOException. 0220 */ 0221 public function query($sql, $bind = array()) 0222 { 0223 if (empty($bind) && $sql instanceof Zend_Db_Select) { 0224 $bind = $sql->getBind(); 0225 } 0226 0227 if (is_array($bind)) { 0228 foreach ($bind as $name => $value) { 0229 if (!is_int($name) && !preg_match('/^:/', $name)) { 0230 $newName = ":$name"; 0231 unset($bind[$name]); 0232 $bind[$newName] = $value; 0233 } 0234 } 0235 } 0236 0237 try { 0238 return parent::query($sql, $bind); 0239 } catch (PDOException $e) { 0240 /** 0241 * @see Zend_Db_Statement_Exception 0242 */ 0243 // require_once 'Zend/Db/Statement/Exception.php'; 0244 throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); 0245 } 0246 } 0247 0248 /** 0249 * Executes an SQL statement and return the number of affected rows 0250 * 0251 * @param mixed $sql The SQL statement with placeholders. 0252 * May be a string or Zend_Db_Select. 0253 * @return integer Number of rows that were modified 0254 * or deleted by the SQL statement 0255 */ 0256 public function exec($sql) 0257 { 0258 if ($sql instanceof Zend_Db_Select) { 0259 $sql = $sql->assemble(); 0260 } 0261 0262 try { 0263 $affected = $this->getConnection()->exec($sql); 0264 0265 if ($affected === false) { 0266 $errorInfo = $this->getConnection()->errorInfo(); 0267 /** 0268 * @see Zend_Db_Adapter_Exception 0269 */ 0270 // require_once 'Zend/Db/Adapter/Exception.php'; 0271 throw new Zend_Db_Adapter_Exception($errorInfo[2]); 0272 } 0273 0274 return $affected; 0275 } catch (PDOException $e) { 0276 /** 0277 * @see Zend_Db_Adapter_Exception 0278 */ 0279 // require_once 'Zend/Db/Adapter/Exception.php'; 0280 throw new Zend_Db_Adapter_Exception($e->getMessage(), $e->getCode(), $e); 0281 } 0282 } 0283 0284 /** 0285 * Quote a raw string. 0286 * 0287 * @param string $value Raw string 0288 * @return string Quoted string 0289 */ 0290 protected function _quote($value) 0291 { 0292 if (is_int($value) || is_float($value)) { 0293 return $value; 0294 } 0295 $this->_connect(); 0296 return $this->_connection->quote($value); 0297 } 0298 0299 /** 0300 * Begin a transaction. 0301 */ 0302 protected function _beginTransaction() 0303 { 0304 $this->_connect(); 0305 $this->_connection->beginTransaction(); 0306 } 0307 0308 /** 0309 * Commit a transaction. 0310 */ 0311 protected function _commit() 0312 { 0313 $this->_connect(); 0314 $this->_connection->commit(); 0315 } 0316 0317 /** 0318 * Roll-back a transaction. 0319 */ 0320 protected function _rollBack() { 0321 $this->_connect(); 0322 $this->_connection->rollBack(); 0323 } 0324 0325 /** 0326 * Set the PDO fetch mode. 0327 * 0328 * @todo Support FETCH_CLASS and FETCH_INTO. 0329 * 0330 * @param int $mode A PDO fetch mode. 0331 * @return void 0332 * @throws Zend_Db_Adapter_Exception 0333 */ 0334 public function setFetchMode($mode) 0335 { 0336 //check for PDO extension 0337 if (!extension_loaded('pdo')) { 0338 /** 0339 * @see Zend_Db_Adapter_Exception 0340 */ 0341 // require_once 'Zend/Db/Adapter/Exception.php'; 0342 throw new Zend_Db_Adapter_Exception('The PDO extension is required for this adapter but the extension is not loaded'); 0343 } 0344 switch ($mode) { 0345 case PDO::FETCH_LAZY: 0346 case PDO::FETCH_ASSOC: 0347 case PDO::FETCH_NUM: 0348 case PDO::FETCH_BOTH: 0349 case PDO::FETCH_NAMED: 0350 case PDO::FETCH_OBJ: 0351 $this->_fetchMode = $mode; 0352 break; 0353 default: 0354 /** 0355 * @see Zend_Db_Adapter_Exception 0356 */ 0357 // require_once 'Zend/Db/Adapter/Exception.php'; 0358 throw new Zend_Db_Adapter_Exception("Invalid fetch mode '$mode' specified"); 0359 break; 0360 } 0361 } 0362 0363 /** 0364 * Check if the adapter supports real SQL parameters. 0365 * 0366 * @param string $type 'positional' or 'named' 0367 * @return bool 0368 */ 0369 public function supportsParameters($type) 0370 { 0371 switch ($type) { 0372 case 'positional': 0373 case 'named': 0374 default: 0375 return true; 0376 } 0377 } 0378 0379 /** 0380 * Retrieve server version in PHP style 0381 * 0382 * @return string 0383 */ 0384 public function getServerVersion() 0385 { 0386 $this->_connect(); 0387 try { 0388 $version = $this->_connection->getAttribute(PDO::ATTR_SERVER_VERSION); 0389 } catch (PDOException $e) { 0390 // In case of the driver doesn't support getting attributes 0391 return null; 0392 } 0393 $matches = null; 0394 if (preg_match('/((?:[0-9]{1,2}\.){1,3}[0-9]{1,2})/', $version, $matches)) { 0395 return $matches[1]; 0396 } else { 0397 return null; 0398 } 0399 } 0400 }