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