Back to index

php5  5.3.10
php_fopen_wrapper.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Rasmus Lerdorf <rasmus@php.net>                             |
00016    |          Jim Winstead <jimw@php.net>                                 |
00017    |          Hartmut Holzgraefe <hholzgra@php.net>                       |
00018    +----------------------------------------------------------------------+
00019  */
00020 /* $Id: php_fopen_wrapper.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #if HAVE_UNISTD_H
00025 #include <unistd.h>
00026 #endif
00027 
00028 #include "php.h"
00029 #include "php_globals.h"
00030 #include "php_standard.h"
00031 #include "php_fopen_wrappers.h"
00032 #include "SAPI.h"
00033 
00034 static size_t php_stream_output_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */
00035 {
00036        PHPWRITE(buf, count);
00037        return count;
00038 }
00039 /* }}} */
00040 
00041 static size_t php_stream_output_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
00042 {
00043        stream->eof = 1;
00044        return 0;
00045 }
00046 /* }}} */
00047 
00048 static int php_stream_output_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
00049 {
00050        return 0;
00051 }
00052 /* }}} */
00053 
00054 php_stream_ops php_stream_output_ops = {
00055        php_stream_output_write,
00056        php_stream_output_read,
00057        php_stream_output_close,
00058        NULL, /* flush */
00059        "Output",
00060        NULL, /* seek */
00061        NULL, /* cast */
00062        NULL, /* stat */
00063        NULL  /* set_option */
00064 };
00065 
00066 static size_t php_stream_input_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */
00067 {
00068        return -1;
00069 }
00070 /* }}} */
00071 
00072 static size_t php_stream_input_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
00073 {
00074        off_t *position = (off_t*)stream->abstract;
00075        size_t read_bytes = 0;
00076 
00077        if (!stream->eof) {
00078               if (SG(request_info).raw_post_data) { /* data has already been read by a post handler */
00079                      read_bytes = SG(request_info).raw_post_data_length - *position;
00080                      if (read_bytes <= count) {
00081                             stream->eof = 1;
00082                      } else {
00083                             read_bytes = count;
00084                      }
00085                      if (read_bytes) {
00086                             memcpy(buf, SG(request_info).raw_post_data + *position, read_bytes);
00087                      }
00088               } else if (sapi_module.read_post) {
00089                      read_bytes = sapi_module.read_post(buf, count TSRMLS_CC);
00090                      if (read_bytes <= 0) {
00091                             stream->eof = 1;
00092                             read_bytes = 0;
00093                      }
00094                      /* Increment SG(read_post_bytes) only when something was actually read. */
00095                      SG(read_post_bytes) += read_bytes;
00096               } else {
00097                      stream->eof = 1;
00098               }
00099        }
00100 
00101        *position += read_bytes;
00102 
00103        return read_bytes;
00104 }
00105 /* }}} */
00106 
00107 static int php_stream_input_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
00108 {
00109        efree(stream->abstract);
00110 
00111        return 0;
00112 }
00113 /* }}} */
00114 
00115 static int php_stream_input_flush(php_stream *stream TSRMLS_DC) /* {{{ */
00116 {
00117        return -1;
00118 }
00119 /* }}} */
00120 
00121 php_stream_ops php_stream_input_ops = {
00122        php_stream_input_write,
00123        php_stream_input_read,
00124        php_stream_input_close,
00125        php_stream_input_flush,
00126        "Input",
00127        NULL, /* seek */
00128        NULL, /* cast */
00129        NULL, /* stat */
00130        NULL  /* set_option */
00131 };
00132 
00133 static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, int read_chain, int write_chain TSRMLS_DC) /* {{{ */
00134 {
00135        char *p, *token;
00136        php_stream_filter *temp_filter;
00137 
00138        p = php_strtok_r(filterlist, "|", &token);
00139        while (p) {
00140               php_url_decode(p, strlen(p));
00141               if (read_chain) {
00142                      if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream) TSRMLS_CC))) {
00143                             php_stream_filter_append(&stream->readfilters, temp_filter);
00144                      } else {
00145                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create filter (%s)", p);
00146                      }
00147               }
00148               if (write_chain) {
00149                      if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream) TSRMLS_CC))) {
00150                             php_stream_filter_append(&stream->writefilters, temp_filter);
00151                      } else {
00152                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create filter (%s)", p);
00153                      }
00154               }
00155               p = php_strtok_r(NULL, "|", &token);
00156        }
00157 }
00158 /* }}} */
00159 
00160 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) /* {{{ */
00161 {
00162        int fd = -1;
00163        int mode_rw = 0;
00164        php_stream * stream = NULL;
00165        char *p, *token, *pathdup;
00166        long max_memory;
00167        FILE *file = NULL;
00168 
00169        if (!strncasecmp(path, "php://", 6)) {
00170               path += 6;
00171        }
00172 
00173        if (!strncasecmp(path, "temp", 4)) {
00174               path += 4;
00175               max_memory = PHP_STREAM_MAX_MEM;
00176               if (!strncasecmp(path, "/maxmemory:", 11)) {
00177                      path += 11;
00178                      max_memory = strtol(path, NULL, 10);
00179                      if (max_memory < 0) {
00180                             php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Max memory must be >= 0");
00181                             return NULL;
00182                      }
00183               }
00184               if (strpbrk(mode, "wa+")) {
00185                      mode_rw = TEMP_STREAM_DEFAULT;
00186               } else {
00187                      mode_rw = TEMP_STREAM_READONLY;
00188               }
00189               return php_stream_temp_create(mode_rw, max_memory);
00190        }
00191 
00192        if (!strcasecmp(path, "memory")) {
00193               if (strpbrk(mode, "wa+")) {
00194                      mode_rw = TEMP_STREAM_DEFAULT;
00195               } else {
00196                      mode_rw = TEMP_STREAM_READONLY;
00197               }
00198               return php_stream_memory_create(mode_rw);
00199        }
00200 
00201        if (!strcasecmp(path, "output")) {
00202               return php_stream_alloc(&php_stream_output_ops, NULL, 0, "wb");
00203        }
00204 
00205        if (!strcasecmp(path, "input")) {
00206               if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
00207                      if (options & REPORT_ERRORS) {
00208                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
00209                      }
00210                      return NULL;
00211               }
00212               return php_stream_alloc(&php_stream_input_ops, ecalloc(1, sizeof(off_t)), 0, "rb");
00213        }
00214 
00215        if (!strcasecmp(path, "stdin")) {
00216               if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
00217                      if (options & REPORT_ERRORS) {
00218                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
00219                      }
00220                      return NULL;
00221               }
00222               if (!strcmp(sapi_module.name, "cli")) {
00223                      static int cli_in = 0;
00224                      fd = STDIN_FILENO;
00225                      if (cli_in) {
00226                             fd = dup(fd);
00227                      } else {
00228                             cli_in = 1;
00229                             file = stdin;
00230                      }
00231               } else {
00232                      fd = dup(STDIN_FILENO);
00233               }
00234        } else if (!strcasecmp(path, "stdout")) {
00235               if (!strcmp(sapi_module.name, "cli")) {
00236                      static int cli_out = 0;
00237                      fd = STDOUT_FILENO;
00238                      if (cli_out++) {
00239                             fd = dup(fd);
00240                      } else {
00241                             cli_out = 1;
00242                             file = stdout;
00243                      }
00244               } else {
00245                      fd = dup(STDOUT_FILENO);
00246               }
00247        } else if (!strcasecmp(path, "stderr")) {
00248               if (!strcmp(sapi_module.name, "cli")) {
00249                      static int cli_err = 0;
00250                      fd = STDERR_FILENO;
00251                      if (cli_err++) {
00252                             fd = dup(fd);
00253                      } else {
00254                             cli_err = 1;
00255                             file = stderr;
00256                      }
00257               } else {
00258                      fd = dup(STDERR_FILENO);
00259               }
00260        } else if (!strncasecmp(path, "fd/", 3)) {
00261               char      *start,
00262                                *end;
00263               long      fildes_ori;
00264               int              dtablesize;
00265 
00266               start = &path[3];
00267               fildes_ori = strtol(start, &end, 10);
00268               if (end == start || *end != '\0') {
00269                      php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
00270                             "php://fd/ stream must be specified in the form php://fd/<orig fd>");
00271                      return NULL;
00272               }
00273 
00274 #if HAVE_UNISTD_H
00275               dtablesize = getdtablesize();
00276 #else
00277               dtablesize = INT_MAX;
00278 #endif
00279 
00280               if (fildes_ori < 0 || fildes_ori >= dtablesize) {
00281                      php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
00282                             "The file descriptors must be non-negative numbers smaller than %d", dtablesize);
00283                      return NULL;
00284               }
00285               
00286               fd = dup(fildes_ori);
00287               if (fd == -1) {
00288                      php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
00289                             "Error duping file descriptor %ld; possibly it doesn't exist: "
00290                             "[%d]: %s", fildes_ori, errno, strerror(errno));
00291                      return NULL;
00292               }
00293        } else if (!strncasecmp(path, "filter/", 7)) {
00294               /* Save time/memory when chain isn't specified */
00295               if (strchr(mode, 'r') || strchr(mode, '+')) {
00296                      mode_rw |= PHP_STREAM_FILTER_READ;
00297               }
00298               if (strchr(mode, 'w') || strchr(mode, '+') || strchr(mode, 'a')) {
00299                      mode_rw |= PHP_STREAM_FILTER_WRITE;
00300               }
00301               pathdup = estrndup(path + 6, strlen(path + 6));
00302               p = strstr(pathdup, "/resource=");
00303               if (!p) {
00304                      php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "No URL resource specified");
00305                      efree(pathdup);
00306                      return NULL;
00307               }
00308               if (!(stream = php_stream_open_wrapper(p + 10, mode, options, opened_path))) {
00309                      efree(pathdup);
00310                      return NULL;
00311               }
00312 
00313               *p = '\0';
00314 
00315               p = php_strtok_r(pathdup + 1, "/", &token);
00316               while (p) {
00317                      if (!strncasecmp(p, "read=", 5)) {
00318                             php_stream_apply_filter_list(stream, p + 5, 1, 0 TSRMLS_CC);
00319                      } else if (!strncasecmp(p, "write=", 6)) {
00320                             php_stream_apply_filter_list(stream, p + 6, 0, 1 TSRMLS_CC);
00321                      } else {
00322                             php_stream_apply_filter_list(stream, p, mode_rw & PHP_STREAM_FILTER_READ, mode_rw & PHP_STREAM_FILTER_WRITE TSRMLS_CC);
00323                      }
00324                      p = php_strtok_r(NULL, "/", &token);
00325               }
00326               efree(pathdup);
00327 
00328               return stream;
00329        } else {
00330               /* invalid php://thingy */
00331               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid php:// URL specified");
00332               return NULL;
00333        }
00334 
00335        /* must be stdin, stderr or stdout */
00336        if (fd == -1) {
00337               /* failed to dup */
00338               return NULL;
00339        }
00340 
00341 #if defined(S_IFSOCK) && !defined(WIN32) && !defined(__BEOS__)
00342        do {
00343               struct stat st;
00344               memset(&st, 0, sizeof(st));
00345               if (fstat(fd, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
00346                      stream = php_stream_sock_open_from_socket(fd, NULL);
00347                      if (stream) {
00348                             stream->ops = &php_stream_socket_ops;
00349                             return stream;
00350                      }
00351               }
00352        } while (0);
00353 #endif
00354 
00355        if (file) {
00356               stream = php_stream_fopen_from_file(file, mode);
00357        } else {
00358               stream = php_stream_fopen_from_fd(fd, mode, NULL);
00359               if (stream == NULL) {
00360                      close(fd);
00361               }
00362        }
00363 
00364        return stream;
00365 }
00366 /* }}} */
00367 
00368 static php_stream_wrapper_ops php_stdio_wops = {
00369        php_stream_url_wrap_php,
00370        NULL, /* close */
00371        NULL, /* fstat */
00372        NULL, /* stat */
00373        NULL, /* opendir */
00374        "PHP",
00375        NULL, /* unlink */
00376        NULL, /* rename */
00377        NULL, /* mkdir */
00378        NULL  /* rmdir */
00379 };
00380 
00381 php_stream_wrapper php_stream_php_wrapper =      {
00382        &php_stdio_wops,
00383        NULL,
00384        0, /* is_url */
00385 };
00386 
00387 
00388 /*
00389  * Local variables:
00390  * tab-width: 4
00391  * c-basic-offset: 4
00392  * End:
00393  * vim600: sw=4 ts=4 fdm=marker
00394  * vim<600: sw=4 ts=4
00395  */