Category Archives: Nonsense

Repository for the uncategorizable.

Special characters, like the British pound symbol “£”, can be entered using a keyboard shortcut. An Alt code shortcut is usually represented by something like Alt 0163 or Alt+0163, but how to actually type this can be pretty confusing, so I’ll explain the process using the British pound symbol as an example.

For a standard keyboard with a numeric keypad, you can enter the pound sign by turning on Num Lock, holding the Alt key, then typing 0163 on the numeric keypad, then releasing the Alt key. The symbol will be entered when the Alt key is released.

For a laptop keyboard without a numeric keypad, certain letter keys also have a number printed on them. These keys act as a virtual numeric keypad. First turn on Num Lock (sometimes Nm Lck), then hold the Alt key and use the virtual numeric keypad to enter 0163, then release the Alt key. The corresponding letter keys are MJOL. Hit the Num Lk key again to turn off the virtual numeric keypad.

7:21 PM 2/26/2012

I recently ran the spider at against and it returned a list of URLs that included a few pages with some suspicious-looking parameters. This is the second time I’ve come across these URLs, so I decided to document what was going on. The first time, I just cleared the cache, spidered the site to preload the cache, and confirmed that the spider didn’t encounter the pages. And then I forgot all about it. But now I’m mad.

Normally, a URL list for a WordPress site includes the various pages of the site, like so:


But in the suspicious URL list, there are additional URLs for the pages directly off of the site’s root.


This occurs only for the pagination of the main site’s pages. I did not find URLs containing the parameter ?option=com_google&controller= for any pages that exist under a category or tag, but that also use the /page/2/ convention.

The parameter is the urlencoded version of the text:



I compared the source code of the pages at the clean URLs vs that of the pages at the bad URLs and found that there was a difference in the pagination code generated by the WP-Paginate plugin.

The good pages had normal-looking pagination links.

<div class="navigation">
<ol class="wp-paginate">
<li><span class="title">Navigation:</span></li>
<li><a href="//" class="prev">&laquo;</a></li>
<li><a href='//' title='1' class='page'>1</a></li>
<li><a href='//' title='2' class='page'>2</a></li>
<li><span class='page current'>3</span></li>
<li><a href='//' title='4' class='page'>4</a></li>
<li><a href='//' title='5' class='page'>5</a></li>
<li><a href='//' title='6' class='page'>6</a></li>
<li><a href='//' title='7' class='page'>7</a></li>
<li><span class='gap'>...</span></li>
<li><a href='//' title='17' class='page'>17</a></li>
<li><a href="//" class="next">&raquo;</a></li>

The bad pages had the suspicious URLs, but were otherwise identical. Other than the URLs in the navigation, there was nothing alarming about the HTML on the bad pages.

I downloaded the entire site and ran a malware scan against the files, which turned up nothing. I also did some full-text searching of the files for the usual base64 decode eval type stuff, but nothing was found. I searched through the tables in my database, but didn’t see any instances of com_google or proc or environ that I could connect to the suspicious URLs.

Google it

Google has turned up a few good links about this problem, including:

  1. – AntiSecurity/Joomla Component Contact Us Google Map com_google Local File Inclusion Vulnerability
  2. – “On a poorly-secured LAMP stack, that would read out your server’s environment variables. That is one step in a process that would grant the hacker root access to your box. Be thankful it’s not working. Hacker is a bad term for this. This is more on the Script Kiddie level.”

    The poster also provided a few lines of code for blocking these URLs in an .htaccess file.

    # Block another hacker
    RewriteCond %{QUERY_STRING} ^(.*)/self/(.*)$ [NC]
    RewriteRule ^.* - [F]
  3. – “This was trying for Local File Inclusion vulnerabilities via the Joomla/Mambo script.”
  4. – a bug ticket submitted to WordPress over a year earlier identifying a security hole if the function that generates the pagination isn’t wrapped in a url_esc function that sanitizes the URL. WP-Paginate’s author submits a comment to the thread, and the plugin does use url_esc.

So, what would evidence of an old Joomla exploit be doing on my WordPress site? And what is happening within the WP-Paginate plugin to cause these parameters to appear?


It seemed prudent to take a closer look at two of the plugins used on the site.

Ardamis uses the WP-Paginate plugin. The business of generating the /page/2/, /page/3/ URLs is a native WordPress function, so it’s strange to see how those URLs become subject to some sort of injection by way of the WP-Paginate plugin. I tried passing a nonsense parameter in a URL (// and confirmed that the navigation links created by WP-Paginate contained that ?foobar parameter within each link. This happens on category pages, too. This behavior of adding any parameters passed in the URL to the links it is writing into the page, even if they are urlencoded, is certainly unsettling.

The site also uses the WP Super Cache plugin. While this plugin seems to have been acting up lately, in that it’s not reliably preloading the cache, I can’t make a connection between it and the problem. I also downloaded the cache folder and didn’t see cached copies of these URLs. I turned off caching in WP Super Cache but left the plugin activated, cleared the cache, and then sent the spider against the site again. This time, the URL list didn’t contain any of the bad URLs. Otherwise, the lists were identical. I re-enabled the plugin, attempted to preload the cache (it got through about 70 pages and then stopped), and then ran a few spiders against the site to finish up the preloading. I generated another URL list and the bad URLs didn’t appear in it, either.

A simple fix for the WP-Paginate behavior

The unwanted behavior of the WP-Paginate plugin can be corrected by changing a few lines of code to strip off the GET parameters from the URL. The lines to be changed all reference the function get_pagenum_link. I’m wrapping that function in the string tokenizing function strtok to strip the question mark and everything that follows.

The relevant snippets of the plugin are below.

$prevlink = ($this->type === 'posts')
? esc_url(strtok(get_pagenum_link($page - 1), '?'))
: get_comments_pagenum_link($page - 1);
$nextlink = ($this->type === 'posts')
? esc_url(strtok(get_pagenum_link($page + 1), '?'))
: get_comments_pagenum_link($page + 1);
function paginate_loop($start, $max, $page = 0) {
    $output = "";
    for ($i = $start; $i <= $max; $i++) {
        $p = ($this->type === 'posts') ? esc_url(strtok(get_pagenum_link($i), '?')) : get_comments_pagenum_link($i);
        $output .= ($page == intval($i))
        ? "<li><span class='page current'>$i</span></li>"
        : "<li><a href='$p' title='$i' class='page'>$i</a></li>";
    return $output;

Once these changes are made, WP-Paginate will no longer insert any passed GET parameters into the links it’s writing into that page.


The change to the WP-Paginate plugin is what we tend to call a bandaid – it doesn’t fix the problem, it just suppresses the symptom.

I’ve found that once the site picks up the bad URLs, they can be temporarily cleaned by clearing the cache and then using a spider to recreate it. The only thing left to do is determine where they are coming from in the first place.

The facts

Let’s pause to review the facts.

  1. The spider sent against // discovers pages with odd parameters that shouldn’t be naturally occurring on the pages
  2. The behavior of the WP-Paginate plugin is to accept any parameters passed and tack them onto the URLs it is generating
  3. Deleting the cached pages created by WP Super Cache and respidering produces a clean list – the bad URLs are absent

So how is the spider finding pages with these bad URLs? How are they first getting added to a page on the site? It would seem likely that they are originating only on the home page, and the absence of the parameters on other pages that use pagination seems to support that theory.

An unsatisfying ending

Well, the day is over. I’ve added my updated WP-Paginate plugin to the site, so hopefully Ardamis has seen the last of the problem, but I’m deeply unsatisfied that I haven’t been able to get to the root cause. I’ve scoured the site and the database, and I can’t find any evidence of the URLs anywhere. If the bad URLs come back again, I’ll not be so quick to clean up the damage, and will instead try to preserve it long enough to make a determination as to their origin.

Update 07 April 2012: It’s happened again. When I spider the site, two pages have the com_google URL. These page have the code appended to the end of the URL created by the WordPress function cancel_comment_reply_link(). This function generates the anchor link in the comments area with an ID of cancel-comment-reply-link. This time, though, I see the hijacked URL used in the link even when I visit the clean URL of the page.

This code is somehow getting onto the site in such a way that it only shows up in the WP Super Cache’d pages. Clearing the cache and revisiting the page returns a clean page. My suspicion is that someone is visiting my pages with the com_google code as part of the URL. WordPress puts the code into a self-referencing link in the comment area. WP Super Cache then updates the cache with this page. I don’t think WordPress can help but work this way with nested comments, but WP Super Cache should know better than to create a cached page from anything but the content from the server.

In the end, because I wasn’t using nested comments to begin with, I chose to remove the block of code that was inserting the link from my theme’s comments.php file.

    <div class="cancel_comment_reply">
        <small><?php cancel_comment_reply_link(); ?></small>

I expect that this will be the last time I find this type of exploit on, as I don’t think there is any other mechanism that will echo out on the page the contents of a parameter passed in the URL.

Google, what is up with your Google+ profile badges and your Google +1 buttons being different sizes?

There is a neat wizard for creating the code snippet for a Google+ profile badge. We get to pick an image size from one of four options, if we want the image to be hosted on Google’s server. (And why wouldn’t we?)

Small (16px)
Standard (32px)
Medium (44px)
Tall (64px)

OK, those are pretty acceptable, I guess, but I would really like to see something in the 20 to 24 pixel range.

What about the wizard for the Google +1 button?

Small (15px)
Standard (24px)
Medium (20px)
Tall (60px)

Wait, what?!? You’re using the same labeling, but the sizes are totally different. Not only that, but none of the sizes are shared between the two buttons. The Standard profile button is 75% larger than the +1 button. Grrr.

The Google +1 button wizard has more options, including a field where you may specify the path to an image, and the button itself is more dynamic. The profile button wizard is very basic, but it is easy to edit the HTML output to use any image. If forced to make my own image and host it, coming up with a custom profile button is clearly less involved.

As a third option, the configuration tool for the Google+ brand page badge makes it possible to essentially combine the functions of both buttons. While the badge takes up a large chunk of real estate, it is probably the best choice, as it looks good, has some bold colors, and adds some extra Google+ stuff (thumbnail images, a counter) that you can’t get from the basic generator.

In Windows, the Num Lock key state (on or off) can be set in the registry. It can be set in either of two locations, depending on when you wish to set the state, or both, if you want to force the state at boot and change it after the user logs in.

The Num Lock key state after logon can be set as a registry value for the current user in the key HKEY_CURRENT_USER\Control Panel\Keyboard. To set the state of the Num Lock key before logon (the key state will be set before the Ctrl+Alt+Del screen), change the registry value in the key HKEY_USERS\.Default\Control Panel\Keyboard. For both keys, the data for the InitialKeyboardIndicators value determines the state of the NumLock key. There are three possible settings.

0 = Num Lock is turned OFF after/at logon.
1 = Disable Num Lock.
2 = Num Lock is turned ON after/at logon.

A registry merge file that sets Num Lock on for the current user after logon is below.

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Control Panel\Keyboard]

It’s also (typically) possible to configure the Num Lock key state in the BIOS, although I personally don’t see the advantage of setting in the BIOS something that is configurable in Windows.

Note that users of full-sized keyboards with distinct Num keypads generally prefer to have the Num Lock key enabled and laptop users typically have Num Lock disabled. Much like the Function key is used to change the behavior of certain laptop keys, laptop keyboards without dedicated Num keypads map numbers to regular character keys. This could potentially cause some confusion, when users begin hitting the letter keys and get numbers instead.

We inherited a number of Little Little Golden Books a few years ago. These are tiny, child-sized versions of the regular Little Golden books. I am not, for the most part, a fan of the writing in the Little Golden Books, which seems to be from the era of Dick and Jane and varies from patriarchal to nonsensical.

But the opening passage in a book called “We Help Daddy”, by Mini Stein, has stuck in my head for some time now due to its similarity to William Faulkner’s recognizable style and voices of certain of his characters in the novels “As I Lay Dying” and “The Sound and the Fury” in particular.

The story “We Help Daddy” is told in the first person by Sue, a girl of about 3 or 4 years old who helps her older brother and her father with household chores.

We help Daddy a lot, Benjy and I. Daddy fixes the attic door. He calls, “Hammer, please.”
Benjy hands him the hammer.
Then Daddy says, “Sue, are you ready to help me, too?”
I am Sue, so I hold out my hands to show I am ready.

The line beginning “I am Sue”, which would sound less unnatural coming from a Faulkner character, sounds completely out of place when spoken by a young child. It seems very unlikely that anyone’s internal monologue contains phrases like, “I am so-and-so.” I would expect this to be particularly true of young children, who, in my experience, have a very different sense of self.

Anyway, I though I’d note this before the books are outgrown and I forget about them completely.

I’m trying to find a way to save some Xbox 360 achievements that I’ve earned while my console was offline. Typically, just connecting to Xbox Live will sync up your gamertag and the offline achievements will be added to you profile. This works because, usually, the gamertag is associated with a single Xbox 360, which goes offline and then back online. My situation is different, and it seems like I’m going to lose my offline achievements.

The set up

I have a single gold account and two Xbox 360 consoles. One of these consoles is always online and is used exclusively for watching Netflix (because the drive tray is broken). The other console works fine for games, but is physically located where wired Ethernet isn’t available, and I haven’t purchased a wireless adapter. In order to get the same gamertag on both consoles, I used the recover gamertag feature to bring it down to the online console. This means that the Netflix gamertag is regularly connecting to Xbox Live while my gaming is done on the same gamertag, but offline.

Microsoft doesn’t seem to want to support this sort of arrangement, as it appears that gamertags are associated with individual Xbox consoles and that only the last-to-be-connected gamertag is seen as legit.

The problems

The first problem I’m facing is how to get all of these achievements that were earned offline sync’d up with my Live profile. One might reasonably think that simply connecting the offline Xbox to Xbox Live and logging in would do this, but Live sees the account as invalid (presumably because the account associated with the other box has connected more recently). Upon connecting to Xbox Live, I’m prompted to recover my gamertag, which I know from experience will erase my offline achievements (I’ll get the gamertag as it exists on the online console – which will also render the gamertag on the online console invalid).

I also tried to use a USB flash drive to move my gamer profile from the offline box to the online box. The move itself was successful, but when I tried to connect to Live, it again found the account to be invalid and invited me to recover my gamertag. I was able to move the gamer profile back to the USB drive, remove the drive, and then recover the online gamertag in order to keep using Netflix, but I was back to square one.

I haven’t yet tried moving the offline console’s hard drive with the gamertag to the online console. As of right now, this is the only thing I can think to try.

The second problem I’m facing is that the offline Xbox doesn’t yet have the new dashboard and some of my games have updates available that are supposed to fix some bugs. I’ve read that it should be possible to get these updates by creating a silver account and logging into Xbox Live under that account. That would be somewhat helpful, but unnecessary if I can solve the first problem.


Network autonegotiation is easily misunderstood. Consider two 10/100Mb devices attached to one another – a PC connected to a router. For each of these devices, it’s possible to configure the connection to use either 1) a fixed speed and duplex or 2) to negotiate the optimal shared speed and duplex with whatever it is connecting to. What is not intuitive is that both devices must be configured with the same settings. The connection will suffer a performance hit, or may not work at all, if the two devices are configured differently.

A common misconception about autonegotiation is that it is possible to manually configure one link partner for 100 Mbps full-duplex and autonegotiate to full-duplex with the other link partner. In fact, an attempt to do this results in a duplex mismatch. This is a consequence of one link partner autonegotiating, not seeing any autonegotiation parameters from the other link partner, and defaulting to half-duplex.

If both devices are configured to autonegotiate speed and duplex, then each will attempt to make the best possible connection among the possibilities they have in common. However, if one of the devices is set to use a fixed speed and duplex and the other device is set to autonegotiate, the autonegotiating device can determine the speed but not the duplex of the other device and so falls back to its default duplex mode. In the case of Cisco switches, the default duplex mode is half-duplex.

…it is possible for a[n autonegotiating] link partner to detect the speed at which the other link partner operates, even though the other link partner is not configured for auto-negotiation. In order to detect the speed, the link partner senses the type of electrical signal that arrives and sees if it is 10 Mb or 100 Mb.

It is not possible to detect the correct duplex mode in the same method that the correct speed can be detected. In this case, the […] port of [the autonegotiating] switch […] is forced to select the default duplex mode. On Catalyst Ethernet ports, the default mode is auto-negotiate. If auto-negotiation fails, the default mode is half-duplex.

Half-duplex as a default duplex mode is not unique to Cisco switches. Below is a link to an article on written by Rich Hernandez, a senior engineer with the Server Networking and Communications Group at Dell, that contains a table summarizing “all possible combinations of speed and duplex settings, both on 10/100/1000-capable switch ports and on NICs.” Included are combinations that would yield no link or link fail conditions, as well as combinations that would yield a duplex mismatch.

The importance of using identical settings on both sides of a network connection is stressed in a KB article from with information on how an autonegotiating port may report that it has established a full-duplex connection with a NIC configured for 100MBs/Full, but in fact is communicating at less than expected capacity.

Only by explicitly setting both sides of the link to the same duplex mode would the link work flawlessly.

Understanding link data errors

The page at the link below contains two tables that explain the various errors and counters logged by a network switch and the possible causes.

Troubleshooting Ethernet Collisions

Collisions may appear to indicate communication problems with a network connection, but as a technote from states, collision counters alone are not indicative of network problems.

…collisions are a way to distribute the traffic load over time by arbitrating access to the shared medium. Collisions are not bad; they are essential to correct Ethernet operation.

There is no set limit for “how many collisions are bad” or a maximum collision rate.

In conclusion, the collisions counter does not provide a very useful statistic to analyze network performance or problems.

Late Collisions

When a collision is detected by a station after it has sent the 512th bit of its frame, it is counted as a late collision.

The station that reports the late collision merely indicates the problem; it is generally not the cause of the problem. Possible causes are usually incorrect cabling or a non-compliant number of hubs in the network. Bad network interface cards (NICs) can also cause late collisions.

Woot. In what was certainly the best email I received today, against all odds, GameFly shipped Elder Scrolls V: Skyrim. This is twice now that I’ve gotten a just-released game from GameFly. Timing your returns to get new releases is hit or miss, and I’ve gone through spells where I’ve gotten one game after another from the bottom of my queue, but sometimes they come through.

