Etienne Kneuss

Insane

I'm currently working on a scala compiler plugin that performs interprocedural, compositional effect and pointer analysis on arbitrary scala programs!

Feel free to check out Insane on github!

Phantm

In short, Phantm is a type checker for PHP applications, but it does also much more!

PHP

I sporadically contributes to the core of PHP for quite a while now, see my patch repository.

Introduction

This little guide can be used as a checklist to correctly debug your PHP userland errors. It covers the main principles and methods to:

  • Detect your errors
  • Find the reason in the code

G1: Expose errors

Before even thinking about debugging, you need to know that an error occured. To tell PHP to report errors accordingly, there is three important ini settings:

  • error_reporting : defines the types of error that PHP will report(or ignore). You should set this one to E_ALL atleast. Using E_ALL | E_STRICT is even prefered. However, it might report errors you can't do anything about, the most common case is PHP5 scripts that tend to be backward compatible.
  • display_errors : makes PHP display the errors along with the output. You should disable this setting on production environment to reduce disclosure.
  • log_errors : tells whether the errors are logged to the error_log. That's an useful alternative to display_errors on production environments.

As This guide is about debugging your code, the easiest way to catch errors is to set error_reporting to E_ALL | E_STRICT, and display_errors to ON.

There are multiple ways to apply these ini settings:

  • At the top of your script, in runtime, using :

    ini_set('display_errors', true); error_reporting(E_ALL | E_STRICT); // Be aware that setting E_STRICT at runtime may hide some errors, because most of E_STRICT errors are issued at compile-time.

  • In a .htaccess file, placed in the main directory of your project to debug(Assuming PHP runs as an apache module and that you've enough rights to overwrite such settings)

    php_flag display_errors on php_value error_reporting 4095

  • In your php.ini

G2: Read the error message

Each error message contains a lot of information. Sadly, they're not often read completely.

Each error is usually issued using the following format: PHP : in line

This guide will cover the main types of errors that occur, and explain a way to track them.

E1: Syntax error, unexpected "..."

Such syntax errors are easy to understand, the grammar of your file is incorrect. Check the line given for errors, if you can't find any, the error may be on the line before. For example, you could have forgotten to close the first string:

echo "mystring;
$foo = true;
$bar = false;
echo "foobar"; // <-- Unexpected T_STRING at this line, however, the error is caused by the first line.

By using a decent editor that supports syntax highlighting, you'll be able to spot such errors easily. PHP may even tell you what it expected instead, so read the error carefully! There is also this common syntax error: "Unexpected $end"

This syntax error is pretty explicit, PHP's parser wasn't expecting to hit the end of the file in this context. For such errors, the line reported is pretty useless, as it will point to the end of your file. How to find the problem then ? Simple: such errors occur when there is a brace mismatch. So you need to check that every time you open a PHP block using "{", you're closing it correctly.

function hello() {
    echo 'Hello world';
    return true;

// ...

// <-- Unexpected $end at the last line of the file, the problem is that you forgot to close the function.

E2: mysql_*(): supplied argument is not a valid MySQL result resource

This error is so common it can't be ignored.

The following code is most likely to issue such errors:

$myResource = mysql_query($sqlQuery, $link);

while($row = mysql_fetch_assoc($myResource)) {
    // ...
}

"Hu? Why? I copied the code from the manual!?". Here is an explanation:

When you're using a SELECT mysql query, for example, mysql_query should return a result resource. However, if the query fails, mysql_query will return false, which is not a resource. mysql_fetch_* won't be able to fetch something from it and will issue the warning.

Here is a code that checks the {{$resource}} before trying to fetch:

$myResource = mysql_query($sqlQuery, $link);

if (!$myResource) {
    // An error occured, you can check mysql_error() for further details about the mysql error
} else {
    while($row = mysql_fetch_assoc($myResource)) {
        // ...
    }
}

E3: Script malfunction

"It doesn't work, but there is no errors, why?". Well, try to find it by yourself first:

PHP offers wonderful tools to check the content of your variables, their type, which is an important part of the debugging process. The concept of debugging is to track errors to their source, here is a debugging process example.

$level = 08;
$start = 01;

// ...

if($level > $start) {
    echo 'You are not at the start of the game';
} else {
    echo 'You are at the beginning of the game';
}

I can already imagine a comment looking like "Ehy, 8 > 1, but it doesn't work, it always says I'm at the beginning of the game!". So? Let's start debugging:

  • What is the conditionnal test, is it accurate ? Yes
  • What is the content of the vars? $level or $start may not be what I believe they are. So I'll check their content, var_dump is really useful for such tasks:

    // ... var_dump($level, $start); if($level > $start) { // ...

  • Wow, $level is 0 ? Why is that. Let's check every affectations of that var.

  • There is only one: $level = 08; What's wrong with that?
  • Ah, any int preceeded by 0 is considered as octal. For that reason, 08 makes no sense.
  • Let's change it to $level = 8. Everything works.

Here is an example of a debugging session, the details are not important. What matters is the process:

  • Find where the unexpected result is in the code.
  • Go backward and check each conditionnal tests.
  • Check the content of used variables.
  • Unexpected content ? Track down every affectation of the var (take care to check modifications done to references as well)

When you've to deal with external content (forms, get arguments, files) it's always a good idea to check their content (var_dump($_GET, $_POST) etc..) before blaming the PHP part.

Conclusions

Of course, only the basics are covered by this guide. However, my experience of PHP help channels on IRC shows that most of the begginers don't know the main principles of debugging when encountering an error, so I hope it helps.

Trip to norway

Sat, 18 November 2006

I made a trip to Norway last summer with a friend: pretty amazing land.

We took some pictures using cheap and broken cameras. However, some of them are decent, and I created a slideshow on flickr:

[http://www.colder.ch/norway http://www.colder.ch/norway]

Introduction

This little guide will cover some of the basic mistakes often seen on IRC. It should enlight people about some basic guidelines required to provide a clean and portable code.

G1: Quote your array indexes

Beginners often forget to quote their indexes when filling an array. Like any other string, you need to quote them. Even if PHP is kind enough to guess what your mistake was, it won't always result in what you expected.

<?php
$array[key1] = 'foo'; // BAD example
$array['key1'] = 'foo'; // Good example
?>

Of course, the first example is perfectly correct if key1 is a defined constant.

G2: Don't quote single variables

I always wanted to know why the beginners use to quote a single variable. Anyway, there is often no point in quoting single variables. You should in fact avoid doing so.

<?php
$name = 'John':
echo "$name"; // The quotes are useless
?>

G3: Always use long open tags

For portability reasons, you should always use long open tags () in your script. Other tags can be removed by setting the configuration directive short_open_tag to 0. So, to have your script as portable as possible, you should take the habit to use to enclose your PHP code.

G4: Do not rely on register_globals

register_globals is a magic feature that will inject your script with variables. For example, if the user request your php page using http://yoursite/page.php?age=18 the following code will work if register_globals is enabled:

<?php
echo 'Hi, you must be '.intval($age).' years old';
?>

However, this setting could expose a script to security problems and, for portability reasons again, your script should not rely on it. You should instead use superglobal arrays ($_GET, $_POST, $_REQUEST, $_COOKIE) to access such content:

G5: Do not rely on magic_quotes_gpc

The magic_quotes_gpc configuration directive was introduced as a security protection against SQL injection. This setting is thus most likely on. However, your script could be used on a server that doesn't have it enabled, and would thus be exposed to major security problems. First, you need to reverse the effects on such settings, here is a nice way doing it:

<?php
function clean (&$item, $key) {
    $item = stripslashes($item);
}
if (get_magic_quotes_gpc()) {
    array_walk_recursive($_GET,     'clean');
    array_walk_recursive($_POST,    'clean');
    array_walk_recursive($_REQUEST, 'clean');
    array_walk_recursive($_COOKIE,  'clean');
}
?>

Note that this code won't affect magic_quotes_gpc's effect on keys as it's often not a problem. You should then use a proper way of escaping/filtering on ALL your tainted data used in a SQL query. Here is some propositions: Use the function intval() on variables that are meant to be integers (id, age, year, ...) Use the correct escaping function on text values, for example mysql_real_escape_string() MySQL based queries. This should save you of lot of troubles.

G6: Enable error reporting

One of the most important thing is to completely enable error_reporting in the development environment by setting error_reporting to E_ALL (including E_STRICT would be even better). You will then be able to detect your mistakes, like an unquoted array index, an undefined variable, etc... so you can fix them and not just hide them!

G7: Indent your code properly

Code readability is quite important, especially if you need to track a bug. The first step to have a readable code is to indent your code properly. A standard is to use 4 spaces instead of a tabulation.

<?php
// Unreadable code
if ($var == true) {
if ($var2 == false) {
switch($var3) {
        case 3:
echo 3;
    break;
default:
    echo 5;
}
echo 'foo';
    }
    echo 'bar';
        }
?>

The readability of this code can be amazingly improved by indenting your code correctly. You'll also decrease the odds to come across a parse error caused by a bracket mismatch:

<?php
// This is much better
if ($var == true) {
    if ($var2 == false) {
        switch($var3) {
            case 3:
                echo 3;
                break;
            default:
                echo 5;
        }
        echo 'foo';
    }
    echo 'bar';
}
?>

Introduction

When building a website, security is an important point which is, sadly, often forgotten. In this article, I'll talk about one security hole called XSS with magic_quotes_gpc. It consists, in website context, of injecting arbitrary html code into a trusted website. The attack is normally targeted towards the client-side. The exploit is used to steal client-side informations like cookies. PHP has tryed to protect novices users against this kind of injection holes by introducing a "magic" feature : magic_quotes_gpc. This feature will automatically escape single and double quotes in untrusted inherited data: GET, POST and COOKIE variables. Escaping quotes is a way to prevent injections, because the attaker can't leave a quoted string:

// get untrusted data (magic_quotes_gpc is on)

$variable = $_GET['variable'];

// use it in an output

echo '<img src="', $variable, '" />';

// if the quotes contained in $variable are escaped, it
//   makes it impossible to leave the src=".." . The
//   result would look like:
// <img src="foo\"bar" />

But, magic_quotes_gpc is not enough, there is still a way to steal passwords is many situations using a trick I've though about.

Idea

Let's take an example : an image gallery community.

  • The script that displays each images get the image url by GET variables.
  • No checks are made to test the validity of the url.
  • magic_quotes_gpc is on.

The code would be similar to the first example:

// get untrusted data (magic_quotes_gpc is on)
$image_url = $_GET['image_url'];

// display the image
echo 'The image you requested : <br />';
echo '<img src="', $image_url, '" alt="some nice image" width="400" height="400" />';

In this case, there is no way to inject an efficient javascript that could request and send the cookie, so we will use a trick.

Let's use the url of a php image requesting http authentication : it will pop up an authentication box requesting a re-login for example. The basic inexperienced user would fill it with his community login and try it. The PHP image will recieve the information and just have to store it.

Note that this kind of trick will work on every injections that will modify client requests to get the complete page: images, frames, css file, ...

Conclusion

As you can see, magic_quotes_gpc does not protect your website against malicious injections that can lead to login theft. There is no "magic" solution when talking security and PHP provides a lot of functions that make your tests easier so use them!

Catching mysql errors

When you work with mysql_* functions, they may return any kind of errors. Those errors won't be printed directly. To display them, you'll have to use the mysql_error() function.

The most common example of its use is :

// ...
$resource = mysql_query('SELECT ....') OR die(mysql_error());
// ...

Explanation

This is a boolean expression which can be written

($resource = mysql_query('SELECT ....')) OR (die(mysql_error()));

You've to know that an assignation will return the value assigned, so in this case ($resource = mysql_query('SELECT ....')) will return the value returned by mysql_query('SELECT ....').

After a quick look into the manual page about mysql_query(), you can see that there are only three things mysql_query can return:

  • when everything works: a resource or true
  • when an error occurs: false

Notice that a ressource even "empty" is evaluated as true in a boolean expression.

We will focus on the case when mysql_query() returns false (error occured) because we want to catch the errors.

An important thing to know is that in boolean expressions, the part after an "OR" won't be executed if the first part is evaluated as true.

false OR print 'hello world'; // 'hello world' is outputted

true OR print 'hello world'; // won't output anything

Now, you can see that the die(mysql_error()) printing the error will be executed only if the first part, the value returned by mysql_query(...), is evaluated as false which means an error occured.

That was an explanation for the short syntax, but notice that this syntax produces the same result and could be easier to understand:

// ...
$resource = mysql_query('SELECT ...');
if ($resource === false) {
    die(mysql_error());
}

ps: the "OR" boolean operator should be replaced by "||" and the "AND" by "&&" for a matter of precedence. I used the textual version to make it more clear.

while ($row = mysql_fetch_...)

First of all, a resource is NOT an array, so using functions like foreach() or count() on it is simply useless.

A resource is something that contains the selected data. The only way to look into it is using the mysql_* functions.

The most common example of fetching multiple rows from a resource is :

// ...
$resource = mysql_query('SELECT...') or die(mysql_error());

while ($row = mysql_fetch_assoc($resource)) {
    // ...
}
// ...

This code is often used but not always understood by novices.

Explanation

You've to know that a ressource contains a data pointer. You can make the analogy:

  • ressource -> file with multiple lines (rows)
  • data pointer -> number of the line to read

This pointer will be moved by the mysql_fetch_* functions after getting the row.

$row1 = mysql_fetch_assoc($resource); // returns one row
$row2 = mysql_fetch_assoc($resource); // returns the next row

At the end of the ressource, when there is no more row after the pointer, the mysql_fetch_* functions will return false.

We have seen that an assignation returns the value assigned, and its known that the while loop will be stopped when the condition is evaluated false, so the while loop will stop at the end of the resource.