Today I want to talk about best practices in regards to reading user input. And if you haven't already, I'm going to convince you why using PHP's superglobal arrays are bad.

Best Practice: Cast to what you want

The first part of this post is all about how important casting incoming data is. As you know, security rule number one is never trust the user. So if you are expecting an Article ID which is an integer, you should make sure that you actually got an integer.

The most common approch is to cast user input when you get it. So if an attacker tries to supply some arbitrary string, PHP will cast it to an integer which usually results in a harmless 0. Sure, you have precautions in place against SQL injection or XSS but by casting data to a specific type, you can greatly simplify code because you can start working under assumptions ("I know for sure that $id is a harmless integer").

Here are a few examples:

  1. // ID's (the use of max to get rid of negatives; Usually ID's are unsigned)
  2. $article_id = max(0, (int)$_GET['id']);
  3.  
  4. // Simple strings
  5. $username = preg_replace('#^[a-zA-Z0-9\-_\.]$#', '', $_GET['show_user']);
  6.  
  7. // Booleans
  8. $show_drafts = (bool)$_GET['show_drafts'];

Note that this isn't really about form validation. If someone is filling out a form, you still need to make sure what they input is valid. For example, the "Simple strings" snippet above is useless to users when they're registering because you're not telling them that their input is invalid.

These strict casts are useful only when you don't expect users to fiddle with values. So things like view.php?id=34 where the URL is generated by your app, or <select> values where the user shouldn't change values etc.

Getting rid of the superglobals

Well, sort of. We obviously can't completely stop using $_GET/$_POST/$_COOKIE for reading incoming data because there's no replacement. What I'm talking about is ridding your code of these superglobals -- pushing them into a special input class. A code snippet is worth a thousand words; here's what I'm talking about:

  1. // Bad
  2. $article_id = $_GET['id'];
  3.  
  4. // Better
  5. $article_id = $input->get('id');

Why

The above snippet doesn't really show off anything other than the concept. So let's talk about what this mysterious input class is meant to do, and why it's better than using superglobals.

Control

You don't have much control over superglobals. They are simply arrays. You can't do anything special before trying to fetch values. You might be thinking about what kind of processing you would want to do. But think about this for a moment.

How many times have you done something like this:

  1. $article_id = (int)$_GET['id'];
  2.  
  3. // Or
  4. if (isset($_GET['id']) {
  5.     $article_id = (int)$_GET['id'];
  6. }

Since you control the input class, you can add a bunch of features to make gathering and casting input really easy.

  1. $article_id = $input->getInt('id');
  2. $search_user = $input->getSimpleString('search_user');
  3. $delete_ids = $input->getArrayOfInts('delete_ids');
  4. $article_content = $input->getString('content');

UTF-8 Handling

One place where this sort of functionality is really useful is when you've switched to using UTF-8. As you know, it is possible for UTF-8 strings to be malformed -- and this is a security risk. So every time you read strings you must make sure they're valid. Without an input class, this would be a lot of work. With an input class, you can just modify your 'getString' method to add UTF-8 checking.

Stripping magic quotes

Another common task PHP programmers routinely need to do is handle magic quotes. Most of us simply test to see if magic quotes is enabled, and run the entire superglobal array family through a function that strips the slashes -- basically undoing this devil-feature.

But by doing this, you're affecting the entire app (because, well, you're modifying a superglobal of course!). This might not matter to you, but it gets a bit dangerous if you use third-party libraries.

A friend of mine creates Facebook applications. The Facebook PHP library is clever enough to test for magic quotes and strips slashes out for values it needs. But what if you're a clever PHP programmer, and you stripped out the slashes as part of your "global.php" file? FB doesn't know that, so it just strips them again! This is an example of how modifying global data is a bad idea.

By moving input-reading into your own class, you can do whatever the hell you want to your data and can rest assured knowing you didn't affect anything else.

Abstraction

By creating this new class, you abstract the details of how input is gathered. You might be wondering why this is important -- isn't there just get/post/cookie? No! While the vast majority of your webpages will only use these types of input, there are certainly others. Here are two that jump to my mind.

