Alex Elliott

The internet home of a prospective software engineer

This is my personal blog where I discuss projects that I'm currently working on, work I've recently completed, or write about any topic which has caught my interest in the world of Computing from my studies or from my personal research.

My Little FAQ For PHP Pitfalls

November 6th, 2009

There are a few questions which come up time and time again in Zymic’s support channels (Zymic IRC, or the forums) and having answered them several times, I feel I would like to spend some time writing up a response which I hope can make handling these support queries a bit easier. So, ok, firstly:

PHP Notices

Since Zymic’s PHP is set to display errors of the level E_NOTICE, users often find they are getting errors on Zymic that they are not getting on their local test server or previous host.  E_NOTICE level errors are good practice recommendations that point out where you’ve written valid but improper PHP.  It is recommended that rather than suppress E_NOTICE level warnings you display them during the development process and fix your code so that the errors are never generated.  This improves the quality and reliability of your code.

If your local test server does not display notices then I would recommend you change your local PHP configuration to start generating them.  You can do this by modifying the “error_reporting” directive in your php.ini file.  In a system where notices are disabled it is typically set up as this:

error_reporting = E_ALL & ~E_NOTICE

This format takes E_ALL, a group of many error levels including notices, and then removes notices from the list by adding ~E_NOTICE (not E_NOTICE).  So you can enable E_NOTICE level errors by making it simply:

error_reporting = E_ALL

The next few topics are about some specific E_NOTICE level errors you may have found and what they mean then how to resolve them.

PHP Notice: Undefined Index or Undefined Variable

This notice refers to using a variable or a member of an array that has not been defined prior to its use.  The simplest example of this is to take this code:

1
2
3
<?php
   echo $foo; // At no point have we defined $foo, so using it is probably bad
?>

This will produce an error along the lines of “PHP Notice: Undefined variable: foo in __FILE__ on __LINE__”. This is obviously a very trivial example and it rarely comes that simple in real code, but it is an illustration of what triggers this error. Attempting to reference some data that doesn’t exist can easily lead to unexpected behaviour, and it’s fairly obvious that all variables/array members you try to read from should be defined and initialised before you try that read.

A common context where “Undefined Index” will turn up is in people handling the superglobals like $_POST. If you attempt to use $_POST['foo'] without checking some input with the name “foo” has been posted to the script will trigger this notice. So, that’s what the notice is and what causes it, but how can you prevent it from appearing? Well, there are some tests that PHP has which can check the data, and then you can make sure that you’re only attempting to read the data if the variable/array member is set or is not empty. So say you want something that outputs “Hello, {name}” to the browser and it works on GET data, an implementation which will trigger this notice might be:

1
2
3
<?php
   echo 'Hello, ', htmlspecialchars($_GET['name'], ENT_QUOTES);
?>

But this script doesn’t work particularly well when a name isn’t provided, you will get a notice and the output will just be “Hello, “, which is not particularly meaningful – we can do better than that. So if we add in a check using PHP’s empty() function to see if there is some data provided we could instead write:

1
2
3
4
5
6
7
<?php
   echo 'Hello, ';
   if(empty($_GET['name']))
      echo 'Stranger';
   else
      echo htmlspecialchars($_GET['name'], ENT_QUOTES);
?>

This is very similar to the last, but it will not trigger a notice if there is no name provided to the script, and in fact handles it by instead outputting “Hello, Stranger” if no name is provided. This is a bit more elegant, and there are many ways you could tackle this. You could have the case where if no input is provided we show a form instead for the user to provide a name.

PHP Notice: Use of undefined constant

This one is very much similar to the last one, but is worth mentioning separately because there’s enough to be said about the mistakes that lead to it, and how you can make these mistakes and not realise it without the benefit of notices. This notice is about the use of undefined constants in code, the interesting thing is how PHP handles a case where an undefined constant is found. It will trigger this notice, but since this is valid PHP it will take a value for the constant for the script to use, and that is the identifier (or name) of the constant, thus an undefined constant foo will evaluate to the string ‘foo’.

Because of this fact you often see cases where an array member is referenced via $array[foo] rather than $array['foo']. If notices are disabled, then it is possible that the author of that code will not notice the mistake (though syntax highlighting in your editor should mitigate this somewhat) because while foo is an undefined constant the two are equivalent. However, this is not always the case. An easy example to demonstrate this is this. Take file1.php to be this:

1
2
3
4
5
<?php
   $array = array( 'foo' => 'Hello there', 'bar' => 'Goodbye');
   echo $array[foo]; // Note here we've not quoted foo so it's a constant,
                     // and in the context of just this script it's undefined.
?>

When you visit this page you will find it triggers this notice and outputs “Hello there”, however if we were to also have a file2.php containing this:

1
2
3
4
5
<?php
   define('foo','bar'); // define the constant foo with the value "bar"
   require 'file1.php'; // and then bring in the file we just wrote,
                        // with this constant in scope
?>

When you visit file2.php you’ll find the notice has gone and we’re now presented with “Goodbye”, this is the crux of the issue, when you unintentionally use an undefined constant you no longer have any idea how that script will run when it is part of a larger program. What it will actually do is now undefined behaviour. So, if what you mean to write is a string, make sure it has quotes around it, so the PHP parser knows that it’s a string – not a constant.

That’s it… for now

I may add to this at a later date to add in anything else that gets asked frequently, we shall see.

Leave a Reply