diff options
author | nmcgann <neil@neilmcgann.co.uk> | 2015-11-23 21:57:01 +0000 |
---|---|---|
committer | nmcgann <neil@neilmcgann.co.uk> | 2015-11-23 21:57:01 +0000 |
commit | c9fc85848b4dc7bd6ff0d1e9ab674b486fe6461a (patch) | |
tree | 11020f1e9d51082d65f54085b14744d6d55c4cab | |
download | 128f4da51eeb83868638-origin/master.zip 128f4da51eeb83868638-origin/master.tar.gz 128f4da51eeb83868638-origin/master.tar.bz2 |
-rw-r--r-- | Dbpdo.php | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/Dbpdo.php b/Dbpdo.php new file mode 100644 index 0000000..caabf7a --- /dev/null +++ b/Dbpdo.php @@ -0,0 +1,261 @@ +<?php +/** + * dbpdo.php + * + * Wrapper class for PDO to handle connecting to different types of db (mssql and mysql). + * Also handles mssql on both windows and linux platforms by using sqlsrv and dblib pdo drivers. + * Adds a logging and timing facility for queries and prepared statements. + * A logging function can be passed to the constructor to capture all calls to the PDO routines. + * + * All normal PDO and PDOStatement functions can be used with no alterations. + * + * Constructor parameters: + * $params['db_type'] - currently 'mssql' or 'mysql' + * $params['db_host'] + * $params['db_port'] - (optional) + * $params['db_name'] - (optional) + * $params['db_username'] + * $params['db_password'] + * $params['commands'] - (optional) array of command strings to be run after connection made. + * + * After connection made isConnectionError() should be called to check if successful and then + * getConnectionError() gets the error message. All other errors raise an exception. + * + * The db logging routine passed should be able to accept a variable number of + * parameters to log each of which can be either scalar or arrays. + * + */ + +class Dbpdo { + + protected $db = null; + protected $dbError = ''; + protected $dbLogHook = null; + + // --------------------------------------------------------------------- // + + public function __construct($params, $dbLogHook = null) { + $this->dbLogHook = $dbLogHook; + + $this->openConnection($params); + } + + // --------------------------------------------------------------------- // + + protected function openConnection($params) { + $commands = array(); //special setup commands + + //handle missing params (e.g. future proofing if sqlite used) + $dbtype = isset($params['db_type']) ? $params['db_type'] : 'mysql'; + $host = isset($params['db_host']) ? $params['db_host'] : ''; + $port = isset($params['db_port']) ? $params['db_port'] : ''; + $dbname = isset($params['db_name']) ? $params['db_name'] : ''; + $username = isset($params['db_username']) ? $params['db_username'] : ''; + $password = isset($params['db_password']) ? $params['db_password'] : ''; + //add any extra init commands + $commands = isset($params['commands']) ? array_merge($commands, $params['commands']) : $commands; + + if($dbtype == 'mssql') { + $port = ($port != '') ? $port : 1433; //default port if not set + + //windows servers have different drivers & dsn strings (Mac shows darwin, so can't just look for "win") + if(strncasecmp(PHP_OS, 'WIN', 3) == 0) { + $dsn = "sqlsrv:server=$host,$port". (($dbname != "") ? ";database=$dbname" : ""); + } else { + //linux etc. + $dsn = "dblib:host=$host:$port".(($dbname != "") ? ";dbname=$dbname" : ""); + } + $commands[] = "SET QUOTED_IDENTIFIER ON"; //should be unnecessary, but safest to be explicit + } else { + //assumed mysql + $port = ($port != '') ? $port : 3306; + $charset = isset($params['db_charset']) ? ';charset=' . $params['db_charset'] : ';charset=utf8'; + + $dsn = "mysql:host=$host;port=$port". (($dbname != "") ? ";dbname=$dbname" : "") . $charset; + } + + //open up (suppressing separate messages) + try { + $this->db = @new PDO($dsn, $username, $password); + $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + if($dbtype != 'mssql') { + $this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + } + //run any special set up commands + foreach($commands as $c) { + $this->db->exec($c); + } + + } catch(PDOException $e) { + $this->dbError = $e->getMessage(); + $this->db = null; + + //call logging hook if present + if(is_callable($this->dbLogHook)) { + $fn = $this->dbLogHook; + $fn('Error connecting to database', $this->dbError); + } + //exit($this->dbError); + } + + } + + // --------------------------------------------------------------------- // + + public function isConnectionError () { + return is_null($this->db); + } + + // --------------------------------------------------------------------- // + + public function getConnectionError () { + return $this->dbError; + } + + // --------------------------------------------------------------------- // + + public function query(){ + $args = func_get_args(); + + $start = microtime(true); + $result = call_user_func_array(array($this->db, 'query'), $args); + $time = microtime(true) - $start; + + //call logging hook if present + if(is_callable($this->dbLogHook)) { + $fn = $this->dbLogHook; + $fn('PDO->query took ' . round($time * 1000, 3) . 'ms ', $args); + } + + return $result; + } + + // --------------------------------------------------------------------- // + + public function exec($statement){ + + $start = microtime(true); + $result = $this->db->exec($statement); + $time = microtime(true) - $start; + + //call logging hook if present + if(is_callable($this->dbLogHook)) { + $fn = $this->dbLogHook; + $fn('PDO->exec took ' . round($time * 1000, 3) . 'ms ', $statement); + } + + return $result; + } + + // --------------------------------------------------------------------- // + + //call standard PDO methods + public function __call($name, $args) { + //call logging hook if present + if(is_callable($this->dbLogHook)) { + $fn = $this->dbLogHook; + $fn($name, $args); + } + + $result = call_user_func_array(array($this->db, $name), $args); + //substitute logged PDOStatement if a logger is present + if(is_object($result) && get_class($result) === 'PDOStatement' && is_callable($this->dbLogHook)) { + return new LoggedPDOStatement($result, $this->dbLogHook); + } + + return $result; + + } + +} //eoc + +/** + * LoggedPDOStatement is returned instead of PDOStatement when logging is active. + * This allows the prepared statement execution time to be logged. + * + */ + +class LoggedPDOStatement { + private $statement; + private $dbLogHook = null; + + // --------------------------------------------------------------------- // + + public function __construct(PDOStatement $statement, $dbLogHook = null) { + $this->statement = $statement; + $this->dbLogHook = $dbLogHook; + } + + // --------------------------------------------------------------------- // + + public function execute($args = null) { + + $start = microtime(true); + $result = $this->statement->execute($args); + $time = microtime(true) - $start; + + //call logging hook if present + if(is_callable($this->dbLogHook)) { + $fn = $this->dbLogHook; + $fn('PDOStatement->execute took ' . round($time * 1000, 3) . 'ms ', is_null($args) ? '(no parameters)' : $args); + } + + return $result; + } + + // --------------------------------------------------------------------- // + + //functions with pass-by-reference parameter(s) need special treatment + public function bindColumn($column, &$param, $type = null, $maxlen = null, $driverdata = null) { + + //call logging hook if present + if(is_callable($this->dbLogHook)) { + $fn = $this->dbLogHook; + $fn('PDOStatement->bindColumn', $column, $param, $type, $maxlen, $driverdata); + } + + return $this->statement->bindColumn($column, $param, $type, $maxlen, $driverdata); + } + + // --------------------------------------------------------------------- // + + public function bindParam($parameter, &$variable, $data_type = PDO::PARAM_STR, $length = null, $driver_options = null) { + + //call logging hook if present + if(is_callable($this->dbLogHook)) { + $fn = $this->dbLogHook; + $fn('PDOStatement->bindParam', $parameter, $variable, $data_type, $length, $driver_options); + } + + return $this->statement->bindParam($parameter, $variable, $data_type, $length, $driver_options); + } + + // --------------------------------------------------------------------- // + + public function bindValue($parameter, $value, $data_type = PDO::PARAM_STR) { + + //call logging hook if present + if(is_callable($this->dbLogHook)) { + $fn = $this->dbLogHook; + $fn('PDOStatement->bindValue', $parameter, $value, $data_type); + } + + return $this->statement->bindValue($parameter, $value, $data_type); + } + + // --------------------------------------------------------------------- // + + //all other functions go direct to PDOStatement object + public function __call($name, $param) { + + //call logging hook if present + if(is_callable($this->dbLogHook)) { + $fn = $this->dbLogHook; + $fn($name, $param); + } + + return call_user_func_array(array($this->statement, $name), $param); + } +} //eoc + +/* end */
\ No newline at end of file |