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(""");
// 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\"><p class=\"code\"><br />";
echo htmlentities($this->output, ENT_QUOTES);
echo "<br /></p></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: \"Courier New\",Courier, monospace;";
echo "<br /> color: #0000BB;";
echo "<br /> border-style: solid;";
echo "<br /> background-color: #DDDDDD;";
echo "<br />}<br />";
echo "<br />.blue {<br /> color: #0000BB<br />}";
echo "<br />";
echo "<br />.red {<br /> color: #DD0000<br />}";
echo "<br />";
echo "<br />.orange {<br /> color: #FF8000<br />}";
echo "<br />";
echo "<br />.green <br />{<br /> 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\"><p class=\"code\"><br />";
echo htmlentities($this->output, ENT_QUOTES);
echo "<br /></p></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: \"Courier New\",Courier, monospace;";
echo "<br /> color: #0000BB;";
echo "<br /> border-style: solid;";
echo "<br /> background-color: #DDDDDD;";
echo "<br />}<br />";
echo "<br />.blue {<br /> color: #0000BB<br />}";
echo "<br />";
echo "<br />.red {<br /> color: #DD0000<br />}";
echo "<br />";
echo "<br />.orange {<br /> color: #FF8000<br />}";
echo "<br />";
echo "<br />.green <br />{<br /> 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(" ");
$found = true;
break;
case 38:
// & Symbol
$this->addColour("green");
$this->addSymbol("&");
$found = true;
break;
case 60:
// Less than <
$this->addColour("green");
$this->addSymbol("<");
$found = true;
break;
case 62:
// Greater than >
$this->addColour("green");
$this->addSymbol(">");
$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(" ");
$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(""");
$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(""");
// 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;
}
}
?>


