php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
dir.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Thies C. Arntzen <thies@thieso.net> |
14 +----------------------------------------------------------------------+
15 */
16
17/* {{{ includes/startup/misc */
18
19#include "php.h"
20#include "fopen_wrappers.h"
21#include "file.h"
22#include "php_dir.h"
23#include "php_dir_int.h"
24#include "php_scandir.h"
25#include "basic_functions.h"
26#include "dir_arginfo.h"
27
28#ifdef HAVE_UNISTD_H
29#include <unistd.h>
30#endif
31
32#include <errno.h>
33
34#ifdef PHP_WIN32
35#include "win32/readdir.h"
36#endif
37
41
42#ifdef ZTS
43#define DIRG(v) ZEND_TSRMG(dir_globals_id, php_dir_globals *, v)
44int dir_globals_id;
45#else
46#define DIRG(v) (dir_globals.v)
48#endif
49
50static zend_class_entry *dir_class_entry_ptr;
51
52#define Z_DIRECTORY_PATH_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 0)
53#define Z_DIRECTORY_HANDLE_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 1)
54
55#define FETCH_DIRP() \
56 myself = getThis(); \
57 if (!myself) { \
58 ZEND_PARSE_PARAMETERS_START(0, 1) \
59 Z_PARAM_OPTIONAL \
60 Z_PARAM_RESOURCE_OR_NULL(id) \
61 ZEND_PARSE_PARAMETERS_END(); \
62 if (id) { \
63 if ((dirp = (php_stream *)zend_fetch_resource(Z_RES_P(id), "Directory", php_file_le_stream())) == NULL) { \
64 RETURN_THROWS(); \
65 } \
66 } else { \
67 if (!DIRG(default_dir)) { \
68 zend_type_error("No resource supplied"); \
69 RETURN_THROWS(); \
70 } \
71 if ((dirp = (php_stream *)zend_fetch_resource(DIRG(default_dir), "Directory", php_file_le_stream())) == NULL) { \
72 RETURN_THROWS(); \
73 } \
74 } \
75 } else { \
76 ZEND_PARSE_PARAMETERS_NONE(); \
77 zval *handle_zv = Z_DIRECTORY_HANDLE_P(myself); \
78 if (Z_TYPE_P(handle_zv) != IS_RESOURCE) { \
79 zend_throw_error(NULL, "Unable to find my handle property"); \
80 RETURN_THROWS(); \
81 } \
82 if ((dirp = (php_stream *)zend_fetch_resource_ex(handle_zv, "Directory", php_file_le_stream())) == NULL) { \
83 RETURN_THROWS(); \
84 } \
85 }
86
87
88static void php_set_default_dir(zend_resource *res)
89{
90 if (DIRG(default_dir)) {
91 zend_list_delete(DIRG(default_dir));
92 }
93
94 if (res) {
96 }
97
98 DIRG(default_dir) = res;
99}
100
102{
103 DIRG(default_dir) = NULL;
104 return SUCCESS;
105}
106
108{
110 dirsep_str[1] = '\0';
111
113 pathsep_str[1] = '\0';
114
115 register_dir_symbols(module_number);
116
117 dir_class_entry_ptr = register_class_Directory();
118
119#ifdef ZTS
120 ts_allocate_id(&dir_globals_id, sizeof(php_dir_globals), NULL, NULL);
121#endif
122
123 return SUCCESS;
124}
125/* }}} */
126
127/* {{{ internal functions */
128static void _php_do_opendir(INTERNAL_FUNCTION_PARAMETERS, int createobject)
129{
130 char *dirname;
131 size_t dir_len;
132 zval *zcontext = NULL;
134 php_stream *dirp;
135
137 Z_PARAM_PATH(dirname, dir_len)
141
143
145
146 if (dirp == NULL) {
148 }
149
151
152 php_set_default_dir(dirp->res);
153
154 if (createobject) {
155 object_init_ex(return_value, dir_class_entry_ptr);
158 php_stream_auto_cleanup(dirp); /* so we don't get warnings under debug */
159 } else {
161 }
162}
163/* }}} */
164
165/* {{{ Open a directory and return a dir_handle */
167{
168 _php_do_opendir(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
169}
170/* }}} */
171
172/* {{{ Directory class with properties, handle and class and methods read, rewind and close */
174{
175 _php_do_opendir(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
176}
177/* }}} */
178
179/* {{{ Close directory connection identified by the dir_handle */
181{
182 zval *id = NULL, *myself;
183 php_stream *dirp;
185
186 FETCH_DIRP();
187
188 if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) {
189 zend_argument_type_error(1, "must be a valid Directory resource");
191 }
192
193 res = dirp->res;
194 zend_list_close(dirp->res);
195
196 if (res == DIRG(default_dir)) {
197 php_set_default_dir(NULL);
198 }
199}
200/* }}} */
201
202#if defined(HAVE_CHROOT) && !defined(ZTS) && defined(ENABLE_CHROOT_FUNC)
203/* {{{ Change root directory */
205{
206 char *str;
207 int ret;
208 size_t str_len;
209
211 Z_PARAM_PATH(str, str_len)
213
214 ret = chroot(str);
215 if (ret != 0) {
216 php_error_docref(NULL, E_WARNING, "%s (errno %d)", strerror(errno), errno);
218 }
219
221
222 ret = chdir("/");
223
224 if (ret != 0) {
225 php_error_docref(NULL, E_WARNING, "%s (errno %d)", strerror(errno), errno);
227 }
228
230}
231/* }}} */
232#endif
233
234/* {{{ Change the current directory */
236{
237 char *str;
238 int ret;
239 size_t str_len;
240
242 Z_PARAM_PATH(str, str_len)
244
245 if (php_check_open_basedir(str)) {
247 }
248 ret = VCWD_CHDIR(str);
249
250 if (ret != 0) {
251 php_error_docref(NULL, E_WARNING, "%s (errno %d)", strerror(errno), errno);
253 }
254
255 if (BG(CurrentStatFile) && !IS_ABSOLUTE_PATH(ZSTR_VAL(BG(CurrentStatFile)), ZSTR_LEN(BG(CurrentStatFile)))) {
256 zend_string_release(BG(CurrentStatFile));
257 BG(CurrentStatFile) = NULL;
258 }
259 if (BG(CurrentLStatFile) && !IS_ABSOLUTE_PATH(ZSTR_VAL(BG(CurrentLStatFile)), ZSTR_LEN(BG(CurrentLStatFile)))) {
260 zend_string_release(BG(CurrentLStatFile));
261 BG(CurrentLStatFile) = NULL;
262 }
263
265}
266/* }}} */
267
268/* {{{ Gets the current directory */
270{
271 char path[MAXPATHLEN];
272 char *ret=NULL;
273
275
276#ifdef HAVE_GETCWD
277 ret = VCWD_GETCWD(path, MAXPATHLEN);
278#elif defined(HAVE_GETWD)
279 ret = VCWD_GETWD(path);
280#endif
281
282 if (ret) {
283 RETURN_STRING(path);
284 } else {
286 }
287}
288/* }}} */
289
290/* {{{ Rewind dir_handle back to the start */
292{
293 zval *id = NULL, *myself;
294 php_stream *dirp;
295
296 FETCH_DIRP();
297
298 if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) {
299 zend_argument_type_error(1, "must be a valid Directory resource");
301 }
302
304}
305/* }}} */
306
307/* {{{ Read directory entry from dir_handle */
309{
310 zval *id = NULL, *myself;
311 php_stream *dirp;
312 php_stream_dirent entry;
313
314 FETCH_DIRP();
315
316 if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) {
317 zend_argument_type_error(1, "must be a valid Directory resource");
319 }
320
321 if (php_stream_readdir(dirp, &entry)) {
322 RETURN_STRINGL(entry.d_name, strlen(entry.d_name));
323 }
325}
326/* }}} */
327
328#ifdef HAVE_GLOB
329/* {{{ Find pathnames matching a pattern */
331{
332 size_t cwd_skip = 0;
333#ifdef ZTS
334 char cwd[MAXPATHLEN];
335 char work_pattern[MAXPATHLEN];
336 char *result;
337#endif
338 char *pattern = NULL;
339 size_t pattern_len;
340 zend_long flags = 0;
341 glob_t globbuf;
342 size_t n;
343 int ret;
344 bool basedir_limit = 0;
345 zval tmp;
346
348 Z_PARAM_PATH(pattern, pattern_len)
352
353 if (pattern_len >= MAXPATHLEN) {
354 php_error_docref(NULL, E_WARNING, "Pattern exceeds the maximum allowed length of %d characters", MAXPATHLEN);
356 }
357
358 if ((GLOB_AVAILABLE_FLAGS & flags) != flags) {
359 php_error_docref(NULL, E_WARNING, "At least one of the passed flags is invalid or not supported on this platform");
361 }
362
363#ifdef ZTS
364 if (!IS_ABSOLUTE_PATH(pattern, pattern_len)) {
366 if (!result) {
367 cwd[0] = '\0';
368 }
369#ifdef PHP_WIN32
370 if (IS_SLASH(*pattern)) {
371 cwd[2] = '\0';
372 }
373#endif
374 cwd_skip = strlen(cwd)+1;
375
376 snprintf(work_pattern, MAXPATHLEN, "%s%c%s", cwd, DEFAULT_SLASH, pattern);
377 pattern = work_pattern;
378 }
379#endif
380
381
382 memset(&globbuf, 0, sizeof(glob_t));
383 globbuf.gl_offs = 0;
384 if (0 != (ret = glob(pattern, flags & GLOB_FLAGMASK, NULL, &globbuf))) {
385#ifdef GLOB_NOMATCH
386 if (GLOB_NOMATCH == ret) {
387 /* Some glob implementation simply return no data if no matches
388 were found, others return the GLOB_NOMATCH error code.
389 We don't want to treat GLOB_NOMATCH as an error condition
390 so that PHP glob() behaves the same on both types of
391 implementations and so that 'foreach (glob() as ...'
392 can be used for simple glob() calls without further error
393 checking.
394 */
395 goto no_results;
396 }
397#endif
399 }
400
401 /* now catch the FreeBSD style of "no matches" */
402 if (!globbuf.gl_pathc || !globbuf.gl_pathv) {
403#ifdef GLOB_NOMATCH
404no_results:
405#endif
407 return;
408 }
409
411 for (n = 0; n < (size_t)globbuf.gl_pathc; n++) {
412 if (PG(open_basedir) && *PG(open_basedir)) {
413 if (php_check_open_basedir_ex(globbuf.gl_pathv[n], 0)) {
414 basedir_limit = 1;
415 continue;
416 }
417 }
418 /* we need to do this every time since GLOB_ONLYDIR does not guarantee that
419 * all directories will be filtered. GNU libc documentation states the
420 * following:
421 * If the information about the type of the file is easily available
422 * non-directories will be rejected but no extra work will be done to
423 * determine the information for each file. I.e., the caller must still be
424 * able to filter directories out.
425 */
426 if (flags & GLOB_ONLYDIR) {
427 zend_stat_t s = {0};
428
429 if (0 != VCWD_STAT(globbuf.gl_pathv[n], &s)) {
430 continue;
431 }
432
433 if (S_IFDIR != (s.st_mode & S_IFMT)) {
434 continue;
435 }
436 }
437 ZVAL_STRING(&tmp, globbuf.gl_pathv[n]+cwd_skip);
439 }
440
441 globfree(&globbuf);
442
443 if (basedir_limit && !zend_hash_num_elements(Z_ARRVAL_P(return_value))) {
446 }
447}
448/* }}} */
449#endif
450
451/* {{{ List files & directories inside the specified path */
453{
454 char *dirn;
455 size_t dirn_len;
457 zend_string **namelist;
458 int n, i;
459 zval *zcontext = NULL;
461
463 Z_PARAM_PATH(dirn, dirn_len)
468
469 if (dirn_len < 1) {
472 }
473
474 if (zcontext) {
476 }
477
479 n = php_stream_scandir(dirn, &namelist, context, (void *) php_stream_dirent_alphasort);
480 } else if (flags == PHP_SCANDIR_SORT_NONE) {
481 n = php_stream_scandir(dirn, &namelist, context, NULL);
482 } else {
483 n = php_stream_scandir(dirn, &namelist, context, (void *) php_stream_dirent_alphasortr);
484 }
485 if (n < 0) {
486 php_error_docref(NULL, E_WARNING, "(errno %d): %s", errno, strerror(errno));
488 }
489
491
492 for (i = 0; i < n; i++) {
493 add_next_index_str(return_value, namelist[i]);
494 }
495
496 if (n) {
497 efree(namelist);
498 }
499}
500/* }}} */
#define BG(v)
chroot(string $directory)
readdir($dir_handle=null)
chdir(string $directory)
scandir(string $directory, int $sorting_order=SCANDIR_SORT_ASCENDING, $context=null)
closedir($dir_handle=null)
opendir(string $directory, $context=null)
dirname(string $path, int $levels=1)
dir(string $directory, $context=null)
glob(string $pattern, int $flags=0)
rewinddir($dir_handle=null)
char s[4]
Definition cdf.c:77
#define Z_DIRECTORY_PATH_P(zv)
Definition dir.c:52
php_dir_globals dir_globals
Definition dir.c:47
#define FETCH_DIRP()
Definition dir.c:55
#define DIRG(v)
Definition dir.c:46
#define Z_DIRECTORY_HANDLE_P(zv)
Definition dir.c:53
const GLOB_AVAILABLE_FLAGS
Definition dir.stub.php:71
const GLOB_ONLYDIR
Definition dir.stub.php:64
zend_long n
Definition ffi.c:4979
zend_string * res
Definition ffi.c:4692
memset(ptr, 0, type->size)
PHPAPI void php_clear_stat_cache(bool clear_realpath_cache, const char *filename, size_t filename_len)
Definition filestat.c:697
PHPAPI int php_check_open_basedir(const char *path)
PHPAPI int php_check_open_basedir_ex(const char *path, int warn)
zval * zcontext
#define NULL
Definition gdcache.h:45
PHPAPI void globfree(glob_t *pglob)
Definition glob.c:777
#define GLOB_NOMATCH
Definition glob.h:94
#define SUCCESS
Definition hash_sha3.c:261
foreach($dp as $el) foreach( $dp as $el) if( $pass2< 2) echo ""
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
char * cwd
#define PHP_FUNCTION
Definition php.h:364
#define PHP_MINIT_FUNCTION
Definition php.h:400
#define PHP_RINIT_FUNCTION
Definition php.h:402
#define PHP_SCANDIR_SORT_NONE
Definition php_dir.h:26
#define PHP_SCANDIR_SORT_ASCENDING
Definition php_dir.h:24
char pathsep_str[2]
Definition php_dir_int.h:67
char dirsep_str[2]
Definition php_dir_int.h:67
#define PG(v)
Definition php_globals.h:31
#define php_stream_context_from_zval(zcontext, nocontext)
struct _php_stream php_stream
Definition php_streams.h:96
struct _php_stream_context php_stream_context
Definition php_streams.h:98
#define REPORT_ERRORS
struct _php_stream_dirent php_stream_dirent
#define php_stream_readdir(dirstream, dirent)
#define php_stream_auto_cleanup(stream)
#define php_stream_to_zval(stream, zval)
#define php_stream_opendir(path, options, context)
PHPAPI int php_stream_dirent_alphasort(const zend_string **a, const zend_string **b)
Definition streams.c:2438
PHPAPI int php_stream_dirent_alphasortr(const zend_string **a, const zend_string **b)
Definition streams.c:2445
#define PHP_STREAM_FLAG_IS_DIR
#define php_stream_scandir(dirname, namelist, context, compare)
#define php_stream_rewinddir(dirstream)
#define PHP_STREAM_FLAG_NO_FCLOSE
char d_name[MAXPATHLEN]
uint32_t flags
zend_resource * res
Definition dce.c:49
Definition glob.h:51
int gl_offs
Definition glob.h:54
int gl_pathc
Definition glob.h:52
char ** gl_pathv
Definition glob.h:56
zend_resource * default_dir
Definition dir.c:39
#define errno
#define INTERNAL_FUNCTION_PARAMETERS
Definition zend.h:49
#define INTERNAL_FUNCTION_PARAM_PASSTHRU
Definition zend.h:50
ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *class_type)
Definition zend_API.c:1849
ZEND_API ZEND_COLD void zend_argument_must_not_be_empty_error(uint32_t arg_num)
Definition zend_API.c:443
ZEND_API ZEND_COLD void zend_argument_type_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:423
ZEND_API zend_result add_next_index_str(zval *arg, zend_string *str)
Definition zend_API.c:2177
#define RETURN_STRING(s)
Definition zend_API.h:1043
#define RETURN_STRINGL(s, l)
Definition zend_API.h:1044
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define RETURN_FALSE
Definition zend_API.h:1058
#define ZEND_PARSE_PARAMETERS_NONE()
Definition zend_API.h:1623
#define ZVAL_STRING(z, s)
Definition zend_API.h:956
#define Z_PARAM_OPTIONAL
Definition zend_API.h:1667
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define Z_PARAM_LONG(dest)
Definition zend_API.h:1896
#define RETURN_THROWS()
Definition zend_API.h:1060
#define Z_PARAM_PATH(dest, dest_len)
Definition zend_API.h:2026
#define Z_PARAM_RESOURCE_OR_NULL(dest)
Definition zend_API.h:2059
#define ZVAL_STRINGL(z, s, l)
Definition zend_API.h:952
#define RETURN_TRUE
Definition zend_API.h:1059
#define array_init(arg)
Definition zend_API.h:537
#define efree(ptr)
Definition zend_alloc.h:155
struct _zval_struct zval
strlen(string $string)
#define snprintf
#define E_WARNING
Definition zend_errors.h:24
ZEND_API zval *ZEND_FASTCALL zend_hash_next_index_insert_new(HashTable *ht, zval *pData)
Definition zend_hash.c:1229
ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
Definition zend_hash.c:1808
ZEND_API zend_result ZEND_FASTCALL zend_list_delete(zend_resource *res)
Definition zend_list.c:46
ZEND_API void ZEND_FASTCALL zend_list_close(zend_resource *res)
Definition zend_list.c:78
int32_t zend_long
Definition zend_long.h:42
struct _zend_string zend_string
#define ZEND_PATHS_SEPARATOR
struct _zend_class_entry zend_class_entry
struct stat zend_stat_t
Definition zend_stream.h:94
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
struct _zend_resource zend_resource
Definition zend_types.h:99
#define GC_ADDREF(p)
Definition zend_types.h:709
#define ZVAL_RES(z, r)
#define Z_ARR_P(zval_p)
Definition zend_types.h:984
#define IS_SLASH(c)
#define DEFAULT_SLASH
#define VCWD_GETWD(buf)
#define IS_ABSOLUTE_PATH(path, len)
#define VCWD_CHDIR(path)
#define VCWD_GETCWD(buff, size)
#define MAXPATHLEN
#define VCWD_STAT(path, buff)
zval * return_value
bool result
zval * ret