Annotation of embedaddon/php/ext/standard/streamsfuncs.c, revision 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>