1
0
mirror of https://github.com/e107inc/e107.git synced 2025-08-02 20:57:26 +02:00

Minimum viable rewrite of File Inspector frontend

This commit is contained in:
Nick Liu
2020-03-27 00:27:46 -05:00
parent 6f6556178f
commit 6095c94de3
7 changed files with 534 additions and 691 deletions

Binary file not shown.

View File

@@ -9,8 +9,6 @@
* Administration - File inspector * Administration - File inspector
* *
*/ */
ini_set('zlib.output_compression', 0);
header('Content-Encoding: none'); // turn off gzip.
ob_implicit_flush(true); ob_implicit_flush(true);
ob_end_flush(); ob_end_flush();
@@ -24,34 +22,6 @@ if(!getperms('Y'))
exit; exit;
} }
$error_handler->debug = FALSE;
$DOCS_DIRECTORY = $HELP_DIRECTORY; // Give a sensible, albeit probably invalid, value
if(substr($HELP_DIRECTORY,-5,5) == 'help/')
{
$DOCS_DIRECTORY = substr($HELP_DIRECTORY,0,-5); // Whatever $HELP_DIRECTORY is set to, assume docs are in a subdirectory called 'help' off it
}
$maindirs = array(
'admin' => $ADMIN_DIRECTORY,
'files' => $FILES_DIRECTORY,
'images' => $IMAGES_DIRECTORY,
'themes' => $THEMES_DIRECTORY,
'plugins' => $PLUGINS_DIRECTORY,
'handlers' => $HANDLERS_DIRECTORY,
'languages' => $LANGUAGES_DIRECTORY,
'downloads' => $DOWNLOADS_DIRECTORY,
'docs' => $DOCS_DIRECTORY
);
foreach ($maindirs as $maindirs_key => $maindirs_value)
{
$coredir[$maindirs_key] = substr($maindirs_value, 0, -1);
}
require_once('core_image.php');
set_time_limit(18000); set_time_limit(18000);
$e_sub_cat = 'fileinspector'; $e_sub_cat = 'fileinspector';
@@ -65,13 +35,14 @@ if(isset($_GET['scan']))
//$css_file = file_exists(e_THEME.$pref['admintheme'].'/'.$pref['admincss']) ? e_THEME.$pref['admintheme'].'/'.$pref['admincss'] : e_THEME.$pref['admintheme'].'/'.$pref['admincss']; //$css_file = file_exists(e_THEME.$pref['admintheme'].'/'.$pref['admincss']) ? e_THEME.$pref['admintheme'].'/'.$pref['admincss'] : e_THEME.$pref['admintheme'].'/'.$pref['admincss'];
// $fi = new file_inspector; // $fi = new file_inspector;
/** @var file_inspector $fi */
$fi = e107::getSingleton('file_inspector'); $fi = e107::getSingleton('file_inspector');
echo "<!DOCTYPE html> echo "<!DOCTYPE html>
<html> <html>
<head> <head>
<title>Results</title> <title>Results</title>
<script type='text/javascript' src='https://cdn.jsdelivr.net/jquery/2.1.4/jquery.min.js'></script> <script type='text/javascript' src='https://cdn.jsdelivr.net/jquery/2.2.1/jquery.min.js'></script>
<link rel='stylesheet' media='all' property='stylesheet' type='text/css' href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css' /> <link rel='stylesheet' media='all' property='stylesheet' type='text/css' href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css' />
".$fi->headerCss()." ".headerjs()." ".$fi->headerCss()." ".headerjs()."
@@ -136,6 +107,9 @@ else
class file_inspector { class file_inspector {
/** @var e_file_inspector */
private $coreImage;
private $coreImageVersion;
var $root_dir; var $root_dir;
var $files = array(); var $files = array();
@@ -167,8 +141,12 @@ class file_inspector {
'num' => 0, 'num' => 0,
'line' => 0 'line' => 0
); );
/**
* @var array
*/
private $glyph;
function setOptions($post) function setOptions($post)
{ {
foreach($this->options as $k=>$v) foreach($this->options as $k=>$v)
{ {
@@ -238,10 +216,11 @@ class file_inspector {
$this->iconTag[$k] = $this->glyph[$k][0]; $this->iconTag[$k] = $this->glyph[$k][0];
} }
global $e107, $core_image; $e107 = e107::getInstance();
$this->coreImage = e107::getFileInspector('core');
$this->coreImageVersion = $this->coreImage->getCurrentVersion();
//$this->totalFiles = count($core_image,COUNT_RECURSIVE); $this->countFiles();
$this->countFiles($core_image);
$this->root_dir = $e107 -> file_path; $this->root_dir = $e107 -> file_path;
@@ -250,7 +229,7 @@ class file_inspector {
$this->root_dir = substr($this->root_dir, 0, -1); $this->root_dir = substr($this->root_dir, 0, -1);
} }
if($_POST['core'] == 'fail') if(isset($_POST['core']) && $_POST['core'] == 'fail')
{ {
$_POST['integrity'] = TRUE; $_POST['integrity'] = TRUE;
} }
@@ -260,7 +239,7 @@ class file_inspector {
$_POST['regex'] = stripslashes($_POST['regex']); $_POST['regex'] = stripslashes($_POST['regex']);
} }
if($_POST['regex']) if(!empty($_POST['regex']))
{ {
if($_POST['core'] == 'fail') if($_POST['core'] == 'fail')
{ {
@@ -280,19 +259,9 @@ class file_inspector {
// Find the Total number of core files before scanning begins. // Find the Total number of core files before scanning begins.
function countFiles($array) private function countFiles()
{ {
foreach($array as $k=>$val) return $this->totalFiles = iterator_count($this->coreImage->getPathIterator($this->coreImageVersion));
{
if(is_array($val))
{
$this->countFiles($val);
}
elseif($val)
{
$this->totalFiles++;
}
}
} }
@@ -545,386 +514,261 @@ class file_inspector {
return 'check'; return 'check';
} }
/**
* @param $baseDir string Absolute path to the directory to inspect
* @return string HTML output of the validated directory structure
*/
protected function inspect($baseDir)
{
$this->inspect_existing($baseDir);
$this->inspect_missing(array_keys($this->files));
return $this->generateScanResultsHtml();
}
// This function does the real work private function inspect_existing($baseDir)
// $list - {
// $deprecated $absoluteBase = realpath($baseDir);
// $level if (!is_dir($absoluteBase)) return;
// $dir
// &$tree_end
// &$parent_expand
function inspect($list, $deprecated, $level, $dir, &$tree_end = null, &$parent_expand = null)
{
global $coredir;
$sub_text = ''; $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($baseDir));
$langs = $this->langs; $index = 0;
$lang_short = $this->lang_short; foreach ($iterator as $file)
{
$this->sendProgress($index++, $this->totalFiles);
if ($file->isDir()) continue;
$absolutePath = $file->getRealPath();
$relativePath = preg_replace("/^" . preg_quote($absoluteBase . "/", "/") . "/", "", $absolutePath);
unset ($childOut); if (empty($relativePath) || $relativePath == $absolutePath) continue;
$parent_expand = false;
if(substr($dir, -1) == '/') $this->files[$relativePath] = $this->coreImage->validate($relativePath);
{ $this->updateFileSizeCounter($absolutePath, $this->files[$relativePath]);
$dir = substr($dir, 0, -1); }
} }
$dir_id = dechex(crc32($dir)); private function inspect_missing($existingPaths)
$this->files[$dir_id]['.']['level'] = $level; {
$this->files[$dir_id]['.']['parent'] = $this->parent; $dbIterator = $this->coreImage->getPathIterator($this->coreImageVersion);
$this->files[$dir_id]['.']['file'] = $dir; $dbPaths = iterator_to_array($dbIterator);
$directory = $level ? basename($dir) : SITENAME; $dbPaths = array_map(function ($defaultPath)
$level++; {
return $this->coreImage->defaultPathToCustomPath($defaultPath);
}, $dbPaths);
$missingPaths = array_diff($dbPaths, $existingPaths);
foreach ($missingPaths as $relativePath)
{
$this->files[$relativePath] = $this->coreImage->validate($relativePath);
}
}
$this->sendProgress(vartrue($this->count['core']['num']),$this->totalFiles,FR_LAN_1); private function updateFileSizeCounter($absolutePath, $validationCode)
{
$status = $this->getStatusForValidationCode($validationCode);
$category = $this->statusToLegacyCountCategory($status);
$fileSize = filesize($absolutePath);
$this->count[$category]['size'] += $fileSize;
foreach ($list as $key => $value) if ($validationCode & e_file_inspector::VALIDATED_RELEVANCE &&
{ $validationCode & e_file_inspector::VALIDATED_PRESENCE)
// $dir_icon = 'fileinspector'; // default as unknown $this->count['core']['size'] += $fileSize;
$this->parent = $dir_id; }
// Entry is a subdirectory - recurse another level private function statusToLegacyCountCategory($status)
if(is_array($value)) {
{ $category = $status;
$path = $dir.'/'.$key; switch ($status)
$child_open = false; {
$child_end = true; case 'check':
$dir_icon = 'folder_check'; $category = 'pass';
$sub_text .= $this->inspect($value, $deprecated[$key], $level, $path, $child_end, $child_expand); break;
$tree_end = false; case 'uncalc':
$category = 'uncalculable';
break;
case 'old':
$category = 'deprecated';
break;
}
return $category;
}
if($child_expand) private function generateScanResultsHtml()
{ {
$parent_expand = true; $nestedFiles = [];
$last_expand = true; foreach ($this->files as $relativePath => $validation)
} {
self::array_set($nestedFiles, $relativePath, $validation);
}
return $this->generateDirectoryHtml([SITENAME => $nestedFiles]);
}
} private function generateDirectoryHtml($tree, $level = 0, $parentPath = '')
else {
{ $html = '';
$this->sendProgress(vartrue($this->count['core']['num']),$this->totalFiles,FR_LAN_1);
$path = $dir.'/'.$key;
$fid = strtolower($key); $this->sortAscDirectoriesFirst($tree);
$this->files[$dir_id][$fid]['file'] = ($_POST['type'] == 'tree') ? $key : $path; $hide = $level;
foreach ($tree as $fileName => $validationCode)
{
$relativePath = "$parentPath/$fileName";
$rowId = base64_encode($relativePath);
list($icon, $title) = $this->getGlyphForValidationCode($validationCode);
$html .= "<div class=\"d\" title=\"$title\" style=\"margin-left: " . ($level * 8) . "px\">";
$html .= "<span onclick=\"ec('$rowId')\">";
$html .= $this->getTreeActionImageForFile($tree, $fileName, $rowId, $hide);
$html .= "</span>&nbsp;<span onclick=\"sh('f_$rowId')\">" .
$icon.
"&nbsp;$fileName</span>";
if (is_array($validationCode))
{
$html .= "<div id=\"d_$rowId\" " . ($hide ? "style=\"display:none\"" : "") . ">";
$html .= $this->generateDirectoryHtml($validationCode, $level + 1, $relativePath);
$html .= "</div>";
}
$html .= "</div>";
}
// We're checking a file here return $html;
if(($this->files[$dir_id][$fid]['size'] = filesize($path)) !== false) }
{
// Look at core files
if($this->opt('core') != 'none')
{
$this->count['core']['num']++;
$this->count['core']['size'] += $this->files[$dir_id][$fid]['size'];
// TODO Max out of Memory when used private function sortAscDirectoriesFirst(array &$tree)
if($_POST['regex']) // Developer prefs activated - search file contents according to regex {
{ return uksort($tree, function ($a, $b) use ($tree)
// Get contents of file {
$file_content = file($path); if (is_array($tree[$a]) && !is_array($tree[$b])) return -1;
elseif (!is_array($tree[$a]) && is_array($tree[$b])) return 1;
return $a > $b;
});
}
if(($this->files[$dir_id][$fid]['size'] = filesize($path)) !== FALSE) private function getTreeActionImageForFile($tree, $fileName, $id, $hide = false)
{ {
// Search string found - add file to list if (!is_array($tree[$fileName]))
if($this->files[$dir_id][$fid]['lines'] = preg_grep("#".$_POST['regex']."#".$_POST['mod'], $file_content)) {
{ $actionImage = 'blank';
$this->files[$dir_id][$fid]['file'] = ($_POST['type'] == 'tree') ? $key : $path; $actionAlt = ' ';
$this->files[$dir_id][$fid]['icon'] = 'file_core'; }
$dir_icon = 'fileinspector'; elseif ($hide)
$parent_expand = TRUE; {
$this->results++; $actionImage = 'expand';
} $actionAlt = '+';
// Search string not found - discard from list }
else else
{ {
unset($this->files[$dir_id][$fid]); $actionImage = 'contract';
$known[$dir_id][$fid] = true; $actionAlt = '-';
$dir_icon = ($dir_icon == 'fileinspector') ? 'folder_unknown': $dir_icon ; }
}
}
}
else
{
// Actually check file integrity
if($this->opt('integrity'))
{
switch ($this_action = $this->check_action($dir,$key))
{
case 'ignore' :
case 'check' :
if($this->checksum($path) != $value)
{
$this->count['fail']['num']++;
$this->count['fail']['size'] += $this->files[$dir_id][$fid]['size'];
$this->files[$dir_id][$fid]['icon'] = 'file_fail';
$dir_icon = 'folder_fail';
$parent_expand = TRUE;
}
else
{
$this->count['pass']['num']++;
$this->count['pass']['size'] += $this->files[$dir_id][$fid]['size'];
if($this->opt('core') != 'fail') return "<img id='e_$id' class='e' src='".e_IMAGE."fileinspector/$actionImage.png' alt='$actionAlt' width='15' />";
{ }
$this->files[$dir_id][$fid]['icon'] = 'file_check';
$dir_icon = ($dir_icon == 'folder_fail' || $dir_icon == 'folder_missing') ? $dir_icon : 'folder_check';
}
else
{
unset($this->files[$dir_id][$fid]);
$known[$dir_id][$fid] = true;
}
}
break;
case 'uncalc' :
case 'nocalc' :
$this->count['uncalculable']['num']++;
$this->count['uncalculable']['size'] += $this->files[$dir_id][$fid]['size'];
if($this->opt('core') != 'fail') private function getGlyphForValidationCode($validationCodeOrArray)
{ {
$this->files[$dir_id][$fid]['icon'] = 'file_uncalc'; if (is_array($validationCodeOrArray)) return $this->getWorstGlyphForFolder($validationCodeOrArray);
} return $this->glyph['file_' . $this->getStatusForValidationCode($validationCodeOrArray)];
else }
{
unset($this->files[$dir_id][$fid]);
$known[$dir_id][$fid] = true;
}
break;
}
}
// Just identify as core file
else
{
$this->files[$dir_id][$fid]['icon'] = 'file_core';
}
}
}
else
{
unset ($this->files[$dir_id][$fid]);
$known[$dir_id][$fid] = true;
}
}
elseif($this->opt('missing'))
{
switch ($this_action = $this->check_action($dir,$key))
{
case 'check' :
case 'uncalc' :
$this->count['missing']['num']++;
$this->files[$dir_id][$fid]['icon'] = 'file_missing';
$dir_icon = ($dir_icon == 'folder_fail') ? $dir_icon : 'folder_missing';
$parent_expand = TRUE;
break;
case 'ignore' :
case 'nocalc' :
// These files can be missing without error - delete from the list
unset ($this->files[$dir_id][$fid]);
$known[$dir_id][$fid] = true;
break;
}
}
else
{
unset ($this->files[$dir_id][$fid]);
}
}
}
if($this->opt('noncore') || $this->opt('oldcore')) private function getStatusForValidationCode($validationCode)
{ {
if(!$handle = opendir($dir.'/')) if ($validationCode & e_file_inspector::VALIDATED)
{ return 'check';
//e107::getMessage()->addInfo("Couldn't Open : ".$dir); if (!($validationCode & e_file_inspector::VALIDATED_RELEVANCE))
} return 'unknown';
if (!($validationCode & e_file_inspector::VALIDATED_SECURITY))
return 'warning';
if (!($validationCode & e_file_inspector::VALIDATED_PRESENCE))
return 'missing';
if (!($validationCode & e_file_inspector::VALIDATED_DETERMINABLE))
return 'uncalc';
if (!($validationCode & e_file_inspector::VALIDATED_UPTODATE))
if ($validationCode & e_file_inspector::VALIDATED_HASH)
return 'old';
else
return 'fail';
return 'unknown';
}
while (is_resource($handle) && false !== ($readdir = readdir($handle))) private function getStatusRank($status)
{ {
// $prog_count = $this->count['unknown']['num'] + $this->count['deprecated']['num']; switch ($status)
// $this->sendProgress($prog_count,$this->totalFiles,FR_LAN_1); {
case 'uncalc':
return -2;
case 'unknown':
return -1;
case 'check':
return 0;
case 'missing':
return 1;
case 'old':
return 2;
case 'fail':
return 3;
case 'warning':
return 4;
}
return -1;
}
if(!in_array($readdir,$this->excludeFiles) && (strpos('._', $readdir) === false)) private function getWorstGlyphForFolder($treeFolder)
{ {
if(is_dir($dir.'/'.$readdir)) $worstStatus = 'uncalc';
{ $worstStatusRank = -PHP_INT_MAX;
if(!isset($list[$readdir]) && ($level > 1 || $readdir == 'e107_install')) array_walk_recursive($treeFolder, function ($value) use (&$worstStatus, &$worstStatusRank)
{ {
$child_open = false; $currentStatus = $this->getStatusForValidationCode($value);
$child_end = true; $currentStatusRank = $this->getStatusRank($currentStatus);
$sub_text .= $this->inspect(array(), $deprecated[$readdir], $level, $dir.'/'.$readdir, $child_end, $child_expand); if ($currentStatusRank > $worstStatusRank)
$tree_end = false; {
if($child_expand) $worstStatusRank = $currentStatusRank;
{ $worstStatus = $currentStatus;
$parent_expand = true; }
$last_expand = true; });
} return $this->glyph['folder_' . $worstStatus];
} }
}
else
{
if($this->opt('nolang') && !empty($langs) && !empty($lang_short)) // Hide Non-core Languages.
{
// PHP Lang files.
$lreg = "/[\/_](".implode("|",$langs).")/";
if(preg_match($lreg, $dir.'/'.$readdir))
{
continue;
}
// TinyMce Lang files. /**
$lregs = "/[\/_](".implode("|",$lang_short).")_dlg\.js/"; * Set an array item to a given value using "slash" notation.
if(preg_match($lregs, $dir.'/'.$readdir)) *
{ * If no key is given to the method, the entire array will be replaced.
continue; *
} * Based on Illuminate\Support\Arr::set()
*
* @param array $array
* @param string|null $key
* @param mixed $value
* @return array
* @copyright Copyright (c) Taylor Otwell
* @license https://github.com/illuminate/support/blob/master/LICENSE.md MIT License
*/
private static function array_set(&$array, $key, $value)
{
if (is_null($key))
{
return $array = $value;
}
// PhpMailer Lang Files. $keys = explode('/', $key);
$lregsm = "/[\/_]phpmailer\.lang-(".implode("|",$lang_short).")\.php/";
if(preg_match($lregsm, $dir.'/'.$readdir))
{
continue;
}
}
$aid = strtolower($readdir); while (count($keys) > 1)
{
$key = array_shift($keys);
if(!isset($this->files[$dir_id][$aid]['file']) && !$known[$dir_id][$aid]) // If the key doesn't exist at this depth, we will just create an empty array
{ // to hold the next value, allowing us to create the arrays to hold final
if($this->checkKnownSecurity($dir.'/'.$readdir) === false) // values at the correct depth. Then we'll keep digging into the array.
{ if (!isset($array[$key]) || !is_array($array[$key]))
if(isset($deprecated[$readdir])) {
{ $array[$key] = [];
if($this->opt('oldcore')) }
{
$this->files[$dir_id][$aid]['file'] = ($_POST['type'] == 'tree') ? $readdir : $dir.'/'.$readdir;
$this->files[$dir_id][$aid]['size'] = filesize($dir.'/'.$readdir);
$this->files[$dir_id][$aid]['icon'] = 'file_old';
$this->count['deprecated']['num']++;
$this->count['deprecated']['size'] += $this->files[$dir_id][$aid]['size'];
$dir_icon = 'folder_old';
}
}
else
{
if($this->opt('noncore'))
{
$this->files[$dir_id][$aid]['file'] = ($_POST['type'] == 'tree') ? $readdir : $dir.'/'.$readdir;
$this->files[$dir_id][$aid]['size'] = filesize($dir.'/'.$readdir);
//echo "<br />dir: ".$dir.'/'.$readdir. " ( ".$this->files[$dir_id][$aid]['size'].")";
$this->files[$dir_id][$aid]['icon'] = 'file_unknown';
$this->count['unknown']['num']++;
$this->count['unknown']['size'] += $this->files[$dir_id][$aid]['size'];
}
}
}
else
{
$this->files[$dir_id][$aid]['file'] = ($_POST['type'] == 'tree') ? $readdir : $dir.'/'.$readdir;
$this->files[$dir_id][$aid]['size'] = filesize($dir.'/'.$readdir);
$this->files[$dir_id][$aid]['icon'] = 'file_warning';
$this->count['warning']['num']++;
$this->count['warning']['size'] += $this->files[$dir_id][$aid]['size'];
$this->count['deprecated']['num']++;
$this->count['deprecated']['size'] += $this->files[$dir_id][$aid]['size'];
$dir_icon = 'folder_warning';
$parent_expand = TRUE;
}
$regexOpt = $this->opt('regex'); $array = &$array[$key];
if(!empty($regexOpt)) }
{
$file_content = file($dir.'/'.$readdir);
if($this->files[$dir_id][$aid]['lines'] = preg_grep("#".$_POST['regex']."#".$_POST['mod'], $file_content))
{
$dir_icon = 'fileinspector';
$parent_expand = TRUE;
$this->results++;
}
else
{
unset($this->files[$dir_id][$aid]);
$dir_icon = ($dir_icon == 'fileinspector') ? $dir_icon : 'folder';
}
}
else
{
if(isset($deprecated[$readdir]))
{
if($this->opt('oldcore'))
{
$dir_icon = ($dir_icon == 'folder_warning' || $dir_icon == 'folder_fail' || $dir_icon == 'folder_missing' ) ? $dir_icon : 'folder_old';
$parent_expand = TRUE;
}
}
else
{
if($this->opt('noncore'))
{
$dir_icon = ($dir_icon == 'folder_warning' || $dir_icon == 'folder_fail' || $dir_icon == 'folder_missing' || $dir_icon == 'folder_old' || $dir_icon == 'folder_old_dir') ? $dir_icon : 'folder_unknown';
$parent_expand = TRUE;
}
}
}
}
elseif($this->opt('core') == 'none')
{
unset($this->files[$dir_id][$aid]);
}
}
}
}
closedir($handle);
} $array[array_shift($keys)] = $value;
$this->sendProgress($this->count['core']['num'],$this->totalFiles,FR_LAN_1); return $array;
}
$dir_icon = $dir_icon ? $dir_icon : 'folder_unknown';
// $icon = "<img src='".e_IMAGE."fileinspector/".$dir_icon."' class='i' alt='' />";
$icon = $this->iconTag[$dir_icon];
$tp = e107::getParser();
$imgBlank = $tp->toImage('{e_IMAGE}fileinspector/blank.png', array(
'alt' => '',
'legacy' => '{e_IMAGE}fileinspector/',
'w' => 9,
'h' => 9,
'class' => 'c',
));
$imgExpand = $tp->toImage('{e_IMAGE}fileinspector/expand.png', array(
'alt' => '',
'legacy' => '{e_IMAGE}fileinspector/',
'w' => 15,
'class' => 'e',
'id' => 'e_' . $dir_id,
));
$imgContract = $tp->toImage('{e_IMAGE}fileinspector/contract.png', array(
'alt' => '',
'legacy' => '{e_IMAGE}fileinspector/',
'w' => 15,
'class' => 'e',
'id' => 'e_' . $dir_id,
));
$hide = ($last_expand && $dir_icon != 'folder_core') ? "" : "style='display: none'";
$text = '<div class="d" title="' . $this->getDiz($dir_icon) . '" style="margin-left: ' . ($level * 8) . 'px">';
$text .= $tree_end ? $imgBlank : '<span onclick="ec(\'' . $dir_id . '\')">' . ($hide ? $imgExpand : $imgContract) . '</span>';
$text .= '&nbsp;<span onclick="sh(\'f_' . $dir_id . '\')">' . $icon . '&nbsp;' . $directory . '</span>';
$text .= $tree_end ? '' : '<div ' . $hide . ' id="d_' . $dir_id . '">' . $sub_text . '</div>';
$text .= '</div>';
$this->files[$dir_id]['.']['icon'] = $dir_icon;
return $text;
}
private function checkKnownSecurity($path) private function checkKnownSecurity($path)
{ {
@@ -944,12 +788,53 @@ class file_inspector {
function scan_results() function scan_results()
{ {
global $core_image, $deprecated_image; $this->count = [
$ns = e107::getRender(); 'core' => [
'num' => 0,
'size' => 0,
],
'fail' => [
'num' => 0,
'size' => 0,
],
'pass' => [
'num' => 0,
'size' => 0,
],
'uncalculable' => [
'num' => 0,
'size' => 0,
],
'missing' => [
'num' => 0,
],
'deprecated' => [
'num' => 0,
'size' => 0,
],
'unknown' => [
'num' => 0,
'size' => 0,
],
'warning' => [
'num' => 0,
'size' => 0,
]
];
$scan_text = $this->inspect($this->root_dir);
$scan_text = $this->inspect($core_image, $deprecated_image, 0, $this->root_dir); array_walk_recursive($this->files, function ($validationCode)
{
$status = $this->getStatusForValidationCode($validationCode);
$category = $this->statusToLegacyCountCategory($status);
$this->count[$category]['num']++;
$this->sendProgress($this->totalFiles,$this->totalFiles,' &nbsp; &nbsp; &nbsp;'); if ($validationCode & e_file_inspector::VALIDATED_RELEVANCE &&
$validationCode & e_file_inspector::VALIDATED_PRESENCE)
$this->count['core']['num']++;
});
$this->sendProgress($this->totalFiles, $this->totalFiles);
echo "<div style='display:block;height:30px'>&nbsp;</div>"; echo "<div style='display:block;height:30px'>&nbsp;</div>";
@@ -1046,16 +931,16 @@ class file_inspector {
$text .= "<tr><td style='padding-right: 4px' colspan='2'> $text .= "<tr><td style='padding-right: 4px' colspan='2'>
<ul><li> <ul><li>
<a href=\"javascript: expandit('i_corrupt')\">".FR_LAN_11."...</a><div style='display: none' id='i_corrupt'> <a href=\"#\" onclick=\"expandit('i_corrupt')\">".FR_LAN_11."...</a><div style='display: none' id='i_corrupt'>
".FR_LAN_12."<br /><br /></div> ".FR_LAN_12."<br /><br /></div>
</li><li> </li><li>
<a href=\"javascript: expandit('i_date')\">".FR_LAN_13."...</a><div style='display: none' id='i_date'> <a href=\"#\" onclick=\"expandit('i_date')\">".FR_LAN_13."...</a><div style='display: none' id='i_date'>
".FR_LAN_14."<br /><br /></div> ".FR_LAN_14."<br /><br /></div>
</li><li> </li><li>
<a href=\"javascript: expandit('i_edit')\">".FR_LAN_15."...</a><div style='display: none' id='i_edit'> <a href=\"#\" onclick=\"expandit('i_edit')\">".FR_LAN_15."...</a><div style='display: none' id='i_edit'>
".FR_LAN_16."<br /><br /></div> ".FR_LAN_16."<br /><br /></div>
</li><li> </li><li>
<a href=\"javascript: expandit('i_cvs')\">".FR_LAN_17."...</a><div style='display: none' id='i_cvs'> <a href=\"#\" onclick=\"expandit('i_cvs')\">".FR_LAN_17."...</a><div style='display: none' id='i_cvs'>
".FR_LAN_18."<br /><br /></div> ".FR_LAN_18."<br /><br /></div>
</li></ul> </li></ul>
</td></tr>"; </td></tr>";
@@ -1088,9 +973,6 @@ class file_inspector {
foreach ($this->files as $dir_id => $fid) foreach ($this->files as $dir_id => $fid)
{ {
// $this->sendProgress($cnt,$this->totalFiles,$path);
ksort($fid); ksort($fid);
$text .= ($this->opt('type') == 'tree') ? "<table class='t' style='display: none' id='f_".$dir_id."'>" : ""; $text .= ($this->opt('type') == 'tree') ? "<table class='t' style='display: none' id='f_".$dir_id."'>" : "";
$initial = FALSE; $initial = FALSE;
@@ -1354,7 +1236,7 @@ class file_inspector {
} }
function sendProgress($rand,$total,$diz) function sendProgress($rand,$total)
{ {
if($this->progress_units <40 && ($rand != $total)) if($this->progress_units <40 && ($rand != $total))
{ {
@@ -1491,29 +1373,27 @@ class file_inspector {
$e_js->renderJs('inline_css', false, 'css', false); $e_js->renderJs('inline_css', false, 'css', false);
echo "\n<!-- footer_inline_css -->\n"; echo "\n<!-- footer_inline_css -->\n";
$text = "
/* <style type='text/css'>
echo "<!-- Theme css -->\n"; <!--\n";
if(strpos(e_SELF.'?'.e_QUERY, 'menus.php?configure') === FALSE && isset($pref['admincss']) && $pref['admincss'] && file_exists(THEME.$pref['admincss'])) { if (vartrue($_POST['regex']))
$css_file = file_exists(THEME.'admin_'.$pref['admincss']) ? THEME_ABS.'admin_'.$pref['admincss'] : THEME_ABS.$pref['admincss']; {
echo "<link rel='stylesheet' href='".$css_file."' type='text/css' />\n"; $text .= ".f { padding: 1px 0px 1px 8px; vertical-align: bottom; width: 90% }\n";
} elseif(isset($pref['themecss']) && $pref['themecss'] && file_exists(THEME.$pref['themecss'])) }
{ else
$css_file = file_exists(THEME.'admin_'.$pref['themecss']) ? THEME_ABS.'admin_'.$pref['themecss'] : THEME_ABS.$pref['themecss']; {
echo "<link rel='stylesheet' href='".$css_file."' type='text/css' />\n"; $text .= ".f { padding: 1px 0px 1px 8px; vertical-align: bottom; width: 90%; white-space: nowrap }\n";
}
$text .= ".d { margin: 2px 0px 1px 8px; cursor: default; white-space: nowrap }
} .s { padding: 1px 8px 1px 0px; vertical-align: bottom; width: 10%; white-space: nowrap }
else .t { margin-top: 1px; width: 100%; border-collapse: collapse; border-spacing: 0px }
{ .w { padding: 1px 0px 1px 8px; vertical-align: bottom; width: 90% }
$css_file = file_exists(THEME.'admin_style.css') ? THEME_ABS.'admin_style.css' : THEME_ABS.'style.css'; .i { width: 16px; height: 16px }
echo "<link rel='stylesheet' href='".$css_file."' type='text/css' />\n"; .e { width: 9px; height: 9px }
} i.fa-folder-open-o, i.fa-times-circle-o { cursor:pointer }
if(!isset($no_core_css) || !$no_core_css) { -->
echo "<link rel='stylesheet' href='".e_WEB_CSS."e107.css' type='text/css' />\n"; </style>\n";
} echo $text;
* */
} }
} }
@@ -1558,82 +1438,15 @@ require_once(e_ADMIN.'footer.php');
function headerjs() function headerjs()
{ {
/*$c = e_IMAGE_ABS . 'fileinspector/contract.png'; e107::js('footer', '{e_WEB}/js/core/all.jquery.js', 'jquery', 1);
$e = e_IMAGE_ABS . 'fileinspector/expand.png'; $text = e107::getJs()->renderJs('footer', 1, true, true);
$text .= "<script type='text/javascript'>
$text = '<script type="text/javascript">
function ec(element) {
$("#d_"+element).stop().animate({"height": "toggle"}, { duration: 500 });
var $img = $("#e_"+element);
if($img.attr("src") == "' . $e . '") {
$img.attr("src", "' . $c . '");
} else {
$img.attr("src", "' . $e . '");
}
}
function sh(element) {
$("#"+element).stop().animate({"height": "toggle"}, { duration: 500 });
}
</script>';*/
/*
* // Start of rework
e107::js('footer-inline', "
c = new Image();
c = '".SITEURLBASE.e_IMAGE_ABS."fileinspector/contract.png';
e = '".SITEURLBASE.e_IMAGE_ABS."fileinspector/expand.png';
function ec(ecid) {
icon = $('#e_' + ecid).src;
if(icon == e) {
$('#e_' + ecid).src = c;
} else {
$('#e_' + ecid).src = e;
}
div = $('#d_' + ecid).style;
if(div.display == 'none')
{
div.display = '';
}
else
{
div.display = 'none';
}
}
var hideid = 'initial';
function sh(showid)
{
if(hideid != showid)
{
show = $('#'+showid).style;
hide = $('#'+hideid).style;
show.display = '';
hide.display = 'none';
hideid = showid;
}
}
");*/
global $e107;
$text = "<script type='text/javascript'>
<!-- <!--
c = new Image(); c = '".SITEURLBASE.e_IMAGE_ABS."fileinspector/contract.png'; c = new Image(); c = '".SITEURLBASE.e_IMAGE_ABS."fileinspector/contract.png';
e = '".SITEURLBASE.e_IMAGE_ABS."fileinspector/expand.png'; e = '".SITEURLBASE.e_IMAGE_ABS."fileinspector/expand.png';
function ec(ecid) { function ec(ecid) {
icon = document.getElementById('e_' + ecid).src; icon = document.getElementById('e_' + ecid).src;
if(icon == e) { if(icon.indexOf('expand.png') !== -1) {
document.getElementById('e_' + ecid).src = c; document.getElementById('e_' + ecid).src = c;
} else { } else {
document.getElementById('e_' + ecid).src = e; document.getElementById('e_' + ecid).src = e;
@@ -1658,24 +1471,6 @@ function sh(showid) {
//--> //-->
</script>"; </script>";
$text .= "
<style type='text/css'>
<!--\n";
if(vartrue($_POST['regex'])) {
$text .= ".f { padding: 1px 0px 1px 8px; vertical-align: bottom; width: 90% }\n";
} else {
$text .= ".f { padding: 1px 0px 1px 8px; vertical-align: bottom; width: 90%; white-space: nowrap }\n";
}
$text .= ".d { margin: 2px 0px 1px 8px; cursor: default; white-space: nowrap }
.s { padding: 1px 8px 1px 0px; vertical-align: bottom; width: 10%; white-space: nowrap }
.t { margin-top: 1px; width: 100%; border-collapse: collapse; border-spacing: 0px }
.w { padding: 1px 0px 1px 8px; vertical-align: bottom; width: 90% }
.i { width: 16px; height: 16px }
.e { width: 9px; height: 9px }
i.fa-folder-open-o, i.fa-times-circle-o { cursor:pointer }
-->
</style>\n";
return $text; return $text;
} }

View File

@@ -193,7 +193,7 @@ class e107
'e_bb_base' => '{e_HANDLER}bbcode_handler.php', 'e_bb_base' => '{e_HANDLER}bbcode_handler.php',
'e_customfields' => '{e_HANDLER}e_customfields_class.php', 'e_customfields' => '{e_HANDLER}e_customfields_class.php',
'e_file' => '{e_HANDLER}file_class.php', 'e_file' => '{e_HANDLER}file_class.php',
'e_file_inspector' => '{e_HANDLER}e_file_inspector_json_phar.php', 'e_file_inspector_json_phar' => '{e_HANDLER}e_file_inspector_json_phar.php',
'e_form' => '{e_HANDLER}form_handler.php', 'e_form' => '{e_HANDLER}form_handler.php',
'e_jshelper' => '{e_HANDLER}js_helper.php', 'e_jshelper' => '{e_HANDLER}js_helper.php',
'e_media' => '{e_HANDLER}media_class.php', 'e_media' => '{e_HANDLER}media_class.php',
@@ -1609,9 +1609,9 @@ class e107
* *
* @return e_file_inspector * @return e_file_inspector
*/ */
public static function getFileInspector() public static function getFileInspector($type = 'core')
{ {
return self::getSingleton('e_file_inspector'); return self::getObject('e_file_inspector_json_phar', e_ADMIN . "core_image.php");
} }
/** /**

View File

@@ -22,6 +22,7 @@ abstract class e_file_inspector implements e_file_inspector_interface
protected $defaultDirsCache; protected $defaultDirsCache;
protected $customDirsCache; protected $customDirsCache;
private $undeterminable = array();
/** /**
* e_file_inspector constructor * e_file_inspector constructor
@@ -32,6 +33,16 @@ abstract class e_file_inspector implements e_file_inspector_interface
{ {
$this->database = $database; $this->database = $database;
$this->loadDatabase(); $this->loadDatabase();
$appRoot = e107::getInstance()->file_path;
$this->undeterminable = array_map(function ($path)
{
return realpath($path) ? realpath($path) : $path;
}, [
$appRoot . "e107_config.php",
$appRoot . e107::getFolder('admin') . "core_image.php",
]
);
} }
/** /**
@@ -165,14 +176,14 @@ abstract class e_file_inspector implements e_file_inspector_interface
return false; return false;
} }
protected function pathToDefaultPath($path) /**
* Convert a custom site path to a default path
* @param string $path Custom path
* @return string
*/
public function customPathToDefaultPath($path)
{ {
if (!$this->customDirsCache) if (!is_array($this->customDirsCache)) $this->populateDirsCache();
{
$this->defaultDirsCache = e107::getInstance()->defaultDirs();
$customDirs = e107::getInstance()->e107_dirs ? e107::getInstance()->e107_dirs : [];
$this->customDirsCache = array_diff_assoc($customDirs, $this->defaultDirsCache);
}
foreach ($this->customDirsCache as $dirType => $customDir) foreach ($this->customDirsCache as $dirType => $customDir)
{ {
if (!isset($this->defaultDirsCache[$dirType])) continue; if (!isset($this->defaultDirsCache[$dirType])) continue;
@@ -186,6 +197,22 @@ abstract class e_file_inspector implements e_file_inspector_interface
return $path; return $path;
} }
public function defaultPathToCustomPath($path)
{
if (!is_array($this->customDirsCache)) $this->populateDirsCache();
foreach ($this->customDirsCache as $dirType => $customDir)
{
if (!isset($this->defaultDirsCache[$dirType])) continue;
$defaultDir = $this->defaultDirsCache[$dirType];
if ($customDir === $defaultDir) continue;
if (substr($path, 0, strlen($defaultDir)) === $defaultDir)
$path = $customDir . substr($path, strlen($defaultDir));
}
return $path;
}
private function getValidatedBitmask() private function getValidatedBitmask()
{ {
if ($this->validatedBitmask !== null) return $this->validatedBitmask; if ($this->validatedBitmask !== null) return $this->validatedBitmask;
@@ -206,6 +233,13 @@ abstract class e_file_inspector implements e_file_inspector_interface
*/ */
private function isDeterminable($absolutePath) private function isDeterminable($absolutePath)
{ {
return is_file($absolutePath) && is_readable($absolutePath); return is_file($absolutePath) && is_readable($absolutePath) && !in_array($absolutePath, $this->undeterminable);
}
protected function populateDirsCache()
{
$this->defaultDirsCache = e107::getInstance()->defaultDirs();
$customDirs = e107::getInstance()->e107_dirs ? e107::getInstance()->e107_dirs : [];
$this->customDirsCache = array_diff_assoc($customDirs, $this->defaultDirsCache);
} }
} }

View File

@@ -56,7 +56,7 @@ class e_file_inspector_json extends e_file_inspector
*/ */
public function getChecksums($path) public function getChecksums($path)
{ {
$path = $this->pathToDefaultPath($path); $path = $this->customPathToDefaultPath($path);
return isset($this->coreImage[$path]) ? $this->coreImage[$path] : []; return isset($this->coreImage[$path]) ? $this->coreImage[$path] : [];
} }

View File

@@ -62,7 +62,7 @@ class e_file_inspector_sqlphar extends e_file_inspector
*/ */
public function getChecksums($path) public function getChecksums($path)
{ {
$path = $this->pathToDefaultPath($path); $path = $this->customPathToDefaultPath($path);
$statement = $this->coreImage->prepare(" $statement = $this->coreImage->prepare("
SELECT versions.version_string, file_hashes.hash SELECT versions.version_string, file_hashes.hash
FROM file_hashes FROM file_hashes

View File

@@ -64,17 +64,12 @@ class e_file_inspectorTest extends \Codeception\Test\Unit
$this->assertEquals(0, $result & e_file_inspector::VALIDATED_PRESENCE); $this->assertEquals(0, $result & e_file_inspector::VALIDATED_PRESENCE);
} }
/** public function testCustomPathToDefaultPath()
* TODO: Create a stable interface for pathToDefaultPath()
* @throws ReflectionException
*/
public function testPathToDefaultPath()
{ {
/** @var e_file_inspector $object */
$object = $this->make('e_file_inspector'); $object = $this->make('e_file_inspector');
$class = new ReflectionClass(get_class($object)); $class = new ReflectionClass(get_class($object));
$method = $class->getMethod('pathToDefaultPath'); $object->customPathToDefaultPath('populate_cache');
$method->setAccessible(true);
$method->invoke($object, 'populate_cache');
$member = $class->getProperty('customDirsCache'); $member = $class->getProperty('customDirsCache');
$member->setAccessible(true); $member->setAccessible(true);
$customDirs = $member->getValue($object); $customDirs = $member->getValue($object);
@@ -83,7 +78,26 @@ class e_file_inspectorTest extends \Codeception\Test\Unit
$input = "e963_admin/index.php"; $input = "e963_admin/index.php";
$expected = "e107_admin/index.php"; $expected = "e107_admin/index.php";
$actual = $method->invoke($object, $input); $actual = $object->customPathToDefaultPath($input);
$this->assertEquals($expected, $actual);
}
public function testDefaultPathToCustomPath()
{
/** @var e_file_inspector $object */
$object = $this->make('e_file_inspector');
$class = new ReflectionClass(get_class($object));
$object->customPathToDefaultPath('populate_cache');
$member = $class->getProperty('customDirsCache');
$member->setAccessible(true);
$customDirs = $member->getValue($object);
$customDirs['ADMIN_DIRECTORY'] = 'e963_admin/';
$member->setValue($object, $customDirs);
$input = "e107_admin/index.php";
$expected = "e963_admin/index.php";
$actual = $object->defaultPathToCustomPath($input);
$this->assertEquals($expected, $actual); $this->assertEquals($expected, $actual);
} }