Saturday, April 10, 2010

Start with URL Rewriting

An Introduction to Rewriting



Readable URLs are nice. A well designed website will have a logical file system layout, with smart folder and file names, and as many implementation details left out as possible. In the most well designed sites, readers can guess at filenames with a high level of success.



However, there are some cases when the best possible information design can’t stop your site’s URLs from being nigh-on impossible to use. For instance, you may be using a Content Management System that serves out URLs that look something like



http://www.example.com/viewcatalog.asp?category=hats&prodID=53



This is a horrible URL, but it and its brethren are becoming increasingly prevalent in these days of dynamically-generated pages. There are a number of problems with an URL of this kind:




  • It exposes the underlying technology of the website (in this case ASP). This can give potential hackers clues as to what type of data they should send along with the query string to perform a ‘front-door’ attack on the site. Information like this shouldn’t be given away if you can help it.



    Even if you’re not overly concerned with the security of your site, the technology you’re using is at best irrelevant — and at worst a source of confusion — to your readers, so it should be hidden from them if possible.



    Also, if at some point in the future you decide to change the language that your site is based on (to » PHP, for instance); all your old URLs will stop working. This is a pretty serious problem, as anyone who has tackled a full-on site rewrite will attest.



  • The URL is littered with awkward punctuation, like the question mark and ampersand. Those & characters, in particular, are problematic because if another webmaster links to this page using that URL, the un-escaped ampersands will mess up their XHTML conformance. They will have to laboriously replace all the ampersands with & character entities, which is often forgotten.


  • Some search engines won’t index pages which they think are generated dynamically. They’ll see that question mark in the URL and just turn their asses around.



Luckily, using rewriting, we can clean up this URL to something far more manageable. For example, we could map it to



http://www.example.com/catalog/hats/53/



Much better. This URL is more logical, readable and memorable, and will be picked up by all search engines. The faux-directories are short and descriptive. Importantly, it looks more permanent.



To use mod_rewrite, you supply it with the link text you want the server to match, and the real URLs that these URLs will be redirected to. The URLs to be matched can be straight file addresses, which will match one file, or they can be regular expressions, which will match many files.



Basic Rewriting



Some servers will not have » mod_rewrite enabled by default. As long as the » module is present in the installation, you can enable it simply by starting a .htaccess file with the command



RewriteEngine on



Put this .htaccess file in your root so that rewriting is enabled throughout your site. You only need to write this line once per .htaccess file.



Basic Redirects



We’ll start off with a straight redirect; as if you had moved a file to a new location and want all links to the old location to be forwarded to the new location. Though you shouldn’t really ever » move a file once it has been placed on the web; at least when you simply have to, you can do your best to stop any old links from breaking.




RewriteEngine on

RewriteRule ^old\.html$ new.html



Though this is the simplest example possible, it may throw a few people off. The structure of the ‘old’ URL is the only difficult part in this RewriteRule. There are three special characters in there.




  • The caret, ^, signifies the start of an URL, under the current directory. This directory is whatever directory the .htaccess file is in. You’ll start almost all matches with a caret.

  • The dollar sign, $, signifies the end of the string to be matched. You should add this in to stop your rules matching the first part of longer URLs.

  • The period or dot before the file extension is a special character in regular expressions, and would mean something special if we didn’t escape it with the backslash, which tells Apache to treat it as a normal character.




So, this rule will make your server transparently redirect from old.html to the new.html page. Your reader will have no idea that it happened, and it’s pretty much instantaneous.



Forcing New Requests



Sometimes you do want your readers to know a redirect has occurred, and can do this by forcing a new HTTP request for the new page. This will make the browser load up the new page as if it was the page originally requested, and the location bar will change to show the URL of the new page. All you need to do is turn on the [R] flag, by appending it to the rule:




RewriteRule ^old\.html$ new.html [R]



Using Regular Expressions



Now we get on to the really useful stuff. The power of mod_rewrite comes at the expense of complexity. If this is your first encounter with regular expressions, you may find them to be a tough nut to crack, but the options they afford you are well worth the slog. I’ll be providing plenty of examples to guide you through the basics here.



Using regular expressions you can have your rules matching a set of URLs at a time, and mass-redirect them to their actual pages. Take this rule;




RewriteRule ^products/([0-9][0-9])/$ /productinfo.php?prodID=$1



This will match any URLs that start with ‘products/’, followed by any two digits, followed by a forward slash. For example, this rule will match an URL like products/12/ or products/99/, and redirect it to the PHP page.



The parts in square brackets are called ranges. In this case we’re allowing anything in the range 0-9, which is any digit. Other ranges would be [A-Z], which is any uppercase letter; [a-z], any lowercase letter; and [A-Za-z], any letter in either case.



We have encased the regular expression part of the URL in parentheses, because we want to store whatever value was found here for later use. In this case we’re sending this value to a PHP page as an argument. Once we have a value in parentheses we can use it through what’s called a back-reference. Each of the parts you’ve placed in parentheses are given an index, starting with one. So, the first back-reference is $1, the third is $3 etc.



Thus, once the redirect is done, the page loaded in the readers’ browser will be something like productinfo.php?prodID=12 or something similar. Of course, we’re keeping this true URL secret from the reader, because it likely ain’t the prettiest thing they’ll see all day.



Multiple Redirects



If your site visitor had entered something like products/12, the rule above won’t do a redirect, as the slash at the end is missing. To promote good URL writing, we’ll take care of this by doing a direct redirect to the same URL with the slash appended.




RewriteRule ^products/([0-9][0-9])$ /products/$1/ [R]



Multiple redirects in the same .htaccess file can be applied in sequence, which is what we’re doing here. This rule is added before the one we did above, like so:




RewriteRule ^products/([0-9][0-9])$ /products/$1/ [R]

RewriteRule ^products/([0-9][0-9])/$ /productinfo.php?prodID=$1



Thus, if the user types in the URL products/12, our first rule kicks in, rewriting the URL to include the trailing slash, and doing a new request for products/12/ so the user can see that we likes our trailing slashes around here. Then the second rule has something to match, and transparently redirects this URL to productinfo.php?prodID=12. Slick.



Match Modifiers



You can expand your regular expression patterns by adding some modifier characters, which allow you to match URLs with an indefinite number of characters. In our examples above, we were only allowing two numbers after products. This isn’t the most expandable solution, as if the shop ever grew beyond these initial confines of 99 products and created the URL productinfo.php?prodID=100, our rules would cease to match this URL.



