Yii2 : How to Customize Error Pages like 404 and 503 - php

I have following config of errorHandler
'errorHandler' => [
'errorAction' => 'page/error',
],
In the Controller page, in the Action error I want to check, that I got 404 error "page not found"?
How can I check it?

If you are trying to customize an Error page and want to get the errors code separately inside the view then you have the $exception,$name and $message variables available inside the view, but in case if you use yii\web\ErrorAction, before I go ahead you need to see in which category you fall.
CASE 1 Using \yii\web\ErrorAction
Inside your PageController you should have an actions() function like below.
public function actions() {
return [
'error' => [
'class' => 'yii\web\ErrorAction' ,
]
];
}
If you haven't created a separate layout for error add one now, it better to keep your error layout separate. Just copy the layouts/main.php and remove all extra CSS and js files or create frontend/assets/ErrorAsset.php and register on top of your layout file.
Add beforeAction() function inside your PageController like below.
Sample Code
public function beforeAction( $action ) {
if ( parent::beforeAction ( $action ) ) {
//change layout for error action after
//checking for the error action name
//so that the layout is set for errors only
if ( $action->id == 'error' ) {
$this->layout = 'error';
}
return true;
}
}
Now as you have specified the 'page/error' inside your errorHandler component's config so the action name would be error and so would be the view file, this view file should be inside the page folder this should be the path page/error.php. You have the $exception variable available which holds the exception object in your case yii\web\NotFoundHttpException Object. and you can call $exception->statusCode to check which status code has been thrown for the exception, in your case, it would show 404.
CASE 2 Using Custom Action for displaying Errors
Another Way is to use custom action inside the controller rather than using the yii\web\ErrorAction in that case you do not need to add the actions() function and inside your custom error function you should call
$exception = Yii::$app->getErrorHandler()->exception;
and use the $exception->statusCode. Make sure you check for the exact action name for inside your beforeAction() function change your check accordingly for the line
if ( $action->id == 'error' ) {
CASE 3 SHUTUP just Give me the Exception
If you don't want any of above and just want to check the Exception code inside the controller's beforeAction() you have to access the same exception object above but with a shorthand via config's erorHandler component.
public function beforeAction($action) {
$exception = Yii::$app->getErrorHandler()->exception;
if(parent::beforeAction($action)) {
$hasError = $action->id == 'error' && $exception !== NULL;
if($hasError) {
echo $exception->statusCode;
return false;
}
}
return true;
}

Related

How to load view or use redirect() inside multiple environment check in Codeigniter?

Want to check Environment and if matches some case then want to redirect or load some view. get_instance(); not working inside index.php where environment check
what i'm looking something like below:
if (ENVIRONMENT === "production")
{
/*if(error ="db error")
redirect("/someview","refresh");
or load view header and footer
*/
}
i just confused about error handling mechanism in CI. By the help of stackoverflow users i found steps to turn off the errors . but now i can't handle those errors.
If you want to handle a certain error, You can redirect it to a certain view in the process as what you have mentioned in your question.
// Assuming you have a [Home] Controller that extends to your [Common] parent class
class Home extends Common {
public function index()
{
$this->load->helper('url');
$bCheck = false;
if ($bCheck !== true) {
$this->handleRedirectMethod('path/to/your/controller');
}
}
}
Then on your parent [Common] controller. (e.g Common.php)
class Common extends CI_Controller
{
public function handleRedirectMethod($sUrl, $sMethodName = 'refresh', $sStatusCode = '302')
{
$sServerName = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'];
redirect($sServerName . '/' . $sUrl, $sMethodName, $sStatusCode);
}
}
Hope this makes you understand how you can handle those errors

Zend 2: Route constraints log specific error

I try to log if user type wrong url parameter for a route with
'constraints' => array('personalnumber' => '[0-9]*')
$error = $e->getError();
if ($error == Application::ERROR_ROUTER_NO_MATCH) {
$url = $e->getRequest()->getUriString();
$sm->get('Zend\Log\RouteLogger')->warn('Url could not match to routing: ' . $url);
}
Can I get a specific error like: Value for Parameter "id" must type integer?
That won't be so easy. You would have to build your own functionality to find out the exact details on why the route didn't match.
Route matching is checked using the RouteInterface::match method from the corresponding class. For example for segment routes this method can be found in the Zend\Router\Http\Segment class on line 359-404.
If there is no match, the class returns null/void. Details on why the route didn't match is not part of the response, so you would have to do such in depth analysis yourself and write your own custom error response.
Such a solution could be to do manually validate the person number (for example by isolating it from the request url) when the dispatch error event is triggered and return your own custom response before the default 404 response.
<?php
namespace Application;
use Zend\Http\Response;
use Zend\Mvc\MvcEvent;
use Zend\Router\Http\RouteMatch;
class Module{
public function onBootstrap(MvcEvent $event)
{
$eventManager = $event->getApplication()->getEventManager();
$eventManager->attach(MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'validatePersonNumber'), 1000);
}
public function validatePersonNumber(MvcEvent $event)
{
if ($event->getError() !== Application::ERROR_ROUTER_NO_MATCH) {
// Not a 404 error
return;
}
$request = $event->getRequest();
$controller = $event->getController();
if($controller !== 'Application\Expected\ControllerName'){
// not a controller for person number route
return;
}
$url = $request->getRequestUri();
$personNumber = ''; //...manually isolate the person number from the request...
/** #var Response $response */
$response = $event->getResponse();
$response->setStatusCode(404);
$viewModel = $event->getViewModel();
$viewModel->setTemplate('error/404');
$event->setViewModel($viewModel);
$event->stopPropagation(true);
if (strlen($personNumber) !== 12) {
$viewModel->setVariable('message', 'A person number should have 12 characters');
}
if(...additional check...){
$viewModel->setVariable('message', 'Some other message');
}
}
}
To make things prettier you could consider moving all this into a Listener class (instead of polluting your module.php file) and you could also consider the 404 code here. Most likely there is a more suitable status code for such validation response.
Note: This is not a completely finished example, it needs more work!

