Własne strony błędów [KO3.2]

Co to są strony błędów? Wyświetla je serwer gdy wystąpi jakiś błąd, na przykład:
- błąd 404 – strona nie zostanie znaleziona (wpisano zły link)
- błąd 500 – wewnętrzny błąd serwera
- itp.

Standardowo po wpisaniu złego linku wyświetlają się błędy Kohany (można je wyłączyć, ale wtedy pusta strona się wyświetli).
W tym wpisie pokażę, jak wykonać własne strony błędów, które zawierać będą nasze komunikaty.

Na początku zmodyfikujemy, aplikację tak, aby strony błędów wyświetlały się w wersji produkcyjnej, a w wersji developerskiej wyświetlane były normalne błędy kohany. Dodatkowo w produkcyjnej będzie włączony caching, a w developerskiej profile (wyświetlanie statystyk) w stopce .

To z jakim środowiskiem mamy do czynienia umieszczamy w pliku .htaccess (wymagany moduł env apache, można również przechowywać w bootstrapie). Do .htaccess na końcu dodajemy

# Set environment  
SetEnv KOHANA_ENV "production"
#

Jeśli tworzymy aplikację (na localhost) production zmieniamy na development

Modyfikujemy /application/bootstrap.php

Kohana::init(array(
    'base_url'   => '/',
    'errors' => TRUE,
    'index_file' => FALSE,
    'profile'       => (Kohana::$environment == Kohana::DEVELOPMENT), 
    'caching'       => (Kohana::$environment == Kohana::PRODUCTION) 
));

Ze wcześniejszych wpisów wiemy już co znaczy base_url i index_file.

'errors' => TRUE, 

Oznacza, że błędy będą wyświetlane.

'profile' => (Kohana::$environment == Kohana::DEVELOPMENT),

Oznacza, że profile zostanie włączony jak środowisko będzie developerskie.

'caching' => (Kohana::$environment == Kohana::PRODUCTION),

Oznacza, że cachowanie zostanie włączone na wersji produkcyjnej.

W szablonie naszej aplikacji możemy dodać do stopki statystyki

<?php if(Kohana::$environment == Kohana::DEVELOPMENT ) echo View::factory('profiler/stats')?>

Spowoduje to wyświetlenie statystyk w środowisku developerskim.

Przejdźmy teraz do części odpowiedzialnej za wyświetlanie błędów – nadpiszemy klasę Exception.
Tworzymy plik exception.php w folderze /application/classes/kohana/

/application/classes/kohana/exception.php »

<?php defined('SYSPATH') or die('No direct script access.');

