php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
php_fopen_wrapper.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Rasmus Lerdorf <rasmus@php.net> |
14 | Jim Winstead <jimw@php.net> |
15 | Hartmut Holzgraefe <hholzgra@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19#include <stdio.h>
20#include <stdlib.h>
21#ifdef HAVE_UNISTD_H
22# include <unistd.h>
23#endif
24
25#include "php.h"
26#include "php_globals.h"
27#include "php_standard.h"
28#include "php_memory_streams.h"
29#include "php_fopen_wrappers.h"
30#include "SAPI.h"
31
32static ssize_t php_stream_output_write(php_stream *stream, const char *buf, size_t count) /* {{{ */
33{
35 return count;
36}
37/* }}} */
38
39static ssize_t php_stream_output_read(php_stream *stream, char *buf, size_t count) /* {{{ */
40{
41 stream->eof = 1;
42 return -1;
43}
44/* }}} */
45
46static int php_stream_output_close(php_stream *stream, int close_handle) /* {{{ */
47{
48 return 0;
49}
50/* }}} */
51
52static const php_stream_ops php_stream_output_ops = {
53 php_stream_output_write,
54 php_stream_output_read,
55 php_stream_output_close,
56 NULL, /* flush */
57 "Output",
58 NULL, /* seek */
59 NULL, /* cast */
60 NULL, /* stat */
61 NULL /* set_option */
62};
63
68/* }}} */
69
70static ssize_t php_stream_input_write(php_stream *stream, const char *buf, size_t count) /* {{{ */
71{
72 return -1;
73}
74/* }}} */
75
76static ssize_t php_stream_input_read(php_stream *stream, char *buf, size_t count) /* {{{ */
77{
78 php_stream_input_t *input = stream->abstract;
79 ssize_t read;
80
81 if (!SG(post_read) && SG(read_post_bytes) < (int64_t)(input->position + count)) {
82 /* read requested data from SAPI */
83 size_t read_bytes = sapi_read_post_block(buf, count);
84
85 if (read_bytes > 0) {
86 php_stream_seek(input->body, 0, SEEK_END);
87 php_stream_write(input->body, buf, read_bytes);
88 }
89 }
90
91 if (!input->body->readfilters.head) {
92 /* If the input stream contains filters, it's not really seekable. The
93 input->position is likely to be wrong for unfiltered data. */
94 php_stream_seek(input->body, input->position, SEEK_SET);
95 }
96 read = php_stream_read(input->body, buf, count);
97
98 if (!read || read == (size_t) -1) {
99 stream->eof = 1;
100 } else {
101 input->position += read;
102 }
103
104 return read;
105}
106/* }}} */
107
108static int php_stream_input_close(php_stream *stream, int close_handle) /* {{{ */
109{
110 efree(stream->abstract);
111 stream->abstract = NULL;
112
113 return 0;
114}
115/* }}} */
116
117static int php_stream_input_flush(php_stream *stream) /* {{{ */
118{
119 return -1;
120}
121/* }}} */
122
123static int php_stream_input_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset) /* {{{ */
124{
125 php_stream_input_t *input = stream->abstract;
126
127 if (input->body) {
128 int sought = php_stream_seek(input->body, offset, whence);
129 *newoffset = input->position = (input->body)->position;
130 return sought;
131 }
132
133 return -1;
134}
135/* }}} */
136
137static const php_stream_ops php_stream_input_ops = {
138 php_stream_input_write,
139 php_stream_input_read,
140 php_stream_input_close,
141 php_stream_input_flush,
142 "Input",
143 php_stream_input_seek,
144 NULL, /* cast */
145 NULL, /* stat */
146 NULL /* set_option */
147};
148
149static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, int read_chain, int write_chain) /* {{{ */
150{
151 char *p, *token = NULL;
152 php_stream_filter *temp_filter;
153
154 p = php_strtok_r(filterlist, "|", &token);
155 while (p) {
157 if (read_chain) {
158 if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream)))) {
159 php_stream_filter_append(&stream->readfilters, temp_filter);
160 } else {
161 php_error_docref(NULL, E_WARNING, "Unable to create filter (%s)", p);
162 }
163 }
164 if (write_chain) {
165 if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream)))) {
166 php_stream_filter_append(&stream->writefilters, temp_filter);
167 } else {
168 php_error_docref(NULL, E_WARNING, "Unable to create filter (%s)", p);
169 }
170 }
171 p = php_strtok_r(NULL, "|", &token);
172 }
173}
174/* }}} */
175
176static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const char *path, const char *mode, int options,
177 zend_string **opened_path, php_stream_context *context STREAMS_DC) /* {{{ */
178{
179 int fd = -1;
180 int mode_rw = 0;
181 php_stream * stream = NULL;
182 char *p, *token = NULL, *pathdup;
183 zend_long max_memory;
184 FILE *file = NULL;
185#ifdef PHP_WIN32
186 int pipe_requested = 0;
187#endif
188
189 if (!strncasecmp(path, "php://", 6)) {
190 path += 6;
191 }
192
193 if (!strncasecmp(path, "temp", 4)) {
194 path += 4;
195 max_memory = PHP_STREAM_MAX_MEM;
196 if (!strncasecmp(path, "/maxmemory:", 11)) {
197 path += 11;
198 max_memory = ZEND_STRTOL(path, NULL, 10);
199 if (max_memory < 0) {
200 zend_argument_value_error(2, "must be greater than or equal to 0");
201 return NULL;
202 }
203 }
205 return php_stream_temp_create(mode_rw, max_memory);
206 }
207
208 if (!strcasecmp(path, "memory")) {
210 return php_stream_memory_create(mode_rw);
211 }
212
213 if (!strcasecmp(path, "output")) {
214 return php_stream_alloc(&php_stream_output_ops, NULL, 0, "wb");
215 }
216
217 if (!strcasecmp(path, "input")) {
218 php_stream_input_t *input;
219
220 if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
221 if (options & REPORT_ERRORS) {
222 php_error_docref(NULL, E_WARNING, "URL file-access is disabled in the server configuration");
223 }
224 return NULL;
225 }
226
227 input = ecalloc(1, sizeof(*input));
228 if ((input->body = SG(request_info).request_body)) {
229 php_stream_rewind(input->body);
230 } else {
232 SG(request_info).request_body = input->body;
233 }
234
235 return php_stream_alloc(&php_stream_input_ops, input, 0, "rb");
236 }
237
238 if (!strcasecmp(path, "stdin")) {
239 if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
240 if (options & REPORT_ERRORS) {
241 php_error_docref(NULL, E_WARNING, "URL file-access is disabled in the server configuration");
242 }
243 return NULL;
244 }
245 if (!strcmp(sapi_module.name, "cli")) {
246 static int cli_in = 0;
248 if (cli_in) {
249 fd = dup(fd);
250 } else {
251 cli_in = 1;
252 file = stdin;
253 }
254 } else {
255 fd = dup(STDIN_FILENO);
256 }
257#ifdef PHP_WIN32
258 pipe_requested = 1;
259#endif
260 } else if (!strcasecmp(path, "stdout")) {
261 if (!strcmp(sapi_module.name, "cli")) {
262 static int cli_out = 0;
264 if (cli_out++) {
265 fd = dup(fd);
266 } else {
267 cli_out = 1;
268 file = stdout;
269 }
270 } else {
271 fd = dup(STDOUT_FILENO);
272 }
273#ifdef PHP_WIN32
274 pipe_requested = 1;
275#endif
276 } else if (!strcasecmp(path, "stderr")) {
277 if (!strcmp(sapi_module.name, "cli")) {
278 static int cli_err = 0;
280 if (cli_err++) {
281 fd = dup(fd);
282 } else {
283 cli_err = 1;
284 file = stderr;
285 }
286 } else {
287 fd = dup(STDERR_FILENO);
288 }
289#ifdef PHP_WIN32
290 pipe_requested = 1;
291#endif
292 } else if (!strncasecmp(path, "fd/", 3)) {
293 const char *start;
294 char *end;
295 zend_long fildes_ori;
296 int dtablesize;
297
298 if (strcmp(sapi_module.name, "cli")) {
299 if (options & REPORT_ERRORS) {
300 php_error_docref(NULL, E_WARNING, "Direct access to file descriptors is only available from command-line PHP");
301 }
302 return NULL;
303 }
304
305 if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
306 if (options & REPORT_ERRORS) {
307 php_error_docref(NULL, E_WARNING, "URL file-access is disabled in the server configuration");
308 }
309 return NULL;
310 }
311
312 start = &path[3];
313 fildes_ori = ZEND_STRTOL(start, &end, 10);
314 if (end == start || *end != '\0') {
316 "php://fd/ stream must be specified in the form php://fd/<orig fd>");
317 return NULL;
318 }
319
320#ifdef HAVE_UNISTD_H
321 dtablesize = getdtablesize();
322#else
323 dtablesize = INT_MAX;
324#endif
325
326 if (fildes_ori < 0 || fildes_ori >= dtablesize) {
328 "The file descriptors must be non-negative numbers smaller than %d", dtablesize);
329 return NULL;
330 }
331
332 fd = dup((int)fildes_ori);
333 if (fd == -1) {
335 "Error duping file descriptor " ZEND_LONG_FMT "; possibly it doesn't exist: "
336 "[%d]: %s", fildes_ori, errno, strerror(errno));
337 return NULL;
338 }
339 } else if (!strncasecmp(path, "filter/", 7)) {
340 /* Save time/memory when chain isn't specified */
341 if (strchr(mode, 'r') || strchr(mode, '+')) {
342 mode_rw |= PHP_STREAM_FILTER_READ;
343 }
344 if (strchr(mode, 'w') || strchr(mode, '+') || strchr(mode, 'a')) {
345 mode_rw |= PHP_STREAM_FILTER_WRITE;
346 }
347 pathdup = estrndup(path + 6, strlen(path + 6));
348 p = strstr(pathdup, "/resource=");
349 if (!p) {
350 zend_throw_error(NULL, "No URL resource specified");
351 efree(pathdup);
352 return NULL;
353 }
354
355 if (!(stream = php_stream_open_wrapper_ex(p + 10, mode, options, opened_path, context))) {
356 efree(pathdup);
357 return NULL;
358 }
359
360 *p = '\0';
361
362 p = php_strtok_r(pathdup + 1, "/", &token);
363 while (p) {
364 if (!strncasecmp(p, "read=", 5)) {
365 php_stream_apply_filter_list(stream, p + 5, 1, 0);
366 } else if (!strncasecmp(p, "write=", 6)) {
367 php_stream_apply_filter_list(stream, p + 6, 0, 1);
368 } else {
369 php_stream_apply_filter_list(stream, p, mode_rw & PHP_STREAM_FILTER_READ, mode_rw & PHP_STREAM_FILTER_WRITE);
370 }
371 p = php_strtok_r(NULL, "/", &token);
372 }
373 efree(pathdup);
374
375 if (EG(exception)) {
376 php_stream_close(stream);
377 return NULL;
378 }
379
380 return stream;
381 } else {
382 /* invalid php://thingy */
383 php_error_docref(NULL, E_WARNING, "Invalid php:// URL specified");
384 return NULL;
385 }
386
387 /* must be stdin, stderr or stdout */
388 if (fd == -1) {
389 /* failed to dup */
390 return NULL;
391 }
392
393#if defined(S_IFSOCK) && !defined(PHP_WIN32)
394 do {
395 zend_stat_t st = {0};
396 memset(&st, 0, sizeof(st));
397 if (zend_fstat(fd, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
399 if (stream) {
400 stream->ops = &php_stream_socket_ops;
401 return stream;
402 }
403 }
404 } while (0);
405#endif
406
407 if (file) {
409 } else {
411 if (stream == NULL) {
412 close(fd);
413 }
414 }
415
416#ifdef PHP_WIN32
417 if (pipe_requested && stream && context) {
418 zval *blocking_pipes = php_stream_context_get_option(context, "pipe", "blocking");
419 if (blocking_pipes) {
420 php_stream_set_option(stream, PHP_STREAM_OPTION_PIPE_BLOCKING, zval_get_long(blocking_pipes), NULL);
421 }
422 }
423#endif
424 return stream;
425}
426/* }}} */
427
428static const php_stream_wrapper_ops php_stdio_wops = {
429 php_stream_url_wrap_php,
430 NULL, /* close */
431 NULL, /* fstat */
432 NULL, /* stat */
433 NULL, /* opendir */
434 "PHP",
435 NULL, /* unlink */
436 NULL, /* rename */
437 NULL, /* mkdir */
438 NULL, /* rmdir */
439 NULL
440};
441
443 &php_stdio_wops,
444 NULL,
445 0, /* is_url */
446};
SAPI_API sapi_module_struct sapi_module
Definition SAPI.c:65
SAPI_API size_t sapi_read_post_block(char *buffer, size_t buflen)
Definition SAPI.c:232
#define SG(v)
Definition SAPI.h:160
#define SAPI_POST_BLOCK_SIZE
Definition SAPI.h:28
bool exception
Definition assert.c:30
file(string $filename, int $flags=0, $context=null)
count(Countable|array $value, int $mode=COUNT_NORMAL)
strstr(string $haystack, string $needle, bool $before_needle=false)
strchr(string $haystack, string $needle, bool $before_needle=false)
#define STDOUT_FILENO
Definition cgi_main.c:291
memset(ptr, 0, type->size)
buf start
Definition ffi.c:4687
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
const SEEK_END
Definition file.stub.php:21
zend_long offset
char * mode
#define SEEK_SET
Definition gd_io_file.c:20
#define NULL
Definition gdcache.h:45
#define STDIN_FILENO
Definition magic.c:78
PHPAPI php_stream_filter * php_stream_filter_create(const char *filtername, zval *filterparams, uint8_t persistent)
Definition filter.c:220
PHPAPI size_t php_url_decode(char *str, size_t len)
Definition url.c:582
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
#define INT_MAX
Definition php.h:237
#define PHPAPI
Definition php.h:71
#define STDERR_FILENO
Definition php_cli.c:221
unsigned const char * end
Definition php_ffi.h:51
struct php_stream_input php_stream_input_t
PHPAPI const php_stream_wrapper php_stream_php_wrapper
#define PG(v)
Definition php_globals.h:31
PHP_JSON_API size_t int options
Definition php_json.h:102
#define TEMP_STREAM_DEFAULT
#define php_stream_temp_create(mode, max_memory_usage)
#define PHP_STREAM_MAX_MEM
#define php_stream_memory_create(mode)
#define php_stream_temp_create_ex(mode, max_memory_usage, tmpdir)
PHPAPI int php_stream_mode_from_str(const char *mode)
Definition memory.c:266
#define php_stream_sock_open_from_socket(socket, persistent)
PHPAPI const php_stream_ops php_stream_socket_ops
Definition xp_socket.c:543
#define PHPWRITE(str, str_len)
PHPAPI char * php_strtok_r(char *s, const char *delim, char **last)
Definition reentrancy.c:263
PHPAPI zval * php_stream_context_get_option(php_stream_context *context, const char *wrappername, const char *optionname)
Definition streams.c:2407
#define php_stream_filter_append(chain, filter)
#define PHP_STREAM_FILTER_WRITE
#define PHP_STREAM_FILTER_READ
#define php_stream_fopen_from_fd(fd, mode, persistent_id)
#define php_stream_fopen_from_file(file, mode)
struct _php_stream_wrapper_ops php_stream_wrapper_ops
struct _php_stream php_stream
Definition php_streams.h:96
struct _php_stream_context php_stream_context
Definition php_streams.h:98
#define REPORT_ERRORS
#define php_stream_read(stream, buf, count)
struct _php_stream_filter php_stream_filter
Definition php_streams.h:99
#define STREAMS_DC
Definition php_streams.h:53
#define php_stream_rewind(stream)
#define STREAM_OPEN_FOR_INCLUDE
#define php_stream_seek(stream, offset, whence)
#define php_stream_open_wrapper_ex(path, mode, options, opened, context)
#define php_stream_close(stream)
#define php_stream_is_persistent(stream)
struct _php_stream_ops php_stream_ops
struct _php_stream_wrapper php_stream_wrapper
Definition php_streams.h:97
#define php_stream_set_option(stream, option, value, ptrvalue)
#define php_stream_alloc(ops, thisptr, persistent_id, mode)
#define PHP_STREAM_OPTION_PIPE_BLOCKING
#define php_stream_write(stream, buf, count)
PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, int options, const char *fmt,...) PHP_ATTRIBUTE_FORMAT(printf
int fd
Definition phpdbg.h:282
p
Definition session.c:1105
const php_stream_ops * ops
uint16_t eof
php_stream_filter_chain writefilters
void * abstract
php_stream_filter_chain readfilters
Definition dce.c:49
#define close(a)
#define errno
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:433
#define estrndup(s, length)
Definition zend_alloc.h:165
#define ecalloc(nmemb, size)
Definition zend_alloc.h:158
#define efree(ptr)
Definition zend_alloc.h:155
struct _zval_struct zval
strlen(string $string)
strcmp(string $string1, string $string2)
#define strncasecmp(s1, s2, n)
#define strcasecmp(s1, s2)
#define E_WARNING
Definition zend_errors.h:24
#define EG(v)
int32_t zend_long
Definition zend_long.h:42
int32_t zend_off_t
Definition zend_long.h:44
#define ZEND_STRTOL(s0, s1, base)
Definition zend_long.h:85
#define ZEND_LONG_FMT
Definition zend_long.h:87
struct _zend_string zend_string
#define zend_fstat
Definition zend_stream.h:98
struct stat zend_stat_t
Definition zend_stream.h:94