5 Commits
v1.0 ... v1.2

Author SHA1 Message Date
Sergey Tsalkov
5525d22a9b we can now throw an exception on errors if DB::$throw_exception_on_error is set 2011-03-04 17:23:42 -05:00
Sergey Tsalkov
0a7b323e81 you can now specify your own error handling function by changing DB::$error_handler 2011-03-04 16:49:17 -05:00
Sergey Tsalkov
620c607f61 remove array_map with inline functions for PHP 5.2 compatability
thanks to Adam for pointing this out!
2011-03-02 12:46:07 -05:00
Sergey Tsalkov
78c8192fdd increase "error output" level and fix various minor bugs
none of these seem to affect functionality, it's just a matter of clean code
thanks to ++ for pointing this out!
2011-03-01 00:12:31 -05:00
Sergey Tsalkov
d01a8be627 more basic tests 2011-03-01 00:12:25 -05:00
2 changed files with 114 additions and 13 deletions

View File

@@ -1,4 +1,4 @@
<? <?php
class DB class DB
{ {
public static $debug = false; public static $debug = false;
@@ -16,7 +16,9 @@ class DB
public static $password = ''; public static $password = '';
public static $host = 'localhost'; public static $host = 'localhost';
public static $encoding = 'latin1'; public static $encoding = 'latin1';
public static $queryMode = 'queryAllRows'; //buffered, unbuffered, queryAllRows public static $queryMode = 'queryAllRows';
public static $error_handler = 'meekrodb_error_handler';
public static $throw_exception_on_error = false;
public static function get($dbName = '') { public static function get($dbName = '') {
static $mysql = null; static $mysql = null;
@@ -68,7 +70,7 @@ class DB
} }
public static function escape($str) { public static function escape($str) {
$db = DB::get($dbName); $db = DB::get(DB::$dbName);
return $db->real_escape_string($str); return $db->real_escape_string($str);
} }
@@ -89,6 +91,20 @@ class DB
return call_user_func_array($function, $args); return call_user_func_array($function, $args);
} }
private static function wrapStr($strOrArray, $wrapChar, $escape = false) {
if (! is_array($strOrArray)) {
if ($escape) return $wrapChar . DB::escape($strOrArray) . $wrapChar;
else return $wrapChar . $strOrArray . $wrapChar;
} else {
$R = array();
foreach ($strOrArray as $element) {
$R[] = DB::wrapStr($element, $wrapChar, $escape);
}
return $R;
}
}
public static function freeResult($result) { public static function freeResult($result) {
if (! ($result instanceof MySQLi_Result)) return; if (! ($result instanceof MySQLi_Result)) return;
return $result->free(); return $result->free();
@@ -112,7 +128,7 @@ class DB
public static function insertOrReplace($which, $table, $data) { public static function insertOrReplace($which, $table, $data) {
$data = unserialize(serialize($data)); // break references within array $data = unserialize(serialize($data)); // break references within array
$keys_str = implode(', ', array_map(function($x) { return "`" . $x . "`"; }, array_keys($data))); $keys_str = implode(', ', DB::wrapStr(array_keys($data), '`'));
foreach ($data as &$datum) { foreach ($data as &$datum) {
if (is_array($datum)) $datum = serialize($datum); if (is_array($datum)) $datum = serialize($datum);
@@ -195,7 +211,7 @@ class DB
$lastPos = 0; $lastPos = 0;
while (($pos = strpos($sql, $type, $lastPos)) !== false) { while (($pos = strpos($sql, $type, $lastPos)) !== false) {
$lastPos = $pos + 1; $lastPos = $pos + 1;
if ($posList[$pos] && strlen($posList[$pos]) > strlen($type)) continue; if (isset($posList[$pos]) && strlen($posList[$pos]) > strlen($type)) continue;
$posList[$pos] = $type; $posList[$pos] = $type;
} }
} }
@@ -219,7 +235,7 @@ class DB
if (! is_array($arg)) die("Badly formatted SQL query: $sql -- expecting array, but didn't get one!"); if (! is_array($arg)) die("Badly formatted SQL query: $sql -- expecting array, but didn't get one!");
} }
if ($type == '%ls') $result = array_map(function($x) { return "'" . DB::escape($x) . "'"; }, $arg); if ($type == '%ls') $result = DB::wrapStr($arg, "'", true);
else if ($type == '%li') $result = array_map('intval', $arg); else if ($type == '%li') $result = array_map('intval', $arg);
else if ($type == '%ld') $result = array_map('floatval', $arg); else if ($type == '%ld') $result = array_map('floatval', $arg);
else if ($type == '%lb') $result = array_map('DB::formatTableName', $arg); else if ($type == '%lb') $result = array_map('DB::formatTableName', $arg);
@@ -276,14 +292,21 @@ class DB
$result = $db->query($sql, $is_buffered ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT); $result = $db->query($sql, $is_buffered ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT);
if (DB::$debug) $runtime = microtime(true) - $starttime; if (DB::$debug) $runtime = microtime(true) - $starttime;
$sqlShow = "$sql (" . ($is_buffered ? 'MYSQLI_STORE_RESULT' : 'MYSQLI_USE_RESULT') . ")";
if (!$sql || $error = DB::checkError()) { if (!$sql || $error = DB::checkError()) {
echo "ATTEMPTED QUERY: $sqlShow<br>\n"; if (function_exists(DB::$error_handler)) {
echo "ERROR: $error<br>\n"; call_user_func(DB::$error_handler, array(
debug_print_backtrace(); 'query' => $sql,
die; 'error' => $error
));
}
if (DB::$throw_exception_on_error) {
$e = new MeekroDBException($error, $sql);
throw $e;
}
} else if (DB::$debug) { } else if (DB::$debug) {
$runtime = sprintf('%f', $runtime * 1000); $runtime = sprintf('%f', $runtime * 1000);
$sqlShow = "$sql (" . ($is_buffered ? 'MYSQLI_STORE_RESULT' : 'MYSQLI_USE_RESULT') . ")";
echo "QUERY: $sqlShow [$runtime ms]<br>\n"; echo "QUERY: $sqlShow [$runtime ms]<br>\n";
} }
@@ -310,7 +333,7 @@ class DB
public static function queryAllRows() { public static function queryAllRows() {
$args = func_get_args(); $args = func_get_args();
$query = call_user_func_array('DB::queryUnbuf', &$args); $query = call_user_func_array('DB::queryUnbuf', $args);
$result = DB::fetchAllRows($query); $result = DB::fetchAllRows($query);
DB::freeResult($query); DB::freeResult($query);
DB::$num_rows = count($result); DB::$num_rows = count($result);
@@ -356,7 +379,7 @@ class DB
$row = call_user_func_array('DB::queryOneRow', $args); $row = call_user_func_array('DB::queryOneRow', $args);
if ($row == null) { if ($row == null) {
return null; return null;
} else if ($field === null) { } else if ($column === null) {
$keys = array_keys($row); $keys = array_keys($row);
$column = $keys[0]; $column = $keys[0];
} }
@@ -468,4 +491,31 @@ class DBTransaction {
} }
class MeekroDBException extends Exception {
protected $query = '';
function __construct($message='', $query='') {
parent::__construct($message);
$this->query = $query;
}
public function getQuery() { return $this->query; }
}
function meekrodb_error_handler($params) {
$out[] = "QUERY: " . $params['query'];
$out[] = "ERROR: " . $params['error'];
$out[] = "";
if (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR'])) {
echo implode("\n", $out);
} else {
echo implode("<br>\n", $out);
}
debug_print_backtrace();
die;
}
?> ?>

View File

@@ -1,6 +1,14 @@
<? <?
function new_error_callback($params) {
global $error_callback_worked;
if (substr_count($params['error'], 'You have an error in your SQL syntax')) $error_callback_worked = 1;
}
class BasicTest extends SimpleTest { class BasicTest extends SimpleTest {
function __construct() { function __construct() {
error_reporting(E_ALL);
require_once '../db.class.php'; require_once '../db.class.php';
DB::$user = 'libdb_user'; DB::$user = 'libdb_user';
DB::$password = 'sdf235sklj'; DB::$password = 'sdf235sklj';
@@ -68,6 +76,8 @@ class BasicTest extends SimpleTest {
'height' => 155.23 'height' => 155.23
)); ));
$this->assert(DB::insertId() === 3);
$counter = DB::queryFirstField("SELECT COUNT(*) FROM accounts"); $counter = DB::queryFirstField("SELECT COUNT(*) FROM accounts");
$this->assert($counter === strval(3)); $this->assert($counter === strval(3));
@@ -78,6 +88,10 @@ class BasicTest extends SimpleTest {
$charlie_password = DB::queryFirstField("SELECT password FROM accounts WHERE username IN %ls AND username = %s", $charlie_password = DB::queryFirstField("SELECT password FROM accounts WHERE username IN %ls AND username = %s",
array('Charlie', 'Charlie\'s Friend'), 'Charlie\'s Friend'); array('Charlie', 'Charlie\'s Friend'), 'Charlie\'s Friend');
$this->assert($charlie_password === 'goodbye'); $this->assert($charlie_password === 'goodbye');
$charlie_password = DB::queryOneField('password', "SELECT * FROM accounts WHERE username IN %ls AND username = %s",
array('Charlie', 'Charlie\'s Friend'), 'Charlie\'s Friend');
$this->assert($charlie_password === 'goodbye');
} }
function test_4_query() { function test_4_query() {
@@ -89,6 +103,43 @@ class BasicTest extends SimpleTest {
$this->assert(count($results) === 2); $this->assert(count($results) === 2);
} }
function test_5_error_handler() {
global $error_callback_worked;
DB::$error_handler = 'new_error_callback';
DB::query("SELET * FROM accounts");
$this->assert($error_callback_worked === 1);
}
function test_6_exception_catch() {
DB::$error_handler = '';
DB::$throw_exception_on_error = true;
try {
DB::query("SELET * FROM accounts");
} catch(MeekroDBException $e) {
$this->assert(substr_count($e->getMessage(), 'You have an error in your SQL syntax'));
$this->assert($e->getQuery() === 'SELET * FROM accounts');
$exception_was_caught = 1;
}
$this->assert($exception_was_caught === 1);
try {
DB::insert('`libdb_test`.`accounts`', array(
'id' => 2,
'username' => 'Another Dude\'s \'Mom"',
'password' => 'asdfsdse',
'age' => 35,
'height' => 555.23
));
} catch(MeekroDBException $e) {
$this->assert(substr_count($e->getMessage(), 'Duplicate entry'));
$exception_was_caught = 2;
}
$this->assert($exception_was_caught === 2);
}
} }