}
namespace wcf\functions\exception {
+ use wcf\system\exception\IExtraInformationException;
use wcf\system\exception\SystemException;
use wcf\system\WCF;
use wcf\util\FileUtil;
</div>
<?php if (WCF::debugModeIsEnabled()) { ?>
<div>
- <h2>System Information:</h2>
+ <h2>System Information</h2>
<dl>
- <dt>PHP Version:</dt> <dd><?php echo StringUtil::encodeHTML(phpversion()); ?></dd>
- <dt>WCF Version:</dt> <dd><?php echo StringUtil::encodeHTML(WCF_VERSION); ?></dd>
- <dt>Date:</dt> <dd><?php echo gmdate('r'); ?></dd>
- <dt>Request URI:</dt> <dd><?php if (isset($_SERVER['REQUEST_URI'])) echo StringUtil::encodeHTML($_SERVER['REQUEST_URI']); ?></dd>
- <dt>Referrer:</dt> <dd><?php if (isset($_SERVER['HTTP_REFERER'])) echo StringUtil::encodeHTML($_SERVER['HTTP_REFERER']); ?></dd>
- <dt>User Agent:</dt> <dd><?php if (isset($_SERVER['HTTP_USER_AGENT'])) echo StringUtil::encodeHTML($_SERVER['HTTP_USER_AGENT']); ?></dd>
- <dt>Peak Memory Usage:</dt> <dd><?php echo $peakMemory = memory_get_peak_usage(); ?>/<?php echo $memoryLimit = FileUtil::getMemoryLimit(); ?> Byte (<?php echo round($peakMemory / 1024 / 1024, 3); ?>/<?php echo round($memoryLimit / 1024 / 1024, 3); ?> MiB)</dd>
+ <dt>PHP Version</dt> <dd><?php echo StringUtil::encodeHTML(phpversion()); ?></dd>
+ <dt>WCF Version</dt> <dd><?php echo StringUtil::encodeHTML(WCF_VERSION); ?></dd>
+ <dt>Date</dt> <dd><?php echo gmdate('r'); ?></dd>
+ <dt>Request URI</dt> <dd><?php if (isset($_SERVER['REQUEST_URI'])) echo StringUtil::encodeHTML($_SERVER['REQUEST_URI']); ?></dd>
+ <dt>Referrer</dt> <dd><?php if (isset($_SERVER['HTTP_REFERER'])) echo StringUtil::encodeHTML($_SERVER['HTTP_REFERER']); ?></dd>
+ <dt>User Agent</dt> <dd><?php if (isset($_SERVER['HTTP_USER_AGENT'])) echo StringUtil::encodeHTML($_SERVER['HTTP_USER_AGENT']); ?></dd>
+ <dt>Peak Memory Usage</dt> <dd><?php echo $peakMemory = memory_get_peak_usage(); ?>/<?php echo $memoryLimit = FileUtil::getMemoryLimit(); ?> Byte (<?php echo round($peakMemory / 1024 / 1024, 3); ?>/<?php echo round($memoryLimit / 1024 / 1024, 3); ?> MiB)</dd>
</dl>
</div>
<?php
do {
?>
<div>
- <h2><?php if (!$e->getPrevious() && !$first) { echo "Original "; } else if ($e->getPrevious() && $first) { echo "Final "; } ?>Error:</h2>
+ <h2><?php if (!$e->getPrevious() && !$first) { echo "Original "; } else if ($e->getPrevious() && $first) { echo "Final "; } ?>Error</h2>
<?php if ($e instanceof SystemException && $e->getDescription()) { ?>
<p><?php echo $e->getDescription(); ?></p>
<?php } ?>
<dl>
- <dt>Error Class:</dt> <dd><?php echo get_class($e); ?></dd>
- <dt>Error Message:</dt> <dd><?php echo StringUtil::encodeHTML($e->getMessage()); ?></dd>
- <dt>Error Code:</dt> <dd><?php echo intval($e->getCode()); ?></dd>
- <dt>File:</dt> <dd><?php echo StringUtil::encodeHTML(sanitizePath($e->getFile())); ?> (<?php echo $e->getLine(); ?>)</dd>
+ <dt>Error Class</dt> <dd><?php echo get_class($e); ?></dd>
+ <dt>Error Message</dt> <dd><?php echo StringUtil::encodeHTML($e->getMessage()); ?></dd>
+ <?php if ($e->getCode()) { ?><dt>Error Code</dt> <dd><?php echo intval($e->getCode()); ?></dd><?php } ?>
+ <dt>File</dt> <dd><?php echo StringUtil::encodeHTML(sanitizePath($e->getFile())); ?> (<?php echo $e->getLine(); ?>)</dd>
<?php
if ($e instanceof SystemException) {
ob_start();
throw new \Exception("Using the 'information' property of SystemException is not supported any more.");
}
}
+ if ($e instanceof IExtraInformationException) {
+ foreach ($e->getExtraInformation() as list($key, $value)) {
+ echo "<dt>".StringUtil::encodeHTML($key)."</dt> <dd>".StringUtil::encodeHTML($value)."</dd>";
+ }
+ }
?>
- <dt>Stack Trace:</dt>
+ <dt>Stack Trace</dt>
<dd class="pre"><?php
$trace = array_map(function ($item) {
if (!isset($item['file'])) $item['file'] = '[internal function]';
return $item ? 'true' : 'false';
case 'array':
$keys = array_keys($item);
- if (count($keys) > 5) return "[ ".StringUtil::HELLIP." ]";
+ if (count($keys) > 5) return "[ ".count($keys)." items ]";
return '[ '.implode(', ', array_map(function ($item) {
return $item.' => ';
}, $keys)).']';
if (!$ignorePaths) {
$item['args'] = array_map(function ($item) {
+ if (!is_string($item)) return $item;
+
if (preg_match('~^'.preg_quote($_SERVER['DOCUMENT_ROOT'], '~').'~', $item)) {
$item = sanitizePath($item);
}
<?php
namespace wcf\system\database;
use wcf\system\benchmark\Benchmark;
+use wcf\system\database\exception\DatabaseException as GenericDatabaseException;
+use wcf\system\database\exception\DatabaseQueryException;
+use wcf\system\database\exception\DatabaseTransactionException;
use wcf\system\WCF;
/**
return $this->pdo->lastInsertId();
}
catch (\PDOException $e) {
- throw new DatabaseException("Cannot fetch last insert id: " . $e->getMessage(), $this);
+ throw new GenericDatabaseException("Cannot fetch last insert id", $e);
}
}
return $result;
}
catch (\PDOException $e) {
- throw new DatabaseException("Cannot begin transaction: " . $e->getMessage(), $this);
+ throw new DatabaseTransactionException("Could not begin transaction", $e);
}
}
return $result;
}
catch (\PDOException $e) {
- throw new DatabaseException("Cannot commit transaction: " . $e->getMessage(), $this);
+ throw new DatabaseTransactionException("Could not commit transaction", $e);
}
}
return $result;
}
catch (\PDOException $e) {
- throw new DatabaseException("Cannot rollback transaction: " . $e->getMessage(), $this);
+ throw new DatabaseTransactionException("Could not roll back transaction", $e);
}
}
return new $this->preparedStatementClassName($this, $pdoStatement, $statement);
}
catch (\PDOException $e) {
- throw new DatabaseException($e->getMessage(), $this, null, $statement);
+ throw new DatabaseQueryException("Could not prepare statement '".$statement."'", $e);
}
}
* @package com.woltlab.wcf
* @subpackage system.database
* @category Community Framework
+ * @deprecated 2.2 - Use \wcf\system\database\exception\DatabaseException
*/
class DatabaseException extends SystemException {
/**
public function getDBType() {
return $this->DBType;
}
-
- /**
- * Prints the error page.
- */
- public function show() {
- $this->information .= '<b>sql type:</b> ' . StringUtil::encodeHTML($this->getDBType()) . '<br />';
- $this->information .= '<b>sql error:</b> ' . StringUtil::encodeHTML($this->getErrorDesc()) . '<br />';
- $this->information .= '<b>sql error number:</b> ' . StringUtil::encodeHTML($this->getErrorNumber()) . '<br />';
- $this->information .= '<b>sql version:</b> ' . StringUtil::encodeHTML($this->getSQLVersion()) . '<br />';
- if ($this->preparedStatement !== null) {
- $this->information .= '<b>sql query:</b> ' . StringUtil::encodeHTML($this->preparedStatement->getSQLQuery()) . '<br />';
- $parameters = $this->preparedStatement->getSQLParameters();
- if (!empty($parameters)) {
- foreach ($parameters as $index => $parameter) {
- $this->information .= '<b>sql query parameter ' . $index . ':</b>' . StringUtil::encodeHTML($parameter) . '<br />';
- }
- }
- }
- else if ($this->sqlQuery !== null) {
- $this->information .= '<b>sql query:</b> ' . StringUtil::encodeHTML($this->sqlQuery) . '<br />';
- }
-
- parent::show();
- }
}
<?php
namespace wcf\system\database;
+use wcf\system\database\exception\DatabaseException as GenericDatabaseException;
/**
* This is the database implementation for MySQL 5.1 or higher using PDO.
$this->setAttributes();
}
catch (\PDOException $e) {
- throw new DatabaseException("Connecting to MySQL server '".$this->host."' failed:\n".$e->getMessage(), $this);
+ throw new GenericDatabaseException("Connecting to MySQL server '".$this->host."' failed", $e);
}
}
<?php
namespace wcf\system\database;
+use wcf\system\database\exception\DatabaseException as GenericDatabaseException;
use wcf\util\StringStack;
/**
$this->setAttributes();
}
catch (\PDOException $e) {
- throw new DatabaseException("Connecting to PostgreSQL server '".$this->host."' failed:\n".$e->getMessage(), $this);
+ throw new GenericDatabaseException("Connecting to PostgreSQL server '".$this->host."' failed", $e);
}
// set connection character set
return $this->pdo->lastInsertId('"' . $table . '_' . $field . '_seq"');
}
catch (\PDOException $e) {
- throw new DatabaseException("Can not fetch last insert id", $this);
+ throw new GenericDatabaseException("Can not fetch last insert id", $this);
}
}
--- /dev/null
+<?php
+namespace wcf\system\database\exception;
+
+/**
+ * Denotes an database related error.
+ *
+ * @author Tim Duesterhus
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.database.exception
+ * @category Community Framework
+ */
+class DatabaseException extends \wcf\system\database\DatabaseException {
+ /**
+ * @see \Exception::__construct()
+ */
+ public function __construct($message, \PDOException $previous = null) {
+ \Exception::__construct($message, 0, $previous);
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\database\exception;
+
+/**
+ * Denotes an error that is related to a specific database query.
+ *
+ * @author Tim Duesterhus
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.database.exception
+ * @category Community Framework
+ */
+class DatabaseQueryException extends DatabaseException {
+
+}
--- /dev/null
+<?php
+namespace wcf\system\database\exception;
+use wcf\system\exception\IExtraInformationException;
+
+/**
+ * Denotes an error that is related to a specific database query.
+ *
+ * @author Tim Duesterhus
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.database.exception
+ * @category Community Framework
+ */
+class DatabaseQueryExecutionException extends DatabaseQueryException implements IExtraInformationException {
+ /**
+ * Parameters that were passed to execute().
+ * @var array
+ */
+ protected $parameters = [];
+
+ /**
+ * @see \Exception::__construct()
+ */
+ public function __construct($message, $parameters, \PDOException $previous = null) {
+ \Exception::__construct($message, 0, $previous);
+
+ $this->parameters = $parameters;
+ }
+
+ /**
+ * Returns the parameters that were passed to execute().
+ *
+ * @return array
+ */
+ public function getParameters() {
+ return $this->parameters;
+ }
+
+ /**
+ * @see \wcf\system\exception\IExtraInformationException::getExtraInformation()
+ */
+ public function getExtraInformation() {
+ return array_map(function ($val) {
+ static $i = 0;
+ return [ 'Query Parameter '.(++$i), $val ];
+ }, $this->getParameters());
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\database\exception;
+
+/**
+ * Denotes an error that is related to a database transaction.
+ *
+ * @author Tim Duesterhus
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.database.exception
+ * @category Community Framework
+ */
+class DatabaseTransactionException extends DatabaseException {
+
+}
namespace wcf\system\database\statement;
use wcf\system\benchmark\Benchmark;
use wcf\system\database\Database;
-use wcf\system\database\DatabaseException;
+use wcf\system\database\exception\DatabaseQueryException;
+use wcf\system\database\exception\DatabaseQueryExecutionException;
use wcf\system\exception\SystemException;
use wcf\system\WCF;
return call_user_func_array(array($this->pdoStatement, $name), $arguments);
}
catch (\PDOException $e) {
- throw new DatabaseException('Could not handle prepared statement: '.$e->getMessage(), $this->database, $this);
+ throw new DatabaseQueryException("Could call '".$name."' on '".$this->query."'", $e);
}
}
try {
if (WCF::benchmarkIsEnabled()) Benchmark::getInstance()->start($this->query, Benchmark::TYPE_SQL_QUERY);
- if (empty($parameters)) $result = $this->pdoStatement->execute();
- else $result = $this->pdoStatement->execute($parameters);
+ $result = $this->pdoStatement->execute($parameters);
if (!$result) {
$errorInfo = $this->pdoStatement->errorInfo();
- throw new DatabaseException('Could not execute prepared statement: '.$errorInfo[0].' '.$errorInfo[2], $this->database, $this);
+ throw new DatabaseQueryExecutionException("Could not execute statement '".$this->query."': ".$errorInfo[0].' '.$errorInfo[2], $parameters);
}
if (WCF::benchmarkIsEnabled()) Benchmark::getInstance()->stop();
catch (\PDOException $e) {
if (WCF::benchmarkIsEnabled()) Benchmark::getInstance()->stop();
- throw new DatabaseException('Could not execute prepared statement: '.$e->getMessage(), $this->database, $this);
+ throw new DatabaseQueryExecutionException("Could not execute statement '".$this->query."'", $parameters, $e);
}
}
return $this->pdoStatement->rowCount();
}
catch (\PDOException $e) {
- throw new DatabaseException("Can not fetch affected rows: ".$e->getMessage(), $this);
+ throw new DatabaseQueryException("Could fetch affected rows for '".$this->query."'", $e);
}
}
--- /dev/null
+<?php
+namespace wcf\system\exception;
+
+/**
+ * Denotes an Exception with extra information for the human reader.
+ *
+ * @author Tim Duesterhus
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.exception
+ * @category Community Framework
+ */
+interface IExtraInformationException {
+ /**
+ * Returns an array of (key, value) tuples with extra information to show
+ * in the human readable error log.
+ * Avoid including sensitive information (such as private keys or passwords).
+ *
+ * @return array<array>
+ */
+ public function getExtraInformation();
+}