Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5525d22a9b | ||
|
|
0a7b323e81 | ||
|
|
620c607f61 | ||
|
|
78c8192fdd | ||
|
|
d01a8be627 |
76
db.class.php
76
db.class.php
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user