The Web Won’t Forget Alex King

If you use a WordPress site, either as a visitor or owner, you’re using code that Alex King, one of the original developers of WordPress, worked on.

He passed away after fighting cancer for 2 years but his online presence lives on in the form of his blog with it’s deep archive of posts going back years, and in so much code that it’s humbling to look at his projects page. Looking through the svn log of WordPress trunk shows he still had a hand in helping the WordPress project until relatively recently:

trunk$ svn log|grep alexkingorg
props alexkingorg for the initial, long-suffering patch.
props alexkingorg. fixes #24162.
Props alexkingorg
`` instead of just `media`. props alexkingorg, see #22676.
Add $post_ID context to the pre_ping filter. props alexkingorg, devesine. fixes #18506.
Add filter so the users can select custom image sizes added by themes and plugins, props alexkingorg, fixes #18520
esc_textarea() and application for obvious textarea escaping. props alexkingorg. fixes #15454
Escape links by default. Props alexkingorg. see #13051
Safely include class-json.php, class-simplepie.php and class-snoopy.php, props alexkingorg, fixes #11827
Fix user creation from admin after changes for #10751. Fixes #10811 props alexkingorg.
Hooks needed to allow alternate category admin inteface. Props alexkingorg. fixes #3408
Wrap cat name in CDATA. props alexkingorg. fixes #3252

I’m sorry I never met Alex, however I remember working virtually with him and Adam Tow on AllThingsD which seems like a lifetime away now. Adam has a great article on Alex on his blog, as does Matt who went into detail about Alex’s involvement with WordPress going back to the days of b2. I had completely forgotten the CSS competition he mentioned!

Alex, your legacy lives on.

WP Super Cache 1.4.5

WP Super Cache is a fast caching plugin for WordPress. It will help your site run faster and serve more traffic.

This is a security and bugfix release.

  • Some servers display a directory index when no index.html is found in a directory. That may reveal the filenames of cache files.
  • There were issues in the settings page that might allow an attacker to browse or delete files named index.html.
  • PHP Object Injection could occur if an attacker managed to inject malicious code into the legacy cache meta files.

When you upgrade, your “legacy cache” files for logged in users will be deleted. This may have an impact on your site:

  • If your site is slow at generating new pages.
  • If you have many known users (logged in users or people who comment).

Your site will suddenly have to generate new cache files for all visiting known users.

Relying on caching like this is not recommended for these types of users as it’s very inefficient. Each user has a separate cache file that must be checked whenever the plugin does administration work like cleaning up stale cache files.

If most of your traffic is anonymous users who don’t comment you don’t need to worry about this.

Directory Listings

If a server is configured to show directory listings it will show files and directories in the cache directory to visitors who access those directories directly through their browser. This might reveal private posts, and in the case where legacy caching is enabled for known users the login cookie was stored in “.meta” files that could be downloaded.


Files named “index.html” were added to the main cache directories to stop remote users viewing the contents of the cache directories. Unfortunately it’s not possible to add empty index.html files to the supercache directories because those files could be served by accident to legitimate visitors of the site. However, the plugin will also add a directive that disables directory listings to the file cache/.htaccess. You can now also change the location of the cache directory on the Advanced Settings page of the plugin. If you can’t disable directory indexing on your server and you have private posts you should change this location and use PHP mode to serve cache files.


If a directory index is found in the cache directory it will show a warning like this to administrators:

index.html warnings

Clicking the logout link will log everyone out, except the user who clicks it, but it guarantees that the login cookies are updated, just in case someone has copied the cookie from an old meta file.

Directory Traversal and File Deletion

User input in the settings page wasn’t properly sanitised. The code that sanitised directory paths when deleting cache files wasn’t secure and might allow an attacker to view or delete files named index.html. Deletes are protected by a nonce, limiting the useful lifetime of the URL however.

PHP Object Injection

The plugin used serialize and unserialize to store data in “legacy cache” meta files. This might be used to perform a PHP object injection attack. Serialised data is now stored as JSON data.

The format of legacy cached files has changed. The files in the meta directory no longer have a .meta extension. They are .php files now and each file has a “die()” command to stop anyone loading them.
The data stored in those files is now stored as JSON serialised data. The login cookie is an MD5 hash now as well.
When you upgrade the plugin your existing legacy cache files will be deleted and regenerated as visitors use your site.

Apart from those security fixes there have been a number of enhancements and bugfixes:

  • Disabling the plugin no longer deletes the configuration file. Uninstalling will do that however.
  • Enhancement: Only preload public post types. Props webaware.
  • It’s now possible to deactivate the plugin without visiting the settings page.
  • Fixed the cache rebuild system. Rebuild files were deleted immediately but now survive up to 10 seconds longer than the request that generate them.
  • Minor optimisations: prune_super_cache() exits immediately if the file doesn’t exist.
  • The output of wp_cache_get_cookies_values() is now cached per visit.
  • Added PHP pid to the debug log to aid debugging.
  • Various small bug fixes.
  • Fixed reset of expiry time and GC settings when updating advanced settings.
  • Removed CacheMeta class to avoid APC errors. It’s not used any more.
  • Fixed reset of advanced settings when using “easy” settings page.

This release wouldn’t be possible without the help of Brandon Kraft, Dane Odekirk, Ben Bidner, Jouko Pynnönen and Scrutinizer. Thank you all!

WP Super Cache 1.4.4

WP Super Cache is a full page caching plugin for WordPress. It creates static pages that are served quickly by the web server.

Light Trails in Blarney

Over the weekend there was a flurry of excitement as not one, but two releases of the plugin were made in quick succession. The second to fix a bug introduced in the first. I’m very sorry about that.

WP Super Cache 1.4.3 fixed a security bug in the cache file listing section of the plugin settings page. A carefully crafted query by a third party would cause an XSS in the file listing. While serious, the owner of the blog cannot be tricked into loading the file listing page by way of an image or public link as a nonce is required to load it. The attacker would have to ask the blog owner to visit the cache listing page manually. Thanks to Marc Montpas from Sucuri for reporting that.

WP Super Cache 1.4.4 fixed a bug introduced in the previous version where queries with GET parameters caused a fatal error. Thanks to webaware on the forums for reporting that and including a patch to fix it.

If you’re using an older version of WP Super Cache you’re encourage to upgrade to 1.4.4 as soon as you can.

PHP Notice: Undefined variable: _SERVER in ..

I upgraded Linux on this server a while back and in the course of that upgrade PHP was upgraded too, to version 5.5.9.

Since I had a modified php.ini it asked me to check over any new options. There were a few but I fixed anything that looked like it might break things. I saved the php.ini and let the upgrade go on.

Clearing up bugs

Some time later I saw odd notices in the PHP error log. Usually it referred to wp-comments-post.php but files outside of WordPress raised the warning too:

PHP Notice: Undefined variable: _SERVER in ..

It turns out the fix is rather easy. Jacques Marneweck on his blog posted a solution. Simply switch off “auto_globals_jit” in your php.ini and restart Apache (if required).

From the PHP manual entry for auto_globals_jit:

When enabled, the SERVER and ENV variables are created when they’re first used (Just In Time) instead of when the script starts. If these variables are not used within a script, having this directive on will result in a performance gain.

The PHP directives register_globals, register_long_arrays, and register_argc_argv must be disabled for this directive to have any affect. Since PHP 5.1.3 it is not necessary to have register_argc_argv disabled.

A bug

It looks like the bug is ancient although I’m not using APC, and the JIT compiler can be fooled if you access the super globals like _SERVER through variable variables. Sneaky!

The default for auto_globals_jit is “On” so next time you upgrade PHP keep an eye on the error log.

WP Super Cache 1.4

WP Super Cache version 1.4 is out now. This release finally removes the mfunc, mclude and dynamic-cached-content tags as I warned about three months ago.

If your site uses that dynamic cached content functionality do not upgrade yet. There is a replacement dynamic cached content system but it’s not compatible so you’ll need to update your themes and helper plugins. It’s not difficult but there’s a lot to take in. I hope the example plugin and explanation in that post gets you most of the way there.

If you don’t use mfunc and it’s friends then you should upgrade immediately and it should be painless.

This release also has a few bug fixes and other features. It will now try to repair broken installs after a site migrates. It will update the wp-config.php and rebuild wp-content/advanced-cache.php. It will also delete tags and category cache files when a post publish status changes.

The shiny new dynamic content in WP Super Cache

Edit: There’s a small bug in WP Super Cache 1.4.2 in the file dynamic-cache-test.php. Grab the development version instead. The documentation in the filehas been updated too. Copy the new file into wp-content/plugins/wp-super-cache/plugins/.

With the next release of WP Super Cache in a day or two the long awaited move away from mfunc, mclude and friends will be complete.

This means that if you have been using mfunc, mclude or dynamic-cached-content the dynamic portions of your sites will go blank if you upgrade WP Super Cache without updating that dynamic code. This may seem complicated but there’s an example script included and detailed explanations below. A lot of effort was made to make this backwards compatible but unfortunately it wasn’t possible.

In their place is a new cacheaction filter called wpsc_cachedata and it’s sidekick wpsc_cachedata_safety. In the future when a site owner using WP Super Cache wants to make part of their website dynamic they will use those filters to modify pre-defined text strings and replace them with the data they want displayed to the end user. There’s an example script ready to be ripped apart to help you figure all this out.

There are two ways of using this:

  1. The dynamic content is the return value of a simple process, be it date() or any of the numerous get_*() functions in WordPress. That data can simply be slotted in place of the pre-defined text mentioned above.
  2. The more difficult bit comes when you need to use an output buffer to collect the data for display. Due to a limitation in PHP it’s impossible to run an output buffer in the callback function of another output buffer, which is when the wpsc_cachedata filter runs. We need to collect that data before the callback function executes.

The first way above is easy. Simply add a text string of random characters to your theme where you want the dynamic content to appear, then hook a function on to the wpsc_cachedata filter to str_replace() it with your dynamic content. These functions in this script do that:

  • dynamic_cache_test_filter()
  • dynamic_cache_test_template_tag()
  • dynamic_cache_test_init()

You’ll have to hook on to the wpsc_cachedata_safety action and return the numeral 1 to actually run the wpsc_cachedata filter. This is a fail safe used by the plugin to make sure things are ok when the filter runs.

Unfortunately if you want to use an output buffer it’s a lot harder. As stated above an output buffer can’t run in the callback function of another output buffer. This means you have to generate your dynamic content earlier in the PHP process.
This could be as easy as calling your dynamic content function (dynamic_output_buffer_test() in the example script) from the wp_footer action, or calling it from any action before shutdown, whichever is appropriate. You’ll also need to add a template tag of your own choosing to your theme.
Your dynamic content function will run just fine for cached pages, so after the new page has run it store the output in a constant or global variable that the same function can look for when the wpsc_cacheaction runs it. If it finds that information, it can do the search and replace of your template tag without running the output buffer again.
Some pages won’t run the dynamic content function however. This includes feeds and sitemaps. Those pages will generate a PHP error because the output buffer will try to run in the callback!

“PHP Fatal error: ob_start(): Cannot use output buffering in output buffering display handlers in…”

To stop that happening you must check that there’s text to shove in the cached page. That’s what happens in the function dynamic_output_buffer_test_safety() in the example script. It fires on the wpsc_cachedata_safety filter and returns the numeral 1 if successful.

Anatomy of an Output Buffer

I’m going to try and explain the output buffer functions in more detail here. They’re only example functions and if you spot a bug or can suggest improvements please do!


This is the string you add to your theme where your dynamic content will appear. The plugin will replace this string with the code generated by your dynamic content function.

function dynamic_output_buffer_test( &$cachedata = 0 ) {
	if ( defined( 'DYNAMIC_OB_TEXT' ) )
		return str_replace( DYNAMIC_OUTPUT_BUFFER_TAG, DYNAMIC_OB_TEXT, $cachedata );
	// call the sidebar function, do something dynamic
	echo "<p>This is a test. The current time on the server is: " . date( 'H:i:s' ) . "</p>";
	$text = ob_get_contents();

	if ( $cachedata === 0 ) // called directly from the theme so store the output
		define( 'DYNAMIC_OB_TEXT', $text );
	else // called via the wpsc_cachedata filter. We only get here in cached pages in wp-cache-phase1.php
		return str_replace( DYNAMIC_OUTPUT_BUFFER_TAG, $text, $cachedata );

add_cacheaction( 'wpsc_cachedata', 'dynamic_output_buffer_test' );
  • 1. dynamic_output_buffer_test() is the function that will generate the dynamic content inserted into the cached page.
  • 2-3. DYNAMIC_OB_TEXT stores the previous output of this function. If it’s set that means we’re in the wpsc_cachedata filter and should insert it into the cached page and return it.
  • 4-8. This creates the output buffer, echoes a string with the current time and copies the buffer into a variable called $text before closing the output buffer.
  • 10-13. This is how we decide to return data. If $cachedata is 0 that means this function was called from the theme so we should define the constant DYNAMIC_OB_TEXT for later use. Otherwise, we must be dealing with an already cached page so insert the dynamic content into the page and return it.
  • 16. Add the dynamic_output_buffer_test() function to the wpsc_cachedata action. “add_cacheaction” is used as it loads before the regular WordPress action code loads.
function dynamic_output_buffer_test_safety( $safety ) {
	if ( defined( 'DYNAMIC_OB_TEXT' ) )
		return 1; // ready to replace tag with dynamic content.
		return 0; // tag cannot be replaced.
add_cacheaction( 'wpsc_cachedata_safety', 'dynamic_output_buffer_test_safety' );
  • 1-6. dynamic_output_buffer_test_safety() is a function that checks if dynamic content was generated correctly. If that constant is not defined the output buffer will run within the callback function of the main WP Super Cache output buffer and generate a PHP error.
  • 7. Add the wpsc_cachedata_safety() function to the dynamic_output_buffer_test_safety action.


As an example, if I wanted to display my dynamic content in the sidebar of my blog I would load sidebar.php in my theme’s directory and add the following code.

if ( function_exists( 'dynamic_output_buffer_test' ) )

I had previously edited the example script, uncommented it and changed the appropriate tag:


Final Note and Download Link

Please grab the development version of the plugin and try it on a staging server before you put it live. Feedback would be appreciated!

Warning! Keep the tags you use secret. You don’t want someone leaving a comment on your blog with that string! Do not use the same function names or constant names as in this post or example script. They’re in this very public post. Someone is bound to use them and cause you problems when you install their plugin.

Finally, barring any last minute major bugs this version of WP Super Cache will be released on Wednesday. Be careful upgrading. Pass the word around if you know someone is using mfunc as their site will stop working!