diff --git a/base.php b/base.php
index 301f369..9f81d6b 100644
--- a/base.php
+++ b/base.php
@@ -102,6 +102,51 @@ if(!empty($cphp_config->autoloader))
spl_autoload_register('cphp_autoload_class');
}
+/* https://stackoverflow.com/a/1159235/1332715 */
+set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext) {
+ if(!(error_reporting() & $errno))
+ return;
+ switch($errno) {
+ case E_WARNING :
+ case E_USER_WARNING :
+ case E_STRICT :
+ case E_NOTICE :
+ case E_USER_NOTICE :
+ $type = 'warning';
+ $fatal = false;
+ break;
+ default :
+ $type = 'fatal error';
+ $fatal = true;
+ break;
+ }
+ $trace = array_reverse(debug_backtrace());
+ array_pop($trace);
+ if(php_sapi_name() == 'cli') {
+ echo 'Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ':' . "\n";
+ foreach($trace as $item)
+ echo ' ' . (isset($item['file']) ? $item['file'] : '') . ' ' . (isset($item['line']) ? $item['line'] : '') . ' calling ' . $item['function'] . '()' . "\n";
+ } else {
+ echo '' . "\n";
+ echo ' Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ':' . "\n";
+ echo '
' . "\n";
+ foreach($trace as $item)
+ echo ' - ' . (isset($item['file']) ? $item['file'] : '') . ' ' . (isset($item['line']) ? $item['line'] : '') . ' calling ' . $item['function'] . '()
' . "\n";
+ echo '
' . "\n";
+ echo '
' . "\n";
+ }
+ if(ini_get('log_errors')) {
+ $items = array();
+ foreach($trace as $item)
+ $items[] = (isset($item['file']) ? $item['file'] : '') . ' ' . (isset($item['line']) ? $item['line'] : '') . ' calling ' . $item['function'] . '()';
+ $message = 'Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ': ' . join(' | ', $items);
+ error_log($message);
+ }
+ if($fatal)
+ exit(1);
+});
+
+
set_exception_handler(function($e){
/* Intentionally not using the templater here; any inner exceptions
* cause serious debugging issues. Avoiding potential issues by just
diff --git a/include.exceptions.php b/include.exceptions.php
index 3e22d97..a3b6f6a 100644
--- a/include.exceptions.php
+++ b/include.exceptions.php
@@ -29,6 +29,8 @@ class PrototypeException extends BaseException {}
class ConstructorException extends BaseException {}
class MissingDataException extends BaseException {}
class DatabaseException extends BaseException {}
+class DatabaseDuplicateException extends DatabaseException {}
+class DatabaseConstraintException extends DatabaseException {}
class TypeException extends BaseException {}
class DeprecatedException extends BaseException {}
diff --git a/include.misc.php b/include.misc.php
index fccc655..95803a8 100644
--- a/include.misc.php
+++ b/include.misc.php
@@ -371,6 +371,11 @@ function generate_pagination($min, $max, $current, $around, $start, $end)
}
}
+function starts_with($haystack, $needle)
+{
+ return (substr($haystack, 0, strlen($needle)) == $needle);
+}
+
function ends_with($haystack, $needle)
{
return (substr($haystack, -strlen($needle)) == $needle);
diff --git a/include.mysql.php b/include.mysql.php
index e71fe4b..f2d7f34 100644
--- a/include.mysql.php
+++ b/include.mysql.php
@@ -25,7 +25,7 @@ class CachedPDO extends PDO
$query_hash = md5($query);
$parameter_hash = md5(serialize($parameters));
$cache_hash = $query_hash . $parameter_hash;
-
+
$return_object = new stdClass;
if($expiry != 0 && $result = mc_get($cache_hash))
@@ -73,7 +73,7 @@ class CachedPDO extends PDO
if($result = $statement->fetchAll(PDO::FETCH_ASSOC))
{
if(count($result) > 0)
- {
+ {
if($expiry != 0)
{
mc_set($cache_hash, $result, $expiry);
@@ -89,16 +89,41 @@ class CachedPDO extends PDO
}
else
{
- /* There were zero results. Return null instead of an object without results, to allow for statements
- * of the form if($result = $database->CachedQuery()) . */
- return null;
+ $last_id = $this->lastInsertId();
+
+ if($last_id == "0" || !starts_with(strtoupper($query), "INSERT"))
+ {
+ /* There were zero results. Return null instead of an object without results, to allow for statements
+ * of the form if($result = $database->CachedQuery()) . */
+ return null;
+ }
+ else
+ {
+ /* This was an INSERT query. Return the primary ID of the created row. */
+ return $last_id;
+ }
}
}
else
{
/* The query failed. */
$err = $statement->errorInfo();
- throw new DatabaseException("The query failed: {$err[2]}", 0, null, array('query' => $query, 'parameters' => $parameters));
+
+ if($err[0] == "23000")
+ {
+ if(starts_with($err[2], "Duplicate entry")) /* There does not seem to be a better way of doing this. */
+ {
+ throw new DatabaseDuplicateException("The query failed because one of the keys was not unique: {$err[2]}", 0, null, array('query' => $query, 'parameters' => $parameters));
+ }
+ else
+ {
+ throw new DatabaseConstraintException("The query violates a database constraint: {$err[2]}", 0, null, array('query' => $query, 'parameters' => $parameters));
+ }
+ }
+ else
+ {
+ throw new DatabaseException("The query failed: {$err[2]}", 0, null, array('query' => $query, 'parameters' => $parameters));
+ }
}
}