Category Archives: Development

Offloading time consuming PHP work outside your application

It is natural that as business applications become more complex they often have to capture and process more information. With web-based applications in particular, this can become a problem.

Let’s suppose we have built a CRM application for our company to store information about our customers. In its first release, the application was designed to capture basic information about a customer,  and store it in the database – simple. This is bread and butter work for most applications and should be fairly light work. User’s of this system would find their interactions with this software to be fairly slick.

However, six months down the line, the company owners think it would be really useful to allow emails to be sent to the customers from the CRM – Quotes, Order Invoices and Progress Updates. Whilst this seems a perfectly legitimate addition to the CRM, adding even simple email connectivity to an application can cause a performance degradation, particularly when using SMTP servers to send the emails. The SMTP protocol is a very ‘chatty’ protocol, and to just send 1 email, requires several conversations between the application and the server to send an email. I won’t go into the specifics of this conversation but in a nutshell these conversations discuss CONNECTION, AUTHENTICATION, SENDING, DELIVERY and RESPONSE. Each of these steps can take a while to happen, and sending an email can very easily amount to an additional three or four seconds of delay that the user would experience waiting for the page to reload and allow them to continue. This is known as IO Blocking Behaviour.

Offloading.

The user of the software wants to click the “send message” button, and then move on to the next customer or activity, but they have to wait for the message to be sent before they can. Three or four seconds per message, per customer, per day can amount to quite a lot of waiting time. So how to we overcome this.

There are several ways you could achieve this, but in this article I am going to explore offloading the “Email sending” process to be handled at a later time. The idea behind this is that the user still clicks the “send message” button, but instead of actually sending the email at this time, we just log a request that the user has requested to send an email. This request could be stored in a log file, or a database table, or even sent to a Message Broker server (more on that later). Regardless of where and how the request to send the email is stored, the user is not blocked by waiting for the email to send. They are notified that the email has been queued for delivery and can carry on their work without the three or four second delay.

Who actually sends the email then..?

Good question. We are going to build a PHP page which scans the queue, or log for email requests and then processes them one at a time. This process can take place on the same, or even a different server, and can be running in the background all day. The only purpose of this process is to send emails that have been requested. Whilst this process is happy chugging away in the corner, the user’s are interacting with their CRM quite happily, raising more and more email requests. The user’s don’t actually care if their email email is delivered seconds, or even minutes after they clicked the “Send Message” button, they just want to know that it will be sent. We can call this partnership between the CRM and the Email Processor a non-blocking relationship. The activity of one system is not being held up by another.

Look out for the next part of this article where I will look at a few techniques to achieve offline processing of these emails, first by using CRON Jobs and then using a more robust messaging system such as RabbitMQ and the AMQP protocol.

Thanks for reading.

James

Double-click button prevention with jQuery

Quite often it is necessary to prevent users from double-clicking on submit buttons, or in fact any buttons on your website. This is particularly important if you are processing orders or payments. Here is a very simple scriptlet which will prevent any buttons from being double clicked.

jQuery(document).ready(function(){
  jQuery("*").dblclick(function(e){
    e.preventDefault();
  });
});

The above script will prevent double clicks on all button elements. If you want to attach to a single control, such as a button called “button_submit” you can do this as follows:

jQuery(document).ready(function(){
  jQuery("#button_submit").dblclick(function(e){
    e.preventDefault();
  });
});

new jQuery Plugin – Equal Height Columns

Have you ever been in the situation where you need to use floated columns on your web page and want them all to be the same height as the tallest column? If you have, then you will probably know that you can achieve it with CSS. However, I don’t like this approach, and quite frankly have never understood it fully anyway. As I used jQuery in practically every project I write I thought it would be neater to just write a jQuery plugin which would do all of the hard work for me.

Here is the plugin code:

/* 
 /* * @Copyright (c) 2013 James Stoddern - info@jamesstoddern.net  
 * web:jamesstoddern.net  
 *  
 * Permission is hereby granted, free of charge, to any person  
 * obtaining a copy of this software and associated documentation  
 * files (the "Software"), to deal in the Software without  
 * restriction, including without limitation the rights to use,  
 * copy, modify, merge, publish, distribute, sublicense, and/or sell  
 * copies of the Software, and to permit persons to whom the  
 * Software is furnished to do so, subject to the following  
 * conditions:  
 * The above copyright notice and this permission notice shall be  
 * included in all copies or substantial portions of the Software.  
 *  
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,  
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES  
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND  
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT  
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,  
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR  
 * OTHER DEALINGS IN THE SOFTWARE.  
 *  
 * How to use it:  
 *  
 * If you have a series of floated columns, which you wish to make the same height, give them all the same  
 * class, and then run the plugin. It will determine the tallest div, and equalise the height of the rest  
 *  
 * $('.selector').equalHeights();  
 *  
 *  
 */

(function( $ ) {
    $.fn.equalHeights = function() {
        var tallestElement = 0;
        var startRow = 0;
        var elements = new Array();
        var $currentElement;
        var topPosition = 0;

        this.each(function() {

            $currentElement = $(this);
            topPostion = $currentElement.position().top;

            if (startRow != topPostion) {
                for (currentDiv = 0 ; currentDiv < elements.length ; currentDiv++) {
                    elements[currentDiv].height(tallestElement);
                }

                elements.length = 0;
                startRow = topPostion;
                tallestElement = $currentElement.height();
                elements.push($currentElement);

            } else {
                elements.push($currentElement);
                tallestElement = (tallestElement < $currentElement.height()) ? ($currentElement.height()) : (tallestElement);

            }

            for (currentDiv = 0 ; currentDiv < elements.length ; currentDiv++) {
                elements[currentDiv].height(tallestElement);
            }

        });

    };
}) ( jQuery );

So how do you use it?

Well, firstly copy the plugin from this page, and save it to a folder where you normally keep your jquery scripts. I usually call it jquery_equalheight.js. After you have included jQuery in your page, simply inlcude the plugin as well.

Next, all you need to do is run the plugin against a selector. In the case of your columns, make sure they all have the same class and then add this neat bit of code to run the plugin.

jQuery('.column').equalHeights();

Enjoy!

Store your snippets with Github Gist

If you are coding a lot then you probably have chunks of re-useable code which you copy and paste into your applications to save time. These are what we refer to as “snippets”. There are a number of ways you can store these, for example in a text-file on your desktop, or the IDE in which you are working. However, if you are working on a different computer, will these snippets be available to you? Unlikely, unless you duplicate them. Then of course, if you need to edit your snippet, you need to make sure you update it everywhere else you might have a copy stored.

bye bye problem, enter GitHub

Our friends at GitHub have come up with the solution, and named it Gist. This is essentially a free online and version controlled area for you to save your snippets. You can create a new snippet (either public or private) and then paste your code into it. Wherever you go, these snippets are available to you, and if you want to update them you can.

gist

SEO friendly urls in codeigniter – the challenge

Codeigniter is generally quite good at providing friendly urls, mainly due to its url segment approach. Instead of the traditional querystring approach where parameters are passed as follows:

index.php?account=james

codeigniter uses segments instead.

index/account/james

So the segmented approach is much friendlier but still not perfect. What I want to achieve is a much more descriptive url such as “view-my-account.html”. In order to achieve this I decided to generate a ‘slug’ (usually a hyphenated string in lower case) for each post as I create or edit them in the cms. The slug is a friendly version of the blog post title as can be seen below. This is stored in a column called “slug” in the database for use later.

slug

The intention is to have my controller perform a database or file-cache lookup for the slug, and then route it to the correct controller.

routing

One of the first challenges is to tame the Codeigniter routing system, which allows urls to be directed to the correct controllers and methods. Routes can be managed inside of “/application/config/routes.php”. In order to dynamically route the first step is to add some extra code in the routes.php to handle dynamic routes:

// include the dynamic routes from the cache file
require_once("application/cache/routes.php");