So, instead of hard-coding a set number of digits to look for, we’ll work in some room to grow by allowing any number of characters to be entered. The rule below does just that:




RewriteRule ^products/([0-9]+)$ /products/$1/ [R]



Note the plus sign (+) that has snuck in there. This modifier changes whatever comes directly before it, by saying ‘one or more of the preceding character or range.’ In this case it means that the rule will match any URL that starts with products/ and ends with at least one digit. So this’ll match both products/1 and products/1000.



Other match modifiers that can be used in the same way are the asterisk, *, which means ‘zero or more of the preceding character or range’, and the question mark, ?, which means ‘zero or only one of the preceding character or range.’



Adding Guessable URLs



Using these simple commands you can set up a slew of ‘shortcut URLs’ that you think visitors will likely try to enter to get to pages they know exist on your site. For example, I’d imagine a lot of visitors try jumping straight into our stylesheets section by typing the URL http://www.yourhtmlsource.com/css/. We can catch these cases, and hopefully alert the reader to the correct address by updating their location bar once the redirect is done with these lines:




RewriteRule ^css(/)?$ /stylesheets/ [R]



The simple regular expression in this rule allows it to match the css URL with or without a trailing slash. The question mark means ‘zero or one of the preceding character or range’ — in other words either yourhtmlsource.com/css or yourhtmlsource.com/css/ will both be taken care of by this one rule.



This approach means less confusing 404 errors for your readers, and a site that seems to run a whole lot smoother all ’round.

Wednesday, March 3, 2010

iPhone development with PHP and XML

Building the command list



Building the application starts with defining some commands that the iPhone remote
control will present for you to select. You use an XML file to define the
commands. Listing 1 shows this file.



Listing 1. commands.xml
                
<commands>
<command title="Next Song">
tell application "iTunes" to next track
</command>

<command title="Previous Song">
tell application "iTunes" to back track
</command>
</commands>


The file is a list of <command> tags. Each tag has
a title attribute that defines a human readable title for the command. And the
content of the <command> tag is the AppleScript
code to execute when the command is requested. Because of XML encodings, if you
want to put in any AppleScript code that has angle bracket (< or >) or
ampersand (&) characters, you must encode those as <,
>, and &, respectively.



To wrap this XML file, I wrote a PHP V5 Command class
that reads the file, returns the command names, and runs the commands using the
Mac OS X osascript command. The code for this class is
shown in Listing 2.



Listing 2. commands.php
                
<?php
class Commands
{
private $_commands;

function __construct()
{
$this->_commands = array();

$doc = new DOMDocument();
$doc->load('commands.xml');
$cmds = $doc->getElementsByTagName( 'command' );
foreach( $cmds as $cmd )
{
$this->_commands []= array(
'title' => $cmd->getAttribute('title'),
'command' => $cmd->firstChild->nodeValue
);
}
}

function getCommands()
{
$cmds = array();
foreach( $this->_commands as $cmd )
{
$cmds []= $cmd['title'];
}
return $cmds;
}

function runCommand( $id )
{
$ph = popen( "osascript", "w" );
fwrite( $ph, $this->_commands[$id]['command'] );
fclose( $ph );
}
}
?>




The class starts by loading up the commands.xml file. It reads in the file using the
DomDocument PHP class. Then, it finds all the command
arguments using getElementsByTagName. When it has the
<command> tags as an array, the class loads the
_commands member variable with the titles and
AppleScript commands.


Two additional methods are defined:




  • The getCommands() method, which simply returns a list of the names

  • The runCommand() method, which given an index runs that command using the osascript command-line AppleScript executor.




Building the interface


With the commands XML file and Commands PHP class written,
it's time to add an interface. Just to make sure everything is
working properly, I'll put a fairly rudimentary interface on it. This interface is
shown in Listing 3.



Listing 3. Simple interface script
                

<html><body>
<?php
require_once('commands.php');
$cmds = new Commands();
?>
<?php
$id = 0;
foreach( $cmds->getCommands() as $cmd ) {
?>
<a href="do.php?id=<?php echo($id);?>"><?php echo( $cmd ); ?></a><br/>
<?php $id++; } ?>

</body></html>


The script first gets the Command class, and then asks it
for the lists of commands using the getCommands() method.
Then, the script builds a set of links to the do.php page using the command index
number and the name of the command that the Commands
class returned.



When I navigate to the page in the Safari browser, I see something like
Figure 1.




Figure 1. The rudimentary interface

The rudimentary interface



I could use this as my iPhone interface and it would work. But it wouldn't feel like
the iPhone. So, the next thing to do is use the iUI toolkit to extend the interface.
Listing 4 shows the code for doing so.




Listing 4. index.php
                
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head>
<title>Mac Controller</title>
<meta name="viewport"
content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=no;"/>
<style type="text/css" media="screen">@import "iui/iui.css";</style>

<script type="application/x-javascript" src="iui/iui.js"></script>
</head>
<body>
<div class="toolbar">
<h1 id="pageTitle"></h1>
<a id="backButton" class="button" href="#"></a>

</div>
<?php
require_once('commands.php');
$cmds = new Commands();
?>
<ul title="Commands" selected="true">
<?php
$id = 0;
foreach( $cmds->getCommands() as $cmd ) {
?>
<li>
<a href="do.php?id=<?php echo($id);?>"><?php echo( $cmd ); ?></a>

</li>
<?php $id++; } ?>
</ul>
</body></html>



At the top of the file, you include the iUI CSS file that has all the styles that
give the page its iPhone look. Then, you include the iUI JavaScript file that
handles all the interactivity. After that, you use the Commands
class to get the list of commands. With that list, you build an unordered list
(<ul>) with list item elements for each item
(<li>). No, it's not as ugly as it sounds. In
fact, you can look at it in Safari, and you'll get exactly the same look as you
would on the iPhone, as shown in Figure 2.





Figure 2. The index.php page as rendered in Safari

The index.php page as rendered in Safari



If you use Windows, don't worry: Safari now runs on both Windows and Mac. Of
course, the PHP that runs this code must be on a Mac to run the
osascript command and the AppleScript code. But you
could use system commands if you want to run this on DOS or UNIX® systems.



The final step is to create the do.php file that index.php references to run the
actual commands. This class is shown in Listing 5.




Listing 5. do.php
                
<?php
require_once('commands.php');

