├── CHANGELOG.md ├── README.md ├── composer.json ├── license.txt ├── modman ├── screenshot-configuration.png └── src └── app ├── code └── community │ └── SSE │ └── DebugErrors │ ├── Exception.php │ ├── Helper │ └── Data.php │ ├── Model │ ├── Errorhandler.php │ ├── Errorhandler │ │ ├── Exception │ │ │ ├── Log.php │ │ │ ├── Show.php │ │ │ └── Throw.php │ │ ├── Interface.php │ │ └── Warning.php │ ├── Observer.php │ └── System │ │ └── Config │ │ └── Handler.php │ └── etc │ ├── config.xml │ └── system.xml ├── design ├── adminhtml │ └── default │ │ └── default │ │ └── template │ │ └── sse_debugerrors │ │ └── exception.phtml └── frontend │ └── base │ └── default │ └── template │ └── sse_debugerrors │ └── exception.phtml └── etc └── modules └── SSE_DebugErrors.xml /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All Notable changes to `SSE_DebugErrors` will be documented in this file 4 | 5 | ## 0.1.0 - 2015-11-17 6 | 7 | Initial release -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SSE_DebugErrors 2 | ====== 3 | Adds a new debug configuration option that adds more information to unspecific error messages and lets you specify how to handle these additional errors. 4 | 5 | ## Version 6 | * Version 0.1.0 7 | 8 | ## Requirements ## 9 | 10 | * Magento 1.x 11 | * PHP 5.4 or higher 12 | 13 | ## List of Errors 14 | 15 | The following errors are handled by this module. They are displayed or logged based on the module configuration (see "Configuration" below): 16 | 17 | - 18 | > Filename cannot be empty 19 | 20 | This message appears when a template file is missing, but unfortunately does not tell you anything about the whereabouts. The new message contains the full path of the missing template, the block name and the block class. 21 | 22 | - 23 | > Not valid template file: $fileName 24 | 25 | This message gets silently logged to system.log if symlinks are not allowed and a template is behind a symlink. A common error on fresh installations that use modman. The new message is more explicit. 26 | 27 | ## Installation 28 | 29 | 1. Manual installation: download [the latest release](https://github.com/schmengler/DebugErrors/zipball/master) and copy the `app` directory into the Magento installation. 30 | 2. Install via composer as dev dependency: 31 | 32 | "repositories": [ 33 | { 34 | "type": "git", 35 | "url": "https://github.com/schmengler/DebugErrors.git" 36 | } 37 | ], 38 | "require-dev": { 39 | "sse/debugerrors": "~0.1.0" 40 | } 41 | 42 | 43 | ## Configuration 44 | 45 | Enable debug errors in System > Configuration > Advanced > Developer > Debug: 46 | 47 | ![Screenshot](https://github.com/schmengler/DebugErrors/raw/master/screenshot-configuration.png) 48 | 49 | If you are using Developer Client Restriction, only the configured IPs will use the additional error handling. 50 | 51 | You can also specify how the debug error messages should be logged and displayed: 52 | 53 | - **Throw exception immediately:** An exception is thrown and logged to exception.log. Note that Magento might catch and swallow the exception. 54 | - **Show exception in block:** Replace current block with exception message (only if error is in context of a block). Also always logs exception to exception.log. 55 | - **Only log exception to exception log:** Only logs exception to exception.log 56 | - **Trigger PHP Warning:** Magento handles warnings depending on the environment variable MAGE_IS_DEVELOPER_MODE. If developer mode is on, an exception is thrown and displayed. If not, the warning gets logged to system.log. 57 | 58 | 59 | ## Technical Information 60 | 61 | The extension does not rewrite any classes. If not enabled in configuration, no behaviour changes. 62 | 63 | ## Support 64 | 65 | If you have any issues with this extension, open an issue on [GitHub](https://github.com/schmengler/DebugErrors/issues). 66 | 67 | ## Contribution 68 | 69 | Any contribution is highly appreciated. The best way to contribute code is to open a [pull request on GitHub](https://help.github.com/articles/using-pull-requests). 70 | 71 | Please follow these rules while adding new features: 72 | 73 | - pass an `SSE_DebugErrors_Exception` to `Mage::getSingleton('sse_debugerrors/errorhandler')->handle()` to trigger the error handling. 74 | - always check if the debug errors are enabled with `Mage::helper('sse_debugerrors')->isEnabled()` and if not, do not do anything 75 | - do not rewrite any classes, do all additional checks in observers. 76 | 77 | ## Developer 78 | 79 | Fabian Schmengler 80 | [http://www.schmengler-se.de](http://www.schmengler-se.de) 81 | [@fschmengler](https://twitter.com/fschmengler) 82 | 83 | ## License 84 | * see [LICENSE](https://github.com/schmengler/DebugErrors/blob/master/license.txt) file 85 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sse/debugerrors", 3 | "license": "OSL-3.0", 4 | "type": "magento-module", 5 | "description": "Development tool: Add more information to unspecific error messages", 6 | "homepage": "https://github.com/schmengler/DebugErrors", 7 | "require": { 8 | "php": ">=5.4" 9 | }, 10 | "authors":[ 11 | { 12 | "name":"Fabian Schmengler", 13 | "email":"fabian@schmengler-se.de" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schmengler/DebugErrors/ba6d7bfd58434787bc5123a28390d8aa3a0d4d46/license.txt -------------------------------------------------------------------------------- /modman: -------------------------------------------------------------------------------- 1 | src/app/code/community/SSE/DebugErrors app/code/community/SSE/DebugErrors 2 | src/app/design/frontend/base/default/template/sse_debugerrors app/design/frontend/base/default/template/sse_debugerrors 3 | src/app/design/adminhtml/default/default/template/sse_debugerrors app/design/adminhtml/default/default/template/sse_debugerrors 4 | src/app/etc/modules/SSE_DebugErrors.xml app/etc/modules/SSE_DebugErrors.xml -------------------------------------------------------------------------------- /screenshot-configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schmengler/DebugErrors/ba6d7bfd58434787bc5123a28390d8aa3a0d4d46/screenshot-configuration.png -------------------------------------------------------------------------------- /src/app/code/community/SSE/DebugErrors/Exception.php: -------------------------------------------------------------------------------- 1 | 7 | * @category SSE 8 | * @package SSE_DebugErrors 9 | * @copyright Copyright (c) 2015 Schmengler Software Engineering (http://www.schmengler-se.de/) 10 | */ 11 | class SSE_DebugErrors_Exception extends Mage_Core_Exception 12 | { 13 | /** 14 | * @var Mage_Core_Block_Abstract 15 | */ 16 | protected $block; 17 | 18 | public function __construct($message = "", $code = 0, Exception $previous = null, Mage_Core_Block_Abstract $block = null) 19 | { 20 | parent::__construct($message, $code, $previous); 21 | if ($block !== null) { 22 | $this->block = $block; 23 | } 24 | } 25 | 26 | /** 27 | * @return Mage_Core_Block_Abstract 28 | */ 29 | public function getBlock() 30 | { 31 | return $this->block; 32 | } 33 | 34 | 35 | } -------------------------------------------------------------------------------- /src/app/code/community/SSE/DebugErrors/Helper/Data.php: -------------------------------------------------------------------------------- 1 | 7 | * @category SSE 8 | * @package SSE_DebugErrors 9 | * @copyright Copyright (c) 2015 Schmengler Software Engineering (http://www.schmengler-se.de/) 10 | */ 11 | 12 | /** 13 | * Default Helper 14 | * 15 | * @package SSE_DebugErrors 16 | */ 17 | class SSE_DebugErrors_Helper_Data extends Mage_Core_Helper_Abstract 18 | { 19 | const XML_PATH_ENABLE = 'dev/debug/debug_errors_enable'; 20 | const XML_PATH_HANDLER = 'dev/debug/debug_errors_handler'; 21 | 22 | public function isEnabled() 23 | { 24 | return Mage::getStoreConfigFlag(self::XML_PATH_ENABLE) && Mage::helper('core')->isDevAllowed(); 25 | } 26 | } -------------------------------------------------------------------------------- /src/app/code/community/SSE/DebugErrors/Model/Errorhandler.php: -------------------------------------------------------------------------------- 1 | 7 | * @category SSE 8 | * @package SSE_DebugErrors 9 | * @copyright Copyright (c) 2015 Schmengler Software Engineering (http://www.schmengler-se.de/) 10 | */ 11 | 12 | class SSE_DebugErrors_Model_Errorhandler 13 | { 14 | /** 15 | * @var SSE_DebugErrors_Model_Errorhandler_Interface 16 | */ 17 | protected $_handler; 18 | 19 | public function handle(SSE_DebugErrors_Exception $exception) 20 | { 21 | $this->_getHandler()->handle($exception); 22 | } 23 | 24 | /** 25 | * @return SSE_DebugErrors_Model_Errorhandler_Interface 26 | */ 27 | protected function _getHandler() 28 | { 29 | if ($this->_handler === null) { 30 | $handlerClass = 'sse_debugerrors/errorhandler_' . Mage::getStoreConfig(SSE_DebugErrors_Helper_Data::XML_PATH_HANDLER); 31 | $this->_handler = Mage::getModel($handlerClass); 32 | if (!$this->_handler instanceof SSE_DebugErrors_Model_Errorhandler_Interface) { 33 | $this->_handler = Mage::getModel('sse_debugerrors/errorhandler_exception_log'); 34 | } 35 | } 36 | return $this->_handler; 37 | } 38 | } -------------------------------------------------------------------------------- /src/app/code/community/SSE/DebugErrors/Model/Errorhandler/Exception/Log.php: -------------------------------------------------------------------------------- 1 | 7 | * @category SSE 8 | * @package SSE_DebugErrors 9 | * @copyright Copyright (c) 2015 Schmengler Software Engineering (http://www.schmengler-se.de/) 10 | */ 11 | 12 | class SSE_DebugErrors_Model_Errorhandler_Exception_Log implements SSE_DebugErrors_Model_Errorhandler_Interface 13 | { 14 | public function handle(SSE_DebugErrors_Exception $exception) 15 | { 16 | Mage::logException($exception); 17 | } 18 | } -------------------------------------------------------------------------------- /src/app/code/community/SSE/DebugErrors/Model/Errorhandler/Exception/Show.php: -------------------------------------------------------------------------------- 1 | 7 | * @category SSE 8 | * @package SSE_DebugErrors 9 | * @copyright Copyright (c) 2015 Schmengler Software Engineering (http://www.schmengler-se.de/) 10 | */ 11 | 12 | class SSE_DebugErrors_Model_Errorhandler_Exception_Show implements SSE_DebugErrors_Model_Errorhandler_Interface 13 | { 14 | public function handle(SSE_DebugErrors_Exception $exception) 15 | { 16 | $exception->getBlock()->setTemplate('sse_debugerrors/exception.phtml')->setException($exception); 17 | Mage::logException($exception); 18 | } 19 | } -------------------------------------------------------------------------------- /src/app/code/community/SSE/DebugErrors/Model/Errorhandler/Exception/Throw.php: -------------------------------------------------------------------------------- 1 | 7 | * @category SSE 8 | * @package SSE_DebugErrors 9 | * @copyright Copyright (c) 2015 Schmengler Software Engineering (http://www.schmengler-se.de/) 10 | */ 11 | 12 | class SSE_DebugErrors_Model_Errorhandler_Exception_Throw implements SSE_DebugErrors_Model_Errorhandler_Interface 13 | { 14 | public function handle(SSE_DebugErrors_Exception $exception) 15 | { 16 | throw $exception; 17 | } 18 | } -------------------------------------------------------------------------------- /src/app/code/community/SSE/DebugErrors/Model/Errorhandler/Interface.php: -------------------------------------------------------------------------------- 1 | 7 | * @category SSE 8 | * @package SSE_DebugErrors 9 | * @copyright Copyright (c) 2015 Schmengler Software Engineering (http://www.schmengler-se.de/) 10 | */ 11 | 12 | interface SSE_DebugErrors_Model_Errorhandler_Interface 13 | { 14 | public function handle(SSE_DebugErrors_Exception $exception); 15 | } -------------------------------------------------------------------------------- /src/app/code/community/SSE/DebugErrors/Model/Errorhandler/Warning.php: -------------------------------------------------------------------------------- 1 | 7 | * @category SSE 8 | * @package SSE_DebugErrors 9 | * @copyright Copyright (c) 2015 Schmengler Software Engineering (http://www.schmengler-se.de/) 10 | */ 11 | 12 | class SSE_DebugErrors_Model_Errorhandler_Warning implements SSE_DebugErrors_Model_Errorhandler_Interface 13 | { 14 | public function handle(SSE_DebugErrors_Exception $exception) 15 | { 16 | trigger_error($exception->getMessage(), E_USER_WARNING); 17 | } 18 | } -------------------------------------------------------------------------------- /src/app/code/community/SSE/DebugErrors/Model/Observer.php: -------------------------------------------------------------------------------- 1 | 7 | * @category SSE 8 | * @package SSE_DebugErrors 9 | * @copyright Copyright (c) 2015 Schmengler Software Engineering (http://www.schmengler-se.de/) 10 | */ 11 | 12 | /** 13 | * Observer for extended error messages 14 | * 15 | * @package SSE_DebugErrors 16 | */ 17 | class SSE_DebugErrors_Model_Observer 18 | { 19 | protected $_allowSymlinks = null; 20 | 21 | public function coreBlockAbstractToHtmlBefore(Varien_Event_Observer $observer) 22 | { 23 | /** @var Mage_Core_Block_Abstract $block */ 24 | $block = $observer->getBlock(); 25 | if ($block instanceof Mage_Core_Block_Template && Mage::helper('sse_debugerrors')->isEnabled()) { 26 | $this->_checkPossibleTemplateErrors($block); 27 | } 28 | } 29 | 30 | /** 31 | * @return bool 32 | */ 33 | protected function _getAllowSymlinks() 34 | { 35 | if (is_null($this->_allowSymlinks)) { 36 | $this->_allowSymlinks = Mage::getStoreConfigFlag(Mage_Core_Block_Template::XML_PATH_TEMPLATE_ALLOW_SYMLINK); 37 | } 38 | return $this->_allowSymlinks; 39 | } 40 | 41 | protected function _triggerError(Exception $e) 42 | { 43 | Mage::getSingleton('sse_debugerrors/errorhandler')->handle($e); 44 | } 45 | 46 | /** 47 | * @param $block 48 | */ 49 | protected function _checkPossibleTemplateErrors($block) 50 | { 51 | if (!$block->getTemplate()) { 52 | /* 53 | * Blocks without template are rendered empty. Unfortunately core modules rely on this and throwing 54 | * an error here would result in too many false positives. 55 | */ 56 | return; 57 | } 58 | try { 59 | $dir = Mage::getBaseDir('design'); 60 | $scriptPath = realpath($dir); 61 | if ($scriptPath === false) { 62 | throw new SSE_DebugErrors_Exception(sprintf( 63 | 'Block %s (type %s): Design base dir %s not found.', 64 | $block->getNameInLayout(), get_class($block), $scriptPath), 0, null, $block); 65 | } 66 | if (strpos($scriptPath, realpath(Mage::getBaseDir('design'))) !== 0 && !$this->_getAllowSymlinks()) { 67 | throw new SSE_DebugErrors_Exception(sprintf( 68 | 'Block %s (type %s): Design base dir %s is a symlink and symlinks are configured to be forbidden.', 69 | $block->getNameInLayout(), get_class($block), $scriptPath), 0, null, $block); 70 | } 71 | $fileName = $block->getTemplateFile(); 72 | 73 | $includeFilePath = realpath($dir . DS . $fileName); 74 | if ($includeFilePath === false) { 75 | throw new SSE_DebugErrors_Exception(sprintf( 76 | 'Block %s (type %s): Template path %s not found', 77 | $block->getNameInLayout(), get_class($block), $dir . DS . $fileName), 0, null, $block); 78 | } 79 | if (strpos($includeFilePath, realpath($dir)) !== 0 && !$this->_getAllowSymlinks()) { 80 | throw new SSE_DebugErrors_Exception(sprintf( 81 | 'Block %s (type %s): Template path %s is a symlink and symlinks are configured to be forbidden.', 82 | $block->getNameInLayout(), get_class($block), $dir), 0, null, $block); 83 | } 84 | } catch (SSE_DebugErrors_Exception $e) { 85 | $this->_triggerError($e); 86 | } 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/app/code/community/SSE/DebugErrors/Model/System/Config/Handler.php: -------------------------------------------------------------------------------- 1 | 7 | * @category SSE 8 | * @package SSE_DebugErrors 9 | * @copyright Copyright (c) 2015 Schmengler Software Engineering (http://www.schmengler-se.de/) 10 | */ 11 | 12 | class SSE_DebugErrors_Model_System_Config_Handler 13 | { 14 | /* 15 | * TODO: other handlers: 16 | * - custom log file 17 | */ 18 | const HANDLER_EXCEPTION_THROW = 'exception_throw'; 19 | const HANDLER_EXCEPTION_LOG = 'exception_log'; 20 | const HANDLER_EXCEPTION_SHOW = 'exception_show'; 21 | const HANDLER_WARNING = 'warning'; 22 | 23 | /** 24 | * Options getter 25 | * 26 | * @return array 27 | */ 28 | public function toOptionArray() 29 | { 30 | return array( 31 | array('value' => self::HANDLER_EXCEPTION_THROW, 'label' => Mage::helper('sse_debugerrors')->__('Throw exception immediately')), 32 | array('value' => self::HANDLER_EXCEPTION_SHOW, 'label' => Mage::helper('sse_debugerrors')->__('Show exception in block')), 33 | array('value' => self::HANDLER_EXCEPTION_LOG, 'label' => Mage::helper('sse_debugerrors')->__('Only log exception to exception log')), 34 | array('value' => self::HANDLER_WARNING, 'label' => Mage::helper('sse_debugerrors')->__('Trigger PHP Warning')), 35 | ); 36 | } 37 | 38 | /** 39 | * Get options in "key-value" format 40 | * 41 | * @return array 42 | */ 43 | public function toArray() 44 | { 45 | $result = []; 46 | foreach ($this->toOptionArray() as $option) { 47 | $result[$option['value']] = $option['label']; 48 | } 49 | return $result; 50 | } 51 | } -------------------------------------------------------------------------------- /src/app/code/community/SSE/DebugErrors/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 0.1.0 17 | 18 | 19 | 20 | 21 | 22 | SSE_DebugErrors_Helper 23 | 24 | 25 | 26 | 27 | SSE_DebugErrors_Model 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | singleton 37 | sse_debugerrors/observer 38 | coreBlockAbstractToHtmlBefore 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | exception_log 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/app/code/community/SSE/DebugErrors/etc/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | select 22 | adminhtml/system_config_source_yesno 23 | 90 24 | 1 25 | 1 26 | 1 27 | 28 | 29 | 30 | select 31 | sse_debugerrors/system_config_handler 32 | 91 33 | 34 | 1 35 | 36 | 1 37 | 1 38 | 1 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/app/design/adminhtml/default/default/template/sse_debugerrors/exception.phtml: -------------------------------------------------------------------------------- 1 | getException()->getMessage(); -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/sse_debugerrors/exception.phtml: -------------------------------------------------------------------------------- 1 | getException()->getMessage(); -------------------------------------------------------------------------------- /src/app/etc/modules/SSE_DebugErrors.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | true 17 | community 18 | 19 | 20 | --------------------------------------------------------------------------------