Fatal error: Call to undefined function preg_match()

Today’s crazy error of the day is:

Fatal error: Call to undefined function preg_match() …

Wahoo! A built in function being undefined!

So how’s this possible? It seems that if you reinstall PHP without compiling in PCRE (Perl Compatible Regular Expressions), you can get this crazy error. It’s a flag you may need to manually enable.

Permission Denied in the PHP Destructor and the Current Folder

I learned something new today, so I’m going to share two cool things with you.

  1. File access is screwed up during a destructor call in PHP. I will show you how to get around this.
  2. How to create a universal absolute path variable that refers to the current folder you are in.

For the application I was working on today, we needed to add logging. This was a quick and dirty log that would (append) dump whatever was on the page into a file. I was working in a framework I wrote, where each page is actually a class. Neat, but not really necessary to understand the problem.

Here’s the code:

function __destruct() {
    $handle = fopen(CURRENT FOLDER . ‘no_sync.response.log’, ‘a’);
    fwrite($handle, ‘– START — (v.’ . self::VERSION . ‘ ‘ . date(‘Y-m-d H:i:s’) . “)\n”);
    fwrite($handle, ob_get_contents() . “\n– END –\n\n\n”);
    fclose($handle);
}

Pay attention to that highlighted part and I’ll address it in a moment.

This code takes whatever is in the output buffer (which ultimately gets shown to the user) and chucks it in a file. Cool.

So how does it execute? I don’t call it explicitly. The __destruct is a special PHP function that gets automatically called when an instance of a class is about to get erased. It is rarely used by novice programmers because of its cryptic nature. But this is a good example where you might. 

Since it triggers when the class instance gets destroyed, I just need to unset the variable that contains the instance. Near the bottom of my code I added:

unset($FRAMEWORK); // my class is a property inside this variable!

And, as expected, everything worked. Yes, second try! Wait, second??

This isn’t how the code looked when I tried it the first time. That highlighted portion, “CURRENT_FOLDER”, was missing. If I’m writing to the current folder, I shouldn’t have to specify a folder path… Usually. This failed, even though the same exact code in the constructor worked fine.

It turns out that when you try to do file-stuff during the destructor, PHP is no longer in the original folder you started out in. PHP has “forgotten” where your script is and has reverted to the root folder (AKA “/” or “C:\”). This, in most systems, causes permission issues.

To get around this problem, you should be explicit about where you want to write the file. You can’t use relative paths (such as “…/logs/”). The “CURRENT_FOLDER” in my example happens to have the following value:

dirname($_SERVER[‘SCRIPT_FILENAME’]) . ‘/’

The great part about this is that it is not relative. It will be the fully qualified path to the folder the script was run from.

Note: from the command line, you should always type in the full path to the script. Failure to do so will render PHP unable to figure out an absolute path to your script. Just a tip for you people writing cron scripts. 😉

I hope that helps!

Boolean and 0.00

ARG. I encountered another potential issue in PHP that is due to loose types that is common if you are using a database back end.

$amount = 0.00;
if($amount)

Versus

$amount = ‘0.00’; // how data from databases comes
if($amount)

Guess what happens. Well, most people might say both should be TRUE, but that’s not true!

The first one evaluates like this:

  1. 0.00 is the same as 0
  2. 0 is the same as FALSE.
  3. Evaluate the IF condition as FALSE.

The second one evaluates like this:

  1. “0.00” is a string.
  2. A non-empty string is the same as TRUE
  3. Evaluate the IF condition as TRUE.

This is a predictable problem, but highly annoying when working with databases. Most people forget that a float field in the database could equal 0.00, but would evaluate as a TRUE when placed in a condition.

As in, when you get results from the database, the NUMBER 0.00 becomes the WORD “0.00”.

So the lesson here is to make sure you always convert your variables before doing conversions like that. As in:

$amount = ‘0.00’;
if(floatval($amount))

Of course, the best solution is always making comparisons explicit:

$amount = ‘0.00’;
if(0 < floatval($amount))

The Best PHP Book Out There

Advanced PHP Programming I’ve read quite a few PHP books, and most of them suck. Many of them contain the same or very similar material recycled with new examples. Only one stands out in my mind as truly exceptional: Advanced PHP Programming. I am willing to bet this is the best book out there for novice to advanced PHP developers. It is not the best beginner book as it has some advanced topics (as the title suggests), but the material it covers is seldom mentioned in any detail in other books.

The book is an excellent resource for novice programmers hoping to become “experts” in the field. Granted, the coverage in the book is a little superficial in some places, but it serves as an excellent introduction to advanced concepts. These concepts played a major role in my understanding of scaling PHP applications.

After developing PHP for nearly a year by the time I had read the book, I remember thinking how much time the book would have saved me had I read it earlier. Many of the lessons the book mentions are things novice programmers learn from trial and error or from tons of Googling.

The book most notably covers some very common problems a PHP developer unexpectedly faces at some point in their career:

  • Session management, especially when integrated with a database back end
  • Common security misconceptions
  • A real database abstraction layer layer (warning: difficult example for beginners)

It also covers some of the new features of PHP 5, which is still foreign and underused by many:

  • Exception handling
  • Object oriented development (with some best-practices included!)

Personally, and this is strictly personal, I feel very much more confident in a developer’s ability when I see her/she is able to write clean, object oriented code that uses exception handling. This is very common in C++ or Java, but is relatively uncommon in PHP. In general, these are good programming practices.

It’s been a few years since I first picked up that book, and even today, sometimes I skim through it and think, “Oh, I forgot about that!” The book was the single greatest investment I ever made in my PHP skills. I’ve recommended this book to every novice PHP developer I’ve ever met.

If you know PHP, but want to know PHP, buy this book. It’s the gateway drug into an advanced PHP programming high.

I find my analogy funny.

PHP Array Keys and Floats

Wow! I found another obscure “feature” of PHP! Array keys were silently round off into integers when I tried to index by floating point numbers!

We’ve all heard PHP is “smart.” It converts stuff for you. If you try to add “4” and ” 2 ” together, it will make 6, even though the two is really a part of a word that happens to contain the number two in it. You see, PHP is very forgiving about mixing variable types. It just converts integers into floats, floats into strings, and strings into doubles without hesitation.

So imagine my surprise when I was creating an array using floating point numbers as keys. Why floating points? Coincidence.

A little “trick” I use is to create an array using some unique value as the key so that I can ensure there are no duplicates. For example, when I am working with result sets for a user, I might use the user’s user ID as the key so that if the result set contained that user again, I can ensure they show up only once in my final array. Other times, I might use the username, since PHP accepts strings as keys. And here was my problem.

It just so happened that the “ID” in this particular case was a float, which is very unusual, but hey, it happened. You see, sometimes my application grouped stuff by strings. Other times numbers. It just so happened this time was a float because that’s just what I was given. Here’s some demo code.

$totals = array();
// grouping results by subtotal
foreach($result as $record) {
    $unique = $record[‘subtotal’];
    $totals[$unique] = $record;
}

Examine that code. Now some people might say, “but why not just format your SQL so that the results are already grouped!” Well, that’s beyond the scope of this discussion, but I’ll entertain the notion. For me, changing a 2 page long SQL query that examined, on average, 2 – 4 million rows was not an option. I’m sure you can sympathize. That’s not the point anyway.

The point is that when you run the above code and “subtotal” happens to be a floating point number, weird shit happens. The unique values looked something like:

0, 0.1, 1, 1.95, 2, 5, 9.95, 35.50, 35.90, 35.99, etc.

The grouped results looked like this…

0, 1, 2, 5, 10, 36, etc

So it was very surprising when the actual result had about half as many uniques as it should have. What happened? Things were getting rounded off! So since most of the values had decimals in them, they were getting lumped together with their nearby counterparts, silently screwing up my results!

The lesson here is that array keys *can not* be floating numbers. And if you assign floating numbers (numbers with decimals), you must convert (cast) them into strings. So to fix the original code snippet…

$totals = array();
foreach($result as $record) {
    $unique = $record[‘subtotal’];
    $totals[(string) $unique] = $record;
}

That makes the number 0.1 into the string “0.1”. Thus, PHP is able to tell “1.1” apart from “1”. Remember, this only applies to array keys since PHP will normally distinguish the two numbers correctly.

And this is one of the many reasons how PHP trains programmers (including me) to be sloppy about their data types. Oh well.

Isset and NULL, Array Keys and NULL – ANNOYING Part 1

I have two VERY annoying bugs to share with you in PHP. After this, I’ll make a post about an annoying thing I found in MySQL regarding NULL values too.

This is a relatively known “bug” to some people, but often forgotten. In fact, I learned about this over a year ago, but completely forgot until now when I came across impossible bugs caused by it. The function isset() returns FALSE for variables equal to NULL, despite the fact they are set!!

