root/ext/standard/streamsfuncs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. PHP_FUNCTION
  2. PHP_FUNCTION
  3. PHP_FUNCTION
  4. PHP_FUNCTION
  5. PHP_FUNCTION
  6. PHP_FUNCTION
  7. PHP_FUNCTION
  8. PHP_FUNCTION
  9. PHP_FUNCTION
  10. PHP_FUNCTION
  11. PHP_FUNCTION
  12. PHP_FUNCTION
  13. stream_array_to_fd_set
  14. stream_array_from_fd_set
  15. stream_array_emulate_read_fd_set
  16. PHP_FUNCTION
  17. user_space_stream_notifier
  18. user_space_stream_notifier_dtor
  19. parse_context_options
  20. parse_context_params
  21. decode_context_param
  22. PHP_FUNCTION
  23. PHP_FUNCTION
  24. PHP_FUNCTION
  25. PHP_FUNCTION
  26. PHP_FUNCTION
  27. PHP_FUNCTION
  28. PHP_FUNCTION
  29. apply_filter_to_stream
  30. PHP_FUNCTION
  31. PHP_FUNCTION
  32. PHP_FUNCTION
  33. PHP_FUNCTION
  34. PHP_FUNCTION
  35. PHP_FUNCTION
  36. PHP_FUNCTION
  37. PHP_FUNCTION
  38. PHP_FUNCTION
  39. PHP_FUNCTION
  40. PHP_FUNCTION
  41. PHP_FUNCTION
  42. PHP_FUNCTION
  43. PHP_FUNCTION

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

/* [<][>][^][v][top][bottom][index][help] */