No more buyer’s remorse

The last game I bought was Final Fantasy XIII, which turned out to be a major disappointment. Since then, I’ve wised up and started renting, although from all accounts, Skyrim seems like one worth buying. Still, dollar-per-hour, renting is a far better deal than buying used, and I’ve been able to try out a ton of games I was curious about (most of which I returned within a week or two) that I wouldn’t have otherwise even played.

GameFly referrals really do work

By the way, the GameFly referral program is really ugly, but it seriously works. I’ve been coasting on referrals for the last four months, and as it stands now, I won’t be billed again until January. I’d recommend checking it out if you have the means of putting your referral code online. If you’re not already a GameFly member, if you use this referral link to sign up with GameFly, we both get a free month: Even if you’re normally on the One Game Out plan, if someone uses your referral, your reward is a free month at the Two Games Out plan (so you get an extra game, too).

As of November 11th, the rewards have changed, though. They no longer can offer cash via Paypal as a reward (which I am fine with). Here’s their communication on the matter:

GameFly Refer-A-Friend: Important Information Regarding Rewards

Thanks for telling your friends about GameFly!

Unfortunately, we are no longer able to offer PayPal as a reward option for our referral program. You’ll still be able to earn a free month of GameFly for every friend you refer (or you can donate it to the Make-A-Wish Foundation).

On December 1st, all users who have selected PayPal will be automatically switched over to the ‘free month of GameFly’ option. Any valid rewards generated in November will be paid out as usual.

We apologize for this change and hope you’ll continue to send your friends our way.

Click Here to access your account, share more and earn more!

Thank you,

The GameFly Referral Program
Powered by Extole

I have a Windows XP guest running in VMWare Workstation 7 on a Windows 7 Ultimate host machine. This is working pretty well. The XP guest is nice and responsive. I have only one gripe. I’d like all of the buttons on my Logitech MX510 (the best mouse ever) to be mappable in the guest.

Starting from square one, I decided to try installing the current version of SetPoint in the guest OS. The installation went fine, but the usual functionality of the SetPoint settings utility was absent.

SetPoint Settings in an XP virtual machine

SetPoint Settings in an XP virtual machine

As shown in the screenshot, the SetPoint Settings utility displays only the Tools tab. It is missing the My Mouse tab (and if a keyboard were installed, I presume it would be missing the Keyboard tab, too).

After some Googling around, it appears to be a due to the way VMware approximates the physical mouse. VMware seems to treat USB mice connected to the host as PS/2 devices in the guest. SetPoint, then, doesn’t detect any Logitech hardware that it can configure.

The question of how to obtain SetPoint functionality in virtual machines is one that has been asked many, many times before, without a satisfactory answer. More on that in a little bit.

The best work around

Thankfully, it seems that, at least in the case of a Windows host and a Windows guest, installing SetPoint inside the virtual machine is not necessary. Installing it on the host seems to make all of the functionality available in the guest. This is the solution that I’m implementing now, and it is what I would recommend, provided you have rights to install software on the host.

Paths to follow if you want to pursue installing SetPoint inside a VMware virtual machine

I applaud your courage. There are a few settings that can be tweaked that may get you closer to a working installation.

Possible setting number one

From the post at

Add the following line to the virtual machine’s .vmx file:

mouse.vusb.enable = "TRUE"

From what I can tell, this setting allows me to use the Forward and Back buttons on the mouse, but does not make the mouse detectable by SetPoint. The remaining mouse buttons do nothing.

Possible setting number two

From the post at

The solution given (which did not work for me) is to:

First add the following line to the virtual machine’s .vmx file:

usb.generic.allowHID = "TRUE"

An explanation of what this does, by a VMware associate, can be found in the thread at

If you’re feeling really adventurous and/or desperate, you can take out the mouse.vusb.enable line and add this option instead:

usb.generic.allowHID = “TRUE”

Then, you’ll notice that your main mouse and keyboard (if they are USB) are available to pass through into the guest via the USB devices menu.

The dangerous part here is that once you pass through the mouse, it is actually disconnected from the host, so you won’t be able to ungrab from the guest just by mousing out of the Fusion window. You can still ungrab with the keyboard (ctrl-cmd I believe is the shortcut?). If you actually pass through your keyboard and your mouse, you’ll be stuck in the guest and you’ll have to shut it down (or worse, reboot your physical machine).

This sounded like a great idea, and I was willing to set up a second, PS/2 mouse to control just the host, if necessary. Without connecting a second mouse, I tried passing the Logitech mouse as a USB device to the VM, just as I would an external hard drive, but VMware prevented this, with a warning message:

[Machine Name] – VMware Workstation
Cannot connect “Logitech USB-PS/2 Optical Mouse” to this virtual machine. The host requires this device for input.

The second step would have been to go into Device Manager, click Actions, and then choose “Scan for hardware changes”.

I didn’t get to the second step, as I was too lazy to track down a PS/2 mouse to keep attached to the host, and I still wanted to find a software solution. I suspect, though, that this would be were to begin, were I to need to get SetPoint running in the guest OS.


While I wasn’t able to figure out how to install SetPoint on a guest OS, the workaround of installing SetPoint on the host OS seems to accomplish my goal.

For a recent project, I needed to create a form that would perform a look up of people names in a MySQL database, but I wanted to use a single input field. To make it easy on the users of the form, I wanted the input field to accept names in either “Firstname Lastname” or “Lastname, Firstname” format, and I wanted it to autocomplete matches as the users typed, including when they typed both names separated by a space or a comma followed by a space.

The Ajax lookup was quick work with jQuery UI’s Autocomplete widget. The harder part was figuring out the most simple table structure and an appropriate SQL query.

A flawed beginning

My people table contains a “first_name” column and a “last_name” column, nothing uncommon there. To get the project out the door, I wrote a PHP function that ran two ALTER TABLE queries on the people table to create two additional columns for pre-formatted strings (column “firstlast”, to be formatted as “Firstname Lastname”, and column “lastfirst”, to be formatted as “Lastname, Firstname”), added indexes on these columns, and then walked through each record in the table, populating these new fields. I then wrote a very straight forward SQL query to perform a lookup on both fields. The PHP and query looked something like this:

// The jQuery UI Autocomplete widget passes the user input as a value for the parameter "name"
$name= $_GET['name'];

// This SQL query uses argument swapping
$query = sprintf("SELECT * FROM people WHERE (`firstlast` LIKE '%1\$s' OR `lastfirst` LIKE '%1\$s') ORDER BY `lastfirst` ASC",
mysql_real_escape_string($name. "%", $link));

This was effective, accurate, and pretty fast, but the addition of columns bothered me and I didn’t like that I needed to run a process to generate those pre-formatted fields each time a record was added to the table (or if a change was made to an existing record). One possible alternative was to watch the input and match either lastname or firstname until the user entered a comma or a space, then explode the string on the comma or space and search more precisely. Once a comma or a space was encountered, I felt pretty sure that I would be able to accurately determine which part of the input was the first name and which was the last name. But this had that same inefficient, clunky bad-code-smell as the extra columns. (Explode is one of those functions that I try to avoid using.) Writing lots of extra PHP didn’t seem necessary or right.

I’m much more comfortable with PHP than with MySQL queries, but I realize that one can do some amazing things within the SQL query, and that it’s probably faster to use SQL to perform some functions. So, I decided that I’d try to work up a query that solved my problem, rather than write more lines of PHP.

CONCAT_WS to the rescue

I Googled around for a bit and settled on using CONCAT_WS to concatenate the first names and last names into a single string be matched, but found it a bit confusing to work with. I kept trying to use it to create an alias, “lastfirst”, and then use the alias in the WHERE clause, which doesn’t work, or I was getting the literal column names back instead of the values. Eventually, I hit upon the correct usage.

The PHP and query now looks like this:

// The jQuery UI Autocomplete widget passes the user input as a value for the parameter "name"
$name= $_GET['name'];

// This SQL query uses argument swapping
$query = sprintf("SELECT *, CONCAT_WS(  ', ',  `last_name`,  `first_name` ) as lastfirst FROM people WHERE (CONCAT_WS(  ', ',  `last_name`,  `first_name` ) LIKE '%1\$s' OR CONCAT_WS(  ' ',  `first_name`,  `last_name` ) LIKE '%1\$s') ORDER BY lastfirst ASC",
mysql_real_escape_string($name. "%", $link));

The first instance of CONCAT_WS isn’t needed for the lookup. The first instance allows me to order the results alphabetically and provides me an array key of “lastfirst” with a value of the person’s name already formatted as “Lastname, Firstname”, so I don’t have to do it later with PHP. The lookup comes from the two instances of CONCAT_WS in the WHERE clause. I haven’t done any performance measuring here, but the results of the lookup get back to the user plenty fast enough, if not just as quickly as the method using dedicated columns.

The result of the query is output back to the page as JSON-formatted data for use in the jQuery Autocomplete.

The end result works exactly as I had hoped. A user of the form is able to type a person’s name in whatever way is comfortable to them, as “Bob Smith” or “Smith, Bob”, and the matches are found either way. The only thing it doesn’t do is output the matches back to the autocompleter in the same format that the user is using. But I can live with that for now.