summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornmcgann <neil@neilmcgann.co.uk>2015-11-23 21:57:01 +0000
committernmcgann <neil@neilmcgann.co.uk>2015-11-23 21:57:01 +0000
commitc9fc85848b4dc7bd6ff0d1e9ab674b486fe6461a (patch)
tree11020f1e9d51082d65f54085b14744d6d55c4cab
download128f4da51eeb83868638-origin/master.zip
128f4da51eeb83868638-origin/master.tar.gz
128f4da51eeb83868638-origin/master.tar.bz2
-rw-r--r--Dbpdo.php261
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