Specific and generic includes

I am in the process of setting up multiple copies of a script where some of the scripts are shared.

I have got it so that the specific folders redirect to the common one to retrieve web pages not defined in the specific folders.

The problem that I have is where the generic page needs to include a file from a sub-folder of the specific folder that it redirected from. Is there a simple way to get it to look in the include folder under the specific folder first when the page has loaded from the generic folder?

The structure will be something like this:


specific1/
   // no page1.php so gets it from generic (already implemented)
   page2.php
   inc/
       inc1.php  // includes inc2.php
specific2/
   // no page1.php so gets it from generic (already implemented)
   page2.php
   inc/
       inc1.php  // includes inc2.php
generic/
    page1.php // needs to include inc1.php
    inc/
        inc2.php

I am not exactly sure of your requirements but think that by including a common file with a function that is passed a folder array of specific paths and the file name to include, may satisfy your requirements.

Try this:



// _include.php
function _includes($folders=array(), $include='_include.php')
{
 // echo '<br />'.getcwd();
 $result = false; // default

 foreach( $folders  as $folder)
   {
       $inc = $folder .$include;
       if ($result = file_exists( $inc ))
       {
       require_once($inc); // only loads once and failure generates ERROR
           break; // success so jump out of the loop
       }
   }

   return $result;
}

// index.php
   require_once '_includes.php';
     $folders = array(
     'specific1/', 
     'specific2/', 
     'specific3/'',
      'src/fred/'   // tried locally and it works fine
    );
     $result = _includes($folders, 'include.php');
     echo $result ? 'Success' : 'failed';


When http://specific2.com/page1.php is called the page loads from generic/page1.php. The address in the address bar reads http://specific2.com/page1.php but getcwd() returns generic as the path and not specific2 as the path.

When page1.php loads from generic/page1.php with http://specific1.com/page1.php in the address bar it needs to look for the includes in specific1/inc first and if not found there then in generic/inc

When page1.php loads from generic/page1.php with http://specific2.com/page1.php in the address bar it needs to look for the includes in specific2/inc first and if not found there then in generic/inc

Only one specificX folder is relevant at any one time but as far as I can tell PHP has no command that will tell be which one that is.

The redirect to the generic folder is being handled by the .htaccess file in each of the specificX folders using:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*)$ ../generic/$1 [L]

Unfortunately that redirects the main file but doesn’t keep the original starting point for any subsequent references.

I can’t see how a PHP solution could possibly work as the PHP code has no idea of which folder it is supposedly running in and always knows it is running from generic even though it will NEVER be run directly from there.

There can be any number of specificX folders and the code in the generic folder has to work unchanged if an additional specific folder is added - if changes were going to be required then the file would be copied to the new specific folder and changed there so as to override the generic one used by all the other specific folders. At no time will the PHP have access to a lits of the specific folders.

I get the impression that multiple domains all land on the same server and .htaccess is used to point each domain to a single directory.

If that is the case then in the “http://specific1.com/index.php” is called, numerous common $_SERVER parameters could be used to locate files only related to that domain.

The common ones which could be used are:
$_SERVER[“HTTP_HOST”]
$_SERVER[“SERVER_NAME”]
$_SERVER[“DOCUMENT_ROOT”]

// full list
echo ‘<pre>’; print_r($_SERVER); echo ‘<pre>’;


// Common index.php
   require_once .'/_includes.php';
   $folders = array
   (
     $_SERVER["SERVER_NAME"] .'/', // try this specific directory first
     'default/'                    // if above fails then include default
    );
    $result = _includes($folders, 'include.php');
    echo $result ? 'Success' : 'failed'; 

Domain
http://specific1.com => specific1/include.php
http://specific2.com => specific2/include.php
http://specific3.com => specific3/include.php
http://specific4.com => specific4/include.php
http://specific5.com => specific5/include.php
http://generic.com => generic/include.php

No - the exact opposite.

Multiple domains each land in their own folder but much of the code is common to all and needs to be pulled from a shared location. Most of the actual pages will be pulled from the common repository but the includes those pages need to reference will often need to be domain specific.

The problem comes with the shared code which needs to be able to redirect the include calls back to the appropriate sub folders within the original domains to see if there is code contained there and only use the generic copy id a specific one can’t be found.

