Barnaby Norman

Coluored Code - PHP Source Code

Barnaby Norman Home Page | Site Map | Family Norman Genealogy Site | Contact Me

PHP

ColouredCode.class

This object takes the plain source code and iterates through each character as an array and finds symbols and keywords and creates an output string containing spans used to add CSS colour attributes appropriately.

On Instantiation of an instance of the object ColouredCode class the class variables are given initial values and an instance of the SQL class (an extended class of mysqli used to simplify access to the database) is created. The string passed to the object is converted into any array called $line[], at this stage.

The calling application will call the reader() function to process the string and in-turn calls the displayOutput() function. This function loops until the array containing the plain source code has exhausted. The function makes three tests depending on the first character in the array and will return to the beginning of the loop upon success in the test. If it fails the criteria the flow falls down to the next level and further tests until the last else statement where the character is added using the default colour.

Part of ColouredCode.class showing the main function: reader():

function reader()
{
    
// Main function used to process string
        
    // Loop through each character until end of string
    
while($this->line)
    {
        
// Test for symbols
        
if(!$this->testSymbols()){                
                
            
// None found now check for special characters
            
if(!$this->testSpecials()){
                
                
// No special characters now so look for a word chunk
                
if($word $this->wordFinder->find($this->line)){
                        
                    
// Test if what found is a php keyword
                    
$this->testWord($word);
                }
                else{
                    
// Catch what is left
                    
$this->addColour("blue");
                    
$this->addToWord();
                }
            }
        }
    }
        
    
$this->displayOutput();
}

The first test is made in the testSymbols() function. This function loops through an array of symbols used in PHP and if one matches with the first character of the line[] array the function calls on a function to begin a new span to add the green colour (if required) and it is added to the output string and removed from the line[] array. Also a flag is set to return to the calling function to indicate success and the looping through the symbols is stopped.

Part of ColouredCode.class showing the function testSymbols():

function testSymbols()
{
    
$retState false;

    
// Create an array of symbols to test
    
$symbolArr array("("")""{""}"";""[""]""=""-""+""*"".""|"":");

    
// Loop through each symbol and comparing against or array character
    
foreach($symbolArr as $symbol)
    {
        if(
$this->line[0] == $symbol)
        {
            
// Add to output when found and flag found and break out
            
$this->addColour("green");
            
$this->addToWord();

            
$retState true;
            break;
        }
    }

    return 
$retState;    
}

If I was rewriting to make the code faster and more efficient I would make the array: symbolArr a class variable and populate it at the start as this function is probably called a lot and currently each time this array is populated.

The second test is made in the testSpecials() function. This function uses a switch function based on the character code of the first character in the line[] array. The function identifies symbols that are used in html and detects text strings and comments. Although the majority of these characters could be converted using the PHP function htmlspecialchars() I wrote it this way to allow more testing for some of the characters. In hindsight I could split the function into two or three functions, testing for html characters, text strings and comments.

Part of ColouredCode.class showing part of the function testSpecials():