We also need some way of actually generating these routes, so what I decided to do was generate them when posts are created or updated. After the new post has been written to the database, a new record is created that contains the friendly url, the Slug, and the route that it should be directed to. In my blog this model is quite straight forward and comprises of the segments “blog/category/postid”. So in my add/edit posts I have some code like this

//////////////////////////////////////////////////////////////////
//update the record for the dynamic route
$dynamic_route = "blog/index/" . $category . "/false/" . (int)$id;
$route = array(
    'post_id' => $id,
    'route' => $dynamic_route,
    'slug' => $slug
);

$result = mysql_query("SELECT * FROM routes WHERE post_id='{$id}'");
$num_rows = mysql_num_rows($result);

if($num_rows > 0) {
    //update the record
    $this->db->where('post_id', $id);
    $this->db->update('routes', $route);
} else {
    //insert a new record
    $this->db->insert('routes', $route);
}

Now that the route has been generated we have to make it accessible to Codeigniter somehow. To save on database queries I have decided to write all of the routes for the site into a file cache – this lives inside “application/cache/routes.php” and effectively contains an array of all the routes for the site. I did this with a new model called “Router_m” which has a method called “cache_routes()” which looks as follows:

class Router_m extends CI_Model {

    function __construct() {
        parent::__construct();
    }   

    //grab all of the routes from the database, and cache to a file
    public function cache_routes()
    {
        $this->db->select("*");
        $query = $this->db->get("routes");

        foreach ($query->result() as $row)
        {
            $data[] = '$route["' . $row->slug . '"] = "' . $row->route . '";';
            $output = "load->helper('file');
            write_file(APPPATH .  "cache/routes.php", $output);
        }
    }
}

This cache file is loaded by “config/routes.php” after the static routes have been defined. The file looks like this:

$route["new-single-whore-left-me.html"] = "blog/index/musician/false/27";
$route["content-management-system.html"] = "blog/index/blog/false/3";
$route["inline-ajax-image-uploader-for-tinymce.html"] = "blog/index/developer/false/45";
$route["jumping-on-the-bandwagon-youtube-videos.html"] = "blog/index/blog/false/41";
$route["test-post.html"] = "blog/index/blog/false/46";
$route["seo-friendly-urls-in-codeigniter-the-challenge.html"] = "blog/index/developer/false/44";
$route["big-brother-is-watching-google-analytics.html"] = "blog/index/blog/false/42";
$route["new-image-uploader-plupload.html"] = "blog/index/developer/false/43";
$route["sublime-text-2-video-intro.html"] = "blog/index/developer/false/40";
$route["multiband-compression.html"] = "blog/index/musician/false/39";
$route["store-your-snippets-with-github-gist.html"] = "blog/index/developer/false/38";
$route["on-fire-with-sparks.html"] = "blog/index/developer/false/37";
$route["sublime-coding.html"] = "blog/index/developer/false/35";
$route["my-new-guitar.html"] = "blog/index/musician/false/36";
$route["a-moment-of-clarity-literally.html"] = "blog/index/musician/false/33";
$route["song-writing-basics.html"] = "blog/index/musician/false/15";
$route["codeigniter-language-packs.html"] = "blog/index/developer/false/29";
$route["are-you-listening-to-your-speakers-or-your-room.html"] = "blog/index/musician/false/34";
$route["the-importance-of-gain-staging.html"] = "blog/index/musician/false/32";
$route["the-studio.html"] = "blog/index/musician/false/30";
$route["the-subjective-part-of-mixing-your-own-vocals.html"] = "blog/index/musician/false/28";
$route["implementing-tinymce-as-your-rich-text-editor.html"] = "blog/index/developer/false/2";
$route["welcome-to-jamesstoddernnet.html"] = "blog/index/home/false/26";
$route["new-single-out-now-smile.html"] = "blog/index/musician/false/14";

Of course, to make use of all this routing, I have had to change the links on the site, so that in the “recent posts” panel for example, instead of building a traditional codeigniter controller/method style link,  the slugs can be used directly. As soon as you navigate to the slug, its correct location is loaded from the routes cache. Of course the user doesn’t know this and just sees the friendly title. I have also got the page title to be set now from the post’s title as well to make everything even more friendly.