Rewriting URLs for static files using PHP’s built-in webserver

I don’t particularly like coding in PHP, but I do think WordPress works well for building websites for small organizations in certain use cases. PHPs built-in webserver, which was added in recent versions of PHP helps make PHP web development feel closer to my flow using other languages and frameworks. In particular, it removes the overhead and context switch for having to configure instances of a webserver like Apache or Nginx for local development.

One feature of the the built-in webserver is that you can define a “router” script to segment out serving of static assets or to direct certain paths to a CMS’ main PHP file.

There are lots of examples of making a router script that will work for one’s particular environment. I used this one for WordPress, because it’s just what came up first in my Google search.

However, I ran into trouble when I was trying to develop locally on a multi-site WordPress instance that used path prefixes rather than subdomains to identify certain blogs. For instance, /blog-1/ would go to one blog while /blog-2/ would go to another. I needed to replicate the functionality of these Apache rewrite rules that would remove the blog prefix from the path:

RewriteRule  ^([_0-9a-zA-Z-]+/)?(wp-.*) $2 [L]
RewriteRule  ^([_0-9a-zA-Z-]+/)?(.*.php)$ $2 [L]

The first rule caused the most problems since I needed to return a static file at a path different than the one reflected in the request URL. I found the answer in this example from the built-in server docs of handling unsupported file types.

To rewrite the path of a static file, you need to:

  • Use a regex to update the path.
  • Figure out the mime type of the file and set the appropriate header.
  • Read the contents of the file and return them.

My finished router.php looks like this:

$root = $_SERVER['DOCUMENT_ROOT'];
chdir($root);
$path = '/'.ltrim(parse_url($_SERVER['REQUEST_URI'])['path'],'/');

// Do some URL rewriting
if (preg_match('/\/([_0-9a-zA-Z-]+\/)?(wp-.*)/', $path, $matches)) {
  $path = '/' . $matches[2];
  if (file_exists($root . $path) && !strpos($path, ".php")) {
    // The rewritten path is to a non-PHP file.  It's probably a static asset
    // or theme asset.  Load the file and return it.
    header("Content-Type: " . mime_content_type($path));
    return readfile($root . $path);
  }
}

if (preg_match('/\/([_0-9a-zA-Z-]+\/)?(.*\.php)$/', $path, $matches)) {
  // The path is to some PHP file.  Remove the leading blog prefix.
  // Logic below will load this PHP file.
  $path = '/' . $matches[2];
}

set_include_path(get_include_path().':'.__DIR__);
if (file_exists($root.$path)) {
  if (is_dir($root.$path) && substr($path,strlen($path) - 1, 1) !== '/')
    $path = rtrim($path,'/').'/index.php';
  if (strpos($path,'.php') === false)
    return false;
  else {
    chdir(dirname($root.$path));
    require_once $root.$path;
  }
} else include_once 'index.php';

WordPress Mu spammed, Chickenfoot to the rescue

I found out last night that I had forgotten to turn off new blog registration on my WordPress Mu instance and that over 500 spammers had created new blogs on my site.  The admin interface allows you to bulk delete blogs but requires that you check the checkbox next to each blog to select it for deletion.  This was getting pretty tedious.  Though I’m sure I could have delved into the internals of WordPress and figured out how to delete these blogs at the database level, this was a little scary and I didn’t really want to spend the time to do the research necessary to feel confident about this method.

So, I installed the Chickenfoot Firefox extension and wrote this simple script that would check every checkbox on the administration page.  This was made easy because of the fact that the only checkboxes on this particular page were ones associated with blogs that I wanted to delete.  This reduced the number of clicks to delete blogs significantly and it only took me a few minutes of manual clicking to delete the hundreds of spam blogs.

for (chk = find(new XPath("//input[@type='checkbox']")); chk.hasMatch; chk = chk.next) {
  check(chk);
}

Photo by loveï½¥janine via Flickr.

csv import plugin for wordpress

I want a plugin to import posts from a CSV file.  This is useful for putting in lots of Let’s Go! events all at once.  A good reference for how to do this is looking at the RSS Import plugin in wp-admin/import/rss.php

community blog hacking

Spent a good amount of time fruitlessly looking for how to get future posts to show up in RSS feed (to allow syndication of events). The place to start looking is in the main method of the WP class (wp-inst/wp-includes/classes.php). Just follow the sub-methods and the relevent code is in there somewhere.

Update: look for the ‘//BOOKMARK’ comment to see where I was looking last.