1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
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 2 : {
74 2 : off_t *position = (off_t*)stream->abstract;
75 2 : size_t read_bytes = 0;
76 :
77 2 : if (!stream->eof) {
78 1 : if (SG(request_info).raw_post_data) { /* data has already been read by a post handler */
79 1 : read_bytes = SG(request_info).raw_post_data_length - *position;
80 1 : if (read_bytes <= count) {
81 1 : stream->eof = 1;
82 : } else {
83 0 : read_bytes = count;
84 : }
85 1 : if (read_bytes) {
86 1 : 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 2 : *position += read_bytes;
102 :
103 2 : return read_bytes;
104 : }
105 : /* }}} */
106 :
107 : static int php_stream_input_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
108 1 : {
109 1 : efree(stream->abstract);
110 :
111 1 : return 0;
112 : }
113 : /* }}} */
114 :
115 : static int php_stream_input_flush(php_stream *stream TSRMLS_DC) /* {{{ */
116 1 : {
117 1 : 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 4 : php_stream_filter_append(&stream->readfilters, temp_filter);
144 : } else {
145 0 : 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 51803 : {
162 51803 : int fd = -1;
163 51803 : int mode_rw = 0;
164 51803 : php_stream * stream = NULL;
165 : char *p, *token, *pathdup;
166 : long max_memory;
167 51803 : FILE *file = NULL;
168 :
169 51803 : if (!strncasecmp(path, "php://", 6)) {
170 51803 : path += 6;
171 : }
172 :
173 51803 : if (!strncasecmp(path, "temp", 4)) {
174 7 : path += 4;
175 7 : max_memory = PHP_STREAM_MAX_MEM;
176 7 : 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 7 : if (strpbrk(mode, "wa+")) {
185 6 : mode_rw = TEMP_STREAM_DEFAULT;
186 : } else {
187 1 : mode_rw = TEMP_STREAM_READONLY;
188 : }
189 7 : return php_stream_temp_create(mode_rw, max_memory);
190 : }
191 :
192 51796 : 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 51760 : if (!strcasecmp(path, "output")) {
202 1 : return php_stream_alloc(&php_stream_output_ops, NULL, 0, "wb");
203 : }
204 :
205 51759 : if (!strcasecmp(path, "input")) {
206 1 : if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
207 0 : if (options & REPORT_ERRORS) {
208 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
209 : }
210 0 : return NULL;
211 : }
212 1 : return php_stream_alloc(&php_stream_input_ops, ecalloc(1, sizeof(off_t)), 0, "rb");
213 : }
214 :
215 51758 : if (!strcasecmp(path, "stdin")) {
216 17252 : if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
217 0 : if (options & REPORT_ERRORS) {
218 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
219 : }
220 0 : return NULL;
221 : }
222 17252 : if (!strcmp(sapi_module.name, "cli")) {
223 : static int cli_in = 0;
224 17252 : fd = STDIN_FILENO;
225 17252 : if (cli_in) {
226 3 : fd = dup(fd);
227 : } else {
228 17249 : cli_in = 1;
229 17249 : file = stdin;
230 : }
231 : } else {
232 0 : fd = dup(STDIN_FILENO);
233 : }
234 34506 : } else if (!strcasecmp(path, "stdout")) {
235 17256 : if (!strcmp(sapi_module.name, "cli")) {
236 : static int cli_out = 0;
237 17256 : fd = STDOUT_FILENO;
238 17256 : if (cli_out++) {
239 7 : fd = dup(fd);
240 : } else {
241 17249 : cli_out = 1;
242 17249 : file = stdout;
243 : }
244 : } else {
245 0 : fd = dup(STDOUT_FILENO);
246 : }
247 17250 : } else if (!strcasecmp(path, "stderr")) {
248 17249 : if (!strcmp(sapi_module.name, "cli")) {
249 : static int cli_err = 0;
250 17249 : fd = STDERR_FILENO;
251 17249 : if (cli_err++) {
252 0 : fd = dup(fd);
253 : } else {
254 17249 : cli_err = 1;
255 17249 : file = stderr;
256 : }
257 : } else {
258 0 : fd = dup(STDERR_FILENO);
259 : }
260 1 : } else if (!strncasecmp(path, "filter/", 7)) {
261 : /* Save time/memory when chain isn't specified */
262 1 : if (strchr(mode, 'r') || strchr(mode, '+')) {
263 1 : mode_rw |= PHP_STREAM_FILTER_READ;
264 : }
265 1 : if (strchr(mode, 'w') || strchr(mode, '+') || strchr(mode, 'a')) {
266 0 : mode_rw |= PHP_STREAM_FILTER_WRITE;
267 : }
268 1 : pathdup = estrndup(path + 6, strlen(path + 6));
269 1 : p = strstr(pathdup, "/resource=");
270 1 : if (!p) {
271 0 : php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "No URL resource specified");
272 0 : efree(pathdup);
273 0 : return NULL;
274 : }
275 1 : if (!(stream = php_stream_open_wrapper(p + 10, mode, options, opened_path))) {
276 0 : efree(pathdup);
277 0 : return NULL;
278 : }
279 :
280 1 : *p = '\0';
281 :
282 1 : p = php_strtok_r(pathdup + 1, "/", &token);
283 3 : while (p) {
284 1 : if (!strncasecmp(p, "read=", 5)) {
285 1 : php_stream_apply_filter_list(stream, p + 5, 1, 0 TSRMLS_CC);
286 0 : } else if (!strncasecmp(p, "write=", 6)) {
287 0 : php_stream_apply_filter_list(stream, p + 6, 0, 1 TSRMLS_CC);
288 : } else {
289 0 : php_stream_apply_filter_list(stream, p, mode_rw & PHP_STREAM_FILTER_READ, mode_rw & PHP_STREAM_FILTER_WRITE TSRMLS_CC);
290 : }
291 1 : p = php_strtok_r(NULL, "/", &token);
292 : }
293 1 : efree(pathdup);
294 :
295 1 : return stream;
296 : } else {
297 : /* invalid php://thingy */
298 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid php:// URL specified");
299 0 : return NULL;
300 : }
301 :
302 : /* must be stdin, stderr or stdout */
303 51757 : if (fd == -1) {
304 : /* failed to dup */
305 0 : return NULL;
306 : }
307 :
308 : #if defined(S_IFSOCK) && !defined(WIN32) && !defined(__BEOS__)
309 : do {
310 : struct stat st;
311 51757 : memset(&st, 0, sizeof(st));
312 51757 : if (fstat(fd, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
313 0 : stream = php_stream_sock_open_from_socket(fd, NULL);
314 0 : if (stream) {
315 0 : stream->ops = &php_stream_socket_ops;
316 0 : return stream;
317 : }
318 : }
319 : } while (0);
320 : #endif
321 :
322 51757 : if (file) {
323 51747 : stream = php_stream_fopen_from_file(file, mode);
324 : } else {
325 10 : stream = php_stream_fopen_from_fd(fd, mode, NULL);
326 10 : if (stream == NULL) {
327 0 : close(fd);
328 : }
329 : }
330 :
331 51757 : return stream;
332 : }
333 : /* }}} */
334 :
335 : static php_stream_wrapper_ops php_stdio_wops = {
336 : php_stream_url_wrap_php,
337 : NULL, /* close */
338 : NULL, /* fstat */
339 : NULL, /* stat */
340 : NULL, /* opendir */
341 : "PHP",
342 : NULL, /* unlink */
343 : NULL, /* rename */
344 : NULL, /* mkdir */
345 : NULL /* rmdir */
346 : };
347 :
348 : php_stream_wrapper php_stream_php_wrapper = {
349 : &php_stdio_wops,
350 : NULL,
351 : 0, /* is_url */
352 : };
353 :
354 :
355 : /*
356 : * Local variables:
357 : * tab-width: 4
358 : * c-basic-offset: 4
359 : * End:
360 : * vim600: sw=4 ts=4 fdm=marker
361 : * vim<600: sw=4 ts=4
362 : */
|