Coverage Report

Created: 2025-06-13 06:43

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