PHP Gotchas: Part 1

    Harry Fuecks
    Harry Fuecks
    Share

    PHP is a remarkably easy language to get started with but from there, if my own experience is anything to go by, developers seem to experience a “rollercoaster ride” in terms of productivity. Some people refer to PHP as the “Visual Basic of Open Source”, which is both a complaint and a complement. A quote attributed to Bjarne Stroustrup (designer of C++); “There are only two kinds of programming languages: those people always ***** about and those nobody uses.”…

    Over the next few weeks (perhaps months) will be attempting to highlight PHP “gotchas”; things that lead to developer slow-down and *****ing, when working with PHP. In other words the types of problem which aren’t obvious up front and only become clear once you’ve “been there”. Some will be purely technical issues (PHP configuration, legacy headaches etc.) while others will be more theoretical (what “works” and what doesn’t in terms of code design).

    The purpose is signpost “gotchas” to developers getting started with PHP and, hopefully, prevent frustration before it happens. Will be based primarily on my own experiences, after almost five years of PHP, as well as things I’ve seen on Sitepoint’s PHP forums. Further input / insight much appreciated, as are requests for subjects.

    PHP Environment and Portability Gotchas

    Kicking off, these are some of the common php.ini related gotchas. When talking about “portability” here, I’m referring to running code under different PHP installations, as opposed to operating system portability or backwards compatibility with older PHP versions, both of which need examining seperately.

    Some of these are already covered here so excuse me re-iterating; think it’s worth attempting to put together a complete list as I see some of these problems over and over again, looking at Open Source PHP projects.

    The basic misconception seems to be the assumption that all PHP installations are equal; code that runs under one should run fine under all. While that’s largely true, some key PHP configuration settings and legacy issues conspire to make headaches. It is possible to write code that runs fine under any PHP installation (assuming comparable PHP versions) but a care is needed.

    Controlling Runtime Configuration

    First up, you need to know how to change PHP’s runtime configuration (runtime as opposed to compile time configuration when PHP is built and installed).

    There are, essentially, four basic mechanisms to control PHP’s runtime configuration; the php.ini file, Apaches httpd.conf file (or similar, such as the Windows registry), using Apache .htaccess files or within the scripts themselves using functions like ini_set(). It’s worth reading the manual on Runtime Configuration as well as browsing the core directives and the more or less complete reference found under ini_set(). Further notes can be found commented in the php.ini file itself.

    The key point to note here is on a shared web server (your typical PHP host) users will only be to changes settings via the scripts themselves and possibly using .htaccess files (few hosts will let users change php.ini or httpd.conf). Changing settings with a .htaccess requires Apache configured to provide users the “AllowOverride Options” or “AllowOverride All” privileges (normally placed in httpd.conf under descriptions) – this is fairly common but cannot be 100% relied upon.

    The mechanism by which a runtime configuration setting can be changed depends on the setting itself. Looking at the list found under ini_set(), you’ll notice values in the “Changeable” column like PHP_INI_PERDIR and PHP_INI_SYSTEM. These are actually constants defined as follows;

    PHP_INI_USER: the configuration option can be change inside a PHP script (in fact you’ll never see this listed – it falls under PHP_INI_ALL below).

    PHP_INI_PERDIR: the setting can be changed in php.ini, httpd.conf or a .htaccess file.

    PHP_INI_SYSTEM: the setting can only be changed in php.ini or httpd.conf.

    PHP_INI_ALL: the setting can be changed by all available mechanisms, include a users script.

    In other words, for portability, avoid writing code that relies on PHP_INI_SYSTEM and be aware that PHP_INI_PERDIR may be a problem for some users.

    Apache Directives

    The are two Apache directives, which can be used in httpd.conf and .htaccess files, available for changing configuration settings, namely php_value for settings which have string values and php_flag for settings which have boolean (0 or 1 in fact) values. An example .htaccess file containing one of both;

    # Switch off register_globals php_flag "register_globals" 0 # Set the include_path - Unix! See below... php_value "include_path" ".:/usr/local/lib/php"

    Place this in some directory on your server and place a PHP script containing;

    You should see that the local values for these settings have been changed (the global values are those set in php.ini or httpd.conf).

    Note for sysadmins – there are also two more directives, php_admin_value and php_admin_flag described here.

    Script Configuration

    To change configuration settings within a PHP script, the main functions are ini_set() to change a configuration value, ini_get() to get the current local value of a configuration setting, get_cfg_var() to get the global value from php.ini, ini_get_all() for a giant array of all settings, containing both local and global values and ini_restore() to revert a local option to it’s global value (overriding .htaccess files as well). Other functions, such as set_include_path() act as aliases for a specific configuration option, but pay close attention to the PHP version information in the manual, when using these.

    An example to append a value to the include path, from within a PHP script;

    The problem with short_open_tag is the PHP interpreter will be confused by XML tags (plus anyone with it switched off will see the tags as HTML) e.g.;

    $xml_body = file_get_contents('nodeclaration.xml'); ?> =$xml_body?>

    PHP will trip on the XML declaration, thinking it’s PHP. The short_open_tag setting is, sadly, PHP_INI_PERDIR so there’s no way to modify it inside a script (which would be nice to have, IMO but, no doubt, tricky to implement).

    Register Globals: Off

    Hopefully you’ve realised that having register_globals switched on is generally bad news for security, as explained here. Will do security “gotchas” another time.

    From the point of view of portability, code written with register_globals switched off should run with register_globals switched on (but may not be secure!) – the same probably won’t work in reverse.

    Cutting a long story short, switch of register_globals!

    Call Time Reference Passing: Off

    References in PHP4 are a tricky subject that you’ll find more on here and probably need their own “gotchas” discussion.

    For portability, switch off allow_call_time_pass_reference. This refers to code like;

    Switching allow_call_time_pass_reference off will result in PHP warning errors being generated if you attempt to use it. Once you understand how references work, there’s no need to do this anyway and it can make code extremely hard to follow.

    Magic Quotes

    Magic quotes are a tricky subject. They do a lot to prevent beginners shooting themself in the foot but can cause big headaches later. There’s more in depth discussion here and here – be aware there are important security concerns to be aware of, regarding magic quotes.

    From a portability perspective, it’s best to write code that doesn’t rely on magic_quotes_gpc being switched on (e.g. use mysql_escape_string()) but can function correctly irrespective of whether magic_quotes_gpc is on or off. A quick way to do this is to execute the something like the following, before the rest of your code;

    // Is magic quotes on? if (get_magic_quotes_gpc()) { // Yes? Strip the added slashes $_GET = array_map('stripslashes', $_GET); $_POST = array_map('stripslashes', $_POST); $_COOKIE = array_map('stripslashes', $_COOKIE); }

    Include Path Seperator

    Although I said I wasn’t going to talk about operating system related issues, as I’ve mentioned it above it’s worth being aware that the include_path seperator is different on Unix and Windows. If you’re setting it within a PHP script, the trick you’ve already seen above can help;

    if (strtoupper(substr(PHP_OS, 0,3) == 'WIN')) { $seperator = ';'; } else { $seperator = ':'; }

    [update]
    PHP 4.3.4 provides the predefined constant PATH_SEPARATOR which contains the above character needed for include paths.

    Thanks Joshelli for tip
    [/update]

    Safe Mode

    Errr – no thanks. Personally don’t write code for users running with safe mode on. If anyone want’s to fill this blank, please do.

    SAPI Issues

    PHP has a number of Server APIs, perhaps the two most popular being the Apache API and the CGI API. The new CLI API adds further issues. The PHP function php_sapi_name() can be useful.

    There’s some discussion of the Apache vs. CGI APIs here, in particular related to the $_SERVER[‘PATH_TRANSLATED’] variable. Notes on compatibility between the CLI and CGI binaries, when running command line scripts, can be found on the later half of this page.

    Enough already for now. Feel free to add / correct – will update this blog with things I’ve missed.

    Frequently Asked Questions (FAQs) about PHP Gotchas

    What are the common pitfalls in PHP that I should be aware of?

    PHP, like any other programming language, has its own set of pitfalls or “gotchas”. These are unexpected behaviors or quirks that can cause bugs or errors in your code. Some common PHP gotchas include the use of global variables, the difference between double equals (==) and triple equals (===), and the unexpected behavior of certain functions like empty() and isset(). Understanding these gotchas can help you write more robust and bug-free code.

    How does the use of global variables affect my PHP code?

    Global variables in PHP can lead to unexpected behavior and bugs. This is because they can be accessed and modified from anywhere in your code, making it difficult to track changes and debug issues. It’s generally recommended to avoid using global variables and instead use function parameters, return values, or class properties to pass data around in your code.

    What is the difference between == and === in PHP?

    In PHP, the double equals (==) operator checks for equality of values, while the triple equals (===) operator checks for equality of both value and type. This can lead to unexpected behavior if you’re not aware of the difference. For example, the expression (0 == “a”) is true because PHP automatically converts the string “a” to 0. However, the expression (0 === “a”) is false because 0 and “a” are not of the same type.

    How do the empty() and isset() functions work in PHP?

    The empty() function in PHP checks if a variable is empty, i.e., it doesn’t exist or its value is considered empty. The isset() function checks if a variable is set, i.e., it exists and is not null. However, these functions can sometimes lead to unexpected results. For example, empty(“0”) is true because “0” is considered empty in PHP, but isset(“0”) is also true because “0” is a set value.

    What are some common PHP filenames and their uses?

    PHP filenames typically correspond to the functionality they provide. For example, index.php is often the main entry point of a PHP application, config.php might contain configuration settings, and database.php might handle database connections. However, the actual filenames can vary depending on the specific application or framework you’re using.

    How does PHP handle error reporting?

    PHP has built-in error reporting functionality that can be configured to display or log errors based on your needs. However, it’s important to understand that not all errors are reported by default, and some errors might be suppressed or hidden depending on your error reporting settings. It’s generally recommended to enable full error reporting during development to catch and fix issues early.

    What is the role of common.php in PHP?

    The common.php file is often used in PHP applications to include code that is shared across multiple scripts. This can include things like database connection code, common functions, or configuration settings. By placing this code in a common.php file, you can avoid duplication and make your code easier to maintain.

    What is the PEAR package in PHP?

    PEAR, which stands for PHP Extension and Application Repository, is a framework and distribution system for reusable PHP components. It provides a structured library of open-source code for PHP users, including a package manager for installing and updating packages. The PEAR package html_common is one such package that provides methods for generating HTML code.

    How can I avoid common PHP gotchas?

    The best way to avoid common PHP gotchas is to understand them and how they work. This includes understanding the difference between == and ===, how empty() and isset() work, and the implications of using global variables. Additionally, following best practices for PHP development, such as using error reporting and avoiding the use of deprecated features, can also help avoid these gotchas.

    What are some resources for learning more about PHP gotchas?

    There are many resources available for learning more about PHP gotchas. The PHP manual is a great starting point, as it provides detailed information about the language’s features and behavior. Online communities like StackOverflow and GitHub can also be valuable resources, as they often have discussions and examples of common PHP gotchas.