chore: complete update

This commit is contained in:
2025-07-17 16:24:20 +02:00
parent 899227b0a4
commit 64a7051137
1300 changed files with 85570 additions and 2756 deletions

View File

@@ -0,0 +1,104 @@
<?php
declare(strict_types=1);
namespace Archive\StreamWrapper\Filter\Filters;
use Archive\StreamWrapper\Filter\StreamFilterInterface;
/**
* Stream-Filter für AES-256-Entschlüsselung
*/
class AES256DecryptFilter extends \php_user_filter implements StreamFilterInterface
{
private string $filterName = 'decrypt.aes256';
private array $supportedModes = ['read'];
private array $params = [];
private string $key = '';
private string $method = 'AES-256-CBC';
public function onCreate(): bool
{
// Parameter aus dem Stream-Context extrahieren
if (isset($this->params)) {
$this->params = $this->params;
}
$this->key = $this->getParam('key', '');
$this->method = $this->getParam('method', 'AES-256-CBC');
return !empty($this->key);
}
public function onClose(): void
{
// Cleanup falls nötig
}
public function getFilterName(): string
{
return $this->filterName;
}
public function getSupportedModes(): array
{
return $this->supportedModes;
}
public function filter($in, $out, &$consumed, bool $closing): int
{
$data = $this->readFromBrigade($in);
$consumed = strlen($data);
if (!empty($data)) {
$ivLength = openssl_cipher_iv_length($this->method);
if (strlen($data) < $ivLength) {
return PSFS_ERR_FATAL;
}
$iv = substr($data, 0, $ivLength);
$encrypted = substr($data, $ivLength);
$decrypted = openssl_decrypt($encrypted, $this->method, $this->key, OPENSSL_RAW_DATA, $iv);
if ($decrypted === false) {
return PSFS_ERR_FATAL;
}
$this->writeToBrigade($out, $decrypted);
}
return PSFS_PASS_ON;
}
/**
* Hilfsmethode zum Lesen von Daten aus der Input-Brigade
*/
private function readFromBrigade($brigade): string
{
$data = '';
while ($bucket = stream_bucket_make_writeable($brigade)) {
$data .= $bucket->data;
}
return $data;
}
/**
* Hilfsmethode zum Schreiben von Daten in die Output-Brigade
*/
private function writeToBrigade($brigade, string $data): void
{
if (!empty($data)) {
$bucket = stream_bucket_new($this->stream, $data);
stream_bucket_append($brigade, $bucket);
}
}
/**
* Gibt einen Parameter zurück
*/
private function getParam(string $key, $default = null)
{
return $this->params[$key] ?? $default;
}
}

View File

@@ -0,0 +1,107 @@
<?php
declare(strict_types=1);
namespace Archive\StreamWrapper\Filter\Filters;
use Archive\StreamWrapper\Filter\StreamFilterInterface;
/**
* Stream-Filter für Access-Logging
*/
class AccessLogFilter extends \php_user_filter implements StreamFilterInterface
{
private string $filterName = 'log.access';
private array $supportedModes = ['read', 'write'];
private array $params = [];
private string $logFile = '';
private bool $logReadAccess = true;
private bool $logWriteAccess = true;
public function onCreate(): bool
{
// Parameter aus dem Stream-Context extrahieren
if (isset($this->params)) {
$this->params = $this->params;
}
$this->logFile = $this->getParam('log_file', sys_get_temp_dir() . '/stream_access.log');
$this->logReadAccess = $this->getParam('log_read', true);
$this->logWriteAccess = $this->getParam('log_write', true);
return true;
}
public function onClose(): void
{
// Cleanup falls nötig
}
public function getFilterName(): string
{
return $this->filterName;
}
public function getSupportedModes(): array
{
return $this->supportedModes;
}
public function filter($in, $out, &$consumed, bool $closing): int
{
$data = $this->readFromBrigade($in);
$consumed = strlen($data);
if (!empty($data)) {
// Access-Log schreiben
$this->logAccess($data);
// Daten unverändert durchreichen
$this->writeToBrigade($out, $data);
}
return PSFS_PASS_ON;
}
private function logAccess(string $data): void
{
$timestamp = date('Y-m-d H:i:s');
$size = strlen($data);
$mode = $this->filtername; // read oder write
$logEntry = "[{$timestamp}] {$mode} - {$size} bytes\n";
file_put_contents($this->logFile, $logEntry, FILE_APPEND | LOCK_EX);
}
/**
* Hilfsmethode zum Lesen von Daten aus der Input-Brigade
*/
private function readFromBrigade($brigade): string
{
$data = '';
while ($bucket = stream_bucket_make_writeable($brigade)) {
$data .= $bucket->data;
}
return $data;
}
/**
* Hilfsmethode zum Schreiben von Daten in die Output-Brigade
*/
private function writeToBrigade($brigade, string $data): void
{
if (!empty($data)) {
$bucket = stream_bucket_new($this->stream, $data);
stream_bucket_append($brigade, $bucket);
}
}
/**
* Gibt einen Parameter zurück
*/
private function getParam(string $key, $default = null)
{
return $this->params[$key] ?? $default;
}
}

View File

@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace Archive\StreamWrapper\Filter\Filters;
use Archive\StreamWrapper\Filter\StreamFilterInterface;
/**
* Stream-Filter für Base64-Kodierung
*/
class Base64EncodeFilter extends \php_user_filter implements StreamFilterInterface
{
private string $filterName = 'transform.base64encode';
private array $supportedModes = ['write'];
private array $params = [];
private bool $urlSafe = false;
public function onCreate(): bool
{
// Parameter aus dem Stream-Context extrahieren
if (isset($this->params)) {
$this->params = $this->params;
}
$this->urlSafe = $this->getParam('url_safe', false);
return true;
}
public function onClose(): void
{
// Cleanup falls nötig
}
public function getFilterName(): string
{
return $this->filterName;
}
public function getSupportedModes(): array
{
return $this->supportedModes;
}
public function filter($in, $out, &$consumed, bool $closing): int
{
$data = $this->readFromBrigade($in);
$consumed = strlen($data);
if (!empty($data)) {
$encoded = base64_encode($data);
if ($this->urlSafe) {
$encoded = strtr($encoded, '+/', '-_');
$encoded = rtrim($encoded, '=');
}
$this->writeToBrigade($out, $encoded);
}
return PSFS_PASS_ON;
}
/**
* Hilfsmethode zum Lesen von Daten aus der Input-Brigade
*/
private function readFromBrigade($brigade): string
{
$data = '';
while ($bucket = stream_bucket_make_writeable($brigade)) {
$data .= $bucket->data;
}
return $data;
}
/**
* Hilfsmethode zum Schreiben von Daten in die Output-Brigade
*/
private function writeToBrigade($brigade, string $data): void
{
if (!empty($data)) {
$bucket = stream_bucket_new($this->stream, $data);
stream_bucket_append($brigade, $bucket);
}
}
/**
* Gibt einen Parameter zurück
*/
private function getParam(string $key, $default = null)
{
return $this->params[$key] ?? $default;
}
}

View File

@@ -0,0 +1,89 @@
<?php
declare(strict_types=1);
namespace Archive\StreamWrapper\Filter\Filters;
use Archive\StreamWrapper\Filter\StreamFilterInterface;
/**
* Stream-Filter für Gzip-Dekomprimierung
*/
class GzipDecompressFilter extends \php_user_filter implements StreamFilterInterface
{
private string $filterName = 'gzip.decompress';
private array $supportedModes = ['read'];
private array $params = [];
public function onCreate(): bool
{
// Parameter aus dem Stream-Context extrahieren
if (isset($this->params)) {
$this->params = $this->params;
}
return true;
}
public function onClose(): void
{
// Cleanup falls nötig
}
public function getFilterName(): string
{
return $this->filterName;
}
public function getSupportedModes(): array
{
return $this->supportedModes;
}
public function filter($in, $out, &$consumed, bool $closing): int
{
$data = $this->readFromBrigade($in);
$consumed = strlen($data);
if (!empty($data)) {
$decompressed = gzuncompress($data);
if ($decompressed === false) {
return PSFS_ERR_FATAL;
}
$this->writeToBrigade($out, $decompressed);
}
return PSFS_PASS_ON;
}
/**
* Hilfsmethode zum Lesen von Daten aus der Input-Brigade
*/
private function readFromBrigade($brigade): string
{
$data = '';
while ($bucket = stream_bucket_make_writeable($brigade)) {
$data .= $bucket->data;
}
return $data;
}
/**
* Hilfsmethode zum Schreiben von Daten in die Output-Brigade
*/
private function writeToBrigade($brigade, string $data): void
{
if (!empty($data)) {
$bucket = stream_bucket_new($this->stream, $data);
stream_bucket_append($brigade, $bucket);
}
}
/**
* Gibt einen Parameter zurück
*/
private function getParam(string $key, $default = null)
{
return $this->params[$key] ?? $default;
}
}

View File

@@ -0,0 +1,172 @@
<?php
declare(strict_types=1);
namespace Archive\StreamWrapper\Filter;
/**
* Factory für die einfache Erstellung und Nutzung von Stream-Filtern
*/
final class StreamFilterFactory
{
/**
* Initialisiert alle Stream-Filter
*/
public static function initialize(): void
{
StreamFilterRegistry::initializeDefaults();
}
/**
* Erstellt einen Kompressions-Filter
*/
public static function compression(int $level = 6): array
{
return [
'name' => 'gzip.compress',
'params' => ['level' => $level]
];
}
/**
* Erstellt einen Dekompressions-Filter
*/
public static function decompression(): array
{
return ['name' => 'gzip.decompress'];
}
/**
* Erstellt einen Verschlüsselungs-Filter
*/
public static function encryption(string $key, string $method = 'AES-256-CBC'): array
{
return [
'name' => 'encrypt.aes256',
'params' => [
'key' => $key,
'method' => $method
]
];
}
/**
* Erstellt einen Entschlüsselungs-Filter
*/
public static function decryption(string $key, string $method = 'AES-256-CBC'): array
{
return [
'name' => 'decrypt.aes256',
'params' => [
'key' => $key,
'method' => $method
]
];
}
/**
* Erstellt einen JSON-Validierungs-Filter
*/
public static function jsonValidation(bool $strict = true, bool $throwOnError = false): array
{
return [
'name' => 'validate.json',
'params' => [
'strict' => $strict,
'throw_on_error' => $throwOnError
]
];
}
/**
* Erstellt einen Base64-Encoding-Filter
*/
public static function base64Encode(bool $urlSafe = false): array
{
return [
'name' => 'transform.base64encode',
'params' => ['url_safe' => $urlSafe]
];
}
/**
* Erstellt einen Access-Log-Filter
*/
public static function accessLog(string $logFile = null): array
{
$params = [];
if ($logFile) {
$params['log_file'] = $logFile;
}
return [
'name' => 'log.access',
'params' => $params
];
}
/**
* Wendet Filter auf einen Stream an
*/
public static function applyFilters($stream, array $filters, int $mode = STREAM_FILTER_ALL): array
{
return StreamFilterRegistry::createFilterChain($stream, $filters, $mode);
}
/**
* Wendet einen einzelnen Filter an
*/
public static function applyFilter($stream, array $filterConfig, int $mode = STREAM_FILTER_ALL)
{
$filterName = $filterConfig['name'] ?? $filterConfig;
$params = $filterConfig['params'] ?? [];
return StreamFilterRegistry::appendFilter($stream, $filterName, $mode, $params);
}
/**
* Erstellt einen Stream mit vordefinierten Filtern
*/
public static function createFilteredStream(string $url, string $mode, array $filters = [], array $contextOptions = [])
{
$context = null;
if (!empty($contextOptions)) {
$context = stream_context_create($contextOptions);
}
$stream = fopen($url, $mode, false, $context);
if ($stream && !empty($filters)) {
self::applyFilters($stream, $filters);
}
return $stream;
}
/**
* Vordefinierte Filter-Kombinationen
*/
public static function secureDataFilter(string $encryptionKey): array
{
return [
self::jsonValidation(true, true),
self::compression(9),
self::encryption($encryptionKey),
self::accessLog()
];
}
public static function compressionFilter(int $level = 6): array
{
return [
self::compression($level),
self::accessLog()
];
}
public static function loggingFilter(string $logFile = null): array
{
return [
self::accessLog($logFile)
];
}
}

View File

@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace Archive\StreamWrapper\Filter;
/**
* Interface für benutzerdefinierte Stream-Filter
*/
interface StreamFilterInterface
{
/**
* Filtert Daten beim Lesen/Schreiben
*
* @param resource $in Input-Bucket-Brigade
* @param resource $out Output-Bucket-Brigade
* @param int $consumed Anzahl der verbrauchten Bytes
* @param bool $closing Gibt an, ob der Stream geschlossen wird
* @return int PSFS_PASS_ON, PSFS_FEED_ME oder PSFS_ERR_FATAL
*/
public function filter($in, $out, &$consumed, bool $closing): int;
/**
* Wird beim Anhängen des Filters an einen Stream aufgerufen
*
* @return bool True bei Erfolg, false bei Fehler
*/
public function onCreate(): bool;
/**
* Wird beim Entfernen des Filters aufgerufen
*/
public function onClose(): void;
/**
* Gibt den Filter-Namen zurück
*/
public function getFilterName(): string;
/**
* Gibt die unterstützten Modi zurück (read, write, read|write)
*/
public function getSupportedModes(): array;
}

View File