$cmds = new Commands();
$cmds->runCommand( $_GET['id'] );
?>


Now, you can use Safari to browse to the page locally and just click the links to
check whether the application works. If everything is in order, iTunes
will go to the next or previous song depending on what you select.


One thing I did have to change on my installation was to edit the /etc/httpd/httpd.conf
file, change the User setting to my user name, and change the Group

setting to staff. I then rebooted my Apache server by running this command
line:


% apachectl graceful


With that done, my iTunes interface flipped back and forth between tracks when I
clicked the links. I can then turn on my iPhone and use the Safari browser to go
to my local machine by IP address and access the application, as long as my laptop
and my iPhone are on the same Wi-Fi network.



Telekenesis



As I did the research for this article, I found that someone had already taken
this whole concept of a Mac-driven remote for the iPhone to a new level. The project
is called telekinesis, and it's
hosted on the Google Code site. The application is called iPhone Remote, and
it runs as a graphical user interface (GUI) application in Mac OS X.



When I launch iPhone Remote, it opens Safari to a page that shows what it will look
like on the iPhone. This is shown in Figure 3.




Figure 3. The iPhone Remote interface

The iPhone Remote interface


From here, I can navigate to my applications and open them, browse my documents, use
an iTunes remote, even navigate around the screen and run command lines—all
from my iPhone.


The iPhone Remote does prompt you for a user name and password so that not just
anyone can use your Mac after you've installed and run it. So, it's possible to
use the iPhone as a secure virtual network computing (VNC) device for your Mac
remotely.




Conclusion






Developing for the iPhone is a breeze. The ads say that the iPhone gives you access
to the Internet as is rather than some mobile version of it, and the ads are right:
You can browse to your normal pages just as you would on your Mac or PC. But
toolkits like the iUI interface builder help give the application a more genuine
iPhone look and feel—handy with applications like this XML
and PHP-driven iPhone remote.

Thursday, February 25, 2010

Easy steps to install smarty for your application


This is a simple guide to get Smarty setup and running quickly. The online
documentation includes a very thorough explanation of a Smarty installation.
This guide is meant to be a quick and painless way of getting Smarty working,
and nothing more. The guide assumes you are familiar with the UNIX system
environment. Windows users will need to make adjustments where necessary.

INSTALL SMARTY LIBRARY FILES

Copy the Smarty library files to your system. In our example, we place them in
/usr/local/lib/php/Smarty/

$> cd YOUR_DOWNLOAD_DIRECTORY
$> gtar -zxvf Smarty-2.6.7.tar.gz
$> mkdir /usr/local/lib/php/Smarty
$> cp -r Smarty-2.6.7/libs/* /usr/local/lib/php/Smarty

You should now have the following file structure:

/usr/local/lib/php/Smarty/
Config_File.class.php
debug.tpl
internals/
plugins/
Smarty.class.php
Smarty_Compiler.class.php


SETUP SMARTY DIRECTORIES

You will need four directories setup for Smarty to work. These files are for
templates, compiled templates, cached templates and config files. You may or
may not use caching or config files, but it is a good idea to set them up
anyways. It is also recommended to place them outside of the web server
document root. The web server PHP user will need write access to the cache and
compile directories as well.

In our example, the document root is /web/www.domain.com/docs and the
web server username is "nobody". We will keep our Smarty files under
/web/www.domain.com/smarty

$> cd /web/www.domain.com
$> mkdir smarty
$> mkdir smarty/templates
$> mkdir smarty/templates_c
$> mkdir smarty/cache
$> mkdir smarty/configs
$> chown nobody:nobody smarty/templates_c
$> chown nobody:nobody smarty/cache
$> chmod 775 smarty/templates_c
$> chmod 775 smarty/cache


SETUP SMARTY PHP SCRIPTS

Now we setup our application in the document root:

$> cd /web/www.domain.com/docs
$> mkdir myapp
$> cd myapp
$> vi index.php

Edit the index.php file to look like the following:


// put full path to Smarty.class.php
require('/usr/local/lib/php/Smarty/Smarty.class.php');
$smarty = new Smarty();

$smarty->template_dir = '/web/www.domain.com/smarty/templates';
$smarty->compile_dir = '/web/www.domain.com/smarty/templates_c';
$smarty->cache_dir = '/web/www.domain.com/smarty/cache';
$smarty->config_dir = '/web/www.domain.com/smarty/configs';

$smarty->assign('name', 'Ned');
$smarty->display('index.tpl');

?>


SETUP SMARTY TEMPLATE

$> vi /web/www.domain.com/smarty/templates/index.tpl

Edit the index.tpl file with the following:



Smarty


Hello, {$name}!





Now go to your new application through the web browser,
http://www.domain.com/myapp/index.php in our example. You should see the text
"Hello Ned!" in your browser.

Once you get this far, you can continue on to the Smarty Crash Course to learn
a few more simple things, or on to the documentation to learn it all.

Friday, January 1, 2010

How to Create a Joomla! Plugin

Introduction


Joomla! plugins serve a variety of purposes.  As modules enhance the presentation of the final output of the Web site, plugins enhance the data and can also provide additional, installable functionality.


This tutorial looks at the general principles used to design and build a plugin.





Plugin Types


While the number of possible types of plugins is almost limitless, there are a number of core plugin types that are used by Joomla!.  These core types are grouped into directories under /plugins/.  They are:




  • authentication

  • content

  • editors

  • editors-xtd

  • search

  • system


  • user

  • xmlrpc


Authentication plugins allow you to authenticate (to allow you to login) against different sources.  By default you will authenticate against the Joomla! user database when you try to login.  However, there are other methods available such as by OpenID, by a Google account, LDAP, and many others.  Wherever a source has a public API, you can write an authentication plugin to verify the login credentials against this source.  For example, you could write a plugin to authenticate against Twitter accounts because they have a public API.



Content plugins modify and add features to displayed content.  For example, content plugins can cloak email address or can convert URL's into SEF format.  Content plugins can also look for markers in content and replace them with other text or HTML.  For example, the Load Module plugin will take {*loadmodule banner1*} (you would remove the *'s in practice.  They are included to actually prevent the plugin from working in this article), load all the modules in the banner1 position and replace the marker with that output.


Editor plugins allow you to add new content editors (usually WYSIYWG).


Editor-XTD (extended) plugins allow you to add additional buttons to the editors.  For example, the Image, Pagebreak and Read more buttons below the default editor are actually plugins.



Search plugins allow you to search different content from different components.  For example, search plugins for Articles, Contacts and Weblinks are already provided in Joomla!.


System plugins allow you to perform actions at various points in the execution of the PHP code that runs a Joomla! Web site.


User plugins allow you to perform actions at different times with respect to users.  Such times include logging in and out and also saving a user.  User plugins are typically user to "bridge" between web applications (such as creating a Joomla! to phpBB bridge).



XML-RPC plugins allow you to provide additional XML-RPC web services for your site.  When your Web site exposes web services, it gives you the ability to interact remotely, possibly from a desktop application.  Web services are a fairly advanced topic and will not be covered in much detail here.


The Basic Files


While a plugin can have any number of files, there are two you need as a minimum and there are specific naming conventions you must follow.  Before we look at the files, we must decide what sort of plugin we are going to create.  It must either fall under one of the built-in types (authentication, content, editors, editors-xtd, search, system, user or xmlrpc) or your can create your own type by adding a new folder under /plugins/.  So, files for an authentication plugin will be saved under /plugins/authentication/, files for a system plugin will be saved under /plugins/system/, and so on.



Let's look at an example creating the basic skeleton for a system plugin called "Test".  There is no restriction on the file name for the plugin (although we recommend sticking with alpha-numeric characters and underscores only), but once you decide on the file name, it will set the naming convention for other parts of the plugin.


For this plugin you will need to create a PHP file, test.php, which is the file actually loaded by Joomla! and an XML file, text.xml, which contains meta and installation information for the plugin as well as the definition of the plugin parameters.


test.php


The skeleton test.php has the following source:



<?php
// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

jimport( 'joomla.plugin.plugin' );

/**
* Example system plugin
*/
class plgSystemTest extends JPlugin
{
/**
* Constructor
*
* For php4 compatibility we must not use the __constructor as a constructor for plugins
* because func_get_args ( void ) returns a copy of all passed arguments NOT references.
* This causes problems with cross-referencing necessary for the observer design pattern.
*
* @access protected
* @param object $subject The object to observe
* @param array $config An array that holds the plugin configuration
* @since 1.0
*/
function plgSystemTest( &$subject, $config )
{
parent::__construct( $subject, $config );

// Do some extra initialisation in this constructor if required
}

/**
* Do something onAfterInitialise
*/
function onAfterInitialise()
{
// Perform some action
}
}

Let's look at this file in detail.  Please note that the usual Docblock (the comment block you normally see at the top of most PHP files) has been omitted for clarity.


The file starts with the normal check for defined( '_JEXEC' ) which ensures that the file will fail to execute if access directly via the URL.  This is a very important security feature and the line must be placed before any other executable PHP in the file (it's fine to go after all the initial comment though).  The importance of having this check your PHP files cannot be overemphasised.


Next we use the jimport function to load the library file with the definition of the JPlugin class.



You will notice that a plugin is simply a class derived from JPlugin (this differs from previous versions of Joomla!).  The naming convention of this class is very important.  The formula for this name is:


plg + Proper case name of the plugin directory + Proper case name of the plugin file without the extension.


Proper case simply means that we capitalise the first letter of the name.  When we join them altogether it's then referred to as "Camel Case".  The case is not that important as PHP classes are not case-sensitive but it's the convention Joomla! uses and generally makes the code a little more readable.



For our test system plugin, the formula gives us a class name of:


plg + System + Test = plgSystemTest


Let's move on to the methods in the class.


The first method, which is called the constructor, is completely optional.  You only require this is you want to do some work when the plugin is actually loaded by Joomla!.  This happens with a call to the helper method JPluginHelper::importPlugin( <plugin_type> ).  This means that you even if the plugin is never triggered, for whatever reason, you still have an opportunity to execute code if you need to in the constructor.



In PHP 4 the name of the constructor method is the same as the name of the class.  If you were designing only for PHP 5 you could replace this with the name of __constructor instead.


The remaining methods will take on the name of "events" that are trigger throughout the execution of the Joomla! code.  In the example, we know there is an event called onAfterInitialise which is the first event called after the Joomla! application sets itself up for work.  For more information on when some events are triggered, see the API Execution Order page on the Documentation Wiki.



The naming rule here is simple: the name of the method must be the same as the event on which you want it triggered.  The Joomla! Framework will auto-register all the methods in the class for you.


That's the basics of the plugin PHP file.  It's location, name and methods will depend on what you want to use the plugin for.  One thing to note about system plugins is that they are not limited to handling just system events.  Because the system plugins are always loaded on each run of the Joomla! PHP, you can include any triggered event in a system plugin.


The events triggered in Joomla! are:


Authentication




  • onAuthenticate


Content



  • onPrepareContent

  • onAfterDisplayTitle

  • onBeforeDisplayContent

  • onBeforeContentSave (new in 1.5.4)


  • onAfterContentSave (new in 1.5.4)


Editors



  • onInit

  • onGetContent

  • onSetContent

  • onSave


  • onDisplay

  • onGetInsertMethod


Editors XTD (Extended)



  • onDisplay


Seach




  • onSearch

  • onSearchAreas


System



  • onAfterInitialise

  • onAfterRoute

  • onAfterDispatch


  • onAfterRender


User



  • onLoginUser

  • onLoginFailure

  • onLogoutUser

  • onLogoutFailure


  • onBeforeStoreUser

  • onAfterStoreUser

  • onBeforeDeleteUser

  • onAfterDeleteUser


XML-RPC



  • onGetWebServices



For more detailed information on how to create specific plugins, visit the Plugins Category on the Documentation Wiki.


text.xml


The skeleton test.xml has the following source:


<?xml version="1.0" encoding="utf-8"?>
<install version="1.5.2" type="plugin" group="system" method="upgrade">

<name>System - Test</name>
<author>Author</author>
<creationDate>Month 2008</creationDate>
<copyright>Copyright (C) 2008 Holder. All rights reserved.</copyright>

<license>GNU General Public License</license>
<authorEmail>email</authorEmail>
<authorUrl>url</authorUrl>
<version>1.0.1</version>

<description>A test system plugin</description>
<files>
<filename plugin="example">example.php</filename>
</files>
<params>

<param name="example"
type="text"
default=""
label="Example"
description="An example text parameter" />
</params>
</install>

This is a very typcial format for most meta XML files (sometimes called manifests).  Let's go through some of the most important tags:


INSTALL


The install tag has several key attributes.  The type must be "plugin" and you must specify the group.  The group attribute is required and is the name of the directory you saved your files in (for example, system, content, etc).  We use the method="upgrade" attribute to allow us to install the extension without uninstalling.  In other words, if you are sharing this plugin with other, they can just install the new version over the top of the old one.



NAME


We usually start the name with the type of plugin this is.  Our example is a system plugin and it has some some nebulous test purpose.  So we have named the plugin "System - Test".  You can name the plugins in any way, but this is a common format.


FILES


The files tag includes all of the files that will will be installed with the plugin.  Plugins can also support be installed with subdirectories.  To specify these just all a FOLDER tag, <folder>test</folder>.  It is common practice to have only one subdirectory and name it the same as the plugin PHP file (without the extension of course).



PARAMS


Any number of parameters can be specified for a plugin.  Please note there is no "advanced" group for plugins as there is in modules and components.


Packaging Plugins


Packaging a plugin is easy.  If you only have the two files (the PHP file and the XML file), just "zip" them up into a compressed archive file.  If your plugin uses a subdirectory then simply include that in the archive as well. 


How To Create A Module in Magento

This is a brief listing of the steps I have taken to test a sample module in Magento



Make folder app/code/local/Schogini <——— this name can be your company’s name, this make a new name space so that your classes will not interfere with other classes of the same name.


Inside the above folder make a folder called Example app/code/local/Schogini/Example <—- here Example is the name of the module we will create


Now add the module xml file at app/etc/modules/Schogini_All.xml <— here this can be Schogini_example.xml but I will use Schogini_All.xml so that all my test module definitions can be added to the same file instead of cluttering the etc/modules folder with many files.


<?xml version=”1.0″?>

<config>

  <modules>


    <Schogini_Example>

      <active>true</active>

      <codePool>local</codePool>

    </Schogini_Example>


  </modules>

</config>


Now create two folders app/code/local/Schogini/Example/etc and app/code/local/Schogini/Example/Block


In the app/code/local/Schogini/Example/etc folder make a file like this


<?xml version=”1.0″ encoding=”UTF-8″?>

<config>


  <modules>

    <Schogini_Example>

      <version>0.1.0</version>

    </Schogini_Example>


  </modules>

  <global>

    <blocks>

      <example>

        <class>Schogini_Example_Block</class>


      </example>

    </blocks>

  </global>

</config>


And now create the block php class file at app/code/local/Schogini/Example/Block/Myview.php



<?php

class Schogini_Example_Block_Myview extends Mage_Core_Block_Template {

 public function myFunction(){

  return “Hello World!“;


 }

}

?>


Now make the view folder at app/design/frontend/default/default/template/example <– here you should figure out the correct template folder of your Magento store.


Inside this create the view file for the module block app/design/frontend/default/default/template/example/myview.phtml


<p>Schogini example:</p>


<?php

  echo $this->myFunction();

?>


We can enable or disable this module at Admin -> System -> Advanced



image


Module creation is over at this point.


Now! Edit any page where you will want this module to show its output!


I have tested the above module in the home page by Admin -> CMS -> Manage Pages -> Home and edited to add these lines somewhere at the bottom


{{block type="example/myview" template="example/myview.phtml"}}


Please not the name space “schogini” is not required in the above line..



Reload the Magento home to see your module in action!

Sunday, December 20, 2009

PHP coding guidelines

PHP coding guidelines

The guidelines that I follow when writing my PHP scripts; can be helpful to have something like this if you're working on a joint project.


N.B. These are only the guidelines that I personally chose to follow for the code I write. This is not an indication that any other coding styles, guidelines or standards are wrong. Feel free to use this document as a template to manage your own coding guideline and change whatever you wish as you see fit.


Why are guidelines important?


First of all, let's make one point crystal clear: it doesn't matter what your guidelines are, so long as everyone understands and sticks to them. I've worked on a team where the person in charge preferred to put braces following the expression, rather than on a line all by themselves. Whilst I didn't necessarily agree with this convention, I stuck to it because it made maintaining the whole project much easier.


It cannot be emphasised enough that guidelines are only useful if they are followed. It's no use having a definitive set of coding guidelines for a joint programming project if everyone continues to write in their own style regardless. It is arguable that you can get away with different coding styles if every team member works on a different section which is encapsulated and therefore their coding style doesn't affect the other developers. Unfortunately, this only holds true until a developer leaves and someone else has to take over their role.


If you are running a joint project, you might consider putting your foot down and basically refuse to accept any code that does not conform to your published guidelines, regardless of its technical merit (or lack thereof). This may sound somewhat draconian and off-putting to developers at first, but once everyone begins to code to the guidelines you'll find it a lot easier to manage the project and you'll get more work done in the same time. It will require a lot of effort from some of your developers who don't want to abandon their coding habits, but at the end of the day different coding styles will cause more problems than they're worth.


Editor settings



Tabs v. spaces


Ahh, the endless debate of tabs v. spaces. To be honest, I recommend using tabs all the time for the simple reasons that it is much easier to align everything using them, and tabs require less space in a file than multiple spaces. Also, if you set your editor to display a tab character as 8 spaces, but another developer prefers to have them represented as 4 spaces, it doesn't matter in the slightest.


A mention needs to be made of the PEAR project, who insist on using four spaces instead of tabs in their guidelines. If you want to write code for them, just do it in tabs and then do a quick search/replace to change them all to four spaces.


Linefeeds


The three major operating systems (Unix, Windows and Mac OS) use different ways to represent the end of a line. Unix systems use the newline character (\n), Mac systems use a carriage return (\r), and Windows systems are terribly wasteful in that they use a carriage return followed by a line feed (\r\n).



I use simple newlines all the time, because the Windows way just doubles the size of your line breaks and the Mac OS way is technically incorrect in that a carriage return should only return you to the beginning of the line, ala the old typewriter systems.


If you develop on Windows (and many people do), either set up your editor to save files in Unix format or run a utility that converts between the two file formats.


Naming conventions


Variable names


A lot of textbooks (particulary those about Visual C++) will try to drum hungarian notation into your head. Basically, this means having rules such as pre-pending g_ to global variables, i to integer data types etc. Not only is a lot of this irrelevant to PHP (being a typeless language), it also produces variable names such as g_iPersonAge which, to be honest, are not easy to read at a glance and often end up looking like a group of random characters strung together without rhyme or reason.


Variable names should be all lowercase, with words separated by underscores. For example, $current_user is correct, but $currentuser, $currentUser and $CurrentUser are not.



Names should be descriptive, but also concise. Wherever possible, keep variable names to under 15 characters, although be prepared to sacrifice a few extra characters to improve clarity. There's no hard and fast rule when it comes to the length of a variable name, so just try and be as concise as possible without affecting clarity too much. Generally speaking, the smaller the scope of a variable, the more concise you should be, so global variables will usually have the longest names (relative to all others) whereas variables local to a loop might have names consisting only of a single character.


Constants should follow the same conventions as variables, except use all uppercase to distinguish them from variables. So USER_ACTIVE_LEVEL is correct, but USERACTIVELEVEL or user_active_level would be incorrect.


Loop indices


This is the only occassion where short variable names (as small as one character in length) are permitted, and indeed encouraged. Unless you already have a specific counting variable, use $i as the variable for the outermost loop, then go onto $j for the next most outermost loop etc. However, do not use the variable $l (lowercase 'L') in any of your code as it looks too much like the number 'one'.



Example of nested loops using this convention:



<?php
for ( $i = 0; $i < 5; $i++ )
{
    for (
$j = 0; $j < 4; $j++ )
    {
        for (
$k = 0; $k < 3; $k++ )
        {
            for (
$m = 0; $m < 2; $m++ )
            {
                
foo($i, $j, $k, $m);
            }
        }
    }
}
?>



If, for some reason, you end up nesting loops so deeply that you get to $z, consider re-writing your code. I've written programs (in Visual Basic, for my sins) with loops nested four levels deep and they were complicated enough. If you use these guidelines in a joint project, you may way to impose an additional rule that states a maximum nesting of x levels for loops and perhaps for other constructs too.


Function names


Function names should follow the same guidelines as variable names, although they should include a verb somewhere if at all possible. Examples include get_user_data() and validate_form_data(). Basically, make it as obvious as possible what the function does from its name, whilst remaining reasonably concise. For example, a_function_which_gets_user_data_from_a_file() would not be appropriate!



Function arguments


Since function arguments are just variables used in a specific context, they should follow the same guidelines as variable names.


It should be possible to tell the main purpose of a function just by looking at the first line, e.g. get_user_data($username). By examination, you can make a good guess that this function gets the user data of a user with the username passed in the $username argument.


Function arguments should be separated by spaces, both when the function is defined and when it is called. However, there should not be any spaces between the arguments and the opening/closing brackets.


Some examples of correct/incorrect ways to write functions:



<?php
get_user_data
( $username, $password ); // incorrect: spaces next to brackets
get_user_data($username,$password); // incorrect: no spaces between arguments
get_user_data($a, $b); // ambiguous: what do variables $a and $b hold?
get_user_data($username, $password); // correct
?>



Code layout


Including braces


Braces should always be included when writing code using if, for, while etc. blocks. There are no exceptions to this rule, even if the braces could be omitted. Leaving out braces makes code harder to maintain in the future and can also cause bugs that are very difficult to track down.



Some examples of correct/incorrect ways to write code blocks using braces:



<?php
/* These are all incorrect */

if ( condition ) foo();

if (
condition )
    
foo();

while (
condition )
    
foo();

for (
$i = 0; $i < 10; $i++ )
    
foo($i);

/* These are all correct */

if ( condition )
{
    
foo();
}

while (
condition )
{
    
foo();
}

for (
$i = 0; $i < 10; $i++ )
{
    
foo($i);
}
?>



Where to put the braces


Braces should always be placed on a line on their own; again there are no exceptions to this rule. Braces should also align properly (use tabs to achieve this) so a closing brace is always in the same column as the corresponding opening brace. For example:



<?php
if ( condition )
{
    while (
condition )
    {
        
foo();
    }
}
?>



I know that a lot of programmers prefer to put the first brace on the first line of the block they are encoding, to prevent wasting a line. However, I strongly disagree with this as it makes code much easier to read (in my opinion) if braces line up correctly.


Spaces between tokens


There should always be one space on either side of a token in expressions, statements etc. The only exceptions are commas (which should have one space after, but none before), semi-colons (which should not have spaces on either side if they are at the end of a line, and one space after otherwise). Functions should follow the rules laid out already, i.e. no spaces between the function name and the opening bracket and no space between the brackets and the arguments, but one space between each argument.


Control statements such as if, for, while etc. should have one space on either side of the opening bracket, and one space before the closing bracket. However, individual conditions inside these brackets (e.g. ($i < 9) || ($i > 16)) should not have spaces between their conditions and their opening/closing brackets.



In these examples, each pair shows the incorrect way followed by the correct way:



<?php
$i
=0;
$i = 0;

if((
$i<2 )||( $i>5 ))
if ( (
$i < 2) || ($i > 5) )

foo ( $a,$b,$c )
foo($a, $b, $c)

$i=($j<5)?$j:5
$i
= ($j < 5) ? $j : 5
?>




Operator precedence


I doubt very much that any developer knows the exact precedence of all the operators in PHP. Even if you think you know the order, don't guess because chances are you'll get it wrong and cause an unexpected bug that will be very difficult to find. Also, it will make maintaining your program a living nightmare for anyone who doesn't know the precedence tables in so much depth. Always use brackets to make it absolutely clear what you are doing.



<?php
$i
= $j < 5 || $k > 6 && $m == 9 || $n != 10 ? 1 : 2; // What *is* going on here?!?
$i = ( (($j < 5) || $k > 6)) && (($m == 9) || ($n != 10)) ) ? 1 : 2; // Much clearer
?>



