Zum Inhalt springen

PHP Streams

Kommen wir zu einem etwas abstrakteren Thema, dem wir uns hier möglichst einfach nähern wollen. Es sind eigentlich nur die Grundkentnisse über Klassen und Funktionen notwendig.

Nehmen wir mal an, dass wir über den Stream „var://foo“ Daten in $GLOBALS[„foo“] lesen/schreiben möchten.

Der Stream wird wie folgt registriert:

<?php

stream_wrapper_register("var", "VariableStream")
    or die("Failed to register protocol");

In dem Fall erstellen wir also das Protokol „myglobal://“ und verweisen dieses auf die Klasse myglobalStream. Dort muss auch die Implementierung erfolgen.

Tasten wir uns mit einem Beispiel daran, wie die Klasse aussehen kann.

<?php

class myglobalStream {
    var $position;
    var $varname;

    /* Methode wird immer aufgerufen, sobald der Wrapper für den Stream intialisiert wird. 
    z.B. fopen() oder file_get_contents() */
    function stream_open($path, $mode, $options, &$opened_path)
    {    
        /* Wir verarbeiten nun die Url. Da wir z.B. var://test in $GLOBAL["test"] schreiben möchten, 
        schreiben wir den Host "test" in $this->varname; */
        $url = parse_url($path);
        $this->varname = $url["host"];
        $this->position = 0;

        return true;
    }
    
    /* Methode wird z.B. bei fread() und fgets() aufgerufen. Liefert also sozusagen 
    Inhalt des Streams bzw. unsrerer vermeintlichen Datei. */
    function stream_read($count)
    {    
        /* Wir geben nun von der aktuellen Position des Streams bis zu $count zurück */
        $ret = substr($GLOBALS[$this->varname], $this->position, $count);
        $this->position += strlen($ret);    //read/write position unseres Streams anpassen (drann denken)
        return $ret;
    }
    
    /* Methode wird bei fwrite() verwendet */
    function stream_write($data)
    {    
        /* Ansatz: In $left die Daten links von der Position speichern, in $right die
        Daten rechts von unserer Position, und am Ende $GLOBALS[$this->varname] zusammensetzen */
        $left = substr($GLOBALS[$this->varname], 0, $this->position);
        $right = substr($GLOBALS[$this->varname], $this->position + strlen($data));
        $GLOBALS[$this->varname] = $left . $data . $right;
        $this->position += strlen($data);
        return strlen($data);
    }
    
    /* Methode liefert aktuelle Position. Wird bei fseek() aufgerufen. */
    function stream_tell()
    {
        return $this->position;
    }

    /* Methode liefert boolean ob EOF erreicht. Aufruf bei feof() */
    function stream_eof()
    {
        return $this->position >= strlen($GLOBALS[$this->varname]);
    }

    /* Methode zum Suchen einer Position. Setzt $this->position. Aufruf bei fseek() */
    function stream_seek($offset, $whence)
    {
        switch ($whence) {
            //Position entspricht $offset bytes
            case SEEK_SET:
                if ($offset < strlen($GLOBALS[$this->varname]) && $offset >= 0) {
                     $this->position = $offset;
                     return true;
                } else {
                     return false;
                }
                break;

            //Position entspricht aktuellem Stand + $offset bytes
            case SEEK_CUR:
                if ($offset >= 0) {
                     $this->position += $offset;
                     return true;
                } else {
                     return false;
                }
                break;

            //Position entspricht eof + $offset
            case SEEK_END:
                if (strlen($GLOBALS[$this->varname]) + $offset >= 0) {
                     $this->position = strlen($GLOBALS[$this->varname]) + $offset;
                     return true;
                } else {
                     return false;
                }
                break;

            default:
                return false;
        }
    }

    /* Methode setzt Metadaten. Aufruf bei touch(), chmod(), chown(), chgrp() */
    function stream_metadata($path, $option, $var) 
    {
        /* Mögliche Werte für $option:
        STREAM_META_TOUCH: touch() - $var liefert Array mit zwei Argumenten der touch() Funktion
        STREAM_META_OWNER_NAME: chown() - $var liefert Name des Besitzers als String
        STREAM_META_OWNER: chown() - $var liefert Besitzer als int
        STREAM_META_GROUP_NAME: chown() - $var liefert Name der Gruppe als String
        STREAM_META_GROUP: $chgrp() - $var liefert Gruppe als int
        STREAM_META_ACCESS: $chmod - $var liefert chmod() Argument als int
        */
        
        /* Beispiel-Implementierung für STREAM_META_TOUCH */
        if($option == STREAM_META_TOUCH) {
            $url = parse_url($path);
            $varname = $url["host"];
            if(!isset($GLOBALS[$varname])) {
                $GLOBALS[$varname] = '';
            }
            return true;
        }
        return false;
    }
}

Die Klasse ist (um eigene erklärende Kommentare (alle) ergänzt) übernommen aus dem PHP Manual Copyright © 1997 – 2016 by the PHP Documentation Group (Lizenz: Creative Commons Attribution 3.0).

 

Kommentare sind geschlossen, aber Trackbacks und Pingbacks sind möglich.