WordPress LOVES backwards compatibility as can be witnessed by the minimum-allowed WordPress PHP version remaining at 5.2.4 a decade after its end-of-life date.  It  may be  one of the reasons they have continued to garner market share.  Don’t require people to do anything to improve their site and they’ll wallow in complacency.  It makes sense.  Inertia is a big thing to overcome.  If you are a business focused on writing content, selling widgets, or doing just about anything else other than managing websites, upgrading software is way at the bottom of the priority list.

This backwards compatibility is one of the reasons why WordPress continues to RECOMMEND PHP 7 for performance and security reasons but allows the minimum WordPress PHP version to remain 5.2.4 without breaking the core application.    It is the reason why so many plugins, including Store Locator Plus, continue to do some convoluted things to reach that PHP 5.2 audience and keep their potential market as big as possible.

We’ll leave the bewilderment as to why ANYONE would be running software that had its end-of-life over a decade ago by the wayside for now.

Leaving PHP 5.2 behind

Besides the fact that it has security and performance issues, I never liked having to support the the low-end of the WordPress PHP version scale.    Until recently, however, it was not much of an issue to write code that worked in PHP 5.2. Sure,  it was far less elegant and therefore easier to read and thus maintain  than its PHP 7 counterpart. The PHP 5.2 solution was only slightly less elegant than the now 2-year-old PHP 5.6 “flavor”.    Sure we gave up anonymous functions and the [] array notation short-hand that makes code easier to read.  Performance-wise and functionally we lost little by “staying on the 5.2 train”.

In version 4.9 of Store Locator Plus we started making the code smarter.   It includes self-instantiating objects that only come into existence, and consume memory and other resources, at the last minute.   Part of this magic relies on a long-time PHP function that called spl_autoload_register().     Name your PHP files in a consistent manner and use best-practices of hosting the primary class only in that file and you are off-and-running.   The code has far less require() calls.  Less lines of code means less places for errors (and typos) to hide.

We soon learned that we could make our code even more efficient by creating a self-instantiating singleton style model with little code.    By writing a simple get_instance() method we could now replace require statements AND new MyClass() statements and replace those with a single $this_thing = MyClass::get_instance().

Since most of our main plugin and add on plugins only ever need or want a single copy of an object to be alive at any given time, this is a BIG step forward in code simplification.  We also lose nothing by including that method as we can still use the $that_thing = new MyClass() method if we need to make fresh copies of an object with its own properties.    It was super-cool.

Our first PHP 5.2 obstacle,  Don’t Repeat Yourself

BUT our cool new model will not run on PHP 5.2.  At least not without a LOT of repeated code.

The issue?    PHP 5.2 does not have a way to reference the CALLED class without going through resource-intensive and messy gyrations that were not only ugly but often unstable.     PHP 5.3, however, has a very elegant and fast get_called_class() method.

That PHP function works beautifully with the aforementioned spl_autoload_register() PHP function when using a BASE class on which all your other self-instantiating singleton classes are built.    The autoload opens the file we need which contains the class when an unknown class name is reference.   The get_called_class() magic-sauce can then be employed in something like ::get_instance() within that class’ public methods to self-instantiate.   That is important because we don’t want to replicate the 8 lines of code for get_instance() in every-single class we create.

Without PHP 5.3 DRY is now a “repeat yourself often” mantra with this new object invocation design.

Our latest PHP 5.2 obstacle, CSV parsing

Recently we ran into a general usability issue with PHP and the most-used feature of our most-popular add on, CSV import of locations.  It turns out that PHP has some very fast and well-tested CSV parsing tools built right into the core language.  This is PERFECT for what we need but NOT on PHP 5.2.

The problem is that PHP 5.2 does provide the fgetcsv() function.  It worked great for most of the last 5 years people have been importing locations with our plugin.   Recently, however, we’ve been having a lot of customers complaining their data is not importing correctly.    As it turns out, Excel is churning out “modified” versions of the CSV data when a customer downloads a file, updates a few locations, and saves as CSV.

Excel is going by the RFC4180 specification for CSV files.  That  specification, it turns out, does NOT consider the backlash () a valid escape character in a CSV file.    The ONLY valid escape character is the quote character, or to be more specific a double “double quote” character.     If you have a piece of data in a CSV file, let’s say  name like My “Super Special” Place then the only valid way to represent that in a CSV file is to double-up the quotes.    When you look at the raw CSV file (such as with a text editor, not a spreadsheet app) it should like like this:

PHP 5.2, however honors the old-school “Sybase” specification which allows a backlash as an escape character.  Not only that but the backlash is THE DEFAULT escape character.    To make matters even more interesting is the default is different for the two corresponding PHP functions.

When creating a CSV file from an application and using fputcsv( array(  ‘My “Super Special” Place’ ) ) it will create a file like the one above.  Yay for standards.

However with PHP 5.2 when you READ a file the “Sybase standard” also applies.   The above file loads in perfectly fine, as it should.   However create a valid CSV file with a name like My Place\ instead an all hell breaks loose.   The CSV file might look like this:

Cool no harm no foul, right?    Wrong!    PHP’s fgetcsv() reads that as an “escape the quote” character.    In this particular case you “lose” the backlash.  Your data is no longer My Place\ but My Place.

Ok, A silly example.  But the real problems appear when you have MULTIPLE fields.

Or our real-world PHP 5.2 test case:

Example CSV File

Example CSV File

Guess what PHP 5.2 does with that?    It decided that \ would escape the ” so your Name field is now  My Place, John”s Island and your city is now SC and your state is nothing.   A huge mess.

This mess is made far worse since a LOT of spreadsheet applications, which nearly EVERYONE uses to edit CSV data, will export the name field as My Place \ exactly as shown above which is perfectly valid per the RFC 4180 specification.

Welcome PHP 5.3 and standards

Luckily PHP 5.3 came along and allowed people to not write their own custom CSV parsers which run FAR slower than the compiled PHP engine’s version.    As of PHP 5.3 you can specify what the valid escape character is.   You can even set it to the RFC 4180 standard double quote. Imagine that!

And that is EXACTLY what we did in Power 4.9.2 and yet again we find ourselves being a little-less held-back by not having to write code to a decade-old language specification.

PHP Versions and the release and end-of-life dates

PHP Versions and the release and end-of-life dates

Now if we could just get those thousands of customers on PHP 5.3 and 5.4 to upgrade to AT LEAST 5.6 we’d be getting somewhere.  We’ve already taken some flack for “forcing” people to upgrade to 8-year-old technology from their beloved 10-year-old crap they’ve been using for years.    Progress is painful.

 

 

 

Leave a Reply

%d bloggers like this: