PHP’s highlight_file and highlight_string functions can do all the hard work of embedding and HTML encoding source listings in your articles and tutorials; they also syntax color any PHP code listed.

However, the generated HTML uses inline styles. There are articles, and tools like Firefox Page Speed, that warn against inline styles because they slow down browser rendering; the reality is that the impact is often miniscule. Of more concern with highlight_file is that its inline styles could significantly increase the size of your page and have a noticeable impact on download times. Can we use CSS classes instead?

A quick search showed that other people had posed this question without answer, and someone had even written their own equivalent PHP function with classes. After putting my thinking cap on I realised that using a technique similar to SQL injection provides a dead simple, and in hindsight, obvious solution:


001<?php
002# Author: Andy Wrigley wptest.means.us.com
003ini_set('highlight.default''"class="aw_default');
004ini_set('highlight.keyword','"class="aw_keyword'); 
005ini_set('highlight.string''"class="aw_string');
006ini_set('highlight.html''"class="aw_htmlsrc');
007ini_set('highlight.comment''"class="aw_comment');
008$aw_source highlight_file('your_sourcefile.ext'TRUE);
009echo 
str_replace('style="color: "''' $aw_source );
010?>

This post extends the above script to add line numbers.

This example uses highlight_file; I assume it will also work for highlight_string, but I have not tested it.


Explanation by example


1. Normal usage, default colors, no classes:

Source of mydemo.php:

<p>Some HTML</p>
<?php
# A php comment
?>

By using <?php highlight_file(mydemo.php); ?> your visitors will see:

<p>Some HTML</p>
<?php
# A php comment
?>

If you “view source” in the browser window you will see that the highlight_file has generated the following syntax colored encoded HTML. I have highlighted the comment to demonstrate how the syntax highlighter inserts spans with inline color styles:

<code><span style="color: #000000">
&lt;p&gt;Some&nbsp;HTML&lt;/p&gt;
<br /><span style="color: #0000BB">&lt;?php
<br /></span><span style="color: #FF8000">#&nbsp;A&nbsp;php&nbsp;comment
<br /></span><span style="color: #0000BB">?&gt;</span>
</span>
</code>

2. Changing default colors:

The colors used by the syntax highlighter are the values set for highlight.comment, highlight.default, highlight.html, highlight.keyword and highlight.string. You can change the default color values by using ini_set e.g. to make comments green ini_set('highlight.comment', '#00FF00').

3. Adding classes:

The syntax highlighter uses concatenation. For a comment span, simplistically something like this: outputstring .= '<span style="color: ' . ini_get(‘highlight.comment’) . '" >;'

The ini_set function does not validate the “color” value so we can set it to any string we want; and it will be inserted by the syntax highlighter between style=”color : and a closing double quote and >. So if we wanted bold red keywords: ini_set('highlight.keyword', 'red; font-weight:bold') and keyword spans would look like this: <span style="color: red; font-weight:bold">

I’ve not seen it suggested elsewhere, but we can use this same technique to add a class. All we have to do is start our string with a double quote to close the inline style and follow it by class="class_name . Do not add a closing double quote, as the syntax highlighter adds this to “close the inline style”.

003ini_set('highlight.default''"class="aw_default');
004ini_set('highlight.keyword','"class="aw_keyword'); 
005ini_set('highlight.string''"class="aw_string');
006ini_set('highlight.html''"class="aw_htmlsrc');
007ini_set('highlight.comment''"class="aw_comment');

Although this will work, all our spans will contain a superfluous style="color: ". The highlight_file function has an optional boolean parameter, if this is set to true, instead of “printing” it will return the encoded HTML as a string. We can strip out the empty inline styles before echoing.

008$aw_source highlight_file('your_sourcefile.ext'TRUE);
009echo 
str_replace('style="color: "''' $aw_source );

A final word


This trick relies on the absence of parameter validation by ini_set. I suspect this will continue to be the case, but it is possible that by the time you read this you may be using a brand spanking new release of PHP that prevents this ‘hack’.

Shameless plug: If you find this article interesting or useful then a “+1″ at the top of the page would really be appreciated.


Author Andy W+