Command-Line

If you make command-line scripts, getting arguments may be a perfect use for your input class.

Friendly-URL's

$_GET only works for values encoded in the query string. But if you are a creating an app with friendly URL's, values are sometimes embedded right into the URL.

For example: /article/42/edit

This URL might mean to "edit" the article with ID of "42". Most frameworks, like Zend Framework's MVC components, make creating URL's like these very easy. In ZF, you define a route with placeholders of the values:

  1. $router->addRoute('article_action', new Zend_Controller_Router_Route(
  2.     'article/:article_id/:action',
  3.     array('controller' => 'article', 'action' => 'view')
  4. ));

The framework provides a way to get the value of 'article_id' and 'action' that you could plug right into your input class. It might look something like this:

  1. $article_id = $input->getIntFromUrl('article_id');
  2. $action = $input->getStringFromUrl('action');

Building an input class

Building your own input class is an excersice you can complete yourself. But I'll get you started.

First of all, what is our goal?

  • Ability to clean data
  • Ability to get data from multiple sources

I think a well-designed system calls for a handful of classes:

  • Cleaner takes values and cleans/casts them to a correct data type. We're using a separate class because it's not directly tied to input -- we might reuse this functionality elsewhere.
  • InputSource_* are classes that read raw data from some source. We have one reader for each source. For example, InputSource_Array for reading information from an array (like supergloabls) or InputReader_Url for reading information from a friendly URL.
  • InputReader is the main class that ties the Cleaner and the InputSource_* classes together.

Here's how it might work:

  1. $cleaner = new Cleaner();
  2. $input = new InputReader($cleaner);
  3. $input->addSource('req', new InputSource_Array($_REQUEST));
  4. $input->addSource('get', new InputSource_Array($_GET));
  5. $input->addSource('post', new InputSource_Array($_POST));
  6. $input->addSource('cookie', new InputSource_Array($_COOKIE));
  7. $input->setDefaultSource('req');
  8.  
  9. $input->getInt('id'); // Get from the 'req' source, a default
  10. $input->getInt('id', 'get'); // Get from 'get' source
  11.  
  12. // $input->getInt() calls a corresponding $cleaner method to
  13. // clean an integer.

