3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
29 * To ensure that PHP errors or unhandled exceptions are reported in JSON
30 * format, wrap this around your code. For example:
33 * $errorContainer = new CRM_Queue_ErrorPolicy();
34 * $errorContainer->call(function(){
35 * ...include some files, do some work, etc...
39 * Note: Most of the code in this class is pretty generic vis-a-vis error
40 * handling -- except for 'reportError', whose message format is only
41 * appropriate for use with the CRM_Queue_Page_AJAX. Some kind of cleanup
42 * will be necessary to get reuse from the other parts of this class.
44 class CRM_Queue_ErrorPolicy
{
48 * @param null|int $level
49 * PHP error level to capture (e.g. E_PARSE|E_USER_ERROR).
51 public function __construct($level = NULL) {
52 register_shutdown_function(array($this, 'onShutdown'));
53 if ($level === NULL) {
54 $level = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR
;
56 $this->level
= $level;
60 * Enable the error policy.
62 public function activate() {
64 $this->backup
= array();
66 'display_errors', 'html_errors', 'xmlrpc_errors') as $key) {
67 $this->backup
[$key] = ini_get($key);
70 set_error_handler(array($this, 'onError'), $this->level
);
71 // FIXME make this temporary/reversible
72 $this->errorScope
= CRM_Core_TemporaryErrorScope
::useException();
76 * Disable the error policy.
78 public function deactivate() {
79 $this->errorScope
= NULL;
80 restore_error_handler();
82 'display_errors', 'html_errors', 'xmlrpc_errors') as $key) {
83 ini_set($key, $this->backup
[$key]);
85 $this->active
= FALSE;
89 * Execute the callable. Activate and deactivate the error policy
92 * @param callable|array|string $callable
93 * A callback function.
97 public function call($callable) {
100 $result = $callable();
103 $this->reportException($e);
110 * Receive (semi) recoverable error notices
112 * @see set_error_handler
114 public function onError($errno, $errstr, $errfile, $errline) {
115 if (!(error_reporting() & $errno)) {
118 throw new Exception(sprintf('PHP Error %s at %s:%s: %s', $errno, $errfile, $errline, $errstr));
122 * Receive non-recoverable error notices
124 * @see register_shutdown_function
125 * @see error_get_last
127 public function onShutdown() {
128 if (!$this->active
) {
131 $error = error_get_last();
132 if (is_array($error) && ($error['type'] & $this->level
)) {
133 $this->reportError($error);
138 * Print a fatal error
140 * @param array $error
141 * The PHP error (with "type", "message", etc).
143 public function reportError($error) {
147 'exception' => htmlentities(sprintf('Error %s: %s in %s, line %s', $error['type'], $error['message'], $error['file'], $error['line'])),
149 global $activeQueueRunner;
150 if (is_object($activeQueueRunner)) {
151 $response['last_task_title'] = $activeQueueRunner->lastTaskTitle
;
153 CRM_Core_Error
::debug_var('CRM_Queue_ErrorPolicy_reportError', $response);
154 echo json_encode($response);
155 // civiExit() is unnecessary -- we're only called as part of abend
159 * Print an unhandled exception
161 * @param Exception $e
162 * The unhandled exception.
164 public function reportException(Exception
$e) {
165 CRM_Core_Error
::debug_var('CRM_Queue_ErrorPolicy_reportException', CRM_Core_Error
::formatTextException($e));
172 $config = CRM_Core_Config
::singleton();
173 if ($config->backtrace || CRM_Core_Config
::isUpgradeMode()) {
174 $response['exception'] = CRM_Core_Error
::formatHtmlException($e);
177 $response['exception'] = htmlentities($e->getMessage());
180 global $activeQueueRunner;
181 if (is_object($activeQueueRunner)) {
182 $response['last_task_title'] = $activeQueueRunner->lastTaskTitle
;
184 CRM_Utils_JSON
::output($response);