CakePHP, IIRF REQUEST_FILENAME problem

Topics: Developer Forum, User Forum
Feb 20, 2010 at 7:44 PM

I was trying to configure cakephp using IIRF filter. CakePHP's root is kinda different from the normal root. The root folder is not wwwroot folder, instead wwwroot\app\webroot\.

So, here's the rule that I've set up on wwwroot.

RewriteRule ^/$  /app/webroot/ [L]                   #1 - if it ask for homepage, show the default homepage from webroot folder.
RewriteCond $1 !^app/webroot/(.*)$ [I]
RewriteRule ^/(.*) /app/webroot/$1 [L]              #2 - if it ask for something else than homepage, make it as relative to webroot folder.

RewriteCond %{REQUEST_FILENAME}     !-d
RewriteCond %{REQUEST_FILENAME}     !-f
RewriteRule ^/(.*)$ /app/webroot/index.php?url=/$1 [QSA,L]   #3 - if it is not requesting for a file or a directory that exist append url to index.php and show it.

 

The problem right now is, if i were to type in:

http://localhost/cake.power.gif

Process 1.

#1 - does not apply
#2 - applies and rewrite it to 'http://localhost/app/webroot/cake.power.gif' [Last Rule]

Process 2.

#1 - does not apply
#2 - Does not fit the condition, does not apply
#3 - Condition check is where the irregularity occured. Since the url is /app/webroot/cake.power.gif, you'd expect %{REQUEST_FILENAME} to be C:\inetpub\wwwroot\app\webroot\cake.power.gif. However, it's still C:\inetpub\wwwroot\cake.power.gif, hence, CSS files and graphic files are never shown.

Is there anyway to fix it??

Coordinator
Feb 20, 2010 at 9:15 PM
Edited Feb 20, 2010 at 9:19 PM

You wrote:

> Since the url is /app/webroot/cake.power.gif, you'd expect %{REQUEST_FILENAME} to be C:\inetpub\wwwroot\app\webroot\cake.power.gif. However, it's still C:\inetpub\wwwroot\cake.power.gif, hence, CSS files and graphic files are never shown.

But I don't think that is true.  You told me that the URL is http://localhost/cake.power.gif .  In that case, the REQUEST_FILENAME is, in fact,  C:\inetpub\wwwroot\cake.power.gif  . 

I don't understand why you expect REQUEST_FILENAME to evaluate to C:\inetpub\wwwroot\app\webroot\cake.power.gif  , when the URL is http://localhost/cake.power.gif.   

------ 

You want a fix, but I don't know what's broken. 

I suspect your rules might be incorrect. They may be NOT doing what you think they are doing, or what you want them to do.

I may be able to help, if you can give me this information:

  • What URLs does your app expose now?  Give me some examples of the non-SEO (or unrewritten) URLs that are available, if you don't use IIRF or another rewriter.
  • What would you like those URLs to be, in simplified form (WITH the use of a rewriter)?  Give me a table of 2 or 3 or 4 URLs. 

 

 

Feb 22, 2010 at 3:58 AM
Cheeso wrote:

You wrote:

> Since the url is /app/webroot/cake.power.gif, you'd expect %{REQUEST_FILENAME} to be C:\inetpub\wwwroot\app\webroot\cake.power.gif. However, it's still C:\inetpub\wwwroot\cake.power.gif, hence, CSS files and graphic files are never shown.

But I don't think that is true.  You told me that the URL is http://localhost/cake.power.gif .  In that case, the REQUEST_FILENAME is, in fact,  C:\inetpub\wwwroot\cake.power.gif  . 

I don't understand why you expect REQUEST_FILENAME to evaluate to C:\inetpub\wwwroot\app\webroot\cake.power.gif  , when the URL is http://localhost/cake.power.gif.   

Though the URL first typed in is http://localhost/cake.power.gif after the second rule's been evaluated it's changed to http://localhost/app/webroot/cake.power.gif , hence I exepect REQUEST_FILENAME to be C:\inetpub\wwwroot\app\webroot\cake.power.gif at least that's how the rewriting is done initially for mod_rewrite anyway.

As for the infos you've asked, see below:

Page

No Rewriting

Rewritten

Home Page

http://localhost/app/webroot/

http://localhost/

Single Page

http://localhost/index.php?url=/page/lorem-ipsum/id:18

http://localhost/page/lorem-ipsum/id:18

List page with query in url

http://localhost/index.php?url=/reports/page:2/sort:date/direction:asc/&month_filter=02

