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 | Authors: Rasmus Lerdorf <rasmus@php.net> |
14 | Stig Bakken <ssb@php.net> |
15 | Andi Gutmans <andi@php.net> |
16 | Zeev Suraski <zeev@php.net> |
17 | PHP 4.0 patches by Thies C. Arntzen (thies@thieso.net) |
18 | PHP streams by Wez Furlong (wez@thebrainroom.com) |
19 +----------------------------------------------------------------------+
20 */
21
22 /* {{{ includes */
23
24 #include "php.h"
25 #include "php_globals.h"
26 #include "ext/standard/flock_compat.h"
27 #include "ext/standard/exec.h"
28 #include "ext/standard/php_filestat.h"
29 #include "php_open_temporary_file.h"
30 #include "ext/standard/basic_functions.h"
31 #include "php_ini.h"
32 #include "zend_smart_str.h"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <wchar.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41
42 #ifdef PHP_WIN32
43 # include <io.h>
44 # define O_RDONLY _O_RDONLY
45 # include "win32/param.h"
46 # include "win32/winutil.h"
47 # include "win32/fnmatch.h"
48 # include "win32/ioutil.h"
49 #else
50 # if HAVE_SYS_PARAM_H
51 # include <sys/param.h>
52 # endif
53 # if HAVE_SYS_SELECT_H
54 # include <sys/select.h>
55 # endif
56 # include <sys/socket.h>
57 # include <netinet/in.h>
58 # include <netdb.h>
59 # if HAVE_ARPA_INET_H
60 # include <arpa/inet.h>
61 # endif
62 #endif
63
64 #include "ext/standard/head.h"
65 #include "php_string.h"
66 #include "file.h"
67
68 #ifdef HAVE_PWD_H
69 # ifdef PHP_WIN32
70 # include "win32/pwd.h"
71 # else
72 # include <pwd.h>
73 # endif
74 #endif
75
76 #ifdef HAVE_SYS_TIME_H
77 # include <sys/time.h>
78 #endif
79
80 #include "fsock.h"
81 #include "fopen_wrappers.h"
82 #include "streamsfuncs.h"
83 #include "php_globals.h"
84
85 #ifdef HAVE_SYS_FILE_H
86 # include <sys/file.h>
87 #endif
88
89 #if MISSING_FCLOSE_DECL
90 extern int fclose(FILE *);
91 #endif
92
93 #ifdef HAVE_SYS_MMAN_H
94 # include <sys/mman.h>
95 #endif
96
97 #include "scanf.h"
98 #include "zend_API.h"
99
100 #ifdef ZTS
101 int file_globals_id;
102 #else
103 php_file_globals file_globals;
104 #endif
105
106 #if defined(HAVE_FNMATCH) && !defined(PHP_WIN32)
107 # ifndef _GNU_SOURCE
108 # define _GNU_SOURCE
109 # endif
110 # include <fnmatch.h>
111 #endif
112
113 #include "file_arginfo.h"
114
115 /* }}} */
116
117 #define PHP_STREAM_TO_ZVAL(stream, arg) \
118 ZEND_ASSERT(Z_TYPE_P(arg) == IS_RESOURCE); \
119 php_stream_from_res(stream, Z_RES_P(arg));
120
121 /* {{{ ZTS-stuff / Globals / Prototypes */
122
123 /* sharing globals is *evil* */
124 static int le_stream_context = FAILURE;
125
php_le_stream_context(void)126 PHPAPI int php_le_stream_context(void)
127 {
128 return le_stream_context;
129 }
130 /* }}} */
131
132 /* {{{ Module-Stuff */
ZEND_RSRC_DTOR_FUNC(file_context_dtor)133 static ZEND_RSRC_DTOR_FUNC(file_context_dtor)
134 {
135 php_stream_context *context = (php_stream_context*)res->ptr;
136 if (Z_TYPE(context->options) != IS_UNDEF) {
137 zval_ptr_dtor(&context->options);
138 ZVAL_UNDEF(&context->options);
139 }
140 php_stream_context_free(context);
141 }
142
file_globals_ctor(php_file_globals * file_globals_p)143 static void file_globals_ctor(php_file_globals *file_globals_p)
144 {
145 memset(file_globals_p, 0, sizeof(php_file_globals));
146 file_globals_p->def_chunk_size = PHP_SOCK_CHUNK_SIZE;
147 }
148
file_globals_dtor(php_file_globals * file_globals_p)149 static void file_globals_dtor(php_file_globals *file_globals_p)
150 {
151 #if defined(HAVE_GETHOSTBYNAME_R)
152 if (file_globals_p->tmp_host_buf) {
153 free(file_globals_p->tmp_host_buf);
154 }
155 #endif
156 }
157
PHP_INI_MH(OnUpdateAutoDetectLineEndings)158 static PHP_INI_MH(OnUpdateAutoDetectLineEndings)
159 {
160 if (zend_ini_parse_bool(new_value)) {
161 zend_error(E_DEPRECATED, "auto_detect_line_endings is deprecated");
162 }
163 return OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
164 }
165
166 PHP_INI_BEGIN()
167 STD_PHP_INI_ENTRY("user_agent", NULL, PHP_INI_ALL, OnUpdateString, user_agent, php_file_globals, file_globals)
168 STD_PHP_INI_ENTRY("from", NULL, PHP_INI_ALL, OnUpdateString, from_address, php_file_globals, file_globals)
169 STD_PHP_INI_ENTRY("default_socket_timeout", "60", PHP_INI_ALL, OnUpdateLong, default_socket_timeout, php_file_globals, file_globals)
170 STD_PHP_INI_BOOLEAN("auto_detect_line_endings", "0", PHP_INI_ALL, OnUpdateAutoDetectLineEndings, auto_detect_line_endings, php_file_globals, file_globals)
PHP_INI_END()171 PHP_INI_END()
172
173 PHP_MINIT_FUNCTION(file)
174 {
175 le_stream_context = zend_register_list_destructors_ex(file_context_dtor, NULL, "stream-context", module_number);
176
177 #ifdef ZTS
178 ts_allocate_id(&file_globals_id, sizeof(php_file_globals), (ts_allocate_ctor) file_globals_ctor, (ts_allocate_dtor) file_globals_dtor);
179 #else
180 file_globals_ctor(&file_globals);
181 #endif
182
183 REGISTER_INI_ENTRIES();
184
185 register_file_symbols(module_number);
186
187 return SUCCESS;
188 }
189 /* }}} */
190
PHP_MSHUTDOWN_FUNCTION(file)191 PHP_MSHUTDOWN_FUNCTION(file) /* {{{ */
192 {
193 #ifndef ZTS
194 file_globals_dtor(&file_globals);
195 #endif
196 return SUCCESS;
197 }
198 /* }}} */
199
php_flock_common(php_stream * stream,zend_long operation,uint32_t operation_arg_num,zval * wouldblock,zval * return_value)200 PHPAPI void php_flock_common(php_stream *stream, zend_long operation,
201 uint32_t operation_arg_num, zval *wouldblock, zval *return_value)
202 {
203 int flock_values[] = { LOCK_SH, LOCK_EX, LOCK_UN };
204 int act;
205
206 act = operation & PHP_LOCK_UN;
207 if (act < 1 || act > 3) {
208 zend_argument_value_error(operation_arg_num, "must be one of LOCK_SH, LOCK_EX, or LOCK_UN");
209 RETURN_THROWS();
210 }
211
212 if (wouldblock) {
213 ZEND_TRY_ASSIGN_REF_LONG(wouldblock, 0);
214 }
215
216 /* flock_values contains all possible actions if (operation & PHP_LOCK_NB) we won't block on the lock */
217 act = flock_values[act - 1] | (operation & PHP_LOCK_NB ? LOCK_NB : 0);
218 if (php_stream_lock(stream, act)) {
219 if (operation && errno == EWOULDBLOCK && wouldblock) {
220 ZEND_TRY_ASSIGN_REF_LONG(wouldblock, 1);
221 }
222 RETURN_FALSE;
223 }
224 RETURN_TRUE;
225 }
226
227 /* {{{ Portable file locking */
PHP_FUNCTION(flock)228 PHP_FUNCTION(flock)
229 {
230 zval *res, *wouldblock = NULL;
231 php_stream *stream;
232 zend_long operation = 0;
233
234 ZEND_PARSE_PARAMETERS_START(2, 3)
235 Z_PARAM_RESOURCE(res)
236 Z_PARAM_LONG(operation)
237 Z_PARAM_OPTIONAL
238 Z_PARAM_ZVAL(wouldblock)
239 ZEND_PARSE_PARAMETERS_END();
240
241 PHP_STREAM_TO_ZVAL(stream, res);
242
243 php_flock_common(stream, operation, 2, wouldblock, return_value);
244 }
245 /* }}} */
246
247 #define PHP_META_UNSAFE ".\\+*?[^]$() "
248
249 /* {{{ Extracts all meta tag content attributes from a file and returns an array */
PHP_FUNCTION(get_meta_tags)250 PHP_FUNCTION(get_meta_tags)
251 {
252 char *filename;
253 size_t filename_len;
254 bool use_include_path = 0;
255 int in_tag = 0, done = 0;
256 int looking_for_val = 0, have_name = 0, have_content = 0;
257 int saw_name = 0, saw_content = 0;
258 char *name = NULL, *value = NULL, *temp = NULL;
259 php_meta_tags_token tok, tok_last;
260 php_meta_tags_data md;
261
262 /* Initialize our structure */
263 memset(&md, 0, sizeof(md));
264
265 /* Parse arguments */
266 ZEND_PARSE_PARAMETERS_START(1, 2)
267 Z_PARAM_PATH(filename, filename_len)
268 Z_PARAM_OPTIONAL
269 Z_PARAM_BOOL(use_include_path)
270 ZEND_PARSE_PARAMETERS_END();
271
272 md.stream = php_stream_open_wrapper(filename, "rb",
273 (use_include_path ? USE_PATH : 0) | REPORT_ERRORS,
274 NULL);
275 if (!md.stream) {
276 RETURN_FALSE;
277 }
278
279 array_init(return_value);
280
281 tok_last = TOK_EOF;
282
283 while (!done && (tok = php_next_meta_token(&md)) != TOK_EOF) {
284 if (tok == TOK_ID) {
285 if (tok_last == TOK_OPENTAG) {
286 md.in_meta = !strcasecmp("meta", md.token_data);
287 } else if (tok_last == TOK_SLASH && in_tag) {
288 if (strcasecmp("head", md.token_data) == 0) {
289 /* We are done here! */
290 done = 1;
291 }
292 } else if (tok_last == TOK_EQUAL && looking_for_val) {
293 if (saw_name) {
294 if (name) efree(name);
295 /* Get the NAME attr (Single word attr, non-quoted) */
296 temp = name = estrndup(md.token_data, md.token_len);
297
298 while (temp && *temp) {
299 if (strchr(PHP_META_UNSAFE, *temp)) {
300 *temp = '_';
301 }
302 temp++;
303 }
304
305 have_name = 1;
306 } else if (saw_content) {
307 if (value) efree(value);
308 value = estrndup(md.token_data, md.token_len);
309 have_content = 1;
310 }
311
312 looking_for_val = 0;
313 } else {
314 if (md.in_meta) {
315 if (strcasecmp("name", md.token_data) == 0) {
316 saw_name = 1;
317 saw_content = 0;
318 looking_for_val = 1;
319 } else if (strcasecmp("content", md.token_data) == 0) {
320 saw_name = 0;
321 saw_content = 1;
322 looking_for_val = 1;
323 }
324 }
325 }
326 } else if (tok == TOK_STRING && tok_last == TOK_EQUAL && looking_for_val) {
327 if (saw_name) {
328 if (name) efree(name);
329 /* Get the NAME attr (Quoted single/double) */
330 temp = name = estrndup(md.token_data, md.token_len);
331
332 while (temp && *temp) {
333 if (strchr(PHP_META_UNSAFE, *temp)) {
334 *temp = '_';
335 }
336 temp++;
337 }
338
339 have_name = 1;
340 } else if (saw_content) {
341 if (value) efree(value);
342 value = estrndup(md.token_data, md.token_len);
343 have_content = 1;
344 }
345
346 looking_for_val = 0;
347 } else if (tok == TOK_OPENTAG) {
348 if (looking_for_val) {
349 looking_for_val = 0;
350 have_name = saw_name = 0;
351 have_content = saw_content = 0;
352 }
353 in_tag = 1;
354 } else if (tok == TOK_CLOSETAG) {
355 if (have_name) {
356 /* For BC */
357 zend_str_tolower(name, strlen(name));
358 if (have_content) {
359 add_assoc_string(return_value, name, value);
360 } else {
361 add_assoc_string(return_value, name, "");
362 }
363
364 efree(name);
365 if (value) efree(value);
366 } else if (have_content) {
367 efree(value);
368 }
369
370 name = value = NULL;
371
372 /* Reset all of our flags */
373 in_tag = looking_for_val = 0;
374 have_name = saw_name = 0;
375 have_content = saw_content = 0;
376 md.in_meta = 0;
377 }
378
379 tok_last = tok;
380
381 if (md.token_data)
382 efree(md.token_data);
383
384 md.token_data = NULL;
385 }
386
387 if (value) efree(value);
388 if (name) efree(name);
389 php_stream_close(md.stream);
390 }
391 /* }}} */
392
393 /* {{{ Read the entire file into a string */
PHP_FUNCTION(file_get_contents)394 PHP_FUNCTION(file_get_contents)
395 {
396 char *filename;
397 size_t filename_len;
398 bool use_include_path = 0;
399 php_stream *stream;
400 zend_long offset = 0;
401 zend_long maxlen;
402 bool maxlen_is_null = 1;
403 zval *zcontext = NULL;
404 php_stream_context *context = NULL;
405 zend_string *contents;
406
407 /* Parse arguments */
408 ZEND_PARSE_PARAMETERS_START(1, 5)
409 Z_PARAM_PATH(filename, filename_len)
410 Z_PARAM_OPTIONAL
411 Z_PARAM_BOOL(use_include_path)
412 Z_PARAM_RESOURCE_OR_NULL(zcontext)
413 Z_PARAM_LONG(offset)
414 Z_PARAM_LONG_OR_NULL(maxlen, maxlen_is_null)
415 ZEND_PARSE_PARAMETERS_END();
416
417 if (maxlen_is_null) {
418 maxlen = (ssize_t) PHP_STREAM_COPY_ALL;
419 } else if (maxlen < 0) {
420 zend_argument_value_error(5, "must be greater than or equal to 0");
421 RETURN_THROWS();
422 }
423
424 context = php_stream_context_from_zval(zcontext, 0);
425
426 stream = php_stream_open_wrapper_ex(filename, "rb",
427 (use_include_path ? USE_PATH : 0) | REPORT_ERRORS,
428 NULL, context);
429 if (!stream) {
430 RETURN_FALSE;
431 }
432
433 /* disabling the read buffer allows doing the whole transfer
434 in just one read() system call */
435 if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) {
436 php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
437 }
438
439 if (offset != 0 && php_stream_seek(stream, offset, ((offset > 0) ? SEEK_SET : SEEK_END)) < 0) {
440 php_error_docref(NULL, E_WARNING, "Failed to seek to position " ZEND_LONG_FMT " in the stream", offset);
441 php_stream_close(stream);
442 RETURN_FALSE;
443 }
444
445 if ((contents = php_stream_copy_to_mem(stream, maxlen, 0)) != NULL) {
446 RETVAL_STR(contents);
447 } else {
448 RETVAL_EMPTY_STRING();
449 }
450
451 php_stream_close(stream);
452 }
453 /* }}} */
454
455 /* {{{ Write/Create a file with contents data and return the number of bytes written */
PHP_FUNCTION(file_put_contents)456 PHP_FUNCTION(file_put_contents)
457 {
458 php_stream *stream;
459 char *filename;
460 size_t filename_len;
461 zval *data;
462 ssize_t numbytes = 0;
463 zend_long flags = 0;
464 zval *zcontext = NULL;
465 php_stream_context *context = NULL;
466 php_stream *srcstream = NULL;
467 char mode[3] = "wb";
468
469 ZEND_PARSE_PARAMETERS_START(2, 4)
470 Z_PARAM_PATH(filename, filename_len)
471 Z_PARAM_ZVAL(data)
472 Z_PARAM_OPTIONAL
473 Z_PARAM_LONG(flags)
474 Z_PARAM_RESOURCE_OR_NULL(zcontext)
475 ZEND_PARSE_PARAMETERS_END();
476
477 if (Z_TYPE_P(data) == IS_RESOURCE) {
478 php_stream_from_zval(srcstream, data);
479 }
480
481 context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
482
483 if (flags & PHP_FILE_APPEND) {
484 mode[0] = 'a';
485 } else if (flags & LOCK_EX) {
486 /* check to make sure we are dealing with a regular file */
487 if (php_memnstr(filename, "://", sizeof("://") - 1, filename + filename_len)) {
488 if (strncasecmp(filename, "file://", sizeof("file://") - 1)) {
489 php_error_docref(NULL, E_WARNING, "Exclusive locks may only be set for regular files");
490 RETURN_FALSE;
491 }
492 }
493 mode[0] = 'c';
494 }
495 mode[2] = '\0';
496
497 stream = php_stream_open_wrapper_ex(filename, mode, ((flags & PHP_FILE_USE_INCLUDE_PATH) ? USE_PATH : 0) | REPORT_ERRORS, NULL, context);
498 if (stream == NULL) {
499 RETURN_FALSE;
500 }
501
502 if ((flags & LOCK_EX) && (!php_stream_supports_lock(stream) || php_stream_lock(stream, LOCK_EX))) {
503 php_stream_close(stream);
504 php_error_docref(NULL, E_WARNING, "Exclusive locks are not supported for this stream");
505 RETURN_FALSE;
506 }
507
508 if (mode[0] == 'c') {
509 php_stream_truncate_set_size(stream, 0);
510 }
511
512 switch (Z_TYPE_P(data)) {
513 case IS_RESOURCE: {
514 size_t len;
515 if (php_stream_copy_to_stream_ex(srcstream, stream, PHP_STREAM_COPY_ALL, &len) != SUCCESS) {
516 numbytes = -1;
517 } else {
518 if (len > ZEND_LONG_MAX) {
519 php_error_docref(NULL, E_WARNING, "content truncated from %zu to " ZEND_LONG_FMT " bytes", len, ZEND_LONG_MAX);
520 len = ZEND_LONG_MAX;
521 }
522 numbytes = len;
523 }
524 break;
525 }
526 case IS_NULL:
527 case IS_LONG:
528 case IS_DOUBLE:
529 case IS_FALSE:
530 case IS_TRUE:
531 convert_to_string(data);
532 ZEND_FALLTHROUGH;
533 case IS_STRING:
534 if (Z_STRLEN_P(data)) {
535 numbytes = php_stream_write(stream, Z_STRVAL_P(data), Z_STRLEN_P(data));
536 if (numbytes != -1 && numbytes != Z_STRLEN_P(data)) {
537 php_error_docref(NULL, E_WARNING, "Only %zd of %zd bytes written, possibly out of free disk space", numbytes, Z_STRLEN_P(data));
538 numbytes = -1;
539 }
540 }
541 break;
542
543 case IS_ARRAY:
544 if (zend_hash_num_elements(Z_ARRVAL_P(data))) {
545 ssize_t bytes_written;
546 zval *tmp;
547
548 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(data), tmp) {
549 zend_string *t;
550 zend_string *str = zval_get_tmp_string(tmp, &t);
551 if (ZSTR_LEN(str)) {
552 numbytes += ZSTR_LEN(str);
553 bytes_written = php_stream_write(stream, ZSTR_VAL(str), ZSTR_LEN(str));
554 if (bytes_written != ZSTR_LEN(str)) {
555 php_error_docref(NULL, E_WARNING, "Failed to write %zd bytes to %s", ZSTR_LEN(str), filename);
556 zend_tmp_string_release(t);
557 numbytes = -1;
558 break;
559 }
560 }
561 zend_tmp_string_release(t);
562 } ZEND_HASH_FOREACH_END();
563 }
564 break;
565
566 case IS_OBJECT:
567 if (Z_OBJ_HT_P(data) != NULL) {
568 zval out;
569
570 if (zend_std_cast_object_tostring(Z_OBJ_P(data), &out, IS_STRING) == SUCCESS) {
571 numbytes = php_stream_write(stream, Z_STRVAL(out), Z_STRLEN(out));
572 if (numbytes != -1 && numbytes != Z_STRLEN(out)) {
573 php_error_docref(NULL, E_WARNING, "Only %zd of %zd bytes written, possibly out of free disk space", numbytes, Z_STRLEN(out));
574 numbytes = -1;
575 }
576 zval_ptr_dtor_str(&out);
577 break;
578 }
579 }
580 ZEND_FALLTHROUGH;
581 default:
582 numbytes = -1;
583 break;
584 }
585 php_stream_close(stream);
586
587 if (numbytes < 0) {
588 RETURN_FALSE;
589 }
590
591 RETURN_LONG(numbytes);
592 }
593 /* }}} */
594
595 #define PHP_FILE_BUF_SIZE 80
596
597 /* {{{ Read entire file into an array */
PHP_FUNCTION(file)598 PHP_FUNCTION(file)
599 {
600 char *filename;
601 size_t filename_len;
602 char *p, *s, *e;
603 int i = 0;
604 char eol_marker = '\n';
605 zend_long flags = 0;
606 bool use_include_path;
607 bool include_new_line;
608 bool skip_blank_lines;
609 php_stream *stream;
610 zval *zcontext = NULL;
611 php_stream_context *context = NULL;
612 zend_string *target_buf;
613
614 /* Parse arguments */
615 ZEND_PARSE_PARAMETERS_START(1, 3)
616 Z_PARAM_PATH(filename, filename_len)
617 Z_PARAM_OPTIONAL
618 Z_PARAM_LONG(flags)
619 Z_PARAM_RESOURCE_OR_NULL(zcontext)
620 ZEND_PARSE_PARAMETERS_END();
621
622 if (flags < 0 || flags > (PHP_FILE_USE_INCLUDE_PATH | PHP_FILE_IGNORE_NEW_LINES | PHP_FILE_SKIP_EMPTY_LINES | PHP_FILE_NO_DEFAULT_CONTEXT)) {
623 zend_argument_value_error(2, "must be a valid flag value");
624 RETURN_THROWS();
625 }
626
627 use_include_path = flags & PHP_FILE_USE_INCLUDE_PATH;
628 include_new_line = !(flags & PHP_FILE_IGNORE_NEW_LINES);
629 skip_blank_lines = flags & PHP_FILE_SKIP_EMPTY_LINES;
630
631 context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
632
633 stream = php_stream_open_wrapper_ex(filename, "rb", (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context);
634 if (!stream) {
635 RETURN_FALSE;
636 }
637
638 /* Initialize return array */
639 array_init(return_value);
640
641 if ((target_buf = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0)) != NULL) {
642 s = ZSTR_VAL(target_buf);
643 e = ZSTR_VAL(target_buf) + ZSTR_LEN(target_buf);
644
645 if (!(p = (char*)php_stream_locate_eol(stream, target_buf))) {
646 p = e;
647 goto parse_eol;
648 }
649
650 if (stream->flags & PHP_STREAM_FLAG_EOL_MAC) {
651 eol_marker = '\r';
652 }
653
654 /* for performance reasons the code is duplicated, so that the if (include_new_line)
655 * will not need to be done for every single line in the file. */
656 if (include_new_line) {
657 do {
658 p++;
659 parse_eol:
660 add_index_stringl(return_value, i++, s, p-s);
661 s = p;
662 } while ((p = memchr(p, eol_marker, (e-p))));
663 } else {
664 do {
665 int windows_eol = 0;
666 if (p != ZSTR_VAL(target_buf) && eol_marker == '\n' && *(p - 1) == '\r') {
667 windows_eol++;
668 }
669 if (skip_blank_lines && !(p-s-windows_eol)) {
670 s = ++p;
671 continue;
672 }
673 add_index_stringl(return_value, i++, s, p-s-windows_eol);
674 s = ++p;
675 } while ((p = memchr(p, eol_marker, (e-p))));
676 }
677
678 /* handle any left overs of files without new lines */
679 if (s != e) {
680 p = e;
681 goto parse_eol;
682 }
683 }
684
685 if (target_buf) {
686 zend_string_free(target_buf);
687 }
688 php_stream_close(stream);
689 }
690 /* }}} */
691
692 /* {{{ Create a unique filename in a directory */
PHP_FUNCTION(tempnam)693 PHP_FUNCTION(tempnam)
694 {
695 char *dir, *prefix;
696 size_t dir_len, prefix_len;
697 zend_string *opened_path;
698 int fd;
699 zend_string *p;
700
701 ZEND_PARSE_PARAMETERS_START(2, 2)
702 Z_PARAM_PATH(dir, dir_len)
703 Z_PARAM_PATH(prefix, prefix_len)
704 ZEND_PARSE_PARAMETERS_END();
705
706 p = php_basename(prefix, prefix_len, NULL, 0);
707 if (ZSTR_LEN(p) >= 64) {
708 ZSTR_VAL(p)[63] = '\0';
709 }
710
711 RETVAL_FALSE;
712
713 if ((fd = php_open_temporary_fd_ex(dir, ZSTR_VAL(p), &opened_path, PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ALWAYS)) >= 0) {
714 close(fd);
715 RETVAL_STR(opened_path);
716 }
717 zend_string_release_ex(p, 0);
718 }
719 /* }}} */
720
721 /* {{{ Create a temporary file that will be deleted automatically after use */
PHP_FUNCTION(tmpfile)722 PHP_FUNCTION(tmpfile)
723 {
724 php_stream *stream;
725
726 ZEND_PARSE_PARAMETERS_NONE();
727
728 stream = php_stream_fopen_tmpfile();
729
730 if (stream) {
731 php_stream_to_zval(stream, return_value);
732 } else {
733 RETURN_FALSE;
734 }
735 }
736 /* }}} */
737
738 /* {{{ Open a file or a URL and return a file pointer */
PHP_FUNCTION(fopen)739 PHP_FUNCTION(fopen)
740 {
741 char *filename, *mode;
742 size_t filename_len, mode_len;
743 bool use_include_path = 0;
744 zval *zcontext = NULL;
745 php_stream *stream;
746 php_stream_context *context = NULL;
747
748 ZEND_PARSE_PARAMETERS_START(2, 4)
749 Z_PARAM_PATH(filename, filename_len)
750 Z_PARAM_STRING(mode, mode_len)
751 Z_PARAM_OPTIONAL
752 Z_PARAM_BOOL(use_include_path)
753 Z_PARAM_RESOURCE_OR_NULL(zcontext)
754 ZEND_PARSE_PARAMETERS_END();
755
756 context = php_stream_context_from_zval(zcontext, 0);
757
758 stream = php_stream_open_wrapper_ex(filename, mode, (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context);
759
760 if (stream == NULL) {
761 RETURN_FALSE;
762 }
763
764 php_stream_to_zval(stream, return_value);
765 }
766 /* }}} */
767
768 /* {{{ Close an open file pointer */
PHP_FUNCTION(fclose)769 PHPAPI PHP_FUNCTION(fclose)
770 {
771 zval *res;
772 php_stream *stream;
773
774 ZEND_PARSE_PARAMETERS_START(1, 1)
775 Z_PARAM_RESOURCE(res)
776 ZEND_PARSE_PARAMETERS_END();
777
778 PHP_STREAM_TO_ZVAL(stream, res);
779
780 if ((stream->flags & PHP_STREAM_FLAG_NO_FCLOSE) != 0) {
781 php_error_docref(NULL, E_WARNING, ZEND_LONG_FMT " is not a valid stream resource", stream->res->handle);
782 RETURN_FALSE;
783 }
784
785 php_stream_free(stream,
786 PHP_STREAM_FREE_KEEP_RSRC |
787 (stream->is_persistent ? PHP_STREAM_FREE_CLOSE_PERSISTENT : PHP_STREAM_FREE_CLOSE));
788
789 RETURN_TRUE;
790 }
791 /* }}} */
792
793 /* {{{ Execute a command and open either a read or a write pipe to it */
PHP_FUNCTION(popen)794 PHP_FUNCTION(popen)
795 {
796 char *command, *mode;
797 size_t command_len, mode_len;
798 FILE *fp;
799 php_stream *stream;
800 char *posix_mode;
801
802 ZEND_PARSE_PARAMETERS_START(2, 2)
803 Z_PARAM_PATH(command, command_len)
804 Z_PARAM_STRING(mode, mode_len)
805 ZEND_PARSE_PARAMETERS_END();
806
807 posix_mode = estrndup(mode, mode_len);
808 #ifndef PHP_WIN32
809 {
810 char *z = memchr(posix_mode, 'b', mode_len);
811 if (z) {
812 memmove(z, z + 1, mode_len - (z - posix_mode));
813 mode_len--;
814 }
815 }
816 #endif
817
818 /* Musl only partially validates the mode. Manually check it to ensure consistent behavior. */
819 if (mode_len > 2 ||
820 (mode_len == 1 && (*posix_mode != 'r' && *posix_mode != 'w')) ||
821 (mode_len == 2 && (memcmp(posix_mode, "rb", 2) && memcmp(posix_mode, "wb", 2)))
822 ) {
823 zend_argument_value_error(2, "must be one of \"r\", \"rb\", \"w\", or \"wb\"");
824 efree(posix_mode);
825 RETURN_THROWS();
826 }
827
828 fp = VCWD_POPEN(command, posix_mode);
829 if (!fp) {
830 php_error_docref2(NULL, command, posix_mode, E_WARNING, "%s", strerror(errno));
831 efree(posix_mode);
832 RETURN_FALSE;
833 }
834
835 stream = php_stream_fopen_from_pipe(fp, mode);
836
837 if (stream == NULL) {
838 php_error_docref2(NULL, command, mode, E_WARNING, "%s", strerror(errno));
839 RETVAL_FALSE;
840 } else {
841 php_stream_to_zval(stream, return_value);
842 }
843
844 efree(posix_mode);
845 }
846 /* }}} */
847
848 /* {{{ Close a file pointer opened by popen() */
PHP_FUNCTION(pclose)849 PHP_FUNCTION(pclose)
850 {
851 zval *res;
852 php_stream *stream;
853
854 ZEND_PARSE_PARAMETERS_START(1, 1)
855 Z_PARAM_RESOURCE(res)
856 ZEND_PARSE_PARAMETERS_END();
857
858 PHP_STREAM_TO_ZVAL(stream, res);
859
860 FG(pclose_wait) = 1;
861 zend_list_close(stream->res);
862 FG(pclose_wait) = 0;
863 RETURN_LONG(FG(pclose_ret));
864 }
865 /* }}} */
866
867 /* {{{ Test for end-of-file on a file pointer */
PHP_FUNCTION(feof)868 PHPAPI PHP_FUNCTION(feof)
869 {
870 zval *res;
871 php_stream *stream;
872
873 ZEND_PARSE_PARAMETERS_START(1, 1)
874 Z_PARAM_RESOURCE(res)
875 ZEND_PARSE_PARAMETERS_END();
876
877 PHP_STREAM_TO_ZVAL(stream, res);
878
879 if (php_stream_eof(stream)) {
880 RETURN_TRUE;
881 } else {
882 RETURN_FALSE;
883 }
884 }
885 /* }}} */
886
887 /* {{{ Get a line from file pointer */
PHP_FUNCTION(fgets)888 PHPAPI PHP_FUNCTION(fgets)
889 {
890 zval *res;
891 zend_long len = 1024;
892 bool len_is_null = 1;
893 char *buf = NULL;
894 size_t line_len = 0;
895 zend_string *str;
896 php_stream *stream;
897
898 ZEND_PARSE_PARAMETERS_START(1, 2)
899 Z_PARAM_RESOURCE(res)
900 Z_PARAM_OPTIONAL
901 Z_PARAM_LONG_OR_NULL(len, len_is_null)
902 ZEND_PARSE_PARAMETERS_END();
903
904 PHP_STREAM_TO_ZVAL(stream, res);
905
906 if (len_is_null) {
907 /* ask streams to give us a buffer of an appropriate size */
908 buf = php_stream_get_line(stream, NULL, 0, &line_len);
909 if (buf == NULL) {
910 RETURN_FALSE;
911 }
912 // TODO: avoid reallocation ???
913 RETVAL_STRINGL(buf, line_len);
914 efree(buf);
915 } else {
916 if (len <= 0) {
917 zend_argument_value_error(2, "must be greater than 0");
918 RETURN_THROWS();
919 }
920
921 str = zend_string_alloc(len, 0);
922 if (php_stream_get_line(stream, ZSTR_VAL(str), len, &line_len) == NULL) {
923 zend_string_efree(str);
924 RETURN_FALSE;
925 }
926 /* resize buffer if it's much larger than the result.
927 * Only needed if the user requested a buffer size. */
928 if (line_len < (size_t)len / 2) {
929 str = zend_string_truncate(str, line_len, 0);
930 } else {
931 ZSTR_LEN(str) = line_len;
932 }
933 RETURN_NEW_STR(str);
934 }
935 }
936 /* }}} */
937
938 /* {{{ Get a character from file pointer */
PHP_FUNCTION(fgetc)939 PHPAPI PHP_FUNCTION(fgetc)
940 {
941 zval *res;
942 php_stream *stream;
943
944 ZEND_PARSE_PARAMETERS_START(1, 1)
945 Z_PARAM_RESOURCE(res)
946 ZEND_PARSE_PARAMETERS_END();
947
948 PHP_STREAM_TO_ZVAL(stream, res);
949
950 int result = php_stream_getc(stream);
951
952 if (result == EOF) {
953 RETVAL_FALSE;
954 } else {
955 RETURN_CHAR(result);
956 }
957 }
958 /* }}} */
959
960 /* {{{ Implements a mostly ANSI compatible fscanf() */
PHP_FUNCTION(fscanf)961 PHP_FUNCTION(fscanf)
962 {
963 int result, argc = 0;
964 size_t format_len;
965 zval *args = NULL;
966 zval *file_handle;
967 char *buf, *format;
968 size_t len;
969 void *what;
970
971 ZEND_PARSE_PARAMETERS_START(2, -1)
972 Z_PARAM_RESOURCE(file_handle)
973 Z_PARAM_STRING(format, format_len)
974 Z_PARAM_VARIADIC('*', args, argc)
975 ZEND_PARSE_PARAMETERS_END();
976
977 what = zend_fetch_resource2(Z_RES_P(file_handle), "File-Handle", php_file_le_stream(), php_file_le_pstream());
978
979 /* we can't do a ZEND_VERIFY_RESOURCE(what), otherwise we end up
980 * with a leak if we have an invalid filehandle. This needs changing
981 * if the code behind ZEND_VERIFY_RESOURCE changed. - cc */
982 if (!what) {
983 RETURN_THROWS();
984 }
985
986 buf = php_stream_get_line((php_stream *) what, NULL, 0, &len);
987 if (buf == NULL) {
988 RETURN_FALSE;
989 }
990
991 result = php_sscanf_internal(buf, format, argc, args, 0, return_value);
992
993 efree(buf);
994
995 if (SCAN_ERROR_WRONG_PARAM_COUNT == result) {
996 WRONG_PARAM_COUNT;
997 }
998 }
999 /* }}} */
1000
1001 /* {{{ Binary-safe file write */
PHP_FUNCTION(fwrite)1002 PHPAPI PHP_FUNCTION(fwrite)
1003 {
1004 zval *res;
1005 char *input;
1006 size_t inputlen;
1007 ssize_t ret;
1008 size_t num_bytes;
1009 zend_long maxlen = 0;
1010 bool maxlen_is_null = 1;
1011 php_stream *stream;
1012
1013 ZEND_PARSE_PARAMETERS_START(2, 3)
1014 Z_PARAM_RESOURCE(res)
1015 Z_PARAM_STRING(input, inputlen)
1016 Z_PARAM_OPTIONAL
1017 Z_PARAM_LONG_OR_NULL(maxlen, maxlen_is_null)
1018 ZEND_PARSE_PARAMETERS_END();
1019
1020 if (maxlen_is_null) {
1021 num_bytes = inputlen;
1022 } else if (maxlen <= 0) {
1023 num_bytes = 0;
1024 } else {
1025 num_bytes = MIN((size_t) maxlen, inputlen);
1026 }
1027
1028 if (!num_bytes) {
1029 RETURN_LONG(0);
1030 }
1031
1032 PHP_STREAM_TO_ZVAL(stream, res);
1033
1034 ret = php_stream_write(stream, input, num_bytes);
1035 if (ret < 0) {
1036 RETURN_FALSE;
1037 }
1038
1039 RETURN_LONG(ret);
1040 }
1041 /* }}} */
1042
1043 /* {{{ Flushes output */
PHP_FUNCTION(fflush)1044 PHPAPI PHP_FUNCTION(fflush)
1045 {
1046 zval *res;
1047 int ret;
1048 php_stream *stream;
1049
1050 ZEND_PARSE_PARAMETERS_START(1, 1)
1051 Z_PARAM_RESOURCE(res)
1052 ZEND_PARSE_PARAMETERS_END();
1053
1054 PHP_STREAM_TO_ZVAL(stream, res);
1055
1056 ret = php_stream_flush(stream);
1057 if (ret) {
1058 RETURN_FALSE;
1059 }
1060 RETURN_TRUE;
1061 }
1062 /* }}} */
1063
1064 /* {{{ Rewind the position of a file pointer */
PHP_FUNCTION(rewind)1065 PHPAPI PHP_FUNCTION(rewind)
1066 {
1067 zval *res;
1068 php_stream *stream;
1069
1070 ZEND_PARSE_PARAMETERS_START(1, 1)
1071 Z_PARAM_RESOURCE(res)
1072 ZEND_PARSE_PARAMETERS_END();
1073
1074 PHP_STREAM_TO_ZVAL(stream, res);
1075
1076 if (-1 == php_stream_rewind(stream)) {
1077 RETURN_FALSE;
1078 }
1079 RETURN_TRUE;
1080 }
1081 /* }}} */
1082
1083 /* {{{ Get file pointer's read/write position */
PHP_FUNCTION(ftell)1084 PHPAPI PHP_FUNCTION(ftell)
1085 {
1086 zval *res;
1087 zend_long ret;
1088 php_stream *stream;
1089
1090 ZEND_PARSE_PARAMETERS_START(1, 1)
1091 Z_PARAM_RESOURCE(res)
1092 ZEND_PARSE_PARAMETERS_END();
1093
1094 PHP_STREAM_TO_ZVAL(stream, res);
1095
1096 ret = php_stream_tell(stream);
1097 if (ret == -1) {
1098 RETURN_FALSE;
1099 }
1100 RETURN_LONG(ret);
1101 }
1102 /* }}} */
1103
1104 /* {{{ Seek on a file pointer */
PHP_FUNCTION(fseek)1105 PHPAPI PHP_FUNCTION(fseek)
1106 {
1107 zval *res;
1108 zend_long offset, whence = SEEK_SET;
1109 php_stream *stream;
1110
1111 ZEND_PARSE_PARAMETERS_START(2, 3)
1112 Z_PARAM_RESOURCE(res)
1113 Z_PARAM_LONG(offset)
1114 Z_PARAM_OPTIONAL
1115 Z_PARAM_LONG(whence)
1116 ZEND_PARSE_PARAMETERS_END();
1117
1118 PHP_STREAM_TO_ZVAL(stream, res);
1119
1120 RETURN_LONG(php_stream_seek(stream, offset, (int) whence));
1121 }
1122 /* }}} */
1123
1124 /* {{{ php_mkdir */
1125
1126 /* DEPRECATED APIs: Use php_stream_mkdir() instead */
php_mkdir_ex(const char * dir,zend_long mode,int options)1127 PHPAPI int php_mkdir_ex(const char *dir, zend_long mode, int options)
1128 {
1129 int ret;
1130
1131 if (php_check_open_basedir(dir)) {
1132 return -1;
1133 }
1134
1135 if ((ret = VCWD_MKDIR(dir, (mode_t)mode)) < 0 && (options & REPORT_ERRORS)) {
1136 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1137 }
1138
1139 return ret;
1140 }
1141
php_mkdir(const char * dir,zend_long mode)1142 PHPAPI int php_mkdir(const char *dir, zend_long mode)
1143 {
1144 return php_mkdir_ex(dir, mode, REPORT_ERRORS);
1145 }
1146 /* }}} */
1147
1148 /* {{{ Create a directory */
PHP_FUNCTION(mkdir)1149 PHP_FUNCTION(mkdir)
1150 {
1151 char *dir;
1152 size_t dir_len;
1153 zval *zcontext = NULL;
1154 zend_long mode = 0777;
1155 bool recursive = 0;
1156 php_stream_context *context;
1157
1158 ZEND_PARSE_PARAMETERS_START(1, 4)
1159 Z_PARAM_PATH(dir, dir_len)
1160 Z_PARAM_OPTIONAL
1161 Z_PARAM_LONG(mode)
1162 Z_PARAM_BOOL(recursive)
1163 Z_PARAM_RESOURCE_OR_NULL(zcontext)
1164 ZEND_PARSE_PARAMETERS_END();
1165
1166 context = php_stream_context_from_zval(zcontext, 0);
1167
1168 RETURN_BOOL(php_stream_mkdir(dir, (int)mode, (recursive ? PHP_STREAM_MKDIR_RECURSIVE : 0) | REPORT_ERRORS, context));
1169 }
1170 /* }}} */
1171
1172 /* {{{ Remove a directory */
PHP_FUNCTION(rmdir)1173 PHP_FUNCTION(rmdir)
1174 {
1175 char *dir;
1176 size_t dir_len;
1177 zval *zcontext = NULL;
1178 php_stream_context *context;
1179
1180 ZEND_PARSE_PARAMETERS_START(1, 2)
1181 Z_PARAM_PATH(dir, dir_len)
1182 Z_PARAM_OPTIONAL
1183 Z_PARAM_RESOURCE_OR_NULL(zcontext)
1184 ZEND_PARSE_PARAMETERS_END();
1185
1186 context = php_stream_context_from_zval(zcontext, 0);
1187
1188 RETURN_BOOL(php_stream_rmdir(dir, REPORT_ERRORS, context));
1189 }
1190 /* }}} */
1191
1192 /* {{{ Output a file or a URL */
PHP_FUNCTION(readfile)1193 PHP_FUNCTION(readfile)
1194 {
1195 char *filename;
1196 size_t filename_len;
1197 size_t size = 0;
1198 bool use_include_path = 0;
1199 zval *zcontext = NULL;
1200 php_stream *stream;
1201 php_stream_context *context = NULL;
1202
1203 ZEND_PARSE_PARAMETERS_START(1, 3)
1204 Z_PARAM_PATH(filename, filename_len)
1205 Z_PARAM_OPTIONAL
1206 Z_PARAM_BOOL(use_include_path)
1207 Z_PARAM_RESOURCE_OR_NULL(zcontext)
1208 ZEND_PARSE_PARAMETERS_END();
1209
1210 context = php_stream_context_from_zval(zcontext, 0);
1211
1212 stream = php_stream_open_wrapper_ex(filename, "rb", (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context);
1213 if (stream) {
1214 size = php_stream_passthru(stream);
1215 php_stream_close(stream);
1216 RETURN_LONG(size);
1217 }
1218
1219 RETURN_FALSE;
1220 }
1221 /* }}} */
1222
1223 /* {{{ Return or change the umask */
PHP_FUNCTION(umask)1224 PHP_FUNCTION(umask)
1225 {
1226 zend_long mask = 0;
1227 bool mask_is_null = 1;
1228 int oldumask;
1229
1230 ZEND_PARSE_PARAMETERS_START(0, 1)
1231 Z_PARAM_OPTIONAL
1232 Z_PARAM_LONG_OR_NULL(mask, mask_is_null)
1233 ZEND_PARSE_PARAMETERS_END();
1234
1235 oldumask = umask(077);
1236
1237 if (BG(umask) == -1) {
1238 BG(umask) = oldumask;
1239 }
1240
1241 if (mask_is_null) {
1242 umask(oldumask);
1243 } else {
1244 umask((int) mask);
1245 }
1246
1247 RETURN_LONG(oldumask);
1248 }
1249 /* }}} */
1250
1251 /* {{{ Output all remaining data from a file pointer */
PHP_FUNCTION(fpassthru)1252 PHPAPI PHP_FUNCTION(fpassthru)
1253 {
1254 zval *res;
1255 size_t size;
1256 php_stream *stream;
1257
1258 ZEND_PARSE_PARAMETERS_START(1, 1)
1259 Z_PARAM_RESOURCE(res)
1260 ZEND_PARSE_PARAMETERS_END();
1261
1262 PHP_STREAM_TO_ZVAL(stream, res);
1263
1264 size = php_stream_passthru(stream);
1265 RETURN_LONG(size);
1266 }
1267 /* }}} */
1268
1269 /* {{{ Rename a file */
PHP_FUNCTION(rename)1270 PHP_FUNCTION(rename)
1271 {
1272 char *old_name, *new_name;
1273 size_t old_name_len, new_name_len;
1274 zval *zcontext = NULL;
1275 php_stream_wrapper *wrapper;
1276 php_stream_context *context;
1277
1278 ZEND_PARSE_PARAMETERS_START(2, 3)
1279 Z_PARAM_PATH(old_name, old_name_len)
1280 Z_PARAM_PATH(new_name, new_name_len)
1281 Z_PARAM_OPTIONAL
1282 Z_PARAM_RESOURCE_OR_NULL(zcontext)
1283 ZEND_PARSE_PARAMETERS_END();
1284
1285 wrapper = php_stream_locate_url_wrapper(old_name, NULL, 0);
1286
1287 if (!wrapper || !wrapper->wops) {
1288 php_error_docref(NULL, E_WARNING, "Unable to locate stream wrapper");
1289 RETURN_FALSE;
1290 }
1291
1292 if (!wrapper->wops->rename) {
1293 php_error_docref(NULL, E_WARNING, "%s wrapper does not support renaming", wrapper->wops->label ? wrapper->wops->label : "Source");
1294 RETURN_FALSE;
1295 }
1296
1297 if (wrapper != php_stream_locate_url_wrapper(new_name, NULL, 0)) {
1298 php_error_docref(NULL, E_WARNING, "Cannot rename a file across wrapper types");
1299 RETURN_FALSE;
1300 }
1301
1302 context = php_stream_context_from_zval(zcontext, 0);
1303
1304 RETURN_BOOL(wrapper->wops->rename(wrapper, old_name, new_name, 0, context));
1305 }
1306 /* }}} */
1307
1308 /* {{{ Delete a file */
PHP_FUNCTION(unlink)1309 PHP_FUNCTION(unlink)
1310 {
1311 char *filename;
1312 size_t filename_len;
1313 php_stream_wrapper *wrapper;
1314 zval *zcontext = NULL;
1315 php_stream_context *context = NULL;
1316
1317 ZEND_PARSE_PARAMETERS_START(1, 2)
1318 Z_PARAM_PATH(filename, filename_len)
1319 Z_PARAM_OPTIONAL
1320 Z_PARAM_RESOURCE_OR_NULL(zcontext)
1321 ZEND_PARSE_PARAMETERS_END();
1322
1323 context = php_stream_context_from_zval(zcontext, 0);
1324
1325 wrapper = php_stream_locate_url_wrapper(filename, NULL, 0);
1326
1327 if (!wrapper || !wrapper->wops) {
1328 php_error_docref(NULL, E_WARNING, "Unable to locate stream wrapper");
1329 RETURN_FALSE;
1330 }
1331
1332 if (!wrapper->wops->unlink) {
1333 php_error_docref(NULL, E_WARNING, "%s does not allow unlinking", wrapper->wops->label ? wrapper->wops->label : "Wrapper");
1334 RETURN_FALSE;
1335 }
1336 RETURN_BOOL(wrapper->wops->unlink(wrapper, filename, REPORT_ERRORS, context));
1337 }
1338 /* }}} */
1339
PHP_FUNCTION(fsync)1340 PHP_FUNCTION(fsync)
1341 {
1342 zval *res;
1343 php_stream *stream;
1344
1345 ZEND_PARSE_PARAMETERS_START(1, 1)
1346 Z_PARAM_RESOURCE(res)
1347 ZEND_PARSE_PARAMETERS_END();
1348
1349 PHP_STREAM_TO_ZVAL(stream, res);
1350
1351 if (!php_stream_sync_supported(stream)) {
1352 php_error_docref(NULL, E_WARNING, "Can't fsync this stream!");
1353 RETURN_FALSE;
1354 }
1355
1356 RETURN_BOOL(php_stream_sync(stream, /* data_only */ 0) == 0);
1357 }
1358
PHP_FUNCTION(fdatasync)1359 PHP_FUNCTION(fdatasync)
1360 {
1361 zval *res;
1362 php_stream *stream;
1363
1364 ZEND_PARSE_PARAMETERS_START(1, 1)
1365 Z_PARAM_RESOURCE(res)
1366 ZEND_PARSE_PARAMETERS_END();
1367
1368 PHP_STREAM_TO_ZVAL(stream, res);
1369
1370 if (!php_stream_sync_supported(stream)) {
1371 php_error_docref(NULL, E_WARNING, "Can't fsync this stream!");
1372 RETURN_FALSE;
1373 }
1374
1375 RETURN_BOOL(php_stream_sync(stream, /* data_only */ 1) == 0);
1376 }
1377
1378 /* {{{ Truncate file to 'size' length */
PHP_FUNCTION(ftruncate)1379 PHP_FUNCTION(ftruncate)
1380 {
1381 zval *fp;
1382 zend_long size;
1383 php_stream *stream;
1384
1385 ZEND_PARSE_PARAMETERS_START(2, 2)
1386 Z_PARAM_RESOURCE(fp)
1387 Z_PARAM_LONG(size)
1388 ZEND_PARSE_PARAMETERS_END();
1389
1390 if (size < 0) {
1391 zend_argument_value_error(2, "must be greater than or equal to 0");
1392 RETURN_THROWS();
1393 }
1394
1395 PHP_STREAM_TO_ZVAL(stream, fp);
1396
1397 if (!php_stream_truncate_supported(stream)) {
1398 php_error_docref(NULL, E_WARNING, "Can't truncate this stream!");
1399 RETURN_FALSE;
1400 }
1401
1402 RETURN_BOOL(0 == php_stream_truncate_set_size(stream, size));
1403 }
1404 /* }}} */
php_fstat(php_stream * stream,zval * return_value)1405 PHPAPI void php_fstat(php_stream *stream, zval *return_value)
1406 {
1407 php_stream_statbuf stat_ssb;
1408 zval stat_dev, stat_ino, stat_mode, stat_nlink, stat_uid, stat_gid, stat_rdev,
1409 stat_size, stat_atime, stat_mtime, stat_ctime, stat_blksize, stat_blocks;
1410 char *stat_sb_names[13] = {
1411 "dev", "ino", "mode", "nlink", "uid", "gid", "rdev",
1412 "size", "atime", "mtime", "ctime", "blksize", "blocks"
1413 };
1414
1415 if (php_stream_stat(stream, &stat_ssb)) {
1416 RETURN_FALSE;
1417 }
1418
1419 array_init(return_value);
1420
1421 ZVAL_LONG(&stat_dev, stat_ssb.sb.st_dev);
1422 ZVAL_LONG(&stat_ino, stat_ssb.sb.st_ino);
1423 ZVAL_LONG(&stat_mode, stat_ssb.sb.st_mode);
1424 ZVAL_LONG(&stat_nlink, stat_ssb.sb.st_nlink);
1425 ZVAL_LONG(&stat_uid, stat_ssb.sb.st_uid);
1426 ZVAL_LONG(&stat_gid, stat_ssb.sb.st_gid);
1427 #ifdef HAVE_STRUCT_STAT_ST_RDEV
1428 ZVAL_LONG(&stat_rdev, stat_ssb.sb.st_rdev);
1429 #else
1430 ZVAL_LONG(&stat_rdev, -1);
1431 #endif
1432 ZVAL_LONG(&stat_size, stat_ssb.sb.st_size);
1433 ZVAL_LONG(&stat_atime, stat_ssb.sb.st_atime);
1434 ZVAL_LONG(&stat_mtime, stat_ssb.sb.st_mtime);
1435 ZVAL_LONG(&stat_ctime, stat_ssb.sb.st_ctime);
1436 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
1437 ZVAL_LONG(&stat_blksize, stat_ssb.sb.st_blksize);
1438 #else
1439 ZVAL_LONG(&stat_blksize,-1);
1440 #endif
1441 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
1442 ZVAL_LONG(&stat_blocks, stat_ssb.sb.st_blocks);
1443 #else
1444 ZVAL_LONG(&stat_blocks,-1);
1445 #endif
1446 /* Store numeric indexes in proper order */
1447 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_dev);
1448 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_ino);
1449 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_mode);
1450 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_nlink);
1451 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_uid);
1452 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_gid);
1453 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_rdev);
1454 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_size);
1455 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_atime);
1456 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_mtime);
1457 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_ctime);
1458 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_blksize);
1459 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_blocks);
1460
1461 /* Store string indexes referencing the same zval*/
1462 zend_hash_str_add_new(Z_ARRVAL_P(return_value), stat_sb_names[0], strlen(stat_sb_names[0]), &stat_dev);
1463 zend_hash_str_add_new(Z_ARRVAL_P(return_value), stat_sb_names[1], strlen(stat_sb_names[1]), &stat_ino);
1464 zend_hash_str_add_new(Z_ARRVAL_P(return_value), stat_sb_names[2], strlen(stat_sb_names[2]), &stat_mode);
1465 zend_hash_str_add_new(Z_ARRVAL_P(return_value), stat_sb_names[3], strlen(stat_sb_names[3]), &stat_nlink);
1466 zend_hash_str_add_new(Z_ARRVAL_P(return_value), stat_sb_names[4], strlen(stat_sb_names[4]), &stat_uid);
1467 zend_hash_str_add_new(Z_ARRVAL_P(return_value), stat_sb_names[5], strlen(stat_sb_names[5]), &stat_gid);
1468 zend_hash_str_add_new(Z_ARRVAL_P(return_value), stat_sb_names[6], strlen(stat_sb_names[6]), &stat_rdev);
1469 zend_hash_str_add_new(Z_ARRVAL_P(return_value), stat_sb_names[7], strlen(stat_sb_names[7]), &stat_size);
1470 zend_hash_str_add_new(Z_ARRVAL_P(return_value), stat_sb_names[8], strlen(stat_sb_names[8]), &stat_atime);
1471 zend_hash_str_add_new(Z_ARRVAL_P(return_value), stat_sb_names[9], strlen(stat_sb_names[9]), &stat_mtime);
1472 zend_hash_str_add_new(Z_ARRVAL_P(return_value), stat_sb_names[10], strlen(stat_sb_names[10]), &stat_ctime);
1473 zend_hash_str_add_new(Z_ARRVAL_P(return_value), stat_sb_names[11], strlen(stat_sb_names[11]), &stat_blksize);
1474 zend_hash_str_add_new(Z_ARRVAL_P(return_value), stat_sb_names[12], strlen(stat_sb_names[12]), &stat_blocks);
1475 }
1476
1477 /* {{{ Stat() on a filehandle */
PHP_FUNCTION(fstat)1478 PHP_FUNCTION(fstat)
1479 {
1480 zval *fp;
1481 php_stream *stream;
1482
1483 ZEND_PARSE_PARAMETERS_START(1, 1)
1484 Z_PARAM_RESOURCE(fp)
1485 ZEND_PARSE_PARAMETERS_END();
1486
1487 PHP_STREAM_TO_ZVAL(stream, fp);
1488
1489 php_fstat(stream, return_value);
1490 }
1491 /* }}} */
1492
1493 /* {{{ Copy a file */
PHP_FUNCTION(copy)1494 PHP_FUNCTION(copy)
1495 {
1496 char *source, *target;
1497 size_t source_len, target_len;
1498 zval *zcontext = NULL;
1499 php_stream_context *context;
1500
1501 ZEND_PARSE_PARAMETERS_START(2, 3)
1502 Z_PARAM_PATH(source, source_len)
1503 Z_PARAM_PATH(target, target_len)
1504 Z_PARAM_OPTIONAL
1505 Z_PARAM_RESOURCE_OR_NULL(zcontext)
1506 ZEND_PARSE_PARAMETERS_END();
1507
1508 if (php_stream_locate_url_wrapper(source, NULL, 0) == &php_plain_files_wrapper && php_check_open_basedir(source)) {
1509 RETURN_FALSE;
1510 }
1511
1512 context = php_stream_context_from_zval(zcontext, 0);
1513
1514 if (php_copy_file_ctx(source, target, 0, context) == SUCCESS) {
1515 RETURN_TRUE;
1516 } else {
1517 RETURN_FALSE;
1518 }
1519 }
1520 /* }}} */
1521
1522 /* {{{ php_copy_file */
php_copy_file(const char * src,const char * dest)1523 PHPAPI int php_copy_file(const char *src, const char *dest)
1524 {
1525 return php_copy_file_ctx(src, dest, 0, NULL);
1526 }
1527 /* }}} */
1528
1529 /* {{{ php_copy_file_ex */
php_copy_file_ex(const char * src,const char * dest,int src_flg)1530 PHPAPI int php_copy_file_ex(const char *src, const char *dest, int src_flg)
1531 {
1532 return php_copy_file_ctx(src, dest, src_flg, NULL);
1533 }
1534 /* }}} */
1535
1536 /* {{{ php_copy_file_ctx */
php_copy_file_ctx(const char * src,const char * dest,int src_flg,php_stream_context * ctx)1537 PHPAPI int php_copy_file_ctx(const char *src, const char *dest, int src_flg, php_stream_context *ctx)
1538 {
1539 php_stream *srcstream = NULL, *deststream = NULL;
1540 int ret = FAILURE;
1541 php_stream_statbuf src_s, dest_s;
1542 int src_stat_flags = (src_flg & STREAM_DISABLE_OPEN_BASEDIR) ? PHP_STREAM_URL_STAT_IGNORE_OPEN_BASEDIR : 0;
1543
1544 switch (php_stream_stat_path_ex(src, src_stat_flags, &src_s, ctx)) {
1545 case -1:
1546 /* non-statable stream */
1547 goto safe_to_copy;
1548 break;
1549 case 0:
1550 break;
1551 default: /* failed to stat file, does not exist? */
1552 return ret;
1553 }
1554 if (S_ISDIR(src_s.sb.st_mode)) {
1555 php_error_docref(NULL, E_WARNING, "The first argument to copy() function cannot be a directory");
1556 return FAILURE;
1557 }
1558
1559 switch (php_stream_stat_path_ex(dest, PHP_STREAM_URL_STAT_QUIET, &dest_s, ctx)) {
1560 case -1:
1561 /* non-statable stream */
1562 goto safe_to_copy;
1563 break;
1564 case 0:
1565 break;
1566 default: /* failed to stat file, does not exist? */
1567 return ret;
1568 }
1569 if (S_ISDIR(dest_s.sb.st_mode)) {
1570 php_error_docref(NULL, E_WARNING, "The second argument to copy() function cannot be a directory");
1571 return FAILURE;
1572 }
1573 if (!src_s.sb.st_ino || !dest_s.sb.st_ino) {
1574 goto no_stat;
1575 }
1576 if (src_s.sb.st_ino == dest_s.sb.st_ino && src_s.sb.st_dev == dest_s.sb.st_dev) {
1577 return ret;
1578 } else {
1579 goto safe_to_copy;
1580 }
1581 no_stat:
1582 {
1583 char *sp, *dp;
1584 int res;
1585
1586 if ((sp = expand_filepath(src, NULL)) == NULL) {
1587 return ret;
1588 }
1589 if ((dp = expand_filepath(dest, NULL)) == NULL) {
1590 efree(sp);
1591 goto safe_to_copy;
1592 }
1593
1594 res =
1595 #ifndef PHP_WIN32
1596 !strcmp(sp, dp);
1597 #else
1598 !strcasecmp(sp, dp);
1599 #endif
1600
1601 efree(sp);
1602 efree(dp);
1603 if (res) {
1604 return ret;
1605 }
1606 }
1607 safe_to_copy:
1608
1609 srcstream = php_stream_open_wrapper_ex(src, "rb", src_flg | REPORT_ERRORS, NULL, ctx);
1610
1611 if (!srcstream) {
1612 return ret;
1613 }
1614
1615 deststream = php_stream_open_wrapper_ex(dest, "wb", REPORT_ERRORS, NULL, ctx);
1616
1617 if (srcstream && deststream) {
1618 ret = php_stream_copy_to_stream_ex(srcstream, deststream, PHP_STREAM_COPY_ALL, NULL);
1619 }
1620 if (srcstream) {
1621 php_stream_close(srcstream);
1622 }
1623 if (deststream) {
1624 php_stream_close(deststream);
1625 }
1626 return ret;
1627 }
1628 /* }}} */
1629
1630 /* {{{ Binary-safe file read */
PHP_FUNCTION(fread)1631 PHPAPI PHP_FUNCTION(fread)
1632 {
1633 zval *res;
1634 zend_long len;
1635 php_stream *stream;
1636 zend_string *str;
1637
1638 ZEND_PARSE_PARAMETERS_START(2, 2)
1639 Z_PARAM_RESOURCE(res)
1640 Z_PARAM_LONG(len)
1641 ZEND_PARSE_PARAMETERS_END();
1642
1643 PHP_STREAM_TO_ZVAL(stream, res);
1644
1645 if (len <= 0) {
1646 zend_argument_value_error(2, "must be greater than 0");
1647 RETURN_THROWS();
1648 }
1649
1650 str = php_stream_read_to_str(stream, len);
1651 if (!str) {
1652 zval_ptr_dtor_str(return_value);
1653 RETURN_FALSE;
1654 }
1655
1656 RETURN_STR(str);
1657 }
1658 /* }}} */
1659
php_fgetcsv_lookup_trailing_spaces(const char * ptr,size_t len)1660 static const char *php_fgetcsv_lookup_trailing_spaces(const char *ptr, size_t len) /* {{{ */
1661 {
1662 int inc_len;
1663 unsigned char last_chars[2] = { 0, 0 };
1664
1665 while (len > 0) {
1666 inc_len = (*ptr == '\0' ? 1 : php_mblen(ptr, len));
1667 switch (inc_len) {
1668 case -2:
1669 case -1:
1670 inc_len = 1;
1671 php_mb_reset();
1672 break;
1673 case 0:
1674 goto quit_loop;
1675 case 1:
1676 default:
1677 last_chars[0] = last_chars[1];
1678 last_chars[1] = *ptr;
1679 break;
1680 }
1681 ptr += inc_len;
1682 len -= inc_len;
1683 }
1684 quit_loop:
1685 switch (last_chars[1]) {
1686 case '\n':
1687 if (last_chars[0] == '\r') {
1688 return ptr - 2;
1689 }
1690 ZEND_FALLTHROUGH;
1691 case '\r':
1692 return ptr - 1;
1693 }
1694 return ptr;
1695 }
1696 /* }}} */
1697
1698 #define FPUTCSV_FLD_CHK(c) memchr(ZSTR_VAL(field_str), c, ZSTR_LEN(field_str))
1699
1700 /* {{{ Format line as CSV and write to file pointer */
PHP_FUNCTION(fputcsv)1701 PHP_FUNCTION(fputcsv)
1702 {
1703 char delimiter = ','; /* allow this to be set as parameter */
1704 char enclosure = '"'; /* allow this to be set as parameter */
1705 int escape_char = (unsigned char) '\\'; /* allow this to be set as parameter */
1706 php_stream *stream;
1707 zval *fp = NULL, *fields = NULL;
1708 ssize_t ret;
1709 char *delimiter_str = NULL, *enclosure_str = NULL, *escape_str = NULL;
1710 size_t delimiter_str_len = 0, enclosure_str_len = 0, escape_str_len = 0;
1711 zend_string *eol_str = NULL;
1712
1713 ZEND_PARSE_PARAMETERS_START(2, 6)
1714 Z_PARAM_RESOURCE(fp)
1715 Z_PARAM_ARRAY(fields)
1716 Z_PARAM_OPTIONAL
1717 Z_PARAM_STRING(delimiter_str, delimiter_str_len)
1718 Z_PARAM_STRING(enclosure_str, enclosure_str_len)
1719 Z_PARAM_STRING(escape_str, escape_str_len)
1720 Z_PARAM_STR_OR_NULL(eol_str)
1721 ZEND_PARSE_PARAMETERS_END();
1722
1723 if (delimiter_str != NULL) {
1724 /* Make sure that there is at least one character in string */
1725 if (delimiter_str_len != 1) {
1726 zend_argument_value_error(3, "must be a single character");
1727 RETURN_THROWS();
1728 }
1729
1730 /* use first character from string */
1731 delimiter = *delimiter_str;
1732 }
1733
1734 if (enclosure_str != NULL) {
1735 if (enclosure_str_len != 1) {
1736 zend_argument_value_error(4, "must be a single character");
1737 RETURN_THROWS();
1738 }
1739 /* use first character from string */
1740 enclosure = *enclosure_str;
1741 }
1742
1743 if (escape_str != NULL) {
1744 if (escape_str_len > 1) {
1745 zend_argument_value_error(5, "must be empty or a single character");
1746 RETURN_THROWS();
1747 }
1748 if (escape_str_len < 1) {
1749 escape_char = PHP_CSV_NO_ESCAPE;
1750 } else {
1751 /* use first character from string */
1752 escape_char = (unsigned char) *escape_str;
1753 }
1754 }
1755
1756 PHP_STREAM_TO_ZVAL(stream, fp);
1757
1758 ret = php_fputcsv(stream, fields, delimiter, enclosure, escape_char, eol_str);
1759 if (ret < 0) {
1760 RETURN_FALSE;
1761 }
1762 RETURN_LONG(ret);
1763 }
1764 /* }}} */
1765
1766 /* {{{ PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char, zend_string *eol_str) */
php_fputcsv(php_stream * stream,zval * fields,char delimiter,char enclosure,int escape_char,zend_string * eol_str)1767 PHPAPI ssize_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, int escape_char, zend_string *eol_str)
1768 {
1769 uint32_t count, i = 0;
1770 size_t ret;
1771 zval *field_tmp;
1772 smart_str csvline = {0};
1773
1774 ZEND_ASSERT((escape_char >= 0 && escape_char <= UCHAR_MAX) || escape_char == PHP_CSV_NO_ESCAPE);
1775 count = zend_hash_num_elements(Z_ARRVAL_P(fields));
1776 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(fields), field_tmp) {
1777 zend_string *tmp_field_str;
1778 zend_string *field_str = zval_get_tmp_string(field_tmp, &tmp_field_str);
1779
1780 /* enclose a field that contains a delimiter, an enclosure character, or a newline */
1781 if (FPUTCSV_FLD_CHK(delimiter) ||
1782 FPUTCSV_FLD_CHK(enclosure) ||
1783 (escape_char != PHP_CSV_NO_ESCAPE && FPUTCSV_FLD_CHK(escape_char)) ||
1784 FPUTCSV_FLD_CHK('\n') ||
1785 FPUTCSV_FLD_CHK('\r') ||
1786 FPUTCSV_FLD_CHK('\t') ||
1787 FPUTCSV_FLD_CHK(' ')
1788 ) {
1789 char *ch = ZSTR_VAL(field_str);
1790 char *end = ch + ZSTR_LEN(field_str);
1791 int escaped = 0;
1792
1793 smart_str_appendc(&csvline, enclosure);
1794 while (ch < end) {
1795 if (escape_char != PHP_CSV_NO_ESCAPE && *ch == escape_char) {
1796 escaped = 1;
1797 } else if (!escaped && *ch == enclosure) {
1798 smart_str_appendc(&csvline, enclosure);
1799 } else {
1800 escaped = 0;
1801 }
1802 smart_str_appendc(&csvline, *ch);
1803 ch++;
1804 }
1805 smart_str_appendc(&csvline, enclosure);
1806 } else {
1807 smart_str_append(&csvline, field_str);
1808 }
1809
1810 if (++i != count) {
1811 smart_str_appendl(&csvline, &delimiter, 1);
1812 }
1813 zend_tmp_string_release(tmp_field_str);
1814 } ZEND_HASH_FOREACH_END();
1815
1816 if (eol_str) {
1817 smart_str_append(&csvline, eol_str);
1818 } else {
1819 smart_str_appendc(&csvline, '\n');
1820 }
1821 smart_str_0(&csvline);
1822
1823 ret = php_stream_write(stream, ZSTR_VAL(csvline.s), ZSTR_LEN(csvline.s));
1824
1825 smart_str_free(&csvline);
1826
1827 return ret;
1828 }
1829 /* }}} */
1830
1831 /* {{{ Get line from file pointer and parse for CSV fields */
PHP_FUNCTION(fgetcsv)1832 PHP_FUNCTION(fgetcsv)
1833 {
1834 char delimiter = ','; /* allow this to be set as parameter */
1835 char enclosure = '"'; /* allow this to be set as parameter */
1836 int escape = (unsigned char) '\\';
1837
1838 zend_long len = 0;
1839 size_t buf_len;
1840 char *buf;
1841 php_stream *stream;
1842
1843 {
1844 zval *fd;
1845 bool len_is_null = 1;
1846 char *delimiter_str = NULL;
1847 size_t delimiter_str_len = 0;
1848 char *enclosure_str = NULL;
1849 size_t enclosure_str_len = 0;
1850 char *escape_str = NULL;
1851 size_t escape_str_len = 0;
1852
1853 ZEND_PARSE_PARAMETERS_START(1, 5)
1854 Z_PARAM_RESOURCE(fd)
1855 Z_PARAM_OPTIONAL
1856 Z_PARAM_LONG_OR_NULL(len, len_is_null)
1857 Z_PARAM_STRING(delimiter_str, delimiter_str_len)
1858 Z_PARAM_STRING(enclosure_str, enclosure_str_len)
1859 Z_PARAM_STRING(escape_str, escape_str_len)
1860 ZEND_PARSE_PARAMETERS_END();
1861
1862 if (delimiter_str != NULL) {
1863 /* Make sure that there is at least one character in string */
1864 if (delimiter_str_len != 1) {
1865 zend_argument_value_error(3, "must be a single character");
1866 RETURN_THROWS();
1867 }
1868
1869 /* use first character from string */
1870 delimiter = delimiter_str[0];
1871 }
1872
1873 if (enclosure_str != NULL) {
1874 if (enclosure_str_len != 1) {
1875 zend_argument_value_error(4, "must be a single character");
1876 RETURN_THROWS();
1877 }
1878
1879 /* use first character from string */
1880 enclosure = enclosure_str[0];
1881 }
1882
1883 if (escape_str != NULL) {
1884 if (escape_str_len > 1) {
1885 zend_argument_value_error(5, "must be empty or a single character");
1886 RETURN_THROWS();
1887 }
1888
1889 if (escape_str_len < 1) {
1890 escape = PHP_CSV_NO_ESCAPE;
1891 } else {
1892 escape = (unsigned char) escape_str[0];
1893 }
1894 }
1895
1896 if (len_is_null || len == 0) {
1897 len = -1;
1898 } else if (len < 0 || len > (ZEND_LONG_MAX - 1)) {
1899 zend_argument_value_error(2, "must be between 0 and " ZEND_LONG_FMT, (ZEND_LONG_MAX - 1));
1900 RETURN_THROWS();
1901 }
1902
1903 PHP_STREAM_TO_ZVAL(stream, fd);
1904 }
1905
1906 if (len < 0) {
1907 if ((buf = php_stream_get_line(stream, NULL, 0, &buf_len)) == NULL) {
1908 RETURN_FALSE;
1909 }
1910 } else {
1911 buf = emalloc(len + 1);
1912 if (php_stream_get_line(stream, buf, len + 1, &buf_len) == NULL) {
1913 efree(buf);
1914 RETURN_FALSE;
1915 }
1916 }
1917
1918 HashTable *values = php_fgetcsv(stream, delimiter, enclosure, escape, buf_len, buf);
1919 if (values == NULL) {
1920 values = php_bc_fgetcsv_empty_line();
1921 }
1922 RETURN_ARR(values);
1923 }
1924 /* }}} */
1925
php_bc_fgetcsv_empty_line(void)1926 PHPAPI HashTable *php_bc_fgetcsv_empty_line(void)
1927 {
1928 HashTable *values = zend_new_array(1);
1929 zval tmp;
1930 ZVAL_NULL(&tmp);
1931 zend_hash_next_index_insert(values, &tmp);
1932 return values;
1933 }
1934
php_fgetcsv(php_stream * stream,char delimiter,char enclosure,int escape_char,size_t buf_len,char * buf)1935 PHPAPI HashTable *php_fgetcsv(php_stream *stream, char delimiter, char enclosure, int escape_char, size_t buf_len, char *buf) /* {{{ */
1936 {
1937 char *temp, *bptr, *line_end, *limit;
1938 size_t temp_len, line_end_len;
1939 int inc_len;
1940 bool first_field = true;
1941
1942 ZEND_ASSERT((escape_char >= 0 && escape_char <= UCHAR_MAX) || escape_char == PHP_CSV_NO_ESCAPE);
1943
1944 /* initialize internal state */
1945 php_mb_reset();
1946
1947 /* Now into new section that parses buf for delimiter/enclosure fields */
1948
1949 /* Strip trailing space from buf, saving end of line in case required for enclosure field */
1950
1951 bptr = buf;
1952 line_end = limit = (char *)php_fgetcsv_lookup_trailing_spaces(buf, buf_len);
1953 line_end_len = buf_len - (size_t)(limit - buf);
1954
1955 /* reserve workspace for building each individual field */
1956 temp_len = buf_len;
1957 temp = emalloc(temp_len + line_end_len + 1);
1958
1959 /* Initialize values HashTable */
1960 HashTable *values = zend_new_array(0);
1961
1962 /* Main loop to read CSV fields */
1963 /* NB this routine will return NULL for a blank line */
1964 do {
1965 char *comp_end, *hunk_begin;
1966 char *tptr = temp;
1967
1968 inc_len = (bptr < limit ? (*bptr == '\0' ? 1 : php_mblen(bptr, limit - bptr)): 0);
1969 if (inc_len == 1) {
1970 char *tmp = bptr;
1971 while ((*tmp != delimiter) && isspace((int)*(unsigned char *)tmp)) {
1972 tmp++;
1973 }
1974 if (*tmp == enclosure && tmp < limit) {
1975 bptr = tmp;
1976 }
1977 }
1978
1979 if (first_field && bptr == line_end) {
1980 zend_array_destroy(values);
1981 values = NULL;
1982 break;
1983 }
1984 first_field = false;
1985 /* 2. Read field, leaving bptr pointing at start of next field */
1986 if (inc_len != 0 && *bptr == enclosure) {
1987 int state = 0;
1988
1989 bptr++; /* move on to first character in field */
1990 hunk_begin = bptr;
1991
1992 /* 2A. handle enclosure delimited field */
1993 for (;;) {
1994 switch (inc_len) {
1995 case 0:
1996 switch (state) {
1997 case 2:
1998 memcpy(tptr, hunk_begin, bptr - hunk_begin - 1);
1999 tptr += (bptr - hunk_begin - 1);
2000 hunk_begin = bptr;
2001 goto quit_loop_2;
2002
2003 case 1:
2004 memcpy(tptr, hunk_begin, bptr - hunk_begin);
2005 tptr += (bptr - hunk_begin);
2006 hunk_begin = bptr;
2007 ZEND_FALLTHROUGH;
2008
2009 case 0: {
2010 if (hunk_begin != line_end) {
2011 memcpy(tptr, hunk_begin, bptr - hunk_begin);
2012 tptr += (bptr - hunk_begin);
2013 hunk_begin = bptr;
2014 }
2015
2016 /* add the embedded line end to the field */
2017 memcpy(tptr, line_end, line_end_len);
2018 tptr += line_end_len;
2019
2020 if (stream == NULL) {
2021 goto quit_loop_2;
2022 }
2023
2024 size_t new_len;
2025 char *new_buf = php_stream_get_line(stream, NULL, 0, &new_len);
2026 if (!new_buf) {
2027 /* we've got an unterminated enclosure,
2028 * assign all the data from the start of
2029 * the enclosure to end of data to the
2030 * last element */
2031 goto quit_loop_2;
2032 }
2033
2034 temp_len += new_len;
2035 char *new_temp = erealloc(temp, temp_len);
2036 tptr = new_temp + (size_t)(tptr - temp);
2037 temp = new_temp;
2038
2039 efree(buf);
2040 buf_len = new_len;
2041 bptr = buf = new_buf;
2042 hunk_begin = buf;
2043
2044 line_end = limit = (char *)php_fgetcsv_lookup_trailing_spaces(buf, buf_len);
2045 line_end_len = buf_len - (size_t)(limit - buf);
2046
2047 state = 0;
2048 } break;
2049 }
2050 break;
2051
2052 case -2:
2053 case -1:
2054 php_mb_reset();
2055 ZEND_FALLTHROUGH;
2056 case 1:
2057 /* we need to determine if the enclosure is
2058 * 'real' or is it escaped */
2059 switch (state) {
2060 case 1: /* escaped */
2061 bptr++;
2062 state = 0;
2063 break;
2064 case 2: /* embedded enclosure ? let's check it */
2065 if (*bptr != enclosure) {
2066 /* real enclosure */
2067 memcpy(tptr, hunk_begin, bptr - hunk_begin - 1);
2068 tptr += (bptr - hunk_begin - 1);
2069 hunk_begin = bptr;
2070 goto quit_loop_2;
2071 }
2072 memcpy(tptr, hunk_begin, bptr - hunk_begin);
2073 tptr += (bptr - hunk_begin);
2074 bptr++;
2075 hunk_begin = bptr;
2076 state = 0;
2077 break;
2078 default:
2079 if (*bptr == enclosure) {
2080 state = 2;
2081 } else if (escape_char != PHP_CSV_NO_ESCAPE && *bptr == escape_char) {
2082 state = 1;
2083 }
2084 bptr++;
2085 break;
2086 }
2087 break;
2088
2089 default:
2090 switch (state) {
2091 case 2:
2092 /* real enclosure */
2093 memcpy(tptr, hunk_begin, bptr - hunk_begin - 1);
2094 tptr += (bptr - hunk_begin - 1);
2095 hunk_begin = bptr;
2096 goto quit_loop_2;
2097 case 1:
2098 bptr += inc_len;
2099 memcpy(tptr, hunk_begin, bptr - hunk_begin);
2100 tptr += (bptr - hunk_begin);
2101 hunk_begin = bptr;
2102 state = 0;
2103 break;
2104 default:
2105 bptr += inc_len;
2106 break;
2107 }
2108 break;
2109 }
2110 inc_len = (bptr < limit ? (*bptr == '\0' ? 1 : php_mblen(bptr, limit - bptr)): 0);
2111 }
2112
2113 quit_loop_2:
2114 /* look up for a delimiter */
2115 for (;;) {
2116 switch (inc_len) {
2117 case 0:
2118 goto quit_loop_3;
2119
2120 case -2:
2121 case -1:
2122 inc_len = 1;
2123 php_mb_reset();
2124 ZEND_FALLTHROUGH;
2125 case 1:
2126 if (*bptr == delimiter) {
2127 goto quit_loop_3;
2128 }
2129 break;
2130 default:
2131 break;
2132 }
2133 bptr += inc_len;
2134 inc_len = (bptr < limit ? (*bptr == '\0' ? 1 : php_mblen(bptr, limit - bptr)): 0);
2135 }
2136
2137 quit_loop_3:
2138 memcpy(tptr, hunk_begin, bptr - hunk_begin);
2139 tptr += (bptr - hunk_begin);
2140 bptr += inc_len;
2141 comp_end = tptr;
2142 } else {
2143 /* 2B. Handle non-enclosure field */
2144
2145 hunk_begin = bptr;
2146
2147 for (;;) {
2148 switch (inc_len) {
2149 case 0:
2150 goto quit_loop_4;
2151 case -2:
2152 case -1:
2153 inc_len = 1;
2154 php_mb_reset();
2155 ZEND_FALLTHROUGH;
2156 case 1:
2157 if (*bptr == delimiter) {
2158 goto quit_loop_4;
2159 }
2160 break;
2161 default:
2162 break;
2163 }
2164 bptr += inc_len;
2165 inc_len = (bptr < limit ? (*bptr == '\0' ? 1 : php_mblen(bptr, limit - bptr)): 0);
2166 }
2167 quit_loop_4:
2168 memcpy(tptr, hunk_begin, bptr - hunk_begin);
2169 tptr += (bptr - hunk_begin);
2170
2171 comp_end = (char *)php_fgetcsv_lookup_trailing_spaces(temp, tptr - temp);
2172 if (*bptr == delimiter) {
2173 bptr++;
2174 }
2175 }
2176
2177 /* 3. Now pass our field back to php */
2178 *comp_end = '\0';
2179
2180 zval z_tmp;
2181 ZVAL_STRINGL(&z_tmp, temp, comp_end - temp);
2182 zend_hash_next_index_insert(values, &z_tmp);
2183 } while (inc_len > 0);
2184
2185 efree(temp);
2186 if (stream) {
2187 efree(buf);
2188 }
2189
2190 return values;
2191 }
2192 /* }}} */
2193
2194 /* {{{ Return the resolved path */
PHP_FUNCTION(realpath)2195 PHP_FUNCTION(realpath)
2196 {
2197 char *filename;
2198 size_t filename_len;
2199 char resolved_path_buff[MAXPATHLEN];
2200
2201 ZEND_PARSE_PARAMETERS_START(1, 1)
2202 Z_PARAM_PATH(filename, filename_len)
2203 ZEND_PARSE_PARAMETERS_END();
2204
2205 if (VCWD_REALPATH(filename, resolved_path_buff)) {
2206 if (php_check_open_basedir(resolved_path_buff)) {
2207 RETURN_FALSE;
2208 }
2209
2210 #ifdef ZTS
2211 if (VCWD_ACCESS(resolved_path_buff, F_OK)) {
2212 RETURN_FALSE;
2213 }
2214 #endif
2215 RETURN_STRING(resolved_path_buff);
2216 } else {
2217 RETURN_FALSE;
2218 }
2219 }
2220 /* }}} */
2221
2222 /* See http://www.w3.org/TR/html4/intro/sgmltut.html#h-3.2.2 */
2223 #define PHP_META_HTML401_CHARS "-_.:"
2224
2225 /* {{{ php_next_meta_token
2226 Tokenizes an HTML file for get_meta_tags */
php_next_meta_token(php_meta_tags_data * md)2227 php_meta_tags_token php_next_meta_token(php_meta_tags_data *md)
2228 {
2229 int ch = 0, compliment;
2230 char buff[META_DEF_BUFSIZE + 1];
2231
2232 memset((void *)buff, 0, META_DEF_BUFSIZE + 1);
2233
2234 while (md->ulc || (!php_stream_eof(md->stream) && (ch = php_stream_getc(md->stream)))) {
2235 if (php_stream_eof(md->stream)) {
2236 break;
2237 }
2238
2239 if (md->ulc) {
2240 ch = md->lc;
2241 md->ulc = 0;
2242 }
2243
2244 switch (ch) {
2245 case '<':
2246 return TOK_OPENTAG;
2247 break;
2248
2249 case '>':
2250 return TOK_CLOSETAG;
2251 break;
2252
2253 case '=':
2254 return TOK_EQUAL;
2255 break;
2256 case '/':
2257 return TOK_SLASH;
2258 break;
2259
2260 case '\'':
2261 case '"':
2262 compliment = ch;
2263 md->token_len = 0;
2264 while (!php_stream_eof(md->stream) && (ch = php_stream_getc(md->stream)) && ch != compliment && ch != '<' && ch != '>') {
2265 buff[(md->token_len)++] = ch;
2266
2267 if (md->token_len == META_DEF_BUFSIZE) {
2268 break;
2269 }
2270 }
2271
2272 if (ch == '<' || ch == '>') {
2273 /* Was just an apostrophe */
2274 md->ulc = 1;
2275 md->lc = ch;
2276 }
2277
2278 /* We don't need to alloc unless we are in a meta tag */
2279 if (md->in_meta) {
2280 md->token_data = (char *) emalloc(md->token_len + 1);
2281 memcpy(md->token_data, buff, md->token_len+1);
2282 }
2283
2284 return TOK_STRING;
2285 break;
2286
2287 case '\n':
2288 case '\r':
2289 case '\t':
2290 break;
2291
2292 case ' ':
2293 return TOK_SPACE;
2294 break;
2295
2296 default:
2297 if (isalnum(ch)) {
2298 md->token_len = 0;
2299 buff[(md->token_len)++] = ch;
2300 while (!php_stream_eof(md->stream) && (ch = php_stream_getc(md->stream)) && (isalnum(ch) || strchr(PHP_META_HTML401_CHARS, ch))) {
2301 buff[(md->token_len)++] = ch;
2302
2303 if (md->token_len == META_DEF_BUFSIZE) {
2304 break;
2305 }
2306 }
2307
2308 /* This is ugly, but we have to replace ungetc */
2309 if (!isalpha(ch) && ch != '-') {
2310 md->ulc = 1;
2311 md->lc = ch;
2312 }
2313
2314 md->token_data = (char *) emalloc(md->token_len + 1);
2315 memcpy(md->token_data, buff, md->token_len+1);
2316
2317 return TOK_ID;
2318 } else {
2319 return TOK_OTHER;
2320 }
2321 break;
2322 }
2323 }
2324
2325 return TOK_EOF;
2326 }
2327 /* }}} */
2328
2329 #ifdef HAVE_FNMATCH
2330 /* {{{ Match filename against pattern */
PHP_FUNCTION(fnmatch)2331 PHP_FUNCTION(fnmatch)
2332 {
2333 char *pattern, *filename;
2334 size_t pattern_len, filename_len;
2335 zend_long flags = 0;
2336
2337 ZEND_PARSE_PARAMETERS_START(2, 3)
2338 Z_PARAM_PATH(pattern, pattern_len)
2339 Z_PARAM_PATH(filename, filename_len)
2340 Z_PARAM_OPTIONAL
2341 Z_PARAM_LONG(flags)
2342 ZEND_PARSE_PARAMETERS_END();
2343
2344 if (filename_len >= MAXPATHLEN) {
2345 php_error_docref(NULL, E_WARNING, "Filename exceeds the maximum allowed length of %d characters", MAXPATHLEN);
2346 RETURN_FALSE;
2347 }
2348 if (pattern_len >= MAXPATHLEN) {
2349 php_error_docref(NULL, E_WARNING, "Pattern exceeds the maximum allowed length of %d characters", MAXPATHLEN);
2350 RETURN_FALSE;
2351 }
2352
2353 RETURN_BOOL( ! fnmatch( pattern, filename, (int)flags ));
2354 }
2355 /* }}} */
2356 #endif
2357
2358 /* {{{ Returns directory path used for temporary files */
PHP_FUNCTION(sys_get_temp_dir)2359 PHP_FUNCTION(sys_get_temp_dir)
2360 {
2361 ZEND_PARSE_PARAMETERS_NONE();
2362
2363 RETURN_STRING((char *)php_get_temporary_directory());
2364 }
2365 /* }}} */
2366