\Drupflare\StreamHttp HttpsStreamWrapper

An http:// and https:// stream wrapper backed by an injected fetch callable.

WHY THIS EXISTS AT ALL. In a PHP-in-wasm runtime there are no sockets, so overriding an HTTP client's own handler stack fixes that one client and nothing else. Any vendor or contrib code calling file_get_contents('https://...') either fails with "Unable to find the wrapper" or -- on a build whose glue still references a suspension helper the link removed -- dies with a JS ReferenceError that PHP cannot catch. Both failures are per-call and late, which is the worst shape for diagnosis. Shadowing both schemes with this class makes the outcome a documented refusal instead.

WHAT IT DELIBERATELY DOES NOT DO. It does not stream. The whole body is fetched on open and served from memory, because PHP's stream_read() is synchronous and a real streaming read would have to suspend the interpreter mid-call. A build without suspension can only fetch-then-read.

THE FETCH IS INJECTED, never reached for. This package has no host, no service container and no framework; register() takes the callable and the wrapper calls nothing else. See README for the request and reply shape.

REGISTER FROM THE HOST, BEFORE THE FRAMEWORK BOOTS. A stream wrapper has to exist before any code that uses one runs, and a service container is built too late for that.

Summary

Methods
Properties
Constants
__construct
register
unregister
setFetch
fetcher
lastError
stream_open
stream_read
stream_write
stream_eof
stream_tell
stream_seek
stream_stat
url_stat
stream_close
responseMeta
context
SCHEMES
No protected methods found
No protected properties found
No protected constants found
request
fail
normaliseHeaders
stringMap
fetch
lastError
ownFetch
body
position
headers
status
No private constants found

Constant

SCHEMES

SCHEMES = ['http', 'https']

The two schemes this wrapper answers for.

Properties

$context

$context : resource|null

The stream context, set by PHP on the instance it creates.

Type

resource|null —

$fetch

$fetch : ?\Closure

The process-wide fetch, set by register() or setFetch().

Type

Closure|null

$lastError

$lastError : string

The last named refusal, readable after a call returned false.

Type

string

$ownFetch

$ownFetch : ?\Closure

This instance's fetch, when one was injected through the constructor.

Type

Closure|null

$body

$body : string

The fetched body.

Type

string

$position

$position : int

Read offset into $body.

Type

int

$headers

$headers : array

Response headers from the last open, as the fetch reported them.

Type

array<string, string> —

$status

$status : int

HTTP status from the last open.

Type

int

Methods

__construct()

__construct(callable|null  $fetch = null) : mixed

Constructs a wrapper, optionally with its own fetch.

Parameters

callable|null $fetch

A fetch for this instance only. PHP constructs a registered wrapper with no arguments, so the parameter is optional by necessity -- it exists for direct construction in a test or a caller that wants one URL fetched through its own transport.

Returns

mixed —

register()

register(callable  $fetch, array  $schemes = \self::SCHEMES) : array

Registers this wrapper for http and https, replacing anything present.

Parameters

callable $fetch

Receives the request array and returns the reply array; see README for both shapes.

array $schemes

Which schemes to take over. Defaults to both.

Returns

array —

The schemes actually registered, in the order given.

unregister()

unregister(array  $schemes = \self::SCHEMES) : array

Hands the schemes back to whatever PHP had, and forgets the fetch.

Parameters

array $schemes

Which schemes to restore. Defaults to both.

Returns

array —

The schemes actually restored.

setFetch()

setFetch(callable  $fetch) : void

Sets the process-wide fetch without touching the wrapper registry.

Parameters

callable $fetch

Returns

void —

fetcher()

fetcher() : ?\Closure

The process-wide fetch, or NULL when none has been set.

Returns

?\Closure —

lastError()

lastError() : string

The last named refusal this class produced, or the empty string.

Exists because a stream function signals failure with FALSE or 0, which is indistinguishable from a real empty result, and PHP discards the warning text.

Returns

string —

stream_open()

stream_open(string  $path, string  $mode, int  $options, string|null  $opened_path) : bool

Opens a URL by fetching it whole.

Parameters

string $path

The URL, exactly as the caller wrote it.

string $mode

The fopen() mode; anything that is not a read is refused.

int $options

Stream flags; STREAM_REPORT_ERRORS asks for a warning.

string|null $opened_path

Set to the URL when PHP asked for it.

Returns

bool —

TRUE once the body is in memory.

stream_read()

stream_read(int  $count) : string

Serves bytes from the response already held in memory.

There is no incremental read: stream_open() fetched the whole body, because a fetch returns a complete response rather than a socket.

Parameters

int $count

How many bytes PHP is asking for.

Returns

string —

Up to $count bytes, or the empty string at EOF.

stream_write()

stream_write(string  $data) : int

Refuses writes; this wrapper is read-only.

Parameters

string $data

Ignored, but its length is named in the refusal.

Returns

int —

Always 0, which is how PHP learns the write did not happen.

stream_eof()

stream_eof() : bool

Reports whether the read position has reached the end of the body.

Returns

bool —

TRUE once every byte has been read.

stream_tell()

stream_tell() : int

Reports the current read position.

Returns

int —

Offset in bytes from the start of the body.

stream_seek()

stream_seek(int  $offset, int  $whence = \Drupflare\StreamHttp\SEEK_SET) : bool

Moves the read position, refusing to land outside the body.

Parameters

int $offset

Offset to seek to, interpreted according to $whence.

int $whence

One of SEEK_SET, SEEK_CUR or SEEK_END.

Returns

bool —

TRUE on success, FALSE if the target is out of range.

stream_stat()

stream_stat() : array

Describes the open stream for fstat() and filesize().

Returns

array —

A stat array; only size and mode are meaningful here.

url_stat()

url_stat(string  $path, int  $flags) : array|false

Describes a URL without opening it, for file_exists() and friends.

Parameters

string $path

The URL being stat'd.

int $flags

Stat flags from PHP; not used, since no request is made.

Returns

array|false —

A stat array claiming the resource exists with an unknown size.

stream_close()

stream_close() : void

Releases the buffered body.

Returns

void —

responseMeta()

responseMeta() : array

The status and headers of the response this instance is serving.

Reachable from a file handle as stream_get_meta_data($fh)['wrapper_data']->responseMeta(), because PHP puts the wrapper instance itself in wrapper_data for a userland wrapper. $http_response_header is populated only by PHP's own http wrapper and cannot be set from here.

NOT called stream_metadata: that name belongs to the streamWrapper prototype, where it is stream_metadata(string $path, int $option, mixed $value): bool and PHP invokes it for touch(), chmod() and chown() on the URL. A 0-argument method under that name is an ArgumentCountError waiting for the first caller who touches an http:// path.

Returns

array —

status and headers.

request()

request(string  $path) : array

Builds the request array from the URL and the stream context.

Parameters

string $path

The URL.

Returns

array —

The request the fetch receives.

fail()

fail(int  $options, string  $message) : bool

Records the reason, emits a warning unless the caller asked for silence, and fails the call.

Parameters

int $options

Stream flags from PHP.

string $message

The named reason.

Returns

bool —

Always FALSE.

normaliseHeaders()

normaliseHeaders(string|array  $header) : array

Turns PHP's header option -- a string or a list -- into a name => value map.

Parameters

string|array $header

Either CRLF-joined lines or a list of them.

Returns

array —

Header name to value, both trimmed.

stringMap()

stringMap(mixed  $headers) : array

Narrows whatever the fetch reported as headers to a string map.

Parameters

mixed $headers

The reply's headers member.

Returns

array —

Header name to value; anything not stringable is dropped rather than cast.