rfc:glob_streamwrapper_support
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rfc:glob_streamwrapper_support [2022/08/20 22:47] – timint | rfc:glob_streamwrapper_support [2022/10/24 13:50] (current) – timint | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PHP RFC: StreamWrapper Support for glob() ====== | ====== PHP RFC: StreamWrapper Support for glob() ====== | ||
+ | |||
* Version: 1.0 | * Version: 1.0 | ||
* Date: 2022-08-15 | * Date: 2022-08-15 | ||
* Author: Timmy Almroth, timmy.almroth@gmail.com | * Author: Timmy Almroth, timmy.almroth@gmail.com | ||
- | * Status: | + | * Status: |
* First Published at: https:// | * First Published at: https:// | ||
+ | |||
+ | **Status: Aborted** | ||
+ | |||
+ | **Comment: This RFC has been aborted as no convenient solution or workaround was found for Alpine platform. / Timmy** | ||
===== Introduction ===== | ===== Introduction ===== | ||
Line 10: | Line 15: | ||
Workarounds can be a struggle. Some projects may rely on regular expressions which are different from globbing. Some may attempt the use of fnmatch() which does not support all the features of glob() like brace expansions. | Workarounds can be a struggle. Some projects may rely on regular expressions which are different from globbing. Some may attempt the use of fnmatch() which does not support all the features of glob() like brace expansions. | ||
- | |||
- | Example of a workaround using opendir and regex: | ||
- | |||
- | < | ||
- | function glob_streamwrapper($glob, | ||
- | |||
- | // Unixify paths | ||
- | $glob = str_replace(' | ||
- | |||
- | // Set basedir and remains | ||
- | $basedir = ''; | ||
- | $remains = $glob; | ||
- | for ($i=0; $i< | ||
- | if (in_array($glob[$i], | ||
- | if ($glob[$i] == '/' | ||
- | @list($basedir, | ||
- | } | ||
- | } | ||
- | |||
- | // Halt if basedir does not exist | ||
- | if ($basedir && !is_dir($basedir)) { | ||
- | return []; | ||
- | } | ||
- | |||
- | // If there are no pattern remains, return base directory if valid | ||
- | if (!$remains) { | ||
- | if (is_dir($basedir)) { | ||
- | return [$basedir]; | ||
- | } else { | ||
- | return []; | ||
- | } | ||
- | } | ||
- | |||
- | // Extract pattern for current directory | ||
- | if (($pos = strpos($remains, | ||
- | list($pattern, | ||
- | } else { | ||
- | list($pattern, | ||
- | } | ||
- | |||
- | // fnmatch() doesn' | ||
- | $regex = strtr($pattern, | ||
- | ' | ||
- | ' | ||
- | ' | ||
- | ' | ||
- | ' | ||
- | ' | ||
- | ' | ||
- | ' | ||
- | ' | ||
- | ' | ||
- | '?' | ||
- | ]); | ||
- | |||
- | if ($flags & GLOB_BRACE) { | ||
- | |||
- | $regex = preg_replace_callback('# | ||
- | return strtr($matches[0], | ||
- | }, $regex); | ||
- | |||
- | } else { | ||
- | $regex = strtr($regex, | ||
- | } | ||
- | |||
- | $regex = '# | ||
- | |||
- | $folders = []; | ||
- | $files = []; | ||
- | |||
- | // Open directory | ||
- | $dh = opendir($basedir ? $basedir : ' | ||
- | |||
- | // Step through each file in directory | ||
- | while ($file = readdir($dh)) { | ||
- | if (in_array($file, | ||
- | |||
- | // Prepend path | ||
- | $file = $basedir . $file; | ||
- | $filetype = filetype($file); | ||
- | |||
- | if ($filetype == ' | ||
- | |||
- | // Collect a matching folder | ||
- | if (preg_match($regex, | ||
- | if ($remains) { | ||
- | $folders = array_merge($folders, | ||
- | } else { | ||
- | $folders[] = $file .'/'; | ||
- | } | ||
- | } | ||
- | |||
- | } else if ($filetype == ' | ||
- | |||
- | // Skip if not a directory during GLOB_ONLYDIR | ||
- | if ($flags & GLOB_ONLYDIR) continue; | ||
- | |||
- | // Collect a matching file | ||
- | if (preg_match($regex, | ||
- | $files[] = $file; | ||
- | } | ||
- | } | ||
- | } | ||
- | |||
- | // Merge folders and files into one and same result | ||
- | $results = array_merge($folders, | ||
- | |||
- | return $results; | ||
- | } | ||
- | </ | ||
===== Proposal ===== | ===== Proposal ===== | ||
Line 125: | Line 20: | ||
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
- | No backwards | + | Fully backwards |
===== Proposed PHP Version(s) ===== | ===== Proposed PHP Version(s) ===== | ||
Line 133: | Line 28: | ||
The glob opendir implementation would be replaced with a wrapper supporting streams. It is possible to produce a fallback condition leaving local file system operations as is. But testing so far have not shown any performance anomalies or incompatibilities. So the intention is to also use the new wrapper for local filesystem operations. | The glob opendir implementation would be replaced with a wrapper supporting streams. It is possible to produce a fallback condition leaving local file system operations as is. But testing so far have not shown any performance anomalies or incompatibilities. So the intention is to also use the new wrapper for local filesystem operations. | ||
- | C open_basedir will be removed as obsolete. | + | open_basedir |
+ | |||
+ | If a StreamWrapper supports listing contents, it will supported by glob(). There will be edge cases where a streamwrapper is not intended to or does not support listing contents of a resource, e.g. http:, data:, compress.zlib: | ||
+ | |||
+ | Which streamwrapper that can be used with glob() is not a limitation of glob(), but the streamwrapper itself. PHP's current ftp streamwrapper might not support listing files in a directory, but a 3rd party wrapper for ftp might. | ||
+ | |||
+ | A word of advice can be put in the documentation that clearifies how glob() will not work with these edge case wrappers. But again, this applies to the current implementation of scandir() also. | ||
===== Unaffected PHP Functionality ===== | ===== Unaffected PHP Functionality ===== | ||
- | The use of the function PHP glob() | + | '' |
+ | |||
+ | Wrappers not intended to return a list of contents will continue returning an empty array as glob does today. | ||
+ | |||
+ | Edit (Oct 2): As noted by @bukka; | ||
===== Future Scope ===== | ===== Future Scope ===== | ||
Line 145: | Line 50: | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
- | Patches and tests are being produced in the Github Feature Request [[https:// | + | A PoC has been produced in the Github Feature Request |
- | Final patch will be produced by Github user @KapitanOczywisty. | + | Final patch will be produced by Github user @KapitanOczywisty |
===== Implementation ===== | ===== Implementation ===== |
rfc/glob_streamwrapper_support.1661035669.txt.gz · Last modified: 2022/08/20 22:47 by timint