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