Implemented a debug switch
authorAlexander Ebert <ebert@woltlab.com>
Fri, 4 Nov 2011 13:24:57 +0000 (14:24 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Fri, 4 Nov 2011 13:24:57 +0000 (14:24 +0100)
It is now possible to switch between debug and production, whereas the last setting will suppress any error message including file/line references and stacktraces.

Furthermore errors will ALWAYS be written to a logfile, regardless if running in production or debug mode.

By default debug mode is enabled for now, it MUST be set to 'production' once the software will be tossed into the wild.

com.woltlab.wcf/option.xml
com.woltlab.wcf/template/userException.tpl
wcfsetup/install.php
wcfsetup/install/files/lib/system/WCFSetup.class.php
wcfsetup/install/files/lib/system/exception/AJAXException.class.php
wcfsetup/install/files/lib/system/exception/LoggedException.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/exception/SystemException.class.php
wcfsetup/install/files/lib/system/exception/UserException.class.php
wcfsetup/install/files/options.inc.php

index ccbcb62f498d2930ad45d02e5fca2d9b08dc64fb..f696db3416004480dc36226b8c272243ee77c96b 100644 (file)
                                <optiontype>boolean</optiontype>
                                <defaultvalue>0</defaultvalue>
                        </option>
+
+                       <option name="debug_mode">
+                               <categoryname>module.system</categoryname>
+                               <optiontype>radiobuttons</optiontype>
+                               <!-- TODO: change to 'production' later -->
+                               <defaultvalue><![CDATA[debug]]></defaultvalue>
+                               <selectoptions>
+                                       <![CDATA[debug:wcf.acp.option.debug_mode.debug
+production:wcf.acp.option.debug_mode.production]]>
+                               </selectoptions>
+                       </option>
                        
                        <!-- general.page -->
                        <option name="page_title">
index 9970d8f64ca6e66e50d61c2fb680f0b03be788b2..4a852d9e5dea18e79038d3ab946cc9a422c74a6e 100644 (file)
        //]]>
 </script>
 
-<!-- 
-{$name} thrown in {$file} ({@$line})
-Stracktrace:
-{$stacktrace}
--->
+{if DEBUG_MODE == 'debug'}
+       <!-- 
+       {$name} thrown in {$file} ({@$line})
+       Stracktrace:
+       {$stacktrace}
+       -->
+{/if}
 
 {include file='footer' sandbox=false}
 </body>
-</html>
\ No newline at end of file
+</html>
index 94a16960d0703e31e39f252877e313cc51f5be0a..047293c97468e878653eb3f68fd35ba460c9497a 100644 (file)
@@ -10,6 +10,7 @@
 define('INSTALL_SCRIPT_DIR', dirname(__FILE__).'/');
 define('SETUP_FILE', INSTALL_SCRIPT_DIR . 'WCFSetup.tar.gz');
 define('NO_IMPORTS', 1);
+define('DEBUG_MODE', 'debug');
 
 // set exception handler
 set_exception_handler('handleException');
index 71ed9b951279e83050571fb23aa0b2b3e77f5c7e..59e16ffbbf60336b30fdcfd5993f2ff086e2425d 100644 (file)
@@ -30,6 +30,7 @@ define('HTTP_ENABLE_GZIP', 0);
 define('HTTP_GZIP_LEVEL', 0);
 define('CACHE_SOURCE_TYPE', 'disk');
 define('MODULE_MASTER_PASSWORD', 1);
+define('DEBUG_MODE', 'debug');
 
 /**
  * WCFSetup executes the installation of the basic wcf systems.
index 4897cd5947210a7ea2ace38cbf5b66dc54b38fda..3dd6ea23058737e191249f871cfd4f5b3dc8afcc 100644 (file)
@@ -12,7 +12,7 @@ use wcf\util\JSON;
  * @subpackage system.exception
  * @category   Community Framework
  */
-class AJAXException extends \Exception {
+class AJAXException extends LoggedException {
        /**
         * Throws a JSON-encoded error message
         * 
@@ -22,13 +22,25 @@ class AJAXException extends \Exception {
        public function __construct($message, $stacktrace = null) {
                if ($stacktrace === null) $stacktrace = $this->getTraceAsString();
                
+               if (DEBUG_MODE == 'debug') {
+                       $responseData = array(
+                               'message' => $message,
+                               'stacktrace' => nl2br($stacktrace)
+                       );
+               }
+               else {
+                       $responseData = array(
+                               'message' => $this->getMessage()
+                       );
+               }
+               
+               // log error
+               $this->logError();
+               
                //header('HTTP/1.0 418 I\'m a Teapot');
                header('HTTP/1.0 503 Service Unavailable');
                header('Content-type: application/json');
-               echo JSON::encode(array(
-                       'message' => $message,
-                       'stacktrace' => nl2br($stacktrace)
-               ));
+               echo JSON::encode($responseData);
                exit;
        }
 }
diff --git a/wcfsetup/install/files/lib/system/exception/LoggedException.class.php b/wcfsetup/install/files/lib/system/exception/LoggedException.class.php
new file mode 100644 (file)
index 0000000..053de2c
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+namespace wcf\system\exception;
+
+/**
+ * A logged exceptions prevents information disclosures and provides an easy
+ * way to log errors.
+ *
+ * @author     Alexander Ebert
+ * @copyright  2001-2011 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
+ */
+class LoggedExceptions extends \Exception {
+       /**
+        * Surpresses the original error message, you can bypass this
+        * by setting $raw to true.
+        * 
+        * @param       boolean         $raw
+        * @see         \Exception::getMessage()
+        */
+       public function getMessage($raw = false) {
+               if ($raw) {
+                       return parent::getMessage();
+               }
+               
+               return 'An error occured. Sorry.';
+       }
+       
+       /**
+        * Writes an error to log file.
+        */
+       protected function logError() {
+               $logFile = WCF_DIR . 'log/' . date('Y-m-d', TIME_NOW) . '.txt';
+               
+               // try to create file
+               @touch($logFile);
+               
+               // validate if file exists and is accessible for us
+               if (!file_exists($logFile) || !is_writable($logFile)) {
+                       /*
+                               We cannot recover if we reached this point, the server admin
+                               is urged to fix his pretty much broken configuration.
+                               
+                               GLaDOS: Look at you, sailing through the air majestically, like an eagle... piloting a blimp.
+                       */
+                       return;
+               }
+               
+               // build message
+               $message = date('r', TIME_NOW) . "\n" . $this->getMessage(true) . "\n\n" . $this->getTraceAsString() . "\n\n\n";
+               
+               // append
+               @file_put_contents($logFile, $message, FILE_APPEND);
+       }
+}
index c51f35eafca2c7492bf3bf5ae791786c813adb53..584ce62f95fe346f534561e4ab39ddac3ce07498 100644 (file)
@@ -12,7 +12,7 @@ use wcf\util\StringUtil;
  * @subpackage system.exception
  * @category   Community Framework
  */
-class SystemException extends \Exception implements IPrintableException {
+class SystemException extends LoggedException implements IPrintableException {
        /**
         * error description
         * @var string
@@ -66,6 +66,9 @@ class SystemException extends \Exception implements IPrintableException {
         * @see wcf\system\exception\IPrintableException::show()
         */
        public function show() {
+               // log error
+               $this->logError();
+               
                // send status code
                @header('HTTP/1.1 503 Service Unavailable');
                
@@ -137,28 +140,30 @@ class SystemException extends \Exception implements IPrintableException {
                        <body>
                                <div class="systemException">
                                        <h1>Fatal error: <?php echo StringUtil::encodeHTML($this->getMessage()); ?></h1>
-
-                                       <div>
-                                               <p><?php echo $this->getDescription(); ?></p>
+                                       
+                                       <?php if (DEBUG_MODE == 'debug') { ?>
+                                               <div>
+                                                       <p><?php echo $this->getDescription(); ?></p>
                                                
-                                               <h2>Information:</h2>
-                                               <p>
-                                                       <b>error message:</b> <?php echo StringUtil::encodeHTML($this->getMessage()); ?><br>
-                                                       <b>error code:</b> <?php echo intval($this->getCode()); ?><br>
-                                                       <?php echo $this->information; ?>
-                                                       <b>file:</b> <?php echo StringUtil::encodeHTML($this->getFile()); ?> (<?php echo $this->getLine(); ?>)<br>
-                                                       <b>php version:</b> <?php echo StringUtil::encodeHTML(phpversion()); ?><br>
-                                                       <b>wcf version:</b> <?php echo WCF_VERSION; ?><br>
-                                                       <b>date:</b> <?php echo gmdate('r'); ?><br>
-                                                       <b>request:</b> <?php if (isset($_SERVER['REQUEST_URI']))  echo StringUtil::encodeHTML($_SERVER['REQUEST_URI']); ?><br>
-                                                       <b>referer:</b> <?php if (isset($_SERVER['HTTP_REFERER'])) echo StringUtil::encodeHTML($_SERVER['HTTP_REFERER']); ?><br>
-                                               </p>
+                                                       <h2>Information:</h2>
+                                                       <p>
+                                                               <b>error message:</b> <?php echo StringUtil::encodeHTML($this->getMessage()); ?><br>
+                                                               <b>error code:</b> <?php echo intval($this->getCode()); ?><br>
+                                                               <?php echo $this->information; ?>
+                                                               <b>file:</b> <?php echo StringUtil::encodeHTML($this->getFile()); ?> (<?php echo $this->getLine(); ?>)<br>
+                                                               <b>php version:</b> <?php echo StringUtil::encodeHTML(phpversion()); ?><br>
+                                                               <b>wcf version:</b> <?php echo WCF_VERSION; ?><br>
+                                                               <b>date:</b> <?php echo gmdate('r'); ?><br>
+                                                               <b>request:</b> <?php if (isset($_SERVER['REQUEST_URI']))  echo StringUtil::encodeHTML($_SERVER['REQUEST_URI']); ?><br>
+                                                               <b>referer:</b> <?php if (isset($_SERVER['HTTP_REFERER'])) echo StringUtil::encodeHTML($_SERVER['HTTP_REFERER']); ?><br>
+                                                       </p>
 
-                                               <h2>Stacktrace:</h2>
-                                               <pre><?php echo StringUtil::encodeHTML($this->__getTraceAsString()); ?></pre>
-                                       </div>
+                                                       <h2>Stacktrace:</h2>
+                                                       <pre><?php echo StringUtil::encodeHTML($this->__getTraceAsString()); ?></pre>
+                                               </div>
+                                       <?php } ?>
 
-                               <?php echo $this->functions; ?>
+                                       <?php echo $this->functions; ?>
                                </div>
                        </body>
                </html>
index 79939c1e18932b68d850f52c14f667edcee3ab45..96600bbe9df47a100c15e2ce8a13113bf0be0a75 100644 (file)
@@ -11,11 +11,16 @@ namespace wcf\system\exception;
  * @subpackage system.exception
  * @category   Community Framework
  */
-abstract class UserException extends \Exception implements IPrintableException {
+abstract class UserException extends LoggedException implements IPrintableException {
        /**
         * @see wcf\system\exception\IPrintableException::show()
         */
        public function show() {
-               echo '<pre>' . $this->getTraceAsString() . '</pre>';
+               if (DEBUG_MODE == 'debug') {
+                       echo '<pre>' . $this->getTraceAsString() . '</pre>';
+               }
+               else {
+                       echo '<pre>' . $this->getMessage() . '</pre>';
+               }
        }
 }
index ddbe25a06a4f886aba6bd6ab9675d69eada98996..9f336507950d1c92ba7b9b99bd178d487c02d290 100644 (file)
@@ -25,3 +25,6 @@ define('SESSION_VALIDATE_USER_AGENT', 0);
 define('CACHE_SOURCE_TYPE', 'disk');
 define('MODULE_MASTER_PASSWORD', 1);
 define('TIMEZONE', 'Europe/Berlin');
+
+// TODO: Change to 'production' later
+define('DEBUG_MODE', 'debug');