WordPress and PHP

I got a bill from 1&1 / IONOS last week for PHP 5.6 Extended Support. I was a little surprised by this, since I thought I’d already taken care of updating PHP to a supported version, but it turns out that I was remembering updating from 5.4 to 5.6 three years ago. (Tempus fugit.) It looks like 5.6 reached EOL at the end of 2018. So I guess I’m paying $7 now for not having upgraded PHP in a while. I went ahead and updated to 7.2.15, so I should be good now for a while, though I guess I should update to 7.3 at some point. And I’ve got WordPress updated to 5.1.1 too. Everything still seems to be working, which is nice.

Every once in a while, I think about switching to some kind of managed WordPress install, so I don’t have to worry about this stuff anymore. Maybe just the $5/month plan from wordpress.com or something like that. But I still like futzing with this stuff a little, so for now, I’ll stay with the traditional web hosting plan, where I’m free to mess things up and forget to update PHP and stuff like that. But I think I’m getting close to the point where I’m going to want to hand this stuff off to somebody else and just concentrate on the blogging and not worry about the sysadmin side of things. Maybe in another three years.

PHP 5.6

I got an email from 1&1 this morning, telling me that if I didn’t switch from PHP 5.4 to PHP 5.6, I’d be subject to a $7.19 monthly “extended support” charge for using an old version of PHP. Fair enough, I suppose, though I didn’t even realize I was still on PHP 5.4.

I remember at some point in the past either updating it, or trying to update it and failing, but that was probably a long time ago. Maybe that was from 5.2 to 5.4 or something like that.

Either way, this site should now be on PHP 5.6. This post is basically just a test to see if the site still works. I don’t think I have any WordPress plugins that won’t work under 5.6, but I guess I’ll find out soon.

xdebug

I thought I’d written up an entry on Xdebug for PHP a while ago,  but apparently not. (Or, if I did, it’s not coming up when I search for “xdebug” for some reason.) Anyway, Xdebug is a debugging tool for PHP. It’s definitely worth enabling, if you’re doing anything with PHP that’s in any way non-trivial.

It’s a bit hard to figure out the best way to get started with it under Windows. It turns out to be pretty easy, though, given a few pointers. First,  go to the wizard page, and paste in the contents of a phpinfo() call, run on the machine you’re installing to. This will then tell you exactly which file to download, where to put it, and what to add to your php.ini. Much easier than trying to figure that stuff out yourself!

A few other pointers:
– Depending on how you download & copy the DLL over, you may need to unblock it. (Blocked files really annoy me, by the way. I don’t know whose idea that “feature” was, but it was not a *good* idea. See here for some ways to unblock multiple files easily.)
– Xdebug can add color to your var_dump() calls. Add “set html_errors = On” to your php.ini to enable this. I’ve found it to be very helpful when looking at a complex object. (Of course, there’s always krumo for that too.)
– To get debugging working under Komodo IDE, take a look at this document. One thing that was confusing to me was that debugging locally is still considered “remote debugging”.

Also, on a related note, I’m not sure I ever mentioned that, after looking at a few options, I settled on Komodo as my PHP IDE of choice. It’s reasonably fast and easy to use, and the debugger works pretty well. There are a few things about it that I’m not too fond of, but overall, it’s really good.

Drupal Rules

I haven’t blogged in a bit, and I have a few random items I want to write up. I’m doing a lot of work with Drupal, and I’m still learning some little tricks here and there.

When I’m writing custom code, I often use Drupal’s cache. That’s pretty easy to do, with cache_set and cache_get. I recently found myself in a situation, though, where I wanted to clear a certain item from cache any time a user created or edited a node of a certain type.

It turns out to be really easy to do that with the Rules module. Just set up a rule that is triggered on insert or update of a certain node type, and make the action a simple line of PHP code:

cache_clear_all(‘your_cache_key’, ‘cache’);

Easy!

Stumbling my way through the Drupal API

I’ve had to fix some interesting problems at work recently, related to a Drupal site that we’ll be rolling out soon. I just finished fixing one issue that, while seemingly minor, took quite a while to figure out.

