Issues

ZF-4491: Support the new Microsoft URL Rewrite Module for IIS 7.0

Description

Microsoft has recently released its own rewrite module for IIS7.0. (See: http://learn.iis.net/page.aspx/460/…). I was trying to get it to work with your quick start application and found out that it is not completely working as expected. This because this new module uses the HTTP_X_ORIGINAL_URL header instead of the HTTP_X_REWRITE_URL header as used by the isapi_rewrite extension. As a consequence I always got the index controller and action for every request made and thus never got the error page for calls to bogus controllers/actions. Exception: when using the http://localhost/myapplication/index.php/… syntax, it already works fine.

As a newbie to the Zend framework I have no idea if what I did is correct and works in all cases, but as an experienced developer I managed to get it to work by doing a global search for all uses of HTTP_X_REWRITE_URL and adding an additional if branch for the HTTP_X_ORIGINAL_URL as well:

Find results: Zend\Controller\Request\Apache404.php(50): if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // check this first so IIS will catch Zend\Controller\Request\Apache404.php(51): $requestUri = $_SERVER['HTTP_X_REWRITE_URL']; Zend\Controller\Request\Http.php(381): * $_SERVER['HTTP_X_REWRITE_URL'], or $_SERVER['ORIG_PATH_INFO'] + $_SERVER['QUERY_STRING']. Zend\Controller\Request\Http.php(389): if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // check this first so IIS will catch Zend\Controller\Request\Http.php(390): $requestUri = $_SERVER['HTTP_X_REWRITE_URL']; Zend\OpenId.php(110): if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { Zend\OpenId.php(111): $url .= $_SERVER['HTTP_X_REWRITE_URL'];

Changes made (this is for OpenId.php, other files have similar changes) (basically add an if elseif for the new HTTP_X_ORIGINAL_URL header): if (isset($_SERVER['HTTP_X_ORIGINAL_URL'])) { // check this first so IIS will catch $url .= $_SERVER['HTTP_X_ORIGINAL_URL']; } elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // check this first so IIS will catch

Comments

The simplest way that I've found to get around this issue is to add the following lines to my bootstrap file, prior to any calls to Zend_Controller_Front::getInstance():

/* * For IIS 7.0 Rewrite Module - allows use of "clean" URL syntax instead of * index.php/controller/action/ by copying original URL value set by the rewrite * module to the server variable expected by the Rewrite Router. */ if (isset($_SERVER['HTTP_X_ORIGINAL_URL'])) {

$_SERVER['HTTP_X_REWRITE_URL'] = $_SERVER['HTTP_X_ORIGINAL_URL'];

}

To fix this issue, the method setRequestUri within Zend_Controller_Request_Http class must be changed as this (line 383):

 
    /**
     * Set the REQUEST_URI on which the instance operates
     *
     * If no request URI is passed, uses the value in $_SERVER['REQUEST_URI'],
     * $_SERVER['HTTP_X_ORIGINAL_URL'], or $_SERVER['HTTP_X_REWRITE_URL'], or $_SERVER['ORIG_PATH_INFO'] + $_SERVER['QUERY_STRING'].
     *
     * @param string $requestUri
     * @return Zend_Controller_Request_Http
     */
    public function setRequestUri($requestUri = null)
    {
        if ($requestUri === null) {
            if (isset($_SERVER['HTTP_X_ORIGINAL_URL'])) { // check IIS 7.x with Microsoft Rewrite Module
                $requestUri = $_SERVER['HTTP_X_ORIGINAL_URL'];
            elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // check IIS with ISAPI_Rewrite, etc
                $requestUri = $_SERVER['HTTP_X_REWRITE_URL'];
            } elseif (isset($_SERVER['REQUEST_URI'])) {
                $requestUri = $_SERVER['REQUEST_URI'];
                // Http proxy reqs setup request uri with scheme and host [and port] + the url path, only use url path
                $schemeAndHttpHost = $this->getScheme() . '://' . $this->getHttpHost();
                if (strpos($requestUri, $schemeAndHttpHost) === 0) {
                    $requestUri = substr($requestUri, strlen($schemeAndHttpHost));
                }
            } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0, PHP as CGI
                $requestUri = $_SERVER['ORIG_PATH_INFO'];
                if (!empty($_SERVER['QUERY_STRING'])) {
                    $requestUri .= '?' . $_SERVER['QUERY_STRING'];
                }
            } else {
                return $this;
            }
        } elseif (!is_string($requestUri)) {
            return $this;
        } else {
            // Set GET items, if available
            if (false !== ($pos = strpos($requestUri, '?'))) {
                // Get key => value pairs and set $_GET
                $query = substr($requestUri, $pos + 1);
                parse_str($query, $vars);
                $this->setQuery($vars);
            }
        }

        $this->_requestUri = $requestUri;
        return $this;
    }

I've already tested it in a development server running Windows Server 2003 SP3 + IIS 7.0 + Rewrite Module, and worked as expercted.

Best Regards, Bruno B B Magalhães

Reopening, as no patch has been applied. :)

This needs to be fixed. IIS 7.0+ is default in Windows Server 2003, Server 2008, Server 2008 R2, and Windows 7. This issue affects anyone using those operating systems with IIS and the URL Rewrite module.

This is fixed in ZF2 with PR 1424.

Fixed in svn r24842 by rob (Rob Allen).