We have a client who has created a number of sub-stores under their main Magento website, so that each of these stores has its own Magento skin, logo and so forth. However, they also have associated subdomains, which normally must be manually specified in the main index.php file so that Magento can be told to run the appropriate store in place of the default. This post details a way to automate the process and make it easier for the user to add additional sub-stores themselves.

Normally, the relevant part of index.php would look something like the following:


$host = explode(':', $_SERVER['HTTP_HOST']);
switch ($host[0]) {
 case 'other.example.com':
 $store = 'other';
 break;

 default:
 $store = 'default';
 break;
}
Mage::run($store, 'store');

As mentioned, the major flaw in this is that it requires manually editing the switch statement every time you want to add one of these sub-stores. Fine if you only ever have two or three, but once you start adding more it can quickly add up to a significant amount of time and effort. Moreover, if it's something that needs to be maintained by site administrators who aren't familiar with PHP, you run the risk of having incorrect code and breaking the whole site.

Because of these issues I set about creating a way to have these values retrieved from the database, rather than requiring modifications to index.php every time. The URLs are stored in the database table core_config_data with the path value "web/unsecure/base_url". For individual store views the scope must be restricted to just "stores". By joining these results with the store codes from the core_stores table we have all the values we need. Once we have collected all these results we can enter them into a associative array with the domain as the key and the code as the value.

From there we do things in a similar fashion to before, but we do a lookup in our array for the store code instead of using a switch. Here is the complete code:


$sites = array();
if (file_exists('app/etc/local.xml')) {
 $xml = simplexml_load_file('app/etc/local.xml');
 $host = $xml->global->resources->default_setup->connection->host;
 $username = $xml->global->resources->default_setup->connection->username;
 $password = $xml->global->resources->default_setup->connection->password;
 $dbname = $xml->global->resources->default_setup->connection->dbname;

 $db = mysql_connect($host, $username, $password);
 mysql_select_db($dbname, $db);
 
 $result = mysql_query('SELECT * FROM core_config_data
 INNER JOIN core_store ON core_store.store_id = core_config_data.scope_id
 WHERE scope LIKE \'stores\' 
 AND path LIKE \'web/unsecure/base_url\'');

 while ($row = mysql_fetch_assoc($result)) {
 $sites[substr(trim($row['value'],'/'), 7)] = $row['code'];
 }
 mysql_close($db);
}

$host = explode(':', $_SERVER['HTTP_HOST']);
if (isset($sites[$host[0]])) {
 $store = $sites[$host[0]];
} else {
 $store = 'default';
}
Mage::run($store, 'store');

Assuming you are only using store views (confusingly referred to as stores internally) then this code will be usable as is. It can be modified fairly easily to work for websites - change scope to be "website", join with the core_website table, use 'website' in Mage::run. I'm sure it could be expanded upon further to allow for using either websites or store views. Since this method requires an extra database query every time index.php is called, but the data changes less frequently, it could also be extended to add some sort of caching for performance optimisation.