/** * Handles a thrown exception. Will also log extra information if the exception happens to by a MySql deadlock. * * @param \Exception $exception The exception captured. * * @return null */ protected function handleException($exception) { // Do some logging. if ($exception instanceof \HttpException) { $status = $exception->status ? $exception->{$status} : ''; Craft::log(($status ? $status . ' - ' : '') . $exception->getMessage(), LogLevel::Warning); } else { if ($exception instanceof \Twig_Error) { Craft::log($exception->getRawMessage(), LogLevel::Error); } else { Craft::log($exception->getMessage(), LogLevel::Error); } } // Log MySQL deadlocks if ($exception instanceof \CDbException && strpos($exception->getMessage(), 'Deadlock') !== false) { $data = craft()->db->createCommand('SHOW ENGINE INNODB STATUS')->query(); $info = $data->read(); $info = serialize($info); Craft::log('Deadlock error, innodb status: ' . $info, LogLevel::Error, 'system.db.CDbCommand'); } // If this is a Twig Runtime exception, use the previous one instead if ($exception instanceof \Twig_Error_Runtime) { if ($previousException = $exception->getPrevious()) { $exception = $previousException; } } // Special handling for Twig syntax errors if ($exception instanceof \Twig_Error) { $this->handleTwigError($exception); } else { if ($exception instanceof DbConnectException) { $this->handleDbConnectionError($exception); } else { parent::handleException($exception); } } }
/** * The __toString method isn't allowed to throw exceptions so we turn them into an error instead * * @param \Exception $e * * @return string */ private function handleException(\Exception $e) { trigger_error($e->getMessage() . "\n" . $e->getTraceAsString(), E_USER_WARNING); if ($e instanceof \Twig_Error) { return '<strong>' . $e->getRawMessage() . '</strong>'; } return ''; }
/** * Mask actual exception for security reasons in case when it should not be exposed to API clients. * * Convert any exception into \Magento\Webapi\Exception. * * @param \Exception $exception Exception to convert to a WebAPI exception * * @return WebapiException */ public function maskException(\Exception $exception) { $isDevMode = $this->_appState->getMode() === State::MODE_DEVELOPER; $stackTrace = $isDevMode ? $exception->getTraceAsString() : null; if ($exception instanceof LocalizedException) { // Map HTTP codes for LocalizedExceptions according to exception type if ($exception instanceof NoSuchEntityException) { $httpCode = WebapiException::HTTP_NOT_FOUND; } elseif ($exception instanceof AuthorizationException || $exception instanceof AuthenticationException) { $httpCode = WebapiException::HTTP_UNAUTHORIZED; } else { // Input, Expired, InvalidState exceptions will fall to here $httpCode = WebapiException::HTTP_BAD_REQUEST; } if ($exception instanceof AbstractAggregateException) { $errors = $exception->getErrors(); } else { $errors = null; } $maskedException = new WebapiException($exception->getRawMessage(), $exception->getCode(), $httpCode, $exception->getParameters(), get_class($exception), $errors, $stackTrace); } elseif ($exception instanceof WebapiException) { $maskedException = $exception; } else { $message = $exception->getMessage(); $code = $exception->getCode(); //if not in Dev mode, make sure the message and code is masked for unanticipated exceptions if (!$isDevMode) { /** Log information about actual exception */ $reportId = $this->_critical($exception); $message = sprintf(self::INTERNAL_SERVER_ERROR_MSG, $reportId); $code = 0; } $maskedException = new WebapiException($message, $code, WebapiException::HTTP_INTERNAL_ERROR, [], '', null, $stackTrace); } return $maskedException; }