Video icon 64
Learning to code? Skill up faster with our practical video courses. Start your free trial today.
Advertisement

Basecamp Style Subdomains With CodeIgniter

by

CodeIgniter is a simple and lightweight PHP framework used to create powerful web applications. Today, we are going to do something nifty: we'll combine user names and subdomains to make for a more cohesive user experience.

If you're a bit confused, this feature allows your users to access their accounts by typing in a custom url, which maps to their user name, such as harbinger.yourapp.com.


Overview

In this tutorial, we are going to be creating both a front-end view and a back-end application view, similar to the configuration used in Basecamp, where visiting basecamphq.com shows the homepage, but visiting a subdomain displays the login page.

We will be using the fictional address nettutsapp.com, and will create a sample "dashboard" page; however, you could incorporate this into an existing project with relative ease.

basecamp-comapre

Before you begin, make sure that you have a web server with PHP installed. You also need to download CodeIgniter; in the example, I am using CodeIgniter 2.0, but the code should work on 1.7.2. So let's get started!


Step 1: DNS Configuration

First, we need to configure our DNS settings to make all subdomains resolve to a single address. If you are working on a live server, then you will have to change your DNS settings with the company who handles your DNS. This is most commonly your web host or domain registrar.

To cover each configuration in this tutorial would take too much time. Instead, ask your host for some help to set up wildcard subdomains. You might expect to add something like the line below to your DNS configuration.

*.nettutsappapp.com.      IN  A    91.32.913.343

Instead, if you are working on a local server, adding a wildcard subdomain to the hosts file is quite tricky. What I prefer to do is add single entries for testing purposes. These can be deleted after you have finished. For our domain, we need to add four entries as follows:

  • 127.0.0.1     nettutsapp.com
  • 127.0.0.1     user1.nettutsapp.com
  • 127.0.0.1     user2.nettutsapp.com
  • 127.0.0.1     user3.nettutsapp.com

Mac Hosts Configuration

To do this on a Mac, open Terminal and type sudo nano /etc/hosts. Use the arrow keys to move to the bottom of the document, and add the entries to the bottom of the file. Once done, press Ctrl+X and Y to confirm the save.

dns-terminal1

Windows Hosts Configuration

If you are using Windows, browse to the directory C:\Program Files\system32\drivers\etc and open the hosts file in Notepad, or your preferred text editor. Add four entries, shown above, and save the file.

If you've made DNS changes to a live server, it will take a while before you notice any effect. If you made changes to your hosts file, the changes will be immediate.


Step 2: Apache Configuration

The aim here is to set up two Virtual Hosts in the Apache Configuration,:one serves the front end page (Basecamp Homepage), and the other serves the page seen when accessed via a subdomain (Dashboard Page).

To add new entries, you need to open the httpd.conf file, which can be found in the Apache installation directory. It's often found in the bin/apache/conf folder. However, depending on your server configuration, the location may vary.

Once opened, you need to add the two entries, shown below. Be sure to change the DocumentRoot to a location of your choice, which you have created.

Note: Remember the wildcard and the different directory path on the second VirtualHost.

WAMP Users: I recommend reading this post, which describes how to set up VirtualHosts. You may also encounter permission problems; so I recommend placing your VirtualHost directories inside the www directory.

	<VirtualHost *:80>
		DocumentRoot "/Users/densepixel/Sites/MAMP PRO/nettutsappfront"
		ServerName nettutsapp.com
		ServerAlias nettutsapp.com
	
		<Directory "/Users/densepixel/Sites/MAMP PRO/nettutsappfront">
			Options -Indexes 
			Options FollowSymLinks
			AllowOverride All
		</Directory>
	</VirtualHost>
	
	<VirtualHost *:80>
		DocumentRoot "/Users/densepixel/Sites/MAMP PRO/nettutsapp"
		ServerName nettutsapp.com
		ServerAlias *.nettutsapp.com
	
		<Directory "/Users/densepixel/Sites/MAMP PRO/nettutsapp">
			Options -Indexes 
			Options FollowSymLinks
			AllowOverride All
		</Directory>
	</VirtualHost>

Once you have saved the file, you need to restart Apache for the changes to take effect.

Make sure that you have created the directories you specified in the httpd.conf file before starting the server.


Step 4: Testing Our Server Configuration

Before we test the configuration, place a basic html page in each of the directories you created earlier. Maybe add a single line of text to each, so you can differentiate them. I have copied an example for you to use.

<!DOCTYPE html>
<html lang="">
<head>  
	<meta charset="utf-8">
	<title>NetTuts App Front</title>
</head>
<body>
	NetTutsApp Front
</body>
</html>

Next, open your favorite browser, and first check the address nettutsapp.com. If everything works, you should be looking at the page you placed in the 'nettutsappfront' directory.

Next, check a subdomain, eg. user1.nettutsapp.com; this should show you the other page you created in the directory.

config-success

You can go on to check the other subdomains you specified in the hosts file, which should all show the page saved within our directory.

Step 5: CodeIgniter Installation

This tutorial assumes that you know how to install CodeIgniter. If not, you should take a look at this video tutorial by Jeffrey Way, which explains the process in detail.

Place the CodeIgniter files into our directory after deleting the html page we created before. If you are using CodeIgniter 1.7.2, you may want to take the application folder out of the system folder.

nettutsapp-ci

Test the installation by browsing to the URL user1.nettutsapp.com, and you should see the CodeIgniter Welcome Page.

nettutsapp-ci-welcome

Step 6: Setting up CodeIgniter

Set up CodeIgniter as you normally would, as described in this tutorial. You may want to remove the index.php from the URL, autoload some libraries or helpers, etc. For the purposes of this tutorial, we need to autoload the database library and the url helper. Open the autoload.php file in the config directory, and add the relevant entries.

We also need to change the default controller to one which we will be making, called dashboard. This value can be changed within the /config/routes.php file.

Base_url

For the user subdomains, we need to make the base_url variable dynamic, as the application will be receiving requests from a number of potential subdomains.

The easiest way to do this is by using the HTTP_HOST variable. Open the config.php file, and find the variable $config['base_url'], and replace it with the following code:

if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on"){$ssl_set = "s";} else{$ssl_set = "";}
$config['base_url'] = 'http'.$ssl_set.'://'.$_SERVER['HTTP_HOST'];

This code allows for HTTPS connections, however, if you never plan on using HTTPS, you can simplify it to base_url = $_SERVER['HTTP_HOST'].

Database Settings

Before we go ahead and add the database settings into our CodeIgniter application, we need to create both the database and a sample table.

This example application uses one database and one table. This table will hold all the subdomains currently assigned, and some basic information about them. If you've decided to use this code in your own application, you'll have to generally assign multiple users to a single subdomain, however that database schema is beyond the scope of this tutorial.

The table is named nt_subdomains, within the database ntapp, and has four fields:

  • subdomain_id(primary, auto_increment)
  • subdomain_name
  • user_fname
  • user_sname

I have also populated the table with two records, which match the subdomains we've added to our hosts file:

php-my-admin

Now we can open the database config, file found in /application/config/database.php, and edit the following values so that they match your personal configuration settings.

$db['default']['hostname'] = 'localhost';
$db['default']['username'] = 'root'; //MAMP default
$db['default']['password'] = 'root'; //MAMP default
$db['default']['database'] = 'ntapp';

And we're done setting up our CodeIgniter installation. Let's start using the subdomains in our application.


Step 7: Creating Our Controllers and Views

For this application, we are going to create two controllers. The first is an error controller, which displays an error if the subdomain has not been registered for use in the application. The other controller is our main dashboard controller, which is what the user sees if the subdomain has been added to our database.

Error Controller

Let's go ahead and create our error controller. First, create a new file in the /application/controllers directory, and call it error.php.
Note: The name of the file is important

<?php

class Error extends Controller {

	function Error()
	{
		parent::Controller();
	}

	function index()
	{
		$this->load->view('error');
	}
}

Add the code above to our new error.php file. The index function loads a view called 'error', which we will be creating later.

Dashboard Controller

Now we need to create the main dashboard controller, which will be loaded when a user enters one of the subdomains. The controller will then check whether the subdomain has been registered, and will redirect as necessary. We'll add this code later, but first, we need to create the basic controller.

Create a new file within the controllers directory, and name it dashboard.php. Within this file, we need to create the controller and load the dashboard view. Copy the code below and save the file.

<?php

class Dashboard extends Controller {

	function Dashboard()
	{
		parent::Controller();
	}

	function index()
	{
		$this->load->view('dashboard');
	}
}

Error View

The error page will be displayed when a user tries to access a subdomain, which has not been registered for use by the application. For the purposes of the tutorial, simply create a basic page, displaying the message Subdomain Not Registered. Add the code below to a new file called error.php and save it within the application/views folder.

<html>
<head>
	<title>Application Error : Nettuts App</title>
</head>
<body>

	<h1>Nettuts Application Error</h1>

	<p>Subdomain Not Registered</p>

</body>
</html>

Dashboard View

initial-dashboard

For the time being, we will only be creating a basic dashboard page. You can use the same structure as the error view, and just change it to read Nettuts Dashboard, or something along those lines. Save the page as dashboard.php, within the application/views folder.

Test the two views by visiting the URLs:

  • user1.nettutsapp.com/index.php/error
  • user1.nettutsapp.com/index.php/dashboard

Working? Let's move on.


Step 8: Extending Our Dashboard Controller (Part 1)

The next step is to extract the subdomain name in our controller so we can use it in a database query.

We are going to insert our subdomain checking code into the construct function within the dashboard controller. (Underneath the parent::Controller()). This means that the subdomain will be checked when any of the functions within the dashboard controller are accessed.

The easiest way to extract the subdomain name is to use the PHP explode function, and set the delimiter to '.'. As we only need the first part, we can split it into two parts, and then assign the first part (the subdomain name) to a variable.

To test this, we can echo the variable out in the controller itself. See the code below:

<?php

class Dashboard extends Controller {

	function Dashboard()
	{
		parent::Controller();
		
		$subdomain_arr = explode('.', $_SERVER['HTTP_HOST'], 2); //creates the various parts
		$subdomain_name = $subdomain_arr[0]; //assigns the first part
		echo $subdomain_name; // for testing only
	}


}

Access your subdomain URLs, and you should see the correct subdomain echoed on your page, as below.
Note: You can delete the echo statement now.

subdomain-parse1

Now that we have access to the subdomain name in our controller, we can check to see if it has been added the table we created earlier.

We will be using CodeIgniter's ActiveRecord Class to build our queries, which will check the table for the accessed subdomain. If it is present, then the user will be able to access the dashboard page. If, on the other hand, the subdomain has not been entered, then they are denied access, and are then redirected to the error page we created earlier.

For this tutorial, we won't be using models as it makes the tutorial much easier to follow. CodeIgniter is quite flexible in that it doesn't force you to use them.

First, we need to assemble the query as show below. This code will only work in PHP5, as it uses method chaining; however, you can change it to your liking.

// adds on from rest of construct //
$this->db->from('nt_subdomains')->where('subdomain_name', $subdomain_name);
$query = $this->db->get();

We can use the CodeIgniter function row() to check whether that subdomain exists in the table. If it doesn't, then we need to use the redirect function to redirect our users to the error controller. The next part of the code is below:

// adds on from previous code //
if($query->num_rows() < 1)
		{
		redirect ('error');
		}

Let's test this by accessing user1.nettutsapp.com, which should direct you to the dashboard page. Now, try user3.nettutsapp.com, which should redirect you to the error page as it was not entered into the table.

subdomain-comapre1

Step 9: Extending Our Dashboard Controller (Part 2)

Now we can use the information in the table to display specific information for each subdomain.

We'll add to the index function in our dashboard controller. First, copy the subdomain name code and the database query we used before.

function index()
	{
		$subdomain_arr = explode('.', $_SERVER['HTTP_HOST'], 2);
		$subdomain_name = $subdomain_arr[0];
		
		$this->db->from('nt_subdomains')->where('subdomain_name', $subdomain_name);
		$query = $this->db->get();
		
	}

We are using CodeIgniter's row() function to retrieve the result of the query. The row function returns a single result row, which means we don't need to use a foreach loop; it's unnecessary.

// adds on from rest of index function //
$subdomain_info = $query->row();

Then, assign the user_fname and user_sname column values to the array, $data, which is then passed to the view.

$data['fname'] = $subdomain_info->user_fname;
$data['sname'] = $subdomain_info->user_sname;
$this->load->view('dashboard', $data);

We can use these values within our view by using the variables $fname and $sname. Open the dashboard view and edit it to read:

	<p>Welcome to your dashboard 
	<b><?php echo $fname; ?> <?php echo $sname ?></b>
	</p>

And we're done! Let's test it.


Step 10: Testing

Try all of the URLs, and hopefully, if everything went according to plan, the results should be as follows:

  • nettutsapp.com → Front End Page
  • user1.nettutsapp.com → Dashboard (John Doe)
  • user2.nettutsapp.com → Dashboard (Steve Smith)
  • user3.nettutsapp.com → Error Page
finalresult

Controller and View Code

Here's the complete cote used for our controllers and views:

Dashboard Controller

<?php

class Dashboard extends Controller {

	function Dashboard()
	{
		parent::Controller();
		
		$subdomain_arr = explode('.', $_SERVER['HTTP_HOST'], 2);
		$subdomain_name = $subdomain_arr[0];
		
		
		$this->db->from('nt_subdomains')->where('subdomain_name', $subdomain_name);
		$query = $this->db->get();
		
		if($query->num_rows() < 1)
		{
		redirect ('error');
		}

	}

	function index()
	{
		$subdomain_arr = explode('.', $_SERVER['HTTP_HOST'], 2);
		$subdomain_name = $subdomain_arr[0];
		
		$this->db->from('nt_subdomains')->where('subdomain_name', $subdomain_name);
		$query = $this->db->get();
		
		$subdomain_info = $query->row();
		$data['fname'] = $subdomain_info->user_fname;
		$data['sname'] = $subdomain_info->user_sname;
		$this->load->view('dashboard', $data);
	}
}

Error Controller

<?php

class Error extends Controller {

	function Error()
	{
		parent::Controller();
	}

	function index()
	{
		$this->load->view('error');
	}
}

Dashboard View

<html>
<head>
	<title>Dashboard : Nettuts App</title>
</head>
<body>

	<h1>Nettuts Dashboard</h1>

	<p>Welcome to your dashboard 
	<b><?php echo $fname; ?> <?php echo $sname ?></b>
	</p>
	
</body>
</html>

Error View

<html>
<head>
	<title>Application Error : Nettuts App</title>
</head>
<body>

	<h1>Application Error</h1>

	<p>Subdomain Not Registered</p>

</body>
</html>

Conclusion

Of course, this tutorial describes only one way of obtaining this nifty functionality. I'm sure there are many more; so feel free to chime in with your thoughts and opinions in the comments section below.

Advertisement