[wp-trac] [WordPress Trac] #34634: Empty PHP_SELF causes 404 pages to load front page with 200 status code
WordPress Trac
noreply at wordpress.org
Mon Nov 9 14:34:41 UTC 2015
#34634: Empty PHP_SELF causes 404 pages to load front page with 200 status code
--------------------------+-----------------------------
Reporter: l3rady | Owner:
Type: defect (bug) | Status: new
Priority: normal | Milestone: Awaiting Review
Component: Query | Version: 4.3.1
Severity: normal | Keywords:
Focuses: |
--------------------------+-----------------------------
I've been having this issue where visiting a non-existent page in
wordpress on our live server would result in the homepage being loaded
with a 200 OK response, however on local and staging going to an non-
existent page would result in the correct 404 page and template being
loaded.
I have a standard 4.3.1 WP install subdomain base multisite with pretty
permalinks enabled running with Nginx/PHP-FPM.
I've looked to see what was different between local and live and it turns
out on live `$_SERVER['PHP_SELF']` is being set blank and on staging it is
being set to `/index.php`. So to test I set at the top of my index.php
file the following line `$_SERVER['PHP_SELF'] = '';`. Then when running on
staging I was now getting the homepage load on a non-existent page.
So I've fired up my debugger to see what is going on in core and here are
my findings.
In wp-load.php we set PHP_SELF to something based off REQUEST_URI
{{{#!php
// Fix empty PHP_SELF
$PHP_SELF = $_SERVER['PHP_SELF'];
if ( empty( $PHP_SELF ) )
$_SERVER['PHP_SELF'] = $PHP_SELF = preg_replace( '/(\?.*)?$/', '',
$_SERVER["REQUEST_URI"] );
}}}
So the request `http://www.example.com/non-existent` results in `PHP_SELF`
equal to `/non-existent` instead of `/index.php`
Then in `class-wp.php WP->parese_request()` we have:
{{{#!php
$self = $_SERVER['PHP_SELF'];
$home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/'
);
$home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path,
'|' ) );
// Trim path info from the end and the leading home path from
the
// front. For path info requests, this leaves us with the
requesting
// filename, if any. For 404 requests, this leaves us with the
// requested permalink.
$req_uri = str_replace($pathinfo, '', $req_uri);
$req_uri = trim($req_uri, '/');
$req_uri = preg_replace( $home_path_regex, '', $req_uri );
$req_uri = trim($req_uri, '/');
$pathinfo = trim($pathinfo, '/');
$pathinfo = preg_replace( $home_path_regex, '', $pathinfo );
$pathinfo = trim($pathinfo, '/');
$self = trim($self, '/');
$self = preg_replace( $home_path_regex, '', $self );
$self = trim($self, '/');
}}}
This ends up with: `$req_uri = $self = non-existent`
Later in the same function we have:
{{{#!php
// If req_uri is empty or if it is a request for ourself, unset error.
if ( empty($request) || $req_uri == $self ||
strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) {
unset( $error, $_GET['error'] );
if ( isset($perma_query_vars) &&
strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false )
unset( $perma_query_vars );
$this->did_permalink = false;
}
}}}
Here because `$req_uri == $self` this code unsets the 404 which
subsequently results in the front page being loaded rather than the 404
page
I did some further investigation and this appears to only happen on
multisite installs. If I take a normal wordpress install and set
`$_SERVER['PHP_SELF'] = ''` the 404's work as normal.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/34634>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list