Stupid PHP tricks: How to turn an array into a human readable list with “and” between the last two items

It seems like it should be simple. Humans list things all the time. If you have more than two items, you separate all but the last two with commas, and then the last two with the word “and”. If you’re pedantic, you might throw in an Oxford comma.

I needed to do the same in PHP. Specifically, I have an array of people’s names, and I want to turn that into a list that gets dropped dynamically into a sentence.

Just converting an array to a comma-separated list is easy:

$list = implode(', ', $array);

But that won’t put the “and” in there. Sure, you could write some code that finds the last comma and replaces it with “and,” but what if a person’s name has a generation suffix with a comma? You don’t want your list to say “Betty Johnson, James Smith and Jr.” when it should say “Betty Johnson and James Smith, Jr.”

I wasn’t able to find a good solution out there, so here’s what I came up with. First I combine the value of the last element in the array with the second-to-last, and remove the last. Then I do the implode().

if (count($array) >= 2) {
    $array[count($array)-2] .= ' and ' . $array[count($array)-1];
    unset($array[count($array)-1]);
}
$list = implode(', ', $array);

Note that you want to be sure that the array has at least two nodes before running the combination.

In case you’re thinking the implode() is going to be an issue when the array includes exactly two nodes, remember that the conditional is running, inserting the “and” and turning it into a one-node array, so implode() will just return the value of the single node, without the concatenation string.

Of course, if you want the Oxford comma, it’s going to be a bit more complicated. You’ll need a conditional that checks for three or more nodes and inserts “, and” in the combination of the last two nodes. Then of course you’d also keep the existing conditional for exactly two nodes, because you don’t want the comma if there are only two items in the list:

if (count($array) >= 3) {
    $array[count($array)-2] .= ', and ' . $array[count($array)-1];
    unset($array[count($array)-1]);
}
elseif (count($array) == 2) {
    $array[count($array)-2] .= ' and ' . $array[count($array)-1];
    unset($array[count($array)-1]);
}
$list = implode(', ', $array);

Gone phishing

Yesterday I got a curious, one-sentence email to the customer support address for my WordPress plugin with the subject “checkout” [sic].

Just wanted to confirm if everything went through.

The person had a weird* — but not too weird — name, and a Gmail address to match. I was immediately suspicious, but since there were no links in the email, I decided to give them the benefit of the doubt as just being a bad communicator, not a phishing attempt. I figured the worst I risked by replying was proving my email address was real, which… well, duh. So I tersely responded that there were no orders matching their name or email address.

This afternoon I got a reply:

I regret my mistake in not attaching the required files to my previous email, as I was unaware that our email system does not support large file attachments. With some assistance, I have now uploaded them to my OneDrive at [redacted] Sorry for the late response.

Don’t worry, I wasn’t stupid enough to click the link. I just blocked them and reported the phishing attempt instead. I’m glad my instinct was right, and I kind of wish I hadn’t felt the need to test it. I suspect I’m going to need to be extra vigilant about incoming emails for a while.

I definitely regret that — out of necessity — I replied with my real email address, but the support email for the plugin is just a forwarding address and can’t send email directly. Maybe it’s worth the $20/year it would take to change that.


*I feel compelled to explain what I mean by “weird,” because people can say someone has a weird name and basically mean something racist by it. That’s not the situation here. The surname was a very common English surname. The first name was the name of an animal that I have never heard used as a person’s name before.

Life is hard enough without people deliberately making it harder for no good reason

I recently turned 51. There is no question at this point that more of my life is behind me than ahead. (If I live to be 102 I will be profoundly miserable, and profoundly miserable people rarely make it to 102.)

As I get older, I’m finding myself more and more just exhausted and exasperated with the goings-on of the world. Even if we didn’t have the one very big obvious own-goal Americans are dealing with at the moment, it just seems like so much stuff in life is a lot harder than it needs to be, for no real reason. But I don’t think it’s just the cynical perspective of my advancing age talking. The world really is getting worse.

There’s just broad stubbornness, cruelty, and lack of generosity. I’m not talking about charity even, just the basic generosity of giving your fellow humans a fucking break now and then. Don’t go out of your way to make things harder on those around you. Is that so much to ask?

“Upgrading” from the iPhone 13 mini to iPhone 16e is a lateral move, at best

Yesterday Apple announced the iPhone 16e, and I briefly considered trading in my iPhone 13 mini for one.

Bear in mind, the name I chose for my Personal Hotspot on the phone is “You can pry my iPhone 13 mini from my cold, dead hands.”

So, is the iPhone 16e worth abandoning that bold stance? Uh… no.

There are definitely some ways it’s better that I would appreciate: faster CPU, better battery life, USB-C port.

There are ways it’s “better” that are either irrelevant to me or actually a downgrade, from my idiosyncratic perspective: a larger screen (too big to reach across with one hand, and too big for my pocket), Apple Intelligence. (I suppose as a “techie” I should care, but I am utterly disinterested in AI in general, and in “Apple Intelligence” in particular.)

There are ways it’s clearly worse, but that I don’t care about, most specifically MagSafe. I like MagSafe in concept, but I don’t have a MagSafe charger and am indifferent about getting one.

And then there are ways it’s worse, that I very much do care about. Again, the size. My eyeballs would appreciate a bigger screen but no other part of me wants my phone to grow. Even the 13 mini is slightly larger than my ideal phone size.

But above all, the real deal-breaker, is the camera situation.

I am not heavily invested in the iPhone for high-end photography. Obviously I’m not, or I wouldn’t still be using an iPhone 13 mini. But I do shoot all of my YouTube videos on my iPhone, and there are two specific features of the iPhone 13 mini camera system that I use extensively: Cinematic Mode, and the 0.5x zoom, wide-angle lens.

The iPhone 16e lacks both of these camera features. Without them, I would be giving up too much.

Of course, I actually own two iPhone 13 minis. (I inherited my dad’s when he died.) So I could trade in my 13 mini and upgrade to the 16e for my day-to-day phone, while still using the spare 13 mini for shooting video.

I considered it. But… back to the size thing. I don’t want to carry a larger phone. So until Apple makes another small phone, or until it just stops working altogether (a far more likely scenario), you can pry my iPhone 13 mini from my cold, dead hands.

How spammers, scammers and botnets know your website is a target

I was just mulling this over as I spent a few minutes looking at the monitoring tools I have running on the large number of websites I maintain, both for myself and my clients.

Unscrupulous types have plenty of reasons for trying to infect a website with malicious code, and they have tools that are designed to help them find websites that are ripe for exploit.

Specifically, there are telltale signs that a website might be running a particular platform, or they might just assume it’s a popular platform (*cough* WordPress *cough*) and run with that. Either way, they have lists of known exploits, and they just need to run a program that tries to find those exploits on a given website.

If they find one, jackpot.

It’s been interesting to see how this has evolved over the years. A decade or so ago, the most common exploit I saw was silently infiltrating a WordPress site and injecting code into its pages, either via JavaScript or a 1-pixel iframe, that would load data from an external site or redirect the user’s browser to a scam site that would throw ads at them, infect their computer with a virus, run a keylogger, etc.

More recently, what I see most often — and it’s maybe because as a matter of course I run tools that block those aforementioned actions — is surges of fake e-commerce transactions for the cheapest item in a store. Clearly in those cases the scammers have gotten their hands on a list of stolen credit card numbers, and they’re testing to see if any of them are still active.

God, these people suck.

Anyway… the thing I was thinking about today was kind of a meta-level factor in all of this. It’s not just that the botnets only infect sites that haven’t been kept up to date and therefore are exploitable. It seems like they only even try to infect sites that are very low traffic, with rarely updated content, which correlates reasonably to the idea that the site owners may be neglecting their site and not running important software updates.

But how do they know these sites have low traffic? How do they know their content is rarely updated?

How do they know these sites even exist?

The big tech companies — and I’m thinking especially Google and Meta here — have amassed huge data sets about not just users and their behavior, but the websites users interact with. In short, if Google crawls a site on a regular basis — and if Google knows about a site, it crawls it, unless you specifically tell it not to — then Google has data on how often that site’s content is updated, and how much traffic it gets. (Traffic in relative terms, at least, in the form of click-through from Google search results. But traffic in absolute terms, if the site has Google Analytics running on it. Which a huge percentage of websites do.)

Google shares a lot of the data it collects. But it also doesn’t share a lot of the data it collects, and this is specifically the type of data Google does not make publicly available. Or sometimes even privately available to the site owners.

How do scammers get it?

I don’t have an answer. I don’t even have proof that they’re getting it. I just have my anecdotal observation that the scammers don’t even seem to try hacking into the sites I work on that get a lot of traffic and frequent updates. But they’re constantly prodding and poking at sites and servers that don’t see much other traffic.

Curious.