1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
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)
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]]]]])
85 : Open a client connection to a remote address */
86 : PHP_FUNCTION(stream_socket_client)
87 37 : {
88 : char *host;
89 : int host_len;
90 37 : zval *zerrno = NULL, *zerrstr = NULL, *zcontext = NULL;
91 37 : double timeout = FG(default_socket_timeout);
92 : php_timeout_ull conv;
93 : struct timeval tv;
94 37 : char *hashkey = NULL;
95 37 : php_stream *stream = NULL;
96 : int err;
97 37 : long flags = PHP_STREAM_CLIENT_CONNECT;
98 37 : char *errstr = NULL;
99 37 : php_stream_context *context = NULL;
100 :
101 37 : RETVAL_FALSE;
102 :
103 37 : 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 36 : context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
108 :
109 36 : if (context) {
110 36 : zend_list_addref(context->rsrc_id);
111 : }
112 :
113 36 : 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 36 : conv = (php_timeout_ull) (timeout * 1000000.0);
119 36 : tv.tv_sec = conv / 1000000;
120 36 : tv.tv_usec = conv % 1000000;
121 :
122 36 : if (zerrno) {
123 10 : zval_dtor(zerrno);
124 10 : ZVAL_LONG(zerrno, 0);
125 : }
126 36 : if (zerrstr) {
127 6 : zval_dtor(zerrstr);
128 6 : ZVAL_STRING(zerrstr, "", 1);
129 : }
130 :
131 36 : stream = php_stream_xport_create(host, host_len, ENFORCE_SAFE_MODE | 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 36 : 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 36 : if (hashkey) {
146 0 : efree(hashkey);
147 : }
148 :
149 36 : 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 : /* no need to dup; we need to efree buf anyway */
156 5 : zval_dtor(zerrstr);
157 5 : ZVAL_STRING(zerrstr, errstr, 0);
158 4 : } else if (errstr) {
159 4 : efree(errstr);
160 : }
161 9 : RETURN_FALSE;
162 : }
163 :
164 27 : if (errstr) {
165 0 : efree(errstr);
166 : }
167 :
168 27 : php_stream_to_zval(stream, return_value);
169 :
170 : }
171 : /* }}} */
172 :
173 : /* {{{ proto resource stream_socket_server(string localaddress [, long &errcode [, string &errstring [, long flags [, resource context]]]])
174 : Create a server socket bound to localaddress */
175 : PHP_FUNCTION(stream_socket_server)
176 68 : {
177 : char *host;
178 : int host_len;
179 68 : zval *zerrno = NULL, *zerrstr = NULL, *zcontext = NULL;
180 68 : php_stream *stream = NULL;
181 68 : int err = 0;
182 68 : long flags = STREAM_XPORT_BIND | STREAM_XPORT_LISTEN;
183 68 : char *errstr = NULL;
184 68 : php_stream_context *context = NULL;
185 :
186 68 : RETVAL_FALSE;
187 :
188 68 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zzlr", &host, &host_len, &zerrno, &zerrstr, &flags, &zcontext) == FAILURE) {
189 0 : RETURN_FALSE;
190 : }
191 :
192 68 : context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
193 :
194 68 : if (context) {
195 68 : zend_list_addref(context->rsrc_id);
196 : }
197 :
198 68 : if (zerrno) {
199 47 : zval_dtor(zerrno);
200 47 : ZVAL_LONG(zerrno, 0);
201 : }
202 68 : if (zerrstr) {
203 47 : zval_dtor(zerrstr);
204 47 : ZVAL_STRING(zerrstr, "", 1);
205 : }
206 :
207 68 : stream = php_stream_xport_create(host, host_len, ENFORCE_SAFE_MODE | REPORT_ERRORS,
208 : STREAM_XPORT_SERVER | flags,
209 : NULL, NULL, context, &errstr, &err);
210 :
211 68 : if (stream == NULL) {
212 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to connect to %s (%s)", host, errstr == NULL ? "Unknown error" : errstr);
213 : }
214 :
215 68 : if (stream == NULL) {
216 0 : if (zerrno) {
217 0 : zval_dtor(zerrno);
218 0 : ZVAL_LONG(zerrno, err);
219 : }
220 0 : if (zerrstr && errstr) {
221 : /* no need to dup; we need to efree buf anyway */
222 0 : zval_dtor(zerrstr);
223 0 : ZVAL_STRING(zerrstr, errstr, 0);
224 0 : } else if (errstr) {
225 0 : efree(errstr);
226 : }
227 0 : RETURN_FALSE;
228 : }
229 :
230 68 : if (errstr) {
231 0 : efree(errstr);
232 : }
233 :
234 68 : php_stream_to_zval(stream, return_value);
235 : }
236 : /* }}} */
237 :
238 : /* {{{ proto resource stream_socket_accept(resource serverstream, [ double timeout [, string &peername ]])
239 : Accept a client connection from a server socket */
240 : PHP_FUNCTION(stream_socket_accept)
241 41 : {
242 41 : double timeout = FG(default_socket_timeout);
243 41 : zval *zpeername = NULL;
244 41 : char *peername = NULL;
245 : int peername_len;
246 : php_timeout_ull conv;
247 : struct timeval tv;
248 41 : php_stream *stream = NULL, *clistream = NULL;
249 : zval *zstream;
250 :
251 41 : char *errstr = NULL;
252 :
253 41 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|dz", &zstream, &timeout, &zpeername) == FAILURE) {
254 0 : RETURN_FALSE;
255 : }
256 :
257 41 : php_stream_from_zval(stream, &zstream);
258 :
259 : /* prepare the timeout value for use */
260 41 : conv = (php_timeout_ull) (timeout * 1000000.0);
261 41 : tv.tv_sec = conv / 1000000;
262 41 : tv.tv_usec = conv % 1000000;
263 :
264 41 : if (zpeername) {
265 0 : zval_dtor(zpeername);
266 0 : ZVAL_NULL(zpeername);
267 : }
268 :
269 82 : if (0 == php_stream_xport_accept(stream, &clistream,
270 : zpeername ? &peername : NULL,
271 : zpeername ? &peername_len : NULL,
272 : NULL, NULL,
273 : &tv, &errstr
274 : TSRMLS_CC) && clistream) {
275 :
276 41 : if (peername) {
277 0 : ZVAL_STRINGL(zpeername, peername, peername_len, 0);
278 : }
279 41 : php_stream_to_zval(clistream, return_value);
280 : } else {
281 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "accept failed: %s", errstr ? errstr : "Unknown error");
282 0 : RETVAL_FALSE;
283 : }
284 :
285 41 : if (errstr) {
286 41 : efree(errstr);
287 : }
288 : }
289 : /* }}} */
290 :
291 : /* {{{ proto string stream_socket_get_name(resource stream, bool want_peer)
292 : Returns either the locally bound or remote name for a socket stream */
293 : PHP_FUNCTION(stream_socket_get_name)
294 0 : {
295 : php_stream *stream;
296 : zval *zstream;
297 : zend_bool want_peer;
298 0 : char *name = NULL;
299 : int name_len;
300 :
301 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rb", &zstream, &want_peer) == FAILURE) {
302 0 : RETURN_FALSE;
303 : }
304 :
305 0 : php_stream_from_zval(stream, &zstream);
306 :
307 0 : if (0 != php_stream_xport_get_name(stream, want_peer,
308 : &name,
309 : &name_len,
310 : NULL, NULL
311 : TSRMLS_CC)) {
312 0 : RETURN_FALSE;
313 : }
314 :
315 0 : RETURN_STRINGL(name, name_len, 0);
316 : }
317 : /* }}} */
318 :
319 : /* {{{ proto long stream_socket_sendto(resouce stream, string data [, long flags [, string target_addr]])
320 : Send data to a socket stream. If target_addr is specified it must be in dotted quad (or [ipv6]) format */
321 : PHP_FUNCTION(stream_socket_sendto)
322 0 : {
323 : php_stream *stream;
324 : zval *zstream;
325 0 : long flags = 0;
326 0 : char *data, *target_addr = NULL;
327 0 : int datalen, target_addr_len = 0;
328 : php_sockaddr_storage sa;
329 0 : socklen_t sl = 0;
330 :
331 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|ls", &zstream, &data, &datalen, &flags, &target_addr, &target_addr_len) == FAILURE) {
332 0 : RETURN_FALSE;
333 : }
334 0 : php_stream_from_zval(stream, &zstream);
335 :
336 0 : if (target_addr_len) {
337 : /* parse the address */
338 0 : if (FAILURE == php_network_parse_network_address_with_port(target_addr, target_addr_len, (struct sockaddr*)&sa, &sl TSRMLS_CC)) {
339 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse `%s' into a valid network address", target_addr);
340 0 : RETURN_FALSE;
341 : }
342 : }
343 :
344 0 : RETURN_LONG(php_stream_xport_sendto(stream, data, datalen, flags, target_addr ? &sa : NULL, sl TSRMLS_CC));
345 : }
346 : /* }}} */
347 :
348 : /* {{{ proto string stream_socket_recvfrom(resource stream, long amount [, long flags [, string &remote_addr]])
349 : Receives data from a socket stream */
350 : PHP_FUNCTION(stream_socket_recvfrom)
351 0 : {
352 : php_stream *stream;
353 0 : zval *zstream, *zremote = NULL;
354 0 : char *remote_addr = NULL;
355 : int remote_addr_len;
356 0 : long to_read = 0;
357 : char *read_buf;
358 0 : long flags = 0;
359 : int recvd;
360 :
361 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|lz", &zstream, &to_read, &flags, &zremote) == FAILURE) {
362 0 : RETURN_FALSE;
363 : }
364 :
365 0 : php_stream_from_zval(stream, &zstream);
366 :
367 0 : if (zremote) {
368 0 : zval_dtor(zremote);
369 0 : ZVAL_NULL(zremote);
370 : }
371 :
372 0 : if (to_read <= 0) {
373 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length parameter must be greater than 0");
374 0 : RETURN_FALSE;
375 : }
376 :
377 0 : read_buf = safe_emalloc(1, to_read, 1);
378 :
379 0 : recvd = php_stream_xport_recvfrom(stream, read_buf, to_read, flags, NULL, NULL,
380 : zremote ? &remote_addr : NULL,
381 : zremote ? &remote_addr_len : NULL
382 : TSRMLS_CC);
383 :
384 0 : if (recvd >= 0) {
385 0 : if (zremote) {
386 0 : ZVAL_STRINGL(zremote, remote_addr, remote_addr_len, 0);
387 : }
388 0 : read_buf[recvd] = '\0';
389 :
390 0 : if (PG(magic_quotes_runtime)) {
391 0 : Z_TYPE_P(return_value) = IS_STRING;
392 0 : Z_STRVAL_P(return_value) = php_addslashes(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), &Z_STRLEN_P(return_value), 1 TSRMLS_CC);
393 0 : return;
394 : } else {
395 0 : RETURN_STRINGL(read_buf, recvd, 0);
396 : }
397 : }
398 :
399 0 : efree(read_buf);
400 0 : RETURN_FALSE;
401 : }
402 : /* }}} */
403 :
404 : /* {{{ proto string stream_get_contents(resource source [, long maxlen [, long offset]])
405 : Reads all remaining bytes (or up to maxlen bytes) from a stream and returns them as a string. */
406 : PHP_FUNCTION(stream_get_contents)
407 97 : {
408 : php_stream *stream;
409 : zval *zsrc;
410 97 : long maxlen = PHP_STREAM_COPY_ALL, pos = 0;
411 : int len, newlen;
412 97 : char *contents = NULL;
413 :
414 97 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|ll", &zsrc, &maxlen, &pos) == FAILURE) {
415 2 : RETURN_FALSE;
416 : }
417 :
418 95 : php_stream_from_zval(stream, &zsrc);
419 :
420 95 : if ((pos > 0 || (pos == 0 && ZEND_NUM_ARGS() > 2)) && php_stream_seek(stream, pos, SEEK_SET) < 0) {
421 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek to position %ld in the stream", pos);
422 0 : RETURN_FALSE;
423 : }
424 :
425 95 : len = php_stream_copy_to_mem(stream, &contents, maxlen, 0);
426 :
427 95 : if (contents) {
428 71 : if (len && PG(magic_quotes_runtime)) {
429 0 : contents = php_addslashes(contents, len, &newlen, 1 TSRMLS_CC); /* 1 = free source string */
430 0 : len = newlen;
431 : }
432 71 : RETVAL_STRINGL(contents, len, 0);
433 : } else {
434 24 : RETVAL_EMPTY_STRING();
435 : }
436 : }
437 : /* }}} */
438 :
439 : /* {{{ proto long stream_copy_to_stream(resource source, resource dest [, long maxlen [, long pos]])
440 : Reads up to maxlen bytes from source stream and writes them to dest stream. */
441 : PHP_FUNCTION(stream_copy_to_stream)
442 15 : {
443 : php_stream *src, *dest;
444 : zval *zsrc, *zdest;
445 15 : long maxlen = PHP_STREAM_COPY_ALL, pos = 0;
446 : size_t len;
447 : int ret;
448 :
449 15 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|ll", &zsrc, &zdest, &maxlen, &pos) == FAILURE) {
450 0 : RETURN_FALSE;
451 : }
452 :
453 15 : php_stream_from_zval(src, &zsrc);
454 15 : php_stream_from_zval(dest, &zdest);
455 :
456 15 : if (pos > 0 && php_stream_seek(src, pos, SEEK_SET) < 0) {
457 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek to position %ld in the stream", pos);
458 0 : RETURN_FALSE;
459 : }
460 :
461 15 : ret = php_stream_copy_to_stream_ex(src, dest, maxlen, &len);
462 :
463 15 : if (ret != SUCCESS) {
464 2 : RETURN_FALSE;
465 : }
466 13 : RETURN_LONG(len);
467 : }
468 : /* }}} */
469 :
470 : /* {{{ proto array stream_get_meta_data(resource fp)
471 : Retrieves header/meta data from streams/file pointers */
472 : PHP_FUNCTION(stream_get_meta_data)
473 109 : {
474 : zval *arg1;
475 : php_stream *stream;
476 : zval *newval;
477 :
478 109 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
479 10 : return;
480 : }
481 99 : php_stream_from_zval(stream, &arg1);
482 :
483 98 : array_init(return_value);
484 :
485 98 : if (stream->wrapperdata) {
486 37 : MAKE_STD_ZVAL(newval);
487 37 : *newval = *(stream->wrapperdata);
488 37 : zval_copy_ctor(newval);
489 37 : INIT_PZVAL(newval);
490 :
491 37 : add_assoc_zval(return_value, "wrapper_data", newval);
492 : }
493 98 : if (stream->wrapper) {
494 80 : add_assoc_string(return_value, "wrapper_type", (char *)stream->wrapper->wops->label, 1);
495 : }
496 98 : add_assoc_string(return_value, "stream_type", (char *)stream->ops->label, 1);
497 :
498 98 : add_assoc_string(return_value, "mode", stream->mode, 1);
499 :
500 : #if 0 /* TODO: needs updating for new filter API */
501 : if (stream->filterhead) {
502 : php_stream_filter *filter;
503 :
504 : MAKE_STD_ZVAL(newval);
505 : array_init(newval);
506 :
507 : for (filter = stream->filterhead; filter != NULL; filter = filter->next) {
508 : add_next_index_string(newval, (char *)filter->fops->label, 1);
509 : }
510 :
511 : add_assoc_zval(return_value, "filters", newval);
512 : }
513 : #endif
514 :
515 98 : add_assoc_long(return_value, "unread_bytes", stream->writepos - stream->readpos);
516 :
517 98 : add_assoc_bool(return_value, "seekable", (stream->ops->seek) && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0);
518 98 : if (stream->orig_path) {
519 78 : add_assoc_string(return_value, "uri", stream->orig_path, 1);
520 : }
521 :
522 98 : if (!php_stream_populate_meta_data(stream, return_value)) {
523 76 : add_assoc_bool(return_value, "timed_out", 0);
524 76 : add_assoc_bool(return_value, "blocked", 1);
525 76 : add_assoc_bool(return_value, "eof", php_stream_eof(stream));
526 : }
527 :
528 : }
529 : /* }}} */
530 :
531 : /* {{{ proto array stream_get_transports()
532 : Retrieves list of registered socket transports */
533 : PHP_FUNCTION(stream_get_transports)
534 2 : {
535 : HashTable *stream_xport_hash;
536 : char *stream_xport;
537 : int stream_xport_len;
538 : ulong num_key;
539 :
540 2 : if (zend_parse_parameters_none() == FAILURE) {
541 0 : return;
542 : }
543 :
544 2 : if ((stream_xport_hash = php_stream_xport_get_hash())) {
545 : HashPosition pos;
546 2 : array_init(return_value);
547 2 : zend_hash_internal_pointer_reset_ex(stream_xport_hash, &pos);
548 20 : while (zend_hash_get_current_key_ex(stream_xport_hash,
549 : &stream_xport, &stream_xport_len,
550 : &num_key, 0, &pos) == HASH_KEY_IS_STRING) {
551 16 : add_next_index_stringl(return_value, stream_xport, stream_xport_len - 1, 1);
552 16 : zend_hash_move_forward_ex(stream_xport_hash, &pos);
553 : }
554 : } else {
555 0 : RETURN_FALSE;
556 : }
557 : }
558 : /* }}} */
559 :
560 : /* {{{ proto array stream_get_wrappers()
561 : Retrieves list of registered stream wrappers */
562 : PHP_FUNCTION(stream_get_wrappers)
563 4 : {
564 : HashTable *url_stream_wrappers_hash;
565 : char *stream_protocol;
566 4 : int key_flags, stream_protocol_len = 0;
567 : ulong num_key;
568 :
569 4 : if (zend_parse_parameters_none() == FAILURE) {
570 0 : return;
571 : }
572 :
573 4 : if ((url_stream_wrappers_hash = php_stream_get_url_stream_wrappers_hash())) {
574 : HashPosition pos;
575 4 : array_init(return_value);
576 4 : for (zend_hash_internal_pointer_reset_ex(url_stream_wrappers_hash, &pos);
577 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;
578 64 : zend_hash_move_forward_ex(url_stream_wrappers_hash, &pos)) {
579 64 : if (key_flags == HASH_KEY_IS_STRING) {
580 64 : add_next_index_stringl(return_value, stream_protocol, stream_protocol_len - 1, 1);
581 : }
582 : }
583 : } else {
584 0 : RETURN_FALSE;
585 : }
586 :
587 : }
588 : /* }}} */
589 :
590 : /* {{{ stream_select related functions */
591 : static int stream_array_to_fd_set(zval *stream_array, fd_set *fds, php_socket_t *max_fd TSRMLS_DC)
592 711956 : {
593 : zval **elem;
594 : php_stream *stream;
595 : php_socket_t this_fd;
596 711956 : int cnt = 0;
597 :
598 711956 : if (Z_TYPE_P(stream_array) != IS_ARRAY) {
599 0 : return 0;
600 : }
601 711956 : for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream_array));
602 3559734 : zend_hash_get_current_data(Z_ARRVAL_P(stream_array), (void **) &elem) == SUCCESS;
603 2135822 : zend_hash_move_forward(Z_ARRVAL_P(stream_array))) {
604 :
605 2135822 : php_stream_from_zval_no_verify(stream, elem);
606 2135822 : if (stream == NULL) {
607 711936 : continue;
608 : }
609 : /* get the fd.
610 : * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag
611 : * when casting. It is only used here so that the buffered data warning
612 : * is not displayed.
613 : * */
614 1423886 : if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&this_fd, 1) && this_fd >= 0) {
615 :
616 1423881 : PHP_SAFE_FD_SET(this_fd, fds);
617 :
618 1423881 : if (this_fd > *max_fd) {
619 1423878 : *max_fd = this_fd;
620 : }
621 1423881 : cnt++;
622 : }
623 : }
624 711956 : return cnt ? 1 : 0;
625 : }
626 :
627 : static int stream_array_from_fd_set(zval *stream_array, fd_set *fds TSRMLS_DC)
628 711949 : {
629 : zval **elem, **dest_elem;
630 : php_stream *stream;
631 : HashTable *new_hash;
632 : php_socket_t this_fd;
633 711949 : int ret = 0;
634 :
635 711949 : if (Z_TYPE_P(stream_array) != IS_ARRAY) {
636 0 : return 0;
637 : }
638 711949 : ALLOC_HASHTABLE(new_hash);
639 711949 : zend_hash_init(new_hash, zend_hash_num_elements(Z_ARRVAL_P(stream_array)), NULL, ZVAL_PTR_DTOR, 0);
640 :
641 711949 : for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream_array));
642 3559713 : zend_hash_get_current_data(Z_ARRVAL_P(stream_array), (void **) &elem) == SUCCESS;
643 2135815 : zend_hash_move_forward(Z_ARRVAL_P(stream_array))) {
644 :
645 2135815 : php_stream_from_zval_no_verify(stream, elem);
646 2135815 : if (stream == NULL) {
647 711936 : 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 1423879 : if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&this_fd, 1) && this_fd >= 0) {
655 1423879 : if (PHP_SAFE_FD_ISSET(this_fd, fds)) {
656 729376 : zend_hash_next_index_insert(new_hash, (void *)elem, sizeof(zval *), (void **)&dest_elem);
657 729376 : if (dest_elem) {
658 729376 : zval_add_ref(dest_elem);
659 : }
660 729376 : ret++;
661 729376 : continue;
662 : }
663 : }
664 : }
665 :
666 : /* destroy old array and add new one */
667 711949 : zend_hash_destroy(Z_ARRVAL_P(stream_array));
668 711949 : efree(Z_ARRVAL_P(stream_array));
669 :
670 711949 : zend_hash_internal_pointer_reset(new_hash);
671 711949 : Z_ARRVAL_P(stream_array) = new_hash;
672 :
673 711949 : return ret;
674 : }
675 :
676 : static int stream_array_emulate_read_fd_set(zval *stream_array TSRMLS_DC)
677 711943 : {
678 : zval **elem, **dest_elem;
679 : php_stream *stream;
680 : HashTable *new_hash;
681 711943 : int ret = 0;
682 :
683 711943 : if (Z_TYPE_P(stream_array) != IS_ARRAY) {
684 0 : return 0;
685 : }
686 711943 : ALLOC_HASHTABLE(new_hash);
687 711943 : zend_hash_init(new_hash, zend_hash_num_elements(Z_ARRVAL_P(stream_array)), NULL, ZVAL_PTR_DTOR, 0);
688 :
689 711943 : for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream_array));
690 3559700 : zend_hash_get_current_data(Z_ARRVAL_P(stream_array), (void **) &elem) == SUCCESS;
691 2135814 : zend_hash_move_forward(Z_ARRVAL_P(stream_array))) {
692 :
693 2135814 : php_stream_from_zval_no_verify(stream, elem);
694 2135814 : if (stream == NULL) {
695 711936 : continue;
696 : }
697 1423878 : if ((stream->writepos - stream->readpos) > 0) {
698 : /* allow readable non-descriptor based streams to participate in stream_select.
699 : * Non-descriptor streams will only "work" if they have previously buffered the
700 : * data. Not ideal, but better than nothing.
701 : * This branch of code also allows blocking streams with buffered data to
702 : * operate correctly in stream_select.
703 : * */
704 1 : zend_hash_next_index_insert(new_hash, (void *)elem, sizeof(zval *), (void **)&dest_elem);
705 1 : if (dest_elem) {
706 1 : zval_add_ref(dest_elem);
707 : }
708 1 : ret++;
709 1 : continue;
710 : }
711 : }
712 :
713 711943 : if (ret > 0) {
714 : /* destroy old array and add new one */
715 1 : zend_hash_destroy(Z_ARRVAL_P(stream_array));
716 1 : efree(Z_ARRVAL_P(stream_array));
717 :
718 1 : zend_hash_internal_pointer_reset(new_hash);
719 1 : Z_ARRVAL_P(stream_array) = new_hash;
720 : } else {
721 711942 : zend_hash_destroy(new_hash);
722 711942 : FREE_HASHTABLE(new_hash);
723 : }
724 :
725 711943 : return ret;
726 : }
727 : /* }}} */
728 :
729 : /* {{{ proto int stream_select(array &read_streams, array &write_streams, array &except_streams, int tv_sec[, int tv_usec])
730 : Runs the select() system call on the sets of streams with a timeout specified by tv_sec and tv_usec */
731 : PHP_FUNCTION(stream_select)
732 711948 : {
733 711948 : zval *r_array, *w_array, *e_array, **sec = NULL;
734 : struct timeval tv;
735 711948 : struct timeval *tv_p = NULL;
736 : fd_set rfds, wfds, efds;
737 711948 : php_socket_t max_fd = 0;
738 711948 : int retval, sets = 0;
739 711948 : long usec = 0;
740 711948 : int set_count, max_set_count = 0;
741 :
742 711948 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!a!Z!|l", &r_array, &w_array, &e_array, &sec, &usec) == FAILURE)
743 0 : return;
744 :
745 711948 : FD_ZERO(&rfds);
746 711948 : FD_ZERO(&wfds);
747 711948 : FD_ZERO(&efds);
748 :
749 711948 : if (r_array != NULL) {
750 711948 : set_count = stream_array_to_fd_set(r_array, &rfds, &max_fd TSRMLS_CC);
751 711948 : if (set_count > max_set_count)
752 711942 : max_set_count = set_count;
753 711948 : sets += set_count;
754 : }
755 :
756 711948 : if (w_array != NULL) {
757 5 : set_count = stream_array_to_fd_set(w_array, &wfds, &max_fd TSRMLS_CC);
758 5 : if (set_count > max_set_count)
759 1 : max_set_count = set_count;
760 5 : sets += set_count;
761 : }
762 :
763 711948 : if (e_array != NULL) {
764 3 : set_count = stream_array_to_fd_set(e_array, &efds, &max_fd TSRMLS_CC);
765 3 : if (set_count > max_set_count)
766 0 : max_set_count = set_count;
767 3 : sets += set_count;
768 : }
769 :
770 711948 : if (!sets) {
771 5 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "No stream arrays were passed");
772 5 : RETURN_FALSE;
773 : }
774 :
775 711943 : PHP_SAFE_MAX_FD(max_fd, max_set_count);
776 :
777 : /* If seconds is not set to null, build the timeval, else we wait indefinitely */
778 711943 : if (sec != NULL) {
779 711943 : convert_to_long_ex(sec);
780 :
781 711943 : if (Z_LVAL_PP(sec) < 0) {
782 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The seconds parameter must be greater than 0");
783 0 : RETURN_FALSE;
784 711943 : } else if (usec < 0) {
785 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The microseconds parameter must be greater than 0");
786 0 : RETURN_FALSE;
787 : }
788 :
789 : /* Solaris + BSD do not like microsecond values which are >= 1 sec */
790 711943 : if (usec > 999999) {
791 0 : tv.tv_sec = Z_LVAL_PP(sec) + (usec / 1000000);
792 0 : tv.tv_usec = usec % 1000000;
793 : } else {
794 711943 : tv.tv_sec = Z_LVAL_PP(sec);
795 711943 : tv.tv_usec = usec;
796 : }
797 :
798 711943 : tv_p = &tv;
799 : }
800 :
801 : /* slight hack to support buffered data; if there is data sitting in the
802 : * read buffer of any of the streams in the read array, let's pretend
803 : * that we selected, but return only the readable sockets */
804 711943 : if (r_array != NULL) {
805 :
806 711943 : retval = stream_array_emulate_read_fd_set(r_array TSRMLS_CC);
807 711943 : if (retval > 0) {
808 1 : if (w_array != NULL) {
809 1 : zend_hash_clean(Z_ARRVAL_P(w_array));
810 : }
811 1 : if (e_array != NULL) {
812 0 : zend_hash_clean(Z_ARRVAL_P(e_array));
813 : }
814 1 : RETURN_LONG(retval);
815 : }
816 : }
817 :
818 711942 : retval = php_select(max_fd+1, &rfds, &wfds, &efds, tv_p);
819 :
820 711942 : if (retval == -1) {
821 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s (max_fd=%d)",
822 : errno, strerror(errno), max_fd);
823 0 : RETURN_FALSE;
824 : }
825 :
826 711942 : if (r_array != NULL) stream_array_from_fd_set(r_array, &rfds TSRMLS_CC);
827 711942 : if (w_array != NULL) stream_array_from_fd_set(w_array, &wfds TSRMLS_CC);
828 711942 : if (e_array != NULL) stream_array_from_fd_set(e_array, &efds TSRMLS_CC);
829 :
830 711942 : RETURN_LONG(retval);
831 : }
832 : /* }}} */
833 :
834 : /* {{{ stream_context related functions */
835 : static void user_space_stream_notifier(php_stream_context *context, int notifycode, int severity,
836 : char *xmsg, int xcode, size_t bytes_sofar, size_t bytes_max, void * ptr TSRMLS_DC)
837 0 : {
838 0 : zval *callback = (zval*)context->notifier->ptr;
839 0 : zval *retval = NULL;
840 : zval zvs[6];
841 : zval *ps[6];
842 : zval **ptps[6];
843 : int i;
844 :
845 0 : for (i = 0; i < 6; i++) {
846 0 : INIT_ZVAL(zvs[i]);
847 0 : ps[i] = &zvs[i];
848 0 : ptps[i] = &ps[i];
849 0 : MAKE_STD_ZVAL(ps[i]);
850 : }
851 :
852 0 : ZVAL_LONG(ps[0], notifycode);
853 0 : ZVAL_LONG(ps[1], severity);
854 0 : if (xmsg) {
855 0 : ZVAL_STRING(ps[2], xmsg, 1);
856 : } else {
857 0 : ZVAL_NULL(ps[2]);
858 : }
859 0 : ZVAL_LONG(ps[3], xcode);
860 0 : ZVAL_LONG(ps[4], bytes_sofar);
861 0 : ZVAL_LONG(ps[5], bytes_max);
862 :
863 0 : if (FAILURE == call_user_function_ex(EG(function_table), NULL, callback, &retval, 6, ptps, 0, NULL TSRMLS_CC)) {
864 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to call user notifier");
865 : }
866 0 : for (i = 0; i < 6; i++) {
867 0 : zval_ptr_dtor(&ps[i]);
868 : }
869 0 : if (retval) {
870 0 : zval_ptr_dtor(&retval);
871 : }
872 0 : }
873 :
874 : static void user_space_stream_notifier_dtor(php_stream_notifier *notifier)
875 2 : {
876 2 : if (notifier && notifier->ptr) {
877 2 : zval_ptr_dtor((zval **)&(notifier->ptr));
878 2 : notifier->ptr = NULL;
879 : }
880 2 : }
881 :
882 : static int parse_context_options(php_stream_context *context, zval *options TSRMLS_DC)
883 49 : {
884 : HashPosition pos, opos;
885 : zval **wval, **oval;
886 : char *wkey, *okey;
887 : int wkey_len, okey_len;
888 49 : int ret = SUCCESS;
889 : ulong num_key;
890 :
891 49 : zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(options), &pos);
892 147 : while (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_P(options), (void**)&wval, &pos)) {
893 97 : if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(Z_ARRVAL_P(options), &wkey, &wkey_len, &num_key, 0, &pos)
894 : && Z_TYPE_PP(wval) == IS_ARRAY) {
895 :
896 48 : zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(wval), &opos);
897 182 : while (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(wval), (void**)&oval, &opos)) {
898 :
899 86 : if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(Z_ARRVAL_PP(wval), &okey, &okey_len, &num_key, 0, &opos)) {
900 86 : php_stream_context_set_option(context, wkey, okey, *oval);
901 : }
902 86 : zend_hash_move_forward_ex(Z_ARRVAL_PP(wval), &opos);
903 : }
904 :
905 : } else {
906 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "options should have the form [\"wrappername\"][\"optionname\"] = $value");
907 : }
908 49 : zend_hash_move_forward_ex(Z_ARRVAL_P(options), &pos);
909 : }
910 :
911 49 : return ret;
912 : }
913 :
914 : static int parse_context_params(php_stream_context *context, zval *params TSRMLS_DC)
915 3 : {
916 3 : int ret = SUCCESS;
917 : zval **tmp;
918 :
919 3 : if (SUCCESS == zend_hash_find(Z_ARRVAL_P(params), "notification", sizeof("notification"), (void**)&tmp)) {
920 :
921 2 : if (context->notifier) {
922 1 : php_stream_notification_free(context->notifier);
923 1 : context->notifier = NULL;
924 : }
925 :
926 2 : context->notifier = php_stream_notification_alloc();
927 2 : context->notifier->func = user_space_stream_notifier;
928 2 : context->notifier->ptr = *tmp;
929 2 : Z_ADDREF_P(*tmp);
930 2 : context->notifier->dtor = user_space_stream_notifier_dtor;
931 : }
932 3 : if (SUCCESS == zend_hash_find(Z_ARRVAL_P(params), "options", sizeof("options"), (void**)&tmp)) {
933 1 : if (Z_TYPE_PP(tmp) == IS_ARRAY) {
934 0 : parse_context_options(context, *tmp TSRMLS_CC);
935 : } else {
936 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream/context parameter");
937 : }
938 : }
939 :
940 3 : return ret;
941 : }
942 :
943 : /* given a zval which is either a stream or a context, return the underlying
944 : * stream_context. If it is a stream that does not have a context assigned, it
945 : * will create and assign a context and return that. */
946 : static php_stream_context *decode_context_param(zval *contextresource TSRMLS_DC)
947 12 : {
948 12 : php_stream_context *context = NULL;
949 :
950 12 : context = zend_fetch_resource(&contextresource TSRMLS_CC, -1, NULL, NULL, 1, php_le_stream_context());
951 12 : if (context == NULL) {
952 : php_stream *stream;
953 :
954 0 : stream = zend_fetch_resource(&contextresource TSRMLS_CC, -1, NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream);
955 :
956 0 : if (stream) {
957 0 : context = stream->context;
958 0 : if (context == NULL) {
959 : /* Only way this happens is if file is opened with NO_DEFAULT_CONTEXT
960 : param, but then something is called which requires a context.
961 : Don't give them the default one though since they already said they
962 : didn't want it. */
963 0 : context = stream->context = php_stream_context_alloc();
964 : }
965 : }
966 : }
967 :
968 12 : return context;
969 : }
970 : /* }}} */
971 :
972 : /* {{{ proto array stream_context_get_options(resource context|resource stream)
973 : Retrieve options for a stream/wrapper/context */
974 : PHP_FUNCTION(stream_context_get_options)
975 2 : {
976 : zval *zcontext;
977 : php_stream_context *context;
978 :
979 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zcontext) == FAILURE) {
980 0 : RETURN_FALSE;
981 : }
982 2 : context = decode_context_param(zcontext TSRMLS_CC);
983 2 : if (!context) {
984 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream/context parameter");
985 0 : RETURN_FALSE;
986 : }
987 :
988 2 : RETURN_ZVAL(context->options, 1, 0);
989 : }
990 : /* }}} */
991 :
992 : /* {{{ proto bool stream_context_set_option(resource context|resource stream, string wrappername, string optionname, mixed value)
993 : Set an option for a wrapper */
994 : PHP_FUNCTION(stream_context_set_option)
995 1 : {
996 1 : zval *options = NULL, *zcontext = NULL, *zvalue = NULL;
997 : php_stream_context *context;
998 : char *wrappername, *optionname;
999 : int wrapperlen, optionlen;
1000 :
1001 1 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
1002 : "rssz", &zcontext, &wrappername, &wrapperlen,
1003 : &optionname, &optionlen, &zvalue) == FAILURE) {
1004 0 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
1005 : "ra", &zcontext, &options) == FAILURE) {
1006 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "called with wrong number or type of parameters; please RTM");
1007 0 : RETURN_FALSE;
1008 : }
1009 : }
1010 :
1011 : /* figure out where the context is coming from exactly */
1012 1 : context = decode_context_param(zcontext TSRMLS_CC);
1013 1 : if (!context) {
1014 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream/context parameter");
1015 0 : RETURN_FALSE;
1016 : }
1017 :
1018 1 : if (options) {
1019 : /* handle the array syntax */
1020 0 : RETVAL_BOOL(parse_context_options(context, options TSRMLS_CC) == SUCCESS);
1021 : } else {
1022 1 : php_stream_context_set_option(context, wrappername, optionname, zvalue);
1023 1 : RETVAL_TRUE;
1024 : }
1025 : }
1026 : /* }}} */
1027 :
1028 : /* {{{ proto bool stream_context_set_params(resource context|resource stream, array options)
1029 : Set parameters for a file context */
1030 : PHP_FUNCTION(stream_context_set_params)
1031 3 : {
1032 : zval *params, *zcontext;
1033 : php_stream_context *context;
1034 :
1035 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ra", &zcontext, ¶ms) == FAILURE) {
1036 0 : RETURN_FALSE;
1037 : }
1038 :
1039 3 : context = decode_context_param(zcontext TSRMLS_CC);
1040 3 : if (!context) {
1041 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream/context parameter");
1042 0 : RETURN_FALSE;
1043 : }
1044 :
1045 3 : RETVAL_BOOL(parse_context_params(context, params TSRMLS_CC) == SUCCESS);
1046 : }
1047 : /* }}} */
1048 :
1049 : /* {{{ proto array stream_context_get_params(resource context|resource stream)
1050 : Get parameters of a file context */
1051 : PHP_FUNCTION(stream_context_get_params)
1052 6 : {
1053 : zval *zcontext, *options;
1054 : php_stream_context *context;
1055 :
1056 6 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zcontext) == FAILURE) {
1057 0 : RETURN_FALSE;
1058 : }
1059 :
1060 6 : context = decode_context_param(zcontext TSRMLS_CC);
1061 6 : if (!context) {
1062 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream/context parameter");
1063 0 : RETURN_FALSE;
1064 : }
1065 :
1066 6 : array_init(return_value);
1067 6 : if (context->notifier && context->notifier->ptr && context->notifier->func == user_space_stream_notifier) {
1068 4 : add_assoc_zval_ex(return_value, ZEND_STRS("notification"), context->notifier->ptr);
1069 4 : Z_ADDREF_P(context->notifier->ptr);
1070 : }
1071 6 : ALLOC_INIT_ZVAL(options);
1072 6 : ZVAL_ZVAL(options, context->options, 1, 0);
1073 6 : add_assoc_zval_ex(return_value, ZEND_STRS("options"), options);
1074 : }
1075 : /* }}} */
1076 :
1077 : /* {{{ proto resource stream_context_get_default([array options])
1078 : Get a handle on the default file/stream context and optionally set parameters */
1079 : PHP_FUNCTION(stream_context_get_default)
1080 2 : {
1081 2 : zval *params = NULL;
1082 : php_stream_context *context;
1083 :
1084 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a", ¶ms) == FAILURE) {
1085 0 : RETURN_FALSE;
1086 : }
1087 :
1088 2 : if (FG(default_context) == NULL) {
1089 2 : FG(default_context) = php_stream_context_alloc();
1090 : }
1091 2 : context = FG(default_context);
1092 :
1093 2 : if (params) {
1094 0 : parse_context_options(context, params TSRMLS_CC);
1095 : }
1096 :
1097 2 : php_stream_context_to_zval(context, return_value);
1098 : }
1099 : /* }}} */
1100 :
1101 : /* {{{ proto resource stream_context_set_default(array options)
1102 : Set default file/stream context, returns the context as a resource */
1103 : PHP_FUNCTION(stream_context_set_default)
1104 0 : {
1105 0 : zval *options = NULL;
1106 : php_stream_context *context;
1107 :
1108 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &options) == FAILURE) {
1109 0 : return;
1110 : }
1111 :
1112 0 : if (FG(default_context) == NULL) {
1113 0 : FG(default_context) = php_stream_context_alloc();
1114 : }
1115 0 : context = FG(default_context);
1116 :
1117 0 : parse_context_options(context, options TSRMLS_CC);
1118 :
1119 0 : php_stream_context_to_zval(context, return_value);
1120 : }
1121 : /* }}} */
1122 :
1123 : /* {{{ proto resource stream_context_create([array options[, array params]])
1124 : Create a file context and optionally set parameters */
1125 : PHP_FUNCTION(stream_context_create)
1126 77 : {
1127 77 : zval *options = NULL, *params = NULL;
1128 : php_stream_context *context;
1129 :
1130 77 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!a!", &options, ¶ms) == FAILURE) {
1131 0 : RETURN_FALSE;
1132 : }
1133 :
1134 77 : context = php_stream_context_alloc();
1135 :
1136 77 : if (options) {
1137 49 : parse_context_options(context, options TSRMLS_CC);
1138 : }
1139 :
1140 77 : if (params) {
1141 0 : parse_context_params(context, params TSRMLS_CC);
1142 : }
1143 :
1144 77 : RETURN_RESOURCE(context->rsrc_id);
1145 : }
1146 : /* }}} */
1147 :
1148 : /* {{{ streams filter functions */
1149 : static void apply_filter_to_stream(int append, INTERNAL_FUNCTION_PARAMETERS)
1150 79 : {
1151 : zval *zstream;
1152 : php_stream *stream;
1153 : char *filtername;
1154 : int filternamelen;
1155 79 : long read_write = 0;
1156 79 : zval *filterparams = NULL;
1157 79 : php_stream_filter *filter = NULL;
1158 : int ret;
1159 :
1160 79 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|lz", &zstream,
1161 : &filtername, &filternamelen, &read_write, &filterparams) == FAILURE) {
1162 0 : RETURN_FALSE;
1163 : }
1164 :
1165 79 : php_stream_from_zval(stream, &zstream);
1166 :
1167 79 : if ((read_write & PHP_STREAM_FILTER_ALL) == 0) {
1168 : /* Chain not specified.
1169 : * Examine stream->mode to determine which filters are needed
1170 : * There's no harm in attaching a filter to an unused chain,
1171 : * but why waste the memory and clock cycles?
1172 : */
1173 50 : if (strchr(stream->mode, 'r') || strchr(stream->mode, '+')) {
1174 45 : read_write |= PHP_STREAM_FILTER_READ;
1175 : }
1176 50 : if (strchr(stream->mode, 'w') || strchr(stream->mode, '+') || strchr(stream->mode, 'a')) {
1177 43 : read_write |= PHP_STREAM_FILTER_WRITE;
1178 : }
1179 : }
1180 :
1181 79 : if (read_write & PHP_STREAM_FILTER_READ) {
1182 63 : filter = php_stream_filter_create(filtername, filterparams, php_stream_is_persistent(stream) TSRMLS_CC);
1183 63 : if (filter == NULL) {
1184 1 : RETURN_FALSE;
1185 : }
1186 :
1187 62 : if (append) {
1188 57 : ret = php_stream_filter_append_ex(&stream->readfilters, filter TSRMLS_CC);
1189 : } else {
1190 5 : ret = php_stream_filter_prepend_ex(&stream->readfilters, filter TSRMLS_CC);
1191 : }
1192 62 : if (ret != SUCCESS) {
1193 7 : php_stream_filter_remove(filter, 1 TSRMLS_CC);
1194 7 : RETURN_FALSE;
1195 : }
1196 : }
1197 :
1198 71 : if (read_write & PHP_STREAM_FILTER_WRITE) {
1199 48 : filter = php_stream_filter_create(filtername, filterparams, php_stream_is_persistent(stream) TSRMLS_CC);
1200 48 : if (filter == NULL) {
1201 0 : RETURN_FALSE;
1202 : }
1203 :
1204 48 : if (append) {
1205 43 : ret = php_stream_filter_append_ex(&stream->writefilters, filter TSRMLS_CC);
1206 : } else {
1207 5 : ret = php_stream_filter_prepend_ex(&stream->writefilters, filter TSRMLS_CC);
1208 : }
1209 48 : if (ret != SUCCESS) {
1210 0 : php_stream_filter_remove(filter, 1 TSRMLS_CC);
1211 0 : RETURN_FALSE;
1212 : }
1213 : }
1214 :
1215 71 : if (filter) {
1216 71 : RETURN_RESOURCE(filter->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, filter, php_file_le_stream_filter()));
1217 : } else {
1218 0 : RETURN_FALSE;
1219 : }
1220 : }
1221 : /* }}} */
1222 :
1223 : /* {{{ proto resource stream_filter_prepend(resource stream, string filtername[, int read_write[, string filterparams]])
1224 : Prepend a filter to a stream */
1225 : PHP_FUNCTION(stream_filter_prepend)
1226 5 : {
1227 5 : apply_filter_to_stream(0, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1228 5 : }
1229 : /* }}} */
1230 :
1231 : /* {{{ proto resource stream_filter_append(resource stream, string filtername[, int read_write[, string filterparams]])
1232 : Append a filter to a stream */
1233 : PHP_FUNCTION(stream_filter_append)
1234 74 : {
1235 74 : apply_filter_to_stream(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1236 74 : }
1237 : /* }}} */
1238 :
1239 : /* {{{ proto bool stream_filter_remove(resource stream_filter)
1240 : Flushes any data in the filter's internal buffer, removes it from the chain, and frees the resource */
1241 : PHP_FUNCTION(stream_filter_remove)
1242 18 : {
1243 : zval *zfilter;
1244 : php_stream_filter *filter;
1245 :
1246 18 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zfilter) == FAILURE) {
1247 3 : RETURN_FALSE;
1248 : }
1249 :
1250 15 : filter = zend_fetch_resource(&zfilter TSRMLS_CC, -1, NULL, NULL, 1, php_file_le_stream_filter());
1251 15 : if (!filter) {
1252 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid resource given, not a stream filter");
1253 2 : RETURN_FALSE;
1254 : }
1255 :
1256 13 : if (php_stream_filter_flush(filter, 1) == FAILURE) {
1257 10 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to flush filter, not removing");
1258 10 : RETURN_FALSE;
1259 : }
1260 :
1261 3 : if (zend_list_delete(Z_LVAL_P(zfilter)) == FAILURE) {
1262 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not invalidate filter, not removing");
1263 0 : RETURN_FALSE;
1264 : } else {
1265 3 : php_stream_filter_remove(filter, 1 TSRMLS_CC);
1266 3 : RETURN_TRUE;
1267 : }
1268 : }
1269 : /* }}} */
1270 :
1271 : /* {{{ proto string stream_get_line(resource stream, int maxlen [, string ending])
1272 : Read up to maxlen bytes from a stream or until the ending string is found */
1273 : PHP_FUNCTION(stream_get_line)
1274 37 : {
1275 37 : char *str = NULL;
1276 37 : int str_len = 0;
1277 : long max_length;
1278 : zval *zstream;
1279 : char *buf;
1280 : size_t buf_size;
1281 : php_stream *stream;
1282 :
1283 37 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|s", &zstream, &max_length, &str, &str_len) == FAILURE) {
1284 0 : RETURN_FALSE;
1285 : }
1286 :
1287 37 : if (max_length < 0) {
1288 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The maximum allowed length must be greater than or equal to zero");
1289 0 : RETURN_FALSE;
1290 : }
1291 37 : if (!max_length) {
1292 3 : max_length = PHP_SOCK_CHUNK_SIZE;
1293 : }
1294 :
1295 37 : php_stream_from_zval(stream, &zstream);
1296 :
1297 37 : if ((buf = php_stream_get_record(stream, max_length, &buf_size, str, str_len TSRMLS_CC))) {
1298 31 : RETURN_STRINGL(buf, buf_size, 0);
1299 : } else {
1300 6 : RETURN_FALSE;
1301 : }
1302 : }
1303 :
1304 : /* }}} */
1305 :
1306 : /* {{{ proto bool stream_set_blocking(resource socket, int mode)
1307 : Set blocking/non-blocking mode on a socket or stream */
1308 : PHP_FUNCTION(stream_set_blocking)
1309 9 : {
1310 : zval *arg1;
1311 : int block;
1312 : long arg2;
1313 : php_stream *stream;
1314 :
1315 9 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &arg1, &arg2) == FAILURE) {
1316 0 : return;
1317 : }
1318 :
1319 9 : php_stream_from_zval(stream, &arg1);
1320 :
1321 9 : block = arg2;
1322 :
1323 9 : if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, block == 0 ? 0 : 1, NULL) == -1) {
1324 2 : RETURN_FALSE;
1325 : }
1326 :
1327 7 : RETURN_TRUE;
1328 : }
1329 :
1330 : /* }}} */
1331 :
1332 : /* {{{ proto bool stream_set_timeout(resource stream, int seconds [, int microseconds])
1333 : Set timeout on stream read to seconds + microseonds */
1334 : #if HAVE_SYS_TIME_H || defined(PHP_WIN32)
1335 : PHP_FUNCTION(stream_set_timeout)
1336 10 : {
1337 : zval *socket;
1338 10 : long seconds, microseconds = 0;
1339 : struct timeval t;
1340 : php_stream *stream;
1341 10 : int argc = ZEND_NUM_ARGS();
1342 :
1343 10 : if (zend_parse_parameters(argc TSRMLS_CC, "rl|l", &socket, &seconds, µseconds) == FAILURE) {
1344 3 : return;
1345 : }
1346 :
1347 7 : php_stream_from_zval(stream, &socket);
1348 :
1349 6 : t.tv_sec = seconds;
1350 :
1351 6 : if (argc == 3) {
1352 3 : t.tv_usec = microseconds % 1000000;
1353 3 : t.tv_sec += microseconds / 1000000;
1354 : } else {
1355 3 : t.tv_usec = 0;
1356 : }
1357 :
1358 6 : if (PHP_STREAM_OPTION_RETURN_OK == php_stream_set_option(stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &t)) {
1359 4 : RETURN_TRUE;
1360 : }
1361 :
1362 2 : RETURN_FALSE;
1363 : }
1364 : #endif /* HAVE_SYS_TIME_H || defined(PHP_WIN32) */
1365 : /* }}} */
1366 :
1367 : /* {{{ proto int stream_set_write_buffer(resource fp, int buffer)
1368 : Set file write buffer */
1369 : PHP_FUNCTION(stream_set_write_buffer)
1370 3 : {
1371 : zval *arg1;
1372 : int ret;
1373 : long arg2;
1374 : size_t buff;
1375 : php_stream *stream;
1376 :
1377 3 : switch (ZEND_NUM_ARGS()) {
1378 : case 2:
1379 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &arg1, &arg2) == FAILURE) {
1380 0 : RETURN_FALSE;
1381 : }
1382 : break;
1383 : default:
1384 0 : WRONG_PARAM_COUNT;
1385 : /* NOTREACHED */
1386 : break;
1387 : }
1388 :
1389 3 : php_stream_from_zval(stream, &arg1);
1390 :
1391 3 : buff = arg2;
1392 :
1393 : /* if buff is 0 then set to non-buffered */
1394 3 : if (buff == 0) {
1395 1 : ret = php_stream_set_option(stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
1396 : } else {
1397 2 : ret = php_stream_set_option(stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_FULL, &buff);
1398 : }
1399 :
1400 3 : RETURN_LONG(ret == 0 ? 0 : EOF);
1401 : }
1402 : /* }}} */
1403 :
1404 : /* {{{ proto int stream_socket_enable_crypto(resource stream, bool enable [, int cryptokind [, resource sessionstream]])
1405 : Enable or disable a specific kind of crypto on the stream */
1406 : PHP_FUNCTION(stream_socket_enable_crypto)
1407 1 : {
1408 1 : long cryptokind = 0;
1409 1 : zval *zstream, *zsessstream = NULL;
1410 1 : php_stream *stream, *sessstream = NULL;
1411 : zend_bool enable;
1412 : int ret;
1413 :
1414 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rb|lr", &zstream, &enable, &cryptokind, &zsessstream) == FAILURE) {
1415 0 : RETURN_FALSE;
1416 : }
1417 :
1418 1 : php_stream_from_zval(stream, &zstream);
1419 :
1420 1 : if (ZEND_NUM_ARGS() >= 3) {
1421 1 : if (zsessstream) {
1422 0 : php_stream_from_zval(sessstream, &zsessstream);
1423 : }
1424 :
1425 1 : if (php_stream_xport_crypto_setup(stream, cryptokind, sessstream TSRMLS_CC) < 0) {
1426 0 : RETURN_FALSE;
1427 : }
1428 0 : } else if (enable) {
1429 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "When enabling encryption you must specify the crypto type");
1430 0 : RETURN_FALSE;
1431 : }
1432 :
1433 1 : ret = php_stream_xport_crypto_enable(stream, enable TSRMLS_CC);
1434 1 : switch (ret) {
1435 : case -1:
1436 0 : RETURN_FALSE;
1437 :
1438 : case 0:
1439 0 : RETURN_LONG(0);
1440 :
1441 : default:
1442 1 : RETURN_TRUE;
1443 : }
1444 : }
1445 : /* }}} */
1446 :
1447 : /* {{{ proto bool stream_is_local(resource stream|string url) U
1448 : */
1449 : PHP_FUNCTION(stream_is_local)
1450 3 : {
1451 : zval **zstream;
1452 3 : php_stream *stream = NULL;
1453 3 : php_stream_wrapper *wrapper = NULL;
1454 :
1455 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &zstream) == FAILURE) {
1456 0 : RETURN_FALSE;
1457 : }
1458 :
1459 3 : if (Z_TYPE_PP(zstream) == IS_RESOURCE) {
1460 1 : php_stream_from_zval(stream, zstream);
1461 1 : if (stream == NULL) {
1462 0 : RETURN_FALSE;
1463 : }
1464 1 : wrapper = stream->wrapper;
1465 : } else {
1466 2 : convert_to_string_ex(zstream);
1467 :
1468 2 : wrapper = php_stream_locate_url_wrapper(Z_STRVAL_PP(zstream), NULL, 0 TSRMLS_CC);
1469 : }
1470 :
1471 3 : if (!wrapper) {
1472 0 : RETURN_FALSE;
1473 : }
1474 :
1475 3 : RETURN_BOOL(wrapper->is_url==0);
1476 : }
1477 : /* }}} */
1478 :
1479 : /* {{{ proto bool stream_supports_lock(resource stream)
1480 : Tells wether the stream supports locking through flock(). */
1481 : PHP_FUNCTION(stream_supports_lock)
1482 5 : {
1483 : php_stream *stream;
1484 : zval *zsrc;
1485 :
1486 5 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zsrc) == FAILURE) {
1487 0 : RETURN_FALSE;
1488 : }
1489 :
1490 5 : php_stream_from_zval(stream, &zsrc);
1491 :
1492 4 : if (!php_stream_supports_lock(stream)) {
1493 2 : RETURN_FALSE;
1494 : }
1495 :
1496 2 : RETURN_TRUE;
1497 : }
1498 :
1499 : #ifdef HAVE_SHUTDOWN
1500 : /* {{{ proto int stream_socket_shutdown(resource stream, int how)
1501 : causes all or part of a full-duplex connection on the socket associated
1502 : with stream to be shut down. If how is SHUT_RD, further receptions will
1503 : be disallowed. If how is SHUT_WR, further transmissions will be disallowed.
1504 : If how is SHUT_RDWR, further receptions and transmissions will be
1505 : disallowed. */
1506 : PHP_FUNCTION(stream_socket_shutdown)
1507 3 : {
1508 : long how;
1509 : zval *zstream;
1510 : php_stream *stream;
1511 :
1512 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zstream, &how) == FAILURE) {
1513 0 : RETURN_FALSE;
1514 : }
1515 :
1516 3 : if (how != STREAM_SHUT_RD &&
1517 : how != STREAM_SHUT_WR &&
1518 : how != STREAM_SHUT_RDWR) {
1519 0 : RETURN_FALSE;
1520 : }
1521 :
1522 3 : php_stream_from_zval(stream, &zstream);
1523 :
1524 3 : RETURN_BOOL(php_stream_xport_shutdown(stream, (stream_shutdown_t)how TSRMLS_CC) == 0);
1525 : }
1526 : /* }}} */
1527 : #endif
1528 :
1529 : /*
1530 : * Local variables:
1531 : * tab-width: 4
1532 : * c-basic-offset: 4
1533 : * End:
1534 : * vim600: noet sw=4 ts=4 fdm=marker
1535 : * vim<600: noet sw=4 ts=4
1536 : */
1537 :
|