10 Advanced PHP Tips Revisited

Advertisement

Here, on the Smashing Editorial team, we always try to meet the expectations of our readers. We do our best to avoid misunderstandings, and we try to spread knowedge and present only the best design practices and development techniques. However, sometimes we do make mistakes. And when we do, we apologize and do our best to correct what we’ve done.

In November 2008 we published the article 10 Advanced PHP Tips To Improve Your Programming. Apparently, according to negative comments to the post, it contained some errors and some statements that are just wrong. We sincerely apologize for our mistake, and we are truly sorry for any inconvenience we caused by it. However, this simple apology is not good enough. To solve the problem, we asked Chris Shiflett and Sean Coates, two PHP gurus, to take a closer look at the article, explain its errors and make it perfectly clear what is actually right and wrong in the theory and practice. This article is a professional response to our article published a couple of months ago.

10 Useful PHP Tips Revisited

by Chris Shiflett and Sean Coates

This article is a rebuttal to 10 Advanced PHP Tips To Improve Your Programming — henceforth referred to as the previous article — published last November here on Smashing Magazine. The introduction sounds intriguing:

Listed below are 10 excellent techniques that PHP developers should learn and use every time they program.

Unfortunately, the intrigue devolves into disappointment. We disagree with many of the tips, and even when we don’t, the accompanying explanation is weak or misleading. In this article, we go through each and every tip from the previous article and provide our own commentary and evidence, either to validate and clarify the tip, or to refute it. Our hope is that you don’t just accept our opinion, but rather learn enough to form your own.

1. Use an SQL Injection Cheat Sheet

This particular tip is just a link to a useful resource with no discussion on how to use it. Studying various permutations of one specific attack can be useful, but your time is better spent learning how to safeguard against it. Additionally, there is much more to Web app security than SQL injection. XSS (Cross-Site Scripting) and CSRF (Cross-Site Request Forgeries), for example, are at least as common and at least as dangerous.

We can provide some much-needed context, but because we don’t want to focus too much on one attack, we’ll first take a step back. Every developer should be familiar with good security practices, and apps should be designed with these practices in mind. A fundamental rule is to never trust data you receive from somewhere else. Another rule is to escape data before you send it somewhere else. Combined, these rules can be simplified to make up a basic tenet of security: filter input, escape output (FIEO).

The root cause of SQL injection is a failure to escape output. More specifically, it is when the distinction between the format of an SQL query and the data used by the SQL query is not carefully maintained. This is common in PHP apps that construct queries as follows:

<?php
 
$query = "SELECT *
          FROM   users
          WHERE  name = '{$_GET['name']}'";
          
?>

In this case, the value of $_GET['name'] is provided by another source, the user, but it is neither filtered nor escaped.

Escaping preserves data in a new context. The emphasis on escaping output is a reminder that data used outside of your Web app needs to be escaped, else it might be misinterpreted. By contrast, filtering ensures that data is valid before it’s used. The emphasis on filtering input is a reminder that data originating outside of your Web app needs to be filtered, because it cannot be trusted.

Assuming we're using MySQL, the SQL injection vulnerability can be mitigated by escaping the name with mysql_real_escape_string(). If the name is also filtered, there is an additional layer of security. (Implementing multiple layers of security is called "defense in depth" and is a very good security practice.) The following example demonstrates filtering input and escaping output, with naming conventions used for code clarity:

<?php
 
// Initialize arrays for filtered and escaped data, respectively.
$clean = array();
$sql = array();
 
// Filter the name. (For simplicity, we require alphabetic names.)
if (ctype_alpha($_GET['name'])) {
    $clean['name'] = $_GET['name'];
} else {
    // The name is invalid. Do something here.
}
 
// Escape the name.
$sql['name'] = mysql_real_escape_string($clean['name']); 
 
// Construct the query.
$query = "SELECT *
          FROM   users
          WHERE  name = '{$sql['name']}'";
 
?>

Although the use of naming conventions can help you keep up with what has and hasn't been filtered, as well as what has and hasn't been escaped, a much better approach is to use prepared statements. Luckily, with PDO, PHP developers have a universal API for data access that supports prepared statements, even if the underlying database does not.

Remember, SQL injection vulnerabilities exist when the distinction between the format of an SQL query and the data used by the SQL query is not carefully maintained. With prepared statements, you can push this responsibility to the database by providing the query format and data in distinct steps:

<?php
 
