Slick vs. Sizzle: The CSS Selector Engine Battle

Javascript frameworks like MooTools and jQuery are used on most modern websites. CSS selector engines are one of the most useful and widely used features in these frameworks. Because of this, selector performance is extremely important for modern web applications.


Both MooTools and jQuery have built their own stand alone selector engines for use in their respective projects. MooTools uses the Slick selector engine and jQuery uses the Sizzle selector engine.


Surprisingly, there are very few performance comparisons out there for these two engines. Below are the results of a selector engine performance test between MooTools 1.3.2 and jQuery 1.6.2. The original code for this test came from this post and you can check out the source code on jsFiddle.



jQuery seems faster than MooTools for almost any type of selector. The one big exception is the ".note" selector, which also happens to be one of the most commonly used. Given that, the overall performance of a webapp between these two frameworks is somewhat up in the air.

Simple AJAX with jQueryUI and PHP

This will be a short tutorial on how to incorporate AJAX interaction into a PHP site using jQuery and the jQueryUI framework.


Imagine we have a page that lets users manage a list of books that is stored in a database.  We want them to be able to easily edit the books via ajax without having to go to another page. Below is an example of what we want.



Here's the database table we'll use plus a few sample books.


CREATE TABLE `books` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(30) NOT NULL,
  `genre` enum('fantasy','mystery','nonfiction') NOT NULL,
  `description` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE = InnoDB;

INSERT INTO `book` (`id`, `title`, `genre`, `description`) VALUES
(1, 'The Lord of the Rings', 'fantasy', 'The Lord of the Rings is an epic fantasy novel written by philologist and University of Oxford professor J. R. R. Tolkien (from Wikipedia).'),
(2, 'The Maltese Falcon', 'mystery', 'The Maltese Falcon is a 1930 detective novel by Dashiell Hammett, originally serialized in the magazine Black Mask (from Wikipedia).'),
(3, 'Economics in One Lesson', 'nonfiction', 'Economics in One Lesson is an introduction to free market economics written by Henry Hazlitt and published in 1946, based on Frédéric Bastiat''s essay Ce qu''on voit et ce qu''on ne voit pas (English: "What is Seen and What is Not Seen") (from Wikipedia).');


First, let's create the PHP page that pulls these books from the database and displays them to the user. Later, we'll add javascript code to this page to make the edit link use AJAX to interact with the database.

//display.php
<div class='books'>
 <?php
 //connect to database
 mysql_connect('localhost', 'mysql_user', 'mysql_password');
 mysql_select_db('dbname');

 //get all books
 $query = "SELECT * FROM books";
 $result = mysql_query($query) or die("Error selecting books");

 //display books
 while($row = mysql_fetch_assoc($result)) {
 ?>
  <div class='book' id='book_<?php echo $row['id']; ?>'>
   <a class='edit' href='#'>edit</a>
   <h3 class='title'><?php echo $row['title']; ?></h3>
   <p><em class='genre'><?php echo $row['genre']; ?></em></p>
   <p class='description'><?php echo $row['description']; ?></p>
  </div>
 <?php
 }
 ?>
</div>

The next page to create is the edit.php page that the ajax link will call.


//edit.php
<?php
//connect to database
mysql_connect('localhost', 'mysql_user', 'mysql_password');
mysql_select_db('dbname');

//pull info from $_POST and sanitize it
$id = mysql_real_escape_string($_POST['id']);
$title = mysql_real_escape_string($_POST['title']);
$genre = mysql_real_escape_string($_POST['genre']);
$description = mysql_real_escape_string($_POST['description']);

//update in database
$query = 'Update books SET title="'.$title.'", genre="'.$genre.'", description="'.$description.'" WHERE id="'.$id.'"';
mysql_query($query);

//generate json code
echo json_encode(array(
 'id'=>$id,
 'title'=>$title,
 'genre'=>$genre,
 'description'=>$description
));
?>

When the user clicks the edit link for a book, we want a dialog box to pop up with a form that lets the user edit the data. We want the form to submit to the edit.php page via AJAX. Finally, we want the page to update to reflect the changes.


To do this, we first create the html for the dialog box. The submit button will be handled by jQuery, so we don't need to add it here. This goes at the bottom of the display.php page.


<div id='edit_dialog'>
 <form action='edit.php' method='post'>
  <input type='hidden' name='id' />

  Title: 
  <input type='text' name='title' /><br />
  
  Genre:
  <select name='genre'>
   <option value='fantasy'>Fantasy</option>
   <option value='mystery'>Mystery</option>
   <option value='nonfiction'>Nonfiction</option>
  </select><br />
  
  Description:
  <textarea name='description' cols='30' rows='3'></textarea>  
 </form>
</div>

Now we add the jQuery code to the display.php page to tie everything together. This requires jQuery, jQueryUI with the dialog widget, and a jQueryUI theme to be loaded. This goes somewhere on the display.php page.


$(document).ready(function() {
 //Create dialog
 $edit_dialog = $("#edit_dialog").dialog({
  autoOpen:false, 
  title:"Edit Book", 
  modal:true, 
  buttons:[
   {text: "Submit", click: function() { $('form',$(this)).submit(); }},
   {text: "Cancel", click: function() { $(this).dialog("close"); }},
  ]
 });
 
 //Submit action for dialog form
 $("#edit_dialog form").submit(function() {
  var form = $(this);
  //post form data to form's action attribute
  $.post($(this).attr('action'), $(this).serialize(),function(data) {   
   //get DOM element of updated book
   var book = $('#book_'+data.id);
  
   //update title
   $('.title',book).html(data.title);
   
   //update genre
   $('.genre',book).html(data.genre);
   
   //update description
   $('.description',book).html(data.description);
  
   //close the dialog
   $("#edit_dialog").dialog('close');
  },'json');
  
  //stop default form submit action
  return false;
 });

 //when the edit link is clicked
 function edit_link_action() {
  //get closest book div
  var book = $(this).closest('.book');
  
  //get id from div
  var id = book.attr('id').split('_');
  id = id[id.length-1];
  
  //set id in form
  $('#edit_dialog input[name="id"]').val(id);
  
  //set current title in form
  $('#edit_dialog input[name="title"]').val($('.title',book).html());
  
  //set current genre in form
  $('#edit_dialog select[name="genre"]').val($('.genre',book).html());
  
  //set current description in form
  $('#edit_dialog textarea[name="description"]').val($('.description',book).html());
  
  //open dialog
  $edit_dialog.dialog('open');
  
  //stop default link action
  return false;
 }
 
 //attach action to edit links
 $(".edit").click(edit_link_action);
});

Once all the parts are put together, you should have a fully functioning AJAX site. Below is the complete code for the display.php page.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
 <script type='text/javascript' src='jquery-1.4.4.min.js'></script>
 <script type='text/javascript' src='jquery-ui-1.8.9.custom.min.js'></script>
 <link rel='stylesheet' href='jquery-ui-1.8.9.custom.css' />
 <script type='text/javascript'>
  $(document).ready(function() {
   //Create dialog
   $edit_dialog = $("#edit_dialog").dialog({
    autoOpen:false, 
    title:"Edit Book", 
    modal:true, 
    buttons:[
     {text: "Submit", click: function() { $('form',$(this)).submit(); }},
     {text: "Cancel", click: function() { $(this).dialog("close"); }},
    ]
   });
   
   //Submit action for dialog form
   $("#edit_dialog form").submit(function() {
    var form = $(this);
    //post form data to form's action attribute
    $.post($(this).attr('action'), $(this).serialize(),function(data) {   
     //get DOM element of updated book
     var book = $('#book_'+data.id);
    
     //update title
     $('.title',book).html(data.title);
     
     //update genre
     $('.genre',book).html(data.genre);
     
     //update description
     $('.description',book).html(data.description);
    
     //close the dialog
     $("#edit_dialog").dialog('close');
    },'json');
    
    //stop default form submit action
    return false;
   });

   //when the edit link is clicked
   function edit_link_action() {
    //get closest book div
    var book = $(this).closest('.book');
    
    //get id from div
    var id = book.attr('id').split('_');
    id = id[id.length-1];
    
    //set id in form
    $('#edit_dialog input[name="id"]').val(id);
    
    //set current title in form
    $('#edit_dialog input[name="title"]').val($('.title',book).html());
    
    //set current genre in form
    $('#edit_dialog select[name="genre"]').val($('.genre',book).html());
    
    //set current description in form
    $('#edit_dialog textarea[name="description"]').val($('.description',book).html());
    
    //open dialog
    $edit_dialog.dialog('open');
    
    //stop default link action
    return false;
   }
   
   //attach action to edit links
   $(".edit").click(edit_link_action);
  });
 </script>
</head>
<body>
 <div class='books'>
  <?php
  //connect to database
  mysql_connect('localhost', 'mysql_user', 'mysql_password');
  mysql_select_db('dbname');

  //get all books
  $query = "SELECT * FROM books";
  $result = mysql_query($query) or die("Error selecting books");

  //display books
  while($row = mysql_fetch_assoc($result)) {
  ?>
   <div class='book' id='book_<?php echo $row['id']; ?>'>
    <a class='edit' href='#'>edit</a>
    <h3 class='title'><?php echo $row['title']; ?></h3>
    <p><em class='genre'><?php echo $row['genre']; ?></em></p>
    <p class='description'><?php echo $row['description']; ?></p>
   </div>
  <?php
  }
  ?>
 </div>
 
 <div id='edit_dialog'>
  <form action='edit.php' method='post'>
   <input type='hidden' name='id' />

   Title: 
   <input type='text' name='title' /><br />
   
   Genre:
   <select name='genre'>
    <option value='fantasy'>Fantasy</option>
    <option value='mystery'>Mystery</option>
    <option value='nonfiction'>Nonfiction</option>
   </select><br />
   
   Description:
   <textarea name='description' cols='30' rows='3'></textarea>  
  </form>
 </div>
</body>
</html>

Storing Passwords in a Database

In this post, I'll go through three common ways to store and retrieve passwords in a database. I'll assume PHP and MySQL, but the techniques should be very similar for other setups.

Only the last method should ever be used for security reasons, but unfortunately, a large number of sites use one of the less secure methods and put their users in danger.

Storing a Password as Plain Text

This is the most basic and definitely least secure method for handling passwords. Never Use This Method!

The basic strategy is to store the password directly in the database. You would then authenticate a user by running a query like this:

SELECT id FROM users WHERE username='johnsmith' AND password='123456'

If the query returns a row, the username and password are correct. As you can see, if anyone intercepts this query along the way, they automatically have the user's username and password. Also if your database gets stolen, the thief has all of your users' usernames and passwords. This is an even bigger problem because most people use the same username and password for everything.

If you ever click a Forgot Your Password link and the site gives you your current password, they are using this method and I would highly suggest not using the site or at least using a unique password just for the site.

Using a Password Hash

This method is better than plain text, but still has some major, relatively little known, security holes in it. A lot of sites use this method thinking it is secure. Again, do not use this method.

This method takes a user's password and converts it to an md5 or similar hash before storing in the database. For example, "123456" becomes "e10adc3949ba59abbe56e057f20f883e". This seems like it solves the problem with plain text since a person cannot look at the hashed string and know the user's password. But, if you type this hash into Google, the second result is titled "Google Hash: md5(123456) = e10adc3949ba59abbe56e057f20f883e". Not as secure as it first looked, is it?

There are md5 hash tables you can download that contain every word in the dictionary and every common password that make this method very susceptible to attacks. Many sites require passwords with numbers, symbols, capital letters, etc., which helps fix the security hole, but why make things harder on your users when you can just use a password salt?

Using a Password Salt

There is no reason not to use this method. It provides an extra layer of security on top of a password hash with very little extra work.

This method generates a random string (salt) and appends it to the user's password before generating an md5 or similar hash. Then, both the password hash and the password salt are stored in the database and used to authenticate the user. For example, "123456" becomes "123456ghjfdweurt" becomes "8e1a92e8f87a5bbf36f26e330cf7f0b5". Try typing that hash into Google and the most you may find is this article.

Here's the PHP code for initially inserting a user into a database. The getRandomString() function is from http://www.lost-in-code.com/programming/php-code/php-random-string-with-numbers-and-letters/.

//get username and password
$username = $_REQUEST['username'];
$password = $_REQUEST['password'];

//generate password salt
$password_salt = genRandomString();

//generate password hash
$password_hash = $password . $password_salt;

//insert into database
$query = "INSERT INTO users (`username`,`password_hash`,`password_salt`) VALUES ('$username', '$password_hash', '$password_salt')";
mysql_query($query);



function  genRandomString() {
    $length = 10;
    $characters = ’0123456789abcdefghijklmnopqrstuvwxyz’;
    $string = ”;    

    for ($p = 0; $p < $length; $p++) {
        $string .= $characters[mt_rand(0, strlen($characters))];
    }

    return $string;
}

Here's the code for authenticating a user once they are already in the database:

//get username and password
$username = $_REQUEST['username'];
$password = $_REQUEST['password'];

//query database
$query = "SELECT * FROM users WHERE username='$username'";
$result = mysql_query($query);

//if no result, username is incorrect
if(!$result) {
    //authentication failed
}

//get database row
$row = mysql_fetch_assoc($result);

//generate password hash from entered password
$password_hash = md5($password . $row['password_salt']);

//check if the generated hash is equal to the hash in the database
if($password_hash === $row['password_hash']) {
     //authentication passed
}
else {
     //authentication failed
}

Important Safety Tip

No matter what method you use, SSL encryption is essential during authentication to protect against man-in-the-middle attacks. This is where an attacker intercepts data between the user and the server. If the user submits a login form and an attacker intercepts it, the password will be compromised no matter which method you use.

Installing and Configuring Dornbase

Dornbase is a PHP contact management system I started a while ago and recently released via Sourceforge (http://sourceforge.net/projects/dornbase/). You can see a demo of it running at http://jeremydorn.com/dornbase.php.

The project is still in its early stages, so there is not much documentation available. I plan to eventually implement an automated installer, like Joomla and most other major PHP applications have. If you have any suggestions or want to help, email me at jeremy@jeremydorn.com.

This post is meant to serve as a guide for installing and configuring Dornbase on either your local machine or a remote host.

Minimum Requirements

Most paid web hosts meet these requirements. All of the required software is included in xampp (http://sourceforge.net/projects/xampp/).

  • Apache 2.2 with mod_rewrite enabled
  • PHP 5+ (make sure ERROR_REPORTING is set to not show E_NOTICE)
  • MySQL 5+ (I haven't tested older versions, but they probably work too)

Download Files

Download Dornbase 1.7 from http://sourceforge.net/projects/dornbase/ and extract the files to your document root (C:/xampp/htdocs/ if using xampp).

Set up Database

Create a new database and run all of the queries in the db_setup.sql file included in the download to set up the database tables. If you are using xampp, follow the phpmyadmin instructions below to do this.

PhpMyAdmin Instructions
  1. Go to http://localhost/phpmyadmin.
  2. In the "Create new database" form, enter a name for the database (e.g. "dornbase") and click the "Create" button.
  3. Click the "import" tab.
  4. Select the db_setup.sql file and click "Go".

The only table you may want to change is the "fields" table, which contains all the fields a record will have. By default, it is set up with all of the fields in the demo, but this can be easily changed. Below is a brief description of what each column in the fields table means.

name- The id of the field (no spaces, all lowercase) (e.g. fname, address_line_1) display- The display name of the field (all lowercase) (e.g. "first name", "address line 1")
datatype- The datatype of the field. Either 'text', 'number', 'date', or 'boolean'.
type- A more specific type differentiator (e.g. 'phone', 'website', 'money', 'ssn')
multiple- Can the field have multiple values? '1' for yes, '0' for no
discrete- Are the field values limited and discrete (i.e. will it use a drop down menu)? '1' for yes, '0' for no
search- Should this field be searchable? '1' for yes, '0' for no
default- The default value this field will have for a new record
summary- Is this field vital for uniquely identifying a record?
padto- For numeric fields, the max number of digits (e.g. if '12', all values are left padded with 0s until there are 12 characters left of the decimal point). This enables storing numbers as text and still being able to properly sort them.

Configure Server

Rename the "server_default" folder to "server". This folder contains 2 files which you need to edit. There are comments and instructions in each of the files.

Rename "htaccess-default" to ".htaccess" (You may need to open it in notepad and use Save As on some Windows machines). Edit the line "RewriteBase /dornbase" and change "/dornbase" to whatever directory you installed the application in.

Rename the "config_default" folder to "config". This folder contains several files that help you customize Dornbase to fit your needs. I'll explain each of these files later.

Test it out

Open up Dornbase in a browser (if you installed it in /htdocs/dornbase/, go to http://localhost/dornbase/). You should see a sign in page. Sign in with the default admin account (username: "admin", password: "password"). If you see an empty record page, everything is installed correctly.

You may see errors if you modified the record fields in the database. After the next step, this should be fixed.

Customize

The important files to edit in the config folder are template.php, record.php, and functions.php.

template.php is really short and defines a few variables such as business name and return address (for printing envelopes).

record.php only needs to be changed if you modified the record fields in the database at all.

functions.php is a large file and contains a bunch of callback functions that provide hooks into the application. I'll go through a few of the important functions.

  • get_record_header(&$data) - Should return the header for a record. By default, it displays the full name (or company if name is empty) followed by a description and the policy type.
  • get_field_order(&$record, $mobile=false) - This determines the layout of the record. It allows you to layout the record differently depending on the record data. For example, you can have a "spouse name" field only show up if their status is set to "married". You can also display different fields on a mobile device.

You can play around with the other functions and the other files in the config folder if you want.

After you make a change to a file in the config folder, most of the time refreshing the page will work. In a few cases, you may have to sign out and sign back in for the changes to take effect.

Reducing Javascript and CSS Load Times

I was making a complex ajax web application and ran into problems with load times. In some cases, it was taking up to 7 or 8 seconds to load a page. I found out the culprit was multiple large javascript and css files. Here's how I was able to get my load times under a second with a few changes. All of the examples below are for javascript files, but they apply equally to css files.

Combine javascript and CSS files

There is overhead each time the browser has to load an external file, so reducing the number of server calls can speed up page loads. Originally, I put all of my javascript scripts in one large file. This helped page load times, but made it difficult to edit individual scripts. I then switched to a PHP solution.

I created the following PHP page, which combines multiple javascript files on the fly.

<?php
//set content type
header('Content-type: text/javascript');

//pull list of comma-separated files from $_GET
$js_files = explode(',',urldecode($_REQUEST['files']));

//read each file
foreach($js_files as $js_file) {
 echo "\n\n\n/*******************$js_file********************/\n";
 $file = '/path/to/js/directory/'.$js_file.".js";
 if(file_exists($file)) readfile($file);
}
?>

Here is how you would load javascript files in the head section of page.

<!-- Using PHP's urlencode function -->
<?php
$files = array("jsfile1","jsfile2","jsfile3");
?>
<script type='text/javascript' src='/path/to/js/directory/javascript.php?files=<?php
 echo urlencode(implode(',',$files));
?>'></script>

<!-- No PHP, hard code commas as "%2C" -->
<script type='text/javascript' src='/path/to/js/directory/javascript.php?files=jsfile1%2Cjsfile2%2Cjsfile3'></script>

This reduced my load times to about 5 or 6 seconds.

Take Advantage of Parallel Downloading

This partially contradicts the previous tip when I said less files were always better. Most browsers are capable of downloading a limited number of javascript and css files at the same time. For example, Firefox will usually download up to 3 files simultaneously from a single host.

If you have 1 or 2 large javascript files, you should put them in their own script tags and combine the rest of the scripts as before. This way, the browser doesn't have to wait for the large script to download before fetching the other ones. Here's an example.

<!-- Large js file -->
<script type='text/javascript' src='/path/to/js/directory/javascript.php?files=largefile'></script>

<!-- Multiple smaller files -->
<script type='text/javascript' src='/path/to/js/directory/javascript.php?files=jsfile1%2Cjsfile2%2Cjsfile3'></script>

Even though you are only loading one file in the first case, you should still use the php script to take advantage of the later tips.

This reduced my load times further to about 2 or 3 seconds.

Compress Javascript and CSS files

The basic idea behind this is to reduce the size of javascript and css files by removing comments and extra white spaces among other things. There are two ways to do this, each with their advantages and disadvantages.

The first is to compress the files directly. The advantages here are speed and reduced server load. The server doesn't have to waste time compressing each file at runtime. The big disadvantage is that compressed files are almost impossible to edit. This method works best for 3rd party scripts, such as javascript frameworks, that you aren't going to be editing yourself. Most frameworks offer compressed versions directly, but you can also compress any file yourself with http://jscompress.com/ for javascript files and http://www.cssdrive.com/index.php/main/csscompressor/ for css files.

The other method is realtime compression. The advantage is files remain editable and the development process is much easier. The disadvantage is that the server must re-compress each script at runtime, which takes time and processing power. This method is best for scripts which you edit often. There is a great php script for doing this called minify that works for js and css files. They have plenty of documentation on the site and it's pretty easy to implement into the php script we created above.

Compressing files can reduce the size by anywhere from 10% to 50% or more. As an example, the uncompressed jquery framework is 160kb and the compressed version is 70kb. This can potentially cut loading times in half, but the actual gain is probably less than that.

Take Advantage of Caching

A lot of times, javascript and css files don't change very often and it doesn't make sense to load them on each page view. With a few simple changes to our php script, we can make the browser cache these pages. This provides the biggest improvement in load times.

<?php
//set content type
header('Content-type: text/javascript');

//if the nocache parameter is not explicitly set
if(!$_REQUEST['nocache']) {
 //store in cache for 1 day (86400 seconds)
 header('Expires: '.gmdate('D, d M Y H:i:s', time()+86400).'GMT');  
 header('Cache-Control: max-age=86400'); 
 header('Pragma: max-age=86400'); 
}

...

If you have some file which changes frequently or is generated at the server side, you can pass "nocache=true" in the script tag source.

One problem you may notice is that if you make a change to a javascript file, a user may not get the latest version for a full day, which could break the site in the meantime. Luckily, there is an easy solution.

If the script src changes, a browser will always reload the script, even if it was cached. Since we're already passing parameters in the script url, we can add "version=#" and increment this number whenever we make a change. That way, the script will be reloaded the next time the page is.

The first time the webpage is loaded, there is no added benefit, but the load times of subsequent pages was reduced to less than a second.

If you can think of any other tips to reduce page load times, let me know.

Fixing jQuery UI Autocomplete

jQuery UI 1.8 was recently released and it included a much needed autocomplete widget. For the most part, this widget works fine, but there is an annoying bug that makes it not quite ready for a production environment. Basically, if a user clicks on an option and doesn't release the mouse button fast enough, the option is not selected. You can see the bug in action on the jQuery UI autocomplete demo.

Thankfully, there is a workaround.

Here is what we would like to be able to do:

$("#autocomplete").autocomplete({
   source: 'search.php',
   select: function(event, ui) {
      alert(ui.item.id);
   }
});

Here is the bug-fixed version I came up with:

//global variable that stores the last focused option
var search_option = false;

$("#autocomplete").autocomplete({
   source: 'search.php',
 
   //when an item is focused, store item in the global variable
   focus: function(event, ui) {
      search_option = ui.item;
   },
 
   //when an item is selected with the keyboard, trigger
   //the mouse down event for consistency
   select: function(event, ui) {
      search_option = ui.item;
      $("#autocomplete").autocomplete('widget')
      .trigger('mousedown.choose_option');
   }
})

//bind the select event to mousedown
.autocomplete('widget').bind('mousedown.choose_option',function() {
   //immediately closes autocomplete when option is selected
   $("#autocomplete").autocomplete('close');
 
   //perform desired action
   alert(search_option.id);
});

Obviously, this isn't a very elegant solution, but I didn't want to mess around with the actual autocomplete code. Hopefully, this is fixed in the next release. Until then, this will have to do.

Site Templates with CakePHP

I started with cakePHP a few months ago and was impressed by their documentation. I could find answers to most of my questions fairly quickly. However, I couldn't find a good tutorial on adding a site-wide template. Hopefully this will help other people with the same problem.

First start with an HTML template. If you don't feel like making one from scratch, any div layout will work fine. Open Source Web Design (http://oswd.org) has tons of free templates that work perfectly with CakePHP. Here's a simplified version of one of their templates:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>

<head>
<link rel='stylesheet' href='style.css'/>
<title>CakePHP</title>
</head>

<body>
<div class="site_container">
 <div class="main_content">
  <div class="top_header">
   <div class="site_title">
    <h1>CakePHP</h1>
   </div>
  </div>

  <div class="content">
   <!-- Main Site Content -->
  </div>

  <div class="sidenav">
   <h1>Navigation</h1>
   <a href='#'>Link 1</a>
   <a href='#'>Link 2</a>
  </div>
 </div>
</div>
</body>

</html>

Copy this template to app/views/layouts/default.ctp. If that file doesn't exist, create it.

The first thing we have to change is the stylesheet. We are currently including the stylesheet with:

<link rel='stylesheet' href='style.css'/>

We need to copy the file style.css to app/webroot/css/style.css. Then replace the above code with:

<?php
 echo $html->css('style');
?>

The next step is to include the page content. Edit the template as follows:

<!-- Main Site Content -->
<?php 
 $session->flash(); 
 echo $content_for_layout; 
?> 

$session->flash(); prints error messages and alerts.
echo $content_for_layout; prints the page content.

Now for the side navigation. To keep the code clean, let's create a new file that just holds the navigation bar. Create the file app/views/elements/menus/sidenav.ctp. Here's some sample data for that page.

<?php
 echo $html->link("Home","/pages/home");
 echo $html->link("About Us","/pages/about"); 

 //if user is logged in
 if($this->Session->check('User'))
  echo $html->link("Sign Out","/users/logout"); 
 else
  echo $html->link("Sign In","/users/login"); 
?>

Here is the current code for the side navigation bar:

<div class="sidenav">
 <h1>Navigation</h1>
 <a href='#'>Link 1</a>
 <a href='#'>Link 2</a>
</div>

Change this to:

<div class="sidenav">
 <h1>Navigation</h1>
 <?php echo $this->renderElement('menus/sidenav'); ?> 
</div>

You can add other page elements the same way you did the side navigation bar.

Hopefully this gives you an idea of how templates work in CakePHP.