Archive for December 23rd, 2010

Simplified ANSI color term support in PHP

December 23rd, 2010 by Sjan Evardsson

I was working on a script that needed some color terminal output and while it wasn’t particularly complicated, I found it was slowing me down. Flipping back and forth between a list of ANSI color codes and my work was frustrating. So, I did what I am often prone to do, I did a quick Google search for a PHP ANSI color terminal library. I found some things that were old, not maintained and not really fitting what I needed. So then, I did what I always end up doing in that situation, I built one.

The ANSI class is a way to quickly create several different foreground and background color combos along with a few style effects (like underline, inverse, and if you really must, blink). Of course the style effects only work on the standard 16 ANSI VT-100 terminal colors (the normal and “bold” or “bright” versions of black, red, green, yellow, blue, purple, cyan and white.)

The simplest way to use it is to create a new ANSI object for each color combo you want. So if you want red text on a white background, underlined bright green text on a black background and blue text on a yellow background, you could create three objects like so:

include_once('ansi.class.php');
$red_white = new ANSI(ANSI::RED, ANSI::WHITE);
$bright_green_black = new ANSI(ANSI::GREEN, ANSI::BLACK, array(ANSI::BRIGHT, ANSI::UNDERLINE));
$blue_yellow = new ANSI('blue', 'yellow');

Notice that I used a couple different ways of setting the colors, the class constant ints and strings. The effects are set in an array since you can chain multiple effects on a single color scheme (until you get into the extended color space, more on that in a minute.) Once you have these objects, styling your terminal output is simple.

$red_white->p("This is red on a white background, and prints no newline.");
$bright_green_black->p("This is bright green on a black background and prints no newline.");
$blue_yellow->pline("This is blue on a yellow background and will print a newline character.");
$red_white->setInverse(true);
$red_white->pline("This is now white on a red background.");

The p() and pline() methods will spit out the correct escape sequence and color codes to style and color the text, then print the text, then spit out the correct escape sequence and color code to “reset” the term to its default. This means no running a script that displays a warning then leaves your terminal bright yellow text on a red background.

So now that the standard color space is taken care of, how about a little love for the xterm 256 color space? Simple enough. Any int value passed to the color arguments of the constructor greater than 7 will automatically invoke the 256 color space. The first 16 colors (0 – 15) are just the default terminal colors, of course, but colors 16 – 231 are the extended color space, with 24 greyscale values from colors 232 – 255. So how do we know what color is what? Well, we can either call one of the static functions to view the color space (ANSI::showForegroundColors(), ANSI::showBackgroundColors()) or we can pass in a value from the static ANSI::rgb($r, $g, $b) function, which takes, you guessed it, three integer values from 0 – 255. While ANSI::rgb() tries to get to the closest color in the color space it still needs work. The very simplistic manner in which it is currently implemented is not the most accurate. It is on my to-do list somewhere, though.

$grey_gold = new ANSI(ANSI::rgb(31, 31, 31), ANSI::rgb(204, 153, 0));
$grey_gold->pline("This is grey text on a gold background.");
// effects don't work in the extended color space, except for inverse
$grey_gold->setInverse(true);
$grey_gold->pline("This is gold text on a grey background");

If you know of any way to apply the ANSI styles (underline, blink, inverse) in conjunction with the extended color space leave a comment to let me know. If you think the script could use some extra functionality do the same.

It is not incredibly clever or full-featured or any of those sorts of things, but it does what I needed it to do. If you would like to, you can download a copy a copy of the ANSI class (ansi.class.php.zip) – it is released under the MIT license, and is free to use, copy, distribute, etc etc.