http://localhost/reports/page:2/sort:date/direction:asc/?month_filter=02

Admin Home

http://localhost/index.php?url=/admin/

http://localhost/admin/

Admin (other pages)

http://localhost/index.php?url=/admin/[any_url_like_above]

http://localhost/admin/[any_url_like_above]

 I hope this makes it clear, do let me know if there's anything else that I've left out.

Feb 22, 2010 at 5:28 AM

Please have a look at the following .htaccess codes that apache mod_rewrite use to configure it.

 

## [root]/.htaccess
RewriteEngine on
RewriteRule    ^$ app/webroot/    [L]
RewriteRule    (.*) app/webroot/$1 [L]
## [root]/app/webroot/.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]

 

 

<IfModule mod_rewrite.c>
   RewriteEngine on
   RewriteRule    ^$ app/webroot/    [L]
   RewriteRule    (.*) app/webroot/$1 [L]
</IfModul
Feb 22, 2010 at 6:14 PM

I'm having a similar problem. What we're looking for IIRF to do (if I can speak for mmhan) is update the physical path represented by %{REQUEST_FILENAME} when the URL is updated by a RewriteRule. That way if the ruleset is run again after a match (the "L" modifier isn't used) IIRF will test against the new file, not the old one.

As an example, we start with:

%{HTTP_URL} = /whoami
%{REQUEST_FILENAME} = c:\wwwroot\whoami

The following rule is executed against the requested URL:

RewriteRule ^/whoami$ /about.htm

And the server variables are updated to hold this information:

%{HTTP_URL} = /about.htm
%{REQUEST_FILENAME} = c:\wwwroot\about.htm

If this isn't possible or recommended, perhaps you can add new variables that represents the current virtual and physical paths.

Feb 22, 2010 at 6:20 PM

Also, here's the configuration I'm using to work around the issue.

RedirectRule ^/path/to/cakeapp$ /path/to/cakeapp/ [I]

RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^/path/to/cakeapp/app/webroot.*$ - [I]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_URL} !^/path/to/cakeapp/app/webroot.*$
ProxyPass ^/path/to/cakeapp(.*)$ http://%{HTTP_HOST}/path/to/cakeapp/app/webroot$1 [I]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/path/to/cakeapp/app/webroot(.*)$ /path/to/cakeapp/app/webroot/index.php?url=$1 [I,L,QSA]

Normally the ProxyPass line would just be another RewriteRule. But since %{REQUEST_FILENAME} is never updated I have to force a new request to the server. I could use RedirectRule instead of ProxyPass ... but then all my pretty URLs are less so.

Unfortunately, I'm not sure this is a viable work-around for two reasons:

  1. (minor) I don't really like the fact that proxying the request can cause a delay in the response.
  2. (major) I'm having problems with response timeouts with this method. Sometimes a page will load fine, other times some of the assets from the page (images, css) won't load correctly.

Mainly because of the second issue I haven't yet implemented IIRF on our production server.

Mar 1, 2010 at 5:35 PM

Do you think the timeouts I'm experiencing when using ProxyPass could be mitigated using the new ProxyTimeouts directive available in Change Set 63993?

Coordinator
Mar 1, 2010 at 7:27 PM

mmhan,  maybe you want a different server variable. I think your problem is that REQUEST_FILENAME is not affected by URL rewrites.  Does that sound like I've understood properly?

If that variable is wrong, try PATH_TRANSLATED or SCRIPT_NAME or one of the other similar IIS server variables.

Sweeney, your use of ProxyPass to get around the challenge seems like the wrong tool for the job.  Yes, the timeouts could be related; by using IIRF to proxying a request to itself, you may have thread starvation in the worker process.

 

Mar 3, 2010 at 6:34 PM
Edited Mar 3, 2010 at 6:48 PM

Ok, so based on Cheeso's response I decided to drop usage of ProxyPass. And based on what's reported in the log files (RewriteLogLevel 4) it doesn't look like the server variables are updated to reflect the changes made by URL rewrites. On the second pass of the ruleset the server variables report the same value as on the first pass.

However, in reading the documentation again and toying around I have come up with a solution that appears to work quite well for CakePHP installations, which I'm happy to share. These rules are based on creating a virtual directory for your CakePHP site and placing everything in that directory. You would have to modify the rules if your virtual directory pointed at CakePHP's app/webroot folder ... I think, but haven't yet tested, that you would just remove the "app/webroot" portion of the URL tests. Also, if your CakePHP install is on the site root, "/path/to/cakesite" would just be /.

# If the URL references a file or directory in the webroot then do nothing
RewriteCond %{APPL_PHYSICAL_PATH}$1 -f [OR]
RewriteCond %{APPL_PHYSICAL_PATH}$1 -d
RewriteRule ^/path/to/cakesite/(app/webroot.*)$ - [I,L]

# If the URL does not reference a file or directory, and if the URL does not point to the webroot
# rewrite the URL to insert the path to the webroot
# note: this rule is not needed if the site/vdir root points to the CakePHP webroot
RewriteCond %{APPL_PHYSICAL_PATH}$2 !-f
RewriteCond %{APPL_PHYSICAL_PATH}$2 !-d
RewriteCond $1 !^/path/to/cakesite/app/webroot.*$
RewriteRule ^(/path/to/cakesite/(.*))$ /path/to/cakesite/app/webroot/$2 [I]

# If the URL does not reference a file or direcotry
# rewrite the URL so CakePHP will parse the controller/action
RewriteCond %{APPL_PHYSICAL_PATH}$1 !-f
RewriteCond %{APPL_PHYSICAL_PATH}$1 !-d
RewriteRule ^/path/to/cakesite/(app/webroot(.*))$ /path/to/cakesite/app/webroot/index.php?url=$2 [I,L,QSA]

Cheeso, you might consider adding an example ini for CakePHP.

[edited to generalize URL paths]

Coordinator
Mar 3, 2010 at 7:06 PM

Thanks, Sweeney, that's helpful.

I'll include that in the docs.

Coordinator
Mar 3, 2010 at 7:07 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Coordinator
Mar 4, 2010 at 5:44 PM

Sweeney, I'd like your opinion on a related workitem:  http://iirf.codeplex.com/WorkItem/View.aspx?WorkItemId=25426 

You mentioned that you would have to prepend /path/to/cakesite to each pattern. There's a workitem that proposed to make a change that would eliminate the need to do this.  I'd like your opinion on whether it would be helpful to you or not.

 Have a look and comment if you've got a moment.

Jun 10, 2010 at 10:12 PM

When setting the virtual directory to point to CakePHP's app/webroot folder, the first and second blocks kept rewrite from working. When I left only the third block (set as follows), it worked like a charm:

# If the URL does not reference a file or direcotry
# rewrite the URL so CakePHP will parse the controller/action
RewriteCond %{APPL_PHYSICAL_PATH}$1 !-f
RewriteCond %{APPL_PHYSICAL_PATH}$1 !-d
RewriteRule ^/((.*))$ /index.php?url=$2 [I,L,QSA]



Apr 19, 2011 at 7:21 AM
Edited Apr 20, 2011 at 1:11 AM

I have been using this for my cakephp site and found that the example here does not work currently with cakephp 1.3 a bracket is in the incorrect position.

Here is the working solution:

RewriteLog c:\logs\iirf
RewriteLogLevel 1
IterationLimit 10
MaxMatchCount 10
RewriteEngine ON
StatusInquiry ON

# If the URL references a file or directory in the webroot then do nothing
RewriteCond %{APPL_PHYSICAL_PATH}$1 -f [OR]
RewriteCond %{APPL_PHYSICAL_PATH}$1 -d
RewriteRule ^/path/to/cakesite/(app/webroot.*?)(\?.*)*$ - [I,L]

# If the URL does not reference a file or directory, and if the URL does not
# point to the webroot, rewrite the URL to insert the path to the webroot.
# Note: this rule is not needed if the site/vdir root points to the CakePHP
# webroot
RewriteCond %{APPL_PHYSICAL_PATH}$2 !-f
RewriteCond %{APPL_PHYSICAL_PATH}$2 !-d
RewriteCond $1 !^/path/to/cakesite/app/webroot.*$
RewriteRule ^(/path/to/cakesite/(.*?))(\?.*)*$ /path/to/cakesite/app/webroot/$2 [I]

# If the URL does not reference a file or direcotry# rewrite the URL so
# CakePHP will parse the controller/action
RewriteCond %{APPL_PHYSICAL_PATH}$1 !-f
RewriteCond %{APPL_PHYSICAL_PATH}$1 !-d
RewriteRule ^(/path/to/cakesite/app/webroot(.*?))(\?.*)*$ /path/to/cakesite/app/webroot/index.php?url=$2 [I,L,QSA]


Edited to work correctly for '?' url passed params such as unit tests