Coverage Report

Created: 2026-10-28 06:20

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