388 lines
15 KiB
PHP
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>
|