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