root/ext/standard/php_fopen_wrapper.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_stream_output_write
  2. php_stream_output_read
  3. php_stream_output_close
  4. php_stream_input_write
  5. php_stream_input_read
  6. php_stream_input_close
  7. php_stream_input_flush
  8. php_stream_input_seek
  9. php_stream_apply_filter_list
  10. php_stream_url_wrap_php

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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$ */
  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 {
  36         PHPWRITE(buf, count);
  37         return count;
  38 }
  39 /* }}} */
  40 
  41 static size_t php_stream_output_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
  42 {
  43         stream->eof = 1;
  44         return 0;
  45 }
  46 /* }}} */
  47 
  48 static int php_stream_output_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
  49 {
  50         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 typedef struct php_stream_input { /* {{{ */
  67         php_stream *body;
  68         off_t position;
  69 } php_stream_input_t;
  70 /* }}} */
  71 
  72 static size_t php_stream_input_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */
  73 {
  74         return -1;
  75 }
  76 /* }}} */
  77 
  78 static size_t php_stream_input_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
  79 {
  80         php_stream_input_t *input = stream->abstract;
  81         size_t read;
  82 
  83         if (!SG(post_read) && SG(read_post_bytes) < input->position + count) {
  84                 /* read requested data from SAPI */
  85                 int read_bytes = sapi_read_post_block(buf, count TSRMLS_CC);
  86 
  87                 if (read_bytes > 0) {
  88                         php_stream_seek(input->body, 0, SEEK_END);
  89                         php_stream_write(input->body, buf, read_bytes);
  90                 }
  91         }
  92 
  93         php_stream_seek(input->body, input->position, SEEK_SET);
  94         read = php_stream_read(input->body, buf, count);
  95 
  96         if (!read || read == (size_t) -1) {
  97                 stream->eof = 1;
  98         } else {
  99                 input->position += read;
 100         }
 101 
 102         return read;
 103 }
 104 /* }}} */
 105 
 106 static int php_stream_input_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
 107 {
 108         efree(stream->abstract);
 109         stream->abstract = NULL;
 110 
 111         return 0;
 112 }
 113 /* }}} */
 114 
 115 static int php_stream_input_flush(php_stream *stream TSRMLS_DC) /* {{{ */
 116 {
 117         return -1;
 118 }
 119 /* }}} */
 120 
 121 static int php_stream_input_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC) /* {{{ */
 122 {
 123         php_stream_input_t *input = stream->abstract;
 124 
 125         if (input->body) {
 126                 int sought = php_stream_seek(input->body, offset, whence);
 127                 *newoffset = (input->body)->position;
 128                 return sought;
 129         }
 130 
 131         return -1;
 132 }
 133 /* }}} */
 134 
 135 php_stream_ops php_stream_input_ops = {
 136         php_stream_input_write,
 137         php_stream_input_read,
 138         php_stream_input_close,
 139         php_stream_input_flush,
 140         "Input",
 141         php_stream_input_seek,
 142         NULL, /* cast */
 143         NULL, /* stat */
 144         NULL  /* set_option */
 145 };
 146 
 147 static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, int read_chain, int write_chain TSRMLS_DC) /* {{{ */
 148 {
 149         char *p, *token;
 150         php_stream_filter *temp_filter;
 151 
 152         p = php_strtok_r(filterlist, "|", &token);
 153         while (p) {
 154                 php_url_decode(p, strlen(p));
 155                 if (read_chain) {
 156                         if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream) TSRMLS_CC))) {
 157                                 php_stream_filter_append(&stream->readfilters, temp_filter);
 158                         } else {
 159                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create filter (%s)", p);
 160                         }
 161                 }
 162                 if (write_chain) {
 163                         if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream) TSRMLS_CC))) {
 164                                 php_stream_filter_append(&stream->writefilters, temp_filter);
 165                         } else {
 166                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create filter (%s)", p);
 167                         }
 168                 }
 169                 p = php_strtok_r(NULL, "|", &token);
 170         }
 171 }
 172 /* }}} */
 173 
 174 php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const char *path, const char *mode, int options,
 175                                                                          char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */
 176 {
 177         int fd = -1;
 178         int mode_rw = 0;
 179         php_stream * stream = NULL;
 180         char *p, *token, *pathdup;
 181         long max_memory;
 182         FILE *file = NULL;
 183 
 184         if (!strncasecmp(path, "php://", 6)) {
 185                 path += 6;
 186         }
 187 
 188         if (!strncasecmp(path, "temp", 4)) {
 189                 path += 4;
 190                 max_memory = PHP_STREAM_MAX_MEM;
 191                 if (!strncasecmp(path, "/maxmemory:", 11)) {
 192                         path += 11;
 193                         max_memory = strtol(path, NULL, 10);
 194                         if (max_memory < 0) {
 195                                 php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Max memory must be >= 0");
 196                                 return NULL;
 197                         }
 198                 }
 199                 if (strpbrk(mode, "wa+")) {
 200                         mode_rw = TEMP_STREAM_DEFAULT;
 201                 } else {
 202                         mode_rw = TEMP_STREAM_READONLY;
 203                 }
 204                 return php_stream_temp_create(mode_rw, max_memory);
 205         }
 206 
 207         if (!strcasecmp(path, "memory")) {
 208                 if (strpbrk(mode, "wa+")) {
 209                         mode_rw = TEMP_STREAM_DEFAULT;
 210                 } else {
 211                         mode_rw = TEMP_STREAM_READONLY;
 212                 }
 213                 return php_stream_memory_create(mode_rw);
 214         }
 215 
 216         if (!strcasecmp(path, "output")) {
 217                 return php_stream_alloc(&php_stream_output_ops, NULL, 0, "wb");
 218         }
 219 
 220         if (!strcasecmp(path, "input")) {
 221                 php_stream_input_t *input;
 222 
 223                 if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
 224                         if (options & REPORT_ERRORS) {
 225                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
 226                         }
 227                         return NULL;
 228                 }
 229 
 230                 input = ecalloc(1, sizeof(*input));
 231                 if ((input->body = SG(request_info).request_body)) {
 232                         php_stream_rewind(input->body);
 233                 } else {
 234                         input->body = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir));
 235                         SG(request_info).request_body = input->body;
 236                 }
 237 
 238                 return php_stream_alloc(&php_stream_input_ops, input, 0, "rb");
 239         }
 240 
 241         if (!strcasecmp(path, "stdin")) {
 242                 if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
 243                         if (options & REPORT_ERRORS) {
 244                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
 245                         }
 246                         return NULL;
 247                 }
 248                 if (!strcmp(sapi_module.name, "cli")) {
 249                         static int cli_in = 0;
 250                         fd = STDIN_FILENO;
 251                         if (cli_in) {
 252                                 fd = dup(fd);
 253                         } else {
 254                                 cli_in = 1;
 255                                 file = stdin;
 256                         }
 257                 } else {
 258                         fd = dup(STDIN_FILENO);
 259                 }
 260         } else if (!strcasecmp(path, "stdout")) {
 261                 if (!strcmp(sapi_module.name, "cli")) {
 262                         static int cli_out = 0;
 263                         fd = STDOUT_FILENO;
 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         } else if (!strcasecmp(path, "stderr")) {
 274                 if (!strcmp(sapi_module.name, "cli")) {
 275                         static int cli_err = 0;
 276                         fd = STDERR_FILENO;
 277                         if (cli_err++) {
 278                                 fd = dup(fd);
 279                         } else {
 280                                 cli_err = 1;
 281                                 file = stderr;
 282                         }
 283                 } else {
 284                         fd = dup(STDERR_FILENO);
 285                 }
 286         } else if (!strncasecmp(path, "fd/", 3)) {
 287                 const char *start;
 288                 char       *end;
 289                 long       fildes_ori;
 290                 int                dtablesize;
 291 
 292                 if (strcmp(sapi_module.name, "cli")) {
 293                         if (options & REPORT_ERRORS) {
 294                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Direct access to file descriptors is only available from command-line PHP");
 295                         }
 296                         return NULL;
 297                 }
 298 
 299                 if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
 300                         if (options & REPORT_ERRORS) {
 301                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration");
 302                         }
 303                         return NULL;
 304                 }
 305 
 306                 start = &path[3];
 307                 fildes_ori = strtol(start, &end, 10);
 308                 if (end == start || *end != '\0') {
 309                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
 310                                 "php://fd/ stream must be specified in the form php://fd/<orig fd>");
 311                         return NULL;
 312                 }
 313 
 314 #if HAVE_UNISTD_H
 315                 dtablesize = getdtablesize();
 316 #else
 317                 dtablesize = INT_MAX;
 318 #endif
 319 
 320                 if (fildes_ori < 0 || fildes_ori >= dtablesize) {
 321                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
 322                                 "The file descriptors must be non-negative numbers smaller than %d", dtablesize);
 323                         return NULL;
 324                 }
 325                 
 326                 fd = dup(fildes_ori);
 327                 if (fd == -1) {
 328                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
 329                                 "Error duping file descriptor %ld; possibly it doesn't exist: "
 330                                 "[%d]: %s", fildes_ori, errno, strerror(errno));
 331                         return NULL;
 332                 }
 333         } else if (!strncasecmp(path, "filter/", 7)) {
 334                 /* Save time/memory when chain isn't specified */
 335                 if (strchr(mode, 'r') || strchr(mode, '+')) {
 336                         mode_rw |= PHP_STREAM_FILTER_READ;
 337                 }
 338                 if (strchr(mode, 'w') || strchr(mode, '+') || strchr(mode, 'a')) {
 339                         mode_rw |= PHP_STREAM_FILTER_WRITE;
 340                 }
 341                 pathdup = estrndup(path + 6, strlen(path + 6));
 342                 p = strstr(pathdup, "/resource=");
 343                 if (!p) {
 344                         php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "No URL resource specified");
 345                         efree(pathdup);
 346                         return NULL;
 347                 }
 348                 if (!(stream = php_stream_open_wrapper(p + 10, mode, options, opened_path))) {
 349                         efree(pathdup);
 350                         return NULL;
 351                 }
 352 
 353                 *p = '\0';
 354 
 355                 p = php_strtok_r(pathdup + 1, "/", &token);
 356                 while (p) {
 357                         if (!strncasecmp(p, "read=", 5)) {
 358                                 php_stream_apply_filter_list(stream, p + 5, 1, 0 TSRMLS_CC);
 359                         } else if (!strncasecmp(p, "write=", 6)) {
 360                                 php_stream_apply_filter_list(stream, p + 6, 0, 1 TSRMLS_CC);
 361                         } else {
 362                                 php_stream_apply_filter_list(stream, p, mode_rw & PHP_STREAM_FILTER_READ, mode_rw & PHP_STREAM_FILTER_WRITE TSRMLS_CC);
 363                         }
 364                         p = php_strtok_r(NULL, "/", &token);
 365                 }
 366                 efree(pathdup);
 367 
 368                 return stream;
 369         } else {
 370                 /* invalid php://thingy */
 371                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid php:// URL specified");
 372                 return NULL;
 373         }
 374 
 375         /* must be stdin, stderr or stdout */
 376         if (fd == -1)   {
 377                 /* failed to dup */
 378                 return NULL;
 379         }
 380 
 381 #if defined(S_IFSOCK) && !defined(WIN32) && !defined(__BEOS__)
 382         do {
 383                 struct stat st;
 384                 memset(&st, 0, sizeof(st));
 385                 if (fstat(fd, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
 386                         stream = php_stream_sock_open_from_socket(fd, NULL);
 387                         if (stream) {
 388                                 stream->ops = &php_stream_socket_ops;
 389                                 return stream;
 390                         }
 391                 }
 392         } while (0);
 393 #endif
 394 
 395         if (file) {
 396                 stream = php_stream_fopen_from_file(file, mode);
 397         } else {
 398                 stream = php_stream_fopen_from_fd(fd, mode, NULL);
 399                 if (stream == NULL) {
 400                         close(fd);
 401                 }
 402         }
 403 
 404         return stream;
 405 }
 406 /* }}} */
 407 
 408 static php_stream_wrapper_ops php_stdio_wops = {
 409         php_stream_url_wrap_php,
 410         NULL, /* close */
 411         NULL, /* fstat */
 412         NULL, /* stat */
 413         NULL, /* opendir */
 414         "PHP",
 415         NULL, /* unlink */
 416         NULL, /* rename */
 417         NULL, /* mkdir */
 418         NULL  /* rmdir */
 419 };
 420 
 421 php_stream_wrapper php_stream_php_wrapper =     {
 422         &php_stdio_wops,
 423         NULL,
 424         0, /* is_url */
 425 };
 426 
 427 
 428 /*
 429  * Local variables:
 430  * tab-width: 4
 431  * c-basic-offset: 4
 432  * End:
 433  * vim600: sw=4 ts=4 fdm=marker
 434  * vim<600: sw=4 ts=4
 435  */

/* [<][>][^][v][top][bottom][index][help] */