![]() ![]() | ![]() |
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.4 ! misho 5: | Copyright (c) 1997-2014 The PHP Group |
1.1 misho 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: Rasmus Lerdorf <rasmus@php.net> |
16: | Jim Winstead <jimw@php.net> |
17: | Hartmut Holzgraefe <hholzgra@php.net> |
18: +----------------------------------------------------------------------+
19: */
1.1.1.2 misho 20: /* $Id$ */
1.1 misho 21:
22: #include <stdio.h>
23: #include <stdlib.h>
24: #if HAVE_UNISTD_H
25: #include <unistd.h>
26: #endif
27:
28: #include "php.h"
29: #include "php_globals.h"
30: #include "php_standard.h"
31: #include "php_fopen_wrappers.h"
32: #include "SAPI.h"
33:
34: static size_t php_stream_output_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */
35: {
36: PHPWRITE(buf, count);
37: return count;
38: }
39: /* }}} */
40:
41: static size_t php_stream_output_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
42: {
43: stream->eof = 1;
44: return 0;
45: }
46: /* }}} */
47:
48: static int php_stream_output_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
49: {
50: return 0;
51: }
52: /* }}} */
53:
54: php_stream_ops php_stream_output_ops = {
55: php_stream_output_write,
56: php_stream_output_read,
57: php_stream_output_close,
58: NULL, /* flush */
59: "Output",
60: NULL, /* seek */
61: NULL, /* cast */
62: NULL, /* stat */
63: NULL /* set_option */
64: };
65:
66: static size_t php_stream_input_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */
67: {
68: return -1;
69: }
70: /* }}} */
71:
72: static size_t php_stream_input_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
73: {
74: off_t *position = (off_t*)stream->abstract;
75: size_t read_bytes = 0;
76:
77: if (!stream->eof) {
78: if (SG(request_info).raw_post_data) { /* data has already been read by a post handler */
79: read_bytes = SG(request_info).raw_post_data_length - *position;
80: if (read_bytes <= count) {
81: stream->eof = 1;
82: } else {
83: read_bytes = count;
84: }
85: if (read_bytes) {
86: memcpy(buf, SG(request_info).raw_post_data + *position, read_bytes);
87: }
88: } else if (sapi_module.read_post) {
89: read_bytes = sapi_module.read_post(buf, count TSRMLS_CC);
90: if (read_bytes <= 0) {
91: stream->eof = 1;
92: read_bytes = 0;
93: }
94: /* Increment SG(read_post_bytes) only when something was actually read. */
95: SG(read_post_bytes) += read_bytes;
96: } else {
97: stream->eof = 1;
98: }
99: }
100:
101: *position += read_bytes;
102:
103: return read_bytes;
104: }
105: /* }}} */
106:
107: static int php_stream_input_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
108: {
109: efree(stream->abstract);
110:
111: return 0;
112: }
113: /* }}} */
114:
115: static int php_stream_input_flush(php_stream *stream TSRMLS_DC) /* {{{ */
116: {
117: return -1;
118: }
119: /* }}} */
120:
121: php_stream_ops php_stream_input_ops = {
122: php_stream_input_write,
123: php_stream_input_read,
124: php_stream_input_close,
125: php_stream_input_flush,
126: "Input",
127: NULL, /* seek */
128: NULL, /* cast */
129: NULL, /* stat */
130: NULL /* set_option */
131: };
132:
133: static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, int read_chain, int write_chain TSRMLS_DC) /* {{{ */
134: {
135: char *p, *token;
136: php_stream_filter *temp_filter;
137:
138: p = php_strtok_r(filterlist, "|", &token);
139: while (p) {
140: php_url_decode(p, strlen(p));
141: if (read_chain) {
142: if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream) TSRMLS_CC))) {
143: php_stream_filter_append(&stream->readfilters, temp_filter);
144: } else {
145: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create filter (%s)", p);
146: }
147: }
148: if (write_chain) {
149: if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream) TSRMLS_CC))) {
150: php_stream_filter_append(&stream->writefilters, temp_filter);
151: } else {
152: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create filter (%s)", p);
153: }
154: }
155: p = php_strtok_r(NULL, "|", &token);
156: }
157: }
158: /* }}} */
159:
160: php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */
161: {
162: int fd = -1;
163: int mode_rw = 0;
164: php_stream * stream = NULL;
165: char *p, *token, *pathdup;
166: long max_memory;
167: FILE *file = NULL;
168:
169: if (!strncasecmp(path, "php://", 6)) {
170: path += 6;
171: }
172:
173: if (!strncasecmp(path, "temp", 4)) {
174: path += 4;
175: max_memory = PHP_STREAM_MAX_MEM;
176: if (!strncasecmp(path, "/maxmemory:", 11)) {
177: path += 11;
178: max_memory = strtol(path, NULL, 10);
179: if (max_memory < 0) {
180: php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Max memory must be >= 0");
181: return NULL;
182: }
183: }
184: if (strpbrk(mode, "wa+")) {
185: mode_rw = TEMP_STREAM_DEFAULT;
186: } else {
187: mode_rw = TEMP_STREAM_READONLY;
188: }
189: return php_stream_temp_create(mode_rw, max_memory);
190: }
191:
192: if (!strcasecmp(path, "memory")) {
193: if (strpbrk(mode, "wa+")) {
194: mode_rw = TEMP_STREAM_DEFAULT;
195: } else {
196: mode_rw = TEMP_STREAM_READONLY;
197: }
198: return php_stream_memory_create(mode_rw);
199: }
200:
201: if (!strcasecmp(path, "output")) {
202: return php_stream_alloc(&php_stream_output_ops, NULL, 0, "wb");
203: }
204:
205: if (!strcasecmp(path, "input")) {
206: if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
207: if (options & REPORT_ERRORS) {
208: php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
209: }
210: return NULL;
211: }
212: return php_stream_alloc(&php_stream_input_ops, ecalloc(1, sizeof(off_t)), 0, "rb");
213: }
214:
215: if (!strcasecmp(path, "stdin")) {
216: if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
217: if (options & REPORT_ERRORS) {
218: php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
219: }
220: return NULL;
221: }
222: if (!strcmp(sapi_module.name, "cli")) {
223: static int cli_in = 0;
224: fd = STDIN_FILENO;
225: if (cli_in) {
226: fd = dup(fd);
227: } else {
228: cli_in = 1;
229: file = stdin;
230: }
231: } else {
232: fd = dup(STDIN_FILENO);
233: }
234: } else if (!strcasecmp(path, "stdout")) {
235: if (!strcmp(sapi_module.name, "cli")) {
236: static int cli_out = 0;
237: fd = STDOUT_FILENO;
238: if (cli_out++) {
239: fd = dup(fd);
240: } else {
241: cli_out = 1;
242: file = stdout;
243: }
244: } else {
245: fd = dup(STDOUT_FILENO);
246: }
247: } else if (!strcasecmp(path, "stderr")) {
248: if (!strcmp(sapi_module.name, "cli")) {
249: static int cli_err = 0;
250: fd = STDERR_FILENO;
251: if (cli_err++) {
252: fd = dup(fd);
253: } else {
254: cli_err = 1;
255: file = stderr;
256: }
257: } else {
258: fd = dup(STDERR_FILENO);
259: }
260: } else if (!strncasecmp(path, "fd/", 3)) {
261: char *start,
262: *end;
263: long fildes_ori;
264: int dtablesize;
265:
1.1.1.3 misho 266: if (strcmp(sapi_module.name, "cli")) {
267: if (options & REPORT_ERRORS) {
268: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Direct access to file descriptors is only available from command-line PHP");
269: }
270: return NULL;
271: }
272:
273: if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
274: if (options & REPORT_ERRORS) {
275: php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
276: }
277: return NULL;
278: }
279:
1.1 misho 280: start = &path[3];
281: fildes_ori = strtol(start, &end, 10);
282: if (end == start || *end != '\0') {
283: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
284: "php://fd/ stream must be specified in the form php://fd/<orig fd>");
285: return NULL;
286: }
287:
288: #if HAVE_UNISTD_H
289: dtablesize = getdtablesize();
290: #else
291: dtablesize = INT_MAX;
292: #endif
293:
294: if (fildes_ori < 0 || fildes_ori >= dtablesize) {
295: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
296: "The file descriptors must be non-negative numbers smaller than %d", dtablesize);
297: return NULL;
298: }
299:
300: fd = dup(fildes_ori);
301: if (fd == -1) {
302: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
303: "Error duping file descriptor %ld; possibly it doesn't exist: "
304: "[%d]: %s", fildes_ori, errno, strerror(errno));
305: return NULL;
306: }
307: } else if (!strncasecmp(path, "filter/", 7)) {
308: /* Save time/memory when chain isn't specified */
309: if (strchr(mode, 'r') || strchr(mode, '+')) {
310: mode_rw |= PHP_STREAM_FILTER_READ;
311: }
312: if (strchr(mode, 'w') || strchr(mode, '+') || strchr(mode, 'a')) {
313: mode_rw |= PHP_STREAM_FILTER_WRITE;
314: }
315: pathdup = estrndup(path + 6, strlen(path + 6));
316: p = strstr(pathdup, "/resource=");
317: if (!p) {
318: php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "No URL resource specified");
319: efree(pathdup);
320: return NULL;
321: }
322: if (!(stream = php_stream_open_wrapper(p + 10, mode, options, opened_path))) {
323: efree(pathdup);
324: return NULL;
325: }
326:
327: *p = '\0';
328:
329: p = php_strtok_r(pathdup + 1, "/", &token);
330: while (p) {
331: if (!strncasecmp(p, "read=", 5)) {
332: php_stream_apply_filter_list(stream, p + 5, 1, 0 TSRMLS_CC);
333: } else if (!strncasecmp(p, "write=", 6)) {
334: php_stream_apply_filter_list(stream, p + 6, 0, 1 TSRMLS_CC);
335: } else {
336: php_stream_apply_filter_list(stream, p, mode_rw & PHP_STREAM_FILTER_READ, mode_rw & PHP_STREAM_FILTER_WRITE TSRMLS_CC);
337: }
338: p = php_strtok_r(NULL, "/", &token);
339: }
340: efree(pathdup);
341:
342: return stream;
343: } else {
344: /* invalid php://thingy */
345: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid php:// URL specified");
346: return NULL;
347: }
348:
349: /* must be stdin, stderr or stdout */
350: if (fd == -1) {
351: /* failed to dup */
352: return NULL;
353: }
354:
355: #if defined(S_IFSOCK) && !defined(WIN32) && !defined(__BEOS__)
356: do {
357: struct stat st;
358: memset(&st, 0, sizeof(st));
359: if (fstat(fd, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
360: stream = php_stream_sock_open_from_socket(fd, NULL);
361: if (stream) {
362: stream->ops = &php_stream_socket_ops;
363: return stream;
364: }
365: }
366: } while (0);
367: #endif
368:
369: if (file) {
370: stream = php_stream_fopen_from_file(file, mode);
371: } else {
372: stream = php_stream_fopen_from_fd(fd, mode, NULL);
373: if (stream == NULL) {
374: close(fd);
375: }
376: }
377:
378: return stream;
379: }
380: /* }}} */
381:
382: static php_stream_wrapper_ops php_stdio_wops = {
383: php_stream_url_wrap_php,
384: NULL, /* close */
385: NULL, /* fstat */
386: NULL, /* stat */
387: NULL, /* opendir */
388: "PHP",
389: NULL, /* unlink */
390: NULL, /* rename */
391: NULL, /* mkdir */
392: NULL /* rmdir */
393: };
394:
395: php_stream_wrapper php_stream_php_wrapper = {
396: &php_stdio_wops,
397: NULL,
398: 0, /* is_url */
399: };
400:
401:
402: /*
403: * Local variables:
404: * tab-width: 4
405: * c-basic-offset: 4
406: * End:
407: * vim600: sw=4 ts=4 fdm=marker
408: * vim<600: sw=4 ts=4
409: */