Domain
http://specific1.com => look in specific1 first and if not found there then get from generic (for both pages and includes)
http://specific2.com => look in specific2 first and if not found there then get from generic
http://specific3.com => look in specific3 first and if not found there then get from generic
http://specific4.com => look in specific4 first and if not found there then get from generic
http://specific5.com => look in specific5 first and if not found there then get from generic
http://generic.com doesn’t exist

The first part works - if the main file isn’t found then it gets the one from generic. The problem is that if a file that then needs to reference exists in the appropriate specific folder I need it to be retrieved from there and not from the generic folder.

From the testing I have done the generic page PHP has no way of telling which specific domain it is running in and so cannot access the right specific folder to look for the includes there first.

For any PHP code to work properly it would need to be able to retrieve the displayed URL and there does not appear to be any way for it to do that.

$_SERVER[“HTTP_HOST”]
$_SERVER[“SERVER_NAME”]
$_SERVER[“DOCUMENT_ROOT”]
all of these identify the WRONG location when the page loaded from generic as they identify generic instead of the correct starting folder (unless the problem is that I am testing locally using folders that are all sub folders of localhost).

It seems more likely that a minor modification to the mod rewrites in the .htaccess would fix it but I have no idea of what that fix would be.

The pages part works - if page 1 is retrieved from generic and there is a link to page 2 that can be found in the appropriate specific folder then it loads the correct page 2 so the HTML recognises which domain the code is running on, it is only the PHP that doesn’t.

I have now done further experiments with virtual domains set up in my local environment and now the original mod rewrite commands don’t work either.

I guess I need to start over.

I now have domains http://specific1.local and http://specific2.local set up as sub folders of the generic folder. (The generic folder could be somewhere else but in any case it needs to be outside of any of the soecific domains so it can be referenced from all of them.

When a page in either of these is requested that does not exist in the specificX folder the page needs to be retrieved from the parent folder instead.

Any includes regardless of whether they are called from pages loaded from the specific or parent folder need to look for the file in the specificX folder first and if not found there need to look in the parent folder.

OK so here is the latest attempt:

  1. Created a GENERIC test sub-domain “aaa” where all the default files are loaded
  2. Created three test sub-domains “test-001”, “test-002” and “test-003”
  3. Some test sub-domains DO NOT have a specific include file so load GENERIC/include.php
  4. ALL index.php files are included from GENERIC/index.php - simplifies testing.

http://test-001.johns-jokes.com/index.php

John,

Thanks for trying but your example only covers one of several possibilities. It is also appears to be a file by file solution and I need a solution that will work automatically for all of the files that the folders might happen to contain.

A given page might exist in a specific folder or it might only exist in generic. If it exists in both then the specific one MUST be used even if the prior page was loaded from generic.

With the includes some may come from specific and some from generic regardless of which the page is in. They might be nested so that a page in generic calls an include in specific which calls another include in generic which calls another include etc.

There are actually about six or so sub-folders and with all of the files in each they need to look for one in specific first and fall back to generic if not found in the specific corresponding to the original domain name 20 pages back. These files include images, pdfs and lots of other things that will be under user control so the redirects need to work back and forth and compensate for the addition or removal of different specific files.

