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 7                                                        |
   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) /* {{{ */
  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) /* {{{ */
  42 {
  43         stream->eof = 1;
  44         return 0;
  45 }
  46 /* }}} */
  47 
  48 static int php_stream_output_close(php_stream *stream, int close_handle) /* {{{ */
  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         zend_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) /* {{{ */
  73 {
  74         return -1;
  75 }
  76 /* }}} */
  77 
  78 static size_t php_stream_input_read(php_stream *stream, char *buf, size_t count) /* {{{ */
  79 {
  80         php_stream_input_t *input = stream->abstract;
  81         size_t read;
  82 
  83         if (!SG(post_read) && SG(read_post_bytes) < (int64_t)(input->position + count)) {
  84                 /* read requested data from SAPI */
  85                 size_t read_bytes = sapi_read_post_block(buf, count);
  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) /* {{{ */
 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) /* {{{ */
 116 {
 117         return -1;
 118 }
 119 /* }}} */
 120 
 121 static int php_stream_input_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset) /* {{{ */
 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) /* {{{ */
 148 {
 149         char *p, *token = NULL;
 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)))) {
 157                                 php_stream_filter_append(&stream->readfilters, temp_filter);
 158                         } else {
 159                                 php_error_docref(NULL, 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)))) {
 164                                 php_stream_filter_append(&stream->writefilters, temp_filter);
 165                         } else {
 166                                 php_error_docref(NULL, 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                                                                          zend_string **opened_path, php_stream_context *context STREAMS_DC) /* {{{ */
 176 {
 177         int fd = -1;
 178         int mode_rw = 0;
 179         php_stream * stream = NULL;
 180         char *p, *token, *pathdup;
 181         zend_long max_memory;
 182         FILE *file = NULL;
 183 #ifdef PHP_WIN32
 184         int pipe_requested = 0;
 185 #endif
 186 
 187         if (!strncasecmp(path, "php://", 6)) {
 188                 path += 6;
 189         }
 190 
 191         if (!strncasecmp(path, "temp", 4)) {
 192                 path += 4;
 193                 max_memory = PHP_STREAM_MAX_MEM;
 194                 if (!strncasecmp(path, "/maxmemory:", 11)) {
 195                         path += 11;
 196                         max_memory = ZEND_STRTOL(path, NULL, 10);
 197                         if (max_memory < 0) {
 198                                 php_error_docref(NULL, E_RECOVERABLE_ERROR, "Max memory must be >= 0");
 199                                 return NULL;
 200                         }
 201                 }
 202                 if (strpbrk(mode, "wa+")) {
 203                         mode_rw = TEMP_STREAM_DEFAULT;
 204                 } else {
 205                         mode_rw = TEMP_STREAM_READONLY;
 206                 }
 207                 return php_stream_temp_create(mode_rw, max_memory);
 208         }
 209 
 210         if (!strcasecmp(path, "memory")) {
 211                 if (strpbrk(mode, "wa+")) {
 212                         mode_rw = TEMP_STREAM_DEFAULT;
 213                 } else {
 214                         mode_rw = TEMP_STREAM_READONLY;
 215                 }
 216                 return php_stream_memory_create(mode_rw);
 217         }
 218 
 219         if (!strcasecmp(path, "output")) {
 220                 return php_stream_alloc(&php_stream_output_ops, NULL, 0, "wb");
 221         }
 222 
 223         if (!strcasecmp(path, "input")) {
 224                 php_stream_input_t *input;
 225 
 226                 if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
 227                         if (options & REPORT_ERRORS) {
 228                                 php_error_docref(NULL, E_WARNING, "URL file-access is disabled in the server configuration");
 229                         }
 230                         return NULL;
 231                 }
 232 
 233                 input = ecalloc(1, sizeof(*input));
 234                 if ((input->body = SG(request_info).request_body)) {
 235                         php_stream_rewind(input->body);
 236                 } else {
 237                         input->body = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir));
 238                         SG(request_info).request_body = input->body;
 239                 }
 240 
 241                 return php_stream_alloc(&php_stream_input_ops, input, 0, "rb");
 242         }
 243 
 244         if (!strcasecmp(path, "stdin")) {
 245                 if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
 246                         if (options & REPORT_ERRORS) {
 247                                 php_error_docref(NULL, E_WARNING, "URL file-access is disabled in the server configuration");
 248                         }
 249                         return NULL;
 250                 }
 251                 if (!strcmp(sapi_module.name, "cli")) {
 252                         static int cli_in = 0;
 253                         fd = STDIN_FILENO;
 254                         if (cli_in) {
 255                                 fd = dup(fd);
 256                         } else {
 257                                 cli_in = 1;
 258                                 file = stdin;
 259                         }
 260                 } else {
 261                         fd = dup(STDIN_FILENO);
 262                 }
 263 #ifdef PHP_WIN32
 264                 pipe_requested = 1;
 265 #endif
 266         } else if (!strcasecmp(path, "stdout")) {
 267                 if (!strcmp(sapi_module.name, "cli")) {
 268                         static int cli_out = 0;
 269                         fd = STDOUT_FILENO;
 270                         if (cli_out++) {
 271                                 fd = dup(fd);
 272                         } else {
 273                                 cli_out = 1;
 274                                 file = stdout;
 275                         }
 276                 } else {
 277                         fd = dup(STDOUT_FILENO);
 278                 }
 279 #ifdef PHP_WIN32
 280                 pipe_requested = 1;
 281 #endif
 282         } else if (!strcasecmp(path, "stderr")) {
 283                 if (!strcmp(sapi_module.name, "cli")) {
 284                         static int cli_err = 0;
 285                         fd = STDERR_FILENO;
 286                         if (cli_err++) {
 287                                 fd = dup(fd);
 288                         } else {
 289                                 cli_err = 1;
 290                                 file = stderr;
 291                         }
 292                 } else {
 293                         fd = dup(STDERR_FILENO);
 294                 }
 295 #ifdef PHP_WIN32
 296                 pipe_requested = 1;
 297 #endif
 298         } else if (!strncasecmp(path, "fd/", 3)) {
 299                 const char *start;
 300                 char       *end;
 301                 zend_long  fildes_ori;
 302                 int                dtablesize;
 303 
 304                 if (strcmp(sapi_module.name, "cli")) {
 305                         if (options & REPORT_ERRORS) {
 306                                 php_error_docref(NULL, E_WARNING, "Direct access to file descriptors is only available from command-line PHP");
 307                         }
 308                         return NULL;
 309                 }
 310 
 311                 if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
 312                         if (options & REPORT_ERRORS) {
 313                                 php_error_docref(NULL, E_WARNING, "URL file-access is disabled in the server configuration");
 314                         }
 315                         return NULL;
 316                 }
 317 
 318                 start = &path[3];
 319                 fildes_ori = ZEND_STRTOL(start, &end, 10);
 320                 if (end == start || *end != '\0') {
 321                         php_stream_wrapper_log_error(wrapper, options,
 322                                 "php://fd/ stream must be specified in the form php://fd/<orig fd>");
 323                         return NULL;
 324                 }
 325 
 326 #if HAVE_UNISTD_H
 327                 dtablesize = getdtablesize();
 328 #else
 329                 dtablesize = INT_MAX;
 330 #endif
 331 
 332                 if (fildes_ori < 0 || fildes_ori >= dtablesize) {
 333                         php_stream_wrapper_log_error(wrapper, options,
 334                                 "The file descriptors must be non-negative numbers smaller than %d", dtablesize);
 335                         return NULL;
 336                 }
 337 
 338                 fd = dup((int)fildes_ori);
 339                 if (fd == -1) {
 340                         php_stream_wrapper_log_error(wrapper, options,
 341                                 "Error duping file descriptor " ZEND_LONG_FMT "; possibly it doesn't exist: "
 342                                 "[%d]: %s", fildes_ori, errno, strerror(errno));
 343                         return NULL;
 344                 }
 345         } else if (!strncasecmp(path, "filter/", 7)) {
 346                 /* Save time/memory when chain isn't specified */
 347                 if (strchr(mode, 'r') || strchr(mode, '+')) {
 348                         mode_rw |= PHP_STREAM_FILTER_READ;
 349                 }
 350                 if (strchr(mode, 'w') || strchr(mode, '+') || strchr(mode, 'a')) {
 351                         mode_rw |= PHP_STREAM_FILTER_WRITE;
 352                 }
 353                 pathdup = estrndup(path + 6, strlen(path + 6));
 354                 p = strstr(pathdup, "/resource=");
 355                 if (!p) {
 356                         php_error_docref(NULL, E_RECOVERABLE_ERROR, "No URL resource specified");
 357                         efree(pathdup);
 358                         return NULL;
 359                 }
 360 
 361                 if (!(stream = php_stream_open_wrapper(p + 10, mode, options, opened_path))) {
 362                         efree(pathdup);
 363                         return NULL;
 364                 }
 365 
 366                 *p = '\0';
 367 
 368                 p = php_strtok_r(pathdup + 1, "/", &token);
 369                 while (p) {
 370                         if (!strncasecmp(p, "read=", 5)) {
 371                                 php_stream_apply_filter_list(stream, p + 5, 1, 0);
 372                         } else if (!strncasecmp(p, "write=", 6)) {
 373                                 php_stream_apply_filter_list(stream, p + 6, 0, 1);
 374                         } else {
 375                                 php_stream_apply_filter_list(stream, p, mode_rw & PHP_STREAM_FILTER_READ, mode_rw & PHP_STREAM_FILTER_WRITE);
 376                         }
 377                         p = php_strtok_r(NULL, "/", &token);
 378                 }
 379                 efree(pathdup);
 380 
 381                 return stream;
 382         } else {
 383                 /* invalid php://thingy */
 384                 php_error_docref(NULL, E_WARNING, "Invalid php:// URL specified");
 385                 return NULL;
 386         }
 387 
 388         /* must be stdin, stderr or stdout */
 389         if (fd == -1)   {
 390                 /* failed to dup */
 391                 return NULL;
 392         }
 393 
 394 #if defined(S_IFSOCK) && !defined(WIN32) && !defined(__BEOS__)
 395         do {
 396                 zend_stat_t st;
 397                 memset(&st, 0, sizeof(st));
 398                 if (zend_fstat(fd, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
 399                         stream = php_stream_sock_open_from_socket(fd, NULL);
 400                         if (stream) {
 401                                 stream->ops = &php_stream_socket_ops;
 402                                 return stream;
 403                         }
 404                 }
 405         } while (0);
 406 #endif
 407 
 408         if (file) {
 409                 stream = php_stream_fopen_from_file(file, mode);
 410         } else {
 411                 stream = php_stream_fopen_from_fd(fd, mode, NULL);
 412                 if (stream == NULL) {
 413                         close(fd);
 414                 }
 415         }
 416 
 417 #ifdef PHP_WIN32
 418         if (pipe_requested && stream && context) {
 419                 zval *blocking_pipes = php_stream_context_get_option(context, "pipe", "blocking");
 420                 if (blocking_pipes) {
 421                         convert_to_long(blocking_pipes);
 422                         php_stream_set_option(stream, PHP_STREAM_OPTION_PIPE_BLOCKING, Z_LVAL_P(blocking_pipes), NULL);
 423                 }
 424         }
 425 #endif
 426         return stream;
 427 }
 428 /* }}} */
 429 
 430 static php_stream_wrapper_ops php_stdio_wops = {
 431         php_stream_url_wrap_php,
 432         NULL, /* close */
 433         NULL, /* fstat */
 434         NULL, /* stat */
 435         NULL, /* opendir */
 436         "PHP",
 437         NULL, /* unlink */
 438         NULL, /* rename */
 439         NULL, /* mkdir */
 440         NULL  /* rmdir */
 441 };
 442 
 443 PHPAPI php_stream_wrapper php_stream_php_wrapper =      {
 444         &php_stdio_wops,
 445         NULL,
 446         0, /* is_url */
 447 };
 448 
 449 
 450 /*
 451  * Local variables:
 452  * tab-width: 4
 453  * c-basic-offset: 4
 454  * End:
 455  * vim600: sw=4 ts=4 fdm=marker
 456  * vim<600: sw=4 ts=4
 457  */

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