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

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