N.B. If you are using expressions like the one above you should split them up into smaller chunks if possible, even if you are already laying them out in the correct format. No-one should have to debug code like that, there's too many conditions and logic operators.


SQL code layout


When writing SQL queries, capitialise all SQL keywords (SELECT, FROM, VALUES, AS etc.) and leave everything else in the relevant case. If you are using WHERE clauses to return data corresponding to a set of conditions, enclose those conditions in brackets in the same way you would for PHP if blocks, e.g. SELECT * FROM users WHERE ( (registered = 'y') AND ((user_level = 'administrator') OR (user_level = 'moderator')) ).



General guidelines


Quoting strings


Strings in PHP can either be quoted with single quotes ('') or double quotes (""). The difference between the two is that the parser will use variable-interpolation in double-quoted strings, but not with single-quoted strings. So if your string contains no variables, use single quotes and save the parser the trouble of attempting to interpolate the string for variables, like so:



<?php
$str
= "Avoid this - it just makes more work for the parser."; // Double quotes
$str = 'This is much better.' // Single quotes
?>



Likewise, if you are passing a variable to a function, there is no need to use double quotes:



<?php
foo
("$bar"); // No need to use double quotes
foo($bar); // Much better
?>



Finally, when using associative arrays, you should include the key within single quotes to prevent any ambiguities, especially with constants:



