Coverage Report

Created: 2025-11-16 06:23

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