4

I'm currently moving to an nginx server. I tried putting this in my 404 ErrorDocument named 404.php:

<?php
    header("Location: http://www.google.com/");
?>

If I now try to access http://mydomain.com/404.php, this works as expected: It redirects me to Google. But once I try to access http://mydomain.com/iDoNotExist, the 404 ErrorDocument is shown without redirecting me to Google.

This behavior seems weird to me. Is there any way I can fix this?

Edit:

Here's what curling the page gives me:

curl -I mydomain.com/404.php

HTTP/1.1 302 Moved Temporarily
Server: nginx/1.2.1
Date: Sun, 05 Jan 2014 11:31:15 GMT
Content-Type: text/html
Connection: keep-alive
X-Powered-By: PHP/5.4.4-14+deb7u7
Location: http://google.com/

curl -I mydomain.com/iDoNotExist

HTTP/1.1 404 Not Found
Server: nginx/1.2.1
Date: Sun, 05 Jan 2014 11:33:49 GMT
Content-Type: text/html
Connection: keep-alive
X-Powered-By: PHP/5.4.4-14+deb7u7
Location: http://google.com/

Edit 2:

As asked by hakre, I'm coming from an Apache setup, and yes, I'm using Chromium. As for Apache, this used to work for all the Gecko and Webkit browsers and even console-based browsers such as Lynx. It would probably have worked for Internet Explorer as well, but I've never tried that (no Windows around here, phew).

hakre
  • 193,403
  • 52
  • 435
  • 836
Chiru
  • 3,661
  • 1
  • 20
  • 30
  • No, I disagree. Valid configuration files can be a matter of good programming, regardless of the purpose they serve. Neither "*look into the source*" nor "*read the manual*" is constructive advice to any kind of problem where you assume that this (and lots of googling) hasn't already been tried. Anyway, accessing the site from `http://mydomain.com/iDoNotExist` will trigger the execution of the PHP code in my ErrorDocument (I just echoed a string to make sure). – Chiru Jan 05 '14 at 11:22
  • Then look with curl (or another HTTP client that is able to show) which headers are received by the client. Please add those response headers to your question. – hakre Jan 05 '14 at 11:26
  • I already did, and it matches with what my browser shows me as well. Curling `http://mydomain.com/404.php` will alter the HTTP status code to 302, curling `http://mydomain.com/iDoNotExist` won't. I'll attach the results to my original post (just in case you want to see). – Chiru Jan 05 '14 at 11:30
  • That's clear because it's a 404 page, so you've got the 404 status code. The meaning of the `Location` response header is based on response status code. This is documented here: http://tools.ietf.org/search/rfc2616#section-14.30 - So the behavior of your browser is not weird but just standard, just following the HTTP specs. Probably weird is your expectation that the browser should do something that has no place in the protocol. ;) – hakre Jan 05 '14 at 11:33
  • I guessed in my title edit you've used Chrome here as browser, but you should write down which browser you're testing with actually as this is related to browser. Also you should write from which configuration you're moving from and tell whether or not this did work before the move (and with which browser/server) or not. – hakre Jan 05 '14 at 11:42
  • Thanks! I've added the information in another edit of my original post. :) – Chiru Jan 05 '14 at 11:51
  • Those details really clear things up! Do you know which SAPI you were using with PHP and Apache (like mod_php probably?). And are you using FCGI with Nginx? I also have left a link in a comment (perhaps you need to refresh, I edited it) which might be helpful or at least worth to try: [`header("Status: 302 Moved Temporarily");`](http://stackoverflow.com/q/8828275/367456) – hakre Jan 05 '14 at 11:55
  • To be honest, I'm not sure whether or not the browser really matters, since Firefox and Lynx behave the same way. It's really more about the server's HTTP response, isn't it? As for Apache, I don't recall switching to another SAPI than the default one — so if it uses **mod_php** as a default, chances are high that I used it. As for Nginx, I'm using **php5-fpm** which is an alternative PHP FastCGI implementation. I really appreciate your help, thanks a lot! – Chiru Jan 05 '14 at 12:10
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/44550/discussion-between-hakre-and-chiru) – hakre Jan 05 '14 at 12:11

1 Answers1

5

The behavior of your browser is correct. The Location: response header has no meaning for status code 404 (compare 14.30 Location and 10.4 Client Error 4xx).

Therefore the response's hypertext body is displayed in the browser - as specified by the HTTP specs for code 404 (see 10.4.5 404 Not Found).


To allow changing the HTTP response code from 404 to a different one (e.g. 302 for the temporary redirect), you have to configure Nginx error_page directive accordingly:

error_page   404 = /404.php;

Without the equal sign (=), it is not possible to change the status code with your PHP script:

header("Location: http://google.com"); # PHP sets 302 status code

SAPI: php5-fpm

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
hakre
  • 193,403
  • 52
  • 435
  • 836
  • Okay, I see. But consider the following change: `header("Location: http://www.google.com/", true, 302);` Putting this in `404.php` won't alter my 404 status code either. So accessing `http://mydomain.com/iDoNotExist` will still be the 404 page. Is there anything I'm missing? *Edit*: Sorry, the whole formatting got a little broken. – Chiru Jan 05 '14 at 11:43
  • @Chiru: For the server used (Nginx) PHP it's SAPI used (no idea how you configured it) requires knowledge how to set the response code in PHP so that the webserver returns it. Which SAPI do you use? Also Nginx must allow to overwrite that status code in this specific 404 error situation I assume. It's probably better to not use 404 handler here, but just do pass all non-existing requests to your script to turn them into a 302. – hakre Jan 05 '14 at 11:48
  • (related but unsolved, just for reference: [Nginx custom PHP error_pages with different header status codes and body contents](http://stackoverflow.com/q/4808327/367456)) - Nginx/FCGI probably? [Still necessary to use 'Status: 404 Not Found' for FCGI?](http://stackoverflow.com/q/8828275/367456) – hakre Jan 05 '14 at 11:51
  • As for the SAPI, I'm using **php5-fpm** in my setup. I just tried fiddling arround with the `302` I've used in the above code snippet and changed it to various other status codes. Overwriting the HTTP status code seems to be allowed when I try to access the file directly (according to `curl` replies). – Chiru Jan 05 '14 at 12:00
  • This would then signal that perhaps Nginx prevents that. I'm not so fit with Nginx, but this is probably documented. It might be helpful you add your nginx configuration for that error page as well to the question. And since PHP 5.4 there is: [`http_response_code()`](http://php.net/http_response_code) – hakre Jan 05 '14 at 12:04
  • Thanks a lot! This solution fixes the issue. For some reason, it will also cause the HTTP response to be **200 OK** instead of **404 Not Found** whenever we're on a 404 page that doesn't redirect. But since this solution allows for setting the HTTP response codes for ErrorDocuments that redirect, you can easily solve the `200 OK` issue by manually setting your HTTP code in PHP (e.g. `header("HTTP/1.1 404 Not Found");` or since PHP 5.4, as hakre already wrote, `http_response_code(404);`). – Chiru Jan 05 '14 at 13:10