@@ -0,0 +1,167 @@
<?php
declare(strict_types=1);
namespace Archive\StreamWrapper\Filter;
use App\Framework\StreamWrapper\Exception\StreamWrapperException;
use App\Framework\StreamWrapper\Filter\Filters;
/**
* Registry zur Verwaltung und Registrierung von Stream-Filtern
*/
final class StreamFilterRegistry
{
private static array $registeredFilters = [];
private static bool $initialized = false;
/**
* Registriert einen Stream-Filter
*/
public static function register(string $filterName, string $filterClass): void
{
if (self::isRegistered($filterName)) {
stream_filter_remove($filterName);
}
if (!stream_filter_register($filterName, $filterClass)) {
throw new StreamWrapperException("Failed to register filter: $filterName");
}
self::$registeredFilters[$filterName] = $filterClass;
}
/**
* Entfernt die Registrierung eines Stream-Filters
*/
public static function unregister(string $filterName): void
{
if (self::isRegistered($filterName)) {
// Hinweis: stream_filter_unregister existiert nicht in PHP
// Filter werden automatisch beim Script-Ende entfernt
unset(self::$registeredFilters[$filterName]);
}
}
/**
* Prüft, ob ein Filter registriert ist
*/
public static function isRegistered(string $filterName): bool
{
return isset(self::$registeredFilters[$filterName]);
}
/**
* Gibt alle registrierten Filter zurück
*/
public static function getRegisteredFilters(): array
{
return array_keys(self::$registeredFilters);
}
/**
* Gibt die Filter-Klasse zurück
*/
public static function getFilterClass(string $filterName): ?string
{
return self::$registeredFilters[$filterName] ?? null;
}
/**
* Initialisiert alle Standard-Stream-Filter
*/
public static function initializeDefaults(): void
{
if (self::$initialized) {
return;
}
// Komprimierungs-Filter
self::register('gzip.compress', Filters\GzipCompressFilter::class);
self::register('gzip.decompress', \Archive\StreamWrapper\Filter\Filters\GzipDecompressFilter::class);
// Verschlüsselungs-Filter
self::register('encrypt.aes256', Filters\AES256EncryptFilter::class);
self::register('decrypt.aes256', \Archive\StreamWrapper\Filter\Filters\AES256DecryptFilter::class);
// Validierungs-Filter
self::register('validate.json', Filters\JsonValidationFilter::class);
self::register('validate.xml', Filters\XmlValidationFilter::class);
// Transform-Filter
self::register('transform.base64encode', \Archive\StreamWrapper\Filter\Filters\Base64EncodeFilter::class);
self::register('transform.base64decode', Filters\Base64DecodeFilter::class);
self::register('transform.uppercase', Filters\UppercaseFilter::class);
self::register('transform.lowercase', Filters\LowercaseFilter::class);
// Logging-Filter
self::register('log.access', \Archive\StreamWrapper\Filter\Filters\AccessLogFilter::class);
self::register('log.debug', Filters\DebugLogFilter::class);
// Caching-Filter
self::register('cache.write', Filters\CacheWriteFilter::class);
self::register('cache.read', Filters\CacheReadFilter::class);
self::$initialized = true;
}
/**
* Entfernt alle Framework-Stream-Filter
*/
public static function cleanup(): void
{
self::$registeredFilters = [];
self::$initialized = false;
}
/**
* Wendet einen Filter auf einen Stream an
*/
public static function appendFilter($stream, string $filterName, int $mode = STREAM_FILTER_ALL, array $params = [])
{
if (!self::isRegistered($filterName)) {
throw new StreamWrapperException("Filter not registered: $filterName");
}
return stream_filter_append($stream, $filterName, $mode, $params);
}
/**
* Wendet einen Filter am Anfang eines Streams an
*/
public static function prependFilter($stream, string $filterName, int $mode = STREAM_FILTER_ALL, array $params = [])
{
if (!self::isRegistered($filterName)) {
throw new StreamWrapperException("Filter not registered: $filterName");
}
return stream_filter_prepend($stream, $filterName, $mode, $params);
}
/**
* Entfernt einen Filter von einem Stream
*/
public static function removeFilter($filter): bool
{
return stream_filter_remove($filter);
}
/**
* Erstellt eine Filter-Kette für einen Stream
*/
public static function createFilterChain($stream, array $filters, int $mode = STREAM_FILTER_ALL): array
{
$appliedFilters = [];
foreach ($filters as $filterConfig) {
$filterName = $filterConfig['name'] ?? $filterConfig;
$params = $filterConfig['params'] ?? [];
$filter = self::appendFilter($stream, $filterName, $mode, $params);
if ($filter) {
$appliedFilters[] = $filter;
}
}
return $appliedFilters;
}
}