![]() |
![]() |
|
Current Projects: PHP on XP Guide — NFO Viewer — Easy Reflections — Photon Storm — HotWire — FileGlider
Friday, November 4. 2005The Good, the Bad and the Ugly There are millions of lines of PHP code freely available to download from the Internet, but how can you tell if the script you are about to install is going to send your site into oblivion or code nirvana?
At the last count the popular resource site HotScripts.com listed over 6,800 PHP scripts with similar resource sites listing thousands more. No matter where you look on the Web you will find plenty of PHP code that you can download and install onto your web site covering just about everything you could ever need. The ease of developing with PHP has lead to the creation of this script gold mine, and while it can be a wonder to explore there are many factors you should take into consideration before going on a downloading frenzy.
Will the script you are about to install bring your server to a halt? Does it open up glaring security issues? Is there a mess of complex and poorly written code behind the sleek HTML exterior? In this article we get our pick axes ready, delve deep and bring back examples that serve one purpose: to show you what to look out for in other peoples code. By looking at good, bad and just downright ugly snippets of code you can gain a far better understanding of the overall quality of a PHP script.
Cutting Edge or Over the hill?Looking at the version of PHP a script was developed for can often provide you with explanations for the way the author has tackled certain problems and give you a good idea of issues to look out for. Having located and downloaded a script, one of the first things you can check are the dates on the files. PHP is a rapidly changing language and with version 5 just around the corner it pays to keep abreast of these updates, but has the author of the script you’ve just found? The leap from PHP4 to PHP5 will be significant, just as it was from PHP2 to 3 and PHP3 to 4, so how can you tell when your newly acquired script was written? The truth of the matter is that unless the author specifically states in the documentation the version of PHP their script was developed for, you’ll have a hard time working it out. Start by reading any text files or code comments you can find, searching for that elusive version number. If that fails to turn anything up you can look at the dates of the files and compare them to the PHP release chart (Table 1). Obviously this isn’t a bullet-proof method, but it may prove useful in your investigations. Open Table 1 in a new browser window It is important to know which PHP version or family (PHP3/4/5) the script was developed with for the following reasons:
The infamous “Register Globals”“Register Globals” seems to get a pretty bad rap these days, with the use of it intensely frowned upon by the PHP digerati, often spouting phrases such as “security risk”. They are right of course, but that doesn’t stop thousands of scripts out there relying on it and there are many books that teach you how to code in the “old style”. This is because it wasn’t until PHP 4.2.0 that register globals were turned “off” by default and as the manual states, reliance of the directive was by then common. Most developers didn’t even know it existed and just assumed that was the way that PHP worked. In itself the directive isn’t insecure, but the misuse of it can be. We won’t cover this ground again here because there is a very good and detailed explanation of this in Chapter 15 of the PHP manual, however it is very useful to be able to determine if the script you have relies on register globals or not.
Listing 1: Determining if “Register Globals” is required [geshi lang=php] [/geshi]Code StructureThere is no “ideal” way to format PHP source code and if you try starting a discussion about coding standards with other developers you’ll find a heated debate on your hands. Some will swear blind that curly braces should be on their own line, some will claim that function names should be all lower-case with underscores splitting words while others will insist “studly caps” is TheWayToGo. So without a standard to follow what use is looking at the actual structure of the code going to be? It will provide one very important clue as to the quality of the script: it will show you how the developer thinks. Take a quick glance at Listing 2 (note that the variable names have been changed to protect the guilty.) The small snippet of code was taken from a PHP script found on Hotscripts.com that had received quite a good user feedback rating. Indeed the code displayed is from the free version of a system for which the professional one costs over $200. Without criticising the code too heavily, now would be a prudent time to bring some key points to your attention: How easy do you think that code would be to modify? There are no tabs or indents used to lay the code out neatly, there are blocks of HTML and code sliced together in echo statements all over the place, and there are variables going directly into SQL statements with no appreciation for data validation. If the query doesn’t execute there is no error handling provided at all other than your script quitting in the middle of the page. Despite this script having been updated in March of 2004 it still assumes that register globals and magic_quotes are turned on and makes no provision otherwise. Although not shown in the listing the administration section of this script assumed that as long as a cookie called “access” was set to a number higher than 1, the user was an administrator. Now compare that code with that found in Listing 3. This is from the Pear MailQueue script and the difference is immediately obvious. The use of indenting blocks of code makes it instantly easy to follow. Even if you don’t know what the function is doing you can read the well thought out class and function names (such as isDeleteAfterSend) and get a good idea immediately what you can expect. The developer has also fully commented the code to truly explain each function (even though none are shown in the Listing, they are present in the script). What can you learn from this comparison? The most obvious is that the majority of the time, if code is cleanly presented and well structured then the script itself has been well thought out also. Code that dumps variables all over the place, mixing core logic functions with the data and presentation usually mean that the developer is inexperienced or has hacked in fixes as and when they needed them. Look at the code you’re about to use carefully and try and get inside the mind of the developer at the time they were creating it. Does it make sense? Is it logical in structure? Is it easy to read and follow? They all have a bearing on the overall quality. Listing 2 : Un-planned code structure, AKA as "a complete mess" [geshi lang=php] $result = mysql_query("SELECT count(id) FROM article_entries") or die(mysql_error()); list($items) = mysql_fetch_row($result); $all = $items; $nextset = $perpage + $offset; if ($nextset > $items) { $nextset = $items; } $items = $items - $nextset; $start = $offset + 1; echo 'Articles: '.$start.'-'.$nextset.'.'; if ($offset > 0) { $preset = $offset - $perpage; if ($preset < 0) { $preset = 0; } echo 'Prev Page'; if ($all > $nextset) { echo ' - '; } } if ($all > $nextset) { echo 'Next Page'; } [/geshi] Listing 3 : Well formed code structure [geshi lang=php] function sendMailsInQueue($limit = MAILQUEUE_ALL, $offset = MAILQUEUE_START, $try = MAILQUEUE_TRY) { $this->container->setOption($limit, $offset, $try); while ($mail = $this->get()) { $this->container->countSend($mail); $result = $this->sendMail($mail); if (!PEAR::isError($result)) { $this->container->setAsSent($mail); if($mail->isDeleteAfterSend()) { $this->deleteMail($mail->getId()); } } else { PEAR::raiseError( MAILQUEUE_ERROR_CANNOT_SEND_MAIL, null, PEAR_ERROR_TRIGGER, E_USER_NOTICE, 'Error in sending mail: '.$result->getMessage()); } } return true; } [/geshi]All you need is “chmod 777”A surprisingly large number of scripts keep their configuration data in plain text files which the administration or main site areas use to operate. There is nothing wrong with this at all until you get to the point in the readme file that tells you to chmod your file (or even worse, the entire directory) to a setting of 777. For those of you who don’t know what chmod is, it’s a way to set file and directory access permissions on Unix systems, please see the links section for a good tutorial. Setting a directory or file to 777 is like asking the entire world to take a shot at it. Very rarely do you actually need to have the permissions this slack and doing so, especially on a shared hosting environment is asking for trouble. You are putting your entire site (or perhaps even server) at the mercy of the security of the application you’ve just installed. You have to hope that it has been written to be water-tight and bug free. For example having a file that is world-writeable and a script that modifies it, and that doesn’t verify the data correctly, could allow someone to start overwriting or appending data to your site. If the file in question holds important details such as MySQL usernames or passwords then you’re open to someone finding this information and compromising your database. On a shared server setting a file to 777 is giving anyone free reign to read, edit and save that file back again. This probably isn’t a situation you want! So how can you get around it? First of all check to see exactly what is being left so widely open – is the file constantly modified, or only changed during installation? For example you can chmod 777 the file while you install the application, and then lock it down again afterwards with more secure permission settings. Another common use is to chmod 777 a directory so users can upload files to it. Instead try chown’ing the directory to Apache so it has permissions to write, but no-one else does. If you are un-sure what options are available then talk to your system administrator or ISP, after all it is the security of their servers at risk. But be wary of instructions that tell you to chmod 777 without telling you about the consequences, it’s a sign that the developer isn’t fully aware of the security implications of this action and must raise the question – what other security elements might they have overlooked? Is the script really needed so badly that you must compromise the security of your server to have it? Common Variables in un-common locationsFollowing on from the chmod theme you will find that many applications bunch their sensitive variables together in a single file that you often need to edit before it will run. An example might be a settings.inc file in which you fill out variable values such as MySQL usernames, passwords, directories and so forth. This practise is common and there is nothing wrong with it – except perhaps in where you are told to place this file once you’ve edited it. If the file contains nothing but variable declarations then there is absolutely no reason for it to live inside the webroot of your site. The “webroot” is the location where you place the rest of your files that need serving via the web server (i.e. html files, images, other php scripts, etc). When PHP includes a file it can include it from anywhere on the server it has permissions to do so from. On a Unix environment you typically have a “home” directory as well as the place to store your web files. You can keep your settings file here rather than in a publicly-accessible webroot. Check the script files carefully to see where they recommend keeping their settings and evaluate for yourself if they really do need to be where you’ve been told to place them. If the settings file is never updated after installation then it would be worth moving it somewhere more secure and manually changing the include statements in the scripts so they know where to find it – it shouldn’t take long to do, but will give you peace of mind that your important settings aren’t open to the world to read. The Sins of Form ValidationWith cross-site scripting attacks and web site hacking and deformation becoming increasingly wide-spread PHP applications need to do everything possible to protect themselves from abuse. Users will exploit anything they can and the more popular your site, the more of a target the applications you have installed become. This casual hacking is often down to something as simple as not correctly validating data that has been passed to a script. First of all – never rely on scripts that only contain form validation on the client-side, i.e. via JavaScript. In virtually all modern browsers this can be disabled with a couple of mouse clicks, leaving forms wide open. Using JavaScript validation is great for the user because they get instant feedback from their decisions without the page reloading, but it is imperative that form data is checked in the PHP code as well. Try some simple “hacks” for yourself to see what happens to the application you want to install, for example if you see a URL such as: http://www.site.com/display.php?id=23 then change the “23” part of it. Swap it for another number; did it just open up what should have been a secured document? Swap the number for some letters; does it know what to make of the new values? Try inserting spurious amounts of random characters, variables or PHP function names and see what gives. You will no-doubt be surprised at the results – some applications will crash with SQL errors, or errors pertaining to variable declaration. Depending on how PHP has been configured a site visitor can usually find out the entire directory structure of your site just by doing something as simple as passing a bogus value on the URL, when they receive an error message such as: Parse error: parse error, unexpected T_STRING in d:\usr\home\rich\public_html\login.php on line 4 By throwing in a rogue value the “hacker” now knows the directory structure of your server. It doesn’t end there – cookies can be edited, session values can be changed or hijacked, form data can be modified or submitted from other sites. Other than checking the application code line by line, the best suggestion is to try your hardest to break it before you move it to a live site. Common validation pitfalls and exploits include:
See the Links section at the end for further information. Out of the frying pan and into the SQL fireOne of the biggest problem with badly coded PHP applications are scripts that take form data and pass it directly into a SQL query with little, if any, validation. When you manage to cause an error in a PHP script you usually find out the path to the script that crashed, depending on the error reporting level of PHP. When you mess up a SQL query, you usually get a complete SQL error message back again giving table names and structure, as well as showing any other data that was used in the query at the time. Obviously this isn’t the best situation to be in and you should check through the application code to see how it will handle a database error, should it occur. As mentioned in the previous section, it is easy to break a SQL query using an apostrophe if the application doesn’t know how to cater for them. PHP has an INI setting called magic_quotes which will automatically handle the adding (and removing) of slashes before quotes, prior to the query running. As this is an INI setting some servers will have it enabled, while others will not. If the application you’ve downloaded assumes it is enabled, and it isn’t, you could be in for some SQL headaches – so check the application and code carefully to ensure this won’t happen. Square hole, round pegBefore installing an application it is worth checking to see if it is going to behave with regards to where it wants to live on your server. Can you create a sub-directory specifically for the application without it complaining that it doesn’t reside at the root of your site? Or is it flexible enough to be placed anywhere? An application that shoehorns itself into a corner and refuses to budge could cause you more trouble than it is worth. Look out for a settings file that allows YOU to specify where the application lives on your server, not one that dictates it. On a related subject you may be adding an application to an already established site and be hoping you can “include” what you need to. In principle this is fine, but look carefully at the names of functions, classes or objects that the application may user. If you already have a $user object for your forum, the last thing you want is a conflicting $user object by installing say a photo gallery. The same goes for SQL table names – will the application be flexible enough not to conflict with an already existing table that might share the same name? Changing every single query could prove to take an awful long time. Look out to see if you can set a “Table Prefix” value prior to installation, this can be used to ensure that the table names are unique to that application and don’t cause you any trouble. ResearchThis might sound obvious – but it’s a good idea to run a few searches on the web for user comments and opinions regarding the application you’re about to install or purchase. Are there any posts in forums or mailing list archives from people who have experienced problems with the application? Try the Google Usenet search as well as the PHP-General mailing list archive and various PHP Developer sites. You never know what horrors 10 minutes Googling might turn up about the application you were ready to pay good money for, or spend time installing. It’s very easy to be swayed by an impressive “demo” of the application on the vendor’s site, especially if their designers are hot and you have nice well formed HTML with colourful icons and smooth layout. But beauty is only skin deep and this is especially true of PHP scripts. ConclusionIt may sound like I’m being overly cautious in this article, but it is born from many years experience (and frustration) of dealing with clients who took a well crafted site, slapped a random application they had found that “looked nice” onto it and wondered why all hell broke loose. If there is money involved and you or a client is paying for the application then you have every right to be as strict as you want with it. Run it through some of the tests shown here, check out the code comments and functions, throw random spurious data into it and see if it stands tall or crumples to the ground – because ultimately your reputation could depend on it. Links & Literature
PHP Manual Chapter 15 – Register Globals. Note:This article was written in March 2004 and was published in International PHP Magazine. At the time PHP 5 was still only in beta, so please allow for this when reading. Even so, I feel most of the advice here holds true even today. Trackbacks
Trackback specific URI for this entry
No Trackbacks
Comments
Display comments as
(Linear | Threaded)
This article provided abundant information, both for buyers, and for scripters. It is was nice to read through it as a check on myself, and see that I passed the test. I am always looking for ways to improve my code though, so anything someone can give me as always welcome.
The author does not allow comments to this entry
|
My AS3 Blog
Photon Storm Great PHP links
C7Y PHP Podcast CorePHP is hosted by |

