/** * Listen to the render event * * @param MvcEvent $e */ public static function onRender(MvcEvent $e) { if (!$e->isError()) { return; } if (self::$acceptFilter != '*') { $headers = $e->getRequest()->getHeaders(); if (!$headers->has('Accept')) { return; } $match = $headers->get('Accept')->match(self::$acceptFilter); if (!$match || $match->getTypeString() == '*/*') { return; } } $model = $e->getResult(); if (!$model instanceof ModelInterface) { return; } $exception = $model->getVariable('exception'); if (!$exception instanceof Exception) { return; } $jsonModel = new JsonModel(array('api-problem' => new ApiProblem($exception->getCode(), $exception))); $e->setResult($jsonModel); $e->setViewModel($jsonModel); }
/** * Check access to module action * * @param MvcEvent $e * @return void */ public function checkAction(MvcEvent $e) { // Skip cache if error occurred if ($e->isError()) { return; } // Deny all access for close/maintenance if (!isset($this->options['check_close']) || false !== $this->options['check_close']) { if (Pi::config('site_close')) { $this->denyAccess($e); return; } } // Grant permission for admin if (Pi::service('permission')->isAdmin()) { return; } $section = $this->engine->section(); $routeMatch = $e->getRouteMatch(); $route = array('section' => $section, 'module' => $routeMatch->getParam('module'), 'controller' => $routeMatch->getParam('controller'), 'action' => $routeMatch->getparam('action')); // Skip module access check for system front section and admin login if ('system' == $route['module'] && ('front' == $section || in_array($route['controller'], array('login')))) { // Grant access permission to system home page and dashboard for all admins } elseif ('system' == $route['module'] && in_array($route['controller'], array('index', 'dashboard')) && Pi::service('user')->hasIdentity()) { // Check against module access } else { $moduleAccess = Pi::service('permission')->modulePermission($route['module']); if (!$moduleAccess) { $this->denyAccess($e); } } // Skip page access check if (empty($this->options['check_page'])) { return; } // Check controller exceptions for permission check $controller = $e->getTarget(); if ($controller instanceof AbstractController && method_exists($controller, 'permissionException')) { $exceptions = $controller->permissionException(); if ($exceptions) { // Skip check against controller if (is_bool($exceptions) && true === $exceptions) { return; } // Skip check against action if (in_array($route['action'], (array) $exceptions)) { return; } } } // Check action permission check against route $actionAccess = Pi::service('permission')->pagePermission($route); // Set up deny process if (false === $actionAccess) { $this->denyAccess($e); } return; }
/** * test acl on route * @param \Zend\Mvc\MvcEvent $event * @return void */ public function onRoute(MvcEvent $event) { if ($event->isError()) { return $event->getResult(); } $routeMatch = $event->getRouteMatch(); $routeName = $routeMatch->getMatchedRouteName(); $resourceId = "route/{$routeName}"; return $this->checkAcl($event, $resourceId); }
public function renderError(MvcEvent $e) { // must be an error if (!$e->isError()) { return; } $request = $e->getRequest(); if (!$request instanceof HttpRequest) { return; } // We ought to check for a JSON accept header here, except that we // don't need to as we only ever send back JSON. // If we have a JsonModel in the result, then do nothing $currentModel = $e->getResult(); if ($currentModel instanceof JsonModel) { return; } // Create a new JsonModel and populate with default error information $model = new JsonModel(); // Override with information from actual ViewModel $displayExceptions = true; if ($currentModel instanceof ModelInterface) { $model->setVariables($currentModel->getVariables()); if ($model->display_exceptions) { $displayExceptions = (bool) $data['display_exceptions']; } } // Check for exception $exception = $currentModel->getVariable('exception'); if ($exception && $displayExceptions) { // If a code was set in the Exception, then assume that it's the // HTTP Status code to be sent back to the client if ($exception->getCode()) { $e->getResponse()->setStatusCode($exception->getCode()); } // Should probably only render a backtrace this if in development mode! $model->backtrace = explode("\n", $exception->getTraceAsString()); // Assign the message & any previous ones $model->message = $exception->getMessage(); $previousMessages = array(); while ($exception = $exception->getPrevious()) { $previousMessages[] = "* " . $exception->getMessage(); } if (count($previousMessages)) { $exceptionString = implode("\n", $previousMessages); $model->previous_messages = $exceptionString; } } // Set the result and view model to our new JsonModel $model->setTerminal(true); $e->setResult($model); $e->setViewModel($model); }
protected function catchRestRouteErrors(MvcEvent $e) { $eventManager = $e->getApplication()->getEventManager(); //When render event occurs, check if there was an error $eventManager->attach(MvcEvent::EVENT_RENDER, function ($e) use($eventManager) { //if it wasn't an error, we don't care if (!$e->isError()) { return; } //using $this in lambda works on php>=5.4 return $this->displayRestError($e, $eventManager); }); }
/** * Listen to the render event * * @param MvcEvent $e */ public static function onRender(MvcEvent $e) { // only worried about error pages if (!$e->isError()) { return; } // and then, only if we have an Accept header... $request = $e->getRequest(); if (!$request instanceof HttpRequest) { return; } $headers = $request->getHeaders(); if (!$headers->has('Accept')) { return; } // ... that matches certain criteria $accept = $headers->get('Accept'); $match = $accept->match(self::$acceptFilter); if (!$match || $match->getTypeString() == '*/*') { return; } // Next, do we have a view model in the result? // If not, nothing more to do. $model = $e->getResult(); if (!$model instanceof ModelInterface) { return; } // Marshall the information we need for the API-Problem response $httpStatus = $e->getResponse()->getStatusCode(); $exception = $model->getVariable('exception'); if ($exception instanceof \Exception) { $apiProblem = new ApiProblem($httpStatus, $exception); } else { $apiProblem = new ApiProblem($httpStatus, $model->getVariable('message')); } // Create a new model with the API-Problem payload, and reset // the result and view model in the event using it. $model = new RestfulJsonModel(array('payload' => $apiProblem)); $model->setTerminal(true); $e->setResult($model); $e->setViewModel($model); }
/** * Logging audit trail * * @param MvcEvent $e * @return void */ public function log(MvcEvent $e) { // Skip if error occured if (!empty($this->options['skipError']) && $e->isError()) { return; } // Skip if response not OK $response = $e->getResponse(); if ($response instanceof Response && !$response->isOk()) { return; } // Skip if not required method if (!empty($this->options['methods'])) { $method = $e->getRequest()->getMethod(); if (!in_array($method, $this->options['methods'])) { return; } } $message = $e->getRequest()->isPost() ? $e->getRequest()->toString() : $e->getRequest()->getRequestUri(); Pi::service('log')->audit($message); }
/** * @param MvcEvent $event * @return mixed */ public function requireSsl(MvcEvent $event) { $config = $event->getApplication()->getConfig(); if (false === $config['uthando_common']['ssl']) { return; } $request = $event->getRequest(); if (!$request instanceof Request) { return; } if ($event->isError() && $event->getError() === MvcApplication::ERROR_ROUTER_NO_MATCH) { // No matched route has been found - don't do anything return; } $match = $event->getRouteMatch(); $params = $match->getParams(); /** * If we have a route that defines 'force-ssl' prefer that instruction above * anything else and redirect if appropriate * * Possible values of 'force-ssl' param are: * 'ssl' : Force SSL * 'http' : Force Non-SSL */ if (isset($params['force-ssl'])) { $force = strtolower($params['force-ssl']); $response = $event->getResponse(); $uri = $request->getUri(); if ('ssl' === $force && 'http' === $uri->getScheme()) { $uri->setScheme('https'); return self::redirect($uri, $response); } if ('http' === $force && 'https' === $uri->getScheme()) { $uri->setScheme('http'); return self::redirect($uri, $response); } } return; }
public function onError(MvcEvent $event) { // if error has been removed if ($event->isError() == false) { return; } $locator = $event->getApplication()->getServiceManager(); /* @var $errorService \BitWeb\ErrorReporting\Service\ErrorService */ $errorService = $locator->get('BitWeb\\ErrorReporting\\Service\\ErrorService'); $exception = $event->getParam('exception'); $error = $event->getError(); $stopPropagation = false; if ($exception instanceof \Exception) { $errorService->errors[] = $exception; if ($exception instanceof \PDOException) { $stopPropagation = true; } } elseif ($error != null) { $errorService->errors[] = new RouterNoMatchException(sprintf('%1$s, %2$s', $error, $event->getControllerClass())); } if ($stopPropagation) { $this->onFinishAfterPostDispatch($event); } }
/** * Determine if we have a valid error event * * @param MvcEvent $e * @return bool */ protected function validateErrorEvent(MvcEvent $e) { // only worried about error pages if (!$e->isError()) { return false; } // and then, only if we have an Accept header... $request = $e->getRequest(); if (!$request instanceof HttpRequest) { return false; } $headers = $request->getHeaders(); if (!$headers->has('Accept')) { return false; } // ... that matches certain criteria $accept = $headers->get('Accept'); if (!$this->matchAcceptCriteria($accept)) { return false; } return true; }
/** * Save action content to cache * * @param MvcEvent $e * @return void */ public function saveAction(MvcEvent $e) { // Skip cache if error occurred if ($e->isError()) { return; } $cacheMeta = $this->cacheMeta($e, 'action'); // Skip if not action cache if ('action' != $cacheMeta['type']) { return; } if (!$this->renderCache()->isOpened()) { return; } $response = $e->getResponse(); // Skip if response not OK if ($response instanceof Response && !$response->isOk()) { return; } $response = $e->getResult(); $data = array('variables' => array(), 'template' => '', 'options' => array()); if ($response instanceof ViewModel) { $variables = (array) $response->getVariables(); if (!$this->isCachable($variables)) { trigger_error('Action content is not cachable.', E_USER_WARNING); return; } $data = array('variables' => $variables, 'template' => $response->getTemplate(), 'options' => $response->getOptions()); //$content = Pi::service('view')->render($response); } elseif (is_scalar($response)) { $data['variables']['content'] = $response; } else { $data['variables'] = $response; //return; } //vd($content); exit; $this->renderCache()->saveCache(json_encode($data)); $this->renderCache()->isOpened(false); return; }
/** * Determine if we have a valid error event * * @param MvcEvent $e * @return bool */ protected function validateErrorEvent(MvcEvent $e) { // only worried about error pages if (!$e->isError()) { return false; } // and then, only if we have an Accept header... $request = $e->getRequest(); if (!$request instanceof HttpRequest) { return false; } return true; }
/** * Canonize layout template for theme * * @param MvcEvent $e * @return void */ public function canonizeThemeLayout(MvcEvent $e) { $result = $e->getResult(); if ($result instanceof Response) { return; } $viewModel = $e->getViewModel(); // Skip for JsonModel/FeedModel which do not need template if (!$viewModel instanceof ViewModel || $viewModel instanceof JsonModel || $viewModel instanceof FeedMode) { return; } // Fetch service configuration $config = $e->getApplication()->getServiceManager()->get('Config'); $viewConfig = $config['view_manager']; // Specify AJAX layout if ('ajax' == $this->type) { $viewModel->setTemplate(isset($viewConfig['layout_ajax']) ? $viewConfig['layout_ajax'] : 'layout-content'); // Specify error page layout } elseif ($e->isError()) { $viewModel->setTemplate(isset($viewConfig['layout_error']) ? $viewConfig['layout_error'] : 'layout-style'); } }
/** * Render JSON response on Error * * @param MvcEvent $e */ public function onRenderError(MvcEvent $e) { // must be an error if (!$e->isError()) { return; } // if we have a JsonModel in the result, then do nothing $currentModel = $e->getResult(); if ($currentModel instanceof JsonModel) { return; } // create a new JsonModel - use application/api-problem+json fields. /** * * @var Response $response */ $response = $e->getResponse(); /** @var \Exception $exception */ $exception = $e->getParam('exception'); // Create a new ViewModel $model = new JsonModel(array("httpStatus" => $exception ? $exception->getCode() : ($response instanceof Response ? $response->getStatusCode() : 500), "title" => $e->getError())); if ($exception && $exception instanceof ValidationException) { $model->httpStatus = $exception->getCode(); if ($response instanceof Response) { $response->setStatusCode($model->httpStatus); } $model->title = 'validation-exception'; //We can have many validation errors $model->validationMessages = $exception instanceof ValidationException ? $exception->getMessages() : $exception->getMessage(); } // Add a detailed info about the error, if it exists if (isset($_SERVER['APPLICATION_ENV']) && $_SERVER['APPLICATION_ENV'] === 'development' && $e->getError()) { switch ($e->getError()) { case 'error-controller-cannot-dispatch': $model->detail = 'The requested controller was unable to dispatch the request.'; break; case 'error-controller-not-found': $model->detail = 'The requested controller could not be mapped to an existing controller class.'; break; case 'error-controller-invalid': $model->detail = 'The requested controller was not dispatchable.'; break; case 'error-router-no-match': $model->detail = 'The requested URL could not be matched by routing.'; break; default: $model->title = get_class($exception); $model->detail = ['message' => $exception instanceof ValidationException ? $exception->getMessages() : $exception->getMessage(), 'file' => $exception->getFile(), 'line' => $exception->getLine()]; break; } } // set our new view model $model->setTerminal(true); $e->setResult($model); $e->setViewModel($model); }
/** * Handle exceptions * * @param MvcEvent $event */ public function handleExceptions(MvcEvent $event) { $logger = $this->logger; // check if event is error if (!$event->isError()) { return; } // get message and exception (if present) $message = $event->getError(); $exception = $event->getParam('exception'); if (!$exception) { return; } // generate unique reference for this error $chars = md5(uniqid('', true)); $errorReference = substr($chars, 2, 2) . substr($chars, 12, 2) . substr($chars, 26, 2); // add it to logger extra array $extras = array('reference' => $errorReference); // check if event has exception and populate extras array. if (!empty($exception)) { $stackTrace = array(); $currentTrace = new \stdClass(); $currentTrace->class = get_class($exception); $currentTrace->file = $exception->getFile(); $currentTrace->message = $exception->getMessage(); $currentTrace->stackTrace = $exception->getTraceAsString(); $stackTrace[] = $currentTrace; //$stackTrace[] = $exception->getTraceAsString(); $e = $exception->getPrevious(); if ($e instanceof \Exception) { while ($e) { $currentTrace = new \stdClass(); $currentTrace->class = get_class($e); $currentTrace->file = $e->getFile(); $currentTrace->message = $e->getMessage(); $currentTrace->stackTrace = $e->getTraceAsString(); $stackTrace[] = $currentTrace; $e = $e->getPrevious(); } } $exceptionBody = ''; $i = 0; foreach ($stackTrace as $trace) { if ($i == 1) { $exceptionBody .= PHP_EOL . PHP_EOL . 'Previous Exceptions' . PHP_EOL . PHP_EOL; } $i++; $exceptionBody .= PHP_EOL . $trace->class . PHP_EOL; $exceptionBody .= PHP_EOL . 'File:' . PHP_EOL . $trace->file . PHP_EOL; $exceptionBody .= PHP_EOL . 'Message:' . PHP_EOL . $trace->message . PHP_EOL; $exceptionBody .= PHP_EOL . 'Stack trace:' . PHP_EOL . $trace->stackTrace . PHP_EOL; } $extras['trace'] = $exceptionBody; } // log it $priority = Logger::ERR; $logger->log($priority, $message, $extras); // hijack skeleton error view and add error reference to the message $originalMessage = $event->getResult()->getVariable('message'); $event->getResult()->setVariable('message', $originalMessage . '<br /> Error Reference: ' . $errorReference); }
/** * @param MvcEvent $event */ public function dispatchError(MvcEvent $event) { $exception = $event->getParam('exception'); while ($exception) { $this->logger->critical('EVENT_DISPATCH_ERROR: ' . $exception->getMessage(), $exception->getTrace()); $exception = $exception->getPrevious(); } if ($event->isError() == true && $event->getError() == Application::ERROR_EXCEPTION) { $this->logger->critical('EVENT_DISPATCH_ERROR: ' . $event->getError()); } }
public function onBootstrap(MvcEvent $event) { $eventManager = $event->getApplication()->getEventManager(); $oauth2Closure = $event->getApplication()->getServiceManager()->get(\ZF\OAuth2\Service\OAuth2Server::class); $logger = $event->getApplication()->getServiceManager()->get('logger'); $eventManager->attach(MvcAuthEvent::EVENT_AUTHENTICATION_POST, function (MvcAuthEvent $event) use($oauth2Closure) { // Manipulating Identity Data $identity = $event->getIdentity(); if (!!$identity) { if ($identity instanceof AuthenticatedIdentity) { $userData = $oauth2Closure()->getStorage('user_credentials')->getUser($identity->getName()); if (is_array($identity->getAuthenticationIdentity())) { $userData = array_merge($userData, $identity->getAuthenticationIdentity()); } $identity = new AuthenticatedIdentity($userData); $event->setIdentity($identity); } //MvcEvent did not understand when manipulated MvcAuthEvent identity $event->getMvcEvent()->setParam('ZF\\MvcAuth\\Identity', $identity); } return $event; }, 900); $moduleRouteListener = new ModuleRouteListener(); $moduleRouteListener->attach($eventManager); $event->getApplication()->getEventManager()->attach(MvcEvent::EVENT_DISPATCH_ERROR, function (MvcEvent $event) use($logger) { $problem = null; if ($event->isError()) { $exception = $event->getParam("exception"); // There are some other errors like that : // "error-controller-cannot-dispatch", // "error-controller-invalid", // "error-controller-not-found", // "error-router-no-match", if ($event->getError() === 'error-controller-not-found') { $problem = new ApiProblem(404, "Endpoint controller not found!"); } elseif ($event->getError() === 'error-router-no-match') { $problem = new ApiProblem(404, "Not found!"); } elseif ($exception instanceof \Exception) { $className = explode('\\', get_class($exception)); $problem = new ApiProblem($exception->getCode(), end($className) . ' error.'); $logger->err($exception->getMessage(), array('controller' => $event->getControllerClass())); } } else { $problem = new ApiProblem(500, "Unknown Error!"); } $response = new ApiProblemResponse($problem); $event->stopPropagation(); return $response; }, 9000); }