12 Responses to “Stop using superglobals!”

  1. Floris Fiedeldij Dop Says:

    Very good read, and I even learned something! I will try to master this and apply it upcoming code. Thanks for writing this all out.

  2. OriginalCopy Says:

    You're right in the aticle, great blog, keep up the quality!

    I have one complaint though. The comments form's inputs should have a color:black when active, as some of us are really using black themes at the OS level :D

  3. Why PHP’s $_REQUEST is dangerous - Devlog Says:

    [...] finally, best practice is to abstract your input reading out (see Stop using superglobals!) so you can define yourself exactly how variables are read and from where. Posted by [...]

  4. Ka Canclini Says:

    This is a good piece of writing, I was wondering if I could use this post on my website, I will link it back to your website though. If this is a problem please let me know and I will take it down right away.

  5. Richard Clifford Says:

    Thanks for this article! Helped quite a lot actually. I try not to use superglobals. And this just confirmed my suspicions! Thanks!

  6. mario Says:

    Maybe you're interested in object-oriented superglobals with filtering built-in:
    http://sourceforge.net/p/php7framework/wiki/input/
    Overriding $_GET and $_POST has surprisingly few side-effects and allows making legacy code safer from a central configuration.

  7. egg cup Says:

    Several thanks for taking the time and energy to publish some thing that's invoking

  8. Rafaela Miriello Says:

    Like a Beginner, I'm often looking on the internet for articles that will help me. Thank you

  9. Ryan Says:

    I find it's better to keep input that comes from an input array, such as forms, grouped together in an array:

    class Input {
    public function getInt($key) {
    if (isset($_POST[$key])) {
    return (int)$_POST[$key];
    }
    if (isset($_GET[$key])) {
    return (int)$_GET[$key];
    }
    }

    $input = new Input();
    $form['foo'] = $input->getInt('foo');

    now when I see $form['foo'] in my code, I know it came from a form, and not a variable called $foo that could have been generated some other way.

  10. 小叫花 Says:

    This is a parameter filter it.
    perhaps,it's great! ^o^

  11. navtkuicvkou Says:

    It is needed that your Uggs fit snugly, without too taut when they may hurt that person. You should also experience the weight of the uggs for cheap about equally right in front and back; and that is, on your ears as well bridge of this nose. Obtaining them using a website most likely are not your best choice mainly because the Ugg boots perhaps may not fit. You'll find adjustable frames that one could purchase, but more times just did nothing, each website will advise you what size is likely to fit you best. An exchange program have got to be offered, however it order Ugg boot that do not fit. There's quite a few things to consider when selecting Ugg boots. The best way to protect up your eyes is to ensure the Uggs you purchase are going to protect you from glare and UV radiation. It also be aware of get them polarized to enable you to wear them outside and inside as well. We do hope you have a good selling with uggs for sale.
    In acquiring the right uggs for cheap , it's essential to evaluate if you desire a software or hardware based uggs cheap . A hardware north face sale is really a separate device that protects your laptop externaly threats. Defense against incoming threats is considered the thing until this particular somewhat like uggs cheap can work. It won't combat ongoing threats in relation to your hard disk. Someone had the ability to hijack your laptop for yourself out attacks with computers, which happens to be something this gadget cannot help you out evade.
    Women want north face sale sale because the north face sale can remember to keep your foot out of the cool in winter. Obtain a report on cheap uggs outlet now.This post is nearly some of the best uggs cheap products in 2012, and to have an individual to protect your laptop while your files secure. Which will be extremely important undertake a the north face sale , there are masses of choices, and the type is better might be challenging to discover. Sometimes you can buy all you have in free versions, therefore, you must evaluate those that desire the advanced version, that you've to pay for. Before you purchase a the north face sale product, make sure that every issue you will be concerned with, can be covered.

    References:
    ugg boots canada,cheap ugg boots,uggs canada
    ugg canada,uggs cheap,ugg canada
    cheap ugg boots,cheap ugg boots,ugg canada

    8bb5f029614692f0e210461aed5edd78

  12. wsowyiqwagup Says:

    In order to individual some uggs cheap , it is very important keep inside a specific budget that could be economical. Your not qualified attention will most definitely struggle to observe the difference between high-priced and furthermore low-priced uggs for cheap , regardless of this many distinctions may very well be excellent. A lot connected with ultraviolet to protect your eyes most likely are not inside more inexpensive sunglass designs. Your custom label through the north face outlet online is obviously section of the sticker price. Overlook creating statements of favor out on the town wonderful tools to handle individual some low-cost uggs cheap ; will possibly not have even Ultraviolet security within them! Consider the most important thing for your situation though costs uggs for cheap online . Nonetheless, it is also essential to be sure the particular Ultraviolet security has been from the contact lens, something which the label can give you advice on.
    UGG boots are th symbol of manner and charming should ten throughout the past.ugg outlet have distinctive styles that could mak you look fashionable along wit keeping you comfortable Individuals will regard you since vogue gals as you put on UGG trainers. Because the large superior and wonderful overall loo, almost each younger looking women need pair of style north face outlet . Dress yourself in UGG athletic shoes, vogue is simply not critical, warm and comfy have to be the first you'll have the ability t feel. Presently you can consider UGG boots for example that they don't ever halt what to adhere to the design and style structure.
    Being wind proof north face outlet online which includes ample stretch, it gives your glove superb dexterity.

    References:
    uggs cheap,uggs cheap,cheap ugg boots
    ugg boots cheap,ugg boots canada,ugg boots canada
    cheap ugg boots,ugg boots cheap,uggs cheap

    8bb5f029614692f0e210461aed5edd78

Leave a Reply