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