I would expect that this ought to be able to be done with a dozen or less commands in the .htaccess file in each specific folder without needing to recode the thousands of other files that already exist for the generic and one specific folder. The idea is that files can be copied either from generic to a corresponding location in a new specific folder or copied from one specific folder to another in order to set up a new specific folder including all sub-folders and working for all of the 1000+ files that each site will use (while hopefully sharing as many files as possible so that once I have 100000 separate specific folders that 99.9% of changes can hopefully be applied just by changing a few files in generic and they will apply to all of the applicable sites.

I have been working on moving as much of the specific data as possible into the database so that hopefully each specific folder can start with a database config file and the page template file in the includes folder and a couple of pages that generate forms specific to the site. Users would then add hundreds or tens of thousands of images and pdfs to their specific copy.

The other problem is that generic is a folder outside of any of the domains that need to reference it - it basically needs to be treated as if all the files it contains have been copied to the corresponding locations in the specific folder but without overwriting existing files and without physically copying hundreds of files. Does anyone know how to create a .htaccess file that will work like that?

I think you are hoping for a simple solution and I doubt if there is one.

GENERIC SITE:
I think that you should create a http://specific.com with a index .php
.htaccessed redirects to a ./specific1/ folder.
This site covers the majority of URLs and uses $_SERVER[“SERVER_NAME”] as the $title, etc

SPECIFIC SITE:
.htaccessed redirects to a ./SPECIFIC/ folder.
Uses SPECIFIC index.php and include.php files.

As far as keeping up to date with the latest versions of say jQuery or JavaScript, a common file -> function loadLatesVersion(“javascript”) could replace the current hard-coded versions.

I have updated the following link which demonstrates the differences between GENERIC and SPECIFIC:

http://test-001.johns-jokes.com/index.php

If there is anything that the latest version does not cover then please let me know and I attempt a remedy.

The speciofic sites will almost certainly NOT have an index.php as that is one of the pages that is most likely to be generic across all the sites.

Most likely the only pages that will be in each specific folder will be a couple of scripts for creating PDF forms that will be laid out differently for each. There will also probably be two or three specific includes, a couple of specific images (logo and similar) and the rest of the specific files are likely to be in the pdfs folder and in the images folder inside of the gallery. Everything else should be able to share the generic copy.

The idea is to keep everything that is specific to a minimum so that all changes and enhancements can be applied to generic and will then apply across all of the thousands of specific sites all at once.

I had been hoping to be able to extract all of the specific data into the database so that all of the sites could run from the same location but there look like there will be a few files left behind that I can’t make generic.

Is there perhaps a way to work this the other way around where all of the sites point to generic but somehow manage to get their own specific files for those files that don’t exist in generic?

I believe that each specific site should use the ,htaccess file to go into their own named directories.
Each named directpry will load a default index.php file.

Is there perhaps a way to work this the other way around where all of the sites point to generic but somehow manage to get their own specific files for those files that don’t exist in generic?

I believe this would work for all the GENERIC sites but problems will arise for SPECIFIC sites.

Take a look at how the three subdomains, test-001, test-002, test-003 are all in their own directory.
To test this try these two links and they will give identical results - courtesy of the .htaccess file :slight_smile:

http://test-003.johns-jokes.com/index.php

The inverted structure looks like it will be easier to implement, I just lose the ability to directly override generic files, I can manage that by giving the specific files slightly different names to the generic ones they are overriding…

New proposed structure:

-generic folder <– all domains point here eg. specific1.com specific2.com

    • includes (generic)
    • images (generic)
      • includes (specific1)
      • images (specific1)
      • includes (specific2)
      • images (specific2)

and so on.

The following appears to work for the simple redirects. Haven’t had chance to test all the options yet (such as redirecting for entire folders.

Options +FollowSymlinks -MultiViews

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_URI} !^/%{HTTP_HOST}/
RewriteRule ^(.*)$ /%{HTTP_HOST}/$1 [L]

This works for page redirects but it isn’t working for the includes. A page in generic is not finding includes in specific1.com/includes and a page in specific1.com is not finding an include in generic/includes. Presumably the same situation will apply for the images, pdfs, plots etc.

So what do I need to add to these .htaccess commands so that they work for all the files in the sub-folders and not just those in the main ones? Alternatively is there a command I can add to the php.ini that will tell PHP to look in both http://specific1.com/iimage and http://specific1.com/specific1.com/image when looking for an image - and similarly for all the other file types?

This works for page redirects but it isn’t working for the includes. A page in generic is not finding includes in specific1.com/includes and a page in specific1.com is not finding an include in generic/includes. Presumably the same situation will apply for the images, pdfs, plots etc.

If you post a simplified PHP page which is not working, I will install it on my system and see if I can get it to work.

My knowledge of htaccess scripting is search, cut & paste, then trial and error :frowning:

John,

Thanks for your help with this. I have finally realised that everything except the includes will be redirected via the .htaccess. With the includes I need to tell the PHP to look for the includes in both places.

The simplest way I can think of to fix the includes in the main part of the site will be to add a statement to set the include_path at the top of each script so as to include both the generic and applicable specific include directories. With the forum and galler there are only a small number of includes that need to be redirected and they will always need to redirect so I can simply nest the include for the specific directory inside the generic one. That just leaves redirecting where Gallery 3 stores its images for each specific gallery to sort out - I am sure a solution to that will eventually come to me.