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