[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