Box drawing in PHP

Back in the “good old days” of MS-DOS, you could draw lines, boxes, filled areas (think progress bars), and more using the extended ASCII character set (AKA code page 437).

While writing a simple command-line utility in PHP I wanted to use the full block () and light shade () characters to create a simple progress bar that is a bit nicer than the typical =========....................

Like this:

█████████████████░░░░░░░░░░░░░░░░░░░░░░░ 42.5%

Instinctively, I turned to PHP’s chr() function and looked up the extended ASCII codes for the characters I needed. Boy, was I disappointed when my progress bar was nothing but a series of un-useful question marks. Surely PHP can render simple ASCII characters, I thought.

It might have gone differently if I had been using a PC, but I do 100% of my development these days on a Macbook Pro. It so happens that the bash shell in UNIX, Linux, and Mac OS X all use UTF-8 encoding by default, not CP437. (Of course, your terminal font will need to support UTF-8 characters for this to work.)

So, I just needed to find the UTF-8 codes for the characters I needed and use those instead of the old familiar CP437 ones. However, the results weren’t much better.

After an hour or more of Googling and experimentation, I finally realized that chr() doesn’t do UTF-8. I found various suggestions on how to produce the desired characters using custom functions and the like, but the best way turned out to just use a good ‘ol HTML entity and run it through html_entity_decode:

$block = html_entity_decode('█', ENT_NOQUOTES, 'UTF-8'); // full block
$shade = html_entity_decode('░', ENT_NOQUOTES, 'UTF-8'); // light shade

Now, a progress bar isn’t exactly a box, so let’s demonstrate:

$tl = html_entity_decode('╔', ENT_NOQUOTES, 'UTF-8'); // top left corner
$tr = html_entity_decode('╗', ENT_NOQUOTES, 'UTF-8'); // top right corner
$bl = html_entity_decode('╚', ENT_NOQUOTES, 'UTF-8'); // bottom left corner
$br = html_entity_decode('╝', ENT_NOQUOTES, 'UTF-8'); // bottom right corner
$v = html_entity_decode('║', ENT_NOQUOTES, 'UTF-8');  // vertical wall
$h = html_entity_decode('═', ENT_NOQUOTES, 'UTF-8');  // horizontal wall

echo $tl . str_repeat($h, 15)  . $tr . "\n" .
     $v  . ' Hello, World! '   . $v  . "\n" .
     $bl . str_repeat($h, 15)  . $br . "\n";

Voilà!

UTF-8, once you get used to it, actually provides many more possibilities than CP437 did back in the MS-DOS days. Enjoy!

Written on November 26, 2012