highlight_string hightlight_file | The Viable Alternative : 5ubliminal's TellinYa

<a href="http://www.tellinya.com/art2/262/">highlight_string hightlight_file | The Viable Alternative : 5ubliminal's TellinYa</a>
Must Reads: Web Scraping | Link Farming | Code Snippets | SEO Freeware
Reveal More!
The greatest PHP Highlighting Ever!

Success. Several hours of work to reinvent the wheel … but what a wheel! I didn't like the highlight_string function because it did not allow me to use my own styles so I had to remake it. Actually I use the ouput of the original function and deface it beyond recognition.

And the output is outstanding … at least I'm very happy with it!

The challenges in recoding it!

This highlight_string function was written just for the very purpose of existing. It's output is a disaster and I had to overcome it. The first version was done quite fast. About 10 minutes and it was done. But I wanted to set underlined style for phpkeywords class which is the color code 007700 in the original output.

This is when it hit me! All the   were actually inserted in spans and the underline was taking the entire row. They also considere operators as keywords and inside keywords I also had (){}=- and all other signs.

So I had to turn the disaster above in the beauty below:

As you notice the grey highlights are actually operators which I removed from the kewyord class and created their own operator class. It's all controlled from CSS and the output is an array of lines to use in an OL or UL. The yellow things are the PHP functions which are links to the PHP site documentation.

The functions are searched in a file that has to be named funclist.txt - click to get it. If the file does not exists the function will have regular ordinary look but I will give you the file too so you can make extra pretty PHP formatting to share your PHP scripts online.

The PHP Source Code:

The beautiful code below is output by this very function. It looks so good. And it can be completely altered through CSS as you see in it's header. It can play nicely with HTML code also and link to it if you like it!

