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 0 : {
135 : char *p, *token;
136 : php_stream_filter *temp_filter;
137 :
138 0 : p = php_strtok_r(filterlist, "|", &token);
139 0 : while (p) {
140 0 : if (read_chain) {
141 0 : if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream) TSRMLS_CC))) {
142 0 : php_stream_filter_append(&stream->readfilters, temp_filter);
143 : } else {
144 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create filter (%s)", p);
145 : }
146 : }
147 0 : if (write_chain) {
148 0 : if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream) TSRMLS_CC))) {
149 0 : php_stream_filter_append(&stream->writefilters, temp_filter);
150 : } else {
151 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create filter (%s)", p);
152 : }
153 : }
154 0 : p = php_strtok_r(NULL, "|", &token);
155 : }
156 0 : }
157 : /* }}} */
158 :
159 : 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) /* {{{ */
160 40289 : {
161 40289 : int fd = -1;
162 40289 : int mode_rw = 0;
163 40289 : php_stream * stream = NULL;
164 : char *p, *token, *pathdup;
165 : long max_memory;
166 40289 : FILE *file = NULL;
167 :
168 40289 : if (!strncasecmp(path, "php://", 6)) {
169 40289 : path += 6;
170 : }
171 :
172 40289 : if (!strncasecmp(path, "temp", 4)) {
173 7 : path += 4;
174 7 : max_memory = PHP_STREAM_MAX_MEM;
175 7 : if (!strncasecmp(path, "/maxmemory:", 11)) {
176 0 : path += 11;
177 0 : max_memory = strtol(path, NULL, 10);
178 0 : if (max_memory < 0) {
179 0 : php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Max memory must be >= 0");
180 0 : return NULL;
181 : }
182 : }
183 7 : if (strpbrk(mode, "wa+")) {
184 6 : mode_rw = TEMP_STREAM_DEFAULT;
185 : } else {
186 1 : mode_rw = TEMP_STREAM_READONLY;
187 : }
188 7 : return php_stream_temp_create(mode_rw, max_memory);
189 : }
190 :
191 40282 : if (!strcasecmp(path, "memory")) {
192 31 : if (strpbrk(mode, "wa+")) {
193 30 : mode_rw = TEMP_STREAM_DEFAULT;
194 : } else {
195 1 : mode_rw = TEMP_STREAM_READONLY;
196 : }
197 31 : return php_stream_memory_create(mode_rw);
198 : }
199 :
200 40251 : if (!strcasecmp(path, "output")) {
201 1 : return php_stream_alloc(&php_stream_output_ops, NULL, 0, "wb");
202 : }
203 :
204 40250 : if (!strcasecmp(path, "input")) {
205 1 : if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
206 0 : if (options & REPORT_ERRORS) {
207 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
208 : }
209 0 : return NULL;
210 : }
211 1 : return php_stream_alloc(&php_stream_input_ops, ecalloc(1, sizeof(off_t)), 0, "rb");
212 : }
213 :
214 40249 : if (!strcasecmp(path, "stdin")) {
215 13416 : if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
216 0 : if (options & REPORT_ERRORS) {
217 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
218 : }
219 0 : return NULL;
220 : }
221 13416 : if (!strcmp(sapi_module.name, "cli")) {
222 : static int cli_in = 0;
223 13416 : fd = STDIN_FILENO;
224 13416 : if (cli_in) {
225 3 : fd = dup(fd);
226 : } else {
227 13413 : cli_in = 1;
228 13413 : file = stdin;
229 : }
230 : } else {
231 0 : fd = dup(STDIN_FILENO);
232 : }
233 26833 : } else if (!strcasecmp(path, "stdout")) {
234 13420 : if (!strcmp(sapi_module.name, "cli")) {
235 : static int cli_out = 0;
236 13420 : fd = STDOUT_FILENO;
237 13420 : if (cli_out++) {
238 7 : fd = dup(fd);
239 : } else {
240 13413 : cli_out = 1;
241 13413 : file = stdout;
242 : }
243 : } else {
244 0 : fd = dup(STDOUT_FILENO);
245 : }
246 13413 : } else if (!strcasecmp(path, "stderr")) {
247 13413 : if (!strcmp(sapi_module.name, "cli")) {
248 : static int cli_err = 0;
249 13413 : fd = STDERR_FILENO;
250 13413 : if (cli_err++) {
251 0 : fd = dup(fd);
252 : } else {
253 13413 : cli_err = 1;
254 13413 : file = stderr;
255 : }
256 : } else {
257 0 : fd = dup(STDERR_FILENO);
258 : }
259 0 : } else if (!strncasecmp(path, "filter/", 7)) {
260 : /* Save time/memory when chain isn't specified */
261 0 : if (strchr(mode, 'r') || strchr(mode, '+')) {
262 0 : mode_rw |= PHP_STREAM_FILTER_READ;
263 : }
264 0 : if (strchr(mode, 'w') || strchr(mode, '+') || strchr(mode, 'a')) {
265 0 : mode_rw |= PHP_STREAM_FILTER_WRITE;
266 : }
267 0 : pathdup = estrndup(path + 6, strlen(path + 6));
268 0 : p = strstr(pathdup, "/resource=");
269 0 : if (!p) {
270 0 : php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "No URL resource specified");
271 0 : efree(pathdup);
272 0 : return NULL;
273 : }
274 0 : if (!(stream = php_stream_open_wrapper(p + 10, mode, options, opened_path))) {
275 0 : efree(pathdup);
276 0 : return NULL;
277 : }
278 :
279 0 : *p = '\0';
280 :
281 0 : p = php_strtok_r(pathdup + 1, "/", &token);
282 0 : while (p) {
283 0 : if (!strncasecmp(p, "read=", 5)) {
284 0 : php_stream_apply_filter_list(stream, p + 5, 1, 0 TSRMLS_CC);
285 0 : } else if (!strncasecmp(p, "write=", 6)) {
286 0 : php_stream_apply_filter_list(stream, p + 6, 0, 1 TSRMLS_CC);
287 : } else {
288 0 : php_stream_apply_filter_list(stream, p, mode_rw & PHP_STREAM_FILTER_READ, mode_rw & PHP_STREAM_FILTER_WRITE TSRMLS_CC);
289 : }
290 0 : p = php_strtok_r(NULL, "/", &token);
291 : }
292 0 : efree(pathdup);
293 :
294 0 : return stream;
295 : } else {
296 : /* invalid php://thingy */
297 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid php:// URL specified");
298 0 : return NULL;
299 : }
300 :
301 : /* must be stdin, stderr or stdout */
302 40249 : if (fd == -1) {
303 : /* failed to dup */
304 0 : return NULL;
305 : }
306 :
307 : #if defined(S_IFSOCK) && !defined(WIN32) && !defined(__BEOS__)
308 : do {
309 : struct stat st;
310 40249 : memset(&st, 0, sizeof(st));
311 40249 : if (fstat(fd, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
312 0 : stream = php_stream_sock_open_from_socket(fd, NULL);
313 0 : if (stream) {
314 0 : stream->ops = &php_stream_socket_ops;
315 0 : return stream;
316 : }
317 : }
318 : } while (0);
319 : #endif
320 :
321 40249 : if (file) {
322 40239 : stream = php_stream_fopen_from_file(file, mode);
323 : } else {
324 10 : stream = php_stream_fopen_from_fd(fd, mode, NULL);
325 10 : if (stream == NULL) {
326 0 : close(fd);
327 : }
328 : }
329 :
330 40249 : return stream;
331 : }
332 : /* }}} */
333 :
334 : static php_stream_wrapper_ops php_stdio_wops = {
335 : php_stream_url_wrap_php,
336 : NULL, /* close */
337 : NULL, /* fstat */
338 : NULL, /* stat */
339 : NULL, /* opendir */
340 : "PHP",
341 : NULL, /* unlink */
342 : NULL, /* rename */
343 : NULL, /* mkdir */
344 : NULL /* rmdir */
345 : };
346 :
347 : php_stream_wrapper php_stream_php_wrapper = {
348 : &php_stdio_wops,
349 : NULL,
350 : 0, /* is_url */
351 : };
352 :
353 :
354 : /*
355 : * Local variables:
356 : * tab-width: 4
357 : * c-basic-offset: 4
358 : * End:
359 : * vim600: sw=4 ts=4 fdm=marker
360 : * vim<600: sw=4 ts=4
361 : */
|