I’m really glad to have come up with a good solution. The thing that amuses me most about this is that, after more than eight hours of messing around, the final solution involved writing only about a half-dozen lines of code.

The problem, in a nutshell, is that we have a content type in the system that represents a university. There’s a location field on each node with, minimally, city and country specified. The user can search for locations, using some custom search code, and the search results are displayed via a standard Drupal view. We allow the user to sort the results by one of a few different fields, with the sort drop-down exposed from the view. This works fine, except when sorting by country. On the location record, only the two-letter country code is stored, for instance “AE” for “United Arab Emirates”. So, when you sort by country, it’s really sorting on country code, so “AE” goes to the top, which isn’t really what the client wanted.

Of course, the first thing I did was Google the problem. I found this issue discussion, which pretty much matches my problem. There was a suggestion in the comments there about using hook_views_pre_render to re-sort the results right before displaying them. That works great, if you’re not paging results. But, if you’re pulling results back one page at a time from a large result set, this doesn’t work, since the pre-render hook only gives you the current page.

So I figured out that I really need to sort by country name at the SQL level, while retrieving results. This led to my next problem, which is that, even with the location module installed, there’s no SQL country lookup table in Drupal. The list of country codes and names is just stored in code, in an array, which can be retrieved via _country_get_predefined_list. (You shouldn’t call that directly, though, of course; you should use country_get_list.)

So off I went to find a module that could give me a SQL table with country info in it. The countries module does that, and a bit more. So, I installed that and figured out where the country table was. Then, my next blind alley was figuring out how to join to the new country table in a view. I was hoping I could just add a join to it in the view definition, and go from there. Well, I still don’t know that much about Drupal views, and it didn’t seem possible to do that easily.

So, the next blind alley was to see if I could alter the view SQL with hook_views_query_alter, which seemed sensible. Well, the query object that you get from that hook isn’t a nice simple query object that can easily be changed, so that turned out to be another dead end. (It’s likely possible that I could have figured it out, but it seemed like the wrong approach.)

Then, finally, I stumbled across this SO question. The one answer posted there led me in the direction of modifying the query with hook_query_alter, which can be used to modify just about any query Drupal issues to MySQL. So, finally, I found a workable solution.

hasAllTags('views', 'views_university_search')) {
    $ord =& $query->getOrderBy();
    if (array_key_exists('location_country', $ord)) {
      $query->addJoin('INNER', 'countries_country', 'cc', 'cc.iso2 = location.country');
      $ord = array('cc.name' => $ord['location_country']);
    }
  }
}

So that’s it. I add a join, and replace the ‘order by’ clause. About a half-dozen lines of code. Oh, and I now also understand passing by reference in PHP a little better too!

random PHP functions

I’m still doing a fair amount of PHP work. Right now, it’s all Drupal, for a site we’re rolling out very soon. I keep stumbling across random PHP functions I hadn’t heard of before, and that turn out to be nice little time savers. Two examples:

  1. curl_setopt_array: I used to just call curl_setopt() a bunch of times to set all my options Now I can set a bunch of options in one fell swoop.
  2. http_build_query: Nothing I couldn’t previously do with simple string concatenation, but this is much cleaner.

PHP

I’ve been doing enough PHP work lately that this blog post really speaks to me. Here’s a good quote:

PHP isn’t so much a language as a random collection of arbitrary stuff, a virtual explosion at the keyword and function factory.

I kind of like Drupal, which is of course written in PHP, but I think I’d like it more if it was written in… something else. I’m not sure what.

You can certainly write good things in PHP, and Drupal is an example of that. CodeIgniter seems like a good thing too,  though I haven’t had much experience with it.

I recently had to do some work on what I’d call a “legacy” PHP site, which was basically all PHP spaghetti code, poorly done HTML, and questionable JavaScript. I wonder how many sites like that one are out there, written 5 or 10 years ago, possibly by an amateur, and working *just* well enough that nobody wants to pay to rewrite it from scratch. Probably a lot!

Drupal 7 Development

I’m continuing my somewhat slow attempt to become a Drupal expert. After finishing up a couple of general Drupal books from Packt, I started “Drupal 7 Module Development,” also from Packt. I got up to chapter four, then put it down in frustration. I’ll likely pick it up again, but it’s not an easy book to read straight through, with little prior Drupal dev experience.

So, then I picked up “Pro Drupal 7 for Windows Developers,” and I’m doing much better with that one. I just finished chapter 5, which walks you through the creation of a simple, but non-trivial, module. I found it fairly easy to follow, and a good start. The book is (obviously) written for Windows programmers looking to learn Drupal, specifically ASP.NET developers, so it’s a good fit for me.

There’s still a lot more to learn. Drupal’s API and hook system are fairly complex and extensive. But I think I’m on the right path.

PHP IDEs

Since I’m doing more and more PHP development, I’ve been spending a bit of time trying to figure out if I can put together a decent development and debugging environment. Up until now, I’ve just been using Notepad++ (on the PC) and TextMate (on the Mac).

I’ve switched over to Komodo Edit on both platforms now, and that works pretty well. To do debugging, you need to spend $300 on Komodo IDE. But Komodo Edit does a lot, including auto-completion, syntax checking, and the ability to drill down into function definitions.

I like the idea of having a debugger, of course, so I decided to explore a couple of free IDEs that would support that. Netbeans looks nice, but it’s pretty heavy. Eclipse PDT is a bit better, but still kind of bloated. I think I may have to spend the $300 on Komodo IDE.

Drupal 7 on Windows

I have a fairly reasonable “WIMP” stack (Windows, IIS, MySQL, PHP) running on my work machine now, and I wanted to document how I got there, for future reference, or for anyone who might stumble across this blog post. My setup has evolved over time, so I’m not 100% sure if these instructions would work exactly right from scratch.

There are some ways to get a Drupal-compatible “WAMP” stack (Windows, Apache, MySQL, PHP) running on Windows pretty quickly, but most of the stuff you really need to do in Drupal works OK in IIS. And I think that the approach I outline below gives you the most flexibility in terms of also using the components for stuff other than Drupal.

In these instructions, I’m creating a Drupal site named “drupal-7-test”, but it doesn’t really matter what you call it.

  1. Get Web Platform Installer from http://www.microsoft.com/web/platform/.
  2. Use Web Platform Installer to install “IIS 7 Recommended Configuration.” You may also need to install URL Rewrite if you don’t already have it.
  3. Install MySQL via the MySQL Installer for Windows. (Do not use Web PI.) Select “developer default” to get the MySQL Server, Workbench, and a few other useful things. For configuration, select “developer machine.”
  4. Install PHP 5.3.x from http://www.microsoft.com/web/platform/phponwindows.aspx with Web PI. (This will pull in a few other necessary components.) (Do not install the PHP for WebMatrix — click the link on the above page.) (Oh, and the page still says “PHP 5.3.5,” though the actual installer has been updated to a more recent version.)
  5. In IIS Manager, go to “default web site” and click “PHP Manager”. Make a note of the location of the config file and the error log. Click “configure error reporting” and select “Development machine”. Click Apply.
  6. Get phpMyAdmin from http://www.phpmyadmin.net and unzip it to c:inetpubwwwrootphpmyadmin. Go to http://localhost/phpmyadmin and run through the setup.
  7. In phpMyAdmin, create a user named “drupal_7_test”. Click the checkbox to also create a database of the same name, and give that user all rights to it.
  8. Get Drupal 7 from http://drupal.org/download and unzip it to c:inetpubwwwrootdrupal-7-test. (The standard Drupal 7 download includes a web.config that enables clean URLs for IIS, given the MS IIS Rewrite module.)
  9. Give IIS_IUSRS modify rights to sites/default/files.
  10. Go to http://localhost/drupal-7-test and run through the setup. Use the MySQL database & user created earlier.
  11. Go to the status report in the Drupal admin and check that everything is working OK.

Random follow-up notes
It’s June 10, and I’m setting up a WIMP environment on my ThinkPad. I’ve also recently set up a WIMP environment on my new work desktop, so I’ve got a few follow-up notes on this post.

  • You may need to enable CGI on your machine, if it’s not already enabled, to get PHP working. See here for details.
  • As an alternative to the full MySQL installer I linked to above, you can also use the stripped-down version that can be found here.