Lab 05: Custom Stream Wrappers

Time: 60 minutes | Level: Architect | Docker: docker run -it --rm php:8.3-cli bash

Overview

PHP's stream API is extensible—you can register custom protocols (myproto://) that work transparently with file_get_contents(), fopen(), fwrite(), and all stream functions. This lab builds a memory-backed stream, then a SQLite-backed db:// stream wrapper.


Step 1: Stream Wrapper Interface

A stream wrapper must implement these methods:

stream_open($path, $mode, $options, &$opened_path)  → bool
stream_read($count)                                  → string
stream_write($data)                                  → int
stream_eof()                                         → bool
stream_stat()                                        → array
stream_seek($offset, $whence)                        → bool
stream_tell()                                        → int
stream_flush()                                       → bool
stream_close()                                       → void
url_stat($path, $flags)                              → array
unlink($path)                                        → bool
mkdir($path, $mode, $options)                        → bool
rmdir($path, $options)                               → bool
dir_opendir($path, $options)                         → bool
dir_readdir()                                        → string|false
dir_closedir()                                       → bool
rename($path_from, $path_to)                         → bool

💡 You only need to implement the methods your use case requires. stream_open, stream_read, stream_eof, and stream_stat are the minimum for read-only streams.


Step 2: In-Memory Stream Wrapper

📸 Verified Output:


Step 3: Stream Context


Step 4: SQLite-Backed db:// Stream Wrapper

📸 Verified Output:


Step 5: Stream Filters


Step 6: Directory Listing Support


Step 7: Error Handling & Options

📸 Verified Output:


Step 8: Capstone — Encrypted Config Stream Wrapper

📸 Verified Output:


Summary

Feature
Function
Use Case

Register wrapper

stream_wrapper_register('proto', Class::class)

Add custom proto:// protocol

Check wrappers

stream_get_wrappers()

List all registered protocols

File functions

file_get_contents/file_put_contents/fopen

Work transparently with custom streams

Stream context

stream_context_create(['proto' => [...]])

Pass options to wrapper

Get context options

stream_context_get_options($context)

Read wrapper options

Built-in filters

stream_filter_append($fh, 'zlib.deflate')

Compress/encode on the fly

Remove wrapper

stream_wrapper_unregister('proto')

Clean up or replace

Restore built-in

stream_wrapper_restore('file')

Restore overridden wrappers

Stat support

url_stat()

Enables file_exists(), filesize()

Directory support

dir_opendir/dir_readdir

Enables opendir(), scandir()

Last updated