1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 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: Rasmus Lerdorf <rasmus@php.net> |
16 : | Jim Winstead <jimw@php.net> |
17 : | Hartmut Holzgraefe <hholzgra@php.net> |
18 : +----------------------------------------------------------------------+
19 : */
20 : /* $Id: php_fopen_wrapper.c 287507 2009-08-20 12:40:15Z jani $ */
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 8 : {
36 8 : PHPWRITE(buf, count);
37 8 : return count;
38 : }
39 : /* }}} */
40 :
41 : static size_t php_stream_output_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
42 0 : {
43 0 : stream->eof = 1;
44 0 : return 0;
45 : }
46 : /* }}} */
47 :
48 : static int php_stream_output_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
49 1 : {
50 1 : 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 0 : {
68 0 : return -1;
69 : }
70 : /* }}} */
71 :
72 : static size_t php_stream_input_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
73 0 : {
74 0 : off_t *position = (off_t*)stream->abstract;
75 0 : size_t read_bytes = 0;
76 :
77 0 : if (!stream->eof) {
78 0 : if (SG(request_info).raw_post_data) { /* data has already been read by a post handler */
79 0 : read_bytes = SG(request_info).raw_post_data_length - *position;
80 0 : if (read_bytes <= count) {
81 0 : stream->eof = 1;
82 : } else {
83 0 : read_bytes = count;
84 : }
85 0 : if (read_bytes) {
86 0 : memcpy(buf, SG(request_info).raw_post_data + *position, read_bytes);
87 : }
88 0 : } else if (sapi_module.read_post) {
89 0 : read_bytes = sapi_module.read_post(buf, count TSRMLS_CC);
90 0 : if (read_bytes <= 0) {
91 0 : stream->eof = 1;
92 0 : read_bytes = 0;
93 : }
94 : /* Increment SG(read_post_bytes) only when something was actually read. */
95 0 : SG(read_post_bytes) += read_bytes;
96 : } else {
97 0 : stream->eof = 1;
98 : }
99 : }
100 :
101 0 : *position += read_bytes;
102 :
103 0 : return read_bytes;
104 : }
105 : /* }}} */
106 :
107 : static int php_stream_input_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
108 0 : {
109 0 : efree(stream->abstract);
110 :
111 0 : return 0;
112 : }
113 : /* }}} */
114 :
115 : static int php_stream_input_flush(php_stream *stream TSRMLS_DC) /* {{{ */
116 0 : {
117 0 : 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 1 : {
135 : char *p, *token;
136 : php_stream_filter *temp_filter;
137 :
138 1 : p = php_strtok_r(filterlist, "|", &token);
139 6 : while (p) {
140 4 : php_url_decode(p, strlen(p));
141 4 : if (read_chain) {
142 4 : if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream) TSRMLS_CC))) {
143 2 : php_stream_filter_append(&stream->readfilters, temp_filter);
144 : } else {
145 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create filter (%s)", p);
146 : }
147 : }
148 4 : if (write_chain) {
149 0 : if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream) TSRMLS_CC))) {
150 0 : php_stream_filter_append(&stream->writefilters, temp_filter);
151 : } else {
152 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create filter (%s)", p);
153 : }
154 : }
155 4 : p = php_strtok_r(NULL, "|", &token);
156 : }
157 1 : }
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 49896 : {
162 49896 : int fd = -1;
163 49896 : int mode_rw = 0;
164 49896 : php_stream * stream = NULL;
165 : char *p, *token, *pathdup;
166 : long max_memory;
167 49896 : FILE *file = NULL;
168 :
169 49896 : if (!strncasecmp(path, "php://", 6)) {
170 49896 : path += 6;
171 : }
172 :
173 49896 : if (!strncasecmp(path, "temp", 4)) {
174 8 : path += 4;
175 8 : max_memory = PHP_STREAM_MAX_MEM;
176 8 : if (!strncasecmp(path, "/maxmemory:", 11)) {
177 0 : path += 11;
178 0 : max_memory = strtol(path, NULL, 10);
179 0 : if (max_memory < 0) {
180 0 : php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Max memory must be >= 0");
181 0 : return NULL;
182 : }
183 : }
184 8 : if (strpbrk(mode, "wa+")) {
185 7 : mode_rw = TEMP_STREAM_DEFAULT;
186 : } else {
187 1 : mode_rw = TEMP_STREAM_READONLY;
188 : }
189 8 : return php_stream_temp_create(mode_rw, max_memory);
190 : }
191 :
192 49888 : if (!strcasecmp(path, "memory")) {
193 36 : if (strpbrk(mode, "wa+")) {
194 34 : mode_rw = TEMP_STREAM_DEFAULT;
195 : } else {
196 2 : mode_rw = TEMP_STREAM_READONLY;
197 : }
198 36 : return php_stream_memory_create(mode_rw);
199 : }
200 :
201 49852 : if (!strcasecmp(path, "output")) {
202 1 : return php_stream_alloc(&php_stream_output_ops, NULL, 0, "wb");
203 : }
204 :
205 49851 : if (!strcasecmp(path, "input")) {
206 : /* Override default behavior for php://input when used as an include and allow_url_include is being used in BC (off) mode */
207 0 : if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include_list) ) {
208 0 : if (options & REPORT_ERRORS) {
209 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
210 : }
211 0 : return NULL;
212 : }
213 0 : return php_stream_alloc(&php_stream_input_ops, ecalloc(1, sizeof(off_t)), 0, "rb");
214 : }
215 :
216 49851 : if (!strcasecmp(path, "stdin")) {
217 : /* Override default behavior for php://stdin when used as an include and allow_url_include is being used in BC (off) mode */
218 16617 : if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include_list) ) {
219 0 : if (options & REPORT_ERRORS) {
220 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
221 : }
222 0 : return NULL;
223 : }
224 16617 : if (!strcmp(sapi_module.name, "cli")) {
225 : static int cli_in = 0;
226 16617 : fd = STDIN_FILENO;
227 16617 : if (cli_in) {
228 3 : fd = dup(fd);
229 : } else {
230 16614 : cli_in = 1;
231 16614 : file = stdin;
232 : }
233 : } else {
234 0 : fd = dup(STDIN_FILENO);
235 : }
236 33234 : } else if (!strcasecmp(path, "stdout")) {
237 16619 : if (!strcmp(sapi_module.name, "cli")) {
238 : static int cli_out = 0;
239 16619 : fd = STDOUT_FILENO;
240 16619 : if (cli_out++) {
241 5 : fd = dup(fd);
242 : } else {
243 16614 : cli_out = 1;
244 16614 : file = stdout;
245 : }
246 : } else {
247 0 : fd = dup(STDOUT_FILENO);
248 : }
249 16615 : } else if (!strcasecmp(path, "stderr")) {
250 16614 : if (!strcmp(sapi_module.name, "cli")) {
251 : static int cli_err = 0;
252 16614 : fd = STDERR_FILENO;
253 16614 : if (cli_err++) {
254 0 : fd = dup(fd);
255 : } else {
256 16614 : cli_err = 1;
257 16614 : file = stderr;
258 : }
259 : } else {
260 0 : fd = dup(STDERR_FILENO);
261 : }
262 1 : } else if (!strncasecmp(path, "filter/", 7)) {
263 : /* Save time/memory when chain isn't specified */
264 1 : if (strchr(mode, 'r') || strchr(mode, '+')) {
265 1 : mode_rw |= PHP_STREAM_FILTER_READ;
266 : }
267 1 : if (strchr(mode, 'w') || strchr(mode, '+') || strchr(mode, 'a')) {
268 0 : mode_rw |= PHP_STREAM_FILTER_WRITE;
269 : }
270 1 : pathdup = estrndup(path + 6, strlen(path + 6));
271 1 : p = strstr(pathdup, "/resource=");
272 1 : if (!p) {
273 0 : php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "No URL resource specified");
274 0 : efree(pathdup);
275 0 : return NULL;
276 : }
277 1 : if (!(stream = php_stream_open_wrapper(p + 10, mode, options, opened_path))) {
278 0 : efree(pathdup);
279 0 : return NULL;
280 : }
281 :
282 1 : *p = '\0';
283 :
284 1 : p = php_strtok_r(pathdup + 1, "/", &token);
285 3 : while (p) {
286 1 : if (!strncasecmp(p, "read=", 5)) {
287 1 : php_stream_apply_filter_list(stream, p + 5, 1, 0 TSRMLS_CC);
288 0 : } else if (!strncasecmp(p, "write=", 6)) {
289 0 : php_stream_apply_filter_list(stream, p + 6, 0, 1 TSRMLS_CC);
290 : } else {
291 0 : php_stream_apply_filter_list(stream, p, mode_rw & PHP_STREAM_FILTER_READ, mode_rw & PHP_STREAM_FILTER_WRITE TSRMLS_CC);
292 : }
293 1 : p = php_strtok_r(NULL, "/", &token);
294 : }
295 1 : efree(pathdup);
296 :
297 1 : return stream;
298 : } else {
299 : /* invalid php://thingy */
300 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid php:// URL specified");
301 0 : return NULL;
302 : }
303 :
304 : /* must be stdin, stderr or stdout */
305 49850 : if (fd == -1) {
306 : /* failed to dup */
307 0 : return NULL;
308 : }
309 :
310 : #if defined(S_IFSOCK) && !defined(WIN32) && !defined(__BEOS__)
311 : do {
312 : struct stat st;
313 49850 : memset(&st, 0, sizeof(st));
314 49850 : if (fstat(fd, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
315 0 : stream = php_stream_sock_open_from_socket(fd, NULL);
316 0 : if (stream) {
317 0 : stream->ops = &php_stream_socket_ops;
318 0 : return stream;
319 : }
320 : }
321 : } while (0);
322 : #endif
323 :
324 49850 : if (file) {
325 49842 : stream = php_stream_fopen_from_file(file, mode);
326 : } else {
327 8 : stream = php_stream_fopen_from_fd(fd, mode, NULL);
328 8 : if (stream == NULL) {
329 0 : close(fd);
330 : }
331 : }
332 :
333 49850 : return stream;
334 : }
335 : /* }}} */
336 :
337 : static php_stream_wrapper_ops php_stdio_wops = {
338 : php_stream_url_wrap_php,
339 : NULL, /* close */
340 : NULL, /* fstat */
341 : NULL, /* stat */
342 : NULL, /* opendir */
343 : "PHP",
344 : NULL, /* unlink */
345 : NULL, /* rename */
346 : NULL, /* mkdir */
347 : NULL /* rmdir */
348 : };
349 :
350 : php_stream_wrapper php_stream_php_wrapper = {
351 : &php_stdio_wops,
352 : NULL,
353 : 0, /* is_url */
354 : };
355 :
356 :
357 : /*
358 : * Local variables:
359 : * tab-width: 4
360 : * c-basic-offset: 4
361 : * End:
362 : * vim600: sw=4 ts=4 fdm=marker
363 : * vim<600: sw=4 ts=4
364 : */
|