<?php
$foo
= $bar[example]; // Wrong: what happens if 'example' is defined as a constant elsewhere?
$foo = $bar['example']; // Correct: no ambiguity as to the name of the key
?>



However, if you are accessing an array with a key that is stored in a variable, you can simply use:



<?php
$foo
= $bar[$example];
?>


Shortcut operators



The shortcut operators ++ and -- should always be used on a line of their own, with the exception of for loops. Failure to do this can cause obscure bugs that are incredibly difficult to track down. For example:



<?php
$foo
[$i++] = $j; // Wrong: relies on $i being incremented after the expression is evaluated
$foo[--$j] = $i; // Wrong: relies on $j being decremented before the expression is evaluated
$foo[$i] = $j;
$i++; // Correct: obvious when $i is incremented

$j--;
$foo[$j] = $i; // Correct: obvious when $j is decremented
?>



Optional shortcut constructs


As well as the useful increment and decrement shortcuts, there are two other ways in which you can make your PHP code easier to use. The first is to replace if statements where you are assigning one of two values to a variable based on a conditional. You may be tempted to write something like this:



<?php
if ( isset($_POST['username']) )
{
    
$username = $_POST['username'];
}
else
{
    
$username = '';
}

if ( isset(
$_POST['password']) )
{
    
$password = md5($_POST['password']);
}
else
{
    
$password = '';
}
?>



