I've been furious all afternoon. I FTP into the free server where my final project is hosted, upload the PHP files that were working perfectly at home, go to the browser and... nothing. Forms don't send data, sessions have vanished, and variables are empty. After hours of tearing my hair out and reviewing the code line by line, I log into the PHP forum and find out the joke: the hosting provider upgraded to PHP 4.2.0, and the register_globals directive is now turned off by default.
If you've been programming in PHP for the last few years, this is a bucket of cold water. They've changed the rules of the game midway through the match, and all of us who learned to build dynamic websites by reading tutorials on the internet now have a pile of broken code.
The end of magic in PHP
Until now, PHP had a feature that made it incredibly easy for those of us just starting to mess around with the web. If a user filled out an HTML form with a field named nombre, when that form reached your PHP script, you magically had a $nombre variable ready to use. The same thing happened with URL parameters (?id=5 created the $id variable) and with sessions.
It was fast, it was convenient, and, as we all just discovered the hard way, it was a colossal security hole.
Think about this: if you had a script that checked a password and then set $autorizado = true;, anyone could bypass your security simply by appending ?autorizado=1 to their browser's address bar. Since register_globals was enabled, PHP grabbed that URL parameter and overwrote your internal variable. A disaster.
In the end, you realize that leaving so much control to the machine or the user always ends badly.
The new paradigm: Welcome to superglobal arrays
With the arrival of PHP 4.1.0, they introduced "superglobal" arrays, and as of version 4.2.0 (which is the one that just ruined my Saturday), we are forced to rely on them.
The code we used to write so cheerfully like this:
<?php
// Vulnerable old-school code
if ($usuario == "admin" && $password == "1234") {
$logueado = true;
}
if ($logueado) {
echo "Welcome to the secret zone, " . $nombre;
}
?>
Now fails because $usuario, $password, and $nombre simply do not exist if you don't declare them. We have to explicitly fetch where that data comes from using $_POST, $_GET, $_SESSION, or $_COOKIE.
The correct and secure code right now looks like this:
<?php
// The new way of working
$usuario = $_POST['usuario'];
$password = $_POST['password'];
$logueado = false; // Always initialize variables
if ($usuario == "admin" && $password == "1234") {
$logueado = true;
}
if ($logueado) {
// Always escaping HTML just in case
echo "Welcome to the secret zone, " . htmlentities($_POST['nombre']);
}
?>
Time to roll up our sleeves and rewrite
The transition hurts, I won't deny it. I had to open UltraEdit and go through dozens of files looking for loose variables to wrap them in $_POST[].
Some on the forums recommend going into php.ini or using an .htaccess file and setting php_flag register_globals on so everything works like before and you can forget about the problem. I advise you not to do that. If the PHP developers made such a radical decision that breaks thousands of websites worldwide, it's because the security issue was unsustainable.
Sooner or later, every shared hosting server is going to have this directive turned off for security reasons. The sooner we get used to writing slightly more verbose but much more secure code, the fewer headaches we'll have when publishing our projects online. Time to write code and do things right from the start.