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