class Kohana_Exception extends Kohana_Kohana_Exception
{
    public static function handler(Exception $e)
    {
        if (Kohana::$environment === Kohana::DEVELOPMENT) 
        { 
            parent::handler($e); 
        } 
        else 
        { 
            Kohana::$log->add(Log::ERROR, Kohana_Exception::text($e)); 
            switch (get_class($e))
            {
                case 'HTTP_Exception_404':
                    $response = new Response;
                    $response->status(404);
                    $view = View::factory('error/template')
                            ->bind('title',$title)
                            ->bind('content',$content);
                    
                    $view->description = 'Błąd 404 - Nie znaleziono żądanej strony.';
                    $url = $_SERVER['REQUEST_URI'];
                    $view->styles = array('media/css/error_style.css' => 'screen');
                    $view->scripts = array();
                    
                    $title = 'Błąd 404 - Nie znaleziono żądanej strony.';
                    $content='<p>Bardzo przepraszamy - podana strona '.HTML::anchor($url, $url, array('rel'=>'nofollow')).' nie została odnaleziona.</p>'.
                    '<p>Być może kliknięto nieważny link lub źle wprowadzono adres. W niektórych adresach internetowych rozróżniane są wielkie i małe litery.</p>'.
                    '<p class="box_yellow pad5">Jeśli błąd pojawił się po kliknięciu w link, będziemy wdzięczni za zgłoszenie tego problemu. W razie pytań lub wątpliwości prosimy o '.HTML::anchor('/contact', 'kontakt').' z biurem obsługi klienta.</p>';
                    
                    echo $response->body($view)->send_headers()->body();
                    return TRUE;
                    break;
                
                case 'HTTP_Exception_500':
                    $response = new Response;
                    $response->status(500);
                    $view = View::factory('error/template')
                            ->bind('title',$title)
                            ->bind('content',$content);
                    
                    $view->description = 'Błąd 500 - Wewnętrzny błąd serwera.';
                    $view->styles = array('media/css/error_style.css' => 'screen');
                    $view->scripts = array();
                    
                    $title = 'Błąd 500 - Wewnętrzny błąd serwera.';
                    $content='<p>Wystąpił błąd podczas realizacji Twojego żądania. Możesz spróbować wykonać następujące czynności: </p>'.
                    '<ul><li>Odświeżyć stronę.</li><li>Wróć do poprzedniej strony.</li></ul>'.
                    '<p class="box_yellow pad5">Jeśli komunikat pojawi się ponownie, będziemy wdzięczni za zgłoszenie tego problemu. W razie pytań lub wątpliwości prosimy o '.HTML::anchor('/contact', 'kontakt').' z biurem obsługi klienta.</p>';
                    
                    echo $response->body($view)->send_headers()->body();
                    return TRUE;
                    break;
                
                default:
                    $response = new Response;
                    $response->status($e->getCode());
                    $view = View::factory('error/template')
                            ->bind('title',$title)
                            ->bind('content',$content);
                    
                    $view->description = $e->getMessage();
                    $view->styles = array('media/css/error_style.css' => 'screen');
                    $view->scripts = array();
                    
                    $title = $e->getMessage();
                    $content='<p>Wystąpił błąd '.$e->getCode().' podczas realizacji Twojego żądania. Możesz spróbować wykonać następujące czynności: </p>'.
                    '<ul><li>Odświeżyć stronę.</li><li>Wróć do poprzedniej strony.</li></ul>'.
                    '<p class="box_yellow pad5">Jeśli komunikat pojawi się ponownie, będziemy wdzięczni za zgłoszenie tego problemu. W razie pytań lub wątpliwości prosimy o '.HTML::anchor('/contact', 'kontakt').' z biurem obsługi klienta.</p>';
                    
                    echo $response->body($view)->send_headers()->body();
                    return TRUE;
                    break;
            }
        }
        
        
        
    }
}

Nadpisujemy w tym momencie funkcję handler() klasy Exception Kohany. W przypadku, gdy działamy na wersji developerskiej, zostają wyświetlone standardowe błędy Kohany.

if (Kohana::$environment === Kohana::DEVELOPMENT) 
{ 
    parent::handler($e); 
} 

W innym razie zostają zapisane błędy w folderze logs i wyświetlone nasze strony błędów.

else 
{ 
    Kohana::$log->add(Log::ERROR, Kohana_Exception::text($e)); 
    switch (get_class($e))
    {

Przyglądnijmy się sekcji case HTTP_Exeption_404. Najpierw tworzymy odpowiedź (wysyłamy ją na końcu)

$response = new Response;

Następnie przesyłamy do niej kod błędu i widok (deklarujemy zmienne przez referencję)

$response->status(404);
$view = View::factory('error/template')
    ->bind('title',$title)
    ->bind('content',$content);

Przesyłamy także w sposób tradycyjny zmienne zawierające opis, style i skrypty

$view->description = 'Błąd 404 - Nie znaleziono żądanej strony.';
$url = $_SERVER['REQUEST_URI'];
$view->styles = array('media/css/userpage_new.css' => 'screen');
$view->scripts = array();

Przypisujemy do zmiennych title i content zawartość (zostaną wysłane do widoku)

$title = 'Błąd 404 - Nie znaleziono żądanej strony.';
$content='<p>Bardzo przepraszamy - podana strona '.HTML::anchor($url, $url, array('rel'=>'nofollow')).' nie została odnaleziona.</p>'.
'<p>Być może kliknięto nieważny link lub źle wprowadzono adres. W niektórych adresach internetowych rozróżniane są wielkie i małe litery.</p>'.
'<p class="box_yellow pad5">Jeśli błąd pojawił się po kliknięciu w link, będziemy wdzięczni za zgłoszenie tego problemu. W razie pytań lub wątpliwości prosimy o '.HTML::anchor('/contact', 'kontakt').' z biurem obsługi klienta.</p>';

Na końcu wyświetlamy stronę z błędami, zwrazamy TRUE i kończymy case.

echo $response->body($view)->send_headers()->body();
return TRUE;
break;

Widok template zawierający szablon błędów należy umieścić w /application/views/error/

/application/views/error/template.php »

<!DOCTYPE html>
<html lang="pl">
    <head>
        <meta charset="utf-8" />
        <meta name="description" content="<?php echo $description?>" />
        <title><?php echo $title?>' | example.com</title>
        <?php foreach ($styles as $file => $type) echo HTML::style($file, array('media' => $type)), "n" ?>
        <?php foreach ($scripts as $file) echo HTML::script($file), "n" ?>
        <link rel="shortcut icon" href="/media/img/favicon.ico" type="image/x-icon" />
    </head>
    <body>
        <div class="w600 mrg40t">
            <h1><a href="/" target="_parent"><?php echo HTML::image('media/img/logo.png', array('alt'=>'example.com'))?></a></h1>
            <h2 class="in_w box_green pad5"><?php echo $title?></h2>
            <div class="in_w box_white mrg-1t pad5 ofh">
                <?php echo $content?>
            </div>
            <div class="mrg5t">Copyright &copy; <?php echo date('Y')?> <?php echo HTML::anchor('/', 'example.com')?>. All Rights Reserved.</div>
        </div>
    </body>
</html>

Zawiera on szablon strony, na której znajdują się błędy. Możemy stworzyć dowolną stronę, zawierającą informacje (w zależności od błędu), a także oryginalne obrazki i skrypty.

Style umieszczamy w /media/css/ Przykładowy plik poniżej

/media/css/error_style.css »

root {
    display: block;
}

html, body {
    margin: 0;
    padding: 0;
    font-family:tahoma,verdana,arial,sans-serif;

    font-size:11px;
    line-height: 1.3;
    color: #333333;
}
img {border: 0;}
p {margin-top: 0}
h1 { margin: 0px; font-size:22px;}
h2 { margin: 0px; font-size:18px; }
.w600{margin: 0px auto;width: 600px;}
.mrg40t{margin-top: 40px}
.in_w{
    float: none;
    left: auto;
    width: auto;
}
.box_white{background-color: #fff;border: 1px solid #b3b3b3;}
.box_green{background-color: #e0ffd7;border:1px solid  #8ec159;}
.box_yellow{background-color: #fff9d7;border:1px solid  #e2c822;}
.mrg-1t{margin-top: -1px;}
.pad5{padding: 5px;}
.mrg5t{margin-top: 5px;} 
.ofh{overflow: hidden}

To wszystko. Jeśli w .htaccess ustawimy na development to błędy będą standardowe (dodatkowo w stopce profile). Jeśli ustawimy production będziemy mieli własne strony błędów (dodatkowo caching).

W switch/case można porobić osobne widoki dla błędów (w tym przykładzie wszystko działa na jednym widoku).

10 Odpowiedzi :“Własne strony błędów [KO3.2]”

  1. tojach napisał:

    Dzięki, napewno sie przyda w dopieszczaniu stron :)

  2. Moim zdaniem bardzo niefajne jest, że wrzucasz tekst, który powinien być w widoku do kontrolera. Tym bardziej, że jest to tekst zawierający kod HTML, czyli śmietniczysz panie :P

    Wygodniej byłoby utworzyć sobie cztery pliki:

    – errors/403.php
    – errors/404.php
    – errors/500.php
    – errors/default.php

    W tym momencie każdy z nich zawiera wygląd strony typowy dla danego błędu (a to nie zawsze musi się pokrywać). Default byłby w tym momencie catch-all w razie wystąpienia bardziej egzotycznych błędów jak choćby HTTP 418 ;)

    • Mariusz napisał:

      Zacytuję siebie :)

      W switch/case można porobić osobne widoki dla błędów (w tym przykładzie wszystko działa na jednym widoku).

      Oczywiście można porobić osobne widoki i tylko wczytywać widoki w case.

  3. Czy aby na pewno obsługuje K3.2? Kohana ignoruje klasę exception (niezaleznie od ustalonego srodowiska wyświetla ładną stronę błedy z K.).

  4. DZIEKUJE :)

  5. Rafał napisał:

    OK, a jak wykorzystać przy tym własny template i podpiąć strony błędów jako widoki?

    • Mariusz napisał:

      Jeśli chcesz wczytać widok template.php, a do niego pod zmienną content podwidok 404.php z folderu /views/error/, to np. tak:

      $view = View::factory('error/template')
          ->set('content', View::factory('error/404'));
      

      Czyli case dla 404:

      case 'HTTP_Exception_404':
          $response = new Response;
          $response->status(404);
      
          $view = View::factory('error/template')
              ->set('content', View::factory('error/404'));
      
          echo $response->body($view)->send_headers()->body();
          return TRUE;
      break;
      

Dodaj komentarz

Dodając kod PHP używaj tagów: [php][/php]

*