1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 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: Wez Furlong <wez@thebrainroom.com> |
16 : | Sara Golemon <pollita@php.net> |
17 : +----------------------------------------------------------------------+
18 : */
19 :
20 : /* $Id: streamsfuncs.c 286744 2009-08-03 15:58:18Z felipe $ */
21 :
22 : #include "php.h"
23 : #include "php_globals.h"
24 : #include "ext/standard/flock_compat.h"
25 : #include "ext/standard/file.h"
26 : #include "ext/standard/php_filestat.h"
27 : #include "php_open_temporary_file.h"
28 : #include "ext/standard/basic_functions.h"
29 : #include "php_ini.h"
30 : #include "streamsfuncs.h"
31 : #include "php_network.h"
32 : #include "php_string.h"
33 :
34 : #ifndef PHP_WIN32
35 : #define php_select(m, r, w, e, t) select(m, r, w, e, t)
36 : typedef unsigned long long php_timeout_ull;
37 : #else
38 : #include "win32/select.h"
39 : #include "win32/sockets.h"
40 : typedef unsigned __int64 php_timeout_ull;
41 : #endif
42 :
43 : static php_stream_context *decode_context_param(zval *contextresource TSRMLS_DC);
44 :
45 : /* Streams based network functions */
46 :
47 : #if HAVE_SOCKETPAIR
48 : /* {{{ proto array stream_socket_pair(int domain, int type, int protocol) U
49 : Creates a pair of connected, indistinguishable socket streams */
50 : PHP_FUNCTION(stream_socket_pair)
51 6 : {
52 : long domain, type, protocol;
53 : php_stream *s1, *s2;
54 : int pair[2];
55 :
56 6 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll",
57 : &domain, &type, &protocol)) {
58 0 : RETURN_FALSE;
59 : }
60 :
61 6 : if (0 != socketpair(domain, type, protocol, pair)) {
62 : char errbuf[256];
63 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to create sockets: [%d]: %s",
64 : php_socket_errno(), php_socket_strerror(php_socket_errno(), errbuf, sizeof(errbuf)));
65 0 : RETURN_FALSE;
66 : }
67 :
68 6 : array_init(return_value);
69 :
70 6 : s1 = php_stream_sock_open_from_socket(pair[0], 0);
71 6 : s2 = php_stream_sock_open_from_socket(pair[1], 0);
72 :
73 : /* set the __exposed flag.
74 : * php_stream_to_zval() does, add_next_index_resource() does not */
75 : php_stream_auto_cleanup(s1);
76 : php_stream_auto_cleanup(s2);
77 :
78 6 : add_next_index_resource(return_value, php_stream_get_resource_id(s1));
79 6 : add_next_index_resource(return_value, php_stream_get_resource_id(s2));
80 : }
81 : /* }}} */
82 : #endif
83 :
84 : /* {{{ proto resource stream_socket_client(string remoteaddress [, long &errcode [, string &errstring [, double timeout [, long flags [, resource context]]]]]) U
85 : Open a client connection to a remote address */
86 : PHP_FUNCTION(stream_socket_client)
87 20 : {
88 : char *host;
89 : int host_len;
90 20 : zval *zerrno = NULL, *zerrstr = NULL, *zcontext = NULL;
91 20 : double timeout = FG(default_socket_timeout);
92 : php_timeout_ull conv;
93 : struct timeval tv;
94 20 : char *hashkey = NULL;
95 20 : php_stream *stream = NULL;
96 : int err;
97 20 : long flags = PHP_STREAM_CLIENT_CONNECT;
98 20 : char *errstr = NULL;
99 20 : php_stream_context *context = NULL;
100 :
101 20 : RETVAL_FALSE;
102 :
103 20 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zzdlr", &host, &host_len, &zerrno, &zerrstr, &timeout, &flags, &zcontext) == FAILURE) {
104 1 : RETURN_FALSE;
105 : }
106 :
107 19 : context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
108 :
109 19 : if (context) {
110 19 : zend_list_addref(context->rsrc_id);
111 : }
112 :
113 19 : if (flags & PHP_STREAM_CLIENT_PERSISTENT) {
114 0 : spprintf(&hashkey, 0, "stream_socket_client__%s", host);
115 : }
116 :
117 : /* prepare the timeout value for use */
118 19 : conv = (php_timeout_ull) (timeout * 1000000.0);
119 19 : tv.tv_sec = (long) (conv / 1000000);
120 19 : tv.tv_usec = conv % 1000000;
121 :
122 19 : if (zerrno) {
123 10 : zval_dtor(zerrno);
124 10 : ZVAL_LONG(zerrno, 0);
125 : }
126 19 : if (zerrstr) {
127 6 : zval_dtor(zerrstr);
128 6 : ZVAL_EMPTY_UNICODE(zerrstr);
129 : }
130 :
131 19 : stream = php_stream_xport_create(host, host_len, REPORT_ERRORS,
132 : STREAM_XPORT_CLIENT | (flags & PHP_STREAM_CLIENT_CONNECT ? STREAM_XPORT_CONNECT : 0) |
133 : (flags & PHP_STREAM_CLIENT_ASYNC_CONNECT ? STREAM_XPORT_CONNECT_ASYNC : 0),
134 : hashkey, &tv, context, &errstr, &err);
135 :
136 :
137 19 : if (stream == NULL) {
138 : /* host might contain binary characters */
139 9 : char *quoted_host = php_addslashes(host, host_len, NULL, 0 TSRMLS_CC);
140 :
141 9 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to connect to %s (%s)", quoted_host, errstr == NULL ? "Unknown error" : errstr);
142 9 : efree(quoted_host);
143 : }
144 :
145 19 : if (hashkey) {
146 0 : efree(hashkey);
147 : }
148 :
149 19 : if (stream == NULL) {
150 9 : if (zerrno) {
151 9 : zval_dtor(zerrno);
152 9 : ZVAL_LONG(zerrno, err);
153 : }
154 14 : if (zerrstr && errstr) {
155 : /* errstr is emalloc'd, either assign it to STRVAL if !UG(unicode)
156 : * Or free it post-conversion if UG(unicode) */
157 5 : zval_dtor(zerrstr);
158 5 : ZVAL_RT_STRING(zerrstr, errstr, ZSTR_AUTOFREE);
159 4 : } else if (errstr) {
160 4 : efree(errstr);
161 : }
162 9 : RETURN_FALSE;
163 : }
164 :
165 10 : if (errstr) {
166 0 : efree(errstr);
167 : }
168 :
169 10 : php_stream_to_zval(stream, return_value);
170 :
171 : }
172 : /* }}} */
173 :
174 : /* {{{ proto resource stream_socket_server(string localaddress [, long &errcode [, string &errstring [, long flags [, resource context]]]]) U
175 : Create a server socket bound to localaddress */
176 : PHP_FUNCTION(stream_socket_server)
177 69 : {
178 : char *host;
179 : int host_len;
180 69 : zval *zerrno = NULL, *zerrstr = NULL, *zcontext = NULL;
181 69 : php_stream *stream = NULL;
182 69 : int err = 0;
183 69 : long flags = STREAM_XPORT_BIND | STREAM_XPORT_LISTEN;
184 69 : char *errstr = NULL;
185 69 : php_stream_context *context = NULL;
186 :
187 69 : RETVAL_FALSE;
188 :
189 69 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zzlr", &host, &host_len, &zerrno, &zerrstr, &flags, &zcontext) == FAILURE) {
190 0 : RETURN_FALSE;
191 : }
192 :
193 69 : context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
194 :
195 69 : if (context) {
196 69 : zend_list_addref(context->rsrc_id);
197 : }
198 :
199 69 : if (zerrno) {
200 47 : zval_dtor(zerrno);
201 47 : ZVAL_LONG(zerrno, 0);
202 : }
203 69 : if (zerrstr) {
204 47 : zval_dtor(zerrstr);
205 47 : ZVAL_EMPTY_UNICODE(zerrstr);
206 : }
207 :
208 69 : stream = php_stream_xport_create(host, host_len, REPORT_ERRORS,
209 : STREAM_XPORT_SERVER | flags,
210 : NULL, NULL, context, &errstr, &err);
211 :
212 69 : if (stream == NULL) {
213 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to connect to %s (%s)", host, errstr == NULL ? "Unknown error" : errstr);
214 : }
215 :
216 69 : if (stream == NULL) {
217 0 : if (zerrno) {
218 0 : zval_dtor(zerrno);
219 0 : ZVAL_LONG(zerrno, err);
220 : }
221 0 : if (zerrstr && errstr) {
222 : /* errstr is emalloc'd, either assign it to STRVAL if !UG(unicode)
223 : * Or free it post-conversion if UG(unicode) */
224 0 : zval_dtor(zerrstr);
225 0 : ZVAL_RT_STRING(zerrstr, errstr, ZSTR_AUTOFREE);
226 0 : } else if (errstr) {
227 0 : efree(errstr);
228 : }
229 0 : RETURN_FALSE;
230 : }
231 :
232 69 : if (errstr) {
233 0 : efree(errstr);
234 : }
235 :
236 69 : php_stream_to_zval(stream, return_value);
237 : }
238 : /* }}} */
239 :
240 : /* {{{ proto resource stream_socket_accept(resource serverstream, [ double timeout [, string &peername ]]) U
241 : Accept a client connection from a server socket */
242 : PHP_FUNCTION(stream_socket_accept)
243 41 : {
244 41 : double timeout = FG(default_socket_timeout);
245 41 : zval *zpeername = NULL;
246 41 : char *peername = NULL;
247 : int peername_len;
248 : php_timeout_ull conv;
249 : struct timeval tv;
250 41 : php_stream *stream = NULL, *clistream = NULL;
251 : zval *zstream;
252 :
253 41 : char *errstr = NULL;
254 :
255 41 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|dz", &zstream, &timeout, &zpeername) == FAILURE) {
256 0 : RETURN_FALSE;
257 : }
258 :
259 41 : php_stream_from_zval(stream, &zstream);
260 :
261 : /* prepare the timeout value for use */
262 41 : conv = (php_timeout_ull) (timeout * 1000000.0);
263 41 : tv.tv_sec = (long) (conv / 1000000);
264 41 : tv.tv_usec = conv % 1000000;
265 :
266 41 : if (zpeername) {
267 0 : zval_dtor(zpeername);
268 0 : ZVAL_NULL(zpeername);
269 : }
270 :
271 82 : if (0 == php_stream_xport_accept(stream, &clistream,
272 : zpeername ? &peername : NULL,
273 : zpeername ? &peername_len : NULL,
274 : NULL, NULL,
275 : &tv, &errstr
276 : TSRMLS_CC) && clistream) {
277 :
278 41 : if (peername) {
279 0 : ZVAL_RT_STRINGL(zpeername, peername, peername_len, ZSTR_AUTOFREE);
280 : }
281 41 : php_stream_to_zval(clistream, return_value);
282 : } else {
283 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "accept failed: %s", errstr ? errstr : "Unknown error");
284 0 : RETVAL_FALSE;
285 : }
286 :
287 41 : if (errstr) {
288 41 : efree(errstr);
289 : }
290 : }
291 : /* }}} */
292 :
293 : /* {{{ proto string stream_socket_get_name(resource stream, bool want_peer) U
294 : Returns either the locally bound or remote name for a socket stream */
295 : PHP_FUNCTION(stream_socket_get_name)
296 0 : {
297 : php_stream *stream;
298 : zval *zstream;
299 : zend_bool want_peer;
300 0 : char *name = NULL;
301 : int name_len;
302 :
303 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rb", &zstream, &want_peer) == FAILURE) {
304 0 : RETURN_FALSE;
305 : }
306 :
307 0 : php_stream_from_zval(stream, &zstream);
308 :
309 0 : if (0 != php_stream_xport_get_name(stream, want_peer,
310 : &name,
311 : &name_len,
312 : NULL, NULL
313 : TSRMLS_CC)) {
314 0 : RETURN_FALSE;
315 : }
316 :
317 0 : RETURN_RT_STRINGL(name, name_len, ZSTR_AUTOFREE);
318 : }
319 : /* }}} */
320 :
321 : /* {{{ proto long stream_socket_sendto(resouce stream, string data [, long flags [, string target_addr]]) U
322 : Send data to a socket stream. If target_addr is specified it must be in dotted quad (or [ipv6]) format */
323 : PHP_FUNCTION(stream_socket_sendto)
324 0 : {
325 : php_stream *stream;
326 : zval *zstream;
327 0 : long flags = 0;
328 0 : char *data, *target_addr = NULL;
329 0 : int datalen, target_addr_len = 0;
330 : php_sockaddr_storage sa;
331 0 : socklen_t sl = 0;
332 :
333 : /* Typically we'll be sending binary data, but implicit RT conversion from unicode is acceptable */
334 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|ls", &zstream, &data, &datalen, &flags, &target_addr, &target_addr_len) == FAILURE) {
335 0 : RETURN_FALSE;
336 : }
337 0 : php_stream_from_zval(stream, &zstream);
338 :
339 0 : if (target_addr_len) {
340 : /* parse the address */
341 0 : if (FAILURE == php_network_parse_network_address_with_port(target_addr, target_addr_len, (struct sockaddr*)&sa, &sl TSRMLS_CC)) {
342 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse `%s' into a valid network address", target_addr);
343 0 : RETURN_FALSE;
344 : }
345 : }
346 :
347 0 : RETURN_LONG(php_stream_xport_sendto(stream, data, datalen, flags, target_addr ? &sa : NULL, sl TSRMLS_CC));
348 : }
349 : /* }}} */
350 :
351 : /* {{{ proto string stream_socket_recvfrom(resource stream, long amount [, long flags [, string &remote_addr]]) U
352 : Receives data from a socket stream */
353 : PHP_FUNCTION(stream_socket_recvfrom)
354 0 : {
355 : php_stream *stream;
356 0 : zval *zstream, *zremote = NULL;
357 0 : char *remote_addr = NULL;
358 : int remote_addr_len;
359 0 : long to_read = 0;
360 : char *read_buf;
361 0 : long flags = 0;
362 : int recvd;
363 :
364 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|lz", &zstream, &to_read, &flags, &zremote) == FAILURE) {
365 0 : RETURN_FALSE;
366 : }
367 :
368 0 : php_stream_from_zval(stream, &zstream);
369 :
370 0 : if (zremote) {
371 0 : zval_dtor(zremote);
372 0 : ZVAL_NULL(zremote);
373 : }
374 :
375 0 : if (to_read <= 0) {
376 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length parameter must be greater than 0");
377 0 : RETURN_FALSE;
378 : }
379 :
380 0 : read_buf = safe_emalloc(1, to_read, 1);
381 :
382 0 : recvd = php_stream_xport_recvfrom(stream, read_buf, to_read, flags, NULL, NULL,
383 : zremote ? &remote_addr : NULL,
384 : zremote ? &remote_addr_len : NULL
385 : TSRMLS_CC);
386 :
387 0 : if (recvd >= 0) {
388 0 : if (zremote) {
389 0 : ZVAL_RT_STRINGL(zremote, remote_addr, remote_addr_len, ZSTR_AUTOFREE);
390 : }
391 0 : read_buf[recvd] = '\0';
392 :
393 0 : RETURN_RT_STRINGL(read_buf, recvd, ZSTR_AUTOFREE);
394 : }
395 :
396 0 : efree(read_buf);
397 0 : RETURN_FALSE;
398 : }
399 : /* }}} */
400 :
401 : /* {{{ proto string stream_get_contents(resource source [, long maxlen [, long offset]]) U
402 : Reads all remaining bytes (or up to maxlen bytes) from a stream and returns them as a string. */
403 : PHP_FUNCTION(stream_get_contents)
404 98 : {
405 : php_stream *stream;
406 : zval *zsrc;
407 98 : long maxlen = PHP_STREAM_COPY_ALL, pos = 0, real_maxlen;
408 : int len;
409 98 : void *contents = NULL;
410 :
411 98 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|ll", &zsrc, &maxlen, &pos) == FAILURE) {
412 2 : RETURN_FALSE;
413 : }
414 :
415 96 : php_stream_from_zval(stream, &zsrc);
416 :
417 96 : if ((pos > 0 || (pos == 0 && ZEND_NUM_ARGS() > 2)) && php_stream_seek(stream, pos, SEEK_SET) < 0) {
418 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek to position %ld in the stream", pos);
419 0 : RETURN_FALSE;
420 : }
421 :
422 192 : if (maxlen <= 0 || stream->readbuf_type == IS_STRING) {
423 96 : real_maxlen = maxlen;
424 : } else {
425 : /* Allows worst case scenario of each input char being turned into two UChars
426 : * UTODO: Have this take converter into account, since many never generate surrogate pairs */
427 0 : real_maxlen = maxlen * 2;
428 : }
429 :
430 96 : len = php_stream_copy_to_mem_ex(stream, stream->readbuf_type, &contents, real_maxlen, maxlen, 0);
431 :
432 96 : if (stream->readbuf_type == IS_STRING) {
433 75 : if (len > 0) {
434 49 : RETVAL_STRINGL(contents, len, 0);
435 : } else {
436 26 : if (contents) {
437 3 : efree(contents);
438 : }
439 26 : RETVAL_EMPTY_STRING();
440 : }
441 : } else {
442 21 : if (len > 0) {
443 20 : RETVAL_UNICODEL(contents, len, 0);
444 : } else {
445 1 : if (contents) {
446 0 : efree(contents);
447 : }
448 1 : RETVAL_EMPTY_UNICODE();
449 : }
450 : }
451 : }
452 : /* }}} */
453 :
454 : /* {{{ proto long stream_copy_to_stream(resource source, resource dest [, long maxlen [, long pos]]) U
455 : Reads up to maxlen bytes from source stream and writes them to dest stream. */
456 : PHP_FUNCTION(stream_copy_to_stream)
457 15 : {
458 : php_stream *src, *dest;
459 : zval *zsrc, *zdest;
460 15 : long maxlen = PHP_STREAM_COPY_ALL, pos = 0;
461 : size_t len;
462 : int ret;
463 :
464 15 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|ll", &zsrc, &zdest, &maxlen, &pos) == FAILURE) {
465 0 : RETURN_FALSE;
466 : }
467 :
468 15 : php_stream_from_zval(src, &zsrc);
469 15 : php_stream_from_zval(dest, &zdest);
470 :
471 15 : if (pos > 0 && php_stream_seek(src, pos, SEEK_SET) < 0) {
472 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek to position %ld in the stream", pos);
473 0 : RETURN_FALSE;
474 : }
475 :
476 15 : ret = php_stream_copy_to_stream_ex(src, dest, maxlen, &len);
477 :
478 15 : if (ret != SUCCESS) {
479 2 : RETURN_FALSE;
480 : }
481 13 : RETURN_LONG(len);
482 : }
483 : /* }}} */
484 :
485 : /* {{{ proto array stream_get_meta_data(resource fp) U
486 : Retrieves header/meta data from streams/file pointers */
487 : PHP_FUNCTION(stream_get_meta_data)
488 109 : {
489 : zval *arg1;
490 : php_stream *stream;
491 : zval *newval;
492 :
493 109 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
494 10 : return;
495 : }
496 99 : php_stream_from_zval(stream, &arg1);
497 :
498 98 : array_init(return_value);
499 :
500 98 : if (stream->wrapperdata) {
501 37 : MAKE_STD_ZVAL(newval);
502 37 : *newval = *(stream->wrapperdata);
503 37 : zval_copy_ctor(newval);
504 37 : INIT_PZVAL(newval);
505 :
506 37 : add_ascii_assoc_zval(return_value, "wrapper_data", newval);
507 : }
508 98 : if (stream->wrapper) {
509 80 : add_ascii_assoc_rt_string(return_value, "wrapper_type", (char *)stream->wrapper->wops->label, ZSTR_DUPLICATE);
510 : }
511 98 : add_ascii_assoc_rt_string(return_value, "stream_type", (char *)stream->ops->label, ZSTR_DUPLICATE);
512 :
513 98 : add_ascii_assoc_rt_string(return_value, "mode", stream->mode, ZSTR_DUPLICATE);
514 :
515 98 : if (stream->readfilters.head) {
516 : php_stream_filter *filter;
517 :
518 5 : MAKE_STD_ZVAL(newval);
519 5 : array_init(newval);
520 :
521 10 : for (filter = stream->readfilters.head; filter != NULL; filter = filter->next) {
522 5 : add_next_index_rt_string(newval, filter->name, ZSTR_DUPLICATE);
523 : }
524 :
525 5 : add_ascii_assoc_zval(return_value, "read_filters", newval);
526 : }
527 :
528 98 : if (stream->writefilters.head) {
529 : php_stream_filter *filter;
530 :
531 6 : MAKE_STD_ZVAL(newval);
532 6 : array_init(newval);
533 :
534 12 : for (filter = stream->writefilters.head; filter != NULL; filter = filter->next) {
535 6 : add_next_index_rt_string(newval, filter->name, ZSTR_DUPLICATE);
536 : }
537 :
538 6 : add_ascii_assoc_zval(return_value, "write_filters", newval);
539 : }
540 :
541 98 : if (stream->readbuf_type == IS_UNICODE) {
542 5 : int readbuf_len = u_countChar32(stream->readbuf.u + stream->readpos, stream->writepos - stream->readpos);
543 5 : add_ascii_assoc_long(return_value, "unread_bytes", UBYTES(stream->writepos - stream->readpos));
544 5 : add_ascii_assoc_long(return_value, "unread_chars", readbuf_len);
545 : } else { /* IS_STRING */
546 93 : add_ascii_assoc_long(return_value, "unread_bytes", stream->writepos - stream->readpos);
547 93 : add_ascii_assoc_long(return_value, "unread_chars", stream->writepos - stream->readpos);
548 : }
549 :
550 98 : add_ascii_assoc_bool(return_value, "seekable", (stream->ops->seek) && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0);
551 98 : if (stream->orig_path) {
552 78 : UChar *decoded_path = NULL;
553 78 : int decoded_path_len = 0;
554 :
555 78 : if (SUCCESS == php_stream_path_decode(stream->wrapper, &decoded_path, &decoded_path_len, stream->orig_path, strlen(stream->orig_path), REPORT_ERRORS, stream->context)) {
556 78 : add_ascii_assoc_unicodel(return_value, "uri", decoded_path, decoded_path_len, 0);
557 : } else {
558 0 : add_ascii_assoc_null(return_value, "uri");
559 : }
560 : }
561 :
562 98 : if (!php_stream_populate_meta_data(stream, return_value)) {
563 76 : add_ascii_assoc_bool(return_value, "timed_out", 0);
564 76 : add_ascii_assoc_bool(return_value, "blocked", 1);
565 76 : add_ascii_assoc_bool(return_value, "eof", php_stream_eof(stream));
566 : }
567 :
568 : }
569 : /* }}} */
570 :
571 : /* {{{ proto array stream_get_transports() U
572 : Retrieves list of registered socket transports */
573 : PHP_FUNCTION(stream_get_transports)
574 2 : {
575 : HashTable *stream_xport_hash;
576 : zstr stream_xport;
577 : uint stream_xport_len;
578 : ulong num_key;
579 :
580 2 : if (zend_parse_parameters_none() == FAILURE) {
581 0 : return;
582 : }
583 :
584 2 : if ((stream_xport_hash = php_stream_xport_get_hash())) {
585 : HashPosition pos;
586 2 : array_init(return_value);
587 2 : zend_hash_internal_pointer_reset_ex(stream_xport_hash, &pos);
588 20 : while (zend_hash_get_current_key_ex(stream_xport_hash,
589 : &stream_xport, &stream_xport_len,
590 : &num_key, 0, &pos) == HASH_KEY_IS_STRING) {
591 16 : add_next_index_rt_stringl(return_value, stream_xport.s, stream_xport_len - 1, ZSTR_DUPLICATE);
592 16 : zend_hash_move_forward_ex(stream_xport_hash, &pos);
593 : }
594 : } else {
595 0 : RETURN_FALSE;
596 : }
597 : }
598 : /* }}} */
599 :
600 : /* {{{ proto array stream_get_wrappers() U
601 : Retrieves list of registered stream wrappers */
602 : PHP_FUNCTION(stream_get_wrappers)
603 4 : {
604 : HashTable *url_stream_wrappers_hash;
605 : zstr stream_protocol;
606 4 : uint key_flags, stream_protocol_len = 0;
607 : ulong num_key;
608 :
609 4 : if (zend_parse_parameters_none() == FAILURE) {
610 0 : return;
611 : }
612 :
613 4 : if ((url_stream_wrappers_hash = php_stream_get_url_stream_wrappers_hash())) {
614 : HashPosition pos;
615 4 : array_init(return_value);
616 4 : for (zend_hash_internal_pointer_reset_ex(url_stream_wrappers_hash, &pos);
617 72 : (key_flags = zend_hash_get_current_key_ex(url_stream_wrappers_hash, &stream_protocol, &stream_protocol_len, &num_key, 0, &pos)) != HASH_KEY_NON_EXISTANT;
618 64 : zend_hash_move_forward_ex(url_stream_wrappers_hash, &pos)) {
619 64 : if (key_flags == HASH_KEY_IS_STRING) {
620 64 : add_next_index_rt_stringl(return_value, stream_protocol.s, stream_protocol_len - 1, ZSTR_DUPLICATE);
621 : }
622 : }
623 : } else {
624 0 : RETURN_FALSE;
625 : }
626 :
627 : }
628 : /* }}} */
629 :
630 : /* {{{ stream_select related functions */
631 : static int stream_array_to_fd_set(zval *stream_array, fd_set *fds, php_socket_t *max_fd TSRMLS_DC)
632 815816 : {
633 : zval **elem;
634 : php_stream *stream;
635 : php_socket_t this_fd;
636 815816 : int cnt = 0;
637 :
638 815816 : if (Z_TYPE_P(stream_array) != IS_ARRAY) {
639 0 : return 0;
640 : }
641 815816 : for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream_array));
642 4079034 : zend_hash_get_current_data(Z_ARRVAL_P(stream_array), (void **) &elem) == SUCCESS;
643 2447402 : zend_hash_move_forward(Z_ARRVAL_P(stream_array))) {
644 :
645 2447402 : php_stream_from_zval_no_verify(stream, elem);
646 2447402 : if (stream == NULL) {
647 815796 : continue;
648 : }
649 : /* get the fd.
650 : * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag
651 : * when casting. It is only used here so that the buffered data warning
652 : * is not displayed.
653 : * */
654 1631606 : if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&this_fd, 1) && this_fd >= 0) {
655 :
656 1631601 : PHP_SAFE_FD_SET(this_fd, fds);
657 :
658 1631601 : if (this_fd > *max_fd) {
659 1631598 : *max_fd = this_fd;
660 : }
661 1631601 : cnt++;
662 : }
663 : }
664 815816 : return cnt ? 1 : 0;
665 : }
666 :
667 : static int stream_array_from_fd_set(zval *stream_array, fd_set *fds TSRMLS_DC)
668 815809 : {
669 : zval **elem, **dest_elem;
670 : php_stream *stream;
671 : HashTable *new_hash;
672 : php_socket_t this_fd;
673 815809 : int ret = 0;
674 :
675 815809 : if (Z_TYPE_P(stream_array) != IS_ARRAY) {
676 0 : return 0;
677 : }
678 815809 : ALLOC_HASHTABLE(new_hash);
679 815809 : zend_hash_init(new_hash, zend_hash_num_elements(Z_ARRVAL_P(stream_array)), NULL, ZVAL_PTR_DTOR, 0);
680 :
681 815809 : for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream_array));
682 4079013 : zend_hash_get_current_data(Z_ARRVAL_P(stream_array), (void **) &elem) == SUCCESS;
683 2447395 : zend_hash_move_forward(Z_ARRVAL_P(stream_array))) {
684 :
685 2447395 : php_stream_from_zval_no_verify(stream, elem);
686 2447395 : if (stream == NULL) {
687 815796 : continue;
688 : }
689 : /* get the fd
690 : * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag
691 : * when casting. It is only used here so that the buffered data warning
692 : * is not displayed.
693 : */
694 1631599 : if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&this_fd, 1) && this_fd >= 0) {
695 1631599 : if (PHP_SAFE_FD_ISSET(this_fd, fds)) {
696 832638 : zend_hash_next_index_insert(new_hash, (void *)elem, sizeof(zval *), (void **)&dest_elem);
697 832638 : if (dest_elem) {
698 832638 : zval_add_ref(dest_elem);
699 : }
700 832638 : ret++;
701 832638 : continue;
702 : }
703 : }
704 : }
705 :
706 : /* destroy old array and add new one */
707 815809 : zend_hash_destroy(Z_ARRVAL_P(stream_array));
708 815809 : efree(Z_ARRVAL_P(stream_array));
709 :
710 815809 : zend_hash_internal_pointer_reset(new_hash);
711 815809 : Z_ARRVAL_P(stream_array) = new_hash;
712 :
713 815809 : return ret;
714 : }
715 :
716 : static int stream_array_emulate_read_fd_set(zval *stream_array TSRMLS_DC)
717 815803 : {
718 : zval **elem, **dest_elem;
719 : php_stream *stream;
720 : HashTable *new_hash;
721 815803 : int ret = 0;
722 :
723 815803 : if (Z_TYPE_P(stream_array) != IS_ARRAY) {
724 0 : return 0;
725 : }
726 815803 : ALLOC_HASHTABLE(new_hash);
727 815803 : zend_hash_init(new_hash, zend_hash_num_elements(Z_ARRVAL_P(stream_array)), NULL, ZVAL_PTR_DTOR, 0);
728 :
729 815803 : for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream_array));
730 4079000 : zend_hash_get_current_data(Z_ARRVAL_P(stream_array), (void **) &elem) == SUCCESS;
731 2447394 : zend_hash_move_forward(Z_ARRVAL_P(stream_array))) {
732 :
733 2447394 : php_stream_from_zval_no_verify(stream, elem);
734 2447394 : if (stream == NULL) {
735 815796 : continue;
736 : }
737 1631598 : if ((stream->writepos - stream->readpos) > 0) {
738 : /* allow readable non-descriptor based streams to participate in stream_select.
739 : * Non-descriptor streams will only "work" if they have previously buffered the
740 : * data. Not ideal, but better than nothing.
741 : * This branch of code also allows blocking streams with buffered data to
742 : * operate correctly in stream_select.
743 : * */
744 1 : zend_hash_next_index_insert(new_hash, (void *)elem, sizeof(zval *), (void **)&dest_elem);
745 1 : if (dest_elem) {
746 1 : zval_add_ref(dest_elem);
747 : }
748 1 : ret++;
749 1 : continue;
750 : }
751 : }
752 :
753 815803 : if (ret > 0) {
754 : /* destroy old array and add new one */
755 1 : zend_hash_destroy(Z_ARRVAL_P(stream_array));
756 1 : efree(Z_ARRVAL_P(stream_array));
757 :
758 1 : zend_hash_internal_pointer_reset(new_hash);
759 1 : Z_ARRVAL_P(stream_array) = new_hash;
760 : } else {
761 815802 : zend_hash_destroy(new_hash);
762 815802 : FREE_HASHTABLE(new_hash);
763 : }
764 :
765 815803 : return ret;
766 : }
767 : /* }}} */
768 :
769 : /* {{{ proto int stream_select(array &read_streams, array &write_streams, array &except_streams, int tv_sec[, int tv_usec]) U
770 : Runs the select() system call on the sets of streams with a timeout specified by tv_sec and tv_usec */
771 : PHP_FUNCTION(stream_select)
772 815808 : {
773 815808 : zval *r_array, *w_array, *e_array, **sec = NULL;
774 : struct timeval tv;
775 815808 : struct timeval *tv_p = NULL;
776 : fd_set rfds, wfds, efds;
777 815808 : php_socket_t max_fd = 0;
778 815808 : int retval, sets = 0;
779 815808 : long usec = 0;
780 815808 : int set_count, max_set_count = 0;
781 :
782 815808 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!a!Z!|l", &r_array, &w_array, &e_array, &sec, &usec) == FAILURE)
783 0 : return;
784 :
785 815808 : FD_ZERO(&rfds);
786 815808 : FD_ZERO(&wfds);
787 815808 : FD_ZERO(&efds);
788 :
789 815808 : if (r_array != NULL) {
790 815808 : set_count = stream_array_to_fd_set(r_array, &rfds, &max_fd TSRMLS_CC);
791 815808 : if (set_count > max_set_count)
792 815802 : max_set_count = set_count;
793 815808 : sets += set_count;
794 : }
795 :
796 815808 : if (w_array != NULL) {
797 5 : set_count = stream_array_to_fd_set(w_array, &wfds, &max_fd TSRMLS_CC);
798 5 : if (set_count > max_set_count)
799 1 : max_set_count = set_count;
800 5 : sets += set_count;
801 : }
802 :
803 815808 : if (e_array != NULL) {
804 3 : set_count = stream_array_to_fd_set(e_array, &efds, &max_fd TSRMLS_CC);
805 3 : if (set_count > max_set_count)
806 0 : max_set_count = set_count;
807 3 : sets += set_count;
808 : }
809 :
810 815808 : if (!sets) {
811 5 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "No stream arrays were passed");
812 5 : RETURN_FALSE;
813 : }
814 :
815 815803 : PHP_SAFE_MAX_FD(max_fd, max_set_count);
816 :
817 : /* If seconds is not set to null, build the timeval, else we wait indefinitely */
818 815803 : if (sec != NULL) {
819 815803 : convert_to_long_ex(sec);
820 :
821 815803 : if (Z_LVAL_PP(sec) < 0) {
822 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The seconds parameter must be greater than 0");
823 0 : RETURN_FALSE;
824 815803 : } else if (usec < 0) {
825 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The microseconds parameter must be greater than 0");
826 0 : RETURN_FALSE;
827 : }
828 :
829 : /* Solaris + BSD do not like microsecond values which are >= 1 sec */
830 815803 : if (usec > 999999) {
831 0 : tv.tv_sec = Z_LVAL_PP(sec) + (usec / 1000000);
832 0 : tv.tv_usec = usec % 1000000;
833 : } else {
834 815803 : tv.tv_sec = Z_LVAL_PP(sec);
835 815803 : tv.tv_usec = usec;
836 : }
837 :
838 815803 : tv_p = &tv;
839 : }
840 :
841 : /* slight hack to support buffered data; if there is data sitting in the
842 : * read buffer of any of the streams in the read array, let's pretend
843 : * that we selected, but return only the readable sockets */
844 815803 : if (r_array != NULL) {
845 :
846 815803 : retval = stream_array_emulate_read_fd_set(r_array TSRMLS_CC);
847 815803 : if (retval > 0) {
848 1 : if (w_array != NULL) {
849 1 : zend_hash_clean(Z_ARRVAL_P(w_array));
850 : }
851 1 : if (e_array != NULL) {
852 0 : zend_hash_clean(Z_ARRVAL_P(e_array));
853 : }
854 1 : RETURN_LONG(retval);
855 : }
856 : }
857 :
858 815802 : retval = php_select(max_fd+1, &rfds, &wfds, &efds, tv_p);
859 :
860 815802 : if (retval == -1) {
861 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s (max_fd=%d)",
862 : errno, strerror(errno), max_fd);
863 0 : RETURN_FALSE;
864 : }
865 :
866 815802 : if (r_array != NULL) stream_array_from_fd_set(r_array, &rfds TSRMLS_CC);
867 815802 : if (w_array != NULL) stream_array_from_fd_set(w_array, &wfds TSRMLS_CC);
868 815802 : if (e_array != NULL) stream_array_from_fd_set(e_array, &efds TSRMLS_CC);
869 :
870 815802 : RETURN_LONG(retval);
871 : }
872 : /* }}} */
873 :
874 : /* {{{ stream_context related functions */
875 : static void user_space_stream_notifier(php_stream_context *context, int notifycode, int severity,
876 : char *xmsg, int xcode, size_t bytes_sofar, size_t bytes_max, void * ptr TSRMLS_DC)
877 0 : {
878 0 : zval *callback = (zval*)context->notifier->ptr;
879 0 : zval *retval = NULL;
880 : zval zvs[6];
881 : zval *ps[6];
882 : zval **ptps[6];
883 : int i;
884 :
885 0 : for (i = 0; i < 6; i++) {
886 0 : INIT_ZVAL(zvs[i]);
887 0 : ps[i] = &zvs[i];
888 0 : ptps[i] = &ps[i];
889 0 : MAKE_STD_ZVAL(ps[i]);
890 : }
891 :
892 0 : ZVAL_LONG(ps[0], notifycode);
893 0 : ZVAL_LONG(ps[1], severity);
894 0 : if (xmsg) {
895 0 : ZVAL_RT_STRING(ps[2], xmsg, ZSTR_DUPLICATE);
896 : } else {
897 0 : ZVAL_NULL(ps[2]);
898 : }
899 0 : ZVAL_LONG(ps[3], xcode);
900 0 : ZVAL_LONG(ps[4], bytes_sofar);
901 0 : ZVAL_LONG(ps[5], bytes_max);
902 :
903 0 : if (FAILURE == call_user_function_ex(EG(function_table), NULL, callback, &retval, 6, ptps, 0, NULL TSRMLS_CC)) {
904 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to call user notifier");
905 : }
906 0 : for (i = 0; i < 6; i++) {
907 0 : zval_ptr_dtor(&ps[i]);
908 : }
909 0 : if (retval) {
910 0 : zval_ptr_dtor(&retval);
911 : }
912 0 : }
913 :
914 : static void user_space_stream_notifier_dtor(php_stream_notifier *notifier)
915 2 : {
916 2 : if (notifier && notifier->ptr) {
917 2 : zval_ptr_dtor((zval **)&(notifier->ptr));
918 2 : notifier->ptr = NULL;
919 : }
920 2 : }
921 :
922 : static int parse_context_options(php_stream_context *context, zval *options TSRMLS_DC)
923 49 : {
924 : HashPosition pos, opos;
925 : zval **wval, **oval;
926 : zstr wkey, okey;
927 : uint wkey_len, okey_len;
928 49 : int ret = SUCCESS;
929 : ulong num_key;
930 :
931 49 : zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(options), &pos);
932 147 : while (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_P(options), (void**)&wval, &pos)) {
933 49 : int wtype = zend_hash_get_current_key_ex(Z_ARRVAL_P(options), &wkey, &wkey_len, &num_key, 0, &pos);
934 97 : if (((HASH_KEY_IS_STRING == wtype) || (HASH_KEY_IS_UNICODE == wtype))
935 : && Z_TYPE_PP(wval) == IS_ARRAY) {
936 48 : if (HASH_KEY_IS_UNICODE == wtype) {
937 : /* fold to string */
938 48 : UErrorCode errCode = 0;
939 : char *tmp;
940 : int tmp_len;
941 :
942 48 : zend_unicode_to_string_ex(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &tmp, &tmp_len, wkey.u, wkey_len, &errCode);
943 48 : wkey.s = tmp;
944 48 : wkey_len = tmp_len;
945 : }
946 :
947 48 : zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(wval), &opos);
948 182 : while (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(wval), (void**)&oval, &opos)) {
949 86 : int otype = zend_hash_get_current_key_ex(Z_ARRVAL_PP(wval), &okey, &okey_len, &num_key, 0, &opos);
950 86 : if (HASH_KEY_IS_UNICODE == otype) {
951 : /* fold to string */
952 86 : UErrorCode errCode = 0;
953 : char *tmp;
954 : int tmp_len;
955 :
956 86 : zend_unicode_to_string_ex(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &tmp, &tmp_len, okey.u, okey_len, &errCode);
957 86 : okey.s = tmp;
958 86 : okey_len = tmp_len;
959 86 : php_stream_context_set_option(context, wkey.s, okey.s, *oval);
960 86 : efree(okey.v);
961 : }
962 86 : if (HASH_KEY_IS_STRING == otype) {
963 0 : php_stream_context_set_option(context, wkey.s, okey.s, *oval);
964 : }
965 86 : zend_hash_move_forward_ex(Z_ARRVAL_PP(wval), &opos);
966 : }
967 48 : if (wtype == HASH_KEY_IS_UNICODE) {
968 48 : efree(wkey.v);
969 : }
970 : } else {
971 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "options should have the form [\"wrappername\"][\"optionname\"] = $value");
972 : }
973 49 : zend_hash_move_forward_ex(Z_ARRVAL_P(options), &pos);
974 : }
975 :
976 49 : return ret;
977 : }
978 :
979 : static int parse_context_params(php_stream_context *context, zval *params TSRMLS_DC)
980 3 : {
981 3 : int ret = SUCCESS;
982 : zval **tmp;
983 :
984 3 : if (SUCCESS == zend_ascii_hash_find(Z_ARRVAL_P(params), "notification", sizeof("notification"), (void**)&tmp)) {
985 :
986 2 : if (context->notifier) {
987 1 : php_stream_notification_free(context->notifier);
988 1 : context->notifier = NULL;
989 : }
990 :
991 2 : context->notifier = php_stream_notification_alloc();
992 2 : context->notifier->func = user_space_stream_notifier;
993 2 : context->notifier->ptr = *tmp;
994 2 : Z_ADDREF_P(*tmp);
995 2 : context->notifier->dtor = user_space_stream_notifier_dtor;
996 : }
997 3 : if (SUCCESS == zend_ascii_hash_find(Z_ARRVAL_P(params), "options", sizeof("options"), (void**)&tmp)) {
998 1 : if (Z_TYPE_PP(tmp) == IS_ARRAY) {
999 0 : parse_context_options(context, *tmp TSRMLS_CC);
1000 : } else {
1001 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream/context parameter");
1002 : }
1003 : }
1004 3 : if (SUCCESS == zend_ascii_hash_find(Z_ARRVAL_P(params), "encoding", sizeof("encoding"), (void**)&tmp)) {
1005 0 : zval strval = **tmp;
1006 :
1007 0 : if (context->input_encoding) {
1008 0 : efree(context->input_encoding);
1009 : }
1010 0 : if (context->output_encoding) {
1011 0 : efree(context->output_encoding);
1012 : }
1013 0 : zval_copy_ctor(&strval);
1014 0 : convert_to_string(&strval);
1015 0 : context->input_encoding = Z_STRVAL(strval);
1016 0 : context->output_encoding = estrdup(Z_STRVAL(strval));
1017 : }
1018 3 : if (SUCCESS == zend_ascii_hash_find(Z_ARRVAL_P(params), "input_encoding", sizeof("input_encoding"), (void**)&tmp)) {
1019 0 : zval strval = **tmp;
1020 :
1021 0 : if (context->input_encoding) {
1022 0 : efree(context->input_encoding);
1023 : }
1024 :
1025 0 : zval_copy_ctor(&strval);
1026 0 : convert_to_string(&strval);
1027 0 : context->input_encoding = Z_STRVAL(strval);
1028 : }
1029 3 : if (SUCCESS == zend_ascii_hash_find(Z_ARRVAL_P(params), "output_encoding", sizeof("output_encoding"), (void**)&tmp)) {
1030 0 : zval strval = **tmp;
1031 :
1032 0 : if (context->output_encoding) {
1033 0 : efree(context->output_encoding);
1034 : }
1035 :
1036 0 : zval_copy_ctor(&strval);
1037 0 : convert_to_string(&strval);
1038 0 : context->output_encoding = Z_STRVAL(strval);
1039 : }
1040 3 : if (SUCCESS == zend_ascii_hash_find(Z_ARRVAL_P(params), "default_mode", sizeof("default_mode"), (void**)&tmp)) {
1041 0 : zval longval = **tmp;
1042 :
1043 0 : zval_copy_ctor(&longval);
1044 0 : convert_to_long(&longval);
1045 0 : context->default_mode = Z_LVAL(longval);
1046 0 : zval_dtor(&longval);
1047 : }
1048 3 : return ret;
1049 : }
1050 :
1051 : /* given a zval which is either a stream or a context, return the underlying
1052 : * stream_context. If it is a stream that does not have a context assigned, it
1053 : * will create and assign a context and return that. */
1054 : static php_stream_context *decode_context_param(zval *contextresource TSRMLS_DC)
1055 12 : {
1056 12 : php_stream_context *context = NULL;
1057 :
1058 12 : context = zend_fetch_resource(&contextresource TSRMLS_CC, -1, NULL, NULL, 1, php_le_stream_context());
1059 12 : if (context == NULL) {
1060 : php_stream *stream;
1061 :
1062 0 : stream = zend_fetch_resource(&contextresource TSRMLS_CC, -1, NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream);
1063 :
1064 0 : if (stream) {
1065 0 : context = stream->context;
1066 0 : if (context == NULL) {
1067 : /* Only way this happens is if file is opened with NO_DEFAULT_CONTEXT
1068 : param, but then something is called which requires a context.
1069 : Don't give them the default one though since they already said they
1070 : didn't want it. */
1071 0 : context = stream->context = php_stream_context_alloc();
1072 : }
1073 : }
1074 : }
1075 :
1076 12 : return context;
1077 : }
1078 : /* }}} */
1079 :
1080 : /* {{{ proto array stream_context_get_options(resource context|resource stream) U
1081 : Retrieve options for a stream/wrapper/context */
1082 : PHP_FUNCTION(stream_context_get_options)
1083 2 : {
1084 : zval *zcontext;
1085 : php_stream_context *context;
1086 :
1087 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zcontext) == FAILURE) {
1088 0 : RETURN_FALSE;
1089 : }
1090 2 : context = decode_context_param(zcontext TSRMLS_CC);
1091 2 : if (!context) {
1092 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream/context parameter");
1093 0 : RETURN_FALSE;
1094 : }
1095 :
1096 2 : RETURN_ZVAL(context->options, 1, 0);
1097 : }
1098 : /* }}} */
1099 :
1100 : /* {{{ proto bool stream_context_set_option(resource context|resource stream, string wrappername, string optionname, mixed value) U
1101 : * Overloaded form: stream_context_set_option(resource context|resource stream, array options)
1102 : * Set an option (or several options) for a wrapper */
1103 : PHP_FUNCTION(stream_context_set_option)
1104 1 : {
1105 1 : zval *options = NULL, *zcontext = NULL, *zvalue = NULL;
1106 : php_stream_context *context;
1107 : char *wrappername, *optionname;
1108 : int wrapperlen, optionlen;
1109 :
1110 1 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
1111 : "rssz", &zcontext, &wrappername, &wrapperlen,
1112 : &optionname, &optionlen, &zvalue) == FAILURE) {
1113 0 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
1114 : "ra", &zcontext, &options) == FAILURE) {
1115 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "called with wrong number or type of parameters; please RTM");
1116 0 : RETURN_FALSE;
1117 : }
1118 : }
1119 :
1120 : /* figure out where the context is coming from exactly */
1121 1 : context = decode_context_param(zcontext TSRMLS_CC);
1122 1 : if (!context) {
1123 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream/context parameter");
1124 0 : RETURN_FALSE;
1125 : }
1126 :
1127 1 : if (options) {
1128 : /* handle the array syntax */
1129 0 : RETVAL_BOOL(parse_context_options(context, options TSRMLS_CC) == SUCCESS);
1130 : } else {
1131 1 : php_stream_context_set_option(context, wrappername, optionname, zvalue);
1132 1 : RETVAL_TRUE;
1133 : }
1134 : }
1135 : /* }}} */
1136 :
1137 : /* {{{ proto bool stream_context_set_params(resource context|resource stream, array options) U
1138 : Set parameters for a file context */
1139 : PHP_FUNCTION(stream_context_set_params)
1140 3 : {
1141 : zval *params, *zcontext;
1142 : php_stream_context *context;
1143 :
1144 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ra", &zcontext, ¶ms) == FAILURE) {
1145 0 : RETURN_FALSE;
1146 : }
1147 :
1148 3 : context = decode_context_param(zcontext TSRMLS_CC);
1149 3 : if (!context) {
1150 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream/context parameter");
1151 0 : RETURN_FALSE;
1152 : }
1153 :
1154 3 : RETVAL_BOOL(parse_context_params(context, params TSRMLS_CC) == SUCCESS);
1155 : }
1156 : /* }}} */
1157 :
1158 : /* {{{ proto array stream_context_get_params(resource context|resource stream) U
1159 : Get parameters of a file context */
1160 : PHP_FUNCTION(stream_context_get_params)
1161 6 : {
1162 : zval *zcontext, *options;
1163 : php_stream_context *context;
1164 :
1165 6 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zcontext) == FAILURE) {
1166 0 : RETURN_FALSE;
1167 : }
1168 :
1169 6 : context = decode_context_param(zcontext TSRMLS_CC);
1170 6 : if (!context) {
1171 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream/context parameter");
1172 0 : RETURN_FALSE;
1173 : }
1174 :
1175 6 : array_init(return_value);
1176 6 : if (context->notifier && context->notifier->ptr && context->notifier->func == user_space_stream_notifier) {
1177 4 : add_ascii_assoc_zval_ex(return_value, ZEND_STRS("notification"), context->notifier->ptr);
1178 4 : Z_ADDREF_P(context->notifier->ptr);
1179 : }
1180 6 : ALLOC_INIT_ZVAL(options);
1181 6 : ZVAL_ZVAL(options, context->options, 1, 0);
1182 6 : add_ascii_assoc_zval_ex(return_value, ZEND_STRS("options"), options);
1183 : }
1184 : /* }}} */
1185 :
1186 :
1187 : /* {{{ proto resource stream_context_get_default([array options]) U
1188 : Get a handle on the default file/stream context and optionally set parameters */
1189 : PHP_FUNCTION(stream_context_get_default)
1190 2 : {
1191 2 : zval *params = NULL;
1192 : php_stream_context *context;
1193 :
1194 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a", ¶ms) == FAILURE) {
1195 0 : RETURN_FALSE;
1196 : }
1197 :
1198 2 : if (FG(default_context) == NULL) {
1199 2 : FG(default_context) = php_stream_context_alloc();
1200 : }
1201 2 : context = FG(default_context);
1202 :
1203 2 : if (params) {
1204 0 : parse_context_options(context, params TSRMLS_CC);
1205 : }
1206 :
1207 2 : php_stream_context_to_zval(context, return_value);
1208 : }
1209 : /* }}} */
1210 :
1211 : /* {{{ proto resource stream_context_set_default(array options) U
1212 : Set default file/stream context, returns the context as a resource */
1213 : PHP_FUNCTION(stream_context_set_default)
1214 0 : {
1215 0 : zval *options = NULL;
1216 : php_stream_context *context;
1217 :
1218 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &options) == FAILURE) {
1219 0 : return;
1220 : }
1221 :
1222 0 : if (FG(default_context) == NULL) {
1223 0 : FG(default_context) = php_stream_context_alloc();
1224 : }
1225 0 : context = FG(default_context);
1226 :
1227 0 : parse_context_options(context, options TSRMLS_CC);
1228 :
1229 0 : php_stream_context_to_zval(context, return_value);
1230 : }
1231 : /* }}} */
1232 :
1233 : /* {{{ proto resource stream_context_create([array options[, array params]]) U
1234 : Create a file context and optionally set parameters */
1235 : PHP_FUNCTION(stream_context_create)
1236 76 : {
1237 76 : zval *options = NULL, *params = NULL;
1238 : php_stream_context *context;
1239 :
1240 76 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!a!", &options, ¶ms) == FAILURE) {
1241 0 : RETURN_FALSE;
1242 : }
1243 :
1244 76 : context = php_stream_context_alloc();
1245 :
1246 76 : if (options) {
1247 49 : parse_context_options(context, options TSRMLS_CC);
1248 : }
1249 :
1250 76 : if (params) {
1251 0 : parse_context_params(context, params TSRMLS_CC);
1252 : }
1253 :
1254 76 : RETURN_RESOURCE(context->rsrc_id);
1255 : }
1256 : /* }}} */
1257 :
1258 : /* {{{ streams filter functions */
1259 : static void apply_filter_to_stream(int append, INTERNAL_FUNCTION_PARAMETERS)
1260 74 : {
1261 : zval *zstream;
1262 : php_stream *stream;
1263 : char *filtername;
1264 : int filternamelen;
1265 74 : long read_write = 0;
1266 74 : zval *filterparams = NULL;
1267 74 : php_stream_filter *filter = NULL;
1268 : int ret;
1269 :
1270 74 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|lz", &zstream,
1271 : &filtername, &filternamelen, &read_write, &filterparams) == FAILURE) {
1272 0 : RETURN_FALSE;
1273 : }
1274 :
1275 74 : php_stream_from_zval(stream, &zstream);
1276 :
1277 74 : if ((read_write & PHP_STREAM_FILTER_ALL) == 0) {
1278 : /* Chain not specified.
1279 : * Examine stream->mode to determine which filters are needed
1280 : * There's no harm in attaching a filter to an unused chain,
1281 : * but why waste the memory and clock cycles?
1282 : */
1283 46 : if (strchr(stream->mode, 'r') || strchr(stream->mode, '+')) {
1284 39 : read_write |= PHP_STREAM_FILTER_READ;
1285 : }
1286 46 : if (strchr(stream->mode, 'w') || strchr(stream->mode, '+') || strchr(stream->mode, 'a')) {
1287 43 : read_write |= PHP_STREAM_FILTER_WRITE;
1288 : }
1289 : }
1290 :
1291 74 : if (read_write & PHP_STREAM_FILTER_READ) {
1292 57 : filter = php_stream_filter_create(filtername, filterparams, php_stream_is_persistent(stream) TSRMLS_CC);
1293 57 : if (filter == NULL) {
1294 2 : RETURN_FALSE;
1295 : }
1296 :
1297 55 : if (append) {
1298 50 : ret = php_stream_filter_append_ex(&stream->readfilters, filter TSRMLS_CC);
1299 : } else {
1300 5 : ret = php_stream_filter_prepend_ex(&stream->readfilters, filter TSRMLS_CC);
1301 : }
1302 55 : if (ret != SUCCESS) {
1303 7 : php_stream_filter_remove(filter, 1 TSRMLS_CC);
1304 7 : RETURN_FALSE;
1305 : }
1306 48 : if (FAILURE == php_stream_filter_check_chain(&stream->readfilters)) {
1307 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Readfilter chain unstable -- unresolvable unicode/string conversion conflict");
1308 : }
1309 : }
1310 :
1311 65 : if (read_write & PHP_STREAM_FILTER_WRITE) {
1312 47 : filter = php_stream_filter_create(filtername, filterparams, php_stream_is_persistent(stream) TSRMLS_CC);
1313 47 : if (filter == NULL) {
1314 0 : RETURN_FALSE;
1315 : }
1316 :
1317 47 : if (append) {
1318 42 : ret = php_stream_filter_append_ex(&stream->writefilters, filter TSRMLS_CC);
1319 : } else {
1320 5 : ret = php_stream_filter_prepend_ex(&stream->writefilters, filter TSRMLS_CC);
1321 : }
1322 47 : if (ret != SUCCESS) {
1323 0 : php_stream_filter_remove(filter, 1 TSRMLS_CC);
1324 0 : RETURN_FALSE;
1325 : }
1326 47 : if (FAILURE == php_stream_filter_check_chain(&stream->writefilters)) {
1327 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Writefilter chain unstable -- unresolvable unicode/string conversion conflict");
1328 : }
1329 : }
1330 :
1331 65 : if (filter) {
1332 65 : RETURN_RESOURCE(filter->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, filter, php_file_le_stream_filter()));
1333 : } else {
1334 0 : RETURN_FALSE;
1335 : }
1336 : }
1337 : /* }}} */
1338 :
1339 : /* {{{ proto resource stream_filter_prepend(resource stream, string filtername[, int read_write[, mixed filterparams]]) U
1340 : Prepend a filter to a stream */
1341 : PHP_FUNCTION(stream_filter_prepend)
1342 5 : {
1343 5 : apply_filter_to_stream(0, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1344 5 : }
1345 : /* }}} */
1346 :
1347 : /* {{{ proto resource stream_filter_append(resource stream, string filtername[, int read_write[, mixed filterparams]]) U
1348 : Append a filter to a stream */
1349 : PHP_FUNCTION(stream_filter_append)
1350 69 : {
1351 69 : apply_filter_to_stream(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1352 69 : }
1353 : /* }}} */
1354 :
1355 : /* {{{ proto bool stream_filter_remove(resource stream_filter) U
1356 : Flushes any data in the filter's internal buffer, removes it from the chain, and frees the resource */
1357 : PHP_FUNCTION(stream_filter_remove)
1358 18 : {
1359 : zval *zfilter;
1360 : php_stream_filter *filter;
1361 :
1362 18 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zfilter) == FAILURE) {
1363 3 : RETURN_FALSE;
1364 : }
1365 :
1366 15 : filter = zend_fetch_resource(&zfilter TSRMLS_CC, -1, NULL, NULL, 1, php_file_le_stream_filter());
1367 15 : if (!filter) {
1368 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid resource given, not a stream filter");
1369 2 : RETURN_FALSE;
1370 : }
1371 :
1372 13 : if (php_stream_filter_flush(filter, 1) == FAILURE) {
1373 10 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to flush filter, not removing");
1374 10 : RETURN_FALSE;
1375 : }
1376 :
1377 3 : if (zend_list_delete(Z_LVAL_P(zfilter)) == FAILURE) {
1378 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not invalidate filter, not removing");
1379 0 : RETURN_FALSE;
1380 : } else {
1381 3 : if (FAILURE == php_stream_filter_check_chain(filter->chain)) {
1382 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filterchain unstable -- unresolvable unicode/string conversion conflict");
1383 : }
1384 :
1385 3 : php_stream_filter_remove(filter, 1 TSRMLS_CC);
1386 3 : RETURN_TRUE;
1387 : }
1388 : }
1389 : /* }}} */
1390 :
1391 : /* {{{ proto string stream_get_line(resource stream, int maxlen [, string ending]) U
1392 : Read up to maxlen bytes from a stream or until the ending string is found */
1393 : PHP_FUNCTION(stream_get_line)
1394 37 : {
1395 : long max_length;
1396 : zval *zstream;
1397 : size_t buf_size;
1398 : php_stream *stream;
1399 37 : zval **delim = NULL;
1400 :
1401 37 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|Z", &zstream, &max_length, &delim) == FAILURE) {
1402 0 : RETURN_FALSE;
1403 : }
1404 :
1405 37 : if (max_length < 0) {
1406 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The maximum allowed length must be greater than or equal to zero");
1407 0 : RETURN_FALSE;
1408 : }
1409 37 : if (!max_length) {
1410 3 : max_length = PHP_SOCK_CHUNK_SIZE;
1411 : }
1412 :
1413 37 : php_stream_from_zval(stream, &zstream);
1414 :
1415 37 : if (stream->readbuf_type == IS_UNICODE) {
1416 : UChar *buf;
1417 0 : UChar *d = NULL;
1418 0 : int dlen = 0;
1419 :
1420 0 : if (delim) {
1421 0 : convert_to_unicode_ex(delim);
1422 0 : d = Z_USTRVAL_PP(delim);
1423 0 : dlen = Z_USTRLEN_PP(delim);
1424 : }
1425 :
1426 : /* maxchars == maxlength will prevent the otherwise generous maxlen == max_length * 2
1427 : from allocating beyond what's requested */
1428 0 : buf = php_stream_get_record_unicode(stream, max_length * 2, max_length, &buf_size, d, dlen TSRMLS_CC);
1429 0 : if (!buf) {
1430 0 : RETURN_FALSE;
1431 : }
1432 :
1433 0 : RETURN_UNICODEL(buf, buf_size, 0);
1434 : } else { /* IS_STRING */
1435 : char *buf;
1436 37 : char *d = NULL;
1437 37 : int dlen = 0;
1438 :
1439 37 : if (delim) {
1440 37 : convert_to_string_ex(delim);
1441 37 : d = Z_STRVAL_PP(delim);
1442 37 : dlen = Z_STRLEN_PP(delim);
1443 : }
1444 :
1445 37 : buf = php_stream_get_record(stream, max_length, &buf_size, d, dlen TSRMLS_CC);
1446 37 : if (!buf) {
1447 6 : RETURN_FALSE;
1448 : }
1449 :
1450 31 : RETURN_STRINGL(buf, buf_size, 0);
1451 : }
1452 : }
1453 :
1454 : /* }}} */
1455 :
1456 : /* {{{ proto bool stream_set_blocking(resource socket, int mode) U
1457 : Set blocking/non-blocking mode on a socket or stream */
1458 : PHP_FUNCTION(stream_set_blocking)
1459 9 : {
1460 : zval *arg1;
1461 : long arg2;
1462 : int block;
1463 : php_stream *stream;
1464 :
1465 9 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &arg1, &arg2) == FAILURE) {
1466 0 : return;
1467 : }
1468 :
1469 9 : php_stream_from_zval(stream, &arg1);
1470 :
1471 9 : block = arg2;
1472 :
1473 9 : if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, block == 0 ? 0 : 1, NULL) == -1) {
1474 2 : RETURN_FALSE;
1475 : }
1476 7 : RETURN_TRUE;
1477 : }
1478 :
1479 : /* }}} */
1480 :
1481 : /* {{{ proto bool stream_set_timeout(resource stream, int seconds [, int microseconds]) U
1482 : Set timeout on stream read to seconds + microseonds */
1483 : #if HAVE_SYS_TIME_H || defined(PHP_WIN32)
1484 : PHP_FUNCTION(stream_set_timeout)
1485 10 : {
1486 : zval *socket;
1487 10 : long seconds, microseconds = 0;
1488 : struct timeval t;
1489 : php_stream *stream;
1490 10 : int argc = ZEND_NUM_ARGS();
1491 :
1492 10 : if (zend_parse_parameters(argc TSRMLS_CC, "rl|l", &socket, &seconds, µseconds) == FAILURE) {
1493 3 : return;
1494 : }
1495 :
1496 7 : php_stream_from_zval(stream, &socket);
1497 :
1498 6 : t.tv_sec = seconds;
1499 :
1500 6 : if (argc == 3) {
1501 3 : t.tv_usec = microseconds % 1000000;
1502 3 : t.tv_sec += microseconds / 1000000;
1503 : } else {
1504 3 : t.tv_usec = 0;
1505 : }
1506 :
1507 6 : if (PHP_STREAM_OPTION_RETURN_OK == php_stream_set_option(stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &t)) {
1508 4 : RETURN_TRUE;
1509 : }
1510 :
1511 2 : RETURN_FALSE;
1512 : }
1513 : #endif /* HAVE_SYS_TIME_H || defined(PHP_WIN32) */
1514 : /* }}} */
1515 :
1516 : /* {{{ proto int stream_set_write_buffer(resource fp, int buffer) U
1517 : Set file write buffer */
1518 : PHP_FUNCTION(stream_set_write_buffer)
1519 3 : {
1520 : zval *arg1;
1521 : long arg2;
1522 : int ret;
1523 : size_t buff;
1524 : php_stream *stream;
1525 :
1526 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &arg1, &arg2) == FAILURE) {
1527 0 : return;
1528 : }
1529 :
1530 3 : php_stream_from_zval(stream, &arg1);
1531 :
1532 3 : buff = arg2;
1533 :
1534 : /* if buff is 0 then set to non-buffered */
1535 3 : if (buff == 0) {
1536 1 : ret = php_stream_set_option(stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
1537 : } else {
1538 2 : ret = php_stream_set_option(stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_FULL, &buff);
1539 : }
1540 :
1541 3 : RETURN_LONG(ret == 0 ? 0 : EOF);
1542 : }
1543 : /* }}} */
1544 :
1545 : /* {{{ proto int stream_socket_enable_crypto(resource stream, bool enable [, int cryptokind [, resource sessionstream]]) U
1546 : Enable or disable a specific kind of crypto on the stream */
1547 : PHP_FUNCTION(stream_socket_enable_crypto)
1548 0 : {
1549 0 : long cryptokind = 0;
1550 0 : zval *zstream, *zsessstream = NULL;
1551 0 : php_stream *stream, *sessstream = NULL;
1552 : zend_bool enable;
1553 : int ret;
1554 :
1555 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rb|lr", &zstream, &enable, &cryptokind, &zsessstream) == FAILURE) {
1556 0 : RETURN_FALSE;
1557 : }
1558 :
1559 0 : php_stream_from_zval(stream, &zstream);
1560 :
1561 0 : if (ZEND_NUM_ARGS() >= 3) {
1562 0 : if (zsessstream) {
1563 0 : php_stream_from_zval(sessstream, &zsessstream);
1564 : }
1565 :
1566 0 : if (php_stream_xport_crypto_setup(stream, cryptokind, sessstream TSRMLS_CC) < 0) {
1567 0 : RETURN_FALSE;
1568 : }
1569 0 : } else if (enable) {
1570 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "When enabling encryption you must specify the crypto type");
1571 0 : RETURN_FALSE;
1572 : }
1573 :
1574 0 : ret = php_stream_xport_crypto_enable(stream, enable TSRMLS_CC);
1575 0 : switch (ret) {
1576 : case -1:
1577 0 : RETURN_FALSE;
1578 :
1579 : case 0:
1580 0 : RETURN_LONG(0);
1581 :
1582 : default:
1583 0 : RETURN_TRUE;
1584 : }
1585 : }
1586 : /* }}} */
1587 :
1588 : /* {{{ proto bool stream_default_encoding(string encoding) U
1589 : Convenience wrapper for ini_set('unicode.stream_encoding', $encoding) */
1590 : PHP_FUNCTION(stream_default_encoding)
1591 0 : {
1592 : char *encoding;
1593 : int encoding_len;
1594 :
1595 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &encoding, &encoding_len) == FAILURE) {
1596 0 : return;
1597 : }
1598 :
1599 0 : RETURN_BOOL(SUCCESS == zend_alter_ini_entry("unicode.stream_encoding", sizeof("unicode.stream_encoding"),
1600 : encoding, encoding_len, PHP_INI_ALL, PHP_INI_STAGE_RUNTIME));
1601 : }
1602 : /* }}} */
1603 :
1604 : /* {{{ proto void stream_encoding(resource stream[, string encoding]) U
1605 : Set character set for stream encoding
1606 : UTODO: Return current encoding charset
1607 : */
1608 : PHP_FUNCTION(stream_encoding)
1609 8 : {
1610 : zval *zstream;
1611 : php_stream *stream;
1612 8 : char *encoding = NULL;
1613 8 : int encoding_len = 0;
1614 8 : int remove_read_tail = 0, remove_write_tail = 0;
1615 :
1616 8 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s", &zstream, &encoding, &encoding_len) == FAILURE) {
1617 0 : return;
1618 : }
1619 :
1620 8 : php_stream_from_zval(stream, &zstream);
1621 :
1622 : /* Double check that the target encoding is legal before attempting anything */
1623 :
1624 8 : if (stream->readfilters.tail) {
1625 0 : if (stream->readfilters.tail->fops == &php_unicode_from_string_filter_ops) {
1626 : /* Remove the current unicode.from.* filter,
1627 : the filter layer will transcode anything in the read buffer back to binary
1628 : or invalidate the read buffer */
1629 0 : remove_read_tail = 1;
1630 0 : } else if (stream->readbuf_type == IS_UNICODE) {
1631 : /* There's an encoding on the stream already, but then there's filtering happening after that point
1632 : It's asking too much for PHP to figure out what the user wants, throw an error back in their face */
1633 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot change encoding on filtered stream");
1634 0 : RETURN_FALSE;
1635 : }
1636 : }
1637 :
1638 8 : if (stream->writefilters.tail) {
1639 0 : if (stream->writefilters.tail->fops == &php_unicode_to_string_filter_ops) {
1640 : /* Remove the current unicode.to.* filter */
1641 0 : remove_write_tail = 1;
1642 0 : } else if ((stream->writefilters.tail->fops->flags & PSFO_FLAG_OUTPUTS_UNICODE) == 0) {
1643 : /* conversion to binary is happening, them another filter is doing something
1644 : bailout for same reason as read filters */
1645 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot change encoding on filtered stream");
1646 0 : RETURN_FALSE;
1647 : }
1648 : }
1649 :
1650 8 : if (remove_read_tail) {
1651 0 : php_stream_filter_remove(stream->readfilters.tail, 1 TSRMLS_CC);
1652 : }
1653 8 : if (remove_write_tail) {
1654 0 : php_stream_filter_remove(stream->writefilters.tail, 1 TSRMLS_CC);
1655 : }
1656 :
1657 8 : if (encoding_len == 0) {
1658 1 : if (UG(stream_encoding) == NULL) {
1659 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The stream_encoding must be defined");
1660 0 : RETURN_FALSE;
1661 : }
1662 1 : encoding = UG(stream_encoding);
1663 : }
1664 :
1665 : /* UTODO: Allow overriding error handling for converters */
1666 8 : php_stream_encoding_apply(stream, 1, encoding, UG(from_error_mode), UG(from_subst_char));
1667 8 : php_stream_encoding_apply(stream, 0, encoding, UG(to_error_mode), NULL);
1668 :
1669 8 : RETURN_TRUE;
1670 : }
1671 : /* }}} */
1672 :
1673 : /* {{{ proto string stream_resolve_include_path(string filename[, resource context]) U
1674 : Determine what file will be opened by calls to fopen() with a relative path */
1675 : PHP_FUNCTION(stream_resolve_include_path)
1676 4 : {
1677 4 : zval **ppfilename, *zcontext = NULL;
1678 4 : char *filename, *ptr = PG(include_path), *end = ptr + (ptr ? strlen(ptr) : 0), buffer[MAXPATHLEN];
1679 : int filename_len;
1680 4 : php_stream_context *context = NULL;
1681 : struct stat sb;
1682 :
1683 4 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|r", &ppfilename, &zcontext) == FAILURE ||
1684 : php_stream_path_param_encode(ppfilename, &filename, &filename_len, REPORT_ERRORS, context = php_stream_context_from_zval(zcontext, 0)) == FAILURE) {
1685 1 : return;
1686 : }
1687 :
1688 8 : while (ptr < end) {
1689 4 : char *s = strchr(ptr, DEFAULT_DIR_SEPARATOR);
1690 : UChar *upath;
1691 : int upath_len;
1692 :
1693 4 : if (!s) {
1694 1 : s = end;
1695 : }
1696 :
1697 4 : if (s == ptr) {
1698 0 : ptr++;
1699 0 : continue;
1700 : }
1701 :
1702 4 : if ((s - ptr) + 1 + filename_len >= MAXPATHLEN) {
1703 : /* Too long to try */
1704 0 : ptr = s + 1;
1705 0 : continue;
1706 : }
1707 :
1708 4 : memcpy(buffer, ptr, s - ptr);
1709 4 : buffer[s - ptr] = '/';
1710 4 : memcpy(buffer + (s - ptr) + 1, filename, filename_len + 1);
1711 :
1712 4 : if (php_check_open_basedir_ex(buffer, 0 TSRMLS_CC)) {
1713 0 : ptr = s + 1;
1714 0 : continue;
1715 : }
1716 :
1717 4 : if (VCWD_STAT(buffer, &sb)) {
1718 2 : ptr = s + 1;
1719 2 : continue;
1720 : }
1721 :
1722 2 : if (SUCCESS == php_stream_path_decode(NULL, &upath, &upath_len, buffer, (s - ptr) + 1 + filename_len, REPORT_ERRORS, context)) {
1723 2 : RETURN_UNICODEL(upath, upath_len, 0);
1724 : } else {
1725 : /* Fallback */
1726 0 : RETURN_STRINGL(buffer, (s - ptr) + 1 + filename_len, 1);
1727 : }
1728 : }
1729 :
1730 1 : RETURN_FALSE;
1731 : }
1732 : /* }}} */
1733 :
1734 : /* {{{ proto bool stream_is_local(resource stream|string url) U
1735 : */
1736 : PHP_FUNCTION(stream_is_local)
1737 3 : {
1738 : zval **zstream;
1739 3 : php_stream *stream = NULL;
1740 3 : php_stream_wrapper *wrapper = NULL;
1741 :
1742 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &zstream) == FAILURE) {
1743 0 : RETURN_FALSE;
1744 : }
1745 :
1746 3 : if (Z_TYPE_PP(zstream) == IS_RESOURCE) {
1747 1 : php_stream_from_zval(stream, zstream);
1748 1 : if (stream == NULL) {
1749 0 : RETURN_FALSE;
1750 : }
1751 1 : wrapper = stream->wrapper;
1752 : } else {
1753 2 : convert_to_string_ex(zstream);
1754 :
1755 2 : wrapper = php_stream_locate_url_wrapper(Z_STRVAL_PP(zstream), NULL, 0 TSRMLS_CC);
1756 : }
1757 :
1758 3 : if (!wrapper) {
1759 0 : RETURN_FALSE;
1760 : }
1761 :
1762 3 : RETURN_BOOL(wrapper->is_url==0);
1763 : }
1764 : /* }}} */
1765 :
1766 : /* {{{ proto bool stream_supports_lock(resource stream)
1767 : Tells wether the stream supports locking through flock(). */
1768 : PHP_FUNCTION(stream_supports_lock)
1769 5 : {
1770 : php_stream *stream;
1771 : zval *zsrc;
1772 :
1773 5 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zsrc) == FAILURE) {
1774 0 : RETURN_FALSE;
1775 : }
1776 :
1777 5 : php_stream_from_zval(stream, &zsrc);
1778 :
1779 4 : if (!php_stream_supports_lock(stream)) {
1780 2 : RETURN_FALSE;
1781 : }
1782 :
1783 2 : RETURN_TRUE;
1784 : }
1785 :
1786 : #ifdef HAVE_SHUTDOWN
1787 : /* {{{ proto int stream_socket_shutdown(resource stream, int how) U
1788 : causes all or part of a full-duplex connection on the socket associated
1789 : with stream to be shut down. If how is SHUT_RD, further receptions will
1790 : be disallowed. If how is SHUT_WR, further transmissions will be disallowed.
1791 : If how is SHUT_RDWR, further receptions and transmissions will be
1792 : disallowed. */
1793 : PHP_FUNCTION(stream_socket_shutdown)
1794 3 : {
1795 : long how;
1796 : zval *zstream;
1797 : php_stream *stream;
1798 :
1799 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zstream, &how) == FAILURE) {
1800 0 : RETURN_FALSE;
1801 : }
1802 :
1803 3 : if (how != STREAM_SHUT_RD &&
1804 : how != STREAM_SHUT_WR &&
1805 : how != STREAM_SHUT_RDWR) {
1806 0 : RETURN_FALSE;
1807 : }
1808 :
1809 3 : php_stream_from_zval(stream, &zstream);
1810 :
1811 3 : RETURN_BOOL(php_stream_xport_shutdown(stream, (stream_shutdown_t)how TSRMLS_CC) == 0);
1812 : }
1813 : /* }}} */
1814 : #endif
1815 :
1816 : /*
1817 : * Local variables:
1818 : * tab-width: 4
1819 : * c-basic-offset: 4
1820 : * End:
1821 : * vim600: noet sw=4 ts=4 fdm=marker
1822 : * vim<600: noet sw=4 ts=4
1823 : */
1824 :
|