# [PATCH] adding stream wrappers to include_path

- Thread: https://externals.io/message/36031
- Original archive: https://news-web.php.net/php.internals/36031
- Started by Gregory Beaver on 2008-03-07T05:06:23+00:00
- Messages: 2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #36031 — Gregory Beaver — 2008-03-07T05:06:23+00:00

URL: https://externals.io/message/36031#36031

Hi,

I found some time to whip up a quick patch against 5.3.

This patch allows adding stream wrappers to include_path on both windows
and unix.  This means one can set an include_path to
".:/usr/local/lib/php:phar:///path/to/ZF.phar/lib" or the windows
equivalent ".;C:\php5;phar://C:/php5/ZF.phar/lib"  Any stream wrapper,
userspace or built-in, will work as long as it satisfies security
constraints and implements url_stat(), stream_open(), `stat()`, and read()
or the C equivalents.

In other words, this test I already had created for pecl/phar works:

<?php
$fname = dirname(__FILE__) . '/tempmanifest1.phar.php';
$a = new Phar($fname);
$a['file1.php'] = 'file1.php
';
$a['test/file1.php'] = 'test/file1.php
';
unset($a);
set_include_path('.' . `PATH_SEPARATOR` . 'phar://' . $fname);
include 'file1.php';
set_include_path('.' . `PATH_SEPARATOR` . 'phar://' . $fname . '/test');
include 'file1.php';
include 'file2.php';
?>
===DONE===

with output:

--EXPECTF--
file1.php
test/file1.php

Warning: include(file2.php): failed to open stream: No such file or
directory in %sinclude_path.php on line %d

Warning: include(): Failed opening 'file2.php' for inclusion
(include_path='.:phar:///home/cellog/workspace/php5/ext/phar/tests/tempmanifest1.phar.php/test')
in %sinclude_path.php on line %d
===DONE===

The internals of the patch borrows logic from
php_stream_locate_url_wrapper to quickly detect a stream wrapper.  It
excludes the data stream wrapper out of hand as this has no business in
include_path for obvious reasons.  It also fully supports disabled
allow_url_fopen/allow_url_include by passing STREAM_OPEN_FOR_INCLUDE to
the eventual php_stream_locate_url_wrapper call.  The most important
part of the patch is the way it finds a stream wrapper on unix.  Because
 `PATH_SEPARATOR` is ":" on unix, the include_path scanner will stop after
"phar" in the sample include_paths above.  The new scanner checks for a
valid stream wrapper (a sequence of alpha-numeric, +, -, or . characters
followed by ://) and seeks to the next : if found.

My primary concern with the patch is performance.  I'm certain it can be
tweaked.  I extracted the call to url_stat from php_stream_stat(), which
removes the possibility of hitting stat cache but eliminates the
redundant call to php_stream_locate_url_wrapper.  If it is indeed faster
to use php_stream_stat(), that's one easy optimization.

In any case, it adds an additional scan of each include_path component
to detect stream wrappers, which is called on each include.  This may be
the biggest candidate for optimization, as a simple cache of paths with
stream wrapper/not could be created whenever include_path is set and
used instead of scanning the string every time.

By the way, there may be some unsafe scans in
php_stream_locate_url_wrapper, specifically line 1531 in PHP_5_3:

    if ((*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) ||
!memcmp("data", path, 4))) {

It doesn't seem to verify that path is at least 4 or there is at least 2
extra characters after p before checking for "//" or "data"

Thanks,
Greg

---

## #36230 — Dmitry Stogov — 2008-03-21T07:44:35+00:00

URL: https://externals.io/message/36031#36230 · In reply to: #36031

Hi Greg,

At least your patch is incomplete.
Even it handles stream wrappers in include(), include_once() it doesn't 
handle them in `fopen()` and some other functions.

In general I like the idea, so I'll look how to extend the support.

Thanks. Dmitry.

Gregory Beaver wrote:
> Hi,
> 
> I found some time to whip up a quick patch against 5.3.
> 
> This patch allows adding stream wrappers to include_path on both windows
> and unix.  This means one can set an include_path to
> ".:/usr/local/lib/php:phar:///path/to/ZF.phar/lib" or the windows
> equivalent ".;C:\php5;phar://C:/php5/ZF.phar/lib"  Any stream wrapper,
> userspace or built-in, will work as long as it satisfies security
> constraints and implements url_stat(), stream_open(), `stat()`, and read()
> or the C equivalents.
> 
> In other words, this test I already had created for pecl/phar works:
> 
> <?php
> $fname = dirname(__FILE__) . '/tempmanifest1.phar.php';
> $a = new Phar($fname);
> $a['file1.php'] = 'file1.php
> ';
> $a['test/file1.php'] = 'test/file1.php
> ';
> unset($a);
> set_include_path('.' . `PATH_SEPARATOR` . 'phar://' . $fname);
> include 'file1.php';
> set_include_path('.' . `PATH_SEPARATOR` . 'phar://' . $fname . '/test');
> include 'file1.php';
> include 'file2.php';
> ?>
> ===DONE===
> 
> with output:
> 
> --EXPECTF--
> file1.php
> test/file1.php
> 
> Warning: include(file2.php): failed to open stream: No such file or
> directory in %sinclude_path.php on line %d
> 
> Warning: include(): Failed opening 'file2.php' for inclusion
> (include_path='.:phar:///home/cellog/workspace/php5/ext/phar/tests/tempmanifest1.phar.php/test')
> in %sinclude_path.php on line %d
> ===DONE===
> 
> The internals of the patch borrows logic from
> php_stream_locate_url_wrapper to quickly detect a stream wrapper.  It
> excludes the data stream wrapper out of hand as this has no business in
> include_path for obvious reasons.  It also fully supports disabled
> allow_url_fopen/allow_url_include by passing STREAM_OPEN_FOR_INCLUDE to
> the eventual php_stream_locate_url_wrapper call.  The most important
> part of the patch is the way it finds a stream wrapper on unix.  Because
> `PATH_SEPARATOR` is ":" on unix, the include_path scanner will stop after
> "phar" in the sample include_paths above.  The new scanner checks for a
> valid stream wrapper (a sequence of alpha-numeric, +, -, or . characters
> followed by ://) and seeks to the next : if found.
> 
> My primary concern with the patch is performance.  I'm certain it can be
> tweaked.  I extracted the call to url_stat from php_stream_stat(), which
> removes the possibility of hitting stat cache but eliminates the
> redundant call to php_stream_locate_url_wrapper.  If it is indeed faster
> to use php_stream_stat(), that's one easy optimization.
> 
> In any case, it adds an additional scan of each include_path component
> to detect stream wrappers, which is called on each include.  This may be
> the biggest candidate for optimization, as a simple cache of paths with
> stream wrapper/not could be created whenever include_path is set and
> used instead of scanning the string every time.
> 
> By the way, there may be some unsafe scans in
> php_stream_locate_url_wrapper, specifically line 1531 in PHP_5_3:
> 
>     if ((*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) ||
> !memcmp("data", path, 4))) {
> 
> It doesn't seem to verify that path is at least 4 or there is at least 2
> extra characters after p before checking for "//" or "data"
> 
> Thanks,
> Greg
