Welcome! Log In Create A New Profile

Advanced

[PHP] How to escape a local path so fopen() doesn't consider it a URL?

Posted by Jesse Schalken 
fopen() supports being passed a URL for use with other "stream wrappers"
besides the local file system.

If I have a local file path that happens to look like a URL (for example, a
file called "data:foo"), what is the correct escaping or manipulation that
I have to do so that fopen() doesn't consider it a URL and it gets passed
verbatim to fopen() in C?

Thanks
On Tue, Dec 20, 2016 at 1:58 AM, Jesse Schalken <[email protected]>
wrote:
>
> If I have a local file path that happens to look like a URL (for example, a
> file called "data:foo"), what is the correct escaping or manipulation that
> I have to do so that fopen() doesn't consider it a URL and it gets passed
> verbatim to fopen() in C?
>

I believe you can use the backslash (\), as is noted in the documentation
related to the use of Window's paths that utilize the backslash instead of
the forward slash. That said, I also thought that the path had to begin
with a valid scheme (e.g., "protocol://"), so I'm not sure "data:foo" would
prove troublesome (but I didn't have time to test anything before hitting
the hay.)

Happy coding!

Adam
On Tue, Dec 20, 2016 at 2:06 AM, Adam Jon Richardson <[email protected]>
wrote:

> On Tue, Dec 20, 2016 at 1:58 AM, Jesse Schalken <[email protected]>
> wrote:
>>
>> If I have a local file path that happens to look like a URL (for example,
>> a
>> file called "data:foo"), what is the correct escaping or manipulation that
>> I have to do so that fopen() doesn't consider it a URL and it gets passed
>> verbatim to fopen() in C?
>>
>
> I believe you can use the backslash (\), as is noted in the documentation
> related to the use of Window's paths that utilize the backslash instead of
> the forward slash. That said, I also thought that the path had to begin
> with a valid scheme (e.g., "protocol://"), so I'm not sure "data:foo" would
> prove troublesome (but I didn't have time to test anything before hitting
> the hay.)
>

And, to clarify, I should have said, "I also thought that the path had to
begin a valid URL (in contrast to merely forming a URI, which doesn't have
to show the means of retrieval), ...

Tired, I am.

Adam
On 20.12.2016 at 07:58, Jesse Schalken wrote:

> fopen() supports being passed a URL for use with other "stream wrappers"
> besides the local file system.
>
> If I have a local file path that happens to look like a URL (for example, a
> file called "data:foo"), what is the correct escaping or manipulation that
> I have to do so that fopen() doesn't consider it a URL and it gets passed
> verbatim to fopen() in C?

Use an absolute path, or at least some qualification, such as
`./data:foo`. That is sufficient to tell PHP that you're not trying to
access a data URL. Whether it works, depends on the filesystem (doesn't
work on NTFS for instance, where colon is a reserved character).

--
Christoph M. Becker


--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
On Wed, Dec 21, 2016 at 12:06 AM, Christoph M. Becker <[email protected]>
wrote:

> On 20.12.2016 at 07:58, Jesse Schalken wrote:
>
> Use an absolute path, or at least some qualification, such as
> `./data:foo`. That is sufficient to tell PHP that you're not trying to
> access a data URL.
>
>
Thanks. I managed to find the responsible functions in PHP
(php_stream_locate_url_wrapper) and HHVM (Stream::getWrapperProtocol) and
came up with this, which seems to work:

/**
* Make sure a path will be treated as a local file path and not as a URL
* for some other stream wrapper.
*/
function make_path_local(string $path): string {
// Look at php_stream_locate_url_wrapper() in PHP source
// or Stream::getWrapperProtocol() in HHVM
//
// Basically, any path that matches this regex is likely to be considered
a
// URL for another stream wrapper.
//
// Handily, a path that matches this regex is guaranteed not to be an
// absolute path on POSIX or Windows, so if it matches we can safely
// force it not to match by prefixing it with ./ on POSIX and .\ on
// Windows.

if (\preg_match('/^([a-zA-Z+\\-.]+:\\/\\/|data:|zlib:)/Ds', $path))
return '.' . \DIRECTORY_SEPARATOR . $path;

return $path;
}
Whoops, the regex should include 0-9 in the character range (the test in
the C code is isalnum() not isalpha()):

function make_path_local(string $path): string {
if (\preg_match('/^([a-zA-Z0-9+\\-.]+:\\/\\/|data:|zlib:)/Ds', $path))
return '.' . \DIRECTORY_SEPARATOR . $path;
return $path;
}

Whoops again, the test should be for a scheme of 2 or more characters, not
1 or more (so it doesn't match C://foo):

function make_path_local(string $path): string {
if (\preg_match('/^([a-zA-Z0-9+\\-.]{2,}:\\/\\/|data:|zlib:)/Ds', $path))
return '.' . \DIRECTORY_SEPARATOR . $path;
return $path;
}

Sorry, only registered users may post in this forum.

Click here to login