From 0291136dd13124f11ea2c1d9261ea0e8a21f538f Mon Sep 17 00:00:00 2001 From: Taras Machyshyn Date: Wed, 30 Apr 2014 16:34:56 +0300 Subject: [PATCH 1/2] added displaing error code for entry point --- application/Espo/Core/Application.php | 2 +- application/Espo/Core/Utils/Api/Output.php | 75 +++++++++++++------ application/Espo/Core/Utils/Api/Slim.php | 85 ++++++++++++---------- 3 files changed, 98 insertions(+), 64 deletions(-) diff --git a/application/Espo/Core/Application.php b/application/Espo/Core/Application.php index b2c90048da..3ea24d2aad 100644 --- a/application/Espo/Core/Application.php +++ b/application/Espo/Core/Application.php @@ -113,7 +113,7 @@ class Application try { $entryPointManager->run($entryPoint); } catch (\Exception $e) { - $container->get('output')->processError($e->getMessage(), $e->getCode()); + $container->get('output')->processError($e->getMessage(), $e->getCode(), true); } }); diff --git a/application/Espo/Core/Utils/Api/Output.php b/application/Espo/Core/Utils/Api/Output.php index 0b25c31885..8955f25f62 100644 --- a/application/Espo/Core/Utils/Api/Output.php +++ b/application/Espo/Core/Utils/Api/Output.php @@ -18,7 +18,7 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ namespace Espo\Core\Utils\Api; @@ -26,11 +26,20 @@ class Output { private $slim; + protected $errorDesc = array( + 400 => 'Bad Request', + 401 => 'Unauthorized', + 403 => 'Forbidden', + 404 => 'Page Not Found', + 409 => 'Conflict', + 500 => 'Internal Server Error', + ); - public function __construct(\Espo\Core\Utils\Api\Slim $slim) - { - $this->slim = $slim; - } + + public function __construct(\Espo\Core\Utils\Api\Slim $slim) + { + $this->slim = $slim; + } protected function getSlim() { @@ -38,53 +47,73 @@ class Output } /** - * Output the result + * Output the result * * @param mixed $data - JSON */ - public function render($data = null) + public function render($data = null) { - if (is_array($data)) { - $dataArr = array_values($data); - $data = empty($dataArr[0]) ? false : $dataArr[0]; - } + if (is_array($data)) { + $dataArr = array_values($data); + $data = empty($dataArr[0]) ? false : $dataArr[0]; + } ob_clean(); - echo $data; + echo $data; } - - public function processError($message = 'Error', $code = 500) + + public function processError($message = 'Error', $code = 500, $isPrint = false) { $GLOBALS['log']->error('API ['.$this->getSlim()->request()->getMethod().']:'.$this->getSlim()->router()->getCurrentRoute()->getPattern().', Params:'.print_r($this->getSlim()->router()->getCurrentRoute()->getParams(), true).', InputData: '.$this->getSlim()->request()->getBody().' - '.$message); - $this->displayError($message, $code); - - ob_clean(); - echo $data; - $this->getSlim()->stop(); + $this->displayError($message, $code, $isPrint); } /** - * Output the error and stop app execution + * Output the error and stop app execution * * @param string $text * @param int $statusCode * * @return void */ - public function displayError($text, $statusCode = 500) + public function displayError($text, $statusCode = 500, $isPrint = false) { - $GLOBALS['log']->info('Display Error: '.$text.', Code: '.$statusCode.' URL: '.$_SERVER['REQUEST_URI']); + $GLOBALS['log']->error('Display Error: '.$text.', Code: '.$statusCode.' URL: '.$_SERVER['REQUEST_URI']); if (!empty( $this->slim)) { $this->getSlim()->response()->status($statusCode); $this->getSlim()->response()->header('X-Status-Reason', $text); + + if ($isPrint) { + $status = $this->getCodeDesc($statusCode); + $status = isset($status) ? $statusCode.' '.$status : 'HTTP '.$statusCode; + $this->getSlim()->printError($text, $status); + } + $this->getSlim()->stop(); - } + } else { $GLOBALS['log']->info('Could not get Slim instance. It looks like a direct call (bypass API). URL: '.$_SERVER['REQUEST_URI']); die($text); } } + /** + * Get status code desription + * + * @param int $statusCode + * @return string | null + */ + protected function getCodeDesc($statusCode) + { + if (isset($this->errorDesc[$statusCode])) { + return $this->errorDesc[$statusCode]; + } + + return null; + } + + + } diff --git a/application/Espo/Core/Utils/Api/Slim.php b/application/Espo/Core/Utils/Api/Slim.php index 54e9abbda4..b91d4acda8 100644 --- a/application/Espo/Core/Utils/Api/Slim.php +++ b/application/Espo/Core/Utils/Api/Slim.php @@ -18,7 +18,7 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ namespace Espo\Core\Utils\Api; @@ -27,54 +27,59 @@ class Slim extends \Slim\Slim { /** - * Redefine the run method - * - * We no need to use a Slim handler - */ + * Redefine the run method + * + * We no need to use a Slim handler + */ public function run() - { - //set_error_handler(array('\Slim\Slim', 'handleErrors')); //Espo: no needs to use this handler + { + //set_error_handler(array('\Slim\Slim', 'handleErrors')); //Espo: no needs to use this handler - //Apply final outer middleware layers - if ($this->config('debug')) { - //Apply pretty exceptions only in debug to avoid accidental information leakage in production - //$this->add(new \Slim\Middleware\PrettyExceptions()); //Espo: no needs to use this handler - } + //Apply final outer middleware layers + if ($this->config('debug')) { + //Apply pretty exceptions only in debug to avoid accidental information leakage in production + //$this->add(new \Slim\Middleware\PrettyExceptions()); //Espo: no needs to use this handler + } - //Invoke middleware and application stack - $this->middleware[0]->call(); + //Invoke middleware and application stack + $this->middleware[0]->call(); - //Fetch status, header, and body - list($status, $headers, $body) = $this->response->finalize(); + //Fetch status, header, and body + list($status, $headers, $body) = $this->response->finalize(); - // Serialize cookies (with optional encryption) - \Slim\Http\Util::serializeCookies($headers, $this->response->cookies, $this->settings); + // Serialize cookies (with optional encryption) + \Slim\Http\Util::serializeCookies($headers, $this->response->cookies, $this->settings); - //Send headers - if (headers_sent() === false) { - //Send status - if (strpos(PHP_SAPI, 'cgi') === 0) { - header(sprintf('Status: %s', \Slim\Http\Response::getMessageForCode($status))); - } else { - header(sprintf('HTTP/%s %s', $this->config('http.version'), \Slim\Http\Response::getMessageForCode($status))); - } + //Send headers + if (headers_sent() === false) { + //Send status + if (strpos(PHP_SAPI, 'cgi') === 0) { + header(sprintf('Status: %s', \Slim\Http\Response::getMessageForCode($status))); + } else { + header(sprintf('HTTP/%s %s', $this->config('http.version'), \Slim\Http\Response::getMessageForCode($status))); + } - //Send headers - foreach ($headers as $name => $value) { - $hValues = explode("\n", $value); - foreach ($hValues as $hVal) { - header("$name: $hVal", false); - } - } - } + //Send headers + foreach ($headers as $name => $value) { + $hValues = explode("\n", $value); + foreach ($hValues as $hVal) { + header("$name: $hVal", false); + } + } + } - //Send body, but only if it isn't a HEAD request - if (!$this->request->isHead()) { - echo $body; - } + //Send body, but only if it isn't a HEAD request + if (!$this->request->isHead()) { + echo $body; + } - //restore_error_handler(); - } + //restore_error_handler(); //Espo: no needs to use this handler + } + + public function printError($error, $status) + { + echo static::generateTemplateMarkup($status, '

'.$error.'

Visit the Home Page'); + } } \ No newline at end of file From 7354f640da1de11863d7fc23833d9ca881de6af1 Mon Sep 17 00:00:00 2001 From: Taras Machyshyn Date: Wed, 30 Apr 2014 18:14:10 +0300 Subject: [PATCH 2/2] Prune error length for logger --- .../Log/Monolog/Handler/StreamHandler.php | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/application/Espo/Core/Utils/Log/Monolog/Handler/StreamHandler.php b/application/Espo/Core/Utils/Log/Monolog/Handler/StreamHandler.php index d543a83fe8..e611a7be49 100644 --- a/application/Espo/Core/Utils/Log/Monolog/Handler/StreamHandler.php +++ b/application/Espo/Core/Utils/Log/Monolog/Handler/StreamHandler.php @@ -28,6 +28,8 @@ class StreamHandler extends \Monolog\Handler\StreamHandler { protected $fileManager; + protected $maxErrorMessageLength = 5000; + public function __construct($url, $level = Logger::DEBUG, $bubble = true) { parent::__construct($url, $level, $bubble); @@ -50,7 +52,7 @@ class StreamHandler extends \Monolog\Handler\StreamHandler $this->errorMessage = null; set_error_handler(array($this, 'customErrorHandler')); - $this->getFileManager()->appendContents($this->url, (string) $record['formatted']); + $this->getFileManager()->appendContents($this->url, $this->pruneMessage($record)); restore_error_handler(); if (isset($this->errorMessage)) { @@ -63,4 +65,22 @@ class StreamHandler extends \Monolog\Handler\StreamHandler $this->errorMessage = $msg; } + /** + * Cut the error message depends on maxErrorMessageLength + * + * @param array $record + * @return string + */ + protected function pruneMessage(array $record) + { + $message = (string) $record['message']; + + if (strlen($message) > $this->maxErrorMessageLength) { + $record['message'] = substr($message, 0, $this->maxErrorMessageLength) . '...'; + $record['formatted'] = $this->getFormatter()->format($record); + } + + return (string) $record['formatted']; + } + } \ No newline at end of file