// Provide the query format.
$query = $db->prepare('SELECT *
                       FROM   users
                       WHERE  name = :name');
 
// Provide the query data and execute the query.
$query->execute(array('name' => $clean['name']));
 
?>

The PDO manual page provides more information and examples. Prepared statements offer the strongest protection against SQL injection.

2. Know the Difference Between Comparison Operators

This is a good tip, but it is missing a practical example that demonstrates when a non-strict comparison can cause problems.

If you use strpos() to determine whether a substring exists within a string (it returns FALSE if the substring is not found), the results can be misleading:

<?php
 
$authors = 'Chris & Sean';
 
if (strpos($authors, 'Chris')) {
    echo 'Chris is an author.';
} else {
    echo 'Chris is not an author.';
}
 
?>

Because the substring Chris occurs at the very beginning of Chris & Sean, strpos() correctly returns 0, indicating the first position in the string. Because the conditional statement treats this as a Boolean, it evaluates to FALSE, and the condition fails. In other words, it looks like Chris is not an author, but he is!

This can be corrected with a strict comparison:

<?php
 
if (strpos($authors, 'Chris') !== FALSE) {
    echo 'Chris is an author.';
} else {
    echo 'Chris is not an author.';
}
 
?>

3. Shortcut the else

This tip accidentally stumbles upon a useful practice, which is to always initialize variables before you use them. Consider a conditional statement that determines whether a user is an administrator based on the username:

<?php
 
if (auth($username) == 'admin') {
    $admin = TRUE;
} else {
    $admin = FALSE;
}
 
?>

This seems safe enough, because it’s easy to comprehend at a glance. Imagine a slightly more elaborate example that sets variables for name and email as well, for convenience:

<?php
 
if (auth($username) == 'admin') {
    $name = 'Administrator';
    $email = 'admin@example.org';
    $admin = TRUE;
} else {
    /* Get the name and email from the database. */
    $query = $db->prepare('SELECT name, email
                           FROM   users
                           WHERE  username = :username');
    $query->execute(array('username' => $clean['username']));
    $result = $query->fetch(PDO::FETCH_ASSOC);
    $name = $result['name'];
    $email = $result['email']; 
    $admin = FALSE;
}
 
?>

Because $admin is still always explicitly set to either TRUE or FALSE, all is well, but if a developer later adds an elseif, there’s an opportunity to forget:

<?php
 
if (auth($username) == 'admin') {
    $name = 'Administrator';
    $email = 'admin@example.org';
    $admin = TRUE;
} elseif (auth($username) == 'mod') {
    $name = 'Moderator';
    $email = 'mod@example.org';
    $moderator = TRUE;
} else {
    /* Get the name and email. */
    $query = $db->prepare('SELECT name, email
                           FROM   users
                           WHERE  username = :username');
    $query->execute(array('username' => $clean['username']));
    $result = $query->fetch(PDO::FETCH_ASSOC);
    $name = $result['name'];
    $email = $result['email']; 
    $admin = FALSE;
    $moderator = FALSE;
}
 
?>

If a user provides a username that triggers the elseif condition, $admin is not initialized. This can lead to unwanted behavior, or worse, a security vulnerability. Additionally, a similar situation now exists for $moderator, which is not initialized in the first condition.

By first initializing $admin and $moderator, it’s easy to avoid this scenario altogether:

<?php
 
$admin = FALSE;
$moderator = FALSE;
 
if (auth($username) == 'admin') {
    $name = 'Administrator';
    $email = 'admin@example.org';
    $admin = TRUE;
} elseif (auth($username) == 'mod') {
    $name = 'Moderator';
    $email = 'mod@example.org';
    $moderator = TRUE;
} else {
    /* Get the name and email. */
    $query = $db->prepare('SELECT name, email
                           FROM   users
                           WHERE  username = :username');
    $query->execute(array('username' => $clean['username']));
    $result = $query->fetch(PDO::FETCH_ASSOC);
    $name = $result['name'];
    $email = $result['email'];
}
 
?>

Regardless of what the rest of the code does, it’s now clear that $admin is FALSE unless it is explicitly set to something else, and the same is true for $moderator. This also hints at another good security practice, which is to fail safely. The worst that can happen as a result of not modifying $admin or $moderator in any of the conditions is that someone who is an administrator or moderator is not treated as one.

If you want to shortcut something, and you’re feeling a little disappointed that our example includes an else, we have a bonus tip that might interest you. We’re not certain it can be considered a shortcut, but we hope it’s helpful nonetheless.

Consider a function that determines whether a user is authorized to view a particular page:

<?php
 
function authorized($username, $page) {
    if (!isBlacklisted($username)) {
        if (isAdmin($username)) {
            return TRUE;
        } elseif (isAllowed($username, $page)) {
            return TRUE;
        } else {
            return FALSE;
        }
    } else {
        return FALSE;
    }
}
 
?>

This example is actually pretty simple, because there are only three rules to consider: administrators are always allowed access; those who are blacklisted are never allowed access; and isAllowed() determines whether anyone else has access. (A special case exists when an administrator is blacklisted, but that is an unlikely possibility, so we’re ignoring it here.) We use functions for the rules to keep the code simple and to focus on the logical structure.

There are numerous ways this example can be improved. If you want to reduce the number of lines, a compound conditional can help:

<?php
 
function authorized($username, $page) {
    if (!isBlacklisted($username)) {
        if (isAdmin($username) || isAllowed($username, $page)) {
            return TRUE;
        } else {
            return FALSE;
        }
    } else {
        return FALSE;
    }
}
 
?>

In fact, you can reduce the entire function to a single compound conditional:

<?php
 
function authorized($username, $page) {
    if (!isBlacklisted($username) && (isAdmin($username) || isAllowed($username, $page)) {
        return TRUE;
    } else {
        return FALSE;
    }
}
 
?>

Finally, this can be reduced to a single return:

<?php
 
function authorized($username, $page) {
    return (!isBlacklisted($username) && (isAdmin($username) || isAllowed($username, $page));
}
 
?>

If your goal is to reduce the number of lines, you’re done. However, note that we’re using isBlacklisted(), isAdmin(), and isAllowed() as placeholders. Depending on what’s involved in making these determinations, reducing everything to a compound conditional may not be as attractive.

This brings us to our tip. A return immediately exits the function, so if you return as soon as possible, you can express these rules very simply:

<?php
 
function authorized($username, $page) {
 
    if (isBlacklisted($username)) {
        return FALSE;
    }
 
    if (isAdmin($username)) {
        return TRUE;
    }
 
    return isAllowed($username, $page);
}
 
?>

This uses more lines of code, but it’s very simple and unimpressive (we’re proudest of our code when it’s the least impressive). More importantly, this approach reduces the amount of context you must keep up with. For example, as soon as you’ve determined whether the user is blacklisted, you can safely forget about it. This is particularly helpful when your logic is more complicated.

4. Drop Those Brackets

Based on the content of this tip, we believe the author means "braces," not brackets. "Curly brackets" may mean braces to some, but "brackets" universally means "square brackets."

This tip should be unconditionally ignored. Without braces, readability and maintainability are damaged. Consider a simple example:

<?php
 
if (date('d M') == '21 May')
    $birthdays = array('Al Franken',
                       'Chris Shiflett',
                       'Chris Wallace',
                       'Lawrence Tureaud');
 
?>

If you’re good enough, smart enough, secure enough, notorious enough, or pitied enough, you might want to party on the 21st of May:

<?php
 
if (date('d M') == '21 May')
    $birthdays = array('Al Franken',
                       'Chris Shiflett',
                       'Chris Wallace',
                       'Lawrence Tureaud');
    party(TRUE);
 
?>

Without braces, this simple addition causes you to party every day. Perhaps you have the stamina for it, so the mistake is a welcome one. Hopefully, the silly example doesn’t detract from the point, which is that the excessive partying is an unintended side effect.

In order to promote the practice of dropping braces, the previous article uses short examples such as the following:

<?php
 
if ($gollum == 'halfling') $height --;  
else $height ++;
 
?>

Because each condition is constrained to a single line, such mistakes might be less likely, but this leads to another problem: inconsistencies are jarring and require more time to read and comprehend. Consistency is such a valued quality that developers often abide by a coding standard even if they dislike the coding standard itself.

We recommend always using braces:

<?php
 
if (date('d M') == '21 May') {
    $birthdays = array('Al Franken',
                       'Chris Shiflett',
                       'Chris Wallace',
                       'Lawrence Tureaud');
    party(TRUE);
}
 
?>
 

You’re welcome to party every day, but make sure it’s deliberate, and please be sure to invite us!

5. Favor str_replace() Over ereg_replace() and preg_replace()

We hate to sound disparaging, but this tip demonstrates the sort of misunderstanding that leads to the same misuse it’s trying to prevent. It’s an obvious truth that string functions are faster at string matching than regular expression functions, but the author’s attempt to draw a corollary from this fails miserably:

If you’re using regular expressions, then ereg_replace() and preg_replace() will be much faster than str_replace().

Because str_replace() does not support pattern matching, this statement makes no sense. The choice between string functions and regular expression functions comes down to which is fit for purpose, not which is faster. If you need to match a pattern, use a regular expression function. If you need to match a string, use a string function.

6. Use Ternary Operators

The benefit of the ternary operator is debatable (there’s only one, by the way). Here is a line of code from an audit we performed recently:

<?php
 
$host = strlen($host) > 0 ? $host : htmlentities($host);
 
?>

Oops! The author actually means to escape $host if the string length is greater than zero, but instead accidentally does the opposite. Easy mistake to make? Maybe. Easy to miss during a code audit? Certainly. Concision doesn’t necessarily make the code any better.

The ternary operator may be fine for one-liners, prototypes, and templates, but we strongly believe that an ordinary conditional statement is almost always better. PHP is descriptive and verbose. We think code should be, too.

7. Memcached

Disk access is slow. Network access is slow. Databases typically use both.

Memory is fast. Using a local cache avoids the overhead of network and disk access. Combine these truths and you get memcached, a “distributed memory object caching system” originally developed for the Perl-based blogging platform LiveJournal.

If your application isn’t distributed across multiple servers, you probably don’t need memcached. Simpler caching approaches — serializing data and storing it in a temporary file, for example — can eliminate a lot of redundant work on each request. In fact, this is the sort of low-hanging fruit we consider when helping our clients tune their apps.

One of the easiest and most universal ways to cache data in memory is to use the shared memory helpers in APC, a caching system originally developed by our colleague George Schlossnagle. Consider the following example:

<?php
 
$feed = apc_fetch('news');
 
if ($feed === FALSE) {
    $feed = file_get_contents('http://example.org/news.xml');
    // Store this data in shared memory for five minutes.
    apc_store('news', $feed, 300);
}
 
// Do something with $feed.
 
?>

With this type of caching, you don’t have to wait on a remote server to send the feed data for every request. Some latency is incurred — up to five minutes in this example — but this can be adjusted to as close to real time as your app requires.

8. Use a Framework

All decisions have consequences. We appreciate frameworks — in fact, the main developers behind CakePHP and Solar work with us at OmniTI — but using one doesn’t magically make what you’re doing better.

In December, our colleague Paul Jones wrote an article for PHP Advent called The Framework as Franchise, in which he compares frameworks to business franchises. He refers to a suggestion by Michael Gerber from his book "The E-Myth Revisited":

Gerber notes that to run a successful business, the entrepreneur needs to act as if he is going to sell his business as a franchise prototype. It is the only way the business owner can make the business operate without him being personally involved in every decision.

This is good advice. Whether you’re using a framework or defining your own standards and conventions, it’s important to consider the value from the perspective of future developers.

Although we would love to give you a universal truth, extending this idea to suggest that a framework is always appropriate isn’t something we’re willing to do. If you ask us whether you should use a framework, the best answer we could give is, “It depends.”

9. Use the Suppression Operator Correctly

Always try to avoid using the error suppression operator. In the previous article, the author states:

The @ operator is rather slow and can be costly if you need to write code with performance in mind.

Error suppression is slow. This is because PHP dynamically changes error_reporting to 0 before executing the suppressed statement, then immediately changes it back. This is expensive.

Worse, using the error suppression operator makes it difficult to track down the root cause of a problem.

The previous article uses the following example to support the practice of assigning a variable by reference when it is unknown if $albus is set:

<?php
 
$albert =& $albus;
 
?>

Although this works — for now — relying on strange, undocumented behavior without a very good understanding of why it works is a good way to introduce bugs. Because $albert is assigned to $albus by reference, future modifications to $albus will also modify $albert.

A much better solution is to use isset(), with braces:

<?php
 
if (!isset($albus)) {
    $albert = NULL;
}
 
?>

Assigning $albert to NULL is the same as assigning it to a nonexistent reference, but being explicit greatly improves the clarity of the code and avoids the referential relationship between the two variables.

If you inherit code that uses the error suppression operator excessively, we’ve got a bonus tip for you. There is a new PECL extension called Scream that disables error suppression.

10. Use isset() Instead of strlen()

This is actually a neat trick, although the previous article completely fails to explain it. Here is the missing example:

<?php
 
if (isset($username[5])) {
    // The username is at least six characters long.
}
 
?>

When you treat strings as arrays, each character in the string is an element in the array. By determining whether a particular element exists, you can determine whether the string is at least that many characters long. (Note that the first character is element 0, so $username[5] is the sixth character in $username.)

The reason this is slightly faster than strlen() is complicated. The simple explanation is that strlen() is a function, and isset() is a language construct. Generally speaking, calling a function is more expensive than using a language construct.

About the Authors

Hi, we’re Chris Shiflett and Sean Coates. We work together at OmniTI (“the most important web company you’ve never heard of”), blog about PHP and other stuff at shiflett.org and seancoates.com, curate PHP Advent, and do the Twitter thing as @shiflett and @coates.

(al)

PHP,

↑ Back to top

Hi, I’m Chris Shiflett, a founding member of Analog, a web design and development co-operative. I blog about PHP and other stuff at shiflett.org, curate PHP Advent, and do the Twitter thing as @shiflett.

  1. 1
  2. 2

    Rasmus Lerdorf, PHP’s daddy tips : http://lerdorf.com/tips.pdf

    Now, the list is bigger :)

    1
  3. 3

    Nice Article Chris & Sean… thanks for sharing!!

    Some of these tips are very useful for optimizations at micro level while others are very useful universally for PHP followers.

    It’s good that you also included Comparison Operators issue as i too learn about this in details last week.

    Also it already mentioned in one of the last post that there is a huge difference between “ and ‘.

    Anyway….. Overall useful stuff you guys got here.

    DKumar M.

    2
  4. 4

    Awesome stuff!
    *Bookmarks*

    0
  5. 5
  6. 6

    Water, you should at least read the introduction before commenting. This article is a rebuttal. :-)

    I’ll be keeping an eye on these comments and Twitter (@shiflett) in case anyone has any feedback.

    Thanks in advance for reading!

    0
  7. 7

    Great, php advice. I’ll pass this on.

    0
  8. 8

    good stuff as always!

    0
  9. 9

    Good read thanks!

    1
  10. 10

    could need a rewrite, if you are going to talk about optimizations (isset > strlen) then atlesat have the basic ones like ++$x instead of $x++,

    And not to use else when not need…
    function authorized($username, $page) {
    if (!isBlacklisted($username) && (isAdmin($username) || isAllowed($username, $page))
    return TRUE;
    return FALSE;
    }

    save the millisecond ;) else a nice writeup for beginners.

    0
  11. 11

    Argh! Linking to a 7-year old pdf on my site. Most of those optimizations tips are ok, but the references one is wrong. You never want to use references for performance reasons.

    As for this article. Good hints. I would expand on number 9 a bit though. @ isn’t just slow because the error_reporting state needs to be toggled, it is slow because the actual error string is created regardless of the error_reporting setting. There is a sprintf and some filter code that is executed on every single warning, notice, strict, error, etc. regardless of the error_reporting setting. So this doesn’t just apply to @. It applies to all messages even if you have them turned off with your default error_reporting setting. You should always develop with all possible messages turned on. eg.

    error_reporting = E_ALL | E_STRICT

    And before you put your site in production make sure you do:

    display_errors = Off

    And send all error messages to a log file:

    log_errors = On
    error_log = “/var/log/php_errors”

    -1
  12. 12

    I’d seriously doubt that Danni’s tip saves a millisecond. His code also violates the point the authors make in point 4. Keep the braces man! I wholeheartedly concur on that one.

    If you really want to optimize the solution is in the article. Don’t people read before they comment?

    0
  13. 13

    Johannes Schlüter

    March 24, 2009 10:23 am

    I’d call the last one a bad micro-optimization. I didn’t measure whether it’s really faster but yes, could be (two opcodes (fetch offset + isset) vs. fcall) but it makes the code really hard to read since at first I’d think “oh, the code is reading an array” and readability is way more important that micro-optimizations. And if this is your bottleneck you should look for another solution (like writing the relevant code in C or something)

    Anyways, if you really want to do that and want a bit more readability use curly braces instead of the square ones, for array/string offset access they are the same, but given a coding style it’s way clearer to read

    if (isset( $username{5} )) {
    // The username is at least six characters long.
    }

    johannes

    -1
  14. 14

    Mithun Sreedharan

    March 24, 2009 10:26 am

    Nice !

    -1
  15. 15

    Not a great article… Maybe more tips?

    -2
  16. 16

    Awesome tips !!

    -1
  17. 17

    Sub par for SM.

    I’m hardly an advanced PHP user and I consider all of these tips to be either common sense, or bad practice.

    -1
  18. 18

    Yikes! Not to split hairs, but….well… yikes.

    0
  19. 19

    Greg Johnson: what exactly do you consider bad practice?
    Some of them are common tips, sure, but one of the goals was to fix the errors in the original article.

    0
  20. 20

    Tip #9: Shouldn’t the sentence:
    “Because $albert is assigned to $albus by reference, future modifications to $albus will also modify $albert.”
    Be instead:
    “Because $albus is assigned to $albert by reference, future modifications to $albus will also modify $albert.”
    or I just suck at English? O.o

    -1
  21. 21

    Md. Rayhan Chowdhury

    March 24, 2009 11:27 am

    Very helpful information indeed, I want to add following along with these for novice like me.

    1. use empty($var) instead of count($var) in if conditions for checking whether the value of a variable exists. like,

    if (count($users)) {
    // display tables.
    }

    to

    if (!empty($users)) {
    // display tables
    }

    2. don’t use count($var) in a loop. like,
    for ($i = 0, $i < count($posts); $i++) {
    }

    to

    $postCounts= count($posts);
    for ($i = 0, $i < $postCounts; $i++) {

    }

    -1
  22. 22

    Much better than previous post. Thanks for recommending that people always make use of braces! That’s up there with proper indenting, variable initialization, and descriptive variable names in my book.

    -1
  23. 23

    slow news day? Gotta make those ad impressions?

    -1
  24. 24

    About usage of isset() instead of the @operator: I wholeheartedly agree, but would like to see added a note about the difference between array_key_exists() and isset() when checking for the presence of a value in an array.
    $arr = array( ‘testme’ => null ) will give different results for those, and can lead to those oh so subtle errors that can programmers that do not know the difference between == and === sometimes make…

    -1
  25. 25

    I enjoyed the article and as a leading web development language, I think a lot of web developers will appreciate it. Thanks Sean and Chris, very informative yet not verbose.

    Thanks SM for these types of articles. I know SM probably has more of a design community heritage but a lot of my friends who do coding for pay stop by every so often. Not to mention the designers I do know who are getting their feet wet with some coding.

    0
  26. 26

    yes.. more tips for rasmus jr

    -1
  27. 27

    Josh lewis: What do you find unimportant about combatting potentially very dangerous misinformation?

    0
  28. 28

    I’m with 4 and 6. I hate braceless code and the over use of ternary code.

    Of course the over use of ternary code usually ends up going along with #3.

    0
  29. 29

    Great list – as always.

    Thanks.

    0
  30. 30

    Kieran Masterton

    March 24, 2009 12:31 pm

    All great stuff!! Personally I can’t stand (or understand the need for) the ternary operator but maybe I’m just a grumpy old man.

    0
  31. 31

    use the foreach loop instead of the for($x = 0;$x < count((array) $y), $x++) loop!

    1
  32. 32

    Stop encouraging the use of ternary statements and not using braces. Ternary statements are good sometimes, but it’s almost never a good idea to leave the braces off.

    1
  33. 33

    Robin, I think you meant to comment on the original article, not here. This article recommends neither of those things.

    Or, perhaps you commented without reading? I hope that’s not the case. :-)

    0
  34. 34

    When talking about ereg_*, it should have been mentioned that it is deprecated as of 5.3 witch is around the corner.. (same goes for split(), as it is part of the ereg extension)

    0
  35. 35

    How to avoid SQL injection 101 is included in a list of ‘advanced’ php tips? If avoiding SQL injection is considered an ‘advanced’ topic, then no wonder there are so many security breaches going on out there….

    0
  36. 36

    The biggest problem with these “tips” is people don’t understand them. Frankly, I would take both pages offline because these lessons are not PHP-specific. Half of them are simply “best practices”, and the other half are hackish tweaks that will not only break in later versions, but also hinder code legibility and reuse.

    If you’re concerned about the speed of your PHP page, don’t go mangling the code in search of the holy millisecond, you can achieve much greater gains via other means. For one, if your site is so busy that performance becomes an issue, you’re either making good money (from ads, etc), or you’re on a horrible server and need to upgrade. There are many server-level improvements that can make a much greater difference than any of these hacks, like installing Xcache, splitting off requests to Lighttpd or load-balancing across multiple servers with Squid.

    Spending hours to squeeze a few hundredths of a second is something game developers do, not web designers.

    -1
  37. 37

    A huge improvement on the original article but I still have a few issues.

    I think it’s usually bad practice to have multiple exit points (returns) throughout a function. Then you introduce the problem of wondering why some code in your function isn’t executing when it has grown to be more complex. Much safer to set a return variable and return it at the end of the function. The exception is returning at the beginning of a function when a necessary precondition has not been met.

    I’m not convinced by your argument that ternary statments shouldn’t be used because some people don’t understand them. They are appropriate and quite useful when setting variables, which is probably the only time they should be used. You can’t always dumb down your code just because some programmers are incompetent. If you applied your logic to all PHP programming, you could dispense with a whole bunch of useful constructs (Hey, what does this ‘while’ thing do, best to stick with a ‘for’ loop).

    The reasoning behind #10 contradicts the reasoning in some of your other tips, eg. “The choice… comes down to which is fit for purpose” and “PHP is descriptive and verbose. We think code should be, too”. If you were to follow the reasoning you have applied in the other tips, strlen() is the obvious choice as it’s a function designed for the exact purpose you are using it for and it’s suitably descriptive.

    Finally – this is purely my own preference – but I don’t mind dropping the curly braces if it’s a short ‘if’ statement that fits on one line, like the example from the previous article. If I refactor and I require multiple statments in my ‘if’, I always add the curly craces at this point. Again, it’s just a preference – it can save a lot of space and I don’t think it’s too dangerous. It’s not something I’d recommend as best practice though but it works for me.

    Cheers,
    Darren.

    0
  38. 38

    I’m not sure if there are new operators in the latest version of PHP that I’m not aware of but it looks like there are two errors in this articles code. Here’s one:

    Tip #2, bottom code snippet, line 3 states :
    “if (strpos($authors, ‘Chris’) !== FALSE) {”

    Shouldn’t this just be “!= FALSE” ?

    Also, what’s the triple equals ( === ) operator??? Tip 7, line 5.

    Thanks,

    Joe

    0
  39. 39

    I’d love to see an article about 10 Advanced PHP books, and the contents of those books. I really enjoyed Larry Ullman’s PHP5 Advanced book, and I’d much rather read a book like that then ponder 10 semi-useless tips that anyone should know already.

    0
  40. 40

    re: 38

    === and !== means PHP checks the value AND the datatype.

    i.e. in PHP
    0 == FALSE is TRUE
    but
    0 === FALSE is FALSE

    Have a read of htis.. http://us.php.net/manual/en/language.operators.comparison.php

    -1
  41. 41

    @Darren

    If your function is that long, it’s time to refactor your code and employ step-through-debugging if you still can’t figure it out. It is indeed a best practice to “exit early” in order to avoid long if/elseif/else and switch statements.

    If you still cannot master the code, something is seriously wrong. This is programming and not rocket science.

    And re: the braces — it’s all about convention. And a convention implies that you follow through! All the way! Not half way, or “most times”. The idea is to have code that looks the same at all times. And not to introduce a 100 edge cases and different reasons for each one.

    If code is easier to read, it becomes easier to debug/extend/maintain.

    0
  42. 42

    Hi, nice article and I agree to most of these terms, but not all.
    Your example of escaping and filtering input variables shows a bad practice. Why do you use custom variable? You had to do this work in each function or method again. Instead you could use the $GLOBALS array respectively the global command but that’s not only a bad practice, that’s worst practice. Instead you should at least use a function to do your escaping stuff or better you encapsulate this into classes that handle all your database related actions including escaping and filtering (escaping could be done by prepared statements as you’ve shown in the last example).

    0
  43. 43

    Nice work guys, that is a well thought out concise rebuttal… I’m really getting a kick out of some of these comments. ;-)

    0
  44. 44

    @joe:
    I’m resisting the urge to flame you, and it’s not easy.

    The operators used are not typos or even remotely new features- the triple equals operator checks whether the two variables are identical, not that they return the same value. That is, if you have the string ’1′ and the number 1 stored as $foo and $bar, respectively:

    $foo == $bar // returns TRUE
    $foo === $bar // returns FALSE

    likewise, the ““if (strpos($authors, ‘Chris’) !== FALSE) {”” line is exactly right. Since “Chris” is at the beginning of the string $authors, strpos($authors, ‘Chris’) returns 0. In this case, 0 should actually be considered a TRUE value, so explicitly checking whether it matches both the type and value of the boolean FALSE makes perfect sense.

    It’s worth noting that === is one of those microoptimizations, because PHP doesn’t have to go to the trouble of recasting $foo and $bar to see if they match. It knows what it’s looking for, and can exit when it doesn’t find it.

    Next time, read the article and look up the stuff you don’t know before claiming the author got it wrong.

    0
  45. 45

    Misuse of if/then (single line, dropping braces) doesn’t mean we throw away if/then, and neither should we the ternary. This isn’t some strange PHP-only operator that no one understands. IMO, keep the ternary, ban empty() and ==/!=.

    0
  46. 46

    Good to see a “remake” and I’m glad to see that SM values honesty more than pride. I wonder how many others admit they’re wrong and correct themselves.

    0
  47. 47

    First, I tip my hat to Smashing for admitting when they made a mistake (in this case, dealing with the original PHP tips article). Not many websites (that I see anyways) are willing to admit when there are problems / errors and the like. So good for Smashing Mag for ‘owning up’ to their initial article shortcomings. Good to see someone out there actually care about what they deliver to their readers (even if it means publicly apologizing). Kudos!

    I think I said this before (and will definitely say it again), as for tip #5. Favor str_replace() Over ereg_replace() and preg_replace(), I would even go so far as to discourage the use of ereg in it’s entirety. ereg is POSIX (Portable Operating System Interface) which will no longer be included within the core of PHP as of version 6. Future proof your code now by learning the more favorable PCRE (Perl-Compatible Regular Expressions) and start using preg instead when dealing with patterns.

    Those who refuse to embrace PCRE might be in for a rude awakening when their code potentially breaks once their hosting providers ultimately upgrade to version 6 without the POSIX extension installed.

    0
  48. 48

    I like the second tip:
    2. Know the Difference Between Comparison Operators
    The strpos() would return a zero for sure since ‘Chris’ is in the first postion.
    But shouldn’t the operator ‘!==’ be ‘!=’ ?

    0
  49. 49

    oh~
    I love java
    But I seldom find something about java here~
    sigh~

    0
  50. 50

    @vishal
    The strpos() would return a zero for sure since ‘Chris’ is in the first postion.
    But shouldn’t the operator ‘!==’ be ‘!=’ ?

    No. 0 and false are equal (0 == false), but they’re not identical (0 !== false).

    http://www.php.net/manual/en/types.comparisons.php

    0
  51. 51

    @till, it’s not unusual for functions to require some sort of tidying up before exiting, eg, closing a database connection, file handle, etc. In these cases, are you going to replicate this tidying code for each exit point? Even if you create a function to do the tidying, you still have to replicate the function call at each exit point. Does this mean that you use multiple exit points in functions that don’t require some tidying code and single exit points for others? What if you realise you need to add tidying code after you’ve gone the multiple exit point route? To use your consistency argument, isn’t it better to favour one structure over the other?

    Also, there are advantages regarding debugging as well. With a single exit point, often you can get away with setting a single breakpoint at the end of the function. With multiple breakpoints, it’s much more likely that you have to set breakpoints before each exit point.

    I wouldn’t say that one way is *always* better than the other but I disagree that the multiple exit strategy is best practice (and there’s plenty of programming books that agree with me on this).

    0
  52. 52

    im using strstr instead strpos, don’t need to worry about operators


    echo strstr('Hi there','Hi') ? 'found' : 'not found';
    or
    echo stristr('Hi there','hi') ? 'found' : 'not found';

    0
  53. 53

    isset and strlen .They are two diffrient thing.
    Mostly i got here x.php?y=0 and x.php?y=1
    Actually first is false because is was zero but mean while the data y=0.Which mean have length equalant to 1 and not empty.
    Tenanry –>Don’t use
    [code] x>j:x>j:x<j
    [/code].It’s become miss use.Use proper code.What the point of small footprint while not maintainable.
    UAC-User Access Control.Blacklist.What a joke since a real system should have blacklist login?
    Short cut to else should use switch
    [code]
    switch ($level) {
    case 'admin':
    case 'staff':
    break;
    default:
    tata
    }
    [/code]
    Dam is kindergarden php not advance php .
    Supression.Did you really need it.This is the second joke
    [code] try catch throw[/code]
    [code] if(!lol) { "goto" sleep(); } [/code]
    [code]Use transaction db[/code]

    Countermeasurement
    This artical just for bigginer

    0
  54. 54

    Thibaut Allender

    March 25, 2009 12:51 am

    Interesting tips for beginners. As pointed out, there’s so much more to tell about PHP but hey, this is not a manual ;-)

    Btw, it could be interesting to talk about utf8 compatibility of some functions, because few are compatible in fact. This is not a problem with english but french and other “exotic ;-)” languages have special chars, leading to some strange results when manipulating multi-byte chars. Hopefully, this will be solved in PHP6.

    0
  55. 55

    I agree with much of the tips and I find the article very good, big thanks to the authors.

    My 10 cents are (mostly in reply to the people’s comments above):

    There are different type of code optimization. Sometimes you save a millisecond of execution time by skipping an ‘else’, or sometimes you look more ‘hackerish’ if you skip this and that, but (!) imagine this : You work in a team of 50 programmers. You get a task to add a small functionality in a module of the system, rather fast just before the code freeze before the release. Now, 1 of your 50 colleagues wanted to look more skilled and he wrote the following:

    return $flow->isAvailable($this->getFeatures($this->isAdmin?$this->availableMods(4):$this->isMod?12:$flow->getusrfeatures()), $flow->currentApp? etc… etc…

    So, being a good programmer is great, using safe practices too, but on top of that the code must be easily read and interpreted by the next guy/gal working on it after you.

    Cheers, Marin

    0
  56. 56

    Thanks SM this is a really interesting article and has some ideas that I will use more often than at current.

    Thanks very much, more of the same please.

    Tim

    0
  57. 57

    Certainly an improvement over the earlier article, but there still seems to be an unhealthy obsession with micro-optimization resulting in less readable code. The isset trick might save you a microsecond but it’s intent is less clear than strlen.

    The place where the biggest gains can be made when it comes to optimizing PHP are almost always in the sections that talk to the database. There are plenty of mistakes that it is very easy to make here, even for seasoned programmers, such as asking for more data than you need or asking for the same data more than once. If you always check before querying that you already have the data you need, and if you are careful to only query the database to get what you need and nothing else, you’ll speed your code up far more than replacing strlen with isset.

    As for SQL injection, why have you not mentioned prepared statements? Using them make injections far more difficult to achieve, and have the added benefit of speeding up repetitive queries.

    0
  58. 58

    In p. 6:

    $host = strlen($host) > 0 ? $host : htmlentities($host);

    Even considering < instead of >, this example is still absurd and can be replaced with:

    $host = htmlentities($host);

    …since htmlentities('') === ''

    0
  59. 59

    Stefan Priebsch

    March 25, 2009 3:03 am

    In #5, you should have discouraged using ereg regular expressions. They are not binary safe, which can quickly cause security problems, and they will officially be deprecated as of PHP 5.3.

    0
  60. 60

    In p. 9 you say that using @ error suppression is slow. From my tests, using isset() instead of @ saves you around 0.2s on 1 million iterations, so it doesn’t matter at all unless you use it in very tight loops that are run millions of times.

    Please don’t spread that kind of misinformation, it doesn’t help anyone. The most important quality of code is readability, and premature optimization is evil.

    An example of a use case for @ error supression:

    $name = @$_GET['name'];

    Your alternative would probably be:

    if (isset($_GET['name'])) {
      $name = $_GET['name'];
    } else {
      $name = NULL;
    }

    Four more lines to accomplish exactly the same thing in 0.0000002s less time. And since that would make the source file a few bytes longer, you’re probably not saving any time at all. I would also argue that my version is more readable.

    I suggest replacing point 9 with “or” operator precedence trick (“or” operator has lower precedence than the assignment “=” operator):

    $page = (int) @$_GET['page']
      or $page = 1;

    0
  61. 61

    About regular expression functions versus string functions:

    What the authors were saying (and I agree with them) is that you only use regular expression functions when you really need them. Most of the time all you need is a simple string function.

    That said, their other point is valid: you can’t evaluate regular expressions with string functions, though I suspect some masochist beginners might try to nest string functions that duplicate one regular expression. That is a waste of development time, and I’m not even going to consider if it would possibly run faster.

    0
  62. 62

    @Pies

    “$page = (int) @$_GET['page']
    or $page = 1;”

    That, in my opinion, is truly truly horrible. Relying on the precendence of operators does not make readable code.

    My personal prefence for that kind of assignment is always the ternary operator, for example:

    $page = isset( $_GET[ "page" ] ) ? intval( $_GET[ "page" ] ) : 1;

    Also point 10 from the original post is a very bad trick to be teaching people, the codes intention is less clear than just using strlen().

    0
  63. 63

    Wow – I think that the article should have had a line inserted that says “If you actually read this, put the word flibbertigibbet in your comment so we know not to mentally put you in /dev/null”

    For example from a comment:

    “As for SQL injection, why have you not mentioned prepared statements? Using them make injections far more difficult to achieve, and have the added benefit of speeding up repetitive queries.”

    From the article:

    Although the use of naming conventions can help you keep up with what has and hasn’t been filtered, as well as what has and hasn’t been escaped, a much better approach is to use prepared statements.

    and

    Prepared statements offer the strongest protection against SQL injection.

    What’s the point of commenting if you’re not actually referencing the article? And the people complaining that “these aren’t very good optimization tips” – did they read the first paragraph? This was basically taking the exact same tips from another article and explaining why they are a good idea, a bad idea, or maybe usable in some situations.

    And by the way “flibbertigibbet”

    0
  64. 64

    Good things come out of OmniTI; PHP Advent, one of the best typographers in the business as Creative Lead, the best IA structure to their sites URL’s I’ve ever seen (my personal favourite) and now an excellent rebuttal to what was originally a fairly disappointing list.

    Nice work guys, just such a shame every PHP article here brings out the morons to wave their e-peens while highlighting their own stupidity and reading incomprehension in the comments.

    0
  65. 65

    Thanks very much for taking the time to comment. I’ll try to respond to some of these to the best of my ability.

    Robert (20):

    I think you’re right. We might send the editors a few edits like this to make sure this article is as helpful as we can make it. Thanks very much for pointing it out.

    Billco (36):

    We considered exploring the topic of performance optimizations in much more detail, but the article was already quite long, so we decided to focus on correcting the mistakes in the previous article. We might still write such an article in the future, and forgive me for saying so, but it sounds like you might learn a few things yourself.

    Darren (37):

    I disagree with your opinion regarding returns, but I understand your position. It’s difficult to suggest a practice that cannot be abused, but I think returning quickly is almost always simpler and clearer than keeping up with context. Even storing a return value to be returned at the end of the function requires this sort of context maintenance. Your exception is exactly what we’re proposing, so it’s possible that we agree more than it seems.

    I also understand your argument regarding the ternary. You seem like a smart developer, so the benefits of reducing the complexity in code are not very pertinent to you. What you describe as dumbing down code is something I strive to do by default, and I think it is a valuable practice. As we claim in the article, we’re proudest of our code when it’s the least impressive.

    Regarding tip 10, we completely agree with you. We considered making this point one last time, and perhaps we should consider a small edit to do so. For anyone else wondering, we don’t recommend the practice of using isset() instead of strlen() to determine the length of a string. It just happens to not be wrong like many of the others. In other words, the trick really is faster, but we think these inconsequential optimizations are almost always a waste of time. (A profiler should be used to determine what is and isn’t a waste of time.)

    Joe (38):

    The code is correct as written, and the strict comparison is the point. If it’s unclear, I’d be grateful if you could suggest ways to make it clearer.

    Patrick (42):

    Thanks much. Good to see you around. :-)

    Gordon (57):

    See my response to Billco (36). As a helpful reminder, you should never be making guesses about your performance problems. Use a profiler. We might write an article about this at some point in the future. Regarding the rest of your comment, you should try a bit harder to hide the fact that you did not read the article.

    Pies (61):

    To my knowledge, there is no misinformation in our article. Be careful not to base such claims on assumptions. When you’re wrong, which you are, you won’t have your politeness to help salvage your dignity.

    Elizabeth (64):

    Flibbertigibbet. :-)

    Steerpike (65):

    Thanks for noticing. :-) We’re proud of all of these things, and I really appreciate when people notice.

    Thanks again for all of the comments. I would very much appreciate knowing about any factual errors. If your disagreement is subjective, that’s also fine, and I’ll just remind you of something we say in the article:

    “Our hope is that you don’t just accept our opinion, but rather learn enough to form your own.”

    Thanks especially to everyone who has shared this article on Twitter and helped it reach the front page of Digg and the most popular bookmark position on Delicious. We are very grateful.

    1
  66. 66

    nice read as always, would love to see more like this

    dugg!

    0
  67. 67

    Nice. The best esoteric use of a Mr. T reference ever.
    Also…couldnt agree more. Thanks for the rebuttal. When I read the original article, I though I was doing something horribly wrong by insisting on using braces, pre-defining variables, and the liberal use of ===

    0
  68. 68

    Chris and Sean,

    This is great. For #6 Use Ternary Operators though, I was under the impression that using a ternary operators takes a hit on performance because behind the scenes PHP is forced to create an extra variable that is otherwise not needed in a normal if else statement. Therefore, they should never be used if you’re trying to create an efficient application. Any truth to that? If so, it’s worth mentioning in the list of reasons not to use them.

    0
  69. 69

    Thanks for the rebuttal :) I just read both articles and you fixed the original nicely.

    0
  70. 70

    Thank you so much for the good work!

    0
  71. 71

    #3 is a tip I am constantly trying to push in my projects.

    The most important thing you can do in code development is make it easy enough to follow for the least experienced member of your development team or contributors. The odds are that someone else is going to edit your code and the easier it is for them to edit the more likely that their edits will improve instead of hinder your code.

    0
  72. 72

    @mckt. You wrote: “Next time, read the article and look up the stuff you don’t know before claiming the author got it wrong.”

    If you re-read my comment, I wasn’t actually claiming anything about it being wrong. I was actually asking a question as I’ve never used comparison operators before to test for data type. Also, I actually did read the article and did look it up with a Google search. I guess the php.net page I landed on didn’t have === or !== in the table that was presented to me. Next time, I’ll dig deeper before I comment.

    I do appreciate the link that Tama provided. Had I seen and read this page before my comment, I would have had my answer. Thanks for the link Tama.

    -Joe

    P.S. @mckt. I take no offense to your post and appreciate the clarification. You should have flamed me. It’s good to have a dose of reality every now and then. :-)

    0
  73. 73

    Hi Chris.

    Question: When using PDO and binding parameters, is it still necessary to “clean” input to prevent SQL injection? Always? My understanding is that binding parameters will clean the input. Could you advise?

    Ex.
    $comment = $_POST['comment'];
    $stmt = $dbh->prepare(“INSERT :comment INTO table”);
    $stmt->bindParam(‘:comment’, $comment, PDO::PARAM_STR, 100);
    $stmt->execute();

    Your thoughts?

    1
  74. 74

    “we’re proudest of our code when it’s the least impressive”

    Beautiful. This reminds me of Dr. Johnson (Samuel):

    “Read over your compositions, and where ever you meet with a passage which you think is particularly fine, strike it out”.

    0
  75. 75

    @Sites, Binding parameters doesn’t clean input. It just (one hopes) separates the format of the query from the data. As the article mentioned in passing, though, some databases don’t support prepared statements, in which case your abstraction layer (presumably PDO) will have to do the separating. Behind the scenes, that’s probably going to boil down to escaping.

    But of course, escaping is a “default-allow” approach: It looks for malicious patterns in your input and attempts to neutralize them. These patterns have to be known in advance.

    But over time, a default-allow approach to anything (firewalls, viruses, SQL data) is almost certainly bound to fail. There are just too many determined and intelligent hackers, not to mention possible bugs in your abstraction layer, unexpected circumstances, etc.

    Chris wrote a nice article illustrating this point a while back. It shows that the effect of some escaping techniques can be nullified by the character-set of the database table.

    And there may be other types of problems that validation will prevent but parameter-binding would not. For example, an adversary might provide the string “Flibbertigibbet” when you ask for a postal code. This is not SQL injection, but it could lead to problems down the line if you don’t check to make sure that you’ve actually got a postal code before updating your database.

    Suppose in a different part of your code you retrieve the corrupt “postal-code” record and pass it, unvalidated, to a geocoding API. All heck could break loose.

    So do your adversary a disservice and validate your input. And as much as possible use a default-deny approach; in other words, make sure the input matches what you’re expecting and discard it otherwise.

    0
  76. 76

    Nice article. I’ll use this as reference when I’m trying to teach new people some things.

    Cheers,
    Darryl

    0
  77. 77

    #2: strpos manual:
    This function may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE, such as 0 or "".

    i think this is better:

    if ( is_int(strpos($authors, 'Chris'))) {

    0
  78. 78

    This is so newb-ish its not even funny … PHP is terrible, and these are extremely basic ‘tips’

    0
  79. 79

    For #3: I would add to the end that if your routines/methods/functions are festooned with conditional statements…it’s most likely time to re-think your design. For example, use case statements instead of if-else chains. They are a far simpler approach and much easier to read.

    0
  80. 80

    Adam Trachtenberg

    March 31, 2009 10:11 pm

    I am surprised that your rebuttals to #3, #4, and #6 don’t also mention that the concept of “saving space and time” by removing removing an else or dropping braces or using ?: shows a complete misunderstanding on how programs are parsed and executed (or that somehow the author believes that programs are charged by the character).

    Anyone who cares about PHP performance is using apc (or the like), and the actual syntax used in the source has been long since tokenized away when you’re hitting the opcode cache (to say nothing of the minimal impact even if you weren’t using apc).

    Also, in #4, the first example has exactly one assignment in all cases, while the second has at least one, and sometimes two assignments. Both have the same one comparison. How can the second example faster?

    Anyway, good piece, given that I would actively discourage 6 of the 10 tips in the original, and think the other 4 are just lame given the topic.

    0
  81. 81

    Nice article

    0
  82. 82

    Ahhh.. Much better. Nice!

    0
  83. 83

    Nice.

    I think the ternary operator is fine if used consistently for small simple things:
    $foo = isset($_REQUEST['foo') ? $_REQUEST['foo'] : ”;

    And to the comment about using “empty” language construct:
    Don’t.
    The silly thing has changed with every major release.
    Stick with isset() and then count() or strlen() or whatever is appropriate for the data type.

    And I must concur that using isset($string[$i]) instead of strlen is not really a Good Idea in general, even if it might be useful in some rare tight loop case.

    0
  84. 84

    very good tips. most of it should be common already

    0
  85. 85

    The popularity of smashing magazines well justify the number of morons in the world. This article is much better rewritten though.

    0
  86. 86

    wenderful
    صصصزةخسمثةخىمهىثزىثف

    0
  87. 87

    PHP is descriptive and verbose. We think code should be, too.

    I think this is said perfectly.

    0
  88. 88

    Thanks for going to the lengths you did, to correct an earlier article. That’s very good!

    0
  89. 89

    Another reason for not using single line if statements such as:

    if ($x==getRandomValue()) do something;

    …is that it is a nightmare to debug since most debuggers only allow breakpoints on a per line, not a per statement basis. How do you trigger a breakpoint if $x == getRandomValue() ?

    How do you know that the “do something” has been executed? If it is a function you’ll need to step into it, if it is a variable being set then you’ll need to put the variable in the watch window.

    I’m sure your co-workers will enjoy debugging that code! No thanks!

    0
  90. 90

    GQdGFO comment5 ,

    0
  91. 91

    Seems more like “basic” tips, but it doesn’t harm anyway

    0
  92. 92

    I like to use the ternary operator for simple conditional output for rows returned by a query, e.g.


    $users = ($rows == 1) ? 'user' : 'users';
    echo 'The search returned '.$rows.' '.$users;

    0
  93. 93

    $username[5]; imho is not good because it doesn’t work well with utf-8 strings or any character ser other than plain ascii. For this reason, this check may be fast, but it may also be wrong. In validation code, to be right is much better than to be fast.

    0
  94. 94

    The introductory paragraph of #4 is just plain wrong. I use the term “brackets” to refer to any one of (), [], {}, and even . Your usage may be different but don’t assert that everyone who doesn’t agree with you is in error.

    0
  95. 95

    I agree with the point #4, dropping brackets increased the amount of mistakes. And to void a bracket will saves you at most 3-15 seconds, while a logic error can ground you for many minutes, if not hours or a entire day.

    0
  96. 96

    …are you serious?

    “In November 2008 we published the article 10 Advanced PHP Tips To Improve Your Programming. Apparently, according to negative comments to the post, it contained some errors and some statements that are just wrong. We sincerely apologize for our mistake, and we are truly sorry for any inconvenience we caused by it. However, this simple apology is not good enough. To solve the problem, we asked Chris Shiflett and Sean Coates, two PHP gurus, to take a closer look at the article, explain its errors and make it perfectly clear what is actually right and wrong in the theory and practice. This article is a professional response to our article published a couple of months ago.”

    0
  97. 97

    Jesus christ, this post again? Why the hell would you “revisit” that horrible post? Why wouldn’t you just make A NEW POST with topics that are actually ADVANCED.

    SM, please stop the “advanced” php posts, PLEASE!

    0
  98. 98

    outstanding article !
    5 stars

    0
  99. 99

    This article is FAR from advanced. There more like common sense for newbies! I mean come on… to protect against SQL injections you made it look a lot more complicated that it needs to be… look at the big picture… you can be sure that pretty much all of the data in $_POST & $_GET for example are from sources you can not trust… so why not just escape the lot? I’ve done that for 6 years now and i’ve never suffered from a single SQL or XSS attack – because you simply “can’t forget” to escape it! Instead you have to remember to unescape it.

    How is this an advanced tip: return (!isBlacklisted($username) && (isAdmin($username) || isAllowed($username, $page));
    5 }

    You’ve made a nice, indented, easy to read, line by line block of code into an operator precedence mess of inverted conditionals… so well done… you made some nice code into a single line of garbage… and why exactly did you do that? Was the aim to just put on it 1 line, because you can? I really do hope not. How is that an “advanced tip”?

    Shortcut the else? Come on…

    Some advanced tips would be lets say… how about using the SPL to make objects iterative or to give objects native array support? So you can do things like: $names = new names();
    $names[] = ‘scott’;
    $names[] = ‘tom’;
    $names->save_to_db();
    print “Saved ” . count($names) . ” names.”;

    Which means new coders can use them as a standard array instead of having to remember object methods? Also, all the array functions will work on the new object.

    Kind regards,
    Scott

    0
  100. 100

    In item 5, strtr() is better

    0
  101. 101

    Or:

    $name;
    if (isset($_GET['name'])) {
    $name = $_GET['name'];
    }

    0
  102. 102

    You’ve said just about everything I wanted to say to the old article, so thanks for that. Well, almost…

    I use ternary operators. I don’t know, they make sense to me as long as they’re used properly. But I can see why some would prefer not to use them at all. I think that one is more an issue of coding style.

    Your comments on the error supression operator make sense, but for me it’s less an issue of using isset, and more an issue of just initializing everything. While it still has it’s place, I usually view isset as more of a red flag that I did something sloppy, rather than using it I usually take a few seconds and either initialize the variable in question or see if I should quickly refactor the part I’m working on.

    0
  103. 103

    very nice tips. thanks for sharing.

    1
  104. 104

    i wouldnt be surprised if there was a third version where he continues to combine apologing and wasting your time. the comment voting feature still works immaculately.

    why is my fake email mandatory?

    i dont know who i feel most sorry for.the person who ends up deleting this, everyone whoes tried to learn something from this or myself

    edit: go on, hunt down my ip address

    0
  105. 105

    What a well written list of tips – I have already bought and memorised Chris’s PHP Security book and followed it to the letter. I am always looking for ways to write cleaner faster code and this has given me a few more strings for my bow! :) well done ps, buy the book, the section on encryption alone was invaluable!

    0
  106. 106

    Some of these tips make your code less readable so I wouldn’t go with all your tips.

    -2
  107. 107

    Yes, these are valid operators.

    “===” means that they are identical with same data type and value.
    5 === 5 // true
    5 === “5″ // false

    “==” means that they are equal type might be different.
    5 == 5 // true
    5 == “5″ // true

    Same way
    “!=” means that they aren’t equal.
    5 != “5″ // false
    5 !== 5 // true

    For further info on this refer php site.
    http://php.net/manual/en/language.operators.comparison.php

    0
  108. 108

    Reading the previous article a lot of things seemed fishy, but this one is just awesome ! I was most surprised by how the suppression operator works, that seems … wrong. But I will check out the Scream extension, sounds nice.

    PS:
    Maybe some more useful tips would be:
    - the differences between ” and ‘
    - proper use of error_reporting, display_errors, and log_errors on prod / dev environments
    - how objects are passed by reference, and the clone operator (I’m surprised how many people don’t know this, and it can’t be re-stated enough)

    Again … awesome article !!!

    0
  109. 109

    Regarding point 3, return statement is not good at any line. It should be from last line !

    0
  110. 110

    Thanks for writing this article. Though the fact that this form is at the bottom of the comments is stupid.

    0
  111. 111

    To get around the false vs zero return of strpos, I like to use this idiom:

    // Prepend haystack with an unlikely character to force matches to be > 0
    if (!strpos(‘¤’.$haystack, $needle))
    print ‘Not here!’;

    0
  112. 112

    João Henrique Rocha Machado

    November 17, 2011 3:41 am

    How is that less readable if they suggest not use ternary operators for example?

    Btw, i really loved this tip(number 9), $albert =& $albus; looks soo wrong…

    0

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top