diff options
Diffstat (limited to 'ext/standard/php_fopen_wrapper.c')
-rw-r--r-- | ext/standard/php_fopen_wrapper.c | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/ext/standard/php_fopen_wrapper.c b/ext/standard/php_fopen_wrapper.c new file mode 100644 index 0000000..f8d7bda --- /dev/null +++ b/ext/standard/php_fopen_wrapper.c @@ -0,0 +1,409 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Rasmus Lerdorf <rasmus@php.net> | + | Jim Winstead <jimw@php.net> | + | Hartmut Holzgraefe <hholzgra@php.net> | + +----------------------------------------------------------------------+ + */ +/* $Id$ */ + +#include <stdio.h> +#include <stdlib.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "php.h" +#include "php_globals.h" +#include "php_standard.h" +#include "php_fopen_wrappers.h" +#include "SAPI.h" + +static size_t php_stream_output_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */ +{ + PHPWRITE(buf, count); + return count; +} +/* }}} */ + +static size_t php_stream_output_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */ +{ + stream->eof = 1; + return 0; +} +/* }}} */ + +static int php_stream_output_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */ +{ + return 0; +} +/* }}} */ + +php_stream_ops php_stream_output_ops = { + php_stream_output_write, + php_stream_output_read, + php_stream_output_close, + NULL, /* flush */ + "Output", + NULL, /* seek */ + NULL, /* cast */ + NULL, /* stat */ + NULL /* set_option */ +}; + +static size_t php_stream_input_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */ +{ + return -1; +} +/* }}} */ + +static size_t php_stream_input_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */ +{ + off_t *position = (off_t*)stream->abstract; + size_t read_bytes = 0; + + if (!stream->eof) { + if (SG(request_info).raw_post_data) { /* data has already been read by a post handler */ + read_bytes = SG(request_info).raw_post_data_length - *position; + if (read_bytes <= count) { + stream->eof = 1; + } else { + read_bytes = count; + } + if (read_bytes) { + memcpy(buf, SG(request_info).raw_post_data + *position, read_bytes); + } + } else if (sapi_module.read_post) { + read_bytes = sapi_module.read_post(buf, count TSRMLS_CC); + if (read_bytes <= 0) { + stream->eof = 1; + read_bytes = 0; + } + /* Increment SG(read_post_bytes) only when something was actually read. */ + SG(read_post_bytes) += read_bytes; + } else { + stream->eof = 1; + } + } + + *position += read_bytes; + + return read_bytes; +} +/* }}} */ + +static int php_stream_input_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */ +{ + efree(stream->abstract); + + return 0; +} +/* }}} */ + +static int php_stream_input_flush(php_stream *stream TSRMLS_DC) /* {{{ */ +{ + return -1; +} +/* }}} */ + +php_stream_ops php_stream_input_ops = { + php_stream_input_write, + php_stream_input_read, + php_stream_input_close, + php_stream_input_flush, + "Input", + NULL, /* seek */ + NULL, /* cast */ + NULL, /* stat */ + NULL /* set_option */ +}; + +static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, int read_chain, int write_chain TSRMLS_DC) /* {{{ */ +{ + char *p, *token; + php_stream_filter *temp_filter; + + p = php_strtok_r(filterlist, "|", &token); + while (p) { + php_url_decode(p, strlen(p)); + if (read_chain) { + if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream) TSRMLS_CC))) { + php_stream_filter_append(&stream->readfilters, temp_filter); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create filter (%s)", p); + } + } + if (write_chain) { + if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream) TSRMLS_CC))) { + php_stream_filter_append(&stream->writefilters, temp_filter); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create filter (%s)", p); + } + } + p = php_strtok_r(NULL, "|", &token); + } +} +/* }}} */ + +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) /* {{{ */ +{ + int fd = -1; + int mode_rw = 0; + php_stream * stream = NULL; + char *p, *token, *pathdup; + long max_memory; + FILE *file = NULL; + + if (!strncasecmp(path, "php://", 6)) { + path += 6; + } + + if (!strncasecmp(path, "temp", 4)) { + path += 4; + max_memory = PHP_STREAM_MAX_MEM; + if (!strncasecmp(path, "/maxmemory:", 11)) { + path += 11; + max_memory = strtol(path, NULL, 10); + if (max_memory < 0) { + php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Max memory must be >= 0"); + return NULL; + } + } + if (strpbrk(mode, "wa+")) { + mode_rw = TEMP_STREAM_DEFAULT; + } else { + mode_rw = TEMP_STREAM_READONLY; + } + return php_stream_temp_create(mode_rw, max_memory); + } + + if (!strcasecmp(path, "memory")) { + if (strpbrk(mode, "wa+")) { + mode_rw = TEMP_STREAM_DEFAULT; + } else { + mode_rw = TEMP_STREAM_READONLY; + } + return php_stream_memory_create(mode_rw); + } + + if (!strcasecmp(path, "output")) { + return php_stream_alloc(&php_stream_output_ops, NULL, 0, "wb"); + } + + if (!strcasecmp(path, "input")) { + if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) { + if (options & REPORT_ERRORS) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration"); + } + return NULL; + } + return php_stream_alloc(&php_stream_input_ops, ecalloc(1, sizeof(off_t)), 0, "rb"); + } + + if (!strcasecmp(path, "stdin")) { + if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) { + if (options & REPORT_ERRORS) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration"); + } + return NULL; + } + if (!strcmp(sapi_module.name, "cli")) { + static int cli_in = 0; + fd = STDIN_FILENO; + if (cli_in) { + fd = dup(fd); + } else { + cli_in = 1; + file = stdin; + } + } else { + fd = dup(STDIN_FILENO); + } + } else if (!strcasecmp(path, "stdout")) { + if (!strcmp(sapi_module.name, "cli")) { + static int cli_out = 0; + fd = STDOUT_FILENO; + if (cli_out++) { + fd = dup(fd); + } else { + cli_out = 1; + file = stdout; + } + } else { + fd = dup(STDOUT_FILENO); + } + } else if (!strcasecmp(path, "stderr")) { + if (!strcmp(sapi_module.name, "cli")) { + static int cli_err = 0; + fd = STDERR_FILENO; + if (cli_err++) { + fd = dup(fd); + } else { + cli_err = 1; + file = stderr; + } + } else { + fd = dup(STDERR_FILENO); + } + } else if (!strncasecmp(path, "fd/", 3)) { + char *start, + *end; + long fildes_ori; + int dtablesize; + + if (strcmp(sapi_module.name, "cli")) { + if (options & REPORT_ERRORS) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Direct access to file descriptors is only available from command-line PHP"); + } + return NULL; + } + + if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) { + if (options & REPORT_ERRORS) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration"); + } + return NULL; + } + + start = &path[3]; + fildes_ori = strtol(start, &end, 10); + if (end == start || *end != '\0') { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, + "php://fd/ stream must be specified in the form php://fd/<orig fd>"); + return NULL; + } + +#if HAVE_UNISTD_H + dtablesize = getdtablesize(); +#else + dtablesize = INT_MAX; +#endif + + if (fildes_ori < 0 || fildes_ori >= dtablesize) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, + "The file descriptors must be non-negative numbers smaller than %d", dtablesize); + return NULL; + } + + fd = dup(fildes_ori); + if (fd == -1) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, + "Error duping file descriptor %ld; possibly it doesn't exist: " + "[%d]: %s", fildes_ori, errno, strerror(errno)); + return NULL; + } + } else if (!strncasecmp(path, "filter/", 7)) { + /* Save time/memory when chain isn't specified */ + if (strchr(mode, 'r') || strchr(mode, '+')) { + mode_rw |= PHP_STREAM_FILTER_READ; + } + if (strchr(mode, 'w') || strchr(mode, '+') || strchr(mode, 'a')) { + mode_rw |= PHP_STREAM_FILTER_WRITE; + } + pathdup = estrndup(path + 6, strlen(path + 6)); + p = strstr(pathdup, "/resource="); + if (!p) { + php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "No URL resource specified"); + efree(pathdup); + return NULL; + } + if (!(stream = php_stream_open_wrapper(p + 10, mode, options, opened_path))) { + efree(pathdup); + return NULL; + } + + *p = '\0'; + + p = php_strtok_r(pathdup + 1, "/", &token); + while (p) { + if (!strncasecmp(p, "read=", 5)) { + php_stream_apply_filter_list(stream, p + 5, 1, 0 TSRMLS_CC); + } else if (!strncasecmp(p, "write=", 6)) { + php_stream_apply_filter_list(stream, p + 6, 0, 1 TSRMLS_CC); + } else { + php_stream_apply_filter_list(stream, p, mode_rw & PHP_STREAM_FILTER_READ, mode_rw & PHP_STREAM_FILTER_WRITE TSRMLS_CC); + } + p = php_strtok_r(NULL, "/", &token); + } + efree(pathdup); + + return stream; + } else { + /* invalid php://thingy */ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid php:// URL specified"); + return NULL; + } + + /* must be stdin, stderr or stdout */ + if (fd == -1) { + /* failed to dup */ + return NULL; + } + +#if defined(S_IFSOCK) && !defined(WIN32) && !defined(__BEOS__) + do { + struct stat st; + memset(&st, 0, sizeof(st)); + if (fstat(fd, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) { + stream = php_stream_sock_open_from_socket(fd, NULL); + if (stream) { + stream->ops = &php_stream_socket_ops; + return stream; + } + } + } while (0); +#endif + + if (file) { + stream = php_stream_fopen_from_file(file, mode); + } else { + stream = php_stream_fopen_from_fd(fd, mode, NULL); + if (stream == NULL) { + close(fd); + } + } + + return stream; +} +/* }}} */ + +static php_stream_wrapper_ops php_stdio_wops = { + php_stream_url_wrap_php, + NULL, /* close */ + NULL, /* fstat */ + NULL, /* stat */ + NULL, /* opendir */ + "PHP", + NULL, /* unlink */ + NULL, /* rename */ + NULL, /* mkdir */ + NULL /* rmdir */ +}; + +php_stream_wrapper php_stream_php_wrapper = { + &php_stdio_wops, + NULL, + 0, /* is_url */ +}; + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ |