Signatur
Beschreibung
stream_wrapper_register() ermöglicht es, eigene Stream-Wrapper zu implementieren, indem eine PHP-Klasse als Handler für ein selbst gewähltes Protokoll (z. B. myproto://) registriert wird. Danach können alle Standard-Datei- und Stream-Funktionen wie fopen(), file_get_contents(), opendir() oder copy() mit dem benutzerdefinierten Protokoll verwendet werden.
Die zu registrierende Klasse muss eine Reihe von Methoden implementieren, die das Stream-Verhalten definieren. Dazu gehören unter anderem stream_open(), stream_read(), stream_write(), stream_eof() und stream_close(). Methoden für Verzeichnisoperationen (dir_opendir(), dir_readdir() etc.) sowie für Metadaten (url_stat()) sind optional, aber nötig, wenn der Wrapper vollständig funktionieren soll.
Typische Anwendungsfälle sind: virtuelle Dateisysteme (z. B. In-Memory-Speicher, Datenbank-Streams), transparente Verschlüsselung oder Kompression von Streams, sowie das Einbinden externer Datenquellen (APIs, Cloud-Speicher) über eine einheitliche Datei-Schnittstelle.
Wenn ein Protokoll bereits registriert ist, schlägt die Funktion fehl. Mit stream_wrapper_unregister() und stream_wrapper_restore() lassen sich bestehende Wrapper temporär ersetzen oder wiederherstellen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $protocol Pflicht | string | Der Name des Protokolls ohne ://, z. B. myproto. Danach kann myproto://pfad in Datei-Funktionen genutzt werden. |
|
| $class Pflicht | string | Der vollqualifizierte Name der Klasse (inkl. Namespace), die den Stream-Wrapper implementiert. Die Klasse muss die nötigen Stream-Methoden bereitstellen. | |
| $flags | int | 0 | Optionale Flags. Derzeit nur STREAM_IS_URL (Wert: 1), das angibt, dass der Wrapper ein URL-basiertes Protokoll darstellt und damit von allow_url_fopen / allow_url_include beeinflusst wird. |
Rückgabewert
true zurück, wenn der Wrapper erfolgreich registriert wurde. Gibt false zurück, wenn das Protokoll bereits registriert ist oder die Registrierung anderweitig fehlschlägt.Beispiele
Einfacher In-Memory-Stream-Wrapper
<?php
class MemoryStreamWrapper
{
protected static array $storage = [];
protected string $path;
protected int $position = 0;
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool
{
$this->path = substr($path, strlen('mem://'));
if (!isset(self::$storage[$this->path])) {
self::$storage[$this->path] = '';
}
$this->position = ($mode === 'a') ? strlen(self::$storage[$this->path]) : 0;
return true;
}
public function stream_read(int $count): string
{
$data = substr(self::$storage[$this->path], $this->position, $count);
$this->position += strlen($data);
return $data;
}
public function stream_write(string $data): int
{
$before = substr(self::$storage[$this->path], 0, $this->position);
$after = substr(self::$storage[$this->path], $this->position + strlen($data));
self::$storage[$this->path] = $before . $data . $after;
$this->position += strlen($data);
return strlen($data);
}
public function stream_eof(): bool
{
return $this->position >= strlen(self::$storage[$this->path]);
}
public function stream_tell(): int
{
return $this->position;
}
public function stream_close(): void {}
}
// Wrapper registrieren
stream_wrapper_register('mem', MemoryStreamWrapper::class);
// Normales fopen/fwrite/fread über das eigene Protokoll
$handle = fopen('mem://testdatei', 'w+');
fwrite($handle, 'Hallo, Welt!');
rewind($handle);
echo fread($handle, 1024);
fclose($handle);
Bestehenden Wrapper temporär ersetzen (z. B. für Tests)
<?php
class LoggingFileWrapper
{
public $context;
private $handle;
public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool
{
// Originalen file://-Wrapper wiederherstellen, damit wir wirklich öffnen können
stream_wrapper_restore('file');
$realPath = substr($path, strlen('file://'));
$this->handle = fopen($realPath, $mode);
// Wieder durch unseren eigenen Wrapper ersetzen
stream_wrapper_unregister('file');
stream_wrapper_register('file', self::class);
error_log("[LOG] Datei geöffnet: $realPath (Modus: $mode)");
return $this->handle !== false;
}
public function stream_read(int $count): string
{
return fread($this->handle, $count);
}
public function stream_eof(): bool
{
return feof($this->handle);
}
public function stream_close(): void
{
fclose($this->handle);
}
}
// Standard-file://-Wrapper durch eigenen ersetzen
stream_wrapper_unregister('file');
$result = stream_wrapper_register('file', LoggingFileWrapper::class);
var_dump($result);
// Originalen Wrapper wiederherstellen
stream_wrapper_restore('file');
echo "file://-Wrapper wiederhergestellt\n";
// Wichtig · Fallstricke
Sicherheitshinweis: Wenn der Wrapper mit dem Flag STREAM_IS_URL registriert wird, unterliegt er den PHP-Einstellungen allow_url_fopen und allow_url_include. Ohne dieses Flag sind diese Einstellungen ohne Wirkung auf den Wrapper.
Pflichtmethoden: Die Wrapper-Klasse benötigt keine formale Schnittstelle (implements), PHP prüft jedoch zur Laufzeit, ob die aufgerufene Methode existiert. Fehlt eine Methode, gibt PHP eine Warnung aus. Es empfiehlt sich, alle relevanten Methoden zu implementieren und auf Vollständigkeit anhand der streamWrapper-Prototypklasse zu prüfen.
Kein Namespace-Problem: Der Klassenname muss vollqualifiziert angegeben werden, wenn die Klasse in einem Namespace liegt, z. B. stream_wrapper_register('myproto', 'App\Stream\MyWrapper').
Fallstrick: Das Ersetzen des eingebauten file://-Wrappers ist möglich, aber riskant — bei einem Fehler im eigenen Wrapper können alle Dateioperationen in PHP fehlschlagen. Immer stream_wrapper_restore() in einem finally-Block aufrufen.