You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1269 lines
35 KiB

23 years ago
23 years ago
22 years ago
22 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2004 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.0 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_0.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. /* $Id$ */
  20. #include "php.h"
  21. #include "php_globals.h"
  22. #include "ext/standard/flock_compat.h"
  23. #include "ext/standard/file.h"
  24. #include "ext/standard/php_filestat.h"
  25. #include "php_open_temporary_file.h"
  26. #include "ext/standard/basic_functions.h"
  27. #include "php_ini.h"
  28. #include "streamsfuncs.h"
  29. #include "php_network.h"
  30. #include "php_string.h"
  31. #ifndef PHP_WIN32
  32. #define php_select(m, r, w, e, t) select(m, r, w, e, t)
  33. #else
  34. #include "win32/select.h"
  35. #endif
  36. static php_stream_context *decode_context_param(zval *contextresource TSRMLS_DC);
  37. /* Streams based network functions */
  38. /* {{{ proto resource stream_socket_client(string remoteaddress [, long &errcode, string &errstring, double timeout, long flags, resource context])
  39. Open a client connection to a remote address */
  40. PHP_FUNCTION(stream_socket_client)
  41. {
  42. char *host;
  43. int host_len;
  44. zval *zerrno = NULL, *zerrstr = NULL, *zcontext = NULL;
  45. double timeout = FG(default_socket_timeout);
  46. unsigned long conv;
  47. struct timeval tv;
  48. char *hashkey = NULL;
  49. php_stream *stream = NULL;
  50. int err;
  51. long flags = PHP_STREAM_CLIENT_CONNECT;
  52. char *errstr = NULL;
  53. php_stream_context *context = NULL;
  54. RETVAL_FALSE;
  55. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zzd!lr", &host, &host_len, &zerrno, &zerrstr, &timeout, &flags, &zcontext) == FAILURE) {
  56. RETURN_FALSE;
  57. }
  58. context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
  59. if (flags & PHP_STREAM_CLIENT_PERSISTENT) {
  60. spprintf(&hashkey, 0, "stream_socket_client__%s", host);
  61. }
  62. /* prepare the timeout value for use */
  63. conv = (unsigned long) (timeout * 1000000.0);
  64. tv.tv_sec = conv / 1000000;
  65. tv.tv_usec = conv % 1000000;
  66. if (zerrno) {
  67. zval_dtor(zerrno);
  68. ZVAL_LONG(zerrno, 0);
  69. }
  70. if (zerrstr) {
  71. zval_dtor(zerrstr);
  72. ZVAL_STRING(zerrstr, "", 1);
  73. }
  74. stream = php_stream_xport_create(host, host_len, ENFORCE_SAFE_MODE | REPORT_ERRORS,
  75. STREAM_XPORT_CLIENT | (flags & PHP_STREAM_CLIENT_CONNECT ? STREAM_XPORT_CONNECT : 0) |
  76. (flags & PHP_STREAM_CLIENT_ASYNC_CONNECT ? STREAM_XPORT_CONNECT_ASYNC : 0),
  77. hashkey, &tv, context, &errstr, &err);
  78. if (stream == NULL) {
  79. /* host might contain binary characters */
  80. char *quoted_host = php_addslashes(host, host_len, NULL, 0 TSRMLS_CC);
  81. php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to connect to %s (%s)", quoted_host, errstr == NULL ? "Unknown error" : errstr);
  82. efree(quoted_host);
  83. }
  84. if (hashkey) {
  85. efree(hashkey);
  86. }
  87. if (stream == NULL) {
  88. if (zerrno) {
  89. zval_dtor(zerrno);
  90. ZVAL_LONG(zerrno, err);
  91. }
  92. if (zerrstr && errstr) {
  93. /* no need to dup; we need to efree buf anyway */
  94. zval_dtor(zerrstr);
  95. ZVAL_STRING(zerrstr, errstr, 0);
  96. } else if (errstr) {
  97. efree(errstr);
  98. }
  99. RETURN_FALSE;
  100. }
  101. if (errstr) {
  102. efree(errstr);
  103. }
  104. php_stream_to_zval(stream, return_value);
  105. if (zcontext) {
  106. zend_list_addref(Z_RESVAL_P(zcontext));
  107. }
  108. }
  109. /* }}} */
  110. /* {{{ proto resource stream_socket_server(string localaddress [, long &errcode, string &errstring, long flags, resource context])
  111. Create a server socket bound to localaddress */
  112. PHP_FUNCTION(stream_socket_server)
  113. {
  114. char *host;
  115. int host_len;
  116. zval *zerrno = NULL, *zerrstr = NULL, *zcontext = NULL;
  117. php_stream *stream = NULL;
  118. int err = 0;
  119. long flags = STREAM_XPORT_BIND | STREAM_XPORT_LISTEN;
  120. char *errstr = NULL;
  121. php_stream_context *context = NULL;
  122. RETVAL_FALSE;
  123. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zzlr", &host, &host_len, &zerrno, &zerrstr, &flags, &zcontext) == FAILURE) {
  124. RETURN_FALSE;
  125. }
  126. context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
  127. if (zerrno) {
  128. zval_dtor(zerrno);
  129. ZVAL_LONG(zerrno, 0);
  130. }
  131. if (zerrstr) {
  132. zval_dtor(zerrstr);
  133. ZVAL_STRING(zerrstr, "", 1);
  134. }
  135. stream = php_stream_xport_create(host, host_len, ENFORCE_SAFE_MODE | REPORT_ERRORS,
  136. STREAM_XPORT_SERVER | flags,
  137. NULL, NULL, context, &errstr, &err);
  138. if (stream == NULL) {
  139. php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to connect to %s (%s)", host, errstr == NULL ? "Unknown error" : errstr);
  140. }
  141. if (stream == NULL) {
  142. if (zerrno) {
  143. zval_dtor(zerrno);
  144. ZVAL_LONG(zerrno, err);
  145. }
  146. if (zerrstr && errstr) {
  147. /* no need to dup; we need to efree buf anyway */
  148. zval_dtor(zerrstr);
  149. ZVAL_STRING(zerrstr, errstr, 0);
  150. }
  151. RETURN_FALSE;
  152. }
  153. if (errstr) {
  154. efree(errstr);
  155. }
  156. php_stream_to_zval(stream, return_value);
  157. if (zcontext) {
  158. zend_list_addref(Z_RESVAL_P(zcontext));
  159. }
  160. }
  161. /* }}} */
  162. /* {{{ proto resource stream_socket_accept(resource serverstream, [ double timeout, string &peername ])
  163. Accept a client connection from a server socket */
  164. PHP_FUNCTION(stream_socket_accept)
  165. {
  166. double timeout = FG(default_socket_timeout);
  167. zval *peername = NULL;
  168. unsigned long conv;
  169. struct timeval tv;
  170. php_stream *stream = NULL, *clistream = NULL;
  171. zval *zstream;
  172. char *errstr = NULL;
  173. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|dz", &zstream, &timeout, &peername) == FAILURE) {
  174. RETURN_FALSE;
  175. }
  176. php_stream_from_zval(stream, &zstream);
  177. /* prepare the timeout value for use */
  178. conv = (unsigned long) (timeout * 1000000.0);
  179. tv.tv_sec = conv / 1000000;
  180. tv.tv_usec = conv % 1000000;
  181. if (peername) {
  182. zval_dtor(peername);
  183. ZVAL_STRING(peername, "", 1);
  184. }
  185. if (0 == php_stream_xport_accept(stream, &clistream,
  186. peername ? &Z_STRVAL_P(peername) : NULL,
  187. peername ? &Z_STRLEN_P(peername) : NULL,
  188. NULL, NULL,
  189. &tv, &errstr
  190. TSRMLS_CC) && clistream) {
  191. php_stream_to_zval(clistream, return_value);
  192. } else {
  193. php_error_docref(NULL TSRMLS_CC, E_WARNING, "accept failed: %s", errstr ? errstr : "Unknown error");
  194. RETVAL_FALSE;
  195. }
  196. if (errstr) {
  197. efree(errstr);
  198. }
  199. }
  200. /* }}} */
  201. /* {{{ proto string stream_socket_get_name(resource stream, bool want_peer)
  202. Returns either the locally bound or remote name for a socket stream */
  203. PHP_FUNCTION(stream_socket_get_name)
  204. {
  205. php_stream *stream;
  206. zval *zstream;
  207. zend_bool want_peer;
  208. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rb", &zstream, &want_peer) == FAILURE) {
  209. RETURN_FALSE;
  210. }
  211. php_stream_from_zval(stream, &zstream);
  212. Z_TYPE_P(return_value) = IS_STRING;
  213. if (0 != php_stream_xport_get_name(stream, want_peer,
  214. &Z_STRVAL_P(return_value),
  215. &Z_STRLEN_P(return_value),
  216. NULL, NULL
  217. TSRMLS_CC)) {
  218. RETURN_FALSE;
  219. }
  220. }
  221. /* }}} */
  222. /* {{{ proto long stream_socket_sendto(resouce stream, string data [, long flags [, string target_addr]])
  223. Send data to a socket stream. If target_addr is specified it must be in dotted quad (or [ipv6]) format */
  224. PHP_FUNCTION(stream_socket_sendto)
  225. {
  226. php_stream *stream;
  227. zval *zstream;
  228. long flags = 0;
  229. char *data, *target_addr;
  230. int datalen, target_addr_len = 0;
  231. php_sockaddr_storage sa;
  232. socklen_t sl = 0;
  233. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|ls", &zstream, &data, &datalen, &flags, &target_addr, &target_addr_len) == FAILURE) {
  234. RETURN_FALSE;
  235. }
  236. php_stream_from_zval(stream, &zstream);
  237. if (target_addr_len) {
  238. /* parse the address */
  239. if (FAILURE == php_network_parse_network_address_with_port(target_addr, target_addr_len, (struct sockaddr*)&sa, &sl TSRMLS_CC)) {
  240. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse `%s' into a valid network address", target_addr);
  241. RETURN_FALSE;
  242. }
  243. }
  244. RETURN_LONG(php_stream_xport_sendto(stream, data, datalen, flags, target_addr ? &sa : NULL, sl TSRMLS_CC));
  245. }
  246. /* }}} */
  247. /* {{{ proto string stream_socket_recvfrom(resource stream, long amount [, long flags [, string &remote_addr]])
  248. Receives data from a socket stream */
  249. PHP_FUNCTION(stream_socket_recvfrom)
  250. {
  251. php_stream *stream;
  252. zval *zstream, *zremote = NULL;
  253. long to_read = 0;
  254. char *read_buf;
  255. long flags = 0;
  256. int recvd;
  257. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|lz", &zstream, &to_read, &flags, &zremote) == FAILURE) {
  258. RETURN_FALSE;
  259. }
  260. php_stream_from_zval(stream, &zstream);
  261. if (zremote) {
  262. zval_dtor(zremote);
  263. ZVAL_NULL(zremote);
  264. Z_STRLEN_P(zremote) = 0;
  265. }
  266. if (to_read <= 0) {
  267. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length parameter must be greater than 0.");
  268. RETURN_FALSE;
  269. }
  270. read_buf = emalloc(to_read + 1);
  271. recvd = php_stream_xport_recvfrom(stream, read_buf, to_read, flags, NULL, NULL,
  272. zremote ? &Z_STRVAL_P(zremote) : NULL,
  273. zremote ? &Z_STRLEN_P(zremote) : NULL
  274. TSRMLS_CC);
  275. if (recvd >= 0) {
  276. if (zremote && Z_STRLEN_P(zremote)) {
  277. Z_TYPE_P(zremote) = IS_STRING;
  278. }
  279. read_buf[recvd] = '\0';
  280. if (PG(magic_quotes_runtime)) {
  281. Z_TYPE_P(return_value) = IS_STRING;
  282. Z_STRVAL_P(return_value) = php_addslashes(Z_STRVAL_P(return_value),
  283. Z_STRLEN_P(return_value), &Z_STRLEN_P(return_value), 1 TSRMLS_CC);
  284. return;
  285. } else {
  286. RETURN_STRINGL(read_buf, recvd, 0);
  287. }
  288. }
  289. RETURN_FALSE;
  290. }
  291. /* }}} */
  292. /* {{{ proto long stream_get_contents(resource source [, long maxlen ])
  293. Reads all remaining bytes (or up to maxlen bytes) from a stream and returns them as a string. */
  294. PHP_FUNCTION(stream_get_contents)
  295. {
  296. php_stream *stream;
  297. zval *zsrc;
  298. long maxlen = PHP_STREAM_COPY_ALL;
  299. int len, newlen;
  300. char *contents = NULL;
  301. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zsrc, &maxlen) == FAILURE) {
  302. RETURN_FALSE;
  303. }
  304. php_stream_from_zval(stream, &zsrc);
  305. if ((len = php_stream_copy_to_mem(stream, &contents, maxlen, 0)) > 0) {
  306. if (PG(magic_quotes_runtime)) {
  307. contents = php_addslashes(contents, len, &newlen, 1 TSRMLS_CC); /* 1 = free source string */
  308. len = newlen;
  309. }
  310. RETVAL_STRINGL(contents, len, 0);
  311. } else if (len == 0) {
  312. RETVAL_EMPTY_STRING();
  313. } else {
  314. RETVAL_FALSE;
  315. }
  316. }
  317. /* }}} */
  318. /* {{{ proto long stream_copy_to_stream(resource source, resource dest [, long maxlen ])
  319. Reads up to maxlen bytes from source stream and writes them to dest stream. */
  320. PHP_FUNCTION(stream_copy_to_stream)
  321. {
  322. php_stream *src, *dest;
  323. zval *zsrc, *zdest;
  324. long maxlen = PHP_STREAM_COPY_ALL;
  325. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|l", &zsrc, &zdest, &maxlen) == FAILURE) {
  326. RETURN_FALSE;
  327. }
  328. php_stream_from_zval(src, &zsrc);
  329. php_stream_from_zval(dest, &zdest);
  330. RETURN_LONG(php_stream_copy_to_stream(src, dest, maxlen));
  331. }
  332. /* }}} */
  333. /* {{{ proto resource stream_get_meta_data(resource fp)
  334. Retrieves header/meta data from streams/file pointers */
  335. PHP_FUNCTION(stream_get_meta_data)
  336. {
  337. zval **arg1;
  338. php_stream *stream;
  339. zval *newval;
  340. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg1) == FAILURE) {
  341. WRONG_PARAM_COUNT;
  342. }
  343. php_stream_from_zval(stream, arg1);
  344. array_init(return_value);
  345. if (stream->wrapperdata) {
  346. MAKE_STD_ZVAL(newval);
  347. *newval = *(stream->wrapperdata);
  348. zval_copy_ctor(newval);
  349. INIT_PZVAL(newval);
  350. add_assoc_zval(return_value, "wrapper_data", newval);
  351. }
  352. if (stream->wrapper) {
  353. add_assoc_string(return_value, "wrapper_type", (char *)stream->wrapper->wops->label, 1);
  354. }
  355. add_assoc_string(return_value, "stream_type", (char *)stream->ops->label, 1);
  356. add_assoc_string(return_value, "mode", stream->mode, 1);
  357. #if 0 /* TODO: needs updating for new filter API */
  358. if (stream->filterhead) {
  359. php_stream_filter *filter;
  360. MAKE_STD_ZVAL(newval);
  361. array_init(newval);
  362. for (filter = stream->filterhead; filter != NULL; filter = filter->next) {
  363. add_next_index_string(newval, (char *)filter->fops->label, 1);
  364. }
  365. add_assoc_zval(return_value, "filters", newval);
  366. }
  367. #endif
  368. add_assoc_long(return_value, "unread_bytes", stream->writepos - stream->readpos);
  369. add_assoc_bool(return_value, "seekable", (stream->ops->seek) && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0);
  370. if (stream->orig_path) {
  371. add_assoc_string(return_value, "uri", stream->orig_path, 1);
  372. }
  373. if (!php_stream_populate_meta_data(stream, return_value)) {
  374. add_assoc_bool(return_value, "timed_out", 0);
  375. add_assoc_bool(return_value, "blocked", 1);
  376. add_assoc_bool(return_value, "eof", php_stream_eof(stream));
  377. }
  378. }
  379. /* }}} */
  380. /* {{{ proto array stream_get_transports()
  381. Retrieves list of registered socket transports */
  382. PHP_FUNCTION(stream_get_transports)
  383. {
  384. HashTable *stream_xport_hash;
  385. char *stream_xport;
  386. int stream_xport_len;
  387. ulong num_key;
  388. if (ZEND_NUM_ARGS() != 0) {
  389. WRONG_PARAM_COUNT;
  390. }
  391. if ((stream_xport_hash = php_stream_xport_get_hash())) {
  392. array_init(return_value);
  393. zend_hash_internal_pointer_reset(stream_xport_hash);
  394. while (zend_hash_get_current_key_ex(stream_xport_hash,
  395. &stream_xport, &stream_xport_len,
  396. &num_key, 0, NULL) == HASH_KEY_IS_STRING) {
  397. add_next_index_stringl(return_value, stream_xport, stream_xport_len, 1);
  398. zend_hash_move_forward(stream_xport_hash);
  399. }
  400. } else {
  401. RETURN_FALSE;
  402. }
  403. }
  404. /* }}} */
  405. /* {{{ proto array stream_get_wrappers()
  406. Retrieves list of registered stream wrappers */
  407. PHP_FUNCTION(stream_get_wrappers)
  408. {
  409. HashTable *url_stream_wrappers_hash;
  410. char *stream_protocol;
  411. int key_flags, stream_protocol_len = 0;
  412. ulong num_key;
  413. if (ZEND_NUM_ARGS() != 0) {
  414. WRONG_PARAM_COUNT;
  415. }
  416. if ((url_stream_wrappers_hash = php_stream_get_url_stream_wrappers_hash())) {
  417. array_init(return_value);
  418. for(zend_hash_internal_pointer_reset(url_stream_wrappers_hash);
  419. (key_flags = zend_hash_get_current_key_ex(url_stream_wrappers_hash, &stream_protocol, &stream_protocol_len, &num_key, 0, NULL)) != HASH_KEY_NON_EXISTANT;
  420. zend_hash_move_forward(url_stream_wrappers_hash)) {
  421. if (key_flags == HASH_KEY_IS_STRING) {
  422. add_next_index_stringl(return_value, stream_protocol, stream_protocol_len, 1);
  423. }
  424. }
  425. } else {
  426. RETURN_FALSE;
  427. }
  428. }
  429. /* }}} */
  430. /* {{{ stream_select related functions */
  431. static int stream_array_to_fd_set(zval *stream_array, fd_set *fds, php_socket_t *max_fd TSRMLS_DC)
  432. {
  433. zval **elem;
  434. php_stream *stream;
  435. php_socket_t this_fd;
  436. if (Z_TYPE_P(stream_array) != IS_ARRAY) {
  437. return 0;
  438. }
  439. for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream_array));
  440. zend_hash_get_current_data(Z_ARRVAL_P(stream_array), (void **) &elem) == SUCCESS;
  441. zend_hash_move_forward(Z_ARRVAL_P(stream_array))) {
  442. php_stream_from_zval_no_verify(stream, elem);
  443. if (stream == NULL) {
  444. continue;
  445. }
  446. /* get the fd.
  447. * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag
  448. * when casting. It is only used here so that the buffered data warning
  449. * is not displayed.
  450. * */
  451. if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&this_fd, 1) && this_fd >= 0) {
  452. FD_SET(this_fd, fds);
  453. if (this_fd > *max_fd) {
  454. *max_fd = this_fd;
  455. }
  456. }
  457. }
  458. return 1;
  459. }
  460. static int stream_array_from_fd_set(zval *stream_array, fd_set *fds TSRMLS_DC)
  461. {
  462. zval **elem, **dest_elem;
  463. php_stream *stream;
  464. HashTable *new_hash;
  465. int this_fd, ret = 0;
  466. if (Z_TYPE_P(stream_array) != IS_ARRAY) {
  467. return 0;
  468. }
  469. ALLOC_HASHTABLE(new_hash);
  470. zend_hash_init(new_hash, 0, NULL, ZVAL_PTR_DTOR, 0);
  471. for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream_array));
  472. zend_hash_get_current_data(Z_ARRVAL_P(stream_array), (void **) &elem) == SUCCESS;
  473. zend_hash_move_forward(Z_ARRVAL_P(stream_array))) {
  474. php_stream_from_zval_no_verify(stream, elem);
  475. if (stream == NULL) {
  476. continue;
  477. }
  478. /* get the fd
  479. * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag
  480. * when casting. It is only used here so that the buffered data warning
  481. * is not displayed.
  482. */
  483. if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&this_fd, 1) && this_fd >= 0) {
  484. if (FD_ISSET(this_fd, fds)) {
  485. zend_hash_next_index_insert(new_hash, (void *)elem, sizeof(zval *), (void **)&dest_elem);
  486. if (dest_elem) {
  487. zval_add_ref(dest_elem);
  488. }
  489. ret++;
  490. continue;
  491. }
  492. }
  493. }
  494. /* destroy old array and add new one */
  495. zend_hash_destroy(Z_ARRVAL_P(stream_array));
  496. efree(Z_ARRVAL_P(stream_array));
  497. zend_hash_internal_pointer_reset(new_hash);
  498. Z_ARRVAL_P(stream_array) = new_hash;
  499. return ret;
  500. }
  501. static int stream_array_emulate_read_fd_set(zval *stream_array TSRMLS_DC)
  502. {
  503. zval **elem, **dest_elem;
  504. php_stream *stream;
  505. HashTable *new_hash;
  506. int ret = 0;
  507. if (Z_TYPE_P(stream_array) != IS_ARRAY) {
  508. return 0;
  509. }
  510. ALLOC_HASHTABLE(new_hash);
  511. zend_hash_init(new_hash, 0, NULL, ZVAL_PTR_DTOR, 0);
  512. for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream_array));
  513. zend_hash_get_current_data(Z_ARRVAL_P(stream_array), (void **) &elem) == SUCCESS;
  514. zend_hash_move_forward(Z_ARRVAL_P(stream_array))) {
  515. php_stream_from_zval_no_verify(stream, elem);
  516. if (stream == NULL) {
  517. continue;
  518. }
  519. if ((stream->writepos - stream->readpos) > 0) {
  520. /* allow readable non-descriptor based streams to participate in stream_select.
  521. * Non-descriptor streams will only "work" if they have previously buffered the
  522. * data. Not ideal, but better than nothing.
  523. * This branch of code also allows blocking streams with buffered data to
  524. * operate correctly in stream_select.
  525. * */
  526. zend_hash_next_index_insert(new_hash, (void *)elem, sizeof(zval *), (void **)&dest_elem);
  527. if (dest_elem) {
  528. zval_add_ref(dest_elem);
  529. }
  530. ret++;
  531. continue;
  532. }
  533. }
  534. if (ret > 0) {
  535. /* destroy old array and add new one */
  536. zend_hash_destroy(Z_ARRVAL_P(stream_array));
  537. efree(Z_ARRVAL_P(stream_array));
  538. zend_hash_internal_pointer_reset(new_hash);
  539. Z_ARRVAL_P(stream_array) = new_hash;
  540. } else {
  541. zend_hash_destroy(new_hash);
  542. FREE_HASHTABLE(new_hash);
  543. }
  544. return ret;
  545. }
  546. /* }}} */
  547. /* {{{ proto int stream_select(array &read_streams, array &write_streams, array &except_streams, int tv_sec[, int tv_usec])
  548. Runs the select() system call on the sets of streams with a timeout specified by tv_sec and tv_usec */
  549. PHP_FUNCTION(stream_select)
  550. {
  551. zval *r_array, *w_array, *e_array, *sec = NULL;
  552. struct timeval tv;
  553. struct timeval *tv_p = NULL;
  554. fd_set rfds, wfds, efds;
  555. int max_fd = 0;
  556. int retval, sets = 0;
  557. long usec = 0;
  558. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!a!z!|l", &r_array, &w_array, &e_array, &sec, &usec) == FAILURE)
  559. return;
  560. FD_ZERO(&rfds);
  561. FD_ZERO(&wfds);
  562. FD_ZERO(&efds);
  563. if (r_array != NULL) sets += stream_array_to_fd_set(r_array, &rfds, &max_fd TSRMLS_CC);
  564. if (w_array != NULL) sets += stream_array_to_fd_set(w_array, &wfds, &max_fd TSRMLS_CC);
  565. if (e_array != NULL) sets += stream_array_to_fd_set(e_array, &efds, &max_fd TSRMLS_CC);
  566. if (!sets) {
  567. php_error_docref(NULL TSRMLS_CC, E_WARNING, "No stream arrays were passed");
  568. RETURN_FALSE;
  569. }
  570. /* If seconds is not set to null, build the timeval, else we wait indefinitely */
  571. if (sec != NULL) {
  572. convert_to_long_ex(&sec);
  573. /* Solaris + BSD do not like microsecond values which are >= 1 sec */
  574. if (usec > 999999) {
  575. tv.tv_sec = Z_LVAL_P(sec) + (usec / 1000000);
  576. tv.tv_usec = usec % 1000000;
  577. } else {
  578. tv.tv_sec = Z_LVAL_P(sec);
  579. tv.tv_usec = usec;
  580. }
  581. tv_p = &tv;
  582. }
  583. /* slight hack to support buffered data; if there is data sitting in the
  584. * read buffer of any of the streams in the read array, let's pretend
  585. * that we selected, but return only the readable sockets */
  586. if (r_array != NULL) {
  587. retval = stream_array_emulate_read_fd_set(r_array TSRMLS_CC);
  588. if (retval > 0) {
  589. RETURN_LONG(retval);
  590. }
  591. }
  592. retval = php_select(max_fd+1, &rfds, &wfds, &efds, tv_p);
  593. if (retval == -1) {
  594. php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s (max_fd=%d)",
  595. errno, strerror(errno), max_fd);
  596. RETURN_FALSE;
  597. }
  598. if (r_array != NULL) stream_array_from_fd_set(r_array, &rfds TSRMLS_CC);
  599. if (w_array != NULL) stream_array_from_fd_set(w_array, &wfds TSRMLS_CC);
  600. if (e_array != NULL) stream_array_from_fd_set(e_array, &efds TSRMLS_CC);
  601. RETURN_LONG(retval);
  602. }
  603. /* }}} */
  604. /* {{{ stream_context related functions */
  605. static void user_space_stream_notifier(php_stream_context *context, int notifycode, int severity,
  606. char *xmsg, int xcode, size_t bytes_sofar, size_t bytes_max, void * ptr TSRMLS_DC)
  607. {
  608. zval *callback = (zval*)context->notifier->ptr;
  609. zval *retval = NULL;
  610. zval zvs[6];
  611. zval *ps[6];
  612. zval **ptps[6];
  613. int i;
  614. for (i = 0; i < 6; i++) {
  615. INIT_ZVAL(zvs[i]);
  616. ps[i] = &zvs[i];
  617. ptps[i] = &ps[i];
  618. }
  619. ZVAL_LONG(ps[0], notifycode);
  620. ZVAL_LONG(ps[1], severity);
  621. if (xmsg) {
  622. ZVAL_STRING(ps[2], xmsg, 0);
  623. } else {
  624. ZVAL_NULL(ps[2]);
  625. }
  626. ZVAL_LONG(ps[3], xcode);
  627. ZVAL_LONG(ps[4], bytes_sofar);
  628. ZVAL_LONG(ps[5], bytes_max);
  629. if (FAILURE == call_user_function_ex(EG(function_table), NULL, callback, &retval, 6, ptps, 0, NULL TSRMLS_CC)) {
  630. php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to call user notifier");
  631. }
  632. if (retval) {
  633. zval_ptr_dtor(&retval);
  634. }
  635. }
  636. static void user_space_stream_notifier_dtor(php_stream_notifier *notifier)
  637. {
  638. if (notifier && notifier->ptr) {
  639. zval_ptr_dtor((zval **)&(notifier->ptr));
  640. notifier->ptr = NULL;
  641. }
  642. }
  643. static int parse_context_options(php_stream_context *context, zval *options)
  644. {
  645. HashPosition pos, opos;
  646. zval **wval, **oval;
  647. char *wkey, *okey;
  648. int wkey_len, okey_len;
  649. int ret = SUCCESS;
  650. ulong num_key;
  651. zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(options), &pos);
  652. while (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_P(options), (void**)&wval, &pos)) {
  653. if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(Z_ARRVAL_P(options), &wkey, &wkey_len, &num_key, 0, &pos)
  654. && Z_TYPE_PP(wval) == IS_ARRAY) {
  655. zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(wval), &opos);
  656. while (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(wval), (void**)&oval, &opos)) {
  657. if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(Z_ARRVAL_PP(wval), &okey, &okey_len, &num_key, 0, &opos)) {
  658. php_stream_context_set_option(context, wkey, okey, *oval);
  659. }
  660. zend_hash_move_forward_ex(Z_ARRVAL_PP(wval), &opos);
  661. }
  662. } else {
  663. zend_error(E_WARNING, "options should have the form [\"wrappername\"][\"optionname\"] = $value");
  664. }
  665. zend_hash_move_forward_ex(Z_ARRVAL_P(options), &pos);
  666. }
  667. return ret;
  668. }
  669. static int parse_context_params(php_stream_context *context, zval *params)
  670. {
  671. int ret = SUCCESS;
  672. zval **tmp;
  673. if (SUCCESS == zend_hash_find(Z_ARRVAL_P(params), "notification", sizeof("notification"), (void**)&tmp)) {
  674. if (context->notifier) {
  675. php_stream_notification_free(context->notifier);
  676. context->notifier = NULL;
  677. }
  678. context->notifier = php_stream_notification_alloc();
  679. context->notifier->func = user_space_stream_notifier;
  680. context->notifier->ptr = *tmp;
  681. ZVAL_ADDREF(*tmp);
  682. context->notifier->dtor = user_space_stream_notifier_dtor;
  683. }
  684. if (SUCCESS == zend_hash_find(Z_ARRVAL_P(params), "options", sizeof("options"), (void**)&tmp)) {
  685. parse_context_options(context, *tmp);
  686. }
  687. return ret;
  688. }
  689. /* given a zval which is either a stream or a context, return the underlying
  690. * stream_context. If it is a stream that does not have a context assigned, it
  691. * will create and assign a context and return that. */
  692. static php_stream_context *decode_context_param(zval *contextresource TSRMLS_DC)
  693. {
  694. php_stream_context *context = NULL;
  695. context = zend_fetch_resource(&contextresource TSRMLS_CC, -1, NULL, NULL, 1, php_le_stream_context());
  696. if (context == NULL) {
  697. php_stream *stream;
  698. stream = zend_fetch_resource(&contextresource TSRMLS_CC, -1, NULL, NULL, 2, php_file_le_stream(), php_file_le_pstream);
  699. if (stream) {
  700. context = stream->context;
  701. if (context == NULL) {
  702. /* Only way this happens is if file is opened with NO_DEFAULT_CONTEXT
  703. param, but then something is called which requires a context.
  704. Don't give them the default one though since they already said they
  705. didn't want it. */
  706. context = stream->context = php_stream_context_alloc();
  707. }
  708. }
  709. }
  710. return context;
  711. }
  712. /* }}} */
  713. /* {{{ proto array stream_context_get_options(resource context|resource stream)
  714. Retrieve options for a stream/wrapper/context */
  715. PHP_FUNCTION(stream_context_get_options)
  716. {
  717. zval *zcontext;
  718. php_stream_context *context;
  719. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zcontext) == FAILURE) {
  720. RETURN_FALSE;
  721. }
  722. context = decode_context_param(zcontext TSRMLS_CC);
  723. if (!context) {
  724. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream/context parameter.");
  725. RETURN_FALSE;
  726. }
  727. *return_value = *context->options;
  728. zval_copy_ctor(return_value);
  729. INIT_PZVAL(return_value);
  730. }
  731. /* }}} */
  732. /* {{{ proto bool stream_context_set_option(resource context|resource stream, string wrappername, string optionname, mixed value)
  733. Set an option for a wrapper */
  734. PHP_FUNCTION(stream_context_set_option)
  735. {
  736. zval *options = NULL, *zcontext = NULL, *zvalue = NULL;
  737. php_stream_context *context;
  738. char *wrappername, *optionname;
  739. int wrapperlen, optionlen;
  740. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
  741. "rssz", &zcontext, &wrappername, &wrapperlen,
  742. &optionname, &optionlen, &zvalue) == FAILURE) {
  743. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
  744. "ra", &zcontext, &options) == FAILURE) {
  745. php_error_docref(NULL TSRMLS_CC, E_WARNING, "called with wrong number or type of parameters; please RTM");
  746. RETURN_FALSE;
  747. }
  748. }
  749. /* figure out where the context is coming from exactly */
  750. context = decode_context_param(zcontext TSRMLS_CC);
  751. if (!context) {
  752. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream/context parameter.");
  753. RETURN_FALSE;
  754. }
  755. if (options) {
  756. /* handle the array syntax */
  757. RETVAL_BOOL(parse_context_options(context, options) == SUCCESS);
  758. } else {
  759. php_stream_context_set_option(context, wrappername, optionname, zvalue);
  760. RETVAL_TRUE;
  761. }
  762. }
  763. /* }}} */
  764. /* {{{ proto bool stream_context_set_params(resource context|resource stream, array options)
  765. Set parameters for a file context */
  766. PHP_FUNCTION(stream_context_set_params)
  767. {
  768. zval *params, *zcontext;
  769. php_stream_context *context;
  770. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ra", &zcontext, &params) == FAILURE) {
  771. RETURN_FALSE;
  772. }
  773. context = decode_context_param(zcontext TSRMLS_CC);
  774. if (!context) {
  775. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid stream/context parameter.");
  776. RETURN_FALSE;
  777. }
  778. RETVAL_BOOL(parse_context_params(context, params) == SUCCESS);
  779. }
  780. /* }}} */
  781. /* {{{ proto resource stream_context_get_default([array options])
  782. Get a handle on the default file/stream context and optionally set parameters */
  783. PHP_FUNCTION(stream_context_get_default)
  784. {
  785. zval *params = NULL;
  786. php_stream_context *context;
  787. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a", &params) == FAILURE) {
  788. RETURN_FALSE;
  789. }
  790. if (FG(default_context) == NULL) {
  791. FG(default_context) = php_stream_context_alloc();
  792. }
  793. context = FG(default_context);
  794. if (params) {
  795. parse_context_options(context, params);
  796. }
  797. php_stream_context_to_zval(context, return_value);
  798. }
  799. /* }}} */
  800. /* {{{ proto resource stream_context_create([array options])
  801. Create a file context and optionally set parameters */
  802. PHP_FUNCTION(stream_context_create)
  803. {
  804. zval *params = NULL;
  805. php_stream_context *context;
  806. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a", &params) == FAILURE) {
  807. RETURN_FALSE;
  808. }
  809. context = php_stream_context_alloc();
  810. if (params) {
  811. parse_context_options(context, params);
  812. }
  813. php_stream_context_to_zval(context, return_value);
  814. }
  815. /* }}} */
  816. /* {{{ streams filter functions */
  817. static void apply_filter_to_stream(int append, INTERNAL_FUNCTION_PARAMETERS)
  818. {
  819. zval *zstream;
  820. php_stream *stream;
  821. char *filtername;
  822. int filternamelen;
  823. long read_write = 0;
  824. zval *filterparams = NULL;
  825. php_stream_filter *filter = NULL;
  826. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|lz", &zstream,
  827. &filtername, &filternamelen, &read_write, &filterparams) == FAILURE) {
  828. RETURN_FALSE;
  829. }
  830. php_stream_from_zval(stream, &zstream);
  831. if ((read_write & PHP_STREAM_FILTER_ALL) == 0) {
  832. /* Chain not specified.
  833. * Examine stream->mode to determine which filters are needed
  834. * There's no harm in attaching a filter to an unused chain,
  835. * but why waste the memory and clock cycles?
  836. */
  837. if (strchr(stream->mode, 'r') || strchr(stream->mode, '+')) {
  838. read_write |= PHP_STREAM_FILTER_READ;
  839. }
  840. if (strchr(stream->mode, 'w') || strchr(stream->mode, '+') || strchr(stream->mode, 'a')) {
  841. read_write |= PHP_STREAM_FILTER_WRITE;
  842. }
  843. }
  844. if (read_write & PHP_STREAM_FILTER_READ) {
  845. filter = php_stream_filter_create(filtername, filterparams, php_stream_is_persistent(stream) TSRMLS_CC);
  846. if (filter == NULL) {
  847. RETURN_FALSE;
  848. }
  849. if (append) {
  850. php_stream_filter_append(&stream->readfilters, filter);
  851. } else {
  852. php_stream_filter_prepend(&stream->readfilters, filter);
  853. }
  854. }
  855. if (read_write & PHP_STREAM_FILTER_WRITE) {
  856. filter = php_stream_filter_create(filtername, filterparams, php_stream_is_persistent(stream) TSRMLS_CC);
  857. if (filter == NULL) {
  858. RETURN_FALSE;
  859. }
  860. if (append) {
  861. php_stream_filter_append(&stream->writefilters, filter);
  862. } else {
  863. php_stream_filter_prepend(&stream->writefilters, filter);
  864. }
  865. }
  866. if (filter) {
  867. RETURN_RESOURCE(ZEND_REGISTER_RESOURCE(NULL, filter, php_file_le_stream_filter()));
  868. } else {
  869. RETURN_FALSE;
  870. }
  871. }
  872. /* {{{ proto resource stream_filter_prepend(resource stream, string filtername[, int read_write[, string filterparams]])
  873. Prepend a filter to a stream */
  874. PHP_FUNCTION(stream_filter_prepend)
  875. {
  876. apply_filter_to_stream(0, INTERNAL_FUNCTION_PARAM_PASSTHRU);
  877. }
  878. /* }}} */
  879. /* {{{ proto resource stream_filter_append(resource stream, string filtername[, int read_write[, string filterparams]])
  880. Append a filter to a stream */
  881. PHP_FUNCTION(stream_filter_append)
  882. {
  883. apply_filter_to_stream(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
  884. }
  885. /* }}} */
  886. /* {{{ proto bool stream_filter_remove(resource stream_filter)
  887. Flushes any data in the filter's internal buffer, removes it from the chain, and frees the resource */
  888. PHP_FUNCTION(stream_filter_remove)
  889. {
  890. zval *zfilter;
  891. php_stream_filter *filter;
  892. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zfilter) == FAILURE) {
  893. RETURN_FALSE;
  894. }
  895. filter = zend_fetch_resource(&zfilter TSRMLS_CC, -1, NULL, NULL, 1, php_file_le_stream_filter());
  896. if (!filter) {
  897. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid resource given, not a stream filter");
  898. RETURN_FALSE;
  899. }
  900. if (php_stream_filter_flush(filter, 1) == FAILURE) {
  901. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to flush filter, not removing");
  902. RETURN_FALSE;
  903. }
  904. if (zend_list_delete(Z_LVAL_P(zfilter)) == FAILURE) {
  905. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not invalidate filter, not removing");
  906. RETURN_FALSE;
  907. } else {
  908. php_stream_filter_remove(filter, 1 TSRMLS_CC);
  909. RETURN_TRUE;
  910. }
  911. }
  912. /* }}} */
  913. /* {{{ proto string stream_get_line(resource stream, int maxlen, string ending)
  914. Read up to maxlen bytes from a stream or until the ending string is found */
  915. PHP_FUNCTION(stream_get_line)
  916. {
  917. char *str;
  918. int str_len;
  919. long max_length;
  920. zval *zstream;
  921. char *buf;
  922. size_t buf_size;
  923. php_stream *stream;
  924. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rls", &zstream, &max_length, &str, &str_len) == FAILURE) {
  925. RETURN_FALSE;
  926. }
  927. if (max_length < 0) {
  928. php_error_docref(NULL TSRMLS_CC, E_WARNING, "The maximum allowed length must be greater then or equal to zero.");
  929. RETURN_FALSE;
  930. }
  931. php_stream_from_zval(stream, &zstream);
  932. if ((buf = php_stream_get_record(stream, max_length, &buf_size, str, str_len TSRMLS_CC))) {
  933. RETURN_STRINGL(buf, buf_size, 0);
  934. } else {
  935. RETURN_FALSE;
  936. }
  937. }
  938. /* }}} */
  939. /* {{{ proto bool stream_set_blocking(resource socket, int mode)
  940. Set blocking/non-blocking mode on a socket or stream */
  941. PHP_FUNCTION(stream_set_blocking)
  942. {
  943. zval **arg1, **arg2;
  944. int block;
  945. php_stream *stream;
  946. if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &arg1, &arg2) == FAILURE) {
  947. WRONG_PARAM_COUNT;
  948. }
  949. php_stream_from_zval(stream, arg1);
  950. convert_to_long_ex(arg2);
  951. block = Z_LVAL_PP(arg2);
  952. if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, block == 0 ? 0 : 1, NULL) == -1)
  953. RETURN_FALSE;
  954. RETURN_TRUE;
  955. }
  956. /* }}} */
  957. /* {{{ proto bool set_socket_blocking(resource socket, int mode)
  958. Set blocking/non-blocking mode on a socket */
  959. PHP_FUNCTION(set_socket_blocking)
  960. {
  961. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "This function is deprecated, use stream_set_blocking() instead");
  962. PHP_FN(stream_set_blocking)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
  963. }
  964. /* }}} */
  965. /* {{{ proto bool stream_set_timeout(resource stream, int seconds, int microseconds)
  966. Set timeout on stream read to seconds + microseonds */
  967. #if HAVE_SYS_TIME_H || defined(PHP_WIN32)
  968. PHP_FUNCTION(stream_set_timeout)
  969. {
  970. zval **socket, **seconds, **microseconds;
  971. struct timeval t;
  972. php_stream *stream;
  973. if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 3 ||
  974. zend_get_parameters_ex(ZEND_NUM_ARGS(), &socket, &seconds, &microseconds)==FAILURE) {
  975. WRONG_PARAM_COUNT;
  976. }
  977. php_stream_from_zval(stream, socket);
  978. convert_to_long_ex(seconds);
  979. t.tv_sec = Z_LVAL_PP(seconds);
  980. if (ZEND_NUM_ARGS() == 3) {
  981. convert_to_long_ex(microseconds);
  982. t.tv_usec = Z_LVAL_PP(microseconds) % 1000000;
  983. t.tv_sec += Z_LVAL_PP(microseconds) / 1000000;
  984. }
  985. else
  986. t.tv_usec = 0;
  987. if (PHP_STREAM_OPTION_RETURN_OK == php_stream_set_option(stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &t)) {
  988. RETURN_TRUE;
  989. }
  990. RETURN_FALSE;
  991. }
  992. #endif /* HAVE_SYS_TIME_H || defined(PHP_WIN32) */
  993. /* }}} */
  994. /* {{{ proto int stream_set_write_buffer(resource fp, int buffer)
  995. Set file write buffer */
  996. PHP_FUNCTION(stream_set_write_buffer)
  997. {
  998. zval **arg1, **arg2;
  999. int ret;
  1000. size_t buff;
  1001. php_stream *stream;
  1002. switch (ZEND_NUM_ARGS()) {
  1003. case 2:
  1004. if (zend_get_parameters_ex(2, &arg1, &arg2)==FAILURE) {
  1005. RETURN_FALSE;
  1006. }
  1007. break;
  1008. default:
  1009. WRONG_PARAM_COUNT;
  1010. /* NOTREACHED */
  1011. break;
  1012. }
  1013. php_stream_from_zval(stream, arg1);
  1014. convert_to_long_ex(arg2);
  1015. buff = Z_LVAL_PP(arg2);
  1016. /* if buff is 0 then set to non-buffered */
  1017. if (buff == 0) {
  1018. ret = php_stream_set_option(stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
  1019. } else {
  1020. ret = php_stream_set_option(stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_FULL, &buff);
  1021. }
  1022. RETURN_LONG(ret == 0 ? 0 : EOF);
  1023. }
  1024. /* }}} */
  1025. /* {{{ proto bool stream_socket_enable_crypto(resource stream, bool enable [, int cryptokind, resource sessionstream])
  1026. Enable or disable a specific kind of crypto on the stream */
  1027. PHP_FUNCTION(stream_socket_enable_crypto)
  1028. {
  1029. long cryptokind;
  1030. zval *zstream, *zsessstream = NULL;
  1031. php_stream *stream, *sessstream = NULL;
  1032. zend_bool enable;
  1033. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rb|lr", &zstream, &enable, &cryptokind, &zsessstream) == FAILURE) {
  1034. RETURN_FALSE;
  1035. }
  1036. php_stream_from_zval(stream, &zstream);
  1037. if (ZEND_NUM_ARGS() >= 3) {
  1038. if (zsessstream) {
  1039. php_stream_from_zval(sessstream, &zsessstream);
  1040. }
  1041. if (php_stream_xport_crypto_setup(stream, cryptokind, sessstream TSRMLS_CC) < 0) {
  1042. RETURN_FALSE;
  1043. }
  1044. }
  1045. RETURN_BOOL(php_stream_xport_crypto_enable(stream, enable TSRMLS_CC) < 0 ? 0 : 1);
  1046. }
  1047. /* }}} */
  1048. /*
  1049. * Local variables:
  1050. * tab-width: 4
  1051. * c-basic-offset: 4
  1052. * End:
  1053. * vim600: noet sw=4 ts=4 fdm=marker
  1054. * vim<600: noet sw=4 ts=4
  1055. */