Return to streamsfuncs.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard |
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: