refactor: reorganize project structure for better maintainability
- Move 45 debug/test files from root to organized scripts/ directories - Secure public/ directory by removing debug files (security improvement) - Create structured scripts organization: • scripts/debug/ (20 files) - Framework debugging tools • scripts/test/ (18 files) - Test and validation scripts • scripts/maintenance/ (5 files) - Maintenance utilities • scripts/dev/ (2 files) - Development tools Security improvements: - Removed all debug/test files from public/ directory - Only production files remain: index.php, health.php Root directory cleanup: - Reduced from 47 to 2 PHP files in root - Only essential production files: console.php, worker.php This improves: ✅ Security (no debug code in public/) ✅ Organization (clear separation of concerns) ✅ Maintainability (easy to find and manage scripts) ✅ Professional structure (clean root directory)
This commit is contained in:
38
scripts/maintenance/autoloader_workaround.php
Normal file
38
scripts/maintenance/autoloader_workaround.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Temporary workaround for the "Uninitialized string offset 0" warning in ClassLoader.php
|
||||
*
|
||||
* This file registers an autoloader hook that catches empty class names,
|
||||
* logs them with stack traces, but doesn't throw exceptions, allowing the
|
||||
* application to continue running.
|
||||
*
|
||||
* Usage: Include this file at the beginning of your application bootstrap process,
|
||||
* before any other autoloading occurs.
|
||||
*/
|
||||
|
||||
// Register the autoloader hook
|
||||
spl_autoload_register(function($class) {
|
||||
if (empty($class)) {
|
||||
// Log the empty class name with stack trace
|
||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10);
|
||||
$logMessage = date('Y-m-d H:i:s') . " - Empty class name detected in autoloader.\nStack trace:\n" .
|
||||
json_encode($trace, JSON_PRETTY_PRINT) . "\n\n";
|
||||
|
||||
// Log to file
|
||||
file_put_contents(
|
||||
__DIR__ . '/empty_class_debug.log',
|
||||
$logMessage,
|
||||
FILE_APPEND
|
||||
);
|
||||
|
||||
// Also log to error_log for server logs
|
||||
error_log('Empty class name detected in autoloader. See empty_class_debug.log for details.');
|
||||
|
||||
// Return false to continue with other autoloaders
|
||||
return false;
|
||||
}
|
||||
|
||||
// Not an empty class name, let other autoloaders handle it
|
||||
return false;
|
||||
}, true, true); // prepend=true to ensure this runs before other autoloaders
|
||||
73
scripts/maintenance/bootstrap-discovery.php
Normal file
73
scripts/maintenance/bootstrap-discovery.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Bootstrap Discovery System
|
||||
*
|
||||
* This script runs the discovery scanners and stores results
|
||||
* Run this ONCE to initialize the new discovery system
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
use App\Framework\BuildTime\Discovery\Scanners\AttributeScanner;
|
||||
use App\Framework\BuildTime\Discovery\Scanners\InterfaceScanner;
|
||||
use App\Framework\BuildTime\Discovery\Scanners\TemplateScanner;
|
||||
use App\Framework\Core\PathProvider;
|
||||
use App\Framework\Discovery\Storage\DiscoveryStorageService;
|
||||
use App\Framework\Filesystem\FileScanner;
|
||||
use App\Framework\Filesystem\FileSystemService;
|
||||
use App\Framework\Logging\NullLogger;
|
||||
use App\Framework\Reflection\CachedReflectionProvider;
|
||||
|
||||
echo "🚀 Bootstrapping Discovery System...\n\n";
|
||||
$totalStart = microtime(true);
|
||||
|
||||
// Create dependencies
|
||||
$basePath = __DIR__;
|
||||
$pathProvider = new PathProvider($basePath);
|
||||
$storage = new DiscoveryStorageService($pathProvider);
|
||||
$fileSystemService = new FileSystemService();
|
||||
$logger = null;
|
||||
$fileScanner = new FileScanner($logger, null, $fileSystemService);
|
||||
$reflectionProvider = new CachedReflectionProvider();
|
||||
|
||||
// 1. Discover Attributes
|
||||
echo "📦 Discovering attributes...\n";
|
||||
$attrStart = microtime(true);
|
||||
$attributeScanner = new AttributeScanner($fileScanner, $reflectionProvider);
|
||||
$paths = [$pathProvider->getSourcePath()];
|
||||
$attributeRegistry = $attributeScanner->scan($paths);
|
||||
$storage->storeAttributes($attributeRegistry);
|
||||
$attrDuration = round((microtime(true) - $attrStart) * 1000, 2);
|
||||
echo " ✅ {$attributeRegistry->count()} attributes in {$attrDuration}ms\n\n";
|
||||
|
||||
// 2. Discover Templates
|
||||
echo "📄 Discovering templates...\n";
|
||||
$tplStart = microtime(true);
|
||||
$templateScanner = new TemplateScanner($fileScanner);
|
||||
$templatePaths = [
|
||||
$pathProvider->getSourcePath(),
|
||||
$pathProvider->getBasePath() . '/resources'
|
||||
];
|
||||
$templateRegistry = $templateScanner->scan($templatePaths);
|
||||
$storage->storeTemplates($templateRegistry);
|
||||
$tplDuration = round((microtime(true) - $tplStart) * 1000, 2);
|
||||
echo " ✅ " . count($templateRegistry->getAll()) . " templates in {$tplDuration}ms\n\n";
|
||||
|
||||
// 3. Discover Interfaces
|
||||
echo "🔌 Discovering interface implementations...\n";
|
||||
$intStart = microtime(true);
|
||||
$interfaceScanner = new InterfaceScanner($fileScanner, $reflectionProvider, []);
|
||||
$interfaceRegistry = $interfaceScanner->scan($paths);
|
||||
$storage->storeInterfaces($interfaceRegistry);
|
||||
$intDuration = round((microtime(true) - $intStart) * 1000, 2);
|
||||
echo " ✅ {$interfaceRegistry->count()} implementations in {$intDuration}ms\n\n";
|
||||
|
||||
// Summary
|
||||
$totalDuration = round((microtime(true) - $totalStart) * 1000, 2);
|
||||
echo str_repeat("=", 60) . "\n";
|
||||
echo "🎉 Discovery bootstrap complete in {$totalDuration}ms\n";
|
||||
echo " 📁 Stored in: storage/discovery/\n";
|
||||
echo str_repeat("=", 60) . "\n";
|
||||
90
scripts/maintenance/compile-container.php
Normal file
90
scripts/maintenance/compile-container.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
// build-container.php
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use App\Framework\DI\DefaultContainer;
|
||||
use App\Framework\DI\ContainerCompiler;
|
||||
|
||||
// Container initialisieren
|
||||
$container = new DefaultContainer();
|
||||
|
||||
// Hier wichtige Core-Klassen registrieren
|
||||
$container->bind(\App\Framework\Http\RequestFactory::class, \App\Framework\Http\RequestFactory::class);
|
||||
// Weitere Bindungen...
|
||||
|
||||
// Liste der zu kompilierenden Services
|
||||
$services = [
|
||||
\App\Framework\Core\Application::class,
|
||||
\App\Framework\EventBus\DefaultEventBus::class,
|
||||
\App\Framework\CommandBus\DefaultCommandBus::class,
|
||||
\App\Framework\Router\HttpRouter::class,
|
||||
\App\Framework\Http\RequestFactory::class,
|
||||
// Weitere wichtige Services...
|
||||
];
|
||||
|
||||
// Services aus Verzeichnissen automatisch erkennen
|
||||
$servicesFromDiscovery = discoverServicesFromDirectories([
|
||||
__DIR__ . '/../src/Application',
|
||||
__DIR__ . '/../src/Framework',
|
||||
]);
|
||||
$services = array_merge($services, $servicesFromDiscovery);
|
||||
|
||||
// Container kompilieren
|
||||
$compiler = new ContainerCompiler();
|
||||
$compiler->compile(
|
||||
$container,
|
||||
$services,
|
||||
__DIR__ . '/../cache/CompiledContainer.php'
|
||||
);
|
||||
|
||||
echo "Container kompiliert!\n";
|
||||
|
||||
// Hilfsfunktion zum Entdecken von Services
|
||||
function discoverServicesFromDirectories(array $directories): array
|
||||
{
|
||||
$services = [];
|
||||
foreach ($directories as $directory) {
|
||||
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->isFile() && $file->getExtension() === 'php') {
|
||||
$className = getClassNameFromFile($file->getRealPath());
|
||||
if ($className) {
|
||||
$services[] = $className;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $services;
|
||||
}
|
||||
|
||||
function getClassNameFromFile(string $file): ?string
|
||||
{
|
||||
$content = file_get_contents($file);
|
||||
$tokens = token_get_all($content);
|
||||
$namespace = '';
|
||||
$class = '';
|
||||
$namespaceFound = false;
|
||||
$classFound = false;
|
||||
|
||||
foreach ($tokens as $token) {
|
||||
if (is_array($token)) {
|
||||
if ($token[0] === T_NAMESPACE) {
|
||||
$namespaceFound = true;
|
||||
} elseif ($namespaceFound && $token[0] === T_STRING) {
|
||||
$namespace .= $token[1];
|
||||
} elseif ($namespaceFound && $token[0] === T_NS_SEPARATOR) {
|
||||
$namespace .= '\\';
|
||||
} elseif ($token[0] === T_CLASS) {
|
||||
$classFound = true;
|
||||
} elseif ($classFound && $token[0] === T_STRING) {
|
||||
$class = $token[1];
|
||||
break;
|
||||
}
|
||||
} elseif ($namespaceFound && $token === ';') {
|
||||
$namespaceFound = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $namespace && $class ? $namespace . '\\' . $class : null;
|
||||
}
|
||||
224
scripts/maintenance/populate_images_from_filesystem.php
Normal file
224
scripts/maintenance/populate_images_from_filesystem.php
Normal file
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Script to populate the database with images found in the filesystem
|
||||
*
|
||||
* This script scans storage/uploads/ for image files and creates database records
|
||||
* to match the existing files on disk.
|
||||
*/
|
||||
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
use App\Domain\Media\Image;
|
||||
use App\Framework\Core\ValueObjects\FileSize;
|
||||
use App\Framework\Core\ValueObjects\Hash;
|
||||
use App\Framework\Database\DatabaseManager;
|
||||
use App\Framework\Filesystem\FilePath;
|
||||
use App\Framework\Http\MimeType;
|
||||
use App\Framework\Ulid\Ulid;
|
||||
use App\Framework\Ulid\UlidGenerator;
|
||||
use App\Framework\DateTime\SystemClock;
|
||||
|
||||
class ImageMigrationScript
|
||||
{
|
||||
private PDO $db;
|
||||
private SystemClock $clock;
|
||||
private string $uploadsPath;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->clock = new SystemClock();
|
||||
$this->uploadsPath = __DIR__ . '/storage/uploads';
|
||||
|
||||
// Initialize database
|
||||
$this->initializeDatabase();
|
||||
}
|
||||
|
||||
private function initializeDatabase(): void
|
||||
{
|
||||
// Simple SQLite connection for this script
|
||||
$pdo = new PDO('sqlite:' . __DIR__ . '/database.sqlite');
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$this->db = $pdo;
|
||||
}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
echo "🔍 Scanning for images in: {$this->uploadsPath}\n";
|
||||
|
||||
if (!is_dir($this->uploadsPath)) {
|
||||
echo "❌ Uploads directory not found: {$this->uploadsPath}\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$imageFiles = $this->findImageFiles();
|
||||
echo "📁 Found " . count($imageFiles) . " image files\n";
|
||||
|
||||
if (empty($imageFiles)) {
|
||||
echo "ℹ️ No images to migrate\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$this->migrateImages($imageFiles);
|
||||
echo "✅ Migration completed!\n";
|
||||
}
|
||||
|
||||
private function findImageFiles(): array
|
||||
{
|
||||
$iterator = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($this->uploadsPath)
|
||||
);
|
||||
|
||||
$imageFiles = [];
|
||||
$allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
if (!$file->isFile()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$extension = strtolower($file->getExtension());
|
||||
if (!in_array($extension, $allowedExtensions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$imageFiles[] = [
|
||||
'path' => $file->getPathname(),
|
||||
'filename' => $file->getFilename(),
|
||||
'extension' => $extension,
|
||||
'size' => $file->getSize(),
|
||||
'mtime' => $file->getMTime()
|
||||
];
|
||||
}
|
||||
|
||||
return $imageFiles;
|
||||
}
|
||||
|
||||
private function migrateImages(array $imageFiles): void
|
||||
{
|
||||
// Check current database schema
|
||||
$this->checkDatabaseSchema();
|
||||
|
||||
$migrated = 0;
|
||||
$errors = 0;
|
||||
|
||||
foreach ($imageFiles as $fileInfo) {
|
||||
try {
|
||||
$this->migrateImageFile($fileInfo);
|
||||
$migrated++;
|
||||
echo "✓ Migrated: {$fileInfo['filename']}\n";
|
||||
} catch (Exception $e) {
|
||||
$errors++;
|
||||
echo "❌ Error migrating {$fileInfo['filename']}: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n📊 Summary:\n";
|
||||
echo " Migrated: $migrated\n";
|
||||
echo " Errors: $errors\n";
|
||||
}
|
||||
|
||||
private function checkDatabaseSchema(): void
|
||||
{
|
||||
// Check what columns exist in the images table
|
||||
$stmt = $this->db->query("PRAGMA table_info(images)");
|
||||
$columns = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
echo "📋 Database schema (images table):\n";
|
||||
foreach ($columns as $column) {
|
||||
echo " - {$column['name']} ({$column['type']})\n";
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
private function migrateImageFile(array $fileInfo): void
|
||||
{
|
||||
$fullPath = $fileInfo['path'];
|
||||
|
||||
// Extract image dimensions if possible
|
||||
$imageInfo = @getimagesize($fullPath);
|
||||
$width = $imageInfo[0] ?? 0;
|
||||
$height = $imageInfo[1] ?? 0;
|
||||
|
||||
// Generate ULID
|
||||
$ulidGenerator = new UlidGenerator();
|
||||
$ulidString = $ulidGenerator->generate($this->clock);
|
||||
|
||||
// Calculate hash
|
||||
$hashValue = hash_file('sha256', $fullPath);
|
||||
|
||||
// Determine MIME type
|
||||
$mimeTypeString = match (strtolower($fileInfo['extension'])) {
|
||||
'jpg', 'jpeg' => 'image/jpeg',
|
||||
'png' => 'image/png',
|
||||
'gif' => 'image/gif',
|
||||
'webp' => 'image/webp',
|
||||
default => 'image/jpeg'
|
||||
};
|
||||
|
||||
// Extract original filename from the complex filename structure
|
||||
$originalFilename = $this->extractOriginalFilename($fileInfo['filename']);
|
||||
|
||||
// Get relative path from storage root
|
||||
$relativePath = str_replace($this->uploadsPath . '/', '', $fullPath);
|
||||
$pathOnly = dirname($relativePath);
|
||||
|
||||
// Insert into database using the correct table structure
|
||||
$sql = "INSERT INTO images (
|
||||
ulid, filename, original_filename, mime_type, file_size,
|
||||
width, height, hash, path, created_at, updated_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
$stmt = $this->db->prepare($sql);
|
||||
$now = date('Y-m-d H:i:s');
|
||||
|
||||
$stmt->execute([
|
||||
$ulidString,
|
||||
$fileInfo['filename'],
|
||||
$originalFilename,
|
||||
$mimeTypeString,
|
||||
$fileInfo['size'],
|
||||
$width,
|
||||
$height,
|
||||
$hashValue,
|
||||
$pathOnly,
|
||||
$now,
|
||||
$now
|
||||
]);
|
||||
}
|
||||
|
||||
private function extractOriginalFilename(string $filename): string
|
||||
{
|
||||
// Pattern for files like: BFWCAKKEHTKF5SYR_6626fc6b...cd1_original.png
|
||||
if (preg_match('/^[A-Z0-9]{16}_[a-f0-9]{64}_original\.(.+)$/', $filename, $matches)) {
|
||||
// This is an original file, try to find the pattern in other files
|
||||
$basePattern = substr($filename, 0, strpos($filename, '_original.'));
|
||||
// For now, just return a cleaned version
|
||||
return "original." . $matches[1];
|
||||
}
|
||||
|
||||
// Pattern for simple files like: 00MF9VW9R36NJN3VCFSTS2CK6R.jpg
|
||||
if (preg_match('/^[A-Z0-9]{26}\.(.+)$/', $filename, $matches)) {
|
||||
return "image." . $matches[1];
|
||||
}
|
||||
|
||||
// Fallback: return as-is
|
||||
return $filename;
|
||||
}
|
||||
}
|
||||
|
||||
// Run the migration
|
||||
echo "🚀 Starting image migration from filesystem to database...\n\n";
|
||||
|
||||
try {
|
||||
$migration = new ImageMigrationScript();
|
||||
$migration->run();
|
||||
} catch (Exception $e) {
|
||||
echo "💥 Migration failed: " . $e->getMessage() . "\n";
|
||||
echo "Stack trace:\n" . $e->getTraceAsString() . "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
echo "\n🎉 Migration script completed!\n";
|
||||
77
scripts/maintenance/quick-cache-fix.php
Normal file
77
scripts/maintenance/quick-cache-fix.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Quick fix to restore localhost functionality
|
||||
* Clears discovery cache and forces a minimal discovery
|
||||
*/
|
||||
|
||||
echo "🚨 Quick Fix: Restoring localhost functionality\n";
|
||||
echo "===============================================\n\n";
|
||||
|
||||
try {
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
echo "1. ✅ Clearing discovery cache...\n";
|
||||
|
||||
// Clear storage cache
|
||||
exec('rm -rf ' . __DIR__ . '/../storage/cache/*', $output, $returnCode);
|
||||
if ($returnCode === 0) {
|
||||
echo " ✅ Storage cache cleared\n";
|
||||
}
|
||||
|
||||
// Clear any potential cache files in var/
|
||||
if (is_dir(__DIR__ . '/../var/cache')) {
|
||||
exec('rm -rf ' . __DIR__ . '/../var/cache/*', $output, $returnCode);
|
||||
echo " ✅ Var cache cleared\n";
|
||||
}
|
||||
|
||||
echo "2. ⚡ Optimizing discovery paths...\n";
|
||||
|
||||
// Create a temporary configuration to reduce discovery scope
|
||||
$optimizedConfig = [
|
||||
'discovery_paths' => [
|
||||
'Application', // Only scan application code
|
||||
'Domain' // And domain models
|
||||
],
|
||||
'exclude_paths' => [
|
||||
'Framework/AsyncExamples', // Skip examples
|
||||
'Framework/Testing', // Skip testing utilities
|
||||
'Framework/Debug', // Skip debug utilities
|
||||
'tests' // Skip test files
|
||||
]
|
||||
];
|
||||
|
||||
echo " ✅ Limited discovery to: " . implode(', ', $optimizedConfig['discovery_paths']) . "\n";
|
||||
echo " ✅ Excluded: " . implode(', ', $optimizedConfig['exclude_paths']) . "\n";
|
||||
|
||||
echo "\n3. 🧪 Testing basic application...\n";
|
||||
|
||||
// Test if basic classes load without discovery
|
||||
$testClasses = [
|
||||
'App\\Framework\\Core\\Application',
|
||||
'App\\Framework\\Http\\HttpRequest'
|
||||
];
|
||||
|
||||
foreach ($testClasses as $class) {
|
||||
if (class_exists($class)) {
|
||||
echo " ✅ $class loaded\n";
|
||||
} else {
|
||||
echo " ❌ $class failed\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n4. 💡 Recommendations:\n";
|
||||
echo " • Discovery system needs optimization for large codebase\n";
|
||||
echo " • Consider implementing lazy loading for non-critical components\n";
|
||||
echo " • Use incremental discovery instead of full scans\n";
|
||||
echo " • Add performance monitoring to discovery process\n";
|
||||
|
||||
echo "\n🎉 Quick fix complete!\n";
|
||||
echo "💬 Try accessing https://localhost/ now\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "❌ Error: " . $e->getMessage() . "\n";
|
||||
exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user