<?php
/**
* @Id: cssComparer.php
* @Version: 1.01
* @Author: Martijn Beulens <hide@address.com>
* @License: No license
* @Comment: Compares 2 css files for missing classes and missing arguments
*/
/**
* Usage:
* Create a blank php file with the folowing code
*
* include('cssComparer1.0.php');
*
* new cssComparer();
*
*/
/* class */
class cssComparer
{
/* Properties */
/**
* @Name: FileStructure1
* @Author: Martijn Beulens <hide@address.com>
* @Access: protected
* @Since: version 10.00001
* @Comment: Contains css structure for file 1
*/
private $FileStructure1;
/**
* @Name: FileStructure2
* @Author: Martijn Beulens <hide@address.com>
* @Access: protected
* @Since: version 10.00001
* @Comment: Contains css structure for file 2
*/
private $FileStructure2;
/**
* @Name: HtmlReport
* @Author: Martijn Beulens <hide@address.com>
* @Access: protected
* @Since: version 10.00001
* @Comment: Contains html report
*/
private $HtmlReport;
//---------------------------------------------------------------------------------------
/**
* @Name: __construct
* @Author: Martijn Beulens <hide@address.com>
* @Param: void
* @Return: void
* @Access: public
* @Since: version 10.00001
* @Comment: constructor
*/
public function __construct()
{
//Set
$this->FileStructure1 = array();
$this->FileStructure2 = array();
$this->HtmlReport = array();
//HTTP header
$this->httpHeader();
//HTML header
$this->htmlHeader();
//FORM upload
$this->formUpload();
//Process css files
$this->processFiles();
//HTML footer
$this->htmlFooter();
}
//---------------------------------------------------------------------------------------
/**
* @Name: httpHeader
* @Author: Martijn Beulens <hide@address.com>
* @Param: void
* @Return: void
* @Access: private
* @Since: version 10.00001
* @Comment: http header for output
*/
private function httpHeader()
{
header("Content-Type: text/html; charset=UTF-8");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); //Date in past
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); //Always new
header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1
header("Cache-Control: post-check=0, pre-check=0", false); //post cehck pre check
header("Pragma: no-cache"); // HTTP/1.0
}
//---------------------------------------------------------------------------------------
/**
* @Name: htmlHeader
* @Author: Martijn Beulens <hide@address.com>
* @Param: void
* @Return: void
* @Access: private
* @Since: version 10.00001
* @Comment: HTML header for page output
*/
private function htmlHeader()
{
echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n";
echo "<html>\n";
echo "<head>\n";
echo "<title>CSS comparer</title>\n";
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n";
$this->htmlStylesheet();
echo "</head>\n";
echo "<body>\n";
echo "<h2>CSS comparer</h2>\n";
}
//---------------------------------------------------------------------------------------
/**
* @Name: htmlFooter
* @Author: Martijn Beulens <hide@address.com>
* @Param: void
* @Return: void
* @Access: private
* @Since: version 10.00001
* @Comment: HTML footer for page output
*/
private function htmlFooter()
{
echo "<hr>\n";
echo "<address>Created by Abisvmm cssComparer 1.0</address>\n";
echo "</body>\n";
echo "</html>\n";
}
//---------------------------------------------------------------------------------------
/**
* @Name: htmlStylesheet
* @Author: Martijn Beulens <hide@address.com>
* @Param: void
* @Return: void
* @Access: private
* @Since: version 10.00001
* @Comment: HTML stylesheet for page output
*/
private function htmlStylesheet()
{
echo "<style type=\"text/css\">\n";
echo "label input { margin: 0px 0px 0px 4px; width: 600px; } ";
echo ".function { color: #FF00FF; }\n";
echo ".argument { color: #000099; }\n";
echo ".value { color: #0000FF; }\n";
echo ".error { color: #FF0000; }\n";
echo ".cell { padding: 4px; border: 1px solid ThreeDShadow; }\n";
echo ".header { background-color: HighLight; color: HighLightText} \n";
echo "</style>\n";
}
//---------------------------------------------------------------------------------------
/**
* @Name: formUpload
* @Author: Martijn Beulens <hide@address.com>
* @Param: void
* @Return: void
* @Access: private
* @Since: version 10.00001
* @Comment: Upload form for css files
*/
private function formUpload()
{
echo "<fieldset>\n";
echo "<legend>Upload</legend>\n";
echo "<form action=\"\" method=\"post\" enctype=\"multipart/form-data\" name=\"frmUpload\" id=\"frmUpload\">\n";
echo "<label>Css file 1<input type=\"file\" name=\"file1\" /></label><br />\n";
echo "<label>Css file 2<input type=\"file\" name=\"file2\" /></label><br />\n";
echo "<br />\n";
echo "<input type=\"submit\" value=\"Compare\">\n";
echo "</form>\n";
echo "</fieldset>\n";
}
//---------------------------------------------------------------------------------------
/**
* @Name: processFiles
* @Author: Martijn Beulens <hide@address.com>
* @Param: void
* @Return: void
* @Access: private
* @Since: version 10.00001
* @Comment: Process the file upload & compare process
*/
private function processFiles()
{
//Test post
if($_SERVER['REQUEST_METHOD']=='POST')
{
//Var
$Validated = true;
$Log = array();
$FileNames = array('file1','file2');
$FileTypes = array('text/css','application/x-css');
//Loop fileNames
foreach($FileNames as $FileName)
{
//Test empty
if(empty($_FILES[$FileName]))
{
$Validated = false;
$Log[] = $FileName." is empty";
}
else
{
if($_FILES[$FileName]['error']!=0)
{
$Validated = false;
$Log[] = $FileName." has upload error ".$_FILES[$FileName]['error'];
}
else
{
if($_FILES[$FileName]['size'] <= 0)
{
$Validated = false;
$Log[] = $FileName." has no contents. Size = ".$_FILES[$FileName]['size'];
}
else
{
if(!in_array(strtolower($_FILES[$FileName]['type']),$FileTypes))
{
$Validated = false;
$Log[] = $FileName." has unsupported file type (".$_FILES[$FileName]['type']."). Supported types: ".implode(', ',$FileTypes)."";
}
}
}
}
} //End foreach($FileNames as $FileName)
//Test validated
if($Validated)
{
//File names
$FileName1 = $_FILES['file1']['name'];
$FileName2 = $_FILES['file2']['name'];
//Read files
$fileData[1] = $this->formatCss(implode('',file($_FILES['file1']['tmp_name'])));
$fileData[2] = $this->formatCss(implode('',file($_FILES['file2']['tmp_name'])));
//Read structures
$this->extractCssClasses($this->FileStructure1,$fileData[1]);
$this->extractCssClasses($this->FileStructure2,$fileData[2]);
//Compare classes
$this->compareCssClasses($this->FileStructure1,$this->FileStructure2);
//Result
echo "<h2>Differences</h2>\n";
//Start table
echo "<table border=\"0\" cellpadding=\"2\" cellspacing=\"2\">\n";
//Header
echo "<tr>\n";
echo "<th class=\"header\">File 1 (".$FileName1.")</th>\n";
echo "<th class=\"header\">File 2 (".$FileName2.")</th>\n";
echo "</tr>\n";
//Loop
foreach($this->HtmlReport as $ar)
{
echo "<tr>\n";
echo "<td valign=\"top\" class=\"cell\"><pre>".$ar['1']."</pre></td>\n";
echo "<td valign=\"top\" class=\"cell\"><pre>".$ar['2']."</pre></td>\n";
echo "</tr>\n";
}
echo "</table>\n";
}
else
{
echo "<h3 class=\"error\">Error</h3>\n";
//Print log
echo "<ul>\n";
foreach($Log as $error)
{
echo "<li class=\"\">".$error."</li>\n";
}
echo "</ul>\n";
} //End if($Validated)
} //End if($_SERVER['REQUEST_METHOD']='POST')
}
//---------------------------------------------------------------------------------------
/**
* @Name: formatCss
* @Author: Martijn Beulens <hide@address.com>
* @Param: (string) data
* @Return: (string) data
* @Access: private
* @Since: version 10.00001
* @Comment: Format css data
*/
private function formatCss($data)
{
$data = preg_replace("/\/\*[\d\D]*?\*\//is","",$data);
//$data = str_replace(":",": ",$data);
$data = str_replace(";","; ",$data);
$data = str_replace(",",", ",$data);
$data = str_replace("{"," {",$data);
$data = str_replace("\r"," ",$data);
$data = str_replace("\n"," ",$data);
$data = str_replace("\t"," ",$data);
$data = str_replace("}","}\n",$data);
$data = str_replace(" "," ",$data);
$data = str_replace(" "," ",$data);
$data = str_replace("\n ","\n",$data);
$Lines = explode("\n",$data);
$newData = '';
foreach($Lines as $Line)
{
$Line = trim($Line);
if($Line!="")
{
$newData .= $Line."\n";
}
}
return trim($newData);
}
//---------------------------------------------------------------------------------------
/**
* @Name: extractCssClasses
* @Author: Martijn Beulens <hide@address.com>
* @Param: &(array) structure
* @Return: (string) cssdata
* @Access: private
* @Since: version 10.00001
* @Comment: extractCssClasses
*/
private function extractCssClasses(&$structure,$fileData)
{
$explodeFile = explode("\n",$fileData);
foreach($explodeFile as $cssMethod)
{
$pattern = "/(.*){(.*)}/is";
preg_match($pattern,$cssMethod,$result);
//Test
if(isset($result[1]) && isset($result[2]) )
{
$varName = trim($result[1]);
$arguments = trim($result[2]);
if(!isset($structure[$varName])) { $structure[$varName] = array(); }
//Expplode arguments
$argExplode = explode(";",$arguments);
foreach($argExplode as $arg)
{
//Explode on :
$fEx = explode(":",$arg);
if( isset($fEx[0]) && isset($fEx[1]) )
{
$structure[$varName][trim($fEx[0])] = trim($fEx[1]);
}
}
}
}
}
//---------------------------------------------------------------------------------------
/**
* @Name: compareCssClasses
* @Author: Martijn Beulens <hide@address.com>
* @Param: (array) structure1, (array) structure2
* @Return: void
* @Access: private
* @Since: version 10.00001
* @Comment: Compares the classes of 2 files
*/
private function compareCssClasses($Structure1,$Structure2)
{
//Var
$Differences = array();
//Loop Structure1
foreach($Structure1 as $Class=>$Arguments)
{
//Test if class exists in other
if(isset($Structure2[$Class]))
{
$diff = array_diff_key($Arguments, $Structure2[$Class]);
if(!empty($diff))
{
//Test for diff array
if(!isset($Differences[$Class])) { $Differences[$Class] = array(); }
//Set
$Differences[$Class][1] = $diff;
}
}
else
{
//Test for diff array
if(!isset($Differences[$Class])) { $Differences[$Class] = array(); }
//Set
$Differences[$Class][2] = array('error'=>'class does not exist');
}
}
//Loop Structure2
foreach($Structure2 as $Class=>$Arguments)
{
//Test if class exists in other
if(isset($Structure1[$Class]))
{
$diff = array_diff_key($Arguments, $Structure1[$Class]);
if(!empty($diff))
{
//Test for diff array
if(!isset($Differences[$Class])) { $Differences[$Class] = array(); }
//Set
$Differences[$Class][2] = $diff;
}
}
else
{
//Test for diff array
if(!isset($Differences[$Class])) { $Differences[$Class] = array(); }
//Set
$Differences[$Class][1] = array('error'=>'class does not exist');
}
}
//Loop differences
foreach($Differences as $Class=>$DiffFile)
{
//Var
$HTML[1] = "";
$HTML[2] = "";
//Start class
$HTML[1] .= "<span class=\"function\">".$Class."</span>\n<span class=\"function\">{</span>\n";
$HTML[2] .= "<span class=\"function\">".$Class."</span>\n<span class=\"function\">{</span>\n";
//Get 1
if(isset($Structure1[$Class]))
{
foreach($Structure1[$Class] as $ArgumentName=>$Value)
{
//Test difference
if(!isset($DiffFile[1][$ArgumentName]))
$HTML[1] .= "\t<span class=\"argument\">".$ArgumentName.": </span><span class=\"value\">".$Value."</span><span class=\"function\">;</span>\n";
else
$HTML[1] .= "\t<span class=\"error\">".$ArgumentName.": </span><span class=\"error\">".$Value."</span><span class=\"function\">;</span>\n";
}
}
else
$HTML[1] .= "\t<span class=\"error\">Class not found</span>\n";
//Get 2
if(isset($Structure2[$Class]))
{
foreach($Structure2[$Class] as $ArgumentName=>$Value)
{
if(!isset($DiffFile[2][$ArgumentName]))
$HTML[2] .= "\t<span class=\"argument\">".$ArgumentName.": </span><span class=\"value\">".$Value."</span><span class=\"function\">;</span>\n";
else
$HTML[2] .= "\t<span class=\"error\">".$ArgumentName.": </span><span class=\"error\">".$Value."</span><span class=\"function\">;</span>\n";
}
}
else
$HTML[2] .= "\t<span class=\"error\">Class not found</span>\n";
//End class
$HTML[1] .= "<span class=\"function\">}</span>\n";
$HTML[2] .= "<span class=\"function\">}</span>\n";
//Append to report
$this->HtmlReport[] = $HTML;
}
}
//---------------------------------------------------------------------------------------
} //End class cssComparer
?>