SwiftMailer 5, PHP5, and ISO-8859-15

I’ve been using SwiftMailer for as long as I can remember because it’s, IMHO, a great library and far more logical than PHPMailer and “others”. While maintaining a PHP5 codebase for a rather large project, I ran into an issue while using ISO-8859-15 encoded data. Most people won’t care about ISO-8859-15 over ISO-8859-1 (“Latin1”), but since I live in Europe, I prefer to have support for the €uro character 🙂

To make a long story short, if you need SwiftMailer 5 to properly handle ISO-8859-15, look for a line in “MimePart.php” that looks like this:

if (!in_array($charset, array('utf-8', 'iso-8859-1', ''))) {

and change it to this:

if (!in_array($charset, array('utf-8', 'iso-8859-15', 'iso-8859-1', ''))) {

(Yes, the project will move to a PHP7 codebase at some not so distant point in the future.)

Lightbox for Bootstrap 4 and jQuery

Lightbox (or “image preview”) functionality for Bootstrap 4 without additional libraries (apart from jQuery).

Written by Joaquim Homrighausen <joho@webbplatsen.se>

Do as you wish with this 🙂

This is the Javascript/jQuery code for the Bootstrap 4 modal. You don’t have to use jQuery to accomplish this obviously.

$(document).ready(function($) {

  $(".xslightbox").click(function () {
    if ($(this).attr("data-message") != "undefined") {
      document.getElementById("lightbox_target").src = "";
      document.getElementById("lightbox_target").src = $(this).attr("data-message");
    if ($(this).attr("data-title") != "undefined") {
      document.getElementById("lightbox_title").innerText = $(this).attr("data-title");
  /* This will focus the close button, but you don't really need to do this or
     have a close button for that matter since Bootstrap will close the modal
     if you click outside the modal or - in this case - press the Esc key */
  $("#xslightmodal").on("shown.bs.modal", function () {


This is the HTML for the Bootstrap 4 modal. You can style it any which way you want. The key to getting the image to behave as you want it (i.e. to make the image responsive) is adding the “img-fluid” class to the img tag.

You can add the “fade” class to the modal if you want it to be “animated”.

<div class="modal" id="xslightmodal" tabindex="-1" role="dialog" aria-hidden="true" data-keyboard="true">
  <div class="modal-dialog modal-dialog-centered" role="document">
    <div class="modal-content bg-light">
      <div class="modal-header">
        <div class="modal-title text-lowercase text-monospace small" id="lightbox_title">
      <div class="modal-body text-center">
        <img id="lightbox_target" class="img-fluid border border-secondary rounded" />
      <div class="modal-footer">
        <button type="button" tabindex="-1" id="lightbox_close" class="btn btn-primary btn-sm" data-dismiss="modal">'.

And then, to use the lightbox, you need:

<a class="xslightbox" title="Preview me"
   data-title="Name of image">Preview</a>

This is also available as a gist on GitHub. Knock yourself out 🙂

Simple password construct validator for PHP

 * Simple password construct validator for PHP 
 * Joaquim Homrighausen <joho@webbplatsen.se>
 * May 30, 2019 
 * Do whatever you want with this snippet :) 
 * This may not necessarily agree with the section
 * "Strength of Memorized Secrets" in the document
 * from NIST:
 * NIST Special Publication 800-63B 
 * Digital Identity Guidelines 
 * Authentication and Lifecycle Management 
 * https://pages.nist.gov/800-63-3/sp800-63b.html 

function password_check_construct ($pstr, $min_length = 8)
  //Setup pattern and stuff minimum requested length into it
  if ($min_length < 4) {
    //We need at least four characters to satisfy our regexp
    $min_length = 4;

  $match_rules = '/^(?=.{'.(int)$min_length.',})(?=.*[a-z])(?=.*[0-9])(?=.*[A-Z])(?=.*[[:punct:]]).*$/';

  //Require at least one a-z, one A-z, one 0-9, and one punctuation/special character
  if (preg_match ($match_rules, $pstr) === 1) {
    return (true);
  return (false);

This is also available as a gist on GitHub. Knock yourself out 🙂

Setting PHP.INI path (or file) for PHP CLI shell scripts

Running a PHP script from the command-line, or CLI, is quite useful at times and is often used to perform some automated task, like a CRON cleanup script, to send out reminders, etc.

It’s common that these CLI scripts need some, but possibly not all, settings that are similar to the main application’s. I may, for example want to include the database configuration settings shared with the main application. So I often create a separate php.ini file for this purpose.

Running /usr/bin/php -c /my/very/special/path cronScript.php is simple enough, but what if I want to be able to create an “executable” PHP shell script? The obvious answer would be something like:

#!/usr/bin/php -c /my/very/special/path

at the top of the .php file, followed by my PHP code, right? Except that may not do what you want. I could not get the PHP interpreter to load anything in /my/very/special/path by using the above construct, even if it works from the actual command-line. After banging my head against the wall for a while, this turns out to work for these “shell scripts”:

#!/usr/bin/php -c=/my/very/special/path

Note the use of the = (equal) sign between the -c and the path (or file).

Carry on.

Coding for Microsoft browsers like Internet Explorer and Edge

Having been doing battles with things like Internet Explorer 4 (yes, I’m that old), it seems to me like Microsoft have really gotten themselves into a bind when it comes to Edge.

With a user-agent string like this:

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299

It’s no wonder Microsoft seems to be suffering from a split personality when it comes to its browser(s).

Once and for all Microsoft, please just join either of the Chrome/Chromimum/Opera/Firefox projects. Please?

PHP is_numeric () fails WordPress version string check

This is, perhaps, obvious to most PHP developers. But it came somewhat as a surprise to me.

Using is_numeric () for validating a WordPress version string, such as ‘4.7’, does not seem to work very well when WordPress introduces minor releases such as ‘4.7.1’.

Since I cannot be bothered to figure out why it behaves in this (erratic, IMHO) way, I have since replaced the call to is_numeric () with a small function using a simple regular expression (regexp):

    function wpVersionStringCheck ($vs)                                                                                                 
        return (preg_match ('/^(\d+\.)+\d+$/', $vs));                                                                                   

I’m sure there is a hole in there somewhere, but on the following strings at least, it gives me the desired result:

1.0 is valid
1.0. is invalid
1.0.1 is valid
1.banana.0 is invalid

Making SimpleXML truly simple using JSON in PHP

So using SimpleXML in PHP is possibly one of the worst hells of typecasting and data extraction procedures one can encounter, or close to it 🙂 But more the point, you don’t need to walk down that road alone, enter JSON.

In the simplest of ways, this will typically get you something useful:

    $pvar = json_decode ($xml);


(Where $xml is a SimpleXML-type object) This returns a “slightly easier to manage” PHP array.

If you want an associative array, do this:

    $pvar = json_decode ($xml, true);


To get it back to JSON, you simply use:

    $json = json_encode ($pvar).


You may need to handle XML data, but you don’t necessarily need to work with it in XML form inside your application. The above examples may not work fully for you if you have to deal with “foreign” files or clean the input data prior to conversion, but you get the idea.

This is, obviously, obvious to many. It’s a lifesaver for others 🙂


Hur svårt kan det vara att testa något innan man släpper det?

Dag 1:

[Jag] Hej, det här ni släppte i fredags fungerar inte. Jag får inget svar från servern när jag testar.

[MS] Är du säker på att det inte fungerar?

[Jag] Ja, jag är helt säker. Jag har testat 10 ggr nu och det blir samma resultat varje gång.

[MS] Vi har inte ändrat något annat än att lägga till fixen. Vi får helt enkelt börja felsöka.

Dag 2:

[Jag] Hej, hur går det med felsökningen, kommer ni någon vart?

[MS] Nej, det ser bra ut på vår sida. Är du helt säker på att du gör rätt? Vi har inte ändrat något här.

[Jag] Du sade det. Nej, det ser inte bra ut på er sida. Jag kommer inte ens fram till er sida.

[MS] Vi fortsätter att felsöka då.

Dag 3:

[MS] Vi har hittat problemet. Den här delen av servern som tar emot anrop från er applikation fungerade visst inte så bra. Vi har startat om den och nu fungerar det bättre tror jag.

[Jag] Åh vad bra. Då testar jag vidare.

Dag 4:

[Jag] Det fungerar inte så bra, er server verkar inte gilla vårat sätt att göra det på.

[MS] Nej, ni gör fel. Ni skall göra så här.

[Jag] Men vi gör exakt precis så.

[MS] Jag kan inte se att ni gör så som ni skall. I våra loggar hittar vi bara andra metoder.

[Jag] Men vi gör precis exakt så som ni har sagt åt oss att göra. Har ni testat det själva?

[MS] Nu testade jag det. Det fungerar inte. Jag får återkomma när det här fungerar.


Timkostnad: En bit över 1000kr/tim ex moms.

Antal dagar bortslösade: 4.

Tror du de tänker bjuda på nedlagd tid eftersom det var hos dem felet låg? Skulle inte tro det.

[MS] är ett “IT-företag” i Stockholm som utvecklat ett “standardsystem” som är allt annat än standard. Man skräddarsyr varje såld kundlösning och tar betalt tills kunden går sönder för allt man gör. Man tar inget ansvar för fel som uppstår vare sig det rör sig om uppgraderingar av egen kod eller saker man levererat. Allt som behöver korrigeras/ändras/fixas debiteras kund.


Locating older version of MySQL 4, MySQL 5, source code, binaries, rpm, etc.

Quite some time ago, we needed to move a customer’s MySQL 4 server from one location to another. In the process, we figured we’d update the server to use some moderately modern version like MySQL 5.0 at least. Also, if we were to have any chance of virtualizing and upgrading the actual server environment to something more modern like Ubuntu 10.04.LTS or 12.04.LTS, or Debian 6.0, we’d have to re-compile the sources regardless. Not taking other incompatibilities into account, that line of thinking ran into Chuck Norris because the Windows DLLs supplied with the application using the database were not compatible with anything but MySQL 4.

The particular version of MySQL 4 running on the customer’s server was self-compiled (by us), so I figured I’d at least locate the “most recent” version of MySQL 4. To my surprise, this turned out to be harder than I could possibly imagine. In a world where “nobody” forgets anything, I could not find a single trace of a source distribution for MySQL 4. Google, Facebook, Microsoft, and Apple probably know the size of shoes I wear, but they don’t know where MySQL 4 sources are located. This struck me as very odd as MySQL 4 was a) very popular, b) open source, and c) should at least reside on half a dozen servers on the Internet, or so I thought.

Like a core dump out of the blue skies, someone Skyped me a link today. The person had ran into a mirror archive and remembered that I was looking for this “eons ago”. I have now mirrored most of that archive into/onto my own cloud store. I’ll go through that in a few days and remove the things I don’t need, but this may very well turn out to he a lifesaver.

I wonder if Sun and/or Oracle decided that keeping old MySQL versions around was a bad idea …

If you, like me, need to find some odd version of MySQL, for whatever reason, here are two links that may be of good use to you: