Refactoring in Practice

I love taking larger functions and slimming them down into a more efficient and readable format. Here is a simple example of just that.

The original function:

function strip_slashes( $data )
{
    if( is_array($data) )
    {
        foreach($data as $key => $val )
        {
            $data[$key] = strip_slashes($val);
        }
    }
    else
    {
        return stripslashes($data);
    }

    return $data;
}

The refactored function:

function strip_slashes( $data )
{
    return is_array($data) ? array_map('strip_slashes', $data) : stripslashes($data);
}

The code is much more readable and can be understood easily. Try to do the same with your own functions. The more you practice refactoring old code the easier it will be to remember how to do things quicker.

CodeIgniter Form with Text CAPTCHA

“A CAPTCHA (Completely Automated Public Turing Test To Tell Computers and Humans Apart) is a program that protects websites against bots by generating and grading tests that humans can pass but current computer programs cannot.” — captcha.net

The current CAPTCHA system I started using is Text CAPTCHA. The Text CAPTCHA web service generates text-based CAPTCHAs which is a single question that can be easily solved by humans but cannot be solved by a robot.

Since I added comments functionality to ThePollPlace a few weeks ago, I’ve been noticing lots of spam. Lots meaning, thousands of spam comments. So I implemented Text CAPTCHA because it was simple and easy to do. Now, I’ll show you how to implement it into a form using CodeIgniter. First I’ll show you the code, then I’ll explain it.

application/controllers/example.php
class Example extends Controller {

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

    function index()
    {
        // load libraries
        $this->load->library(array('session', 'form_validation'));

        // load helper
        $this->load->helper('form');

        // setup form validation
        $this->form_validation->set_rules('name',    'name',    'required');
        $this->form_validation->set_rules('email',   'email',   'valid_email');
        $this->form_validation->set_rules('url',     'url',     'prep_url');
        $this->form_validation->set_rules('captcha', 'captcha', 'required|callback_check_captcha');
        $this->form_validation->set_rules('comment', 'comment', 'required');

        if( $this->form_validation->run() )
        {
            // create comment
            die('Validated!');
        }

        // setup textCAPTCHA
        try {
            $xml = @new SimpleXMLElement('http://textcaptcha.com/api/your_api_key', NULL, TRUE);
        } catch ( Exception $e ) {
            $fallback  = '<captcha>';
            $fallback .= '<question>Is ice hot or cold?</question>';
            $fallback .= '<answer>'.md5('cold').'<answer>';
            $fallback .= '</captcha>';
            $xml = new SimpleXMLElement($fallback);
        }

        // store answers in session for use later
        $answers = array();
        foreach( $xml->answer as $hash )
        {
            $answers[] = (string)$hash;
        }
        $this->session->set_userdata('captcha_answers', $answers);

        // load vars into view
        $this->load->vars(array( 'captcha' => (string)$xml->question ));

        // load the view
        $this->load->view('example');
    }

    function check_captcha( $string )
    {
        $user_answer = md5(strtolower(trim($string)));
        $answers = $this->session->userdata('captcha_answers');

        if( in_array($user_answer, $answers) )
        {
            return TRUE;
        }
        else
        {
            $this->form_validation->set_message('check_captcha', 'Your answer was incorrect!');
            return FALSE;
        }
    }
}
application/views/example.php
<h2>Leave a Comment</h2>
<?php echo form_open('/example/index/'); ?>

    <div class="textfield">
        <?php echo form_label('Name', 'name'); ?>
        <?php echo form_error('name'); ?>
        <?php echo form_input('name'); ?>
    </div>

    <div class="textfield">
        <?php echo form_label('Email', 'email'); ?>
        <?php echo form_error('email'); ?>
        <?php echo form_input('email'); ?>
    </div>

    <div class="textfield">
        <?php echo form_label('Url', 'url'); ?>
        <?php echo form_error('url'); ?>
        <?php echo form_input('url'); ?>
    </div>

    <div class="textfield">
        <?php echo form_label($captcha, 'captcha'); ?>
        <?php echo form_error('captcha'); ?>
        <?php echo form_input('captcha'); ?>
    </div>

    <div class="textarea">
        <?php echo form_label('Comment', 'comment'); ?>
        <?php echo form_error('comment'); ?>
        <?php echo form_textarea('comment'); ?>
    </div>

    <div class="buttons">
        <button type="submit" name="submit" value="submit">Submit Comment</button>
    </div>
