From b1d7bbdbd467eae897a29635c5ae70e4425334b3 Mon Sep 17 00:00:00 2001
From: colshrapnel
Date: Wed, 12 Dec 2012 12:32:51 -0800
Subject: [PATCH] Create safemysql.class.php
---
safemysql.class.php | 365 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 365 insertions(+)
create mode 100644 safemysql.class.php
diff --git a/safemysql.class.php b/safemysql.class.php
new file mode 100644
index 0000000..89769a7
--- /dev/null
+++ b/safemysql.class.php
@@ -0,0 +1,365 @@
+ 'localhost',
+ 'user' => 'root',
+ 'pass' => '',
+ 'db' => 'test',
+ 'port' => NULL,
+ 'socket' => NULL,
+ 'pconnect' => FALSE,
+ 'charset' => 'utf8',
+ 'errmode' => 'error', //or exception
+ 'exception' => 'Exception', //Exception class name
+ );
+
+ const RESULT_ASSOC = MYSQLI_ASSOC;
+ const RESULT_NUM = MYSQLI_NUM;
+
+ function __construct($opt = array())
+ {
+ $opt = array_merge($this->defaults,$opt);
+
+ $this->emode = $opt['errmode'];
+ $this->exname = $opt['exception'];
+
+ if ($opt['pconnect'])
+ {
+ $opt['host'] = "p:".$opt['host'];
+ }
+
+ @$this->conn = mysqli_connect($opt['host'], $opt['user'], $opt['pass'], $opt['db'], $opt['port'], $opt['socket']);
+ if ( !$this->conn )
+ {
+ $this->error(mysqli_connect_errno()." ".mysqli_connect_error());
+ }
+
+ mysqli_set_charset($this->conn, $opt['charset']) or $this->error(mysqli_error($this->conn));
+ unset($opt); // I am paranoid
+ }
+
+ public function query()
+ {
+ $query = $this->prepareQuery(func_get_args());
+ $res = mysqli_query($this->conn, $query) or $this->error(mysqli_error($this->conn).". Full query: [$query]");
+ return $res;
+ }
+ public function fetch($result,$mode=self::RESULT_ASSOC)
+ {
+ return mysqli_fetch_array($result, $mode);
+ }
+
+ public function affected_rows()
+ {
+ return mysqli_affected_rows ($this->conn);
+ }
+
+ public function insert_id()
+ {
+ return mysqli_insert_id($this->conn);
+ }
+
+ public function num_rows($result)
+ {
+ return mysqli_num_rows($result);
+ }
+
+ public function free($result)
+ {
+ mysqli_free_result($result);
+ }
+
+ public function getOne()
+ {
+ $query = $this->prepareQuery(func_get_args());
+ if ( !preg_match('~LIMIT\s+\d+\s*(,\s*\d+\s*)?$~', $query) )
+ {
+ $query .= " LIMIT 1";
+ }
+ if ($res = $this->query($query))
+ {
+ $row = $this->fetch($res);
+ if (is_array($row)) {
+ return reset($row);
+ }
+ $this->free($res);
+ }
+ return FALSE;
+ }
+
+ public function getRow()
+ {
+ $query = $this->prepareQuery(func_get_args());
+ if ( !preg_match('~LIMIT\s+\d+\s*(,\s*\d+\s*)?$~',$query) )
+ {
+ $query.= " LIMIT 1";
+ }
+
+ if ($res = $this->query($query)) {
+ $ret = $this->fetch($res);
+ $this->free($res);
+ return $ret;
+ }
+ return FALSE;
+ }
+
+ public function getCol()
+ {
+ $ret = array();
+ $query = $this->prepareQuery(func_get_args());
+ if ( $res = $this->query($query) )
+ {
+ while($row = $this->fetch($res))
+ {
+ $ret[] = reset($row);
+ }
+ $this->free($res);
+ }
+ return $ret;
+ }
+
+ public function getAll()
+ {
+ $ret = array();
+ $query = $this->prepareQuery(func_get_args());
+ if ( $res = $this->query($query) )
+ {
+ while($row = $this->fetch($res))
+ {
+ $ret[] = $row;
+ }
+ $this->free($res);
+ }
+ return $ret;
+ }
+
+ public function getInd()
+ {
+ $args = func_get_args();
+ $index = array_shift($args);
+ $query = $this->prepareQuery($args);
+
+ $ret = array();
+ if ( $res = $this->query($query) )
+ {
+ while($row = $this->fetch($res))
+ {
+ $ret[$row[$index]] = $row;
+ }
+ $this->free($res);
+ }
+ return $ret;
+ }
+
+ public function getIndCol()
+ {
+ $args = func_get_args();
+ $index = array_shift($args);
+ $query = $this->prepareQuery($args);
+
+ $ret = array();
+ if ( $res = $this->query($query) )
+ {
+ while($row = $res->fetch($res))
+ {
+ $key = $row[$index];
+ unset($row[$index]);
+ $ret[$key] = reset($row);
+ }
+ $this->free($res);
+ }
+ return $ret;
+ }
+
+ public function parse()
+ {
+ return $this->prepareQuery(func_get_args());
+ }
+
+ public function whiteList($input,$allowed,$strict=FALSE)
+ {
+ $found = array_search($input);
+ if ($strict && ($found === FALSE))
+ {
+ return FALSE;
+ } else {
+ return $allowed[$found];
+ }
+ }
+
+ public function filterArray($input,$allowed)
+ {
+ foreach(array_keys($input) as $key )
+ {
+ if ( !in_array($key,$allowed) )
+ {
+ unset($input[$key]);
+ }
+ }
+ return $input;
+ }
+ private function prepareQuery($args)
+ {
+ $raw = $query = array_shift($args);
+ preg_match_all('~(\?[a-z?])~',$query,$m,PREG_OFFSET_CAPTURE);
+ $pholders = $m[1];
+ $count = 0;
+ foreach ($pholders as $i => $p)
+ {
+ if ($p[0] != '??')
+ {
+ $count++;
+ }
+ }
+ if ( $count != count($args) )
+ {
+ $this->error("Number of args (".count($args).") doesn't match number of placeholders ($count) in [$raw]");
+ }
+ $shift = 0;
+ $qmarks = 0;
+ foreach ($pholders as $i => $p)
+ {
+ $pholder = $p[0];
+ $offset = $p[1] + $shift;
+ if ($pholder != '??')
+ {
+ $value = $args[$i-$qmarks];
+ }
+ switch ($pholder)
+ {
+ case '?n':
+ $value = $this->escapeIdent($value);
+ break;
+ case '?s':
+ $value = $this->escapeString($value);
+ break;
+ case '?i':
+ $value = $this->escapeInt($value);
+ break;
+ case '?a':
+ $value = $this->createIN($value);
+ break;
+ case '?u':
+ $value = $this->createSET($value);
+ break;
+ case '??':
+ $value = '?';
+ $qmarks++;
+ break;
+ default:
+ $this->error("Unknown placeholder type ($pholder) in [$raw]");
+ }
+ $query = substr_replace($query,$value,$offset,2);
+ $shift+= strlen($value) - strlen($pholder);
+ }
+ $this->lastquery = $query;
+ return $query;
+ }
+
+ private function escapeInt($value)
+ {
+ if (is_float($value))
+ {
+ return number_format($value, 0, '.', ''); // may lose precision on big numbers
+ }
+ elseif(is_numeric($value))
+ {
+ return (string)$value;
+ }
+ else
+ {
+ $this->error("Invalid value for ?i (int) placeholder: [$value](".gettype($value).")");
+ }
+ }
+
+ private function escapeString($value)
+ {
+ return "'".mysqli_real_escape_string($this->conn,$value)."'";
+ }
+
+ private function escapeIdent($value)
+ {
+ if ($value)
+ {
+ return "`".str_replace("`","``",$value)."`";
+ } else {
+ $this->error("Empty value for ?n (identifier) placeholder.");
+ }
+ }
+
+ private function createIN($data)
+ {
+ if (!is_array($data))
+ {
+ $this->error("Value for ?a (IN) placeholder should be array.");
+ return;
+ }
+ if (!$data)
+ {
+ return 'NULL';
+ }
+ $query = $comma = '';
+ foreach ($data as $key => $value)
+ {
+ $query .= $comma.$this->escapeString($value);
+ $comma = ",";
+ }
+ return $query;
+ }
+
+ private function createSET($data)
+ {
+ if (!is_array($data))
+ {
+ $this->error("Value for ?u (SET) placeholder should be an array. ".gettype($data)." passed instead.");
+ return;
+ }
+ if (!$data)
+ {
+ $this->error("Empty array for ?u (SET) placeholder.");
+ return;
+ }
+ $query = $comma = '';
+ foreach ($data as $key => $value)
+ {
+ $query .= $comma.$this->escapeIdent($key).'='.$this->escapeString($value);
+ $comma = ",";
+ }
+ return $query;
+ }
+
+ private function error($err)
+ {
+ $err = __CLASS__.": ".$err;
+
+ if ( $this->emode == 'error' )
+ {
+ $err .= ". Error initiated in ".$this->caller().", thrown";
+ trigger_error($err,E_USER_ERROR);
+ } else {
+ throw new $this->exname($err);
+ }
+ }
+
+ private function caller()
+ {
+ $trace = debug_backtrace();
+ $caller = '';
+ foreach ($trace as $t)
+ {
+ if ( isset($t['class']) && $t['class'] == __CLASS__ )
+ {
+ $caller = $t['file']." on line ".$t['line'];
+ } else {
+ break;
+ }
+ }
+ return $caller;
+ }
+}