<?php
/****************************************************************
*****************************************************************
class_log.php: create to work with log file (create and search).
Copyright (C) 2003 Matthieu MARY hide@address.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
You can found more information about GPL licence at:
http://www.gnu.org/licenses/gpl.html
for contact me: hide@address.com
****************************************************************
****************************************************************/
/**
* Can be download at
* http://www.phpclasses.org/
**/
require_once "class_dir.php";
require_once "class_specif.php";
class requirement{
/**
* the path to the ini file
* @type string
* @private
**/
var $iniFile;
/**
* the errors arrays
* @type array
* @private
**/
var $aErrors;
/**
* file to analyse
* @type string
* @private
**/
var $sFile;
/**
* dir file to analyse
* @type string
* @private
**/
var $sDir;
/**
* requirement
* @type string
* @private
**/
var $aRequirement;
/**
* array of keywords
* @type array
* @private
**/
var $aKeywords;
/**
* is there a use of require_once or include_once
* @type bool
* @private
**/
var $bRequirement;
/**
* Constructor.
*
* @public
**/
function requirement(){
$this->iniFile = './functions.ini';
$this->aErrors = array();
$this->sFile = '';
$this->sDir = '';
$this->aRequirement = array();
$this->aKeywords = array('foreach','array','for','while','if','elseif','list','each','switch','DISTINCT','COUNT','VALUES','MAX','PASSWORD','MD5','IN');
$this->bRequirement = FALSE;
}
/**
* Function that check the php file for requirement.
*
* @param string sPath_for_analyse required; the file need to be analysed
* @public
**/
function check($sPath_for_analyse='')
{
$contents = '';
$iLatest_version = '5';
$iFirst_version = '3';
$aFunctions_ini = array();
$aFunctions = array();
$bCSV = FALSE;
$sNot_formated = '';
$aLimits = array();
$aLimits_final = array();
$aFields = array();
$aNumbers = array();
$iNext = 0;
$aCheck = array();
$aLimits_detected = array();
$aVersions_required = array();
$aVersions_count = array();
$bEnd = FALSE;
// set the default values
for($i = $iFirst_version;$i < $iLatest_version;$i++){
$aLimits_detected[$i] = array(
'inf' => $i,
'sup' => ($i+1));
}
// is there a parameter?
if (trim($sPath_for_analyse)==''){
$this->aErrors[] = "missing argument 1 for checking";
return;
}
$this->sFile = realpath($sPath_for_analyse);
$this->sDir = dirname($this->sFile);
$this->aRequirement = '';
// file exist?
if (!file_exists($this->sFile)){
$this->aErrors[] = "file [".basename($this->sFile)."] doesn't exist";
return;
}
// get the array of functions
$aFunctions_ini = $this->read_ini_file();
if (!$aFunctions_ini){
$this->aErrors[] = "unable to get the function list in the inifile [".$this->iniFile."]";
$this->aErrors[] = "please use the build method on the documentation path";
return;
}
// analyse script
$aFunctions = $this->study_function($this->sFile);
$aFunctions['use'] = array_diff($aFunctions['use'],$aFunctions['declared']);
// print_r($aFunctions);
// get the requirements
foreach($aFunctions['use'] as $id => $function_name){
$aLimits = array();
$sNot_formated = trim($aFunctions_ini[$function_name]);
// get each expressions
$aFields = explode(',',$sNot_formated);
if (count($aFields)==1) $aFields = array($sNot_formated);
foreach($aFields as $i => $sReq){
if (preg_match_all("/[0-9]{1}(\.[0-9]+)*/",$sReq,$aMatches)){
$aNumbers = $aMatches[0];
$iNext = substr($aNumbers[0],0,1)+1;
$aCheck = array(
'count' => ((count($aNumbers)==1)?1:0),
'>' => preg_match("/>/",$sReq),
'<' => preg_match("/</",$sReq),
'=' => preg_match("/=/",$sReq),
'CSV' => preg_match("/CSV/",$sReq));
if ($aCheck['CSV']) $bCSV = TRUE;
if ($aCheck['count'] || $aCheck['>']){
$aLimits[] = array(
'inf' => (($aCheck['>'])?$aNumbers[1]:$aNumbers[0]),
'sup' => $iNext);
}//if
else{
$aLimits[] = array(
'inf' => $aNumbers[0],
'sup' => $aNumbers[1]);
}//else
}//if
}//foreach
if (count($aLimits)>0) $aLimits_final[] = $aLimits;
}//foreach
// set the require value
if ($this->bRequirement){
$aLimits[0] = array('inf' => '4.0.1', 'sup' => '5');
$aLimits_final[] = $aLimits;
}
// get the versions of php required
foreach($aLimits_final as $i => $aDatas){
foreach($aDatas as $id => $aLimits){
$iVersion = substr($aLimits['inf'],0,1);
$aVersions_count[] = $iVersion;
}
}
$aCount = array_count_values($aVersions_count);
arsort($aCount);
$aKeys = array_keys($aCount);
$number_max = $aCount[$aKeys[0]];
foreach($aCount as $iVersion => $iOcc){
if ($number_max == $iOcc) $aVersions_required[] = $iVersion;
else unset($aLimits_detected[$iVersion]);
}
// set the limits
foreach($aLimits_final as $i => $aDatas){
foreach($aDatas as $id => $aLimits){
$iVersion = substr($aLimits['inf'],0,1);
if (in_array($iVersion,$aVersions_required)){
if (strcmp($aLimits_detected[$iVersion]['inf'],$aLimits['inf'])<0) $aLimits_detected[$iVersion]['inf'] = $aLimits['inf'];
if (strcmp($aLimits_detected[$iVersion]['sup'],$aLimits['sup'])>0) $aLimits_detected[$iVersion]['sup'] = $aLimits['sup'];
}
}
}
$this->aRequirement = $aLimits_detected;
return $this->end();
}//check
/**
* return the requirement
*
* @private
* @type string
**/
function end()
{
$spe = new specif();
$sReturn = '';
foreach($this->aRequirement as $iVersion => $dDatas){
if (strcmp($dDatas['sup'],$dDatas['inf'])<0){
$this->aErrors[] = "this script cannot works ! [requirement min [".$dDatas['inf']."] max [".$dDatas['sup']."]";
return;
}
if ($dDatas['sup'] == ($iVersion+1)) $sReturn .= 'PHP '.$dDatas['inf'].' or later'.$spe->Endline();
else $sReturn .= 'PHP '.$dDatas['inf'].' to '.$dDatas['sup'].$spe->Endline();
}
return $sReturn;
}
/**
* Read the ini file : there is a bug in parse_ini_file function
* when this function is call on file bigger than 16 ko, there is an error
*
* @private
* @type mixed
**/
function read_ini_file()
{
$aParse = array();
if (!file_exists($this->iniFile)) return FALSE;
if (filesize($this->iniFile)<(1024*16)){
$aDatas = @parse_ini_file($this->iniFile,TRUE);
$aParse = $aDatas['function'];
}
else{
$aValues = file($this->iniFile);
$begin = FALSE;
foreach($aValues as $line_number => $line){
if ($begin){
$aFields = explode('=',$line);
$function_name = strtolower($aFields[0]);
for($i = 1,$sF = '';$i < count($aFields);$i++) $sF .= $aFields[$i]."=";
$aParse[$function_name] = trim(substr($sF,0,(strlen($sF)-1)));
}
if (!$begin) $begin = (!$begin && preg_match("/^\[function\]/",$line));
}
}
return $aParse;
}
/**
* Method build the ini file
*
* @param string max_execution_time optional, default value '.'; the PATh to the php html doc
* @public
* @type void
**/
function build($sPath_to_doc='.')
{
$dDatas = array();
$dContents = array();
// ini file already exists?
if (file_exists($this->iniFile)){
$this->aErrors[] = "ini file [".$this->iniFile."] already exists; stop build method";
return;
}
// get list of documentation file
$dir_doc = new dir($sPath_to_doc);
if ($dir_doc->DATA_errors_size()){
$this->aErrors = $dir_doc->DATA_errors();
return;
}
$aFilelist = $dir_doc->LIST_get(FALSE,array('html'));
if(count($aFilelist)==0){
$this->aErrors[] = "path [".realpath($sPath_to_doc)."] have any html files; be sure that is the documentation folder";
return;
}
// foreach function file of the doc
foreach($aFilelist as $id => $filename){
if (preg_match("/^(function)[.]/",basename($filename))){
// get its content
$contents = $this->_get_contents($filename);
if (trim($contents)=='') continue;
$aPatterns = array(
"/(\n<TT>)/",
"/(<\/TT>\n)/",
"/(>)/",
"/(<)/",
"/( )/",
"/(é)/",
"/(â)/",
"/(à)/",
"/(è)/",
"/(')/",
"/($)/",
"/(&)/");
$aReplacements = array(
" ",
" ",
">",
"<",
" ",
"é",
"â",
"à",
"è",
"'",
"$",
"&");
$contents = preg_replace($aPatterns,$aReplacements,$contents);
// get the function name
$pattern_function = '(fonction=)[a-zA-Z0-9_]+';
preg_match("/$pattern_function/",$contents,$elts);
$elts2 = preg_split("/(fonction=)/",$elts[0]);
$function_name = $elts2[1];
// get php version
$pattern_version = '(h3>\[)[0-9A-Za-z":<>= .?_\/]+(<\/A>\])[ <>=PH0-9.,CVSonlyuniquement-]+';
preg_match("/$pattern_version/",$contents,$elts3);
$aversion = explode("]",$elts3[0]);
$strrpos = ((preg_match("/[<]{1}[p]?$/",trim($aversion[1])))?strrpos($aversion[1],"<"):strlen($aversion[1]));
$version = preg_replace("/[ ]+/"," ",trim(substr($aversion[1],0,$strrpos)));
$dDatas[$function_name] = $version;
} //if
}//foreach
$dContents['function'] = $dDatas;
$this->_write_ini_file($dContents);
}//build
/**
* @shortdesc Function get contents of a file
* the contents returns have any comments
*
* @param string sFilename required; the path to the file need to be read
* @private
**/
function _get_contents($sFilename)
{
$contents = array();
$contents_line = '';
$contents_comment = array();
$contents_file = file($sFilename);
$contents = $contents_file;
$pattern = '^\/\/.*$';
$pattern2 = '\/\*';
$pattern3 = '\*\/';
// remove the comments with //
foreach($contents_file as $i => $line) if (preg_match("/$pattern/",trim($line))) $contents_comment[] = $line;
$contents = array_diff($contents,$contents_comment);
// remove the comments with /* and */
foreach($contents as $i => $line)
{
if ($bBegin) $contents_comment[] = $line;
if ($bBegin) $bBegin = (!preg_match("/$pattern3/",$line));
if (!$bBegin){
$bBegin = preg_match("/$pattern2/",$line);
if ($bBegin) $contents_comment[] = $line;
}
}
$contents = array_diff($contents,$contents_comment);
// put the content of the file without comment in line
foreach($contents as $i => $line) $contents_line .= $line;
return $contents_line;
}
/**
* Function write the ini file
*
* @param array contents required. the hashtable for the ini file
* @private
* @type bool
**/
function _write_ini_file($contents)
{
$spe = new specif();
if (!is_array($contents)) return FALSE;
$str = '; generated by ['.basename($_SERVER["PHP_SELF"]).'] on '.date('r').$spe->Endfile();
foreach ($contents as $section => $values) {
if (!is_array($values)) return FALSE;
$str .= $spe->Endfile()."[$section]";
foreach ($values as $function_name => $php_value) {
$str .= $spe->Endfile().strtolower($function_name)."=$php_value";
}
$str .= $spe->Endfile();
}
$fp = @fopen($this->iniFile,'w');
if (!$fp){
$this->aErrors[] = "unable to open the iniFile [".$this->iniFile."]";
return;
}
fputs($fp, $str);
fclose($fp);
return;
}//write_ini_file
/**
* @shortdesc get all functions and others
* Get all functions (declared and uses), get although the declared objects and the tables name of insert query
*
* @param string contents required. the contents of the script to study
* @private
* @type array
**/
function get_function_all($contents)
{
$aFunction_object = array();
$aObject = array();
$aInsert_labels = array();
// get the declared objects
$pattern = '\$[a-zA-Z_0-9]+[ ]*=[ ]*new [a-zA-Z0-9]+';
$values = $this->get_pattern($contents,$pattern);
foreach($values[0] as $i => $declared_object){
$aWords = explode("=",$declared_object);
$aObject[] = trim(substr($aWords[0],1));
}
// get the functions object use
$pattern = '(((->)|(:{2}))[A-Za-z0-9_]+)+';
$values = $this->get_pattern($contents,$pattern);
foreach($values[0] as $i => $function_object){
$aFunction_object[] = trim(substr($function_object,2));
}
// get the insert values of the script
$pattern = 'INSERT\s+INTO\s+[a-zA-Z_]+\s*\(';
$values = $this->get_pattern($contents,$pattern);
if (count($values[0])>0){
foreach($values[0] as $i => $sInsert_rq){
$matches = preg_split("/\s+/",trim($sInsert_rq),-1,PREG_SPLIT_NO_EMPTY);
$aInsert_labels[] = ((preg_match("/\(/",$matches[2]))?substr(trim($matches[2]),0,strlen($matches[2])-1):$matches[2]);
}
}
// get all the functions of the script
$pattern = '(^|[^a-zA-Z0-9_])([a-zA-Z_][a-zA-Z0-9_]*)\s*\(';
$values = $this->get_pattern($contents,$pattern);
$aReturn = array_unique(array_diff($values[2],$this->aKeywords,$aFunction_object,$aObject,$aInsert_labels));
return $aReturn;
}
/**
* get_pattern
*
* @param string contents required. the contents of the script to examine
* @param string pattern required. the pattern to reconize
* @private
* @type array
**/
function get_pattern($contents,$pattern)
{
preg_match_all("/$pattern/",$contents,$matches);
return $matches;
}
/**
* Get declared function of the script
*
* @param string contents required. the contents of the script to examine
* @private
* @type array
**/
function get_functions_declared($contents)
{
$pattern = 'function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(';
$values = $this->get_pattern($contents,$pattern);
return $values[1];
}
/**
* @shortdesc function which analyse a script
* Function that will analyse a script
*
* @param string contents required. the contents of the script to examine
* @private
* @type array
**/
function study_function($sFile)
{
// get the contents of the script
$contents = $this->_get_contents($sFile);
// get it's functions
$aFunctions_ini = array(
'declared' => $this->get_functions_declared($contents),
'use' => $this->get_function_all($contents));
// get the file requirement
$aFiles = $this->_get_requirement($contents);
foreach($aFiles as $i => $sPath){
if (file_exists($sPath)){
$aFunctions = $this->study_function($sPath);
$aFunctions_ini['declared'] = array_merge($aFunctions_ini['declared'],$aFunctions['declared']);
$aFunctions_ini['use'] = array_merge($aFunctions_ini['use'],$aFunctions['use']);
}
}
$aFunctions = array(
'declared' => array_unique($aFunctions_ini['declared']),
'use' => array_unique($aFunctions_ini['use']));
return $aFunctions;
}
/**
* @shortdesc function which get requirement files for a script
* function which get requirement files for a script
*
* @param string contents required. the contents of the script to examine
* @private
* @type array
**/
function _get_requirement($contents)
{
$spe = new specif(FALSE);
$files = array();
$aIncludes_files = array();
$complete_path_file = array();
$include_path = ini_get('include_path');
$aInclude_path = array();
$pattern_require = '(require|include)(_once)?[ ]*\(?["\'][a-zA-Z_.]+\)?["\']';
// get the pattern of require
$aIncludes_files = $this->get_pattern($contents,$pattern_require);
// get filenames
foreach($aIncludes_files[0] as $i => $include_sq){
$del = ((strpos($include_sq,"'"))?"'":'"');
$files_match = explode($del,$include_sq);
if (!$this->bRequirement) $this->bRequirement = preg_match("/once/",$include_sq);
$files[] = $files_match[1];
}
$files = array_unique($files);
// get their path
$aInclude_path = explode(";",$include_path);
foreach($files as $i => $sPath_file){
$sPath = $this->sDir.$spe->Path_delimiter().$sPath_file;
if (!file_exists($sPath)) $complete_path_file[] = $aInclude_path[1].$spe->Path_delimiter().$sPath_file;
else $complete_path_file[] = $sPath;
}
return array_unique($complete_path_file);
}
}// class
?>