Getting data from the user – part I

When it comes to being really useful, PHP’s greatest benefit comes when it can modify the contents of a page based on how a user interacts with it. Key to that ability is getting information from the user to reach your scripts.

There’s a couple different ways to do that. The first way is by passing information through the URL. You do this with a ? in your URL after the end of the filename, like this:

file.php?name=Joe

In your script, you can access that variable with the special super-global array $_GET, like this:

echo ‘Hello ‘ . $_GET[‘name’];

{show output}

However, it’s worth noting that this is actually a security hazard. We talk more about cross-site scripting later, but imagine some malicious hacker linked to your site like this:

<?php
echo ‘<a href=”file.php?name=’ . rawurlencode(“<script type=\”text/javascript\”>setTimeout(\”alert(‘Your PC is infected with a virus. Click here to buy some fake anti-virus software’)\”,2000);</script>”) . ‘”>click here</a>’;
?>
{show result of clicking in firefox}
By the way, for my personal browsing, I typically use Google Chrome. One of the neat things about Chrome is that it notes whenever the URL includes javascript and it won’t run that javascript fragment if it appears in the webpage. It specifically protects me from an attack like this. But firefox, another browser I sometimes use, has no such protection, which is why I’m using it here.

So, to protect your visitors, before you echo out a variable that gets sent directly from the URL, just use one of the special PHP functions like ‘htmlentities’ or ‘strip_tags’ or another similar function:

echo htmlentities($_GET[‘name’]);

{show new output}

So, moving along, to pass more variables, you string them together with the &, as in:

file.php?name=Joe&lastName=Smith

$_GET[‘name’] = htmlentities($_GET[‘name’]);
$_GET[‘lastName’] = htmlentities($_GET[‘lastName’]);
echo “Hello $_GET[name] $_GET[lastName]”;

{show output}

Whether you pass a number or a sequence of characters, doing a gettype proves that these variables are always strings. But that’s ok since anything that can be sent through a URL can be expressed as a string.

Now, this is probably a good time to talk about register_globals. In PHP 5, register_globals is turned off by default, but it’s a directive in PHP that lets variables passed through the URL become variables inside your scripts without needing to go through the $_GET super-global array. It’s turned off in PHP 5 by default in order to get people with PHP 4 scripts to take the time to update their code while still giving them a way to the code work, if they turn it on. In PHP 5.3 register_globals is officially deprecated, and in PHP 6, register_globals is gone.

However, it’s worth mentioning, so I’ve turned it on for the moment. In a later video we examine how to change the ini directives, so I won’t take the time right now to show you how I did it, but here’s the gist of it:

echo “Hello $name $lastName”;

$name and $lastName aren’t defined anywhere in my script. With register_globals, I can add any variable to the global scope just by sticking it into the URL. And since it’s on, here’s the output:

{show output}

So, that was how things were passed from the URL in PHP 4.1 and earlier, back before the superglobal arrays were added to the language. But the PHP engineers decided this made it far too easy to introduce security vulnerabilities. Take this example:

if(reallySecureLoginFunction() === true) {
$authorized = 1;
}

if($authorized == 1) {
include(‘reallySecureContent.php’);
} else {
include(‘userNotAuthorized.php’);
}

Without register_globals, there’s no way for $authorized to be set except in the case that reallySecureLoginFunction returns true. But with register_globals, all the user needs to do if he wants access is add ?authorized=1 to the end of the URL. What the PHP best practices told people to do was make sure that all variables get declared before they’re used – simply adding $authorized = 0 before the call to reallySecureLoginFunction() would have been enough to prevent this security exploit.

But novice programmers, sort of by definition, didn’t know the PHP best practices, and PHP certainly didn’t throw up any kind of error if they didn’t follow them. So, to get rid of the security hole, they turned off register_globals and told people not to turn it on, which is exactly what I’m passing on to you. Don’t turn it on. If you do, and you rely on it being on, you won’t be able to migrate your scripts to PHP 6. And it makes it really easy to accidentally make your scripts insecure.

In addition to simple string variables, I should point out that it is also possible to pass arrays from the URL. The syntax is a little different, but easy to understand, because it uses square brackets just like building a PHP array:

?file.php?names[]=Jim&names[]=Kate&fruits[red]=plum&fruits[yellow]=banana

To access these values in your script, simply treat $_GET like a 2-D array:

echo $_GET[‘names’][0] . ‘ wants a ‘ . $_GET[‘fruits’][‘red’];

Now, you wouldn’t typically expect your users to type these extra parameters into the URL the way I’m doing. Generally, you provide a link, they click it, and these parameters are automatically filled in. To help you build a link with the variables in it, PHP provides a useful function called http_build_query.

http_build_query takes an associative array as the first argument. I you want to use a numeric-indexed array, you can, you just need to provide a prefix so the function can give you valid variable names. That’s your second argument, if you decide to include it. For instance, if you have an array with 3 items that uses numeric indexes, and your prefix is ‘myvar_’ your variables will be myvar_0, myvar_1, and myvar_2. And since they don’t start with numbers, they’re legal variable names. Of course, since register_globals should be off, and you’ll be accessing them inside an array, you can also just leave them as numeric indexes, without the prefix, and access them as keys 0, 1, and 2 inside $_GET.

So, here’s an example of a simple script I’ve created.

{show output}

It gives me a choice of links, and depending on which one I click it shows a different pair of images at the top.

{click links, show changing page}

But these are all using the same PHP script. I’ll show you how it works:

{display script}

So, with nested foreach loops I go through both arrays, and create a combination for each possible image pairing based on the two sets of images, using the keys as the variables I pass through the URL when someone clicks on the link that pairing creates.

Notice the call to http_build_query has one last argument. This is what determines the variable separator. By default, it’s the &, but I’ve picked ‘&amp;’. I did that because to have valid HTML markup, the & needs to be replaced with the special HTML entity, and that’s the code &amp;.

So, that concludes the lesson on passing variables through the URL. In the next video we look at using information collected from forms.

February 14 2010 07:15 pm | Basics and PHP Programming Basics and PHP tutorial scripts

Trackback URI | Comments RSS

Leave a Reply