streamsfuncs.c 45 KB

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