chore: complete update
This commit is contained in:
87
.archive/StreamWrapper/Context/StreamContext.php
Normal file
87
.archive/StreamWrapper/Context/StreamContext.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Archive\StreamWrapper\Context;
|
||||
|
||||
/**
|
||||
* Wrapper für Stream-Context-Optionen
|
||||
*/
|
||||
final class StreamContext
|
||||
{
|
||||
private array $options = [];
|
||||
private array $params = [];
|
||||
|
||||
public function __construct($resource = null)
|
||||
{
|
||||
if ($resource !== null) {
|
||||
$this->options = stream_context_get_options($resource);
|
||||
$this->params = stream_context_get_params($resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt eine Option für das angegebene Protokoll zurück
|
||||
*/
|
||||
public function getOption(string $protocol, string $key, $default = null)
|
||||
{
|
||||
return $this->options[$protocol][$key] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt alle Optionen für ein Protokoll zurück
|
||||
*/
|
||||
public function getProtocolOptions(string $protocol): array
|
||||
{
|
||||
return $this->options[$protocol] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt eine Option für das angegebene Protokoll
|
||||
*/
|
||||
public function setOption(string $protocol, string $key, $value): self
|
||||
{
|
||||
$this->options[$protocol][$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt einen Parameter zurück
|
||||
*/
|
||||
public function getParam(string $key, $default = null)
|
||||
{
|
||||
return $this->params[$key] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt einen Parameter
|
||||
*/
|
||||
public function setParam(string $key, $value): self
|
||||
{
|
||||
$this->params[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt alle Optionen zurück
|
||||
*/
|
||||
public function getAllOptions(): array
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt alle Parameter zurück
|
||||
*/
|
||||
public function getAllParams(): array
|
||||
{
|
||||
return $this->params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt einen neuen Stream-Context mit den aktuellen Optionen
|
||||
*/
|
||||
public function createResource()
|
||||
{
|
||||
return stream_context_create($this->options, $this->params);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Archive\StreamWrapper\Exception;
|
||||
|
||||
use App\Framework\StreamWrapper\Exception\StreamWrapperException;
|
||||
|
||||
/**
|
||||
* Exception für nicht unterstützte Stream-Protokolle
|
||||
*/
|
||||
class UnsupportedProtocolException extends StreamWrapperException
|
||||
{
|
||||
public function __construct(string $protocol)
|
||||
{
|
||||
parent::__construct("Unsupported stream protocol: $protocol");
|
||||
}
|
||||
}
|
||||
104
.archive/StreamWrapper/Filter/Filters/AES256DecryptFilter.php
Normal file
104
.archive/StreamWrapper/Filter/Filters/AES256DecryptFilter.php
Normal 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;
|
||||
}
|
||||
}
|
||||
107
.archive/StreamWrapper/Filter/Filters/AccessLogFilter.php
Normal file
107
.archive/StreamWrapper/Filter/Filters/AccessLogFilter.php
Normal 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;
|
||||
}
|
||||
}
|
||||
94
.archive/StreamWrapper/Filter/Filters/Base64EncodeFilter.php
Normal file
94
.archive/StreamWrapper/Filter/Filters/Base64EncodeFilter.php
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
172
.archive/StreamWrapper/Filter/StreamFilterFactory.php
Normal file
172
.archive/StreamWrapper/Filter/StreamFilterFactory.php
Normal 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)
|
||||
];
|
||||
}
|
||||
}
|
||||
43
.archive/StreamWrapper/Filter/StreamFilterInterface.php
Normal file
43
.archive/StreamWrapper/Filter/StreamFilterInterface.php
Normal 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;
|
||||
}
|
||||
167
.archive/StreamWrapper/Filter/StreamFilterRegistry.php
Normal file
167
.archive/StreamWrapper/Filter/StreamFilterRegistry.php
Normal 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;
|
||||
}
|
||||
}
|
||||
29
.archive/StreamWrapper/README.md
Normal file
29
.archive/StreamWrapper/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# StreamWrapper Module
|
||||
|
||||
Das StreamWrapper-Modul ermöglicht den transparenten Zugriff auf verschiedene Framework-Services über einheitliche Stream-URLs. Dadurch können Sie native PHP-Funktionen wie `file_get_contents()`, `fopen()`, `copy()` etc. mit Framework-Services verwenden.
|
||||
|
||||
## Installation
|
||||
|
||||
```php
|
||||
// Initialisierung
|
||||
StreamWrapperFactory::initialize();
|
||||
|
||||
// Filter verwenden
|
||||
$data = StreamWrapperFactory::readWithFilters(
|
||||
'cache://session/user123',
|
||||
[
|
||||
StreamFilterFactory::decompression(),
|
||||
StreamFilterFactory::decryption($key),
|
||||
StreamFilterFactory::jsonValidation()
|
||||
]
|
||||
);
|
||||
|
||||
// Neue Filter sind verfügbar
|
||||
$encoded = StreamWrapperFactory::writeWithFilters(
|
||||
'cache://data',
|
||||
$binaryData,
|
||||
[
|
||||
StreamFilterFactory::base64Encode(true), // URL-safe
|
||||
StreamFilterFactory::compression(9)
|
||||
]
|
||||
);
|
||||
167
.archive/StreamWrapper/StreamWrapperFactory.php
Normal file
167
.archive/StreamWrapper/StreamWrapperFactory.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Archive\StreamWrapper;
|
||||
|
||||
use App\Framework\StreamWrapper\StreamWrapperRegistry;
|
||||
|
||||
/**
|
||||
* Factory für die einfache Erstellung und Nutzung von Stream-Wrappern
|
||||
*/
|
||||
final class StreamWrapperFactory
|
||||
{
|
||||
/**
|
||||
* Initialisiert alle Stream-Wrapper und Filter
|
||||
*/
|
||||
public static function initialize(): void
|
||||
{
|
||||
StreamWrapperRegistry::initializeDefaults();
|
||||
\Archive\StreamWrapper\Filter\StreamFilterRegistry::initializeDefaults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt eine Cache-Stream-URL
|
||||
*/
|
||||
public static function cache(string $key, ?string $namespace = null): string
|
||||
{
|
||||
$host = $namespace ?? 'default';
|
||||
return "cache://{$host}/{$key}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt eine Config-Stream-URL
|
||||
*/
|
||||
public static function config(string $key, string $source = 'default'): string
|
||||
{
|
||||
return "config://{$source}/{$key}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt eine Log-Stream-URL
|
||||
*/
|
||||
public static function log(string $filename, string $channel = 'default'): string
|
||||
{
|
||||
return "log://{$channel}/{$filename}";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Erstellt eine Database-Stream-URL
|
||||
*/
|
||||
public static function database(string $table, string $operation = 'select', array $params = [], string $connection = 'default'): string
|
||||
{
|
||||
$url = "db://{$connection}/{$table}/{$operation}";
|
||||
|
||||
if (!empty($params)) {
|
||||
$url .= '?' . http_build_query($params);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt eine HTTP-Client-Stream-URL
|
||||
*/
|
||||
public static function httpClient(string $host, string $path = ''): string
|
||||
{
|
||||
return "http-client://{$host}/{$path}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest Daten von einer Stream-URL
|
||||
*/
|
||||
public static function read(string $url, array $contextOptions = []): string|false
|
||||
{
|
||||
if (!empty($contextOptions)) {
|
||||
$context = stream_context_create($contextOptions);
|
||||
return file_get_contents($url, false, $context);
|
||||
}
|
||||
|
||||
return file_get_contents($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schreibt Daten zu einer Stream-URL
|
||||
*/
|
||||
public static function write(string $url, string $data, array $contextOptions = []): int|false
|
||||
{
|
||||
if (!empty($contextOptions)) {
|
||||
$context = stream_context_create($contextOptions);
|
||||
return file_put_contents($url, $data, 0, $context);
|
||||
}
|
||||
|
||||
return file_put_contents($url, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft, ob eine Stream-URL existiert
|
||||
*/
|
||||
public static function exists(string $url): bool
|
||||
{
|
||||
return file_exists($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Kopiert zwischen Stream-URLs
|
||||
*/
|
||||
public static function copy(string $from, string $to): bool
|
||||
{
|
||||
return copy($from, $to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Löscht eine Stream-URL
|
||||
*/
|
||||
public static function delete(string $url): bool
|
||||
{
|
||||
return unlink($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt einen Stream mit Filtern
|
||||
*/
|
||||
public static function createFilteredStream(string $url, string $mode, array $filters = [], array $contextOptions = [])
|
||||
{
|
||||
return \Archive\StreamWrapper\Filter\StreamFilterFactory::createFilteredStream($url, $mode, $filters, $contextOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wendet Filter auf einen bestehenden Stream an
|
||||
*/
|
||||
public static function applyFilters($stream, array $filters, int $mode = STREAM_FILTER_ALL): array
|
||||
{
|
||||
return \Archive\StreamWrapper\Filter\StreamFilterFactory::applyFilters($stream, $filters, $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest von einer URL mit angewendeten Filtern
|
||||
*/
|
||||
public static function readWithFilters(string $url, array $filters = [], array $contextOptions = []): string|false
|
||||
{
|
||||
$stream = self::createFilteredStream($url, 'r', $filters, $contextOptions);
|
||||
if (!$stream) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$content = stream_get_contents($stream);
|
||||
fclose($stream);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schreibt zu einer URL mit angewendeten Filtern
|
||||
*/
|
||||
public static function writeWithFilters(string $url, string $data, array $filters = [], array $contextOptions = []): int|false
|
||||
{
|
||||
$stream = self::createFilteredStream($url, 'w', $filters, $contextOptions);
|
||||
if (!$stream) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = fwrite($stream, $data);
|
||||
fclose($stream);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
95
.archive/StreamWrapper/StreamWrapperInterface.php
Normal file
95
.archive/StreamWrapper/StreamWrapperInterface.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Archive\StreamWrapper;
|
||||
|
||||
/**
|
||||
* Interface für benutzerdefinierte Stream-Wrapper
|
||||
*/
|
||||
interface StreamWrapperInterface
|
||||
{
|
||||
/**
|
||||
* Öffnet einen Stream
|
||||
*/
|
||||
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool;
|
||||
|
||||
/**
|
||||
* Liest Daten aus dem Stream
|
||||
*/
|
||||
public function stream_read(int $count): string|false;
|
||||
|
||||
/**
|
||||
* Schreibt Daten in den Stream
|
||||
*/
|
||||
public function stream_write(string $data): int|false;
|
||||
|
||||
/**
|
||||
* Gibt die aktuelle Position im Stream zurück
|
||||
*/
|
||||
public function stream_tell(): int|false;
|
||||
|
||||
/**
|
||||
* Prüft, ob das Ende des Streams erreicht ist
|
||||
*/
|
||||
public function stream_eof(): bool;
|
||||
|
||||
/**
|
||||
* Setzt die Position im Stream
|
||||
*/
|
||||
public function stream_seek(int $offset, int $whence = SEEK_SET): bool;
|
||||
|
||||
/**
|
||||
* Schließt den Stream
|
||||
*/
|
||||
public function stream_close(): void;
|
||||
|
||||
/**
|
||||
* Gibt Statistiken über den Stream zurück
|
||||
*/
|
||||
public function stream_stat(): array|false;
|
||||
|
||||
/**
|
||||
* Gibt Statistiken über eine URL zurück
|
||||
*/
|
||||
public function url_stat(string $path, int $flags): array|false;
|
||||
|
||||
/**
|
||||
* Erstellt ein Verzeichnis
|
||||
*/
|
||||
public function mkdir(string $path, int $mode, int $options): bool;
|
||||
|
||||
/**
|
||||
* Entfernt ein Verzeichnis
|
||||
*/
|
||||
public function rmdir(string $path, int $options): bool;
|
||||
|
||||
/**
|
||||
* Öffnet ein Verzeichnis zum Lesen
|
||||
*/
|
||||
public function dir_opendir(string $path, int $options): bool;
|
||||
|
||||
/**
|
||||
* Liest den nächsten Eintrag aus einem Verzeichnis
|
||||
*/
|
||||
public function dir_readdir(): string|false;
|
||||
|
||||
/**
|
||||
* Setzt den Verzeichnis-Handle zurück
|
||||
*/
|
||||
public function dir_rewinddir(): bool;
|
||||
|
||||
/**
|
||||
* Schließt ein Verzeichnis-Handle
|
||||
*/
|
||||
public function dir_closedir(): bool;
|
||||
|
||||
/**
|
||||
* Benennt eine Datei um oder verschiebt sie
|
||||
*/
|
||||
public function rename(string $path_from, string $path_to): bool;
|
||||
|
||||
/**
|
||||
* Löscht eine Datei
|
||||
*/
|
||||
public function unlink(string $path): bool;
|
||||
}
|
||||
123
.archive/StreamWrapper/Wrappers/ConfigStreamWrapper.php
Normal file
123
.archive/StreamWrapper/Wrappers/ConfigStreamWrapper.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Archive\StreamWrapper\Wrappers;
|
||||
|
||||
use App\Framework\Config\ConfigManager;
|
||||
use App\Framework\StreamWrapper\Helper\StreamWrapperHelper;
|
||||
use Archive\StreamWrapper\Context\StreamContext;
|
||||
use Archive\StreamWrapper\StreamWrapperInterface;
|
||||
|
||||
/**
|
||||
* Stream-Wrapper für das Config-System
|
||||
* Syntax: config://source/key.path
|
||||
*/
|
||||
class ConfigStreamWrapper implements StreamWrapperInterface
|
||||
{
|
||||
public $context;
|
||||
private string $content = '';
|
||||
private int $position = 0;
|
||||
private string $mode = 'r';
|
||||
private array $parsedUrl = [];
|
||||
private ?StreamContext $streamContext = null;
|
||||
|
||||
private ConfigManager $config;
|
||||
private string $configKey;
|
||||
private string $source;
|
||||
|
||||
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool
|
||||
{
|
||||
$this->streamContext = StreamWrapperHelper::initializeContext($this->context);
|
||||
$this->parsedUrl = StreamWrapperHelper::parseUrl($path);
|
||||
$this->mode = $mode;
|
||||
|
||||
$this->source = $this->parsedUrl['host'] ?: 'default';
|
||||
$this->configKey = $this->parsedUrl['path'];
|
||||
|
||||
// Config-Manager initialisieren
|
||||
$this->config = new ConfigManager();
|
||||
|
||||
// Konfigurationswert laden
|
||||
if (str_contains($mode, 'r') || str_contains($mode, '+')) {
|
||||
$this->content = $this->loadContent($this->configKey);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function stream_read(int $count): string|false
|
||||
{
|
||||
return StreamWrapperHelper::streamRead($this->content, $this->position, $count);
|
||||
}
|
||||
|
||||
public function stream_write(string $data): int|false
|
||||
{
|
||||
return StreamWrapperHelper::streamWrite($this->content, $this->position, $data);
|
||||
}
|
||||
|
||||
public function stream_tell(): int|false
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function stream_eof(): bool
|
||||
{
|
||||
return $this->position >= strlen($this->content);
|
||||
}
|
||||
|
||||
public function stream_seek(int $offset, int $whence = SEEK_SET): bool
|
||||
{
|
||||
return StreamWrapperHelper::streamSeek($this->content, $this->position, $offset, $whence);
|
||||
}
|
||||
|
||||
public function stream_close(): void
|
||||
{
|
||||
$this->content = '';
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
public function stream_stat(): array|false
|
||||
{
|
||||
return StreamWrapperHelper::streamStat($this->content);
|
||||
}
|
||||
|
||||
public function url_stat(string $path, int $flags): array|false
|
||||
{
|
||||
$parsedUrl = StreamWrapperHelper::parseUrl($path);
|
||||
$source = $parsedUrl['host'] ?: 'default';
|
||||
$configKey = $parsedUrl['path'];
|
||||
|
||||
$config = new ConfigManager();
|
||||
|
||||
if (!$config->has($configKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = $config->get($configKey);
|
||||
$content = is_string($value) ? $value : json_encode($value);
|
||||
$size = strlen($content);
|
||||
|
||||
return StreamWrapperHelper::createDefaultStat($size);
|
||||
}
|
||||
|
||||
// Nicht unterstützte Operationen
|
||||
public function mkdir(string $path, int $mode, int $options): bool { return false; }
|
||||
public function rmdir(string $path, int $options): bool { return false; }
|
||||
public function dir_opendir(string $path, int $options): bool { return false; }
|
||||
public function dir_readdir(): string|false { return false; }
|
||||
public function dir_rewinddir(): bool { return false; }
|
||||
public function dir_closedir(): bool { return false; }
|
||||
public function rename(string $path_from, string $path_to): bool { return false; }
|
||||
public function unlink(string $path): bool { return false; }
|
||||
|
||||
private function loadContent(string $path): string
|
||||
{
|
||||
$value = $this->config->get($path);
|
||||
|
||||
if ($value === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return is_string($value) ? $value : json_encode($value);
|
||||
}
|
||||
}
|
||||
205
.archive/StreamWrapper/Wrappers/DatabaseStreamWrapper.php
Normal file
205
.archive/StreamWrapper/Wrappers/DatabaseStreamWrapper.php
Normal file
@@ -0,0 +1,205 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Archive\StreamWrapper\Wrappers;
|
||||
|
||||
use App\Framework\Database\DatabaseManager;
|
||||
use App\Framework\StreamWrapper\Helper\StreamWrapperHelper;
|
||||
use Archive\StreamWrapper\Context\StreamContext;
|
||||
use Archive\StreamWrapper\StreamWrapperInterface;
|
||||
|
||||
/**
|
||||
* Stream-Wrapper für Database-Operationen
|
||||
* Syntax: db://connection/table/operation?params
|
||||
*/
|
||||
class DatabaseStreamWrapper implements StreamWrapperInterface
|
||||
{
|
||||
public $context;
|
||||
private string $content = '';
|
||||
private int $position = 0;
|
||||
private string $mode = 'r';
|
||||
private array $parsedUrl = [];
|
||||
private ?StreamContext $streamContext = null;
|
||||
|
||||
private DatabaseManager $database;
|
||||
private string $connection;
|
||||
private string $table;
|
||||
private string $operation;
|
||||
private array $params = [];
|
||||
|
||||
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool
|
||||
{
|
||||
$this->streamContext = StreamWrapperHelper::initializeContext($this->context);
|
||||
$this->parsedUrl = StreamWrapperHelper::parseUrl($path);
|
||||
$this->mode = $mode;
|
||||
|
||||
$this->connection = $this->parsedUrl['host'] ?: 'default';
|
||||
|
||||
$pathParts = explode('/', $this->parsedUrl['path']);
|
||||
$this->table = $pathParts[0] ?? '';
|
||||
$this->operation = $pathParts[1] ?? 'select';
|
||||
|
||||
// Query-Parameter parsen
|
||||
if ($this->parsedUrl['query']) {
|
||||
parse_str($this->parsedUrl['query'], $this->params);
|
||||
}
|
||||
|
||||
// Database-Manager initialisieren
|
||||
$this->database = new DatabaseManager();
|
||||
|
||||
// Bei Lese-Operationen Query ausführen
|
||||
if (str_contains($mode, 'r') || str_contains($mode, '+')) {
|
||||
$this->content = $this->loadContent($this->operation);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function stream_read(int $count): string|false
|
||||
{
|
||||
return StreamWrapperHelper::streamRead($this->content, $this->position, $count);
|
||||
}
|
||||
|
||||
public function stream_write(string $data): int|false
|
||||
{
|
||||
return StreamWrapperHelper::streamWrite($this->content, $this->position, $data);
|
||||
}
|
||||
|
||||
public function stream_tell(): int|false
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function stream_eof(): bool
|
||||
{
|
||||
return $this->position >= strlen($this->content);
|
||||
}
|
||||
|
||||
public function stream_seek(int $offset, int $whence = SEEK_SET): bool
|
||||
{
|
||||
return StreamWrapperHelper::streamSeek($this->content, $this->position, $offset, $whence);
|
||||
}
|
||||
|
||||
public function stream_close(): void
|
||||
{
|
||||
// Bei Schreib-Modi Operation ausführen
|
||||
if (str_contains($this->mode, 'w') || str_contains($this->mode, 'a') || str_contains($this->mode, '+')) {
|
||||
$this->saveContent($this->operation, $this->content);
|
||||
}
|
||||
|
||||
$this->content = '';
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
public function stream_stat(): array|false
|
||||
{
|
||||
return StreamWrapperHelper::streamStat($this->content);
|
||||
}
|
||||
|
||||
public function url_stat(string $path, int $flags): array|false
|
||||
{
|
||||
return StreamWrapperHelper::createDefaultStat(strlen($this->content));
|
||||
}
|
||||
|
||||
// Nicht unterstützte Operationen
|
||||
public function mkdir(string $path, int $mode, int $options): bool { return false; }
|
||||
public function rmdir(string $path, int $options): bool { return false; }
|
||||
public function dir_opendir(string $path, int $options): bool { return false; }
|
||||
public function dir_readdir(): string|false { return false; }
|
||||
public function dir_rewinddir(): bool { return false; }
|
||||
public function dir_closedir(): bool { return false; }
|
||||
public function rename(string $path_from, string $path_to): bool { return false; }
|
||||
public function unlink(string $path): bool { return false; }
|
||||
|
||||
private function loadContent(string $operation): string
|
||||
{
|
||||
$connection = $this->streamContext?->getOption('db', 'connection', $this->connection);
|
||||
|
||||
$result = match($operation) {
|
||||
'select', 'all' => $this->executeSelect(),
|
||||
'count' => $this->executeCount(),
|
||||
'exists' => $this->executeExists(),
|
||||
default => []
|
||||
};
|
||||
|
||||
return json_encode($result);
|
||||
}
|
||||
|
||||
private function saveContent(string $operation, string $content): bool
|
||||
{
|
||||
$data = json_decode($content, true);
|
||||
|
||||
return match($operation) {
|
||||
'insert' => $this->executeInsert($data),
|
||||
'update' => $this->executeUpdate($data),
|
||||
'delete' => $this->executeDelete($data),
|
||||
'bulk-insert' => $this->executeBulkInsert($data),
|
||||
default => false
|
||||
};
|
||||
}
|
||||
|
||||
private function executeSelect(): array
|
||||
{
|
||||
$query = $this->database->connection($this->connection)->table($this->table);
|
||||
|
||||
foreach ($this->params as $key => $value) {
|
||||
if ($key === 'id') {
|
||||
$query->where('id', $value);
|
||||
} elseif (str_starts_with($key, 'where_')) {
|
||||
$field = substr($key, 6);
|
||||
$query->where($field, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return $query->get()->toArray();
|
||||
}
|
||||
|
||||
private function executeCount(): array
|
||||
{
|
||||
$count = $this->database->connection($this->connection)->table($this->table)->count();
|
||||
return ['count' => $count];
|
||||
}
|
||||
|
||||
private function executeExists(): array
|
||||
{
|
||||
$exists = $this->database->connection($this->connection)->table($this->table);
|
||||
|
||||
if (isset($this->params['id'])) {
|
||||
$exists->where('id', $this->params['id']);
|
||||
}
|
||||
|
||||
return ['exists' => $exists->exists()];
|
||||
}
|
||||
|
||||
private function executeInsert(array $data): bool
|
||||
{
|
||||
return $this->database->connection($this->connection)->table($this->table)->insert($data);
|
||||
}
|
||||
|
||||
private function executeUpdate(array $data): bool
|
||||
{
|
||||
$query = $this->database->connection($this->connection)->table($this->table);
|
||||
|
||||
if (isset($this->params['id'])) {
|
||||
$query->where('id', $this->params['id']);
|
||||
}
|
||||
|
||||
return $query->update($data) > 0;
|
||||
}
|
||||
|
||||
private function executeDelete(array $data): bool
|
||||
{
|
||||
$query = $this->database->connection($this->connection)->table($this->table);
|
||||
|
||||
if (isset($this->params['id'])) {
|
||||
$query->where('id', $this->params['id']);
|
||||
}
|
||||
|
||||
return $query->delete() > 0;
|
||||
}
|
||||
|
||||
private function executeBulkInsert(array $data): bool
|
||||
{
|
||||
return $this->database->connection($this->connection)->table($this->table)->insert($data);
|
||||
}
|
||||
}
|
||||
164
.archive/StreamWrapper/Wrappers/HttpStreamWrapper.php
Normal file
164
.archive/StreamWrapper/Wrappers/HttpStreamWrapper.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Archive\StreamWrapper\Wrappers;
|
||||
|
||||
use App\Framework\HttpClient\HttpClient;
|
||||
use App\Framework\StreamWrapper\Helper\StreamWrapperHelper;
|
||||
use Archive\StreamWrapper\Context\StreamContext;
|
||||
use Archive\StreamWrapper\StreamWrapperInterface;
|
||||
|
||||
/**
|
||||
* Stream-Wrapper für HTTP-Client-Operationen
|
||||
* Syntax: http-client://host/path
|
||||
*/
|
||||
class HttpStreamWrapper implements StreamWrapperInterface
|
||||
{
|
||||
public $context;
|
||||
private string $content = '';
|
||||
private int $position = 0;
|
||||
private string $mode = 'r';
|
||||
private array $parsedUrl = [];
|
||||
private ?StreamContext $streamContext = null;
|
||||
|
||||
private HttpClient $httpClient;
|
||||
private string $host;
|
||||
private string $path;
|
||||
private array $headers = [];
|
||||
private int $timeout = 30;
|
||||
private ?string $auth = null;
|
||||
|
||||
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool
|
||||
{
|
||||
$this->streamContext = StreamWrapperHelper::initializeContext($this->context);
|
||||
$this->parsedUrl = StreamWrapperHelper::parseUrl($path);
|
||||
$this->mode = $mode;
|
||||
|
||||
$this->host = $this->parsedUrl['host'];
|
||||
$this->path = '/' . ltrim($this->parsedUrl['path'], '/');
|
||||
|
||||
// Optionen aus Context lesen
|
||||
if ($this->streamContext) {
|
||||
$this->headers = $this->streamContext->getOption('http-client', 'headers', []);
|
||||
$this->timeout = $this->streamContext->getOption('http-client', 'timeout', 30);
|
||||
$this->auth = $this->streamContext->getOption('http-client', 'auth');
|
||||
}
|
||||
|
||||
// HTTP-Client initialisieren
|
||||
$this->httpClient = new HttpClient();
|
||||
|
||||
// Bei Lese-Modi HTTP-Request ausführen
|
||||
if (str_contains($mode, 'r') || str_contains($mode, '+')) {
|
||||
$this->content = $this->loadContent($this->buildUrl());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function stream_read(int $count): string|false
|
||||
{
|
||||
return StreamWrapperHelper::streamRead($this->content, $this->position, $count);
|
||||
}
|
||||
|
||||
public function stream_write(string $data): int|false
|
||||
{
|
||||
return StreamWrapperHelper::streamWrite($this->content, $this->position, $data);
|
||||
}
|
||||
|
||||
public function stream_tell(): int|false
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function stream_eof(): bool
|
||||
{
|
||||
return $this->position >= strlen($this->content);
|
||||
}
|
||||
|
||||
public function stream_seek(int $offset, int $whence = SEEK_SET): bool
|
||||
{
|
||||
return StreamWrapperHelper::streamSeek($this->content, $this->position, $offset, $whence);
|
||||
}
|
||||
|
||||
public function stream_close(): void
|
||||
{
|
||||
// Bei Schreib-Modi POST/PUT-Request senden
|
||||
if (str_contains($this->mode, 'w') || str_contains($this->mode, 'a') || str_contains($this->mode, '+')) {
|
||||
$this->saveContent($this->buildUrl(), $this->content);
|
||||
}
|
||||
|
||||
$this->content = '';
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
public function stream_stat(): array|false
|
||||
{
|
||||
return StreamWrapperHelper::streamStat($this->content);
|
||||
}
|
||||
|
||||
public function url_stat(string $path, int $flags): array|false
|
||||
{
|
||||
return StreamWrapperHelper::createDefaultStat(strlen($this->content));
|
||||
}
|
||||
|
||||
// Nicht unterstützte Operationen
|
||||
public function mkdir(string $path, int $mode, int $options): bool { return false; }
|
||||
public function rmdir(string $path, int $options): bool { return false; }
|
||||
public function dir_opendir(string $path, int $options): bool { return false; }
|
||||
public function dir_readdir(): string|false { return false; }
|
||||
public function dir_rewinddir(): bool { return false; }
|
||||
public function dir_closedir(): bool { return false; }
|
||||
public function rename(string $path_from, string $path_to): bool { return false; }
|
||||
public function unlink(string $path): bool { return false; }
|
||||
|
||||
private function loadContent(string $url): string
|
||||
{
|
||||
$request = $this->httpClient->get($url);
|
||||
|
||||
if ($this->auth) {
|
||||
$request->withHeader('Authorization', $this->auth);
|
||||
}
|
||||
|
||||
foreach ($this->headers as $name => $value) {
|
||||
$request->withHeader($name, $value);
|
||||
}
|
||||
|
||||
$response = $request->timeout($this->timeout)->send();
|
||||
|
||||
return $response->body();
|
||||
}
|
||||
|
||||
private function saveContent(string $url, string $content): bool
|
||||
{
|
||||
$request = $this->httpClient->post($url, $content);
|
||||
|
||||
if ($this->auth) {
|
||||
$request->withHeader('Authorization', $this->auth);
|
||||
}
|
||||
|
||||
foreach ($this->headers as $name => $value) {
|
||||
$request->withHeader($name, $value);
|
||||
}
|
||||
|
||||
$response = $request->timeout($this->timeout)->send();
|
||||
|
||||
return $response->successful();
|
||||
}
|
||||
|
||||
private function buildUrl(): string
|
||||
{
|
||||
$scheme = 'https'; // Default zu HTTPS
|
||||
|
||||
if ($this->streamContext) {
|
||||
$scheme = $this->streamContext->getOption('http-client', 'scheme', 'https');
|
||||
}
|
||||
|
||||
$url = "{$scheme}://{$this->host}{$this->path}";
|
||||
|
||||
if ($this->parsedUrl['query']) {
|
||||
$url .= '?' . $this->parsedUrl['query'];
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user