views:

42

answers:

2

We have a custom PHP/MySQL CMS running on Linux/Apache thats rolled out to multiple sites (20+) on the same server. Each site uses exactly the same CMS files with a few files for each site being customised.

The customised files for each site are:

/library/mysql_connect.php
/public_html/css/*
/public_html/ftparea/*
/public_html/images/*

There's also a couple of other random files inside /public_html/includes/ that are unique to each site. Other than this each site on the server uses the exact same files. Each site sitting within /home/username/. There is obviously a massive amount of replication here as each time we want to deploy a system update we need to update to each user account. Given the common site files are all stored in SVN it would make far more sense if we were able to simply commit to SVN and deploy to a single location direct from there. Unfortunately, making a major architecture change at this stage could be problematic. In my mind the ideal scenario would mean creating an account like /home/commonfiles/ and each site using these common files unless an account specific file exists, for example a request is made to /home/user/public_html/index.php but as this file doesnt exist the request is then redirected to /home/commonfiles/public_html/index.php. I know that generally this approach is possible, similar to how Zend Framework (and probably others) redirect all requests that dont match a specific file to index.php. I'm just not sure about how exactly to go about implementing it and whether its actually advisable. Would really welcome any input/ideas people have got.

EDIT AllenJB's comment reminded me that we have previously explored AliasMatch as a potential solution to this, we ended up with an general.conf file for a user that looked something like this:

php_admin_value open_basedir "/home/commonfi:/home/usertes:/usr/lib/php:/usr/local/lib/php:/tmp"
php_admin_value include_path "/home/commonfi"
AliasMatch (.*).php /home/commonfi/public_html/$1.php
AliasMatch (.*).html /home/commonfi/public_html/$1.html
+1  A: 

You certainly can build a "cascading" system as you describe (load local file, if that doesn't exist, load global file). The complexity is that the files are loaded in different ways (using include() in PHP, through the web, ... maybe even more ways?)

Filesystem includes

If the includes/ consist of files containing one PHP class each, you could use an autoloader like Zend Framework does. The autoloader would look first for a custom version of the include file, and if it doesn't find one, include the global version instead. I happen to have such an autoloader handy if you need code to start with.

If the includes don't match the one-class-per-file structure, you would have to build a custom include() function that fetches the local version of the file or, failing that, the global one.

Pseudo-code:

function fetch_path($name)
 { 
 if (file_exists(LOCAL_DIRECTORY."/$name")) return LOCAL_DIRECTORY."/$name";
 if (file_exists(GLOBAL_DIRECTORY."/$name")) return GLOBAL_DIRECTORY."/$name";
 return false;
}

Web resources

The second part is going to be the web part (i.e. Web URLs with local or global files). I think this should be pretty easily solvable using the -f switch in a .htaccess file. You would build a rule that rewrites failed requests (!-f) to the local web resources directory (example.com/css/main_stylesheet.css) to the global one /home/commonfiles/public_html/main_stylesheet.css). You would need to fiddle around with Apache's server config to be able to rewrite local requests to the commonfiles directory, but it should be possible.

That is maybe worth a separate question.

Pekka
Yes i have considered this but if i have a directory with all files needed to be in common files except 1 (for example) then i'm not sure how that would/could be handled
seengee
@seengee true, that is difficult to handle using symlinks. Hmm.
Pekka
Create symlinks for all the files inside the directory, not the directory itself. Not the best solution, but the only one that would 'work'.
Matthew Scharley
@Matthew - that is an option but it does kinda suck for obvious reasons
seengee
@seengee I expanded my answer a bit.
Pekka
@sengee: I never said it was a good option, or that I advocated it, simply that it was the only way to work around the problems presented with that implementation. You're right, it's a horrific idea, don't do it.
Matthew Scharley
@Matthew yeah, of course. sorry if i sounded flippant, i appreciate you were simply providing a solution that would work
seengee
@Pekka - unfortunately `includes` contains a real mixture of files, some classes other old style procedural code so an autoloader wouldn't work. I'm considering moving the random files within includes out to another location to solve that issue.
seengee
@seengee right. However, you have that already sorted with your ingenious `include_path` solution in your update, haven't you? Which would leave only the web part.
Pekka
@Pekka - thanks for all the help but ultimately the solution that has worked is AllenJB's answer with my own work.
seengee
@seengee no problem, I already thought so.
Pekka
+1  A: 

You can set this up via the Apache configuration - you probably want Alias, but there are several options: http://httpd.apache.org/docs/2.2/urlmapping.html

AllenJB
I do like this option the best, its one i have looked at previously. Added code above to show this
seengee