I have a client site that consists of a CakePHP installation and a Magento installation:

/web/example.com/app/ <== CakePHP
/web/example.com/app/webroot/ <== DocumentRoot
/web/example.com/app/webroot/store/ <== Magento
/web/example.com/config/ <== Site-wide config
/web/example.com/vendors/ <== Site-wide libraries

The server runs Apache 2.2.3.

The problem

The whole company has FTP access and got used to clogging up the /web/example.com/, /web/example.com/app/webroot/, and /web/example.com/app/webroot/store/ directories with their own files. Sometimes these files need HTTP access and sometimes they don't.

In any case, this mess makes my job harder when it comes to maintaining the site. Code merges, tarring the live code, etc, is very complicated and usually requires a bunch of filters.

Abandoned solution

At first, I thought I would set up a new subdomain on the same server, move all of their files there, and change their FTP chroot. But that wouldn't work for these reasons:

Firstly, I have no idea (and neither do they remember) what marketing materials they've sent out that contain URLs to certain resources they've uploaded to the server, using the main domain, and also using abstract subdomains that use the main virtual host because it has ServerAlias *.example.com. So suddenly having them only use static.example.com isn't feasible.

Secondly, The PHP scripts in their projects are potentially very non-portable. I want their files to stay in as similar an environment as they were built as I can. Also, I do not want to debug their code to make it portable.

Half-baked solution

After some thought, I decided to find a way to section off the actual website files into another directory that they would not touch. The company's uploaded files would stay where they were. This would ensure that I didn't break any of their projects that needed HTTP access. It would look something like this:

/web/example.com/ <== A bunch of their files are in here
/web/example.com/app/webroot/ <== 1st DocumentRoot; A bunch of their files are in here
/web/example.com/app/webroot/store/ <== Some more are in here
/web/example.com/site/ <== New dir; Contains only site files
/web/example.com/site/app/ <== CakePHP
/web/example.com/site/app/webroot/ <== 2nd DocumentRoot
/web/example.com/site/app/webroot/store/ <== Magento
/web/example.com/site/config/ <== Site-wide config
/web/example.com/site/vendors/ <== Site-wide libraries

After I made this change, I would not need to pay attention to anything except for the stuff within /web/example.com/site/ and my job would be a lot easier. I would be the only one changing stuff in there.

So here's where the Apache magic would happen: I need an HTTP request to http://www.example.com/ to first use /web/example.com/app/webroot/ as the document root. If nothing is found (no miscellaneous uploaded company projects are found), try finding something within /web/example.com/site/app/webroot/.

Another thing to keep in mind is, the site might have some problems if the $_SERVER['DOCUMENT_ROOT'] variable reads /web/example.com/app/webroot/ but the actual files are within /web/example.com/site/app/webroot/. It would be better if the DOCUMENT_ROOT environment variable could be /web/example.com/site/app/webroot/ for anything within the /web/example.com/site/app/webroot/ directory.


Is my half-baked solution possible with Apache 2.2.3?

Is there a better way to solve this problem?

  • Have you already looked at the documentation for mod_rewrite? – ruquay Jan 7 '11 at 18:55

I believe mod_rewrite would do the trick. In your virtual host for www.example.com, you could do something like this:

RewriteEngine On                                                                                                                                  
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /site/app/webroot/$1 [R=301,L] 

This should rewrite any non-existing file/directory requests to site/app/webroot/* with a 301 request. This should update the DOCUMENT_ROOT to match the directory. You can drop the R=301 flag to just do an internal rewrite (the user doesn't see the change) but I'm not 100% sure that will update the DOCUMENT_ROOT...It might.

Note, this example is from memory and not tested, but it gives a general idea of what mod_rewrite can do

  • Why would a 301 be necessary if the URL isn't changing? – Matt Alexander Jan 7 '11 at 21:23
  • If you don't want the url to change, you don't want the R=301. Try it without and see if you get any conflicts with the DOCUMENT_ROOT...I don't think you will, but am not 100% sure on it – DTest Jan 7 '11 at 21:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.