Files
Commerce/variable_scan.php
“VeLiTi” 580f835fff 2nd update
2025-05-26 15:07:22 +02:00

388 lines
15 KiB
PHP

<?php
/**
* PHP Variable Declaration Finder - Web Interface
* Save this file in your project root and access it through your browser
* Regular Mode: Shows all variable declarations found in your PHP files
* View-Only Mode: Shows only variables used in $view declarations (accessed by adding ?view_only=1 to the URL)
* Download: Get results as JSON by adding ?download=all or ?download=view to the URL
*/
class PHPVariableDeclarationFinder {
private $variables = [];
private $viewVariables = [];
private $rootDir;
private $onlyViewVars = false;
public function __construct($rootDir = '.', $onlyViewVars = false) {
$this->rootDir = rtrim($rootDir, '/');
$this->onlyViewVars = $onlyViewVars;
}
public function findDeclarations() {
$this->scanDirectory($this->rootDir);
if ($this->onlyViewVars) {
return $this->viewVariables;
}
return $this->variables;
}
private function scanDirectory($dir) {
$items = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($items as $item) {
if ($item->isFile() && $item->getExtension() === 'php') {
// Skip scanning this finder script itself
if (basename($item->getPathname()) === basename($_SERVER['SCRIPT_FILENAME'])) {
continue;
}
$this->extractDeclarationsFromFile($item->getPathname());
}
}
}
private function extractDeclarationsFromFile($filePath) {
$content = file_get_contents($filePath);
// Remove comments to avoid false positives
$content = preg_replace('!/\*.*?\*/!s', '', $content);
$content = preg_replace('#//.*#', '', $content);
$relativePath = str_replace($this->rootDir . '/', '', $filePath);
// If we're looking for view variables specifically
if ($this->onlyViewVars) {
$this->findViewVariables($content, $relativePath);
return;
}
// Otherwise proceed with normal variable declaration extraction
$this->findAllVariableDeclarations($content, $relativePath);
// Additionally find view variables but store them separately
$this->findViewVariables($content, $relativePath);
}
private function findAllVariableDeclarations($content, $filePath) {
// Patterns to match variable declarations
$patterns = [
// Variable assignments
'/\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*=(?!=)/',
// Function parameters
'/function\s+\w+\s*\(([^)]*)\)/',
// foreach loops
'/foreach\s*\(\s*\$\w+\s+as\s+(\$[^=)]+)/',
// Class properties
'/(?:public|private|protected|var)\s+(\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/',
// Global declarations
'/global\s+(\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\s*,\s*\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*)/',
// Static declarations
'/static\s+(\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\s*,\s*\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*)/',
// Catch exception blocks
'/catch\s*\(\s*\w+\s+(\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*\)/'
];
$declarations = [];
// Process regular variable assignments
if (preg_match_all($patterns[0], $content, $matches)) {
foreach ($matches[1] as $var) {
$declarations[] = '$' . $var;
}
}
// Process function parameters
if (preg_match_all($patterns[1], $content, $matches)) {
foreach ($matches[1] as $paramList) {
preg_match_all('/\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $paramList, $params);
$declarations = array_merge($declarations, $params[0]);
}
}
// Process foreach variables
if (preg_match_all($patterns[2], $content, $matches)) {
foreach ($matches[1] as $foreachVars) {
preg_match_all('/\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $foreachVars, $vars);
$declarations = array_merge($declarations, $vars[0]);
}
}
// Process class properties
if (preg_match_all($patterns[3], $content, $matches)) {
$declarations = array_merge($declarations, $matches[1]);
}
// Process global declarations
if (preg_match_all($patterns[4], $content, $matches)) {
foreach ($matches[1] as $globalVars) {
preg_match_all('/\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $globalVars, $vars);
$declarations = array_merge($declarations, $vars[0]);
}
}
// Process static declarations
if (preg_match_all($patterns[5], $content, $matches)) {
foreach ($matches[1] as $staticVars) {
preg_match_all('/\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $staticVars, $vars);
$declarations = array_merge($declarations, $vars[0]);
}
}
// Process catch block variables
if (preg_match_all($patterns[6], $content, $matches)) {
$declarations = array_merge($declarations, $matches[1]);
}
if (!empty($declarations)) {
$this->variables[$filePath] = array_unique($declarations);
}
}
private function findViewVariables($content, $filePath) {
// Patterns specifically for $view declarations
$viewPatterns = [
// $view = "..."
'/\$view\s*=\s*([^;]+)/',
// $view .= "..."
'/\$view\s*\.=\s*([^;]+)/'
];
$viewVars = [];
foreach ($viewPatterns as $pattern) {
if (preg_match_all($pattern, $content, $matches)) {
foreach ($matches[1] as $viewContent) {
// Find variables within the view content
// Look for PHP variable pattern with braces like {$variable}
if (preg_match_all('/\{\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/', $viewContent, $varMatches)) {
foreach ($varMatches[1] as $var) {
$viewVars[] = '$' . $var;
}
}
// Look for PHP variable pattern without braces in double-quoted strings
if (strpos($viewContent, '"') !== false &&
preg_match_all('/"\s*\.\s*\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*\.\s*"/', $viewContent, $varMatches)) {
foreach ($varMatches[1] as $var) {
$viewVars[] = '$' . $var;
}
}
// Look for variables in double-quoted strings
if (preg_match_all('/"[^"]*\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)[^"]*"/', $viewContent, $varMatches)) {
foreach ($varMatches[1] as $var) {
$viewVars[] = '$' . $var;
}
}
}
}
}
if (!empty($viewVars)) {
$this->viewVariables[$filePath] = array_unique($viewVars);
}
}
public function getHtmlResults() {
$resultData = $this->onlyViewVars ? $this->viewVariables : $this->variables;
$totalVars = 0;
$totalFiles = 0;
$html = '<div style="font-family: Arial, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px;">';
if ($this->onlyViewVars) {
$html .= '<h1>Variables Found in $view Declarations</h1>';
} else {
$html .= '<h1>Variable Declarations Found in PHP Files</h1>';
}
if (empty($resultData)) {
$html .= '<div style="padding: 20px; background-color: #f8f9fa; border-radius: 5px;">No variables found.</div>';
} else {
foreach ($resultData as $file => $vars) {
$totalFiles++;
$totalVars += count($vars);
$html .= '<div style="margin-bottom: 20px; border: 1px solid #ddd; border-radius: 5px; overflow: hidden;">';
$html .= '<div style="padding: 10px; background-color: #f8f9fa; border-bottom: 1px solid #ddd; font-weight: bold;">' . htmlspecialchars($file) . ' <span style="font-weight: normal; color: #666;">(' . count($vars) . ' variables)</span></div>';
$html .= '<div style="padding: 10px; background-color: #fff;">';
foreach ($vars as $var) {
$html .= '<div style="padding: 5px; margin: 2px 0; background-color: #f1f8ff; border-radius: 3px;">' . htmlspecialchars($var) . '</div>';
}
$html .= '</div></div>';
}
// Summary section
$html .= '<div style="margin-top: 20px; padding: 15px; background-color: #f8f9fa; border-radius: 5px;">';
$html .= '<h2>Summary</h2>';
if ($this->onlyViewVars) {
$html .= '<p>Total files with $view variables: <strong>' . $totalFiles . '</strong></p>';
$html .= '<p>Total variables found in $view declarations: <strong>' . $totalVars . '</strong></p>';
} else {
$html .= '<p>Total files with variable declarations: <strong>' . $totalFiles . '</strong></p>';
$html .= '<p>Total variable declarations found: <strong>' . $totalVars . '</strong></p>';
// Show view variables summary if not in view-only mode
if (!empty($this->viewVariables)) {
$viewVarCount = 0;
$viewFileCount = count($this->viewVariables);
foreach ($this->viewVariables as $vars) {
$viewVarCount += count($vars);
}
$html .= '<div style="margin-top: 15px; padding: 10px; background-color: #e6f7ff; border-radius: 3px;">';
$html .= '<p>Additionally found <strong>' . $viewVarCount . '</strong> variables in $view declarations across <strong>' . $viewFileCount . '</strong> files</p>';
$html .= '</div>';
}
}
$html .= '</div>';
}
// Toggle button
$html .= '<div style="margin-top: 20px; text-align: center;">';
if ($this->onlyViewVars) {
$html .= '<a href="' . $_SERVER['PHP_SELF'] . '" style="display: inline-block; padding: 10px 15px; background-color: #4CAF50; color: white; text-decoration: none; border-radius: 4px;">Show All Variable Declarations</a>';
} else {
$html .= '<a href="' . $_SERVER['PHP_SELF'] . '?view_only=1" style="display: inline-block; padding: 10px 15px; background-color: #2196F3; color: white; text-decoration: none; border-radius: 4px;">Show Only $view Variables</a>';
}
$html .= '</div>';
// Download button
$html .= '<div style="margin-top: 15px; text-align: center;">';
$html .= '<a href="' . $_SERVER['PHP_SELF'] . '?download=' . ($this->onlyViewVars ? 'view' : 'all') . '" style="display: inline-block; padding: 10px 15px; background-color: #FF9800; color: white; text-decoration: none; border-radius: 4px;">Download Results as JSON</a>';
$html .= '</div>';
$html .= '</div>';
return $html;
}
public function exportToJson() {
$resultData = $this->onlyViewVars ? $this->viewVariables : $this->variables;
return json_encode($resultData, JSON_PRETTY_PRINT);
}
}
// ------ MAIN EXECUTION ------
// Set execution time to a higher value to handle large codebases
set_time_limit(300);
// Check for download request
if (isset($_GET['download'])) {
$viewOnly = ($_GET['download'] === 'view');
$finder = new PHPVariableDeclarationFinder('.', $viewOnly);
$finder->findDeclarations();
$filename = $viewOnly ? 'view_variables.json' : 'all_variables.json';
header('Content-Type: application/json');
header('Content-Disposition: attachment; filename="' . $filename . '"');
echo $finder->exportToJson();
exit;
}
// HTML header
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PHP Variable Finder</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #333;
margin: 0;
padding: 0;
background-color: #f5f5f5;
}
header {
background-color: #4a76a8;
color: white;
padding: 15px 20px;
text-align: center;
}
header h1 {
margin: 0;
font-size: 24px;
}
.progress {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 4px;
background-color: #f1f1f1;
z-index: 1000;
}
.progress-bar {
height: 100%;
background-color: #4CAF50;
width: 0%;
transition: width 0.3s;
}
</style>
</head>
<body>
<div class="progress"><div class="progress-bar" id="progressBar"></div></div>
<header>
<h1>PHP Variable Finder</h1>
</header>
<script>
// Simple progress animation
document.addEventListener('DOMContentLoaded', function() {
const bar = document.getElementById('progressBar');
let width = 0;
const interval = setInterval(function() {
if (width >= 90) {
clearInterval(interval);
} else {
width += Math.random() * 10;
if (width > 90) width = 90;
bar.style.width = width + '%';
}
}, 300);
// When everything is loaded
window.addEventListener('load', function() {
bar.style.width = '100%';
setTimeout(function() {
document.querySelector('.progress').style.display = 'none';
}, 500);
});
});
</script>
<?php
// Process the request
$viewOnly = isset($_GET['view_only']) && $_GET['view_only'] == '1';
$finder = new PHPVariableDeclarationFinder('.', $viewOnly);
// Scan for variables with progress indicator
$finder->findDeclarations();
// Output results as HTML
echo $finder->getHtmlResults();
?>
</body>
</html>