<?php echo form_close(); ?>

In order for Text CAPTCHA to do its job, we need to add a new form field for the question to be answered. I pass the question to the view as $captcha.

<div class="textfield">
    <?php echo form_label($captcha, 'captcha'); ?>
    <?php echo form_error('captcha'); ?>
    <?php echo form_input('captcha'); ?>
</div>

Using CodeIgniter’s Form Validation library, we need to add a new rule for the CAPTCHA. Notice we also have defined a call back: callback_check_captcha. We will use this callback to write a custom validation function to make sure our CAPTCHA was answered correctly

$this->form_validation->set_rules('captcha', 'captcha', 'required|callback_check_captcha');

Next we need to call the Text CAPTCHA service to get our random question. You will need to register to receive your api key. Be sure to replace your_api_key with the key you receive.

This try-catch statement will attempt to communicate with the Text CAPTCHA web service. If it fails, we fallback to a predefined question seamlessly. We then store all of the accepted answers into an array which is also stored in the session so we can use it for validation later.

// setup textCAPTCHA
try {
    $xml = @new SimpleXMLElement('http://textcaptcha.com/api/your_api_key', NULL, TRUE);
} catch ( Exception $e ) {
    $fallback  = '<captcha>';
    $fallback .= '<question>Is ice hot or cold?</question>';
    $fallback .= '<answer>'.md5('cold').'<answer>';
    $fallback .= '</captcha>';
    $xml = new SimpleXMLElement($fallback);
}

// store answers in session for use later
$answers = array();
foreach( $xml->answer as $hash )
{
    $answers[] = (string)$hash;
}
$this->session->set_userdata('captcha_answers', $answers);

After Text CAPTCHA is setup and initialized, we need to pass the question to our view for use in the form.

// load vars into view
$this->load->vars(array( 'captcha' => (string)$xml->question ));

CodeIgniter’s Form Validation library makes custom validation functions easy. All we need to do is check if the answer submitted is in the list of acceptable answers. If not, we fail the test and return our error message.

function check_captcha( $string )
{
    $user_answer = md5(strtolower(trim($string)));
    $answers = $this->session->userdata('captcha_answers');

    if( in_array($user_answer, $answers) )
    {
        return TRUE;
    }
    else
    {
        $this->form_validation->set_message('check_captcha', 'Your answer was incorrect!');
        return FALSE;
    }
}

That’s it! Simple enough, right? You can download the demo for the complete code.

Validate terminal command in PHP

Testing if a function exists in PHP is easy. Testing if a command exists on the system is also easy.

I’ve never really run into the problem of having to create a compatibility suite script to make sure my PHP script will run without trouble. Simple things like checking the version of PHP installed or the version of MySQL are straightforward. This time though, I needed to make sure a command line program existed on the system which I invoke using exec().

First and foremost, we need to check that exec() exists and we can use it. If it does, we then need to use it to execute a command on the server which will output the path to our command. I will be testing for tar in the example.

if( function_exists('exec') )
{
    // send test command to system
    exec('command -v tar >& /dev/null && echo "Found" || echo "Not Found"', $output);

    if( $output[0] == "Found" )
    {
        // command is available
        return TRUE;
    }
    else
    {
        // command is unavailable
        return FALSE;
    }
}

Our focus will be this line:

exec('command -v tar >& /dev/null && echo "Found" || echo "Not Found"', $output);

In the first part of the command we will run command with the -v option. The -v option causes the output of the command to be displayed or return zero if the command is not found. Here’s a short description of the command:

SYNTAX
    command [-pVv] command [arguments ...]
OPTIONS
    -P  Use a default path
    -v  Verbose
    -V  More verbose

