Files
michaelschiemer/src/Framework/Filesystem/PermissionChecker.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

211 lines
6.3 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\Filesystem;
use App\Framework\Core\PathProvider;
use App\Framework\Filesystem\ValueObjects\FilePermissions;
/**
* Helper-Klasse für Filesystem-Permissions-Checks
*/
final readonly class PermissionChecker
{
public function __construct(
private PathProvider $pathProvider
) {
}
private function resolvePath(string $path): string
{
// Absolute paths bleiben unverändert
if (str_starts_with($path, '/')) {
return $path;
}
// Relative paths über PathProvider auflösen (mit Caching)
return $this->pathProvider->resolvePath($path);
}
public function isDirectoryWritable(string $path): bool
{
$resolvedPath = $this->resolvePath($path);
if (! is_dir($resolvedPath)) {
return false;
}
return is_writable($resolvedPath);
}
public function canCreateDirectory(string $path): bool
{
$resolvedPath = $this->resolvePath($path);
// Prüfe, ob Parent-Directory existiert und schreibbar ist
$parentDir = dirname($resolvedPath);
if (! is_dir($parentDir)) {
return $this->canCreateDirectory(dirname($path));
}
return is_writable($parentDir);
}
public function canWriteFile(string $path): bool
{
$resolvedPath = $this->resolvePath($path);
// Wenn Datei existiert, prüfe ob sie schreibbar ist
if (file_exists($resolvedPath)) {
return is_writable($resolvedPath);
}
// Wenn Datei nicht existiert, prüfe ob Directory schreibbar ist
$dir = dirname($path);
return $this->isDirectoryWritable($dir) || $this->canCreateDirectory($dir);
}
public function canReadFile(string $path): bool
{
$resolvedPath = $this->resolvePath($path);
return file_exists($resolvedPath) && is_readable($resolvedPath);
}
public function canDeleteFile(string $path): bool
{
$resolvedPath = $this->resolvePath($path);
if (! file_exists($resolvedPath)) {
return false;
}
// Datei muss schreibbar sein UND Directory muss schreibbar sein
$dir = dirname($resolvedPath);
return is_writable($resolvedPath) && is_writable($dir);
}
public function getPermissionString(string $path): string
{
$resolvedPath = $this->resolvePath($path);
if (! file_exists($resolvedPath)) {
return 'not found';
}
$perms = fileperms($resolvedPath);
$info = '';
// Type
if (($perms & 0xC000) == 0xC000) {
$info = 's'; // Socket
} elseif (($perms & 0xA000) == 0xA000) {
$info = 'l'; // Symbolic Link
} elseif (($perms & 0x8000) == 0x8000) {
$info = 'f'; // Regular file
} elseif (($perms & 0x6000) == 0x6000) {
$info = 'b'; // Block special
} elseif (($perms & 0x4000) == 0x4000) {
$info = 'd'; // Directory
} elseif (($perms & 0x2000) == 0x2000) {
$info = 'c'; // Character special
} elseif (($perms & 0x1000) == 0x1000) {
$info = 'p'; // FIFO pipe
} else {
$info = 'u'; // Unknown
}
// Owner
$info .= (($perms & 0x0100) ? 'r' : '-');
$info .= (($perms & 0x0080) ? 'w' : '-');
$info .= (($perms & 0x0040) ?
(($perms & 0x0800) ? 's' : 'x') :
(($perms & 0x0800) ? 'S' : '-'));
// Group
$info .= (($perms & 0x0020) ? 'r' : '-');
$info .= (($perms & 0x0010) ? 'w' : '-');
$info .= (($perms & 0x0008) ?
(($perms & 0x0400) ? 's' : 'x') :
(($perms & 0x0400) ? 'S' : '-'));
// World
$info .= (($perms & 0x0004) ? 'r' : '-');
$info .= (($perms & 0x0002) ? 'w' : '-');
$info .= (($perms & 0x0001) ?
(($perms & 0x0200) ? 't' : 'x') :
(($perms & 0x0200) ? 'T' : '-'));
return $info;
}
public function getDiagnosticInfo(string $path): array
{
$resolvedPath = $this->resolvePath($path);
$realPath = realpath($resolvedPath) ?: $resolvedPath;
return [
'path' => $path,
'resolved_path' => $resolvedPath,
'real_path' => $realPath,
'exists' => file_exists($resolvedPath),
'is_file' => is_file($resolvedPath),
'is_dir' => is_dir($resolvedPath),
'is_readable' => is_readable($resolvedPath),
'is_writable' => is_writable($resolvedPath),
'permissions' => $this->getPermissionString($path),
'owner' => file_exists($resolvedPath) ? posix_getpwuid(fileowner($resolvedPath))['name'] ?? 'unknown' : null,
'group' => file_exists($resolvedPath) ? posix_getgrgid(filegroup($resolvedPath))['name'] ?? 'unknown' : null,
'parent_dir' => dirname($resolvedPath),
'parent_writable' => is_dir(dirname($resolvedPath)) && is_writable(dirname($resolvedPath)),
];
}
/**
* Get current file permissions as FilePermissions value object
*/
public function getPermissions(string $path): ?FilePermissions
{
$resolvedPath = $this->resolvePath($path);
if (! file_exists($resolvedPath)) {
return null;
}
$perms = fileperms($resolvedPath);
// Extract only permission bits (last 9 bits)
$mode = $perms & 0777;
return new FilePermissions($mode);
}
/**
* Set file permissions using FilePermissions value object
*/
public function setPermissions(string $path, FilePermissions $permissions): bool
{
$resolvedPath = $this->resolvePath($path);
if (! file_exists($resolvedPath)) {
return false;
}
return @chmod($resolvedPath, $permissions->mode);
}
/**
* Ensure file has specific permissions, set them if different
*/
public function ensurePermissions(string $path, FilePermissions $permissions): bool
{
$current = $this->getPermissions($path);
if ($current === null) {
return false; // File doesn't exist
}
if ($current->equals($permissions)) {
return true; // Already has correct permissions
}
return $this->setPermissions($path, $permissions);
}
}