The PHP function isset() returns whether a variable “is set” or “does exist.” UNFORTUNATELY, that’s only half true. Take the two following code samples. One will act as you think, and the other will not.

$myName = ‘Michi’;
isset($myName); // TRUE

$myName = NULL;
isset($myName); // FALSE. @$!%#*?

For those of you screaming bloody murder, it gets worse. Consider the following:

$names = array();
$names[‘a’] = ‘Michi’;
$names[‘b’] = ‘Kono’;
$names[‘c’] = NULL;

Now observe the results of the following applied to that array.

isset($names); // TRUE
isset($names[‘a’]); // TRUE!
isset($names[‘b’]); // TRUE…
isset($names[‘c’]); // FALSE, %@#*^!

That’s right, the function ALSO ignores NULL array keys!!!

 Anyway, I’m sure this will introduce more than its fair share of bugs in code without people ever even realizing it. Ever. Since this throws up no warnings and will very, very rarely be a factor. But trust me, sooner or later, it will cause bugs, whether or not you’ve noticed.

Here are the fixes to this insanely stupid bug. Well, some people call it a “feature,” but it’s a bug in my book. That or the function should be renamed to not_null().

array_key_exists(‘myName’ ,get_defined_vars()); // TRUE
array_key_exists(‘c’, $names); // TRUE

The first line checks to see if the variable is set by comparing it to an array that contains all variables in the current scope. The second line checks to see if the specific key is set (obviously).

Isset() is only good for variables you know will never be NULL, and for cases where you are not doing type-sensitive checks (triple equals sign). Luckily, that’s 99% of the time in PHP.

A New Library: NSFW JS — Protect Your Visitors at Work

I wrote a drop-in library in JavaScript that protects your visitors from accidentally viewing material not suitable at work.

It is based on an article about adding a new “NSFW” attribute:

I am now proposing a new attribute:

rel=”nsfw”

NSFW is an abbreviation often used to indicate that content is “not safe for work.”

Check out the demo and source code here. There are tons of examples on the page so I won’t post any sample code here. It could probably be a little more efficient, but I got lazy. But despite my “laziness,” the script does three major things:

  1. All marked <a> tags prompt the visitor
  2. Marked <img> tags are replaced with a placeholder until they are clicked on.
  3. Marked <div> and <p> tags masked so that all the text is the same color as the background until it is clicked on.

I went a step further and made it also check the CSS class name as well as use the text “adult” interchangeably with “nsfw”. Here is an example of #2 (the content is safe for work, despite the warning message):

For those of you still reading, the version I wrote took me longer than I hoped because I had one major goal in mind:

Dropping this script in should not break any site, ever.

Well, that’s difficult given the current state of the Internet: tons of links out there already have “onClick” actions. Any regular drop in script would overwrite those actions! So I had to make sure my version would work even in those situations. So, granted, it probably won’t work exactly as I’m hoping on some small percentage of sites out there (who knows), but for 99.999% of the cases, this should work.

I have appropriately called this script Nsfw JS and released it for free as usual.

Update: I plan on releasing an update to this library soon, so if you plan on adopting this now, make sure to check back later.

Clean Coding

Consider the following source code:

$uSess = uLogin($uName, $pwd);

That’s a fictional piece of code that might exist in a login script. The uLogin function, short for “user login” versus, perhaps, aLogin for “admin login”, accepts two parameters: a username and a password and assigns the result to a session variable called “uSess”.

This sort of code is very common, and I hate it. By looking at the code, there are numerous problems with how the variables and function are named that can cause long term problems. The proper naming should be:

$USER_SESSION = userLogin($username, $password);

There are two primary changes I have made.

  1. Globals and constants should be capitalized. While technically $password is a global variable, in this context, I am referring to variables that are accessible in any function or class, which sessions are. Since the result is being assigned to some session variable (in my example), it should either be in all caps or use the $_SESSION global array.
  2. No abbreviations!!! Was it passwd? Pass? Psswd? Pwd? Password? Pword? You might remember now, but you won’t in three months. And if someone else in the same namespace decides to create another variable referring to another password, things can get VERY messy when you end up with code with $pwd, $password, $pass, and $pass2 all mixed together near each other. It would have made things much simpler had each person who added the variables used a fully qualified prefix and name such that, instead, you ended up with: $password (the original), $adminPassword, $systemPassword, $databasePassword, etc.

It’s only a few more letters to type that will save you hours some day in the future. It’s worth it.