Wildcard Subdomain Prerouting


Ever have a need to have wildcard subdomains on your CakePHP application? This is the solution to that problem. Assume all subdomains have there own template folder, and the subdomains need to be able to be created and modified on the fly.

Create a subdomain model, as well as a table in your database called Subdomains with the following schema

MYSQL Subdomain Schema
sub_id         int (11)
sub_name       varchar (255)
sub_template   varchar (255)
sub_active     tinyint(1)

Initially, the URL is used to extract the subdomain and the host name from the clients entry point. The contents are then assigned to an array in a custom variable using the internal cache. The bootstrap is called within the dispatcher stage of the MVC architecture as shown below.

MVC Structure

CakePHP MVC Structure


preg_match('/^(?:www\.)?(?:(.+)\.)?(.+\..+)$/i', env('HTTP_HOST'), $urlmatches); 
Configure::write('SubdomainHTTP', array('subdomain' => empty($urlmatches[1]) ? false : $urlmatches[1], 'hostURL' => empty($urlmatches[2]) ? false : $urlmatches[2])); 

The subdomain is now passed through the application and can be accessed by configure::read. A custom library called SubdomainRoute writes values to the cache and the router then reads the results. If a template is set after the SubdomainRoute is initialized it assumes the client is accessing our application on a valid subdomain found in the database.


App::uses('SubdomainRoute', 'Routes');

if (Configure::read('SubdomainHTTP.subdomain')) {
    $subdomainRouting = new SubdomainRoute();

if (Configure::read('Subdomain.sub_template’) != NULL) {
    Router::connect('/', array('controller' => ‘pages’, 'action' => ‘index’));

The subdomain is determined by accessing the mysql subdomain table. The results are stored and later used for routing (above), as well as assigning a template folder for a particular subdomain (below).


App::uses('Subdomain', 'Model');

class SubdomainRoute extends CakeRoute {

     * Name of the subdomain to use
     * @var
    private $subdomain = NULL;

     * Overrides the routes constructor not to use templates
    public function __construct() {

        $this->subdomain = Configure::read('SubdomainHTTP.subdomain');

        if ($this->subdomain != false) {

     * Determine subdomain (assoc_id), set to global var
     * @return null
    private function setSubdomain() {

        $Subdomain = new Subdomain();
        $subdomain = $Subdomain->find("first", array(
            'conditions' => array('Subdomain.sub_name' => $this->subdomain, 'Subdomain.sub_active' => '1'),
            'recursive' => -1,
            'fields' => array('Subdomain.sub_name', 'Subdomain.sub_template')

        if (!isset($subdomain['Subdomain']['sub_bus_id'])) {
            throw new BadRequestException('The subdomain specified does not exist.');

        Configure::write('Subdomain', array(
            'sub_name' => $subdomain['Subdomain']['sub_name'],
            'sub_template' => $subdomain['Subdomain']['sub_template']

The final step is to tell cake which template the subdomain is associated too. This assumes that you have created the templates folder in the directory.


private function setTheme() {

    $subdomainDetails = Configure::read('Subdomain');
    if (isset($subdomainDetails['sub_template'])) {
        return $this->theme = ucfirst($subdomainDetails['sub_template']);
    return $this->theme = “default”;

Leave a Reply

Your email address will not be published.