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 * Start of the Error framework. We should check out and inherit from
30 * PEAR_ErrorStack and use that framework
33 * @copyright CiviCRM LLC (c) 2004-2014
38 require_once 'PEAR/ErrorStack.php';
39 require_once 'PEAR/Exception.php';
40 require_once 'CRM/Core/Exception.php';
42 require_once 'Log.php';
47 class CRM_Exception
extends PEAR_Exception
{
49 * Redefine the exception so message isn't optional
50 * Supported signatures:
51 * - PEAR_Exception(string $message);
52 * - PEAR_Exception(string $message, int $code);
53 * - PEAR_Exception(string $message, Exception $cause);
54 * - PEAR_Exception(string $message, Exception $cause, int $code);
55 * - PEAR_Exception(string $message, PEAR_Error $cause);
56 * - PEAR_Exception(string $message, PEAR_Error $cause, int $code);
57 * - PEAR_Exception(string $message, array $causes);
58 * - PEAR_Exception(string $message, array $causes, int $code);
60 * @param string $message exception message
62 * @param Exception $previous
64 public function __construct($message = NULL, $code = 0, Exception
$previous = NULL) {
65 parent
::__construct($message, $code, $previous);
70 * Class CRM_Core_Error
72 class CRM_Core_Error
extends PEAR_ErrorStack
{
75 * Status code of various types of errors
77 const FATAL_ERROR
= 2;
78 const DUPLICATE_CONTACT
= 8001;
79 const DUPLICATE_CONTRIBUTION
= 8002;
80 const DUPLICATE_PARTICIPANT
= 8003;
83 * We only need one instance of this object. So we use the singleton
84 * pattern and cache the instance in this variable
87 private static $_singleton = NULL;
90 * The logger object for this application
93 private static $_log = NULL;
96 * If modeException == true, errors are raised as exception instead of returning civicrm_errors
98 public static $modeException = NULL;
101 * Singleton function used to manage this object.
103 * @param null $package
104 * @param bool $msgCallback
105 * @param bool $contextCallback
106 * @param bool $throwPEAR_Error
107 * @param string $stackClass
111 public static function &singleton($package = NULL, $msgCallback = FALSE, $contextCallback = FALSE, $throwPEAR_Error = FALSE, $stackClass = 'PEAR_ErrorStack') {
112 if (self
::$_singleton === NULL) {
113 self
::$_singleton = new CRM_Core_Error('CiviCRM');
115 return self
::$_singleton;
121 public function __construct() {
122 parent
::__construct('CiviCRM');
124 $log = CRM_Core_Config
::getLog();
125 $this->setLogger($log);
127 // set up error handling for Pear Error Stack
128 $this->setDefaultCallback(array($this, 'handlePES'));
133 * @param string $separator
135 * @return array|null|string
137 static public function getMessages(&$error, $separator = '<br />') {
138 if (is_a($error, 'CRM_Core_Error')) {
139 $errors = $error->getErrors();
141 foreach ($errors as $e) {
142 $message[] = $e['code'] . ': ' . $e['message'];
144 $message = implode($separator, $message);
151 * Status display function specific to payment processor errors
153 * @param string $separator
155 public static function displaySessionError(&$error, $separator = '<br />') {
156 $message = self
::getMessages($error, $separator);
158 $status = ts("Payment Processor Error message") . "{$separator} $message";
159 $session = CRM_Core_Session
::singleton();
160 $session->setStatus($status);
165 * Create the main callback method. this method centralizes error processing.
167 * the errors we expect are from the pear modules DB, DB_DataObject
168 * which currently use PEAR::raiseError to notify of error messages.
170 * @param object $pearError PEAR_Error
174 public static function handle($pearError) {
176 // setup smarty with config, session and template location.
177 $template = CRM_Core_Smarty
::singleton();
178 $config = CRM_Core_Config
::singleton();
180 if ($config->backtrace
) {
184 // create the error array
186 $error['callback'] = $pearError->getCallback();
187 $error['code'] = $pearError->getCode();
188 $error['message'] = $pearError->getMessage();
189 $error['mode'] = $pearError->getMode();
190 $error['debug_info'] = $pearError->getDebugInfo();
191 $error['type'] = $pearError->getType();
192 $error['user_info'] = $pearError->getUserInfo();
193 $error['to_string'] = $pearError->toString();
194 if (function_exists('mysql_error') &&
197 $mysql_error = mysql_error() . ', ' . mysql_errno();
198 $template->assign_by_ref('mysql_code', $mysql_error);
200 // execute a dummy query to clear error stack
201 mysql_query('select 1');
203 elseif (function_exists('mysqli_error')) {
204 $dao = new CRM_Core_DAO();
206 // we do it this way, since calling the function
207 // getDatabaseConnection could potentially result
208 // in an infinite loop
209 global $_DB_DATAOBJECT;
210 if (isset($_DB_DATAOBJECT['CONNECTIONS'][$dao->_database_dsn_md5
])) {
211 $conn = $_DB_DATAOBJECT['CONNECTIONS'][$dao->_database_dsn_md5
];
212 $link = $conn->connection
;
214 if (mysqli_error($link)) {
215 $mysql_error = mysqli_error($link) . ', ' . mysqli_errno($link);
216 $template->assign_by_ref('mysql_code', $mysql_error);
218 // execute a dummy query to clear error stack
219 mysqli_query($link, 'select 1');
224 $template->assign_by_ref('error', $error);
225 $errorDetails = CRM_Core_Error
::debug('', $error, FALSE);
226 $template->assign_by_ref('errorDetails', $errorDetails);
228 CRM_Core_Error
::debug_var('Fatal Error Details', $error);
229 CRM_Core_Error
::backtrace('backTrace', TRUE);
231 if ($config->initialized
) {
232 $content = $template->fetch('CRM/common/fatal.tpl');
233 echo CRM_Utils_System
::theme($content);
236 echo "Sorry. A non-recoverable error has occurred. The error trace below might help to resolve the issue<p>";
237 CRM_Core_Error
::debug(NULL, $error);
239 static $runOnce = FALSE;
248 * this function is used to trap and print errors
249 * during system initialization time. Hence the error
250 * message is quite ugly
254 public static function simpleHandler($pearError) {
256 // create the error array
258 $error['callback'] = $pearError->getCallback();
259 $error['code'] = $pearError->getCode();
260 $error['message'] = $pearError->getMessage();
261 $error['mode'] = $pearError->getMode();
262 $error['debug_info'] = $pearError->getDebugInfo();
263 $error['type'] = $pearError->getType();
264 $error['user_info'] = $pearError->getUserInfo();
265 $error['to_string'] = $pearError->toString();
267 // ensure that debug does not check permissions since we are in bootstrap
268 // mode and need to print a decent message to help the user
269 CRM_Core_Error
::debug('Initialization Error', $error, TRUE, TRUE, FALSE);
271 // always log the backtrace to a file
272 self
::backtrace('backTrace', TRUE);
278 * Handle errors raised using the PEAR Error Stack.
280 * currently the handler just requests the PES framework
281 * to push the error to the stack (return value PEAR_ERRORSTACK_PUSH).
283 * Note: we can do our own error handling here and return PEAR_ERRORSTACK_IGNORE.
285 * Also, if we do not return any value the PEAR_ErrorStack::push() then does the
286 * action of PEAR_ERRORSTACK_PUSHANDLOG which displays the errors on the screen,
287 * since the logger set for this error stack is 'display' - see CRM_Core_Config::getLog();
289 public static function handlePES($pearError) {
290 return PEAR_ERRORSTACK_PUSH
;
294 * Display an error page with an error message describing what happened
296 * @param string $message
298 * @param string $code
299 * The error code if any.
300 * @param string $email
301 * The email address to notify of this situation.
307 public static function fatal($message = NULL, $code = NULL, $email = NULL) {
309 'message' => $message,
313 if (self
::$modeException) {
315 CRM_Core_Error
::debug_var('Fatal Error Details', $vars);
316 CRM_Core_Error
::backtrace('backTrace', TRUE);
318 $details = 'A fatal error was triggered';
320 $details .= ': ' . $message;
322 throw new Exception($details, $code);
326 $message = ts('We experienced an unexpected error. Please post a detailed description and the backtrace on the CiviCRM forums: %1', array(1 => 'http://forum.civicrm.org/'));
329 if (php_sapi_name() == "cli") {
330 print ("Sorry. A non-recoverable error has occurred.\n$message \n$code\n$email\n\n");
331 debug_print_backtrace();
333 // FIXME: Why doesn't this call abend()?
334 // Difference: abend() will cleanup transaction and (via civiExit) store session state
335 // self::abend(CRM_Core_Error::FATAL_ERROR);
338 $config = CRM_Core_Config
::singleton();
340 if ($config->fatalErrorHandler
&&
341 function_exists($config->fatalErrorHandler
)
343 $name = $config->fatalErrorHandler
;
346 // the call has been successfully handled
348 self
::abend(CRM_Core_Error
::FATAL_ERROR
);
352 if ($config->backtrace
) {
356 CRM_Core_Error
::debug_var('Fatal Error Details', $vars);
357 CRM_Core_Error
::backtrace('backTrace', TRUE);
359 // If we are in an ajax callback, format output appropriately
360 if (CRM_Utils_Array
::value('snippet', $_REQUEST) === CRM_Core_Smarty
::PRINT_JSON
) {
363 'content' => '<div class="messages status no-popup"><div class="icon inform-icon"></div>' . ts('Sorry but we are not able to provide this at the moment.') . '</div>',
365 if ($config->backtrace
&& CRM_Core_Permission
::check('view debug output')) {
366 $out['backtrace'] = self
::parseBacktrace(debug_backtrace());
367 $message .= '<p><em>See console for backtrace</em></p>';
369 CRM_Core_Session
::setStatus($message, ts('Sorry an Error Occured'), 'error');
370 CRM_Core_Transaction
::forceRollbackIfEnabled();
371 CRM_Core_Page_AJAX
::returnJsonResponse($out);
374 $template = CRM_Core_Smarty
::singleton();
375 $template->assign($vars);
377 $config->userSystem
->outputError($template->fetch($config->fatalErrorTemplate
));
379 self
::abend(CRM_Core_Error
::FATAL_ERROR
);
383 * Display an error page with an error message describing what happened
385 * This function is evil -- it largely replicates fatal(). Hopefully the
386 * entire CRM_Core_Error system can be hollowed out and replaced with
387 * something that follows a cleaner separation of concerns.
389 * @param Exception $exception
393 public static function handleUnhandledException($exception) {
395 CRM_Utils_Hook
::unhandledException($exception);
397 catch (Exception
$other) {
398 // if the exception-handler generates an exception, then that sucks! oh, well. carry on.
399 CRM_Core_Error
::debug_var('handleUnhandledException_nestedException', self
::formatTextException($other));
401 $config = CRM_Core_Config
::singleton();
403 'message' => $exception->getMessage(),
405 'exception' => $exception,
407 if (!$vars['message']) {
408 $vars['message'] = ts('We experienced an unexpected error. Please post a detailed description and the backtrace on the CiviCRM forums: %1', array(1 => 'http://forum.civicrm.org/'));
412 if (php_sapi_name() == "cli") {
413 printf("Sorry. A non-recoverable error has occurred.\n%s\n", $vars['message']);
414 print self
::formatTextException($exception);
416 // FIXME: Why doesn't this call abend()?
417 // Difference: abend() will cleanup transaction and (via civiExit) store session state
418 // self::abend(CRM_Core_Error::FATAL_ERROR);
421 // Case B: Custom error handler
422 if ($config->fatalErrorHandler
&&
423 function_exists($config->fatalErrorHandler
)
425 $name = $config->fatalErrorHandler
;
428 // the call has been successfully handled
430 self
::abend(CRM_Core_Error
::FATAL_ERROR
);
434 // Case C: Default error handler
437 CRM_Core_Error
::debug_var('Fatal Error Details', $vars);
438 CRM_Core_Error
::backtrace('backTrace', TRUE);
441 $template = CRM_Core_Smarty
::singleton();
442 $template->assign($vars);
443 $content = $template->fetch($config->fatalErrorTemplate
);
444 if ($config->backtrace
) {
445 $content = self
::formatHtmlException($exception) . $content;
447 if ($config->userFramework
== 'Joomla' &&
448 class_exists('JError')
450 JError
::raiseError('CiviCRM-001', $content);
453 echo CRM_Utils_System
::theme($content);
457 self
::abend(CRM_Core_Error
::FATAL_ERROR
);
461 * Outputs pre-formatted debug information. Flushes the buffers
462 * so we can interrupt a potential POST/redirect
464 * @param string $name name of debug section
465 * @param $variable mixed reference to variables that we need a trace of
466 * @param bool $log should we log or return the output
467 * @param bool $html whether to generate a HTML-escaped output
468 * @param bool $checkPermission should we check permissions before displaying output
469 * useful when we die during initialization and permissioning
470 * subsystem is not initialized - CRM-13765
473 * the generated output
475 public static function debug($name, $variable = NULL, $log = TRUE, $html = TRUE, $checkPermission = TRUE) {
476 $error = self
::singleton();
478 if ($variable === NULL) {
483 $out = print_r($variable, TRUE);
486 $out = htmlspecialchars($out);
488 $prefix = "<p>$name</p>";
490 $out = "{$prefix}<p><pre>$out</pre></p><p></p>";
494 $prefix = "$name:\n";
496 $out = "{$prefix}$out\n";
500 (!$checkPermission || CRM_Core_Permission
::check('view debug output'))
509 * Similar to the function debug. Only difference is
510 * in the formatting of the output.
512 * @param string $variable_name
513 * @param mixed $variable
515 * Should we use print_r ? (else we use var_dump).
517 * Should we log or return the output.
518 * @param string $comp
522 * the generated output
526 * @see CRM_Core_Error::debug()
527 * @see CRM_Core_Error::debug_log_message()
529 public static function debug_var(
536 // check if variable is set
537 if (!isset($variable)) {
538 $out = "\$$variable_name is not set";
542 $out = print_r($variable, TRUE);
543 $out = "\$$variable_name = $out";
549 $dump = ob_get_contents();
551 $out = "\n\$$variable_name = $dump";
553 // reset if it is an array
554 if (is_array($variable)) {
558 return self
::debug_log_message($out, FALSE, $comp);
562 * Display the error message on terminal
566 * Should we log or return the output.
568 * @param string $comp
569 * Message to be output.
571 * format of the backtrace
575 public static function debug_log_message($message, $out = FALSE, $comp = '') {
576 $config = CRM_Core_Config
::singleton();
578 $file_log = self
::createDebugLogger($comp);
579 $file_log->log("$message\n");
580 $str = "<p/><code>$message</code>";
581 if ($out && CRM_Core_Permission
::check('view debug output')) {
586 if ($config->userFrameworkLogging
) {
587 // should call $config->userSystem->logger($message) here - but I got a situation where userSystem was not an object - not sure why
588 if ($config->userSystem
->is_drupal
and function_exists('watchdog')) {
589 watchdog('civicrm', $message, NULL, WATCHDOG_DEBUG
);
597 * Append to the query log (if enabled)
599 public static function debug_query($string) {
600 if (defined('CIVICRM_DEBUG_LOG_QUERY')) {
601 if (CIVICRM_DEBUG_LOG_QUERY
== 'backtrace') {
602 CRM_Core_Error
::backtrace($string, TRUE);
604 elseif (CIVICRM_DEBUG_LOG_QUERY
) {
605 CRM_Core_Error
::debug_var('Query', $string, FALSE, TRUE);
611 * Execute a query and log the results.
613 * @param string $query
615 public static function debug_query_result($query) {
616 $dao = CRM_Core_DAO
::executeQuery($query);
618 while ($dao->fetch()) {
619 $results[] = (array) $dao;
621 CRM_Core_Error
::debug_var('dao result', array('query' => $query, 'results' => $results));
625 * Obtain a reference to the error log
627 * @param string $comp
631 public static function createDebugLogger($comp = '') {
632 $config = CRM_Core_Config
::singleton();
638 $fileName = "{$config->configAndLogDir}CiviCRM." . $comp . md5($config->dsn
) . '.log';
640 // Roll log file monthly or if greater than 256M
641 // note that PHP file functions have a limit of 2G and hence
642 // the alternative was introduce
643 if (file_exists($fileName)) {
644 $fileTime = date("Ym", filemtime($fileName));
645 $fileSize = filesize($fileName);
646 if (($fileTime < date('Ym')) ||
647 ($fileSize > 256 * 1024 * 1024) ||
651 $fileName . '.' . date('Ymdhs', mktime(0, 0, 0, date("m") - 1, date("d"), date("Y")))
656 return Log
::singleton('file', $fileName);
663 public static function backtrace($msg = 'backTrace', $log = FALSE) {
664 $backTrace = debug_backtrace();
665 $message = self
::formatBacktrace($backTrace);
667 CRM_Core_Error
::debug($msg, $message);
670 CRM_Core_Error
::debug_var($msg, $message);
675 * Render a backtrace array as a string
677 * @param array $backTrace
678 * Array of stack frames.
679 * @param bool $showArgs
680 * TRUE if we should try to display content of function arguments (which could be sensitive); FALSE to display only the type of each function argument.
681 * @param int $maxArgLen
682 * Maximum number of characters to show from each argument string.
684 * printable plain-text
686 public static function formatBacktrace($backTrace, $showArgs = TRUE, $maxArgLen = 80) {
688 foreach (self
::parseBacktrace($backTrace, $showArgs, $maxArgLen) as $idx => $trace) {
689 $message .= sprintf("#%s %s\n", $idx, $trace);
691 $message .= sprintf("#%s {main}\n", 1 +
$idx);
696 * Render a backtrace array as an array
698 * @param array $backTrace
699 * Array of stack frames.
700 * @param bool $showArgs
701 * TRUE if we should try to display content of function arguments (which could be sensitive); FALSE to display only the type of each function argument.
702 * @param int $maxArgLen
703 * Maximum number of characters to show from each argument string.
705 * @see debug_backtrace
706 * @see Exception::getTrace()
708 public static function parseBacktrace($backTrace, $showArgs = TRUE, $maxArgLen = 80) {
710 foreach ($backTrace as $trace) {
712 $fnName = CRM_Utils_Array
::value('function', $trace);
713 $className = isset($trace['class']) ?
($trace['class'] . $trace['type']) : '';
715 // Do not show args for a few password related functions
716 $skipArgs = ($className == 'DB::' && $fnName == 'connect') ?
TRUE : FALSE;
718 if (!empty($trace['args'])) {
719 foreach ($trace['args'] as $arg) {
720 if (!$showArgs ||
$skipArgs) {
721 $args[] = '(' . gettype($arg) . ')';
724 switch ($type = gettype($arg)) {
726 $args[] = $arg ?
'TRUE' : 'FALSE';
735 $args[] = '"' . CRM_Utils_String
::ellipsify(addcslashes((string) $arg, "\r\n\t\""), $maxArgLen) . '"';
739 $args[] = '(Array:' . count($arg) . ')';
743 $args[] = 'Object(' . get_class($arg) . ')';
747 $args[] = 'Resource';
763 CRM_Utils_Array
::value('file', $trace, '[internal function]'),
764 CRM_Utils_Array
::value('line', $trace, ''),
774 * Render an exception as HTML string
776 * @param Exception $e
778 * printable HTML text
780 public static function formatHtmlException(Exception
$e) {
783 // Exception metadata
785 // Exception backtrace
786 if ($e instanceof PEAR_Exception
) {
788 while (is_callable(array($ei, 'getCause'))) {
789 if ($ei->getCause() instanceof PEAR_Error
) {
790 $msg .= '<table class="crm-db-error">';
791 $msg .= sprintf('<thead><tr><th>%s</th><th>%s</th></tr></thead>', ts('Error Field'), ts('Error Value'));
793 foreach (array('Type', 'Code', 'Message', 'Mode', 'UserInfo', 'DebugInfo') as $f) {
794 $msg .= sprintf('<tr><td>%s</td><td>%s</td></tr>', $f, call_user_func(array($ei->getCause(), "get$f")));
796 $msg .= '</tbody></table>';
798 $ei = $ei->getCause();
800 $msg .= $e->toHtml();
803 $msg .= '<p><b>' . get_class($e) . ': "' . htmlentities($e->getMessage()) . '"</b></p>';
804 $msg .= '<pre>' . htmlentities(self
::formatBacktrace($e->getTrace())) . '</pre>';
810 * Write details of an exception to the log
812 * @param Exception $e
814 * printable plain text
816 public static function formatTextException(Exception
$e) {
817 $msg = get_class($e) . ": \"" . $e->getMessage() . "\"\n";
820 while (is_callable(array($ei, 'getCause'))) {
821 if ($ei->getCause() instanceof PEAR_Error
) {
822 foreach (array('Type', 'Code', 'Message', 'Mode', 'UserInfo', 'DebugInfo') as $f) {
823 $msg .= sprintf(" * ERROR %s: %s\n", strtoupper($f), call_user_func(array($ei->getCause(), "get$f")));
826 $ei = $ei->getCause();
828 $msg .= self
::formatBacktrace($e->getTrace());
835 * @param string $level
836 * @param array $params
840 public static function createError($message, $code = 8000, $level = 'Fatal', $params = NULL) {
841 $error = CRM_Core_Error
::singleton();
842 $error->push($code, $level, array($params), $message);
847 * Set a status message in the session, then bounce back to the referrer.
849 * @param string $status
850 * The status message to set.
852 * @param null $redirect
853 * @param string $title
856 public static function statusBounce($status, $redirect = NULL, $title = NULL) {
857 $session = CRM_Core_Session
::singleton();
859 $redirect = $session->readUserContext();
861 if ($title === NULL) {
862 $title = ts('Error');
864 $session->setStatus($status, $title, 'alert', array('expires' => 0));
865 if (CRM_Utils_Array
::value('snippet', $_REQUEST) === CRM_Core_Smarty
::PRINT_JSON
) {
866 CRM_Core_Page_AJAX
::returnJsonResponse(array('status' => 'error'));
868 CRM_Utils_System
::redirect($redirect);
872 * Reset the error stack
875 public static function reset() {
876 $error = self
::singleton();
877 $error->_errors
= array();
878 $error->_errorsByLevel
= array();
882 * PEAR error-handler which converts errors to exceptions
885 * @throws PEAR_Exception
887 public static function exceptionHandler($pearError) {
888 CRM_Core_Error
::backtrace('backTrace', TRUE);
889 throw new PEAR_Exception($pearError->getMessage(), $pearError);
893 * PEAR error-handler to quietly catch otherwise fatal errors. Intended for use with smtp transport.
896 * The PEAR_ERROR object.
900 public static function nullHandler($obj) {
901 CRM_Core_Error
::debug_log_message("Ignoring exception thrown by nullHandler: {$obj->code}, {$obj->message}");
902 CRM_Core_Error
::backtrace('backTrace', TRUE);
908 * This function is no longer used by v3 api.
909 * @fixme Some core files call it but it should be re-thought & renamed or removed
917 public static function &createAPIError($msg, $data = NULL) {
918 if (self
::$modeException) {
919 throw new Exception($msg, $data);
924 $values['is_error'] = 1;
925 $values['error_message'] = $msg;
927 $values = array_merge($values, $data);
935 public static function movedSiteError($file) {
936 $url = CRM_Utils_System
::url('civicrm/admin/setting/updateConfigBackend',
940 echo "We could not write $file. Have you moved your site directory or server?<p>";
941 echo "Please fix the setting by running the <a href=\"$url\">update config script</a>";
946 * Terminate execution abnormally
948 protected static function abend($code) {
949 // do a hard rollback of any pending transactions
950 // if we've come here, its because of some unexpected PEAR errors
951 CRM_Core_Transaction
::forceRollbackIfEnabled();
952 CRM_Utils_System
::civiExit($code);
956 * @param array $error
961 public static function isAPIError($error, $type = CRM_Core_Error
::FATAL_ERROR
) {
962 if (is_array($error) && !empty($error['is_error'])) {
963 $code = $error['error_message']['code'];
964 if ($code == $type) {
972 $e = new PEAR_ErrorStack('CRM');
973 $e->singleton('CRM', FALSE, NULL, 'CRM_Core_Error');