Phalcon PHP framework not passing parameters to controller

Just started development in the Phalcon PHP framework and am also pretty new to PHP in general. My question is on how to create a request with a route, which I believe I have done, and pass the parameters of the route to the controller action that is linked to the said route. Below I have included the three files that I have been working on and summarize what each one is supposed to do. I also have the end result and where my problem lies directly.
The first file is the index.php file that takes in all route requests for my site.
<?php
//Include all routes on site
foreach (glob("../app/routes/*.php") as $filename)
{
include $filename;
}
foreach (glob("../app/controllers/*.php") as $filename)
{
include $filename;
}
//Create routes and initialize routes
$router = new \Phalcon\Mvc\Router();
$router->mount(new PublicRoutes());
$router->mount(new ApiRoutes());
$router->mount(new AdminRoutes());
$router->handle();
$controller = $router->getControllerName();
$action = $router->getActionName();
$params = $router->getParams();
$di = new \Phalcon\DI\FactoryDefault();
$d = new Phalcon\Mvc\Dispatcher();
$d->setDI($di);
$d->setControllerName($router->getControllerName());
$d->setActionName($router->getActionName());
$d->setParams($router->getParams());
$controller = $d->dispatch();
The second file is the actual routes mounted in for my API call which I am testing everything out with.
<?php
class ApiRoutes extends Phalcon\Mvc\Router\Group
{
public function initialize()
{
//Basic api route for pixelpusher
$this->add(
"/addhawk/api/:action/:model/:params",
array(
"controller" => "api",
"action" => 1,
"model" => 2,
"params" => 3,
)
);
}
}
The third, and final file is the controller class for the API with the only action I am testing right now.
<?php
class ApiController extends \Phalcon\Mvc\Controller
{
public function handlerAction()
{
//Pull in parameters
echo "<h1>API Handler Entered</h1>";
$model = $this->dispatcher->getParam("model");
echo $model;
//Choose correct api based off of api param
if( $model == "grid" ) {
echo 'grid';
}
else if ( $model == "admin" ) {
echo 'admin';
}
else {
//No valid api must have been found for request
}
//Return result from api call
return true;
}
}
So, the url is "localhost/addhawk/api/handler/grate/view" which results in the following output in html courtesy of line 9 in the ApiController.
There is no print out of the $model variable as it should do. There is also no error so I have no idea why it's not printing. According to the documentation and every resource I have read online, all parameters should be available directly from each controller action thanks to the dispatcher and $di class or something similar. So my question is why can I not access the parameters if everything seems to be saying I should be able to?

Cakephp calling function from view

I have the following function:
public function make_order($id = null){
if($this->request->is('post')){
if(isset($id)){
$single_product = $this->Product->find('first', array('Product.id' => $id));
$this->placeOrder($single_product);
}else{
$product_array = $_SESSION['basket'];
foreach($product_array as $product){
$this->placeOrder($product);
}
}
}
}
private function placeOrder($product){
$order_array = array();
$order_array['Order']['Product_id'] = $product['Product']['id'];
$order_array['Order']['lejer_id'] = $this->userid;
$order_array['Order']['udlejer_id'] = $product['users_id'];
$this->Order->add($order_array);
}
Now these two function are not "connected" to a view but i still need to call them from within another view
For this ive tried the following:
<?php echo $this->Html->link(__('Bestil'), array('action' => 'make_order')); ?>
However this throws an error saying it couldnt find the view matching make_order and for good reason ( i havnt created one and i do not intend to create one)
My question is how do i call and execute this function from within my view?
At the end of your make_order function, you'll either need to:
a) specify a view file to render, or
b) redirect to a different controller and / or action, that does have a view file to render.
a) would look like this:
$this->render('some_other_view_file');
b) might look like this (note: setting the flash message is optional)
$this->Session->setFlash(__('Your order was placed'));
$this->redirect(array('controller' => 'some_controller', 'action' => 'some_action'));
You can turn auto-rendering off by setting $this->autoRender = false; in your controller's action (make_order() in this case). This way you don't need a view file, and you can output whatever you need.
The problem is that nothing will be rendered on the screen. Therefore, my advice is to have your "link" simply call a controller::action via AJAX. If that's not possible in your situation, then you'll have to either render a view in your make_order() method, or redirect to an action that will render a view.

How do I catch a HTTP_Exception_404 Error in Kohana

I tried to follow the instructions here: http://kohanaframework.org/3.0/guide/kohana/tutorials/error-pages But for some reason I am unable to catch the HTTP_Exception_404 I still get a ugly error page and not my custom page.
Also when I type in the URL error/404/Message, I get a ugly Kohana HTTP 404 error message.
Here is the files structure:
modules
my
init.php
classes
controller
error_handler.php
http_response_exception.php
kohana.php
views
error.php
Code:
init.php:
<?php defined('SYSPATH') or die('No direct access');
Route::set('error', 'error/<action>(/<message>)', array('action' => '[0-9]++', 'message' => '.+'))
->defaults(array(
'controller' => 'error_handler'
));
http_response_exception.php:
<?php defined('SYSPATH') or die('No direct access');
class HTTP_Response_Exception extends Kohana_Exception {
public static function exception_handler(Exception $e)
{
if (Kohana::DEVELOPMENT === Kohana::$environment)
{
Kohana_Core::exception_handler($e);
}
else
{
Kohana::$log->add(Kohana::ERROR, Kohana::exception_text($e));
$attributes = array
(
'action' => 500,
'message' => rawurlencode($e->getMessage()),
);
if ($e instanceof HTTP_Response_Exception)
{
$attributes['action'] = $e->getCode();
}
// Error sub-request.
echo Request::factory(Route::url('error', $attributes))
->execute()
->send_headers()
->response;
}
}
}
kohana.php:
<?php defined('SYSPATH') or die('No direct script access.');
class Kohana extends Kohana_Core
{
/**
* Redirect to custom exception_handler
*/
public static function exception_handler(Exception $e)
{
Error::exception_handler($e);
}
} // End of Kohana
error_handler.php:
<?php defined('SYSPATH') or die('No direct access');
class Controller_Error_handler extends Controller {
public function before()
{
parent::before();
$this->template = View::factory('template/useradmin');
$this->template->content = View::factory('error');
$this->template->page = URL::site(rawurldecode(Request::$instance->uri));
// Internal request only!
if (Request::$instance !== Request::$current)
{
if ($message = rawurldecode($this->request->param('message')))
{
$this->template->message = $message;
}
}
else
{
$this->request->action = 404;
}
}
public function action_404()
{
$this->template->title = '404 Not Found';
// Here we check to see if a 404 came from our website. This allows the
// webmaster to find broken links and update them in a shorter amount of time.
if (isset ($_SERVER['HTTP_REFERER']) AND strstr($_SERVER['HTTP_REFERER'], $_SERVER['SERVER_NAME']) !== FALSE)
{
// Set a local flag so we can display different messages in our template.
$this->template->local = TRUE;
}
// HTTP Status code.
$this->request->status = 404;
}
public function action_503()
{
$this->template->title = 'Maintenance Mode';
$this->request->status = 503;
}
public function action_500()
{
$this->template->title = 'Internal Server Error';
$this->request->status = 500;
}
} // End of Error_handler
I really cannot see where I have done wrong. Thanks in advance for any help.
First of all, you need to make sure you are loading your module by including it in the modules section of your application/bootstrap.php file like so
Kohana::modules(array(
'my'=>MODPATH.'my'
)
);
The fact that you mentioned going directly to the url for your error handler controller triggers a 404 error makes me think your module has not been loaded.
I would also suggest a few more changes.
http_response_exception.php does not need to extend Kohana_Exception, since this class is not an exception, but an exception handler. Along those same lines, a more appropriate class name might be Exception_Handler, since the class is not representing an exception, but handling them. Secondly, because of how you've named this file, it should be located in modules/my/classes/http/response/exception.php. Other than that, the code for this class looks ok.
Similarly, because of how you've named your controller, it should be located and named a bit differently. Move it to modules/my/classes/controller/error/handler.php
Remember that underscores in a class name means a new directory, as per http://kohanaframework.org/3.2/guide/kohana/conventions
Finally, I don't think you really need to extend the Kohana_Core class here, but instead just register your own custom exception handler. You can register your custom exception handler in either your application's bootstrap file, or in your module's init file with the following generic code:
set_exception_handler(array('Exception_Handler_Class', 'handle_method'));
Here's a customer exception handler I use, which is pretty similar to yours:
<?php defined('SYSPATH') or die('No direct script access.');
class Exception_Handler {
public static function handle(Exception $e)
{
$exception_type = strtolower(get_class($e));
switch ($exception_type)
{
case 'http_exception_404':
$response = new Response;
$response->status(404);
$body = Request::factory('site/404')->execute()->body();
echo $response->body($body)->send_headers()->body();
return TRUE;
break;
default:
if (Kohana::$environment == Kohana::DEVELOPMENT)
{
return Kohana_Exception::handler($e);
}
else
{
Kohana::$log->add(Log::ERROR, Kohana_Exception::text($e));
$response = new Response;
$response->status(500);
$body = Request::factory('site/500')->execute()->body();
echo $response->body($body)->send_headers()->body();
return TRUE;
}
break;
}
}
}
You're using an outdated documentation. HTTP_Exception_404 was bundled in 3.1, and you're trying to implement a solution from 3.0.
See documentation for your version of Kohana for a solution that works.
All you need to do is set the path to a different view in your bootstrap.php add:
Kohana_Exception::$error_view = 'error/myErrorPage';
that will parse all the variables currently being parsed to the error page that lives in:
system/views/kohana/error.php
ie:
<h1>Oops [ <?= $code ?> ]</h1>
<span class="message"><?= html::chars($message) ?></span>
After a VERY LONG TIME of searching I finally found a solution to my little problem.
Here is a step by step tutorial on how to load your own custom error pages with Kohana 3.2:
Change the environment variable in the bootstrap.
Here you have multiple options:
a. Do what they say in the documentation of the bootstrap.php:
/**
* Set the environment status by the domain.
*/
if (strpos($_SERVER['HTTP_HOST'], 'kohanaphp.com') !== FALSE)
{
// We are live!
Kohana::$environment = Kohana::PRODUCTION;
// Turn off notices and strict errors
error_reporting(E_ALL ^ E_NOTICE ^ E_STRICT);
}
b. Or just add those two lines without the "if":
Kohana::$environment = Kohana::PRODUCTION;
error_reporting(E_ALL ^ E_NOTICE ^ E_STRICT);
c. I have not try this way but in the new bootstrap.php you have this code:
/**
* Set Kohana::$environment if a 'KOHANA_ENV' environment variable has been supplied.
*
* Note: If you supply an invalid environment name, a PHP warning will be thrown
* saying "Couldn't find constant Kohana::<INVALID_ENV_NAME>"
*/
if (isset($_SERVER['KOHANA_ENV']))
{
Kohana::$environment = constant('Kohana::'.strtoupper($_SERVER['KOHANA_ENV']));
}
I assume that you could just give the value "production" to "$_SERVER['KOHANA_ENV']" before those lines.
Again, like I said I haven't tried it, but it should work.
I personally just commented out those lines of codes.
2 Now you need to add a few configurations in a "ini.php" file, or in the "bootstra.php" file.
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Turn errors into exceptions.
*/
Kohana::$errors = true;
/**
* Custom exception handler.
*/
restore_exception_handler();
set_exception_handler(array('Exception_Handler', 'handler'));
/**
* Error route.
*/
Route::set('error', 'error/<action>(/<message>)', array('action' => '[0-9]++', 'message' => '.+'))
->defaults(array(
'controller' => 'exception_handler'
));
This is what was missing and made it to hard. For the rest you can easily just follow Kohana3.2 documentation or you can get the module that I added to a repo in GitHub: https://github.com/jnbdz/Kohana-error
Every underscore is a directory separator in a class name. So when naming your class Http_Response_Exception, the class should be in classes/http/response/exception.php. Otherwise the class will not be found by the autoloader of Kohana.
edit
Hmm, seems like the documentation is wrong in this aspect. classes/http_response_exception.php doesn't make sense.

Categories