function testSpecials()
{
    
// Reset found flag
    
$found false;
    
    
// Switch based on character code
    
switch(ord($this->line[0]))
    {
        case 
32:

            
// Space
            
$this->addSymbol(" ");

            
$found true;
            break;

Text strings begin with the first double quote " and ends with the same. When a quote is discovered the function loops until either the line[] array is exhausted or the second quote is identified. The function tests for exceptions to this rule when the preceding character is an escape symbol \. Between the quotes all characters are ignored and sent to the output string in red. The last character used is stored in the class variable lastCal.

Part of ColouredCode.class showing part of the function testSpecials():

case 34
            
    
// Double quotes ""
    
$this->addColour("red");
    
$this->addSymbol(""");
    
$stopGo true;
                        
    
// Skip for empty string in quotes
    
if(ord($this->line[0]) == 34)
    {
        
$stopGo false;
    }

    
// Loop while flag set
    
while ($stopGo)
    {
        if (ord(
$this->line[0]) == 13)
        {
            
$this->addSpecial("<br />");
                    
            if(ord(
$this->line[0]) == 10)
            {
                
$this->shift();
            }
        }
                    
        
// Add data, converting any special chars as going along
        
$this->addSymbol(htmlspecialchars($this->line[0], ENT_QUOTES));
                
        
// Test data still available
        
if(count($this->line) < 1)
        {
            
$stopGo false;
            
// No data - flag to stop
        
}
        else
        {
            
// Test for second quote and flag if found to stop loop
            
if(ord($this->line[0]) == 34)
            {
                
$stopGo false;
                                
                
// Test the previous char and unflag if escape charater (\)
                
if (ord($this->lastCal) == 92)
                {
                    
$stopGo true;
                }
            }
        }
    }

    
// Add to output
    
$this->addSymbol("&quot;");
                        
    
// Flag return value for calling function
    
$found true;
    break;

The test for comments works in a similar way but it ends with the end of the line (tested by new line and carriage return characters). If a forward slash is detected the function tests the next character in the array to see if it is also a forward slash.

Part of ColouredCode.class showing part of the function testSpecials():

case 47:
        
// Forward slash /
                
        // Test if next character is forward slash
        
if (ord($this->line[1]) == 47)
        {
            
$this->addColour("orange");

            
// Run until new line / carriage return
            
while ((ord($this->line[0]) !10) && (ord($this->line[0]) !13))
            {
                
// Add all charaters + convert specials into html
                
$this->addSymbol(htmlspecialchars($this->line[0], ENT_QUOTES));
            }
        }
        else
        {
            
// Not comments line so just add it in green
            
$this->addColour("green");
            
$this->addToWord();
        }
            
$found true;
        break;

The third and final test is a search for a keywords, which is achieved in two parts; the first part isolates a word from the complete line[] array (delimitated by a space), found using an instance of the wordFinder class and the second part tests the word (if found) for matching a keyword in the function testWord():

Part of ColouredCode.class showing the function testWord():

function testWord($word)
{    
    
// Test if word is found
    
if($this->findPHPWord($word))
    {
        
// Is a key word
        
$this->addColour("green");
        
        
$this->addWord($word);
    }
    else
    {    
        
// Not a key word
        
$this->addColour("blue");
        
        
$this->addWord($word);
    }
}

The testWord() function passes the testing function to findPHPWord() and then calls functions to change the colour (if needed) and adds the complete word to the output string, depending on if its found or not.

Function findPHPWord() takes the isolated word and uses a SQL select statement to search for it. If the word is found in the database the if satement in testWord() is true and the word is coloured green instead of blue.

Part of ColouredCode.class showing the function findPHPWord():

function findPHPWord($word)
{
    
// Search database for the word
    
$sql "SELECT * from words WHERE keyWord = '$word'";

    
$rs $this->mysql->query($sql);

    
// The result set will return false if not found
    
return mysqli_fetch_array ($rs);
}

The other functions are used often and are small in scale and have little processing, but I used them because it makes a distinction as to what a function is doing and removes a lot of repetition. I will list them in the order that they appear.

Function addColour() is the most complex of these support functions. It first tests if the colour used has the same class or style as the one in the last span used and only if it has changed will it close the previous span and open a new one. The function checks if inline styles or a style sheet is to be used in the span.

Part of ColouredCode.class showing the function addColour():

function addColour($colId)
{    
    
// Adds <span> tags to add colour style to the code
        
    // If not changed skip
    
if($this->colour !$colId)
    {        
        
// Test for use of inline styles
        
if($this->style == "inline")
        {
            
// Close previous span and open new one depending on colour
            
switch($colId)
            {
                case 
"green" $this->output $this->output 
                                            
"</span><span style=\"color: #007700\">";
        
                    break;

                case 
"red" $this->output $this->output 
                                            
"</span><span style=\"color: #DD0000\">";
        
                    break;

                case 
"orange" $this->output $this->output 
                                            
"</span><span style=\"color: #FF8000\">";
        
                    break;

                case 
"blue" $this->output $this->output 
                                            
"</span><span style=\"color: #0000BB\">";
        
                    break;
            }
        }
        else
        {
            
// Use the name in the class
            
$this->output .= "</span><span class=\"$colId\">";
        }
        
        
// Record the new colour for testing next time
        
$this->colour $colId;
    }
}

Function addToWord() simply adds the current character from the front of the line[] array to the output and calls the shift() function to remove it from the array.

Part of ColouredCode.class showing the function addToWord():

function addToWord()
{
    
// Add one character to the output string
    
$this->output $this->output $this->line[0];
        
    
// Remove it from the array
    
$this->shift();
}

Function addSymbol() works in the same way as the above but the html to represent the symbol is passed to the function.

Part of ColouredCode.class showing the function addSymbol():

function addSymbol($symbol)
{
    
// Add the html code in symbol to output string
    
$this->output $this->output $symbol;
        
    
// Remove the character it represents from the array
    
$this->shift();
}

Function addWord() adds multiple characters to the output string. First it counts how many characters are in the word and it calls the shift() function that many times.

Part of ColouredCode.class showing the function addWord():

function addWord($word)
{    
    
// Get the length of the word passed
    
$len = strlen($word);
        
    
// Call shift for the amount of chars found
    
for($x=0$x<$len$x++)
    {
        
$this->shift();
    }
        
    
// Add word to output string
    
$this->output $this->output $word;
}
}

Function shift() records the current character at the front of the line[] array as in the lastCal class variable and then uses the PHP array function array_shift to remove the element.

Part of ColouredCode.class showing the function shift():

function shift()
{
    
// Record the last character used
    
$this->lastCal $this->line[0];
        
    
// Remove it from the array
    
array_shift($this->line);
}

The final function is dislayOutput(). This function is called by the reader() function when all processing is complete. The function creates two outputs; one with inline mark-up added and the other without. Depending on the user's choice either could be converted using the PHP function htmlentities() to offer the user for pasting.

Part of ColouredCode.class showing the function dislayOutput():

function displayOutput(){
        
    
// Create display string with style markup
    
$displayOutput "<p class=\"code\">";
    
$displayOutput .= $this->output;
    
$displayOutput .= "</p>";

    
// Set the output to use style marked-up string if inline selected
    
if($this->style == "inline")
    {
        
$this->output $displayOutput;
    }
        
    
// Output the coloured code to the screen
    
echo "<h3>The colored code:</h3>" $displayOutput;
        
    
// Add Span at start and end
    
$this->output "<span class=\"blue\">" $this->output "</span>";
        
    
// Output the html that can be pasted into the user's file
    
echo "<h3>Paste this into your HTML file:</h3><p class=\"code\">&lt;p class=\"code\"&gt;<br />";
    echo htmlentities(
$this->output, ENT_QUOTES);    
    echo 
"<br />&lt;/p&gt;</p>";

    
// Display the stylesheet markup for user to add if selected
    
if($this->style == "styleSheet")
    {
        echo 
"<h3>Style Sheet</h3>";
        echo 
"<p class=\"code\">pre{<br />";
        echo 
" font-family:&nbsp;&nbsp;&nbsp;\"Courier New\",Courier, monospace;";
        echo 
"<br />&nbsp;&nbsp;&nbsp;color: #0000BB;";
        echo 
"<br />&nbsp;&nbsp;&nbsp;border-style: solid;";
        echo 
"<br />&nbsp;&nbsp;&nbsp;background-color: #DDDDDD;";
        echo 
"<br />}<br />";
        echo 
"<br />.blue {<br />&nbsp;&nbsp;&nbsp;color: #0000BB<br />}";
        echo 
"<br />";
        echo 
"<br />.red {<br />&nbsp;&nbsp;&nbsp;color: #DD0000<br />}";
        echo 
"<br />";
        echo 
"<br />.orange {<br />&nbsp;&nbsp;&nbsp;color: #FF8000<br />}";
        echo 
"<br />";
        echo 
"<br />.green <br />{<br />&nbsp;&nbsp;&nbsp;color: #007700";
        echo 
"<br />}<br /></p>";
    }
}

The full source code for the class follows

ColouredCode.class (full source code):

<?php

require_once "WordFinder.class";
require_once 
"SQL.class";

class 
ColouredCode
{
    
    private 
$line;
    private 
$output;
    private 
$lastCal;
    private 
$quotes;
    private 
$wordFinder;
    private 
$comments;
    private 
$style;
    private 
$colour;
    private 
$mysql;
    private 
$lineCount;
    
    function 
__construct($line, $style)
    {
        
// Initialise class variables
        
$this->line str_split($line);
        
$this->output "";
        
$this->lastCal "";
        
$this->quotes false;
        
$this->wordFinder new WordFinder();
        
$this->style $style;
        
$this->colour "blue";
        
$this->mysql new SQL("phpWords");
        
$this->lineCount 0;
    }

    function 
reader()
    {
        
// Main function used to process string
        
        // Loop through each character until end of string
        
while($this->line)
        {
            
// Test for symbols
            
if(!$this->testSymbols()){                
                
                
// None found now check for special characters
                
if(!$this->testSpecials()){
                    
                    
// No special characters now so look for a word chunk
                    
if($word $this->wordFinder->find($this->line)){
                        
                        
// Test if what found is a php keyword
                        
$this->testWord($word);
                    }
                    else{
                        
// Catch what is left
                        
$this->addColour("blue");
                        
$this->addToWord();
                    }
                }
            }
        }
        
        
$this->displayOutput();
    }
    
    function 
displayOutput(){
        
        
// Create display string with style markup
        
$displayOutput "<p class=\"code\">";
        
$displayOutput .= $this->output;
        
$displayOutput .= "</p>";

        
// Set the output to use style marked-up string if inline selected
        
if($this->style == "inline")
        {
            
$this->output $displayOutput;
        }
        
        
// Output the coloured code to the screen
        
echo "<h3>The colored code:</h3>" $displayOutput;
        
        
// Add Span at start and end
        
$this->output "<span class=\"blue\">" $this->output "</span>";
        
        
// Output the html that can be pasted into the user's file
        
echo "<h3>Paste this into your HTML file:</h3><p class=\"code\">&lt;p class=\"code\"&gt;<br />";
        echo htmlentities(
$this->output, ENT_QUOTES);    
        echo 
"<br />&lt;/p&gt;</p>";

        
// Display the stylesheet markup for user to add if selected
        
if($this->style == "styleSheet")
        {
            echo 
"<h3>Style Sheet</h3>";
            echo 
"<p class=\"code\">pre{<br />";
            echo 
" font-family:&nbsp;&nbsp;&nbsp;\"Courier New\",Courier, monospace;";
            echo 
"<br />&nbsp;&nbsp;&nbsp;color: #0000BB;";
            echo 
"<br />&nbsp;&nbsp;&nbsp;border-style: solid;";
            echo 
"<br />&nbsp;&nbsp;&nbsp;background-color: #DDDDDD;";
            echo 
"<br />}<br />";
            echo 
"<br />.blue {<br />&nbsp;&nbsp;&nbsp;color: #0000BB<br />}";
            echo 
"<br />";
            echo 
"<br />.red {<br />&nbsp;&nbsp;&nbsp;color: #DD0000<br />}";
            echo 
"<br />";
            echo 
"<br />.orange {<br />&nbsp;&nbsp;&nbsp;color: #FF8000<br />}";
            echo 
"<br />";
            echo 
"<br />.green <br />{<br />&nbsp;&nbsp;&nbsp;color: #007700";
            echo 
"<br />}<br /></p>";
        }
    }
    
    function 
testSymbols()
    {
        
$retState false;

        
// Create an array of symbols to test
        
$symbolArr array("("")""{""}"";""[""]""=""-"
                            
"+""*"".""|"":");

        
// Loop through each symbol and comparing against or array character
        
foreach($symbolArr as $symbol)
        {
            if(
$this->line[0] == $symbol)
            {
                
// Add to output when found and flag found and break out
                
$this->addColour("green");
                
$this->addToWord();

                
$retState true;
                break;
            }
        }

        return 
$retState;    
    }
    
    function 
testSpecials()
    {
        
// Reset found flag
        
$found false;
    
        
// Switch based on character code
        
switch(ord($this->line[0]))
        {
            case 
32:

                
// Space
                
$this->addSymbol("&nbsp;");

                
$found true;
                break;

            case 
38:

                
// & Symbol
                
$this->addColour("green");
                
$this->addSymbol("&amp;");

                
$found true;
                break;

            case 
60:

                
// Less than <
                
$this->addColour("green");
                
$this->addSymbol("&lt;");

                
$found true;
                break;

            case 
62:

                
// Greater than >
                
$this->addColour("green");
                
$this->addSymbol("&gt;");

                
$found true;
                break;

            case 
13:

                
// New line / carriage return
                
$this->addSymbol("<br />");
                    
                if (ord(
$this->line[0]) == 10)
                {
                    
// Remove double line space
                    
$this->shift();
                }

                
$found true;
                break;

            case 
10:

                
// New line and carriage return
                
$this->addSymbol("<br />");

                
$found true;
                break;

            case 
9:

                
// Tab character
                
$this->addSymbol("&nbsp;&nbsp;&nbsp;&nbsp;");

                
$found true;
                break;

            case 
47:

                
// Forward slash /
                
                // Test if next character is forward slash
                
if (ord($this->line[1]) == 47)
                {
                    
$this->addColour("orange");

                    
// Run until new line / carriage return
                    
while ((ord($this->line[0]) !10) && (ord($this->line[0]) !13))
                    {
                        
// Add all charaters + convert specials into html
                        
$this->addSymbol(htmlspecialchars($this->line[0], ENT_QUOTES));
                    }
                }
                else
                {
                    
// Not comments line so just add it in green
                    
$this->addColour("green");
                    
$this->addToWord();
                }

                
$found true;
                break;

            case 
34
                    
                
// Double quotes ""
                
$this->addColour("red");
                
$this->addSymbol("&quot;");
                
$stopGo true;
                        
                
// Skip for empty string in quotes
                
if(ord($this->line[0]) == 34)
                {
                    
$stopGo false;
                }

                
// Loop while flag set
                
while ($stopGo)
                {
                    if (ord(
$this->line[0]) == 13)
                    {
                        
$this->addSpecial("<br />");
                        
                        if(ord(
$this->line[0]) == 10)
                        {
                            
$this->shift();
                        }
                    }
                    
                    
// Add data, converting any special chars as going along
                    
$this->addSymbol(htmlspecialchars($this->line[0], ENT_QUOTES));
                
                    
// Test data still available
                    
if(count($this->line) < 1)
                    {
                        
$stopGo false;
                        
// No data - flag to stop
                    
}
                    else
                    {
                        
// Test for second quote and flag if found to stop loop
                        
if(ord($this->line[0]) == 34)
                        {
                            
$stopGo false;
                                
                            
// Test the previous char and unflag if escape charater (\)
                            
if (ord($this->lastCal) == 92)
                            {
                                
$stopGo true;
                            }
                        }
                    }
                }

                
// Add to output
                
$this->addSymbol("&quot;");
                        
                
// Flag return value for calling function
                
$found true;
                break;

            case 
39
                    
                
// Single quotes ''
                
$this->addColour("red");
                
$this->addSymbol("'");
                
$stopGo true;
                        
                
// Skip for empty string in quotes
                
if(ord($this->line[0]) == 39)
                {
                    
$stopGo false;
                }

                
// Loop while flag set
                
while ($stopGo)
                {
                    if (ord(
$this->line[0]) == 13)
                    {
                        
$this->addSpecial("<br />");
                        
                        if(ord(
$this->line[0]) == 10)
                        {
                            
$this->shift();
                        }
                    }
                    
                    
// Add data, converting any special chars as going along
                    
$this->addSymbol(htmlspecialchars($this->line[0], ENT_QUOTES));
                
                    
// Test data still available
                    
if(count($this->line) < 1)
                    {
                        
$stopGo false;
                        
// No data - flag to stop
                    
}
                    else
                    {
                        
// Test for second quote and flag if found to stop loop
                        
if(ord($this->line[0]) == 39)
                        {
                            
$stopGo false;
                                
                            
// Test the previous char and unflag if escape charater (\)
                            
if (ord($this->lastCal) == 92)
                            {
                                
$stopGo true;
                            }
                        }
                    }
                }

                
// Add to output
                
$this->addSymbol("'");
                        
                
// Flag return value for calling function
                
$found true;
                break;
        }
                
        return 
$found;
    }
    
    function 
addToWord()
    {
        
// Add one character to the output string
        
$this->output $this->output $this->line[0];
        
        
// Remove it from the array
        
$this->shift();
    }
    
    function 
addSymbol($symbol)
    {
        
// Add the html code in symbol to output string
        
$this->output $this->output $symbol;
        
        
// Remove the character it represents from the array
        
$this->shift();
    }
    
    function 
shift()
    {
        
// Record the last character used
        
$this->lastCal $this->line[0];
        
        
// Remove it from the array
        
array_shift($this->line);
    }

    function 
addColour($colId)
    {    
        
// Adds <span> tags to add colour style to the code
        
        // If not changed skip
        
if($this->colour !$colId)
        {        
            
// Test for use of inline styles
            
if($this->style == "inline")
            {
                
// Close previous span and open new one depending on colour
                
switch($colId)
                {
                    case 
"green" $this->output $this->output 
                                
"</span><span style=\"color: #007700\">";
        
                        break;

                    case 
"red" $this->output $this->output 
                                
"</span><span style=\"color: #DD0000\">";
        
                        break;

                    case 
"orange" $this->output $this->output 
                                
"</span><span style=\"color: #FF8000\">";
        
                        break;

                    case 
"blue" $this->output $this->output 
                                
"</span><span style=\"color: #0000BB\">";
        
                        break;
                }
            }
            else
            {
                
// Use the name in the class
                
$this->output .= "</span><span class=\"$colId\">";
            }
        
            
// Record the new colour for testing next time
            
$this->colour $colId;
        }
    }
    
    function 
testWord($word)
    {    
        
// Test if word is found
        
if($this->findPHPWord($word))
        {
            
// Is a key word
            
$this->addColour("green");
        
            
$this->addWord($word);
        }
        else
        {    
            
// Not a key word
            
$this->addColour("blue");
            
            
$this->addWord($word);
        }
    }
    
    function 
findPHPWord($word)
    {
        
// Search database for the word
        
$sql "SELECT * from words WHERE keyWord = '$word'";

        
$rs $this->mysql->query($sql);

        
// The result set will return false if not found
        
return mysqli_fetch_array ($rs);
    }
    
    function 
addWord($word)
    {    
        
// Get the length of the word passed
        
$len = strlen($word);
        
        
// Call shift for the amount of chars found
        
for($x=0$x<$len$x++)
        {
            
$this->shift();
        }
        
        
// Add word to output string
        
$this->output $this->output $word;
    }
}

?>