Whilst the above code works and makes it obvious what you are doing, it's not the easiest or clearest way if you want to run through a list of different variables and do a similar thing to all of them. A more compact way would be to use the ternary operator ? : like so:



<?php
$username
= isset($_POST['username']) ? $_POST['username'] : '';
$password = isset($_POST['password']) ? md5($_POST['password']) : '';
?>



I would recommend using the latter notation wherever you are checking assigning a number of variables one of two values depending on a boolean expression, simply because it makes the code easier to scan and also makes it obvious what you are doing without being unnecessarily verbose.


Use constants where possible


If a value is not going to change throughout the execution of your script, then use a constant rather than a variable to define it. That way, if you do change the value by accident, the PHP parser will output an error and allow you to fix the problem, without it causing any unforeseen side effects.


Remember that constants should never be enclosed in strings, either single or double. You must always use concatenation if you wish to include a constant's value in a string.


Turn on all error reporting


A lot of code I've downloaded from the web and tried to use has failed on my machines because the developers switched off the E_NOTICE flag in their PHP configuration for some reason or another. As soon as I bring it onto my system, where error reporting is set to E_ALL (i.e. show all errors, including references to variables being used without being initialised), the PHP interpreter spews out dozens of error messages which I then have to fix before I can proceed to use the script.



What you need to remember as a developer is that the person who uses your script may not have exactly the same php.ini configuration as you so you aim for the worst possible case, i.e. when some awkard person like me has all error reporting enabled. If your code works with E_ALL set, then it will also work with any other error reporting configuration, including when all error reporting is turned off (e.g. on sites where PHP errors are logged to a file instead).


It's not impossible to get scripts to work with all error reporting turned on, because I've managed it for all the code on all the sites I've ever written PHP code for. Admittedly I've not written any major projects such as a CMS, but if you write proper object oreintated code and make sure that each class doesn't produce any errors, you should be able to make your program as a whole run without errors under normal circumstances.


Of course, on a production site you might want to turn off all errors, or at least redirect them to a file, to avoid admitting to users that your scripts are broken in some way (we know that scripts can't handle every possible error, but users often don't see things this way!). That's perfectly fine and in many cases the recommended action to take. So long as your scripts work with all error reporting turned on, it doesn't matter where they are deployed.

Friday, November 27, 2009

SQL Injection: How To Prevent Security Flaws In PHP / MySQL

Foreword: SQL injection is a very scary phrase. After all, it has single-handedly been responsible for putting down major government websites and thousands of personal home pages- and everything in between. (Something that has been increasingly popular after the “Techie” generation had puberty-riddled children.) Yet believe it or not, guarding against the attack is simple as a couple of lines of code.


SQL Injection: What It Is


There was once a famous doctor that had it completely right: never trust your patients. Now this doctor may have only been a sitcom doctor on the show “House,” but we’ll be taking a page from his book. Of course, in our case the patients will actually be Internet users. Don’t let your guard down! They are conniving, dastardly, plot-making fiends- and you’ll do well to remember it.


First, Let’s define an SQL Injection:


Define SQL Injection



  SQL Injection - \S-Q-L-in-'jek-shen\ - Noun
The technique of inputting malicious data into an SQL statement, which would therefore make the vulnerability present on the database layer. Surprisingly, it seems everyone who has recently taken up learning a web development language has to try the technique out on their favorite websites. Luckily for said websites, this technique isn't at all hard to protect against.

The technique of inputting malicious data into an SQL statement, which would therefore make the vulnerability present on the database layer. Surprisingly, it seems everyone who has recently taken up learning a web development language has to try the technique out on their favorite websites. Luckily for said websites, this technique isn’t at all hard to protect against.


SQL Injection: What It Looks Like


The vast majority of all SQL injections will take place on an input form. Contrary to popular belief, this isn’t the only place where we will see them- it’s also common to manipulate URLs to inject SQL code. (But we’ll get more into that later.)


The most basic of all SQL injections will look like the following:


The Basic SQL Injection


 Variable' or 1=1--


Let’s say we have a login form. By inputting the above code, we can use our SQL injection to gain login even without proper credentials! So how’s it work? Take a look at the “bigger picture” below:


What It Looks Like On The Back-End


 SELECT * FROM users WHERE username = 'Variable' or 1=1--'

See how our code is nicely injected into the query? The result of this query will grant us access regardless of the username, since the result of “1=1″ will always be true. In this case, we bypass the whole selection process.


You may have been wondering what the double dashes are for ( — ). These dashes at the end tell the SQL server to ignore the rest of the query. If the exploit isn’t being used on an SQL server, then omitting the double dashes and ending single quote will get the desired results.


Note that while this is the most standard way, it certainly isn’t the only way that malicious users will gain entry. SQL queries will differ greatly from one syntax to another, and thus, so too should the SQL injection. It’s also common to see the following:


More SQL Injection Syntax Fun



    ') or ('1'='1
"or "1"="1
' or '1'='1
Or 1=1--
" or 1=1--
' or 1=1--

SQL Injection: Attacking Via URLs


Did you know it was possible to attack an SQL server through a URL? Well, it’s possible, and usually much more dangerous to webmasters. When using PHP and SQL, there is commonly a URL such as the following:



  • http://YourWebsite.com/login.php?id=2


By adding a little SQL to the end of the URL, we can do some very mischievous mischief:



  • http://YourWebsite.com/login.php?id=2‘; DROP TABLE login; #



You might be confused by the hash. This little guy is just like the double dash we used earlier; it will tell the SQL query to halt after our input. And if you haven’t noticed, we just told the server to drop the entire table of users! This is an example of how powerful and dangerous SQL injections can be- and also shows that constant backups are a necessity.


Enough already! Let’s finally find out how to make sure that little script kiddies aren’t going to ruin the hard work webmasters and web developers set aside for their projects.


SQL Injection Prevention: Editing Lengths Of Form Components


The first step in the process is simple: simply restrict input fields to the absolute minimum- usually anywhere from 7-12 characters is fine. Doing so will make long queries unable to be input, since the field is only enough characters for smaller queries. This will actually not prevent an SQL injection, but will make work harder for those trying to make use of one.


PHP MySQL


Savvy SQL injection users can simply make a new form and remove the limits on the character length, since the length is in plain HTML and viewable (and editable) by anyone.


SQL Injection Prevention: Data Type Validation


Another good idea is to validate any data once it is received. If a user had to input an age, make sure the input is an actual number. If it was a date, make sure the date is in proper format. Again, this will not prevent an SQL injection in itself- it just makes work harder for those trying to exploit an SQL server.


sql injection prevent



Data type validation can be thwarted by modifying the query over a trial-and-error test period. This is still only slowing attackers down- but isn’t it much more satisfying to have them waste their time before finding out one’s own query is impervious to harm? Of course! An eye for an eye!


SQL Injection Prevention: User Privileges


It’s nice to be able to create a “super user” in one’s own database that can create, drop, and edit tables at will. The security-obsessive webmaster will want to make individual users that can only do one or two tasks at a time. In effect, this means that SQL injections will only be able to do one or two things at a time.


This is just a little prevention fun, it can certainly still cause a certain amount of danger. If a user is made for deleting tables, than an SQL injection can do the same thing- it just won’t be able to do much else. Regardless, deleting a table is a very big privilege to handle. This method is still useful for throwing attackers off track, as well as minimizing risk from areas of a website that aren’t critical to the security of the database.


SQL Injection Prevention: Magic Quotes (Which Aren’t So Magical)


We all love magic. Heck, magic is downright cool. It serves as the basis for great children books (Harry Potter, anyone?) and even has been used for themes in nerdy card games everyone seems to enjoy (Ah, we’re looking at you, Magic The Gathering!)


One thing that just doesn’t live up to the magic name is magic quotes. PHP developers thought it would be a wonderful idea to make a process that escapes all incoming data in a PHP script. Sounds like it would fix our problem with SQL injections, but alas, there are better ways.


Anyone who has recommended a fix with magic quotes doesn’t know what they are talking about. After all, magic quotes are considered deprecated and removed as of PHP version 6. So why such hostility over a process that is seemingly beneficial to our predicament?


The short answer: magic quotes are horrible for portability issues, performance issues, and they mess with other data that doesn’t need to be escaped.




  1. Many scripts made with magic quotes won’t work on servers that have (intelligently) turned the feature off.

  2. Performance loss is observed because not all of the data is being input into a database- we’re wasting process time.

  3. Lastly, magic quotes are just inconvenient. They add an extra slash (”\”) to all of our form data, even when it might not be needed. To fix this, we have to use another process to fix it (If you are unfortunate enough to have used magic quotes, look up the stripslashes() function, and consider switching if possible)


We came close to finding a real solution there- almost! But we did learn something: don’t use magic quotes, and instead find an alternative that can escape the input data based on what we need: not what we don’t.


SQL Injection Prevention: The Solution In Preventing SQL Attacks


We could’ve given you the answer right away, but what fun would that have been? Too often, PHP developers are becoming lazy and not following proper security tactics the way they should. By reaching this point in the lecture, you’ve increased your knowledge on how SQL injections are used, how not to prevent the attacks, and finally: you’ll learn the right way to keep injection attacks at bay.


We’ll accomplish this last feat with a simple function that the developers of PHP made especially for SQL injections. We call this function mysql_real_escape_string() – take a look at it below:



mysql_real_escape_string() In Action!


    $name = "John";
$name = mysql_real_escape_string($name);
$SQL = "SELECT * FROM users WHERE username = '$name'";

Although for a more practical use, we would have the $name variable pointed to a POST result, as seen below:



$_POST Can Dig In On The Action Too!


    $name = mysql_real_escape_string($_POST['user']);

And we can even make things easier by putting it into one line:


All In One Line Now; Here We Go!


$SQL = "SELECT * FROM users where username = "mysql_real_escape_string($POST['user']);


So what’s the output like if malicious users try to get access to our SQL server? Well glad you asked! Their attempts may look something like this:


Cause And Effect With mysql_real_escape_string()


    $malcious_input = "' OR 1'";
// The Above Is The Malicious Input. Don't Be Scared!
// With The mysql_real_escape_string() usage, the following is obtained:


\' OR 1\'
// Notice how the slashes escape the quotes! Now users can't enter malicious data

And the best part is, they just wasted their time and effort for nothing. Now how’s that for vindication!


SQL Injection: Closing Comments



We’ve learned quite a bit today. SQL injections are bad. All Internet users are equally as bad. Protecting against both ensures a happy and stable web application. And above all else, never use magic quotes! Despite their cleverly disguised name, we’ve found no evidence of magic.


Lastly, note that there are libraries and classes that can help aid in the fight against SQL injection. Prepared statements are plausible as well, but as for us, we enjoy sticking to the mysql_real_escape_string() function for less headaches.


Bottom Line: mysql_real_escape_string() – It doesn’t have a magically awesome name, but it’s 24 characters worth of SQL injection-protection goodness.