Welcome Guest, Not a member yet? Register   Sign In
Did we ever figure out custom 404 pages?
#1

[eluser]Madmartigan1[/eluser]
I see lots of threads that miss the mark. Maybe I haven't looked hard enough, but I wanted to go to bed 3 hours ago :-P

A custom 404 page should:

- Send a 404 header

- Access the CI superglobal to load data/views/etc.
(you can't just call get_instance() in the default template)

- be shown any time show_404() is called

- log the error

- NOT redirect to another url

Do we all agree on this, and did anyone ever find a sensible, elegant solution that works?
#2

[eluser]skunkbad[/eluser]
I've got a 404 page that works for me. It does send a 404 header, you can load whatever you want, it is called when show_404() is called, it does not redirect to another url, but it doesn't log the error (because I just don't care).

It doesn't take super genius php skills to achieve this. I just created a MY_Exceptions.php and use the following:

Code:
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
if (stristr($_SERVER['HTTP_HOST'], 'localhost' ))
{
    define("BASE", "http://localhost");
}
else
{
    define("BASE", "http://mysite.com");
}
class MY_Exceptions extends CI_Exceptions {

    function show_error($heading, $message, $template = 'error_general', $status_code = 500)
    {
        set_status_header($status_code);

        if (ob_get_level() > $this->ob_level + 1)
        {
            ob_end_flush();    
        }
        ob_start();
        // First context options are built for the development server, because it is a Windows server, and was not compiled --with-curlwrappers.
        if (stristr($_SERVER['HTTP_HOST'], 'localhost') || (substr($_SERVER['HTTP_HOST'], 0, 7) == '192.168')){
            $opts = array(
              'http'=>array(
                'method'=>"POST",
                'header'=>    "Content-type: application/x-www-form-urlencoded\r\n" ,
                'user_agent'=>    $_SERVER['HTTP_USER_AGENT'],
                'content' => http_build_query( array ( 'heading' => $heading,
                                                        'message' => $message,
                                                        'status_code' => $status_code
                                                    )
                                            )
              )
            );
        // or else if the script is running from the production server, the options are built as needed (with the header options as an array)
        }else{
            $opts = array(
              'http'=>array(
                'method'=>"POST",
                'header'=>    array(    
                                    'Content-type: application/x-www-form-urlencoded'
                                ),
                'user_agent'=>    $_SERVER['HTTP_USER_AGENT'],
                'content' => http_build_query( array ( 'heading' => $heading,
                                                        'message' => $message,
                                                        'status_code' => $status_code
                                                    )
                                            )
              )
            );
        }
        $context = stream_context_create($opts);
        echo(file_get_contents( BASE .'/errorpage', FALSE , $context));
        $buffer = ob_get_contents();
        ob_end_clean();
        return $buffer;
    }

}
/* End of file MY_Exceptions.php */
/* Location: .application/libraries/MY_Exceptions.php */

Then, you can have an errorpage controller like this:

Code:
<?php
class Errorpage extends Controller {

    public function index()
    {
        print_r($_POST);
        if($this->input->post('heading'))
        {
            $vars['title'] = $this->input->post('heading');
            $vars['heading'] = $this->input->post('heading');
        }
        else
        {
            $vars['title'] = '404 - PAGE NOT FOUND';
            $vars['heading'] = '404 - PAGE NOT FOUND';
        }
        if($this->input->post('message'))
        {
            $vars['message'] = $this->input->post('message');
        }
        else
        {
            $vars['message'] = 'The page you tried to access does not exist or has been moved.';
        }
        if($this->input->post('status_code'))
        {
            $vars['status_code'] = $this->input->post('status_code');
        }
        else
        {
            $vars['status_code'] = '404';
        }
        $this->load->vars($vars);

        // insert page specific data into template
        $data = array(
            'base_tag' => TRUE,
            'style_sheet_names' => array(
                                        'css/style.css'
            ),
            'media_targets' => array(
                                    'screen'
            ),
            'slogan' => 'Maybe your fingers are too fast for you?',
            'content' => $this->load->view('errorpage', '', TRUE ),
            'dynamic_extras' => $this->load->view('countdown', '', TRUE)
        );
        $this->load->view('template_content', $data );
    }
}
/* End of file errorpage.php */
/* Location: .application/controllers/errorpage.php */

You may have to tweak the stream context depending on your server...
#3

[eluser]Madmartigan1[/eluser]
Thanks a lot for the reply Skunkbad.

This is not working for me at all. Either I get a fatal error from file_get_contents() or the page loads forever.

Any clues?
#4

[eluser]skunkbad[/eluser]
You might check this to see if this is your problem:

http://en.kioskea.net/faq/1449-php-5-usi...on-include

Even though your errorpage is obviously within your site, the absolute URL that I use may not be allowed. That's all I can think of, but it would for sure be server configuration. The creation of the stream context may be giving you some problems too. If php has been compiled with or without curl wrappers, which you can check with phpinfo(), then the type of stream context may need to be adjusted. For instance, I show two examples in my code. One is for my Windows installation, and the other is for my production server. You may need one or the other. Unfortunately, I don't know of a way for php to check if curl wrappers are on/off and make its own decision.
#5

[eluser]skunkbad[/eluser]
ALSO!!! I left in rbg72.web in the code... change this to localhost.
#6

[eluser]Tominator[/eluser]
I think you should delete this line from errorpage controller:
Code:
print_r($_POST);
(line 5)

I will write my solution tommorow (if will be needed), cause I am going to sleep Big Grin

Question: What kind of data do you want to log?

Tom.
#7

[eluser]skunkbad[/eluser]
[quote author="Tominator" date="1272163157"]I think you should delete this line from errorpage controller:
Code:
print_r($_POST);
(line 5)

I will write my solution tommorow (if will be needed), cause I am going to sleep Big Grin

Question: What kind of data do you want to log?

Tom.[/quote]

YES! I just had that there for testing last night.
#8

[eluser]skunkbad[/eluser]
as a side issue, does anyone know how to use php to test if if php was compiled --with-curlwrappers ? Yes, php has a function that checks for installed extensions, but it just says "curl", and that's not good enough. phpinfo(1) could be used to bring in what php was compiled with, but since I am using a buffer already, I can't flush it just to test for curl wrappers. As usual, I'm probably making things harder than they have to be, so I hope Tominator has a great solution!
#9

[eluser]Madmartigan1[/eluser]
Skunkbad - I did get this working. The controller was making the server gag, it worked as soon as I put in my own stuff. It's logging the 404 as well. Smile

1 issue, which I know you mentioned:
[function.file-get-contents]: Content-type not specified assuming application/x-www-form-urlencoded

Setting the context param to NULL made the notice disappear, but this will affect other types of errors won't it?

Other than that this seems to be working great so far, thank you so much.
This is the cleanest method I've seen so far. I've seen solutions where people extend Router AND Exceptions, that doesn't send a 404 header, and redirects to something like http://localhost/file_not_found. Just awful.

Thanks again! Tominator GL! CI 2.0 is still in development so if you can come up with something really nice, please submit it! I think we're all sick and tired of seeing CI default 404 pages!
#10

[eluser]skunkbad[/eluser]
Yes, by setting the context param to NULL, you won't be posting the show error vars over to the controller. For most sites this isn't a big deal, since the 404 is all most people are likely to get, but if you use custom show errors, then they won't be seen the right way.

The real issue with creating the stream context comes from if php is compiled --with-curlwrappers. You can see this if you use phpinfo. A section near the very top shows what extensions php was loaded with, and if --with-curlwrappers is not there, you can use the block of code I was only running on localhost. This to me is a bug, or at minimum a real pain, and documentation is crap for this --with-curlwrappers thing.

The real difference is the way that the context param is set. Take a look and you will see only a slight difference.

Also, Tominator is a super genius, so he might create a better solution, but if this one works for you, then have fun, and don't forget me when you are rich.




Theme © iAndrew 2016 - Forum software by © MyBB