Short question:
The stream_cast method has thrown me for a loop. The method does not take any parameters and is invoked by stream_select which has lots of arguements - so I don't know what I'm supposed to return for it and where to get the options.... I figured I'd ask here if anyone else knows what they are.

-----Long explanation------
I've been hacking about with Google's App Engine and Joomla. One limitation I ran into is that App Engine does not allow for the PHP application running on the website to change/modify/add files to a running application. In essence, from within a PHP application running on App Engine[or any other language for that matter] we only have "read" access to the file system.

Benefits of this are of course, security[no exploits can be used to modify php scripts on the website] - performance[static resources such as javascript, images, css, etc can be optimized for delivery] and caching[since the files are only modified when new code is 'deployed' APC does not need to check the file change dates when caching PHP code - the deployment process can force a flush of the cache when needed].

App Engine does allow for accessing files from Google Cloud Storage buckets - and they even provide a stream wrapper so any gs://bucketname paths can be treated like files. You can even allow for execution of PHP code from Cloud Storage....but then your no longer secure from exploits which try to modify PHP files on the server!]

For my own custom code, it's easy enough to build paths using different paths. IE when checking to include php scripts with file_exists I can use the local file: path - and when saving or retrieiving image file uploads I can use the gs: file path. But to get someone else's code working that way is a non-trivial chunk of work - and it struck me that instead I can let PHP do things "magically". So I created my own stream wrapper:https://github.com/garyamort/Stream-Morpher <https://github.com/garyamort/Stream-Morpher>

It can use a set of string manipulation rules to convert one path to another, ie ggsm://websitepath/media/image.png would become gs://gmimagebucket/images/image.png and a default rule at the end can swap ggsm://websitepath/anythingelse to file:///appinstancepath/anythingelse

For the most part, it's been fairly obvious how to map to method calls. Most file modifications will only be made after a call to fopen, so stream_open is the primary method:
        $this->streamHandle = false;
        if ($this->processPathname($pathname, $mode))
        {
if ($this->checkRecursiveRules($this->path, STREAM_URL_STAT_QUIET))
            {
                // Path translated to itself recursively, abort, abort
                $this->path = null;
                return false;
            }
             $use_include_path = $options & STREAM_USE_PATH;

$handle = fopen($this->path->truePath, $mode, $use_include_path);
            if (is_resource($handle))
            {
                $this->streamHandle = $handle;
                return true;
            }

        }
        return false;


That code converts the pathname to the "true" pathname, makes sure that whatever stream it morphed into is not assigned to the stream morpher itself[otherwise you get ugly recursion calls as it tries to keep morphing it over and over], and finally simply calls fopen again to pass the file open on to the real processor.

One oddity I found is that the return from stream_open is irrelevant, I originally tried returning the handle opened however future calls to read and write would use my morpher object, not the handle - so I had to save the "true" handle in the morpher object and create a proxy call for every method. Some of them, such as write, are simple:
    function stream_write($data)
    {
        return fwrite($this->streamHandle, $data);
    }


Some them are ugly due to having to check lots of flags, such as set_option:
    public function stream_set_option ( $option , $arg1 , $arg2 )
    {
        if ($option & STREAM_OPTION_BLOCKING)
        {
            return stream_set_blocking($arg1, $arg2);
        }


        if ($option & STREAM_OPTION_READ_TIMEOUT)
        {
            return stream_set_timeout($arg1, $arg2);
        }


        if ($option & STREAM_OPTION_WRITE_BUFFER)
        {
            return stream_set_write_buffer($arg1, $arg2);
        }

        return false;

    }


But stream_cast has thrown me for a loop. The method does not take any parameters and is invoked by stream_select which has lots of arguements - so I don't know what I'm supposed to return for it and where to get the options.... I figured I'd ask here if anyone else knows what they are.


I'm still hacking around a bit on the driver to use it for other things. For example, since the mode a file is opened with is known, it would be possible to use the regular file stream wrapper for files opened in read mode, but use an ftp wrapper for files opened in write mode.

Or for things like logfile writing, since their usually a sequence of lines appended to a file, modify log file paths so writes get sent to syslog of phperror instead.

--Gary
_______________________________________________
New York PHP User Group Community Talk Mailing List
http://lists.nyphp.org/mailman/listinfo/talk

http://www.nyphp.org/show-participation

Reply via email to