<?
//-----------------------------------------------------------------
//-- Copyright 5ubliminal 2007. (5ubliminal.com)
// http://www.tellinya.com/art2/262/
// You can do anything with it except selling it or claiming it
// Copyright notice must remain intact!
//-----------------------------------------------------------------
/*
<style type="text/css">
ol.phpcode{
    color:#008; margin:0px; padding:0px;
    padding-left:50px; list-style-position:outside;
    line-height:12px; font-size:11px; white-space:nowrap;
}
ol.phpcode li{ font-family:courier new; margin:1px; padding:1px; color:#aaa; }
ol.phpcode li:hover{ color:#000; }
ol.phpcode li .phpdefault { color:#00b; font-weight: normal;}
ol.phpcode li .phpkeyword { color:#0be; text-decoration:underline;}
ol.phpcode li .phpstring  { color:#f00; font-weight: normal;}
ol.phpcode li .phpcomment { color:#9c0; font-weight: normal;}
ol.phpcode li .phpoperator { color:#999; text-decoration: none; background-color:#eee; }
ol.phpcode li .phphtml { color:#456; background-color:#eee; border:1px solid #ddd;}
ol.phpcode li .phpfunction{ color:#123; text-decoration:none; background-color:#ff0; }
ol.phpcode li .phpfunction:hover{ color:#000; text-decoration:underline; }
</style>
*/
function highlight($source,$linkfuncs = false){
    //We trim spaces
    $source = trim($source);
    //We hightlight it using old function!
    $source = highlight_string($source,true);
    //We strip some unwanted fat
    //Version sanity check!
    if (version_compare( phpversion(), "5.0.0", "<")){
        $source = str_replace("</font>", "</span>", $source);
        $source = preg_replace("/<font color=\"#([0-9A-F]{6})\">/is", "<span style=\"color: #$1\">", $source);
    }
    $source = preg_replace (
        array (
            '/.*<code>\s*<span style="color: #000000">/' , //Start
            '/<\/span>\s*<\/code>/',    //  <code><span black>
            '/<span[^>]*><\/span>/'    // empty spans
        ),array('','',''),$source);
    //We convert color codes to classes.
    $source = str_replace(
        array(
            'style="color: #0000BB"','style="color: #007700"',
            'style="color: #DD0000"','style="color: #FF8000"'
        ),
        array(
            'class="phpdefault"','class="phpkeyword"',
            'class="phpstring"','class="phpcomment"'
        ),
    $source);
    //Challenge one! Removing spaces from withing entities and switching them to style default
    //We have to ditch all &nbsp; that are included in spans.
    //They need no style but can mess the looks up completely.
    if(preg_match_all("/<span class=\"([^\"]+)\">(.*?)<\/span>/si",$source,$fixSpans)){
        for($i=0;$i<count($fixSpans[0]);$i++){
            $spanML = $fixSpans[0][$i];
            $spanType = $fixSpans[1][$i];
            $spanCode = $fixSpans[2][$i];
            $spanCode = str_replace("<br />","\n",$spanCode);
            $spanCode = preg_replace(
                "/&([nsbp;&]+);/i",
                "</span>&$1;<span class=\"$spanType\">",
                $spanCode
            );
            $source = str_replace($spanML,
                "<span class=\"$spanType\">".nl2br($spanCode)."</span>",
                $source
            );
        }
    }
    //We do some more fixes again here excluding BR from tags also!
    $source = preg_replace("/<span[^>]*><\/span>/i",'',$source);
    $source = preg_replace("/<br \/>\s*<br \/>/i",'<br />',$source);
    $source = preg_replace("/<br \/>\s+<\/span>/i",'</span><br />',$source);
    //Challange two! Let's take away signs from keywords type!
    //We now convert ?{()} and so on to another span class called operator.
    //Easier to handle in CSS and keeps function names alone.
    if(preg_match_all("/<span class=\"phpkeyword\">(.*?)<\/span>/si",$source,$fixKeys)){
        //Not so easy to fulfill this task. Took me over an hour of
        //different approaches to succeed.
        $fixKeys = array_unique($fixKeys[1]);
        $fixKeys = array_values($fixKeys);
        $oldKeys = $fixKeys; //We keep old HTML codes as we'll mess'em up good!
        foreach($fixKeys as $fixKeyIndex => $fixKey){
            $fixKey = str_replace("<br />","\n",$fixKey);
            $fixKeys[$fixKeyIndex]=html_entity_decode($fixKey);
        }
        for($i=0;$i<count($fixKeys);$i++){
            $keyCode = $fixKeys[$i];
            $oldCode = $oldKeys[$i];
            $keyML = "<span class=\"phpkeyword\">".$oldCode."</span>";
            $slices = preg_split("/([a-z_0-9]+)/i",
                $keyCode, -1,
                PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY
            );
            //We make up new HTML here
            $keyNML = "";
            foreach($slices as $slice){
                if(preg_match("/^[a-z_0-9]+$/i",$slice)){
                    //We found a keyword
                    $keyNML .= "<span class=\"phpkeyword\">".nl2br($slice)."</span>";
                    continue;
                }
                //We found an operator
                $slice = htmlentities($slice);
                $keyNML .= "<span class=\"phpoperator\">".nl2br($slice)."</span>";
            }
            //We replace old one
            $source = str_replace($keyML, $keyNML, $source);
        }
    }
    //Final source fixes!
    $source = preg_replace("/<br \/>\s*<br \/>/i",'<br />',$source);
    $source = preg_replace("/<br \/>\s+<\/span>/i",'</span><br />',$source);
    $source = preg_replace("/\s+/",' ',$source);
    $source = str_replace("\"> ",">",$source);
    //Do we have a function list?
    //If you have the funclist file in same folder with script include
    //it will use it to hightlight functions with a new class = phpfunction
    $funcFile = dirname(__FILE__)."/funclist.txt";
    if(file_exists($funcFile)){
        $funcsText = file_get_contents($funcFile);
        $funcList = preg_split("/[\r\n]+/", $funcsText);
        //Locate all functions. They have to be surrounded by >function_name<
        if(preg_match_all("/>([a-z_0-9+]+)</i",$source,$funcs)){
            $funcs = $funcs[1];
            foreach($funcs as $func){
                if(!in_array($func, $funcList)) continue;
                if($linkfuncs){
                    //If you set this parameter to true it will convert function to a link
                    $source = str_replace(">$func<",
                        "><a href=\"http://php.net/$func\" ".
                        "rel=\"nofollow\" target=\"_blank\" class=\"phpfunction\">$func</a><",
                        $source
                    );
                }else{
                    //Otherwise it will just be static.
                    $source = str_replace(">$func<",
                        "><span class=\"phpfunction\">$func</span><",
                        $source
                    );
                }
            }
        }
    }
    //If we have line breaks within spans TAGS remained unclosed when lines are split
    //and it all goes down the drain! We have to fix it!
    //We insert close,open span on every new line so it can go inside LI or other tags
    $source = str_replace("<br />", "\r\n", $source);
    if(preg_match_all("/<span class=\"([^\"]+)\">([^<]+)<\/span>/i",$source,$spans)){
        for($i=0;$i<count($spans[0]);$i++){
            $spanML = $spans[0][$i];
            $spanType = $spans[1][$i];
            $spanCode = $spans[2][$i];
            if(!strstr($spanCode,"\n")) continue;
            $spanCode = str_replace("\r\n",
                "</span>\r\n<span class=\"$spanType\">", $spanCode
            );
            $source = str_replace($spanML,
                "<span class=\"$spanType\">".$spanCode."</span>", $source
            );
        }
    }
    $lines = preg_split("/[\r\n]+/",trim($source));
    //If a line has no span inside ... I swear to GOD it's HTML
    //Let's give HTML a new class of its own
    foreach($lines as $index => $line){
        //It's PHP ... we go on
        if(strstr($line,"<span")) continue;
        //If no span is found this line contains HTML code
        //So we apply it a new class = phphtml
        $line = "<span class=\"phphtml\">".$line."</span>";
        $lines[$index] = $line;
    }
    //OMFG! It's over!
    return $lines;
}
//--
?>

13 Comments Posted By Readers :

Add your comment
#1 phpBuddy from Sweden web
Posted on Saturday, 19 January, 2008
And how do I download your great highlight function? I tried to copy and paste. But ended up with 180 line numbers that corrupt my code! Sorry to say, this is an example HOW NOT TO publish php code. Thanks for the script. But I wont use it and I can not use it, until all those line numbers are gone ....... ;) Regards, phpBuddy
#2 5ubliminal web
Posted on Saturday, 19 January, 2008
After I read your message I burst in tears. Crying uncontrollably I made efforts to write this message.
I have to say I use Opera and both Opera and IE do not copy/paste line numbers.
If FireFox is dumb enough to copy/paste line numbers … I have to say I'm sorry and I suggest you change your browser.

The whole idea of this is to demonstrate it can also be placed in lists for line numbers that's why I'm not going to remove them.
So get a real browser (Opera) or email FireFox and tell them to fix this stupid flaw.

Cheers ;)
#3 phpBuddy from Sweden web
Posted on Saturday, 19 January, 2008
There are plenty of other reasons that you may consider using Firefox instead of IE7. right now firefox has got something like 30% of used browsers and this number will only increase if I have understood the signs correctly I will try to remove your 180 !! line numbers, manually, because your script seems like a good one. But how many of your readers would bother ..... A simple file download, highlight.txt or highlight.zip ot maybe even using the option to show php files: >>>> highlight.phps

That is if you really want peple to use your script. It is called USER FRIENDLINESS and Microsoft with IE7 are good at this. Otherwise you can forget my advice. Those who kill the messenger and the critics will never improve and develop in a progressive way. Regards, phpBuddy
#4 5ubliminal web
Posted on Saturday, 19 January, 2008
You must have missed something. I said I use OPERA Browser but it works in IE7 too!
I do have FireFox installed just for the Google toolbar … not to use it. It can't compare to Opera!
2nd thing: I'd like to have a valid email from you to notify you of replies. That's user friendlyiness.
I'm not really friendly and, aside from the fact the script is free … I want you to put in some effort for copy / paste!

If I charge you for it I'll deliver it by snail mail with an autograph. Otherwise … you have to walk the extra inch of copy / paste!
I'm not gonna integrate the script in your site for you. That's provided by the commercial side of life.

Cherrs.
PS: I'm not user friendly. Especially with those who just want to pick on me for stupid reasons (like the copy/paste challenged). I level them!
#5 JD from United States
Posted on Thursday, 31 January, 2008
I use Firefox and it doesn't copy the numbers..
#6 Duffman from Germany
Posted on Monday, 04 February, 2008
I got a problem.
I included the function, but when I use it like that:
$code = highlight(§this);
echo $code;

I only get "Array"...
#7 5ubliminal web
Posted on Monday, 04 February, 2008
:) Indeed. The function returns an array in case you use it with OL combined with LI.
To use text alone you need to implode text with
or <br>. Use print_r to see it's output.

Tell me if you got other problems.
#8 Duffman from Germany
Posted on Tuesday, 05 February, 2008
hmm I guess you got me wrong... I don't get an Array but only the word "Array" :(
But still thanks for your help and that great function.. gonna try to get it to work!

Oh and btw, you got a little mistake in your code on line 61. Theres a "&;nbsp;" before the replace.

Greetings
Duffman
#9 5ubliminal web
Posted on Tuesday, 05 February, 2008
It must be the damn HTML encoding. I'll check it out today.

I'll email you later my copy which works but make sure you PHP is wellformed.
The code you see on site in the latest post is generated with it.
#10 Duffman from Germany
Posted on Tuesday, 05 February, 2008
Thank you for your efforts :)
I kinda got it to work, but it doesn't highlight as in your post but like the usual highlight_string-function, which really doesn't look very nice.
Well I'll keep trying, maybe I get it to work without your help :D
#11 5ubliminal web
Posted on Tuesday, 05 February, 2008
I updated the site version with my latest which overcomes the PHP 5 limitation.
I hope you noticed the old one was only PHP 5+ compatible.
This one works with PHP4 also.

PS: If this doesn't work use my email and send over the code your run it against. I haven't gotten it to fail using valid PHP code or HTML so I'm curious.
#12 Duffman from Germany
Posted on Tuesday, 05 February, 2008
Yes I noticed and i got PHP5 on my server.How ever, it works now! Thank you soooo much!!!
#13 5ubliminal web
Posted on Tuesday, 05 February, 2008
You're soooooo welcome :)
Post Feedback 
Name *
Mail *
URL
« Anti-Spam
» URL will only go live after a review. Comments are moderated. «
5ubliminal's TellinYa.com SEM & SEO Blog © 2007 - All rights reserved unless mentioned otherwise .
Rendered On : [Thursday, 07 August, 2008 - 23:42:30 GMT]   No Ajax / Flash Used Here
" highlight_string hightlight_file | The Viable Alternative : 5ubliminal's TellinYa "