diff --git a/system/Exception/Throwable.php b/system/Exception/Throwable.php index 948ffc9..5a59a96 100644 --- a/system/Exception/Throwable.php +++ b/system/Exception/Throwable.php @@ -34,5 +34,8 @@ if (interface_exists('Throwable')) { */ interface Throwable extends ThrowableBase { + const DEFAULT_EXCEPTION_FILE = 'exception.log'; + + const DEFAULT_WEBEXCEPTION_FILE = 'web_exception.log'; } diff --git a/system/Exception/WebApiException.php b/system/Exception/WebApiException.php index eb195c7..a309305 100644 --- a/system/Exception/WebApiException.php +++ b/system/Exception/WebApiException.php @@ -41,6 +41,13 @@ class WebApiException extends \Phacil\Framework\Exception { const FAULT_CODE_SENDER = 'Sender'; const FAULT_CODE_RECEIVER = 'Receiver'; + /** + * @var \Phacil\Framework\Config + */ + private $config; + + protected $exceptionFile = \Phacil\Framework\Exception\Throwable::DEFAULT_WEBEXCEPTION_FILE; + /** * Construct the exception. Note: The message is NOT binary safe. * @@ -50,7 +57,14 @@ class WebApiException extends \Phacil\Framework\Exception { * @return void */ public function __construct($message = "", int $code = 400, $previous = null) { + /** @var \Phacil\Framework\Config */ + $this->config = \Phacil\Framework\Registry::getInstance(\Phacil\Framework\Config::class); parent::__construct((is_array($message) ? \Phacil\Framework\Json::encode($message) : $message), $code, $previous); } + public function __destruct() { + if($this->config->get('config_registry_webexceptions')) + parent::__destruct(); + } + } \ No newline at end of file diff --git a/system/engine/exception.php b/system/engine/exception.php index 219ea0a..547ef4e 100644 --- a/system/engine/exception.php +++ b/system/engine/exception.php @@ -24,6 +24,8 @@ class Exception extends \Exception implements \Phacil\Framework\Exception\Throwa protected $heritageTrace = false; + protected $exceptionFile = self::DEFAULT_EXCEPTION_FILE; + /** * * @param \Exception $object @@ -46,14 +48,26 @@ class Exception extends \Exception implements \Phacil\Framework\Exception\Throwa $debugging = (\Phacil\Framework\Config::DEBUG()) ?: false; $this->errorFormat = \Phacil\Framework\Config::DEBUG_FORMAT() ?: $this->errorFormat; - $log = new \Phacil\Framework\Log("exception.log"); + $log = new \Phacil\Framework\Log($this->exceptionFile); $errorStamp = [ - 'error' => $this->getMessage(), + 'message' => $this->getMessage(), 'line' => $this->getLine(), 'file' => $this->getFile(), 'trace' => ($debugging) ? (($this->errorFormat == 'json') ? ($this->heritageTrace ?: $this->getTrace()) : Debug::trace(($this->heritageTrace ?: $this->getTrace()))) : null ]; + + if($this->getCode() > 0) + $errorStamp['code'] = $this->getCode(); + + if($this->getCode() < 200 || $this->getCode() > 499) { + $log->critical(($this->errorFormat == 'json') ? json_encode($errorStamp) : implode(PHP_EOL, array_map( + [self::class, 'convertArray'], + $errorStamp, + array_keys($errorStamp) + ))); + return; + } $log->write(($this->errorFormat == 'json') ? json_encode($errorStamp) : implode(PHP_EOL, array_map( [self::class,'convertArray'], $errorStamp, diff --git a/system/engine/front.php b/system/engine/front.php index fb3816b..001ec3a 100644 --- a/system/engine/front.php +++ b/system/engine/front.php @@ -56,22 +56,26 @@ final class Front implements frontInterface { */ public function dispatch(\Phacil\Framework\Interfaces\Action $action, $error) { $this->error = $error; - - $this->registry->set('route', $action->getRoute()); - - foreach ($this->pre_action as $pre_action) { - $result = $this->execute($pre_action); - - if ($result) { - $action = $result; + try { + $this->registry->set('route', $action->getRoute()); - break; + foreach ($this->pre_action as $pre_action) { + $result = $this->execute($pre_action); + + if ($result) { + $action = $result; + + break; + } } + + while ($action) { + $action = $this->execute($action); + } + } catch (\Exception $th) { + throw $th; } - - while ($action) { - $action = $this->execute($action); - } + } /** @@ -100,6 +104,8 @@ final class Front implements frontInterface { } } catch (\Phacil\Framework\Exception\Throwable $th) { throw $th; + } catch (\Exception $e) { + throw ($e); } } @@ -108,6 +114,8 @@ final class Front implements frontInterface { $action = $this->callController($this->injectionClass($classAlt['class']), $method, $args); } catch (\Phacil\Framework\Exception\Throwable $th) { throw ($th); + } catch (\Exception $e) { + throw ($e); } }else { $action = new Action($this->error); @@ -138,7 +146,7 @@ final class Front implements frontInterface { } return $action; } catch (\Exception $th) { - throw new Exception($th->getMessage(), $th->getCode(), $th); + throw ($th); //throw $th; } } diff --git a/system/engine/log.php b/system/engine/log.php index 39adf93..e4d598b 100644 --- a/system/engine/log.php +++ b/system/engine/log.php @@ -347,11 +347,7 @@ class Log implements \Phacil\Framework\Api\Log { 'route' => \Phacil\Framework\startEngineExacTI::getRoute(), ]; - $trated = $this->logTreatment($record); - - $log = $this->interpolate($this->format, $trated); - - return $this->writeToFile($log); + return $this->writeToFile($this->interpolate($this->format, $this->logTreatment($record))); } /** diff --git a/system/engine/response.php b/system/engine/response.php index 78660aa..b3b0803 100644 --- a/system/engine/response.php +++ b/system/engine/response.php @@ -88,6 +88,10 @@ final class Response { $this->output = $output; } + public function setParcialOutput($output) { + $this->output .= ($output ?: ''); + } + /** * @param mixed $data * @param int $level @@ -140,9 +144,9 @@ final class Response { else header($key.": ".$header, true); - } catch (Exception $th) { + } catch (\Exception $th) { //throw $th; - throw new Exception("Error Processing Header ".$key, 1); + throw new Exception("Error Processing Header ".$key, 1, $th); } } @@ -168,4 +172,13 @@ final class Response { $this->addHeader("HTTP/1.1 ".$code.(($description) ? " ". $description : "")); $this->addHeader("Status: ".$code.""); } + + /** + * Clean all seted headers + * @return $this + */ + public function clearHeaders() { + $this->headers = []; + return $this; + } } \ No newline at end of file diff --git a/system/system.php b/system/system.php index 95ef812..0ab4923 100644 --- a/system/system.php +++ b/system/system.php @@ -15,6 +15,7 @@ namespace Phacil\Framework; * @package Phacil\Framework * @property \Phacil\Framework\Api\Database $db * @property \Phacil\Framework\Api\Log $log + * @property \Phacil\Framework\Config $config */ final class startEngineExacTI { @@ -190,7 +191,7 @@ final class startEngineExacTI { throw new \Exception("Can't load minimun config constants, please check your config file!"); } - } catch (Exception $e) { + } catch (\Exception $e) { exit($e->getMessage()); } @@ -243,7 +244,7 @@ final class startEngineExacTI { try { $tzc = @date_default_timezone_set($utc); if (!$tzc){ - throw new \ErrorException($utc. " not found in PHP Compiler."); + throw new \Phacil\Framework\Exception\ErrorException($utc. " not found in PHP Compiler."); } } catch (\ErrorException $e) { $trace = ($e->getTrace()); @@ -381,6 +382,11 @@ final class startEngineExacTI { $this->registry->set($key, $this->registry->create(\Phacil\Framework\Api\Log::class, [$this->config->get('config_error_filename')])); break; + case 'cache': + /** @var \Phacil\Framework\Caches */ + $this->registry->set($key, $this->registry->getInstance(\Phacil\Framework\Caches::class)); + break; + default: $objectToCreate = false; break; @@ -394,6 +400,59 @@ final class startEngineExacTI { return self::$instance->registry; } + /** @return null|array|string */ + public function isDeveloperMode() { + //return $this->config->get('config_developer_mode'); + return \Phacil\Framework\Config::DEBUG() && $this->config->get('config_error_display'); + } + + /** + * @param \Exception $e + * @return never + * @throws \ReflectionException + * @throws \Exception + * @throws \Phacil\Framework\Exception + */ + public function terminate(\Exception $e) + { + /** @var Response $response */ + $response = $this->registry->getInstance(\Phacil\Framework\Response::class); + $response->clearHeaders(); + $response->code(500); + $response->addHeader('Content-Type', 'text/plain'); + $response->setOutput(''); + if ($this->isDeveloperMode()) { + $response->addHeader('Content-Type', 'text/html'); + //$response->setBody($e); + $response->setParcialOutput(sprintf("%s", get_class($e)).PHP_EOL); + $response->setParcialOutput(sprintf("
%s", $e->getMessage()) . PHP_EOL); + //print_r(\Phacil\Framework\Debug::backtrace(true)); + $response->setParcialOutput(\Phacil\Framework\Debug::trace($e->getTrace(), true, true) . PHP_EOL); + + if($e->getPrevious()) { + $p = $e->getPrevious(); + $response->setParcialOutput(sprintf("%s", get_class($p)) . PHP_EOL); + $response->setParcialOutput(sprintf("
%s", $p->getMessage()) . PHP_EOL); + //print_r(\Phacil\Framework\Debug::backtrace(true)); + $response->setParcialOutput(\Phacil\Framework\Debug::trace($p->getTrace(), true, true) . PHP_EOL); + } + //print_r($e->getTraceAsString()); + } else { + $message = "An error has happened during application run. See exception log for details.\n"; + try { + if (!$this->registry) { + throw new \DomainException(); + } + $this->log->critical($e); + } catch (\Exception $e) { + $message .= "Could not write error message to log. Please use developer mode to see the message.\n"; + } + $response->setOutput($message); + } + $response->output(); + exit(1); + } + } /** @@ -401,186 +460,192 @@ final class startEngineExacTI { * */ $engine = startEngineExacTI::getInstance(); -// Registry -/** @var \Phacil\Framework\startEngineExacTI $engine */ -$engine->engine = $engine; +try { -// Loader -/** - * @var \Phacil\Framework\Interfaces\Loader - */ -$engine->load = $engine->getRegistry()->create(\Phacil\Framework\Interfaces\Loader::class, [$engine->registry]); + // Registry + /** @var \Phacil\Framework\startEngineExacTI $engine */ + $engine->engine = $engine; -// Config -/** @var Config */ -$engine->config = new Config(); + // Loader + /** + * @var \Phacil\Framework\Interfaces\Loader + */ + $engine->load = $engine->getRegistry()->create(\Phacil\Framework\Interfaces\Loader::class, [$engine->registry]); -// Exception Handler -set_exception_handler(function ($e) use (&$engine) { - if ($engine->config->get('config_error_display')) { - echo '
' . get_class($e) . ': ' . $e->getMessage() . ' in ' . str_replace(\Phacil\Framework\Config::DIR_APPLICATION(), '', $e->getFile()) . ' on line ' . $e->getLine() . '
'; - } + // Config + /** @var Config */ + $engine->config = $engine->getRegistry()->create(\Phacil\Framework\Config::class); - if (get_class($e) != 'Phacil\Framework\Exception') { - $exception = new \Phacil\Framework\Exception(); - $exception->setObject($e); - } + // Exception Handler + set_exception_handler(function ($e) use (&$engine) { + if ($engine->config->get('config_error_display')) { + echo '' . get_class($e) . ': ' . $e->getMessage() . ' in ' . str_replace(\Phacil\Framework\Config::DIR_APPLICATION(), '', $e->getFile()) . ' on line ' . $e->getLine() . '
'; + } + if (get_class($e) != 'Phacil\Framework\Exception') { + $exception = new \Phacil\Framework\Exception(); + $exception->setObject($e); + } - if ($engine->config->get('config_error_log')) { - $engine->log->write(get_class($e) . ': ' . $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine()); - } -}); - -if(\Phacil\Framework\Config::DB_DRIVER()) - $engine->db = $engine->getRegistry()->create(\Phacil\Framework\Api\Database::class, [ - \Phacil\Framework\Config::DB_DRIVER(), - \Phacil\Framework\Config::DB_HOSTNAME(), - \Phacil\Framework\Config::DB_USERNAME(), - \Phacil\Framework\Config::DB_PASSWORD(), - \Phacil\Framework\Config::DB_DATABASE() - ]); -// Settings -if(!empty($configs)){ - foreach ($configs as $key => $confValue) { - $engine->config->set($key, $confValue); + if ($engine->config->get('config_error_log')) { + $engine->log->write(get_class($e) . ': ' . $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine()); + } + }); + + if (\Phacil\Framework\Config::DB_DRIVER()) + $engine->db = $engine->getRegistry()->create(\Phacil\Framework\Api\Database::class, [ + \Phacil\Framework\Config::DB_DRIVER(), + \Phacil\Framework\Config::DB_HOSTNAME(), + \Phacil\Framework\Config::DB_USERNAME(), + \Phacil\Framework\Config::DB_PASSWORD(), + \Phacil\Framework\Config::DB_DATABASE() + ]); + + // Settings + if (!empty($configs)) { + foreach ($configs as $key => $confValue) { + $engine->config->set($key, $confValue); + } } -} -if(\Phacil\Framework\Config::USE_DB_CONFIG() === true) { + if (\Phacil\Framework\Config::USE_DB_CONFIG() === true) { - $query = (\Phacil\Framework\Config::CUSTOM_DB_CONFIG()) ? $engine->db->query(\Phacil\Framework\Config::CUSTOM_DB_CONFIG()) : $engine->db->query()->select()->from('settings')->orderBy('setting_id', \Phacil\Framework\MagiQL\Api\Syntax\OrderBy::ASC)->load(); + $query = (\Phacil\Framework\Config::CUSTOM_DB_CONFIG()) ? $engine->db->query(\Phacil\Framework\Config::CUSTOM_DB_CONFIG()) : $engine->db->query()->select()->from('settings')->orderBy('setting_id', \Phacil\Framework\MagiQL\Api\Syntax\OrderBy::ASC)->load(); - foreach ($query as $setting) { - if (!$setting['serialized']) { - $engine->config->set($setting['key'], $setting['value']); - } else { - $engine->config->set($setting['key'], unserialize($setting['value'])); + foreach ($query as $setting) { + if (!$setting['serialized']) { + $engine->config->set($setting['key'], $setting['value']); + } else { + $engine->config->set($setting['key'], unserialize($setting['value'])); + } } } -} -$engine->config->set('config_url', \Phacil\Framework\Config::HTTP_URL()); -$engine->config->set('config_ssl', \Phacil\Framework\Config::HTTPS_URL()); + $engine->config->set('config_url', \Phacil\Framework\Config::HTTP_URL()); + $engine->config->set('config_ssl', \Phacil\Framework\Config::HTTPS_URL()); -//timezone -if($engine->config->get('date_timezone')){ - $engine->setTimezone($engine->config->get('date_timezone')); -} + //timezone + if ($engine->config->get('date_timezone')) { + $engine->setTimezone($engine->config->get('date_timezone')); + } -// Site Title -if($engine->config->get('PatternSiteTitle') == true) { - define('PATTERSITETITLE', $engine->config->get('PatternSiteTitle')); -} else { - define('PATTERSITETITLE', false); -} + // Site Title + if ($engine->config->get('PatternSiteTitle') == true) { + define('PATTERSITETITLE', $engine->config->get('PatternSiteTitle')); + } else { + define('PATTERSITETITLE', false); + } -// Url -/** - * @var \Phacil\Framework\Interfaces\Url - */ -$engine->url = $engine->getRegistry()->create(\Phacil\Framework\Interfaces\Url::class, [ - $engine->config->get('config_url'), - $engine->config->get('config_use_ssl') ? $engine->config->get('config_ssl') : $engine->config->get('config_url') -]); - -// Log -if(!$engine->config->get('config_error_filename')){ - $engine->config->set('config_error_filename', 'error.log'); -} + // Url + /** + * @var \Phacil\Framework\Interfaces\Url + */ + $engine->url = $engine->getRegistry()->create(\Phacil\Framework\Interfaces\Url::class, [ + $engine->config->get('config_url'), + $engine->config->get('config_use_ssl') ? $engine->config->get('config_ssl') : $engine->config->get('config_url') + ]); -/** - * @var \Phacil\Framework\Api\Log - */ -//$engine->log = $engine->getRegistry()->create(\Phacil\Framework\Api\Log::class, [$engine->config->get('config_error_filename')]); - -// Error Handler -set_error_handler(function ($errno, $errstr, $errfile, $errline) use (&$engine){ - $showPrepend = false; - switch ($errno) { - case E_NOTICE: - case E_USER_NOTICE: - $error = 'Notice'; - $logFunction = 'notice'; - break; - case E_WARNING: - case E_USER_WARNING: - $error = 'Warning'; - $logFunction = 'warning'; - break; - case E_ERROR: - $error = 'Fatal Error'; - $logFunction = 'critical'; - break; - case E_USER_ERROR: - $error = 'Fatal Error'; - $logFunction = 'error'; - break; - case E_DEPRECATED: - case E_USER_DEPRECATED: - $error = 'Deprecated'; - $logFunction = 'warning'; - $showPrepend = true; - break; - default: - $error = $engine->constantName($errno, 'Core'); - $logFunction = 'write'; - $showPrepend = true; - break; + // Log + if (!$engine->config->get('config_error_filename')) { + $engine->config->set('config_error_filename', 'error.log'); } - if ($engine->config->get('config_error_display')) { - echo '' . $error . ': ' . $errstr . ' in ' . str_replace(\Phacil\Framework\Config::DIR_APPLICATION(), "", $errfile) . ' on line ' . $errline . '
'; - } + /** + * @var \Phacil\Framework\Api\Log + */ + //$engine->log = $engine->getRegistry()->create(\Phacil\Framework\Api\Log::class, [$engine->config->get('config_error_filename')]); + + // Error Handler + set_error_handler(function ($errno, $errstr, $errfile, $errline) use (&$engine) { + $showPrepend = false; + switch ($errno) { + case E_NOTICE: + case E_USER_NOTICE: + $error = 'Notice'; + $logFunction = 'notice'; + break; + case E_WARNING: + case E_USER_WARNING: + $error = 'Warning'; + $logFunction = 'warning'; + break; + case E_ERROR: + $error = 'Fatal Error'; + $logFunction = 'critical'; + break; + case E_USER_ERROR: + $error = 'Fatal Error'; + $logFunction = 'error'; + break; + case E_DEPRECATED: + case E_USER_DEPRECATED: + $error = 'Deprecated'; + $logFunction = 'warning'; + $showPrepend = true; + break; + default: + $error = $engine->constantName($errno, 'Core'); + $logFunction = 'write'; + $showPrepend = true; + break; + } - if ($engine->config->get('config_error_log')) { - $engine->log->$logFunction(($showPrepend ? $error . ': ' : '') . $errstr . ' in ' . $errfile . ' on line ' . $errline.' | Phacil '.$engine->version(). ' on PHP '.$engine->phpversion); - } + if ($engine->config->get('config_error_display')) { + echo '' . $error . ': ' . $errstr . ' in ' . str_replace(\Phacil\Framework\Config::DIR_APPLICATION(), "", $errfile) . ' on line ' . $errline . '
'; + } + + if ($engine->config->get('config_error_log')) { + $engine->log->$logFunction(($showPrepend ? $error . ': ' : '') . $errstr . ' in ' . $errfile . ' on line ' . $errline . ' | Phacil ' . $engine->version() . ' on PHP ' . $engine->phpversion); + } - return true; -}); + return true; + }); -// Session -$engine->session = $engine->getRegistry()->create(\Phacil\Framework\Session::class); + // Session + $engine->session = $engine->getRegistry()->create(\Phacil\Framework\Session::class); -/** - * Caches - * @var Caches - */ -$engine->cache = new Caches(); + /** + * Caches + * @var Caches + */ + //$engine->cache = new Caches(); -// Response -/** @var Response */ -$engine->response = $engine->registry->getInstance(\Phacil\Framework\Response::class); -$engine->response->addHeader('Content-Type: text/html; charset=utf-8'); + // Response + /** @var Response */ + $engine->response = $engine->registry->getInstance(\Phacil\Framework\Response::class); + $engine->response->addHeader('Content-Type', 'text/html; charset=utf-8'); -if($engine->config->get('config_compression')) - $engine->response->setCompression($engine->config->get('config_compression')); + if ($engine->config->get('config_compression')) + $engine->response->setCompression($engine->config->get('config_compression')); -// Custom registrations -$engine->extraRegistrations(); + // Custom registrations + $engine->extraRegistrations(); -// Front Controller -$frontController = new Front($engine->registry); + // Front Controller + $frontController = new Front($engine->registry); -// SEO URL's -$frontController->addPreAction(new Action((string) 'url/seo_url', [], \Phacil\Framework\Interfaces\Action::SYSTEM)); + // SEO URL's + $frontController->addPreAction(new Action((string) 'url/seo_url', [], \Phacil\Framework\Interfaces\Action::SYSTEM)); -//extraPreActions -if($engine->controllerPreActions()){ - foreach ($engine->controllerPreActions() as $action){ - $frontController->addPreAction(new Action($action)); + //extraPreActions + if ($engine->controllerPreActions()) { + foreach ($engine->controllerPreActions() as $action) { + $frontController->addPreAction(new Action($action)); + } } -} -// Router -$action = new Action(startEngineExacTI::getRoute()); + // Router + $action = new Action(startEngineExacTI::getRoute()); -// Dispatch -$not_found = \Phacil\Framework\Config::NOT_FOUND() ?: \Phacil\Framework\Config::NOT_FOUND('error/not_found'); -$frontController->dispatch($action, ($not_found)); + // Dispatch + $not_found = \Phacil\Framework\Config::NOT_FOUND() ?: \Phacil\Framework\Config::NOT_FOUND('error/not_found'); + $frontController->dispatch($action, ($not_found)); -// Output -$engine->response->output(); + // Output + $engine->response->output(); +} catch (\Exception $th) { + $engine->terminate($th); + //throw new \Exception($th->getMessage(), $th->getCode(), $th); +} \ No newline at end of file