The next part of the command we use >& which is a metacharacter in Unix which tells the command to redirect the standard output and standard error. Which in this case, we redirect the output to a file /dev/null. We do this because we want to handle the response of the command with the last part.

The last part of the command we use && which is another metacharacter which tells Unix to execute the following command only if the preceding command succeeds. We also use the || metacharacter which tells Unix to execute the following command if the preceding command fails. To understand it better, it’s just like writing an if-then-else statement:

If( command -v tar >& /dev/null ) Then
    echo "Found"
Else
    echo "Not Found"
End If

Now we need to bring the response back to PHP. We do that with the second parameter of exec(); $output. Every line of output from the command will be returned in $output as an array which we can then run our conditional against.

Short, simple, easy little command. Just replace tar with the command you’d like to check for. You could even take the code and place it into a function to make it easily reusable.

Modular Sidebar in WordPress

Like all good developers, I go back and look at past code to see what I could have improved and how I can apply the new knowledge to a current project.

Both of the projects in question had sidebars with sections that are shared throughout the site. However, not all sections are being displayed at once. Some blocks of HTML would be show on the homepage, another on the about page and both on the contact page. Here is how I coded it in WordPress for each site.

Site One

For this site, there is ‘Live Bulletin’, ‘Make a Donation’, ‘Testimonials’, ‘Downloads’ and ‘Social Networks’ sections. In the sidebar template I had each section in it’s own if statement. For each if statement, I would use WordPress’ Conditional Tags to show or hide certain sections that I needed for a particular page. Here is a quick glance at how my template file was looking:

<div id="sidebar">

	<?php if( !is_page(270) AND !is_page(262) ) : ?>
		<div id="live-bulletin">
			<!-- html code -->
		</div>
	<?php endif; ?>

	<?php if( is_page(270) ) : ?>
		<div id="make-donation">
			<!-- html code -->
		</div>
	<?php endif; ?>

	<?php if( is_home() OR is_page(262) ) : ?>
		<div id="testimonials">
			<!-- html code -->
		</div>
	<?php endif; ?>

	<?php if( is_front_page() OR is_search() OR is_page(890) ) : ?>
		<div id="downloads">
			<!-- html code -->
		</div>
	<?php endif; ?>

	<div id="social-networks">
		<!-- html code (shown on all pages) -->
	</div>

</div>

This sidebar template got pretty messy, very quickly. Little updates such as displaying a section on another page became a hassle. For the next site, I didn’t rush, took my time and tried a different method.

Site Two

I’ll just use the same sections as the previous site for easy comparison. With this next method, I decided to put each section in it’s own function. That way, I could separate the logic from the view easily and make modifications quickly. Here is how this template came out:

<?php function sidebar_livebulletin() { ?>
	<div id="live-bulletin">
		<!-- html code -->
	</div>
<?php } ?>

<?php function sidebar_makedonation() { ?>
	<div id="make-donation">
		<!-- html code -->
	</div>
<?php } ?>

<?php function sidebar_testimonials() { ?>
	<div id="testimonials">
		<!-- html code -->
	</div>
<?php } ?>

<?php function sidebar_downloads() { ?>
	<div id="downloads">
		<!-- html code -->
	</div>
<?php } ?>

<?php function sidebar_socialnetworks() { ?>
	<div id="social-networks">
		<!-- html code -->
	</div>
<?php } ?>

<div id="sidebar">
	<?php
	// Home Page
	if( is_front_page() )
	{
		sidebar_livebulletin();
		sidebar_testimonials();
		sidebar_socialnetworks();
	}

	// About Page
	if( is_page(8) )
	{
		sidebar_testimonials();
		sidebar_downloads();
		sidebar_socialnetworks();
	}

	// Contact Page
	if( is_page(12) )
	{
		sidebar_makedonation();
		sidebar_socialnetworks();
	}
	?>
</div>

Now that is a better looking template! I’ve seen this function-based implementation before and I really like it. Updating this template has proven to be quick and easy. I have already started to adopt this method and will continue too until I establish a better method.