PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - main - rfc1867.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 551 610 90.3 %
Date: 2015-07-05 Functions: 29 30 96.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2015 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             :    |          Jani Taskinen <jani@php.net>                                |
      17             :    +----------------------------------------------------------------------+
      18             :  */
      19             : 
      20             : /* $Id$ */
      21             : 
      22             : /*
      23             :  *  This product includes software developed by the Apache Group
      24             :  *  for use in the Apache HTTP server project (http://www.apache.org/).
      25             :  *
      26             :  */
      27             : 
      28             : #include <stdio.h>
      29             : #include "php.h"
      30             : #include "php_open_temporary_file.h"
      31             : #include "zend_globals.h"
      32             : #include "php_globals.h"
      33             : #include "php_variables.h"
      34             : #include "rfc1867.h"
      35             : #include "ext/standard/php_string.h"
      36             : #include "ext/standard/php_smart_string.h"
      37             : 
      38             : #if defined(PHP_WIN32) && !defined(HAVE_ATOLL)
      39             : # define atoll(s) _atoi64(s)
      40             : # define HAVE_ATOLL 1
      41             : #endif
      42             : 
      43             : #define DEBUG_FILE_UPLOAD ZEND_DEBUG
      44             : 
      45           0 : static int dummy_encoding_translation(void)
      46             : {
      47           0 :         return 0;
      48             : }
      49             : 
      50             : static char *php_ap_getword(const zend_encoding *encoding, char **line, char stop);
      51             : static char *php_ap_getword_conf(const zend_encoding *encoding, char *str);
      52             : 
      53             : static php_rfc1867_encoding_translation_t php_rfc1867_encoding_translation = dummy_encoding_translation;
      54             : static php_rfc1867_get_detect_order_t php_rfc1867_get_detect_order = NULL;
      55             : static php_rfc1867_set_input_encoding_t php_rfc1867_set_input_encoding = NULL;
      56             : static php_rfc1867_getword_t php_rfc1867_getword = php_ap_getword;
      57             : static php_rfc1867_getword_conf_t php_rfc1867_getword_conf = php_ap_getword_conf;
      58             : static php_rfc1867_basename_t php_rfc1867_basename = NULL;
      59             : 
      60             : PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra) = NULL;
      61             : 
      62             : static void safe_php_register_variable(char *var, char *strval, size_t val_len, zval *track_vars_array, zend_bool override_protection);
      63             : 
      64             : /* The longest property name we use in an uploaded file array */
      65             : #define MAX_SIZE_OF_INDEX sizeof("[tmp_name]")
      66             : 
      67             : /* The longest anonymous name */
      68             : #define MAX_SIZE_ANONNAME 33
      69             : 
      70             : /* Errors */
      71             : #define UPLOAD_ERROR_OK   0  /* File upload successful */
      72             : #define UPLOAD_ERROR_A    1  /* Uploaded file exceeded upload_max_filesize */
      73             : #define UPLOAD_ERROR_B    2  /* Uploaded file exceeded MAX_FILE_SIZE */
      74             : #define UPLOAD_ERROR_C    3  /* Partially uploaded */
      75             : #define UPLOAD_ERROR_D    4  /* No file uploaded */
      76             : #define UPLOAD_ERROR_E    6  /* Missing /tmp or similar directory */
      77             : #define UPLOAD_ERROR_F    7  /* Failed to write file to disk */
      78             : #define UPLOAD_ERROR_X    8  /* File upload stopped by extension */
      79             : 
      80       21049 : void php_rfc1867_register_constants(void) /* {{{ */
      81             : {
      82       21049 :         REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_OK",         UPLOAD_ERROR_OK, CONST_CS | CONST_PERSISTENT);
      83       21049 :         REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_INI_SIZE",   UPLOAD_ERROR_A,  CONST_CS | CONST_PERSISTENT);
      84       21049 :         REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FORM_SIZE",  UPLOAD_ERROR_B,  CONST_CS | CONST_PERSISTENT);
      85       21049 :         REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL",    UPLOAD_ERROR_C,  CONST_CS | CONST_PERSISTENT);
      86       21049 :         REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE",    UPLOAD_ERROR_D,  CONST_CS | CONST_PERSISTENT);
      87       21049 :         REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E,  CONST_CS | CONST_PERSISTENT);
      88       21049 :         REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_CANT_WRITE", UPLOAD_ERROR_F,  CONST_CS | CONST_PERSISTENT);
      89       21049 :         REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_EXTENSION",  UPLOAD_ERROR_X,  CONST_CS | CONST_PERSISTENT);
      90       21049 : }
      91             : /* }}} */
      92             : 
      93         453 : static void normalize_protected_variable(char *varname) /* {{{ */
      94             : {
      95         453 :         char *s = varname, *index = NULL, *indexend = NULL, *p;
      96             : 
      97             :         /* overjump leading space */
      98         906 :         while (*s == ' ') {
      99           0 :                 s++;
     100             :         }
     101             : 
     102             :         /* and remove it */
     103         453 :         if (s != varname) {
     104           0 :                 memmove(varname, s, strlen(s)+1);
     105             :         }
     106             : 
     107        3342 :         for (p = varname; *p && *p != '['; p++) {
     108        2889 :                 switch(*p) {
     109             :                         case ' ':
     110             :                         case '.':
     111           0 :                                 *p = '_';
     112             :                                 break;
     113             :                 }
     114             :         }
     115             : 
     116             :         /* find index */
     117         453 :         index = strchr(varname, '[');
     118         453 :         if (index) {
     119         271 :                 index++;
     120         271 :                 s = index;
     121             :         } else {
     122         182 :                 return;
     123             :         }
     124             : 
     125             :         /* done? */
     126         833 :         while (index) {
     127         582 :                 while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') {
     128           0 :                         index++;
     129             :                 }
     130         291 :                 indexend = strchr(index, ']');
     131         291 :                 indexend = indexend ? indexend + 1 : index + strlen(index);
     132             : 
     133         291 :                 if (s != index) {
     134           0 :                         memmove(s, index, strlen(index)+1);
     135           0 :                         s += indexend-index;
     136             :                 } else {
     137         291 :                         s = indexend;
     138             :                 }
     139             : 
     140         291 :                 if (*s == '[') {
     141          20 :                         s++;
     142          20 :                         index = s;
     143             :                 } else {
     144         271 :                         index = NULL;
     145             :                 }
     146             :         }
     147         271 :         *s = '\0';
     148             : }
     149             : /* }}} */
     150             : 
     151         102 : static void add_protected_variable(char *varname) /* {{{ */
     152             : {
     153         102 :         normalize_protected_variable(varname);
     154         102 :         zend_hash_str_add_empty_element(&PG(rfc1867_protected_variables), varname, strlen(varname));
     155         102 : }
     156             : /* }}} */
     157             : 
     158         351 : static zend_bool is_protected_variable(char *varname) /* {{{ */
     159             : {
     160         351 :         normalize_protected_variable(varname);
     161         351 :         return zend_hash_str_exists(&PG(rfc1867_protected_variables), varname, strlen(varname));
     162             : }
     163             : /* }}} */
     164             : 
     165         200 : static void safe_php_register_variable(char *var, char *strval, size_t val_len, zval *track_vars_array, zend_bool override_protection) /* {{{ */
     166             : {
     167         200 :         if (override_protection || !is_protected_variable(var)) {
     168         200 :                 php_register_variable_safe(var, strval, val_len, track_vars_array);
     169             :         }
     170         200 : }
     171             : /* }}} */
     172             : 
     173         251 : static void safe_php_register_variable_ex(char *var, zval *val, zval *track_vars_array, zend_bool override_protection) /* {{{ */
     174             : {
     175         251 :         if (override_protection || !is_protected_variable(var)) {
     176         251 :                 php_register_variable_ex(var, val, track_vars_array);
     177             :         }
     178         251 : }
     179             : /* }}} */
     180             : 
     181         102 : static void register_http_post_files_variable(char *strvar, char *val, zval *http_post_files, zend_bool override_protection) /* {{{ */
     182             : {
     183         102 :         safe_php_register_variable(strvar, val, strlen(val), http_post_files, override_protection);
     184         102 : }
     185             : /* }}} */
     186             : 
     187         153 : static void register_http_post_files_variable_ex(char *var, zval *val, zval *http_post_files, zend_bool override_protection) /* {{{ */
     188             : {
     189         153 :         safe_php_register_variable_ex(var, val, http_post_files, override_protection);
     190         153 : }
     191             : /* }}} */
     192             : 
     193          43 : static int unlink_filename(zval *el) /* {{{ */
     194             : {
     195          43 :         zend_string *filename = Z_STR_P(el);
     196          43 :         VCWD_UNLINK(filename->val);
     197          43 :         return 0;
     198             : }
     199             : /* }}} */
     200             : 
     201             : 
     202          45 : static void free_filename(zval *el) {
     203          45 :         zend_string *filename = Z_STR_P(el);
     204             :         zend_string_release(filename);
     205          45 : }
     206             : 
     207          34 : PHPAPI void destroy_uploaded_files_hash(void) /* {{{ */
     208             : {
     209          34 :         zend_hash_apply(SG(rfc1867_uploaded_files), unlink_filename);
     210          34 :         zend_hash_destroy(SG(rfc1867_uploaded_files));
     211          34 :         FREE_HASHTABLE(SG(rfc1867_uploaded_files));
     212          34 : }
     213             : /* }}} */
     214             : 
     215             : /* {{{ Following code is based on apache_multipart_buffer.c from libapreq-0.33 package. */
     216             : 
     217             : #define FILLUNIT (1024 * 5)
     218             : 
     219             : typedef struct {
     220             : 
     221             :         /* read buffer */
     222             :         char *buffer;
     223             :         char *buf_begin;
     224             :         int  bufsize;
     225             :         int  bytes_in_buffer;
     226             : 
     227             :         /* boundary info */
     228             :         char *boundary;
     229             :         char *boundary_next;
     230             :         int  boundary_next_len;
     231             : 
     232             :         const zend_encoding *input_encoding;
     233             :         const zend_encoding **detect_order;
     234             :         size_t detect_order_size;
     235             : } multipart_buffer;
     236             : 
     237             : typedef struct {
     238             :         char *key;
     239             :         char *value;
     240             : } mime_header_entry;
     241             : 
     242             : /*
     243             :  * Fill up the buffer with client data.
     244             :  * Returns number of bytes added to buffer.
     245             :  */
     246         267 : static int fill_buffer(multipart_buffer *self)
     247             : {
     248         267 :         int bytes_to_read, total_read = 0, actual_read = 0;
     249             : 
     250             :         /* shift the existing data if necessary */
     251         267 :         if (self->bytes_in_buffer > 0 && self->buf_begin != self->buffer) {
     252         231 :                 memmove(self->buffer, self->buf_begin, self->bytes_in_buffer);
     253             :         }
     254             : 
     255         267 :         self->buf_begin = self->buffer;
     256             : 
     257             :         /* calculate the free space in the buffer */
     258         267 :         bytes_to_read = self->bufsize - self->bytes_in_buffer;
     259             : 
     260             :         /* read the required number of bytes */
     261         568 :         while (bytes_to_read > 0) {
     262             : 
     263         301 :                 char *buf = self->buffer + self->bytes_in_buffer;
     264             : 
     265         301 :                 actual_read = (int)sapi_module.read_post(buf, bytes_to_read);
     266             : 
     267             :                 /* update the buffer length */
     268         301 :                 if (actual_read > 0) {
     269          34 :                         self->bytes_in_buffer += actual_read;
     270          34 :                         SG(read_post_bytes) += actual_read;
     271          34 :                         total_read += actual_read;
     272          34 :                         bytes_to_read -= actual_read;
     273             :                 } else {
     274         267 :                         break;
     275             :                 }
     276             :         }
     277             : 
     278         267 :         return total_read;
     279             : }
     280             : 
     281             : /* eof if we are out of bytes, or if we hit the final boundary */
     282         143 : static int multipart_buffer_eof(multipart_buffer *self)
     283             : {
     284         143 :         if ( (self->bytes_in_buffer == 0 && fill_buffer(self) < 1) ) {
     285           1 :                 return 1;
     286             :         } else {
     287         142 :                 return 0;
     288             :         }
     289             : }
     290             : 
     291             : /* create new multipart_buffer structure */
     292          34 : static multipart_buffer *multipart_buffer_new(char *boundary, int boundary_len)
     293             : {
     294          34 :         multipart_buffer *self = (multipart_buffer *) ecalloc(1, sizeof(multipart_buffer));
     295             : 
     296          34 :         int minsize = boundary_len + 6;
     297          34 :         if (minsize < FILLUNIT) minsize = FILLUNIT;
     298             : 
     299          34 :         self->buffer = (char *) ecalloc(1, minsize + 1);
     300          34 :         self->bufsize = minsize;
     301             : 
     302          34 :         spprintf(&self->boundary, 0, "--%s", boundary);
     303             : 
     304          34 :         self->boundary_next_len = (int)spprintf(&self->boundary_next, 0, "\n--%s", boundary);
     305             : 
     306          34 :         self->buf_begin = self->buffer;
     307          34 :         self->bytes_in_buffer = 0;
     308             : 
     309          34 :         if (php_rfc1867_encoding_translation()) {
     310           1 :                 php_rfc1867_get_detect_order(&self->detect_order, &self->detect_order_size);
     311             :         } else {
     312          33 :                 self->detect_order = NULL;
     313          33 :                 self->detect_order_size = 0;
     314             :         }
     315             : 
     316          34 :         self->input_encoding = NULL;
     317             : 
     318          34 :         return self;
     319             : }
     320             : 
     321             : /*
     322             :  * Gets the next CRLF terminated line from the input buffer.
     323             :  * If it doesn't find a CRLF, and the buffer isn't completely full, returns
     324             :  * NULL; otherwise, returns the beginning of the null-terminated line,
     325             :  * minus the CRLF.
     326             :  *
     327             :  * Note that we really just look for LF terminated lines. This works
     328             :  * around a bug in internet explorer for the macintosh which sends mime
     329             :  * boundaries that are only LF terminated when you use an image submit
     330             :  * button in a multipart/form-data form.
     331             :  */
     332         534 : static char *next_line(multipart_buffer *self)
     333             : {
     334             :         /* look for LF in the data */
     335         534 :         char* line = self->buf_begin;
     336         534 :         char* ptr = memchr(self->buf_begin, '\n', self->bytes_in_buffer);
     337             : 
     338         534 :         if (ptr) {      /* LF found */
     339             : 
     340             :                 /* terminate the string, remove CRLF */
     341         490 :                 if ((ptr - line) > 0 && *(ptr-1) == '\r') {
     342          20 :                         *(ptr-1) = 0;
     343             :                 } else {
     344         450 :                         *ptr = 0;
     345             :                 }
     346             : 
     347             :                 /* bump the pointer */
     348         470 :                 self->buf_begin = ptr + 1;
     349         470 :                 self->bytes_in_buffer -= (self->buf_begin - line);
     350             : 
     351             :         } else {        /* no LF found */
     352             : 
     353             :                 /* buffer isn't completely full, fail */
     354          64 :                 if (self->bytes_in_buffer < self->bufsize) {
     355          64 :                         return NULL;
     356             :                 }
     357             :                 /* return entire buffer as a partial line */
     358           0 :                 line[self->bufsize] = 0;
     359           0 :                 self->buf_begin = ptr;
     360           0 :                 self->bytes_in_buffer = 0;
     361             :         }
     362             : 
     363         470 :         return line;
     364             : }
     365             : 
     366             : /* Returns the next CRLF terminated line from the client */
     367         502 : static char *get_line(multipart_buffer *self)
     368             : {
     369         502 :         char* ptr = next_line(self);
     370             : 
     371         502 :         if (!ptr) {
     372          32 :                 fill_buffer(self);
     373          32 :                 ptr = next_line(self);
     374             :         }
     375             : 
     376         502 :         return ptr;
     377             : }
     378             : 
     379             : /* Free header entry */
     380         140 : static void php_free_hdr_entry(mime_header_entry *h)
     381             : {
     382         140 :         if (h->key) {
     383         140 :                 efree(h->key);
     384             :         }
     385         140 :         if (h->value) {
     386         140 :                 efree(h->value);
     387             :         }
     388         140 : }
     389             : 
     390             : /* finds a boundary */
     391         142 : static int find_boundary(multipart_buffer *self, char *boundary)
     392             : {
     393             :         char *line;
     394             : 
     395             :         /* loop thru lines */
     396         394 :         while( (line = get_line(self)) )
     397             :         {
     398             :                 /* finished if we found the boundary */
     399         220 :                 if (!strcmp(line, boundary)) {
     400         110 :                         return 1;
     401             :                 }
     402             :         }
     403             : 
     404             :         /* didn't find the boundary */
     405          32 :         return 0;
     406             : }
     407             : 
     408             : /* parse headers */
     409         142 : static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header)
     410             : {
     411             :         char *line;
     412         142 :         mime_header_entry entry = {0};
     413         142 :         smart_string buf_value = {0};
     414         142 :         char *key = NULL;
     415             : 
     416             :         /* didn't find boundary, abort */
     417         142 :         if (!find_boundary(self, self->boundary)) {
     418          32 :                 return 0;
     419             :         }
     420             : 
     421             :         /* get lines of text, or CRLF_CRLF */
     422             : 
     423         360 :         while ((line = get_line(self)) && line[0] != '\0') {
     424             :                 /* add header to table */
     425         140 :                 char *value = NULL;
     426             : 
     427         140 :                 if (php_rfc1867_encoding_translation()) {
     428           3 :                         self->input_encoding = zend_multibyte_encoding_detector((const unsigned char *) line, strlen(line), self->detect_order, self->detect_order_size);
     429             :                 }
     430             : 
     431             :                 /* space in the beginning means same header */
     432         140 :                 if (!isspace(line[0])) {
     433         140 :                         value = strchr(line, ':');
     434             :                 }
     435             : 
     436         140 :                 if (value) {
     437         140 :                         if (buf_value.c && key) {
     438             :                                 /* new entry, add the old one to the list */
     439          30 :                                 smart_string_0(&buf_value);
     440          30 :                                 entry.key = key;
     441          30 :                                 entry.value = buf_value.c;
     442          30 :                                 zend_llist_add_element(header, &entry);
     443          30 :                                 buf_value.c = NULL;
     444          30 :                                 key = NULL;
     445             :                         }
     446             : 
     447         140 :                         *value = '\0';
     448         280 :                         do { value++; } while (isspace(*value));
     449             : 
     450         140 :                         key = estrdup(line);
     451         140 :                         smart_string_appends(&buf_value, value);
     452           0 :                 } else if (buf_value.c) { /* If no ':' on the line, add to previous line */
     453           0 :                         smart_string_appends(&buf_value, line);
     454             :                 } else {
     455           0 :                         continue;
     456             :                 }
     457             :         }
     458             : 
     459         110 :         if (buf_value.c && key) {
     460             :                 /* add the last one to the list */
     461         110 :                 smart_string_0(&buf_value);
     462         110 :                 entry.key = key;
     463         110 :                 entry.value = buf_value.c;
     464         110 :                 zend_llist_add_element(header, &entry);
     465             :         }
     466             : 
     467         110 :         return 1;
     468             : }
     469             : 
     470         155 : static char *php_mime_get_hdr_value(zend_llist header, char *key)
     471             : {
     472             :         mime_header_entry *entry;
     473             : 
     474         155 :         if (key == NULL) {
     475           0 :                 return NULL;
     476             :         }
     477             : 
     478         155 :         entry = zend_llist_get_first(&header);
     479         355 :         while (entry) {
     480         174 :                 if (!strcasecmp(entry->key, key)) {
     481         129 :                         return entry->value;
     482             :                 }
     483          45 :                 entry = zend_llist_get_next(&header);
     484             :         }
     485             : 
     486          26 :         return NULL;
     487             : }
     488             : 
     489         428 : static char *php_ap_getword(const zend_encoding *encoding, char **line, char stop)
     490             : {
     491         428 :         char *pos = *line, quote;
     492             :         char *res;
     493             : 
     494        3893 :         while (*pos && *pos != stop) {
     495        3194 :                 if ((quote = *pos) == '"' || quote == '\'') {
     496         157 :                         ++pos;
     497        1637 :                         while (*pos && *pos != quote) {
     498        1325 :                                 if (*pos == '\\' && pos[1] && pos[1] == quote) {
     499           2 :                                         pos += 2;
     500             :                                 } else {
     501        1321 :                                         ++pos;
     502             :                                 }
     503             :                         }
     504         157 :                         if (*pos) {
     505         155 :                                 ++pos;
     506             :                         }
     507        2880 :                 } else ++pos;
     508             :         }
     509         428 :         if (*pos == '\0') {
     510         108 :                 res = estrdup(*line);
     511         108 :                 *line += strlen(*line);
     512         108 :                 return res;
     513             :         }
     514             : 
     515         320 :         res = estrndup(*line, pos - *line);
     516             : 
     517         960 :         while (*pos == stop) {
     518         320 :                 ++pos;
     519             :         }
     520             : 
     521         320 :         *line = pos;
     522         320 :         return res;
     523             : }
     524             : 
     525         160 : static char *substring_conf(char *start, int len, char quote)
     526             : {
     527         160 :         char *result = emalloc(len + 1);
     528         160 :         char *resp = result;
     529             :         int i;
     530             : 
     531        1510 :         for (i = 0; i < len && start[i] != quote; ++i) {
     532        1355 :                 if (start[i] == '\\' && (start[i + 1] == '\\' || (quote && start[i + 1] == quote))) {
     533           5 :                         *resp++ = start[++i];
     534             :                 } else {
     535        1345 :                         *resp++ = start[i];
     536             :                 }
     537             :         }
     538             : 
     539         160 :         *resp = '\0';
     540         160 :         return result;
     541             : }
     542             : 
     543         160 : static char *php_ap_getword_conf(const zend_encoding *encoding, char *str)
     544             : {
     545         320 :         while (*str && isspace(*str)) {
     546           0 :                 ++str;
     547             :         }
     548             : 
     549         160 :         if (!*str) {
     550           0 :                 return estrdup("");
     551             :         }
     552             : 
     553         160 :         if (*str == '"' || *str == '\'') {
     554         155 :                 char quote = *str;
     555             : 
     556         155 :                 str++;
     557         155 :                 return substring_conf(str, (int)strlen(str), quote);
     558             :         } else {
     559           5 :                 char *strend = str;
     560             : 
     561          42 :                 while (*strend && !isspace(*strend)) {
     562          32 :                         ++strend;
     563             :                 }
     564           5 :                 return substring_conf(str, strend - str, 0);
     565             :         }
     566             : }
     567             : 
     568          50 : static char *php_ap_basename(const zend_encoding *encoding, char *path)
     569             : {
     570          50 :         char *s = strrchr(path, '\\');
     571          50 :         char *s2 = strrchr(path, '/');
     572             : 
     573          50 :         if (s && s2) {
     574           1 :                 if (s > s2) {
     575           0 :                         ++s;
     576             :                 } else {
     577           1 :                         s = ++s2;
     578             :                 }
     579           1 :                 return s;
     580          49 :         } else if (s) {
     581           0 :                 return ++s;
     582          49 :         } else if (s2) {
     583           0 :                 return ++s2;
     584             :         }
     585          49 :         return path;
     586             : }
     587             : 
     588             : /*
     589             :  * Search for a string in a fixed-length byte string.
     590             :  * If partial is true, partial matches are allowed at the end of the buffer.
     591             :  * Returns NULL if not found, or a pointer to the start of the first match.
     592             :  */
     593         293 : static void *php_ap_memstr(char *haystack, int haystacklen, char *needle, int needlen, int partial)
     594             : {
     595         293 :         int len = haystacklen;
     596         293 :         char *ptr = haystack;
     597             : 
     598             :         /* iterate through first character matches */
     599         590 :         while( (ptr = memchr(ptr, needle[0], len)) ) {
     600             : 
     601             :                 /* calculate length after match */
     602         295 :                 len = haystacklen - (ptr - (char *)haystack);
     603             : 
     604             :                 /* done if matches up to capacity of buffer */
     605         295 :                 if (memcmp(needle, ptr, needlen < len ? needlen : len) == 0 && (partial || len >= needlen)) {
     606             :                         break;
     607             :                 }
     608             : 
     609             :                 /* next character */
     610           4 :                 ptr++; len--;
     611             :         }
     612             : 
     613         293 :         return ptr;
     614             : }
     615             : 
     616             : /* read until a boundary condition */
     617         200 : static int multipart_buffer_read(multipart_buffer *self, char *buf, size_t bytes, int *end)
     618             : {
     619             :         size_t len, max;
     620             :         char *bound;
     621             : 
     622             :         /* fill buffer if needed */
     623         200 :         if (bytes > self->bytes_in_buffer) {
     624         200 :                 fill_buffer(self);
     625             :         }
     626             : 
     627             :         /* look for a potential boundary match, only read data up to that point */
     628         200 :         if ((bound = php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 1))) {
     629         198 :                 max = bound - self->buf_begin;
     630         198 :                 if (end && php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 0)) {
     631          93 :                         *end = 1;
     632             :                 }
     633             :         } else {
     634           2 :                 max = self->bytes_in_buffer;
     635             :         }
     636             : 
     637             :         /* maximum number of bytes we are reading */
     638         200 :         len = max < bytes-1 ? max : bytes-1;
     639             : 
     640             :         /* if we read any data... */
     641         200 :         if (len > 0) {
     642             : 
     643             :                 /* copy the data */
     644         101 :                 memcpy(buf, self->buf_begin, len);
     645         101 :                 buf[len] = 0;
     646             : 
     647         101 :                 if (bound && len > 0 && buf[len-1] == '\r') {
     648           3 :                         buf[--len] = 0;
     649             :                 }
     650             : 
     651             :                 /* update the buffer */
     652         101 :                 self->bytes_in_buffer -= (int)len;
     653         101 :                 self->buf_begin += len;
     654             :         }
     655             : 
     656         200 :         return (int)len;
     657             : }
     658             : 
     659             : /*
     660             :   XXX: this is horrible memory-usage-wise, but we only expect
     661             :   to do this on small pieces of form data.
     662             : */
     663          53 : static char *multipart_buffer_read_body(multipart_buffer *self, size_t *len)
     664             : {
     665          53 :         char buf[FILLUNIT], *out=NULL;
     666          53 :         int total_bytes=0, read_bytes=0;
     667             : 
     668         158 :         while((read_bytes = multipart_buffer_read(self, buf, sizeof(buf), NULL))) {
     669          52 :                 out = erealloc(out, total_bytes + read_bytes + 1);
     670          52 :                 memcpy(out + total_bytes, buf, read_bytes);
     671          52 :                 total_bytes += read_bytes;
     672             :         }
     673             : 
     674          53 :         if (out) {
     675          52 :                 out[total_bytes] = '\0';
     676             :         }
     677          53 :         *len = total_bytes;
     678             : 
     679          53 :         return out;
     680             : }
     681             : /* }}} */
     682             : 
     683             : /*
     684             :  * The combined READER/HANDLER
     685             :  *
     686             :  */
     687             : 
     688          37 : SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
     689             : {
     690          37 :         char *boundary, *s = NULL, *boundary_end = NULL, *start_arr = NULL, *array_index = NULL;
     691          37 :         char *lbuf = NULL, *abuf = NULL;
     692          37 :         zend_string *temp_filename = NULL;
     693          37 :         int boundary_len = 0, cancel_upload = 0, is_arr_upload = 0, array_len = 0;
     694          37 :         int64_t total_bytes = 0, max_file_size = 0;
     695          37 :         int skip_upload = 0, anonindex = 0, is_anonymous;
     696          37 :         HashTable *uploaded_files = NULL;
     697             :         multipart_buffer *mbuff;
     698          37 :         zval *array_ptr = (zval *) arg;
     699          37 :         int fd = -1;
     700             :         zend_llist header;
     701          37 :         void *event_extra_data = NULL;
     702          37 :         unsigned int llen = 0;
     703          37 :         int upload_cnt = INI_INT("max_file_uploads");
     704          37 :         const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding();
     705             :         php_rfc1867_getword_t getword;
     706             :         php_rfc1867_getword_conf_t getword_conf;
     707             :         php_rfc1867_basename_t _basename;
     708          37 :         zend_long count = 0;
     709             : 
     710          38 :         if (php_rfc1867_encoding_translation() && internal_encoding) {
     711           1 :                 getword = php_rfc1867_getword;
     712           1 :                 getword_conf = php_rfc1867_getword_conf;
     713           1 :                 _basename = php_rfc1867_basename;
     714             :         } else {
     715          36 :                 getword = php_ap_getword;
     716          36 :                 getword_conf = php_ap_getword_conf;
     717          36 :                 _basename = php_ap_basename;
     718             :         }
     719             : 
     720          37 :         if (SG(post_max_size) > 0 && SG(request_info).content_length > SG(post_max_size)) {
     721           1 :                 sapi_module.sapi_error(E_WARNING, "POST Content-Length of " ZEND_LONG_FMT " bytes exceeds the limit of " ZEND_LONG_FMT " bytes", SG(request_info).content_length, SG(post_max_size));
     722           1 :                 return;
     723             :         }
     724             : 
     725             :         /* Get the boundary */
     726          36 :         boundary = strstr(content_type_dup, "boundary");
     727          36 :         if (!boundary) {
     728           1 :                 int content_type_len = (int)strlen(content_type_dup);
     729           1 :                 char *content_type_lcase = estrndup(content_type_dup, content_type_len);
     730             : 
     731           1 :                 php_strtolower(content_type_lcase, content_type_len);
     732           1 :                 boundary = strstr(content_type_lcase, "boundary");
     733           1 :                 if (boundary) {
     734           0 :                         boundary = content_type_dup + (boundary - content_type_lcase);
     735             :                 }
     736           1 :                 efree(content_type_lcase);
     737             :         }
     738             : 
     739          36 :         if (!boundary || !(boundary = strchr(boundary, '='))) {
     740           1 :                 sapi_module.sapi_error(E_WARNING, "Missing boundary in multipart/form-data POST data");
     741           1 :                 return;
     742             :         }
     743             : 
     744          35 :         boundary++;
     745          35 :         boundary_len = (int)strlen(boundary);
     746             : 
     747          35 :         if (boundary[0] == '"') {
     748           2 :                 boundary++;
     749           2 :                 boundary_end = strchr(boundary, '"');
     750           2 :                 if (!boundary_end) {
     751           1 :                         sapi_module.sapi_error(E_WARNING, "Invalid boundary in multipart/form-data POST data");
     752           1 :                         return;
     753             :                 }
     754             :         } else {
     755             :                 /* search for the end of the boundary */
     756          33 :                 boundary_end = strpbrk(boundary, ",;");
     757             :         }
     758          34 :         if (boundary_end) {
     759           5 :                 boundary_end[0] = '\0';
     760           5 :                 boundary_len = boundary_end-boundary;
     761             :         }
     762             : 
     763             :         /* Initialize the buffer */
     764          34 :         if (!(mbuff = multipart_buffer_new(boundary, boundary_len))) {
     765           0 :                 sapi_module.sapi_error(E_WARNING, "Unable to initialize the input buffer");
     766           0 :                 return;
     767             :         }
     768             : 
     769             :         /* Initialize $_FILES[] */
     770          34 :         zend_hash_init(&PG(rfc1867_protected_variables), 8, NULL, NULL, 0);
     771             : 
     772          34 :         ALLOC_HASHTABLE(uploaded_files);
     773          34 :         zend_hash_init(uploaded_files, 8, NULL, free_filename, 0);
     774          34 :         SG(rfc1867_uploaded_files) = uploaded_files;
     775             : 
     776          34 :         if (Z_TYPE(PG(http_globals)[TRACK_VARS_FILES]) != IS_ARRAY) {
     777             :                 /* php_auto_globals_create_files() might have already done that */
     778          34 :                 array_init(&PG(http_globals)[TRACK_VARS_FILES]);
     779             :         }
     780             : 
     781          34 :         zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0);
     782             : 
     783          34 :         if (php_rfc1867_callback != NULL) {
     784             :                 multipart_event_start event_start;
     785             : 
     786          34 :                 event_start.content_length = SG(request_info).content_length;
     787          34 :                 if (php_rfc1867_callback(MULTIPART_EVENT_START, &event_start, &event_extra_data) == FAILURE) {
     788           0 :                         goto fileupload_done;
     789             :                 }
     790             :         }
     791             : 
     792         177 :         while (!multipart_buffer_eof(mbuff))
     793             :         {
     794             :                 char buff[FILLUNIT];
     795         142 :                 char *cd = NULL, *param = NULL, *filename = NULL, *tmp = NULL;
     796         142 :                 size_t blen = 0, wlen = 0;
     797             :                 zend_off_t offset;
     798             : 
     799         142 :                 zend_llist_clean(&header);
     800             : 
     801         142 :                 if (!multipart_buffer_headers(mbuff, &header)) {
     802          32 :                         goto fileupload_done;
     803             :                 }
     804             : 
     805         110 :                 if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) {
     806         110 :                         char *pair = NULL;
     807         110 :                         int end = 0;
     808             : 
     809         220 :                         while (isspace(*cd)) {
     810           0 :                                 ++cd;
     811             :                         }
     812             : 
     813         493 :                         while (*cd && (pair = getword(mbuff->input_encoding, &cd, ';')))
     814             :                         {
     815         273 :                                 char *key = NULL, *word = pair;
     816             : 
     817         709 :                                 while (isspace(*cd)) {
     818         163 :                                         ++cd;
     819             :                                 }
     820             : 
     821         273 :                                 if (strchr(pair, '=')) {
     822         163 :                                         key = getword(mbuff->input_encoding, &pair, '=');
     823             : 
     824         163 :                                         if (!strcasecmp(key, "name")) {
     825         107 :                                                 if (param) {
     826           0 :                                                         efree(param);
     827             :                                                 }
     828         107 :                                                 param = getword_conf(mbuff->input_encoding, pair);
     829         107 :                                                 if (mbuff->input_encoding && internal_encoding) {
     830             :                                                         unsigned char *new_param;
     831             :                                                         size_t new_param_len;
     832           2 :                                                         if ((size_t)-1 != zend_multibyte_encoding_converter(&new_param, &new_param_len, (unsigned char *)param, strlen(param), internal_encoding, mbuff->input_encoding)) {
     833           2 :                                                                 efree(param);
     834           2 :                                                                 param = (char *)new_param;
     835             :                                                         }
     836             :                                                 }
     837          56 :                                         } else if (!strcasecmp(key, "filename")) {
     838          56 :                                                 if (filename) {
     839           0 :                                                         efree(filename);
     840             :                                                 }
     841          56 :                                                 filename = getword_conf(mbuff->input_encoding, pair);
     842          56 :                                                 if (mbuff->input_encoding && internal_encoding) {
     843             :                                                         unsigned char *new_filename;
     844             :                                                         size_t new_filename_len;
     845           1 :                                                         if ((size_t)-1 != zend_multibyte_encoding_converter(&new_filename, &new_filename_len, (unsigned char *)filename, strlen(filename), internal_encoding, mbuff->input_encoding)) {
     846           1 :                                                                 efree(filename);
     847           1 :                                                                 filename = (char *)new_filename;
     848             :                                                         }
     849             :                                                 }
     850             :                                         }
     851             :                                 }
     852         273 :                                 if (key) {
     853         163 :                                         efree(key);
     854             :                                 }
     855         273 :                                 efree(word);
     856             :                         }
     857             : 
     858             :                         /* Normal form variable, safe to read all data into memory */
     859         110 :                         if (!filename && param) {
     860             :                                 size_t value_len;
     861          53 :                                 char *value = multipart_buffer_read_body(mbuff, &value_len);
     862             :                                 size_t new_val_len; /* Dummy variable */
     863             : 
     864          53 :                                 if (!value) {
     865           1 :                                         value = estrdup("");
     866           1 :                                         value_len = 0;
     867             :                                 }
     868             : 
     869          53 :                                 if (mbuff->input_encoding && internal_encoding) {
     870             :                                         unsigned char *new_value;
     871             :                                         size_t new_value_len;
     872           1 :                                         if ((size_t)-1 != zend_multibyte_encoding_converter(&new_value, &new_value_len, (unsigned char *)value, value_len, internal_encoding, mbuff->input_encoding)) {
     873           1 :                                                 efree(value);
     874           1 :                                                 value = (char *)new_value;
     875           1 :                                                 value_len = new_value_len;
     876             :                                         }
     877             :                                 }
     878             : 
     879          53 :                                 if (++count <= PG(max_input_vars) && sapi_module.input_filter(PARSE_POST, param, &value, value_len, &new_val_len)) {
     880           0 :                                         if (php_rfc1867_callback != NULL) {
     881             :                                                 multipart_event_formdata event_formdata;
     882           0 :                                                 size_t newlength = new_val_len;
     883             : 
     884           0 :                                                 event_formdata.post_bytes_processed = SG(read_post_bytes);
     885           0 :                                                 event_formdata.name = param;
     886           0 :                                                 event_formdata.value = &value;
     887           0 :                                                 event_formdata.length = new_val_len;
     888           0 :                                                 event_formdata.newlength = &newlength;
     889           0 :                                                 if (php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data) == FAILURE) {
     890           0 :                                                         efree(param);
     891           0 :                                                         efree(value);
     892           0 :                                                         continue;
     893             :                                                 }
     894           0 :                                                 new_val_len = newlength;
     895             :                                         }
     896           0 :                                         safe_php_register_variable(param, value, new_val_len, array_ptr, 0);
     897             :                                 } else {
     898          53 :                                         if (count == PG(max_input_vars) + 1) {
     899           0 :                                                 php_error_docref(NULL, E_WARNING, "Input variables exceeded " ZEND_LONG_FMT ". To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
     900             :                                         }
     901             : 
     902          53 :                                         if (php_rfc1867_callback != NULL) {
     903             :                                                 multipart_event_formdata event_formdata;
     904             : 
     905          53 :                                                 event_formdata.post_bytes_processed = SG(read_post_bytes);
     906          53 :                                                 event_formdata.name = param;
     907          53 :                                                 event_formdata.value = &value;
     908          53 :                                                 event_formdata.length = value_len;
     909          53 :                                                 event_formdata.newlength = NULL;
     910          53 :                                                 php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data);
     911             :                                         }
     912             :                                 }
     913             : 
     914          53 :                                 if (!strcasecmp(param, "MAX_FILE_SIZE")) {
     915             : #ifdef HAVE_ATOLL
     916           1 :                                         max_file_size = atoll(value);
     917             : #else
     918             :                                         max_file_size = strtoll(value, NULL, 10);
     919             : #endif
     920             :                                 }
     921             : 
     922          53 :                                 efree(param);
     923          53 :                                 efree(value);
     924          53 :                                 continue;
     925             :                         }
     926             : 
     927             :                         /* If file_uploads=off, skip the file part */
     928          57 :                         if (!PG(file_uploads)) {
     929           1 :                                 skip_upload = 1;
     930          56 :                         } else if (upload_cnt <= 0) {
     931           0 :                                 skip_upload = 1;
     932           0 :                                 sapi_module.sapi_error(E_WARNING, "Maximum number of allowable file uploads has been exceeded");
     933             :                         }
     934             : 
     935             :                         /* Return with an error if the posted data is garbled */
     936          57 :                         if (!param && !filename) {
     937           1 :                                 sapi_module.sapi_error(E_WARNING, "File Upload Mime headers garbled");
     938           1 :                                 goto fileupload_done;
     939             :                         }
     940             : 
     941          56 :                         if (!param) {
     942           2 :                                 is_anonymous = 1;
     943           2 :                                 param = emalloc(MAX_SIZE_ANONNAME);
     944           2 :                                 snprintf(param, MAX_SIZE_ANONNAME, "%u", anonindex++);
     945             :                         } else {
     946          54 :                                 is_anonymous = 0;
     947             :                         }
     948             : 
     949             :                         /* New Rule: never repair potential malicious user input */
     950          56 :                         if (!skip_upload) {
     951          53 :                                 long c = 0;
     952          53 :                                 tmp = param;
     953             : 
     954         370 :                                 while (*tmp) {
     955         265 :                                         if (*tmp == '[') {
     956           7 :                                                 c++;
     957         258 :                                         } else if (*tmp == ']') {
     958           6 :                                                 c--;
     959           6 :                                                 if (tmp[1] && tmp[1] != '[') {
     960           1 :                                                         skip_upload = 1;
     961           1 :                                                         break;
     962             :                                                 }
     963             :                                         }
     964         264 :                                         if (c < 0) {
     965           0 :                                                 skip_upload = 1;
     966           0 :                                                 break;
     967             :                                         }
     968         264 :                                         tmp++;
     969             :                                 }
     970             :                                 /* Brackets should always be closed */
     971          53 :                                 if(c != 0) {
     972           1 :                                         skip_upload = 1;
     973             :                                 }
     974             :                         }
     975             : 
     976          56 :                         total_bytes = cancel_upload = 0;
     977          56 :                         temp_filename = NULL;
     978          56 :                         fd = -1;
     979             : 
     980          56 :                         if (!skip_upload && php_rfc1867_callback != NULL) {
     981             :                                 multipart_event_file_start event_file_start;
     982             : 
     983          51 :                                 event_file_start.post_bytes_processed = SG(read_post_bytes);
     984          51 :                                 event_file_start.name = param;
     985          51 :                                 event_file_start.filename = &filename;
     986          51 :                                 if (php_rfc1867_callback(MULTIPART_EVENT_FILE_START, &event_file_start, &event_extra_data) == FAILURE) {
     987           0 :                                         temp_filename = NULL;
     988           0 :                                         efree(param);
     989           0 :                                         efree(filename);
     990           0 :                                         continue;
     991             :                                 }
     992             :                         }
     993             : 
     994          56 :                         if (skip_upload) {
     995           5 :                                 efree(param);
     996           5 :                                 efree(filename);
     997           5 :                                 continue;
     998             :                         }
     999             : 
    1000          51 :                         if (filename[0] == '\0') {
    1001             : #if DEBUG_FILE_UPLOAD
    1002             :                                 sapi_module.sapi_error(E_NOTICE, "No file uploaded");
    1003             : #endif
    1004           3 :                                 cancel_upload = UPLOAD_ERROR_D;
    1005             :                         }
    1006             : 
    1007          51 :                         offset = 0;
    1008          51 :                         end = 0;
    1009             : 
    1010          51 :                         if (!cancel_upload) {
    1011             :                                 /* only bother to open temp file if we have data */
    1012          48 :                                 blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end);
    1013             : #if DEBUG_FILE_UPLOAD
    1014             :                                 if (blen > 0) {
    1015             : #else
    1016             :                                 /* in non-debug mode we have no problem with 0-length files */
    1017             :                                 {
    1018             : #endif
    1019          48 :                                         fd = php_open_temporary_fd_ex(PG(upload_tmp_dir), "php", &temp_filename, 1);
    1020          48 :                                         upload_cnt--;
    1021          48 :                                         if (fd == -1) {
    1022           0 :                                                 sapi_module.sapi_error(E_WARNING, "File upload error - unable to create a temporary file");
    1023           0 :                                                 cancel_upload = UPLOAD_ERROR_E;
    1024             :                                         }
    1025             :                                 }
    1026             :                         }
    1027             : 
    1028         149 :                         while (!cancel_upload && (blen > 0))
    1029             :                         {
    1030          47 :                                 if (php_rfc1867_callback != NULL) {
    1031             :                                         multipart_event_file_data event_file_data;
    1032             : 
    1033          47 :                                         event_file_data.post_bytes_processed = SG(read_post_bytes);
    1034          47 :                                         event_file_data.offset = offset;
    1035          47 :                                         event_file_data.data = buff;
    1036          47 :                                         event_file_data.length = blen;
    1037          47 :                                         event_file_data.newlength = &blen;
    1038          47 :                                         if (php_rfc1867_callback(MULTIPART_EVENT_FILE_DATA, &event_file_data, &event_extra_data) == FAILURE) {
    1039           0 :                                                 cancel_upload = UPLOAD_ERROR_X;
    1040           0 :                                                 continue;
    1041             :                                         }
    1042             :                                 }
    1043             : 
    1044          48 :                                 if (PG(upload_max_filesize) > 0 && (zend_long)(total_bytes+blen) > PG(upload_max_filesize)) {
    1045             : #if DEBUG_FILE_UPLOAD
    1046             :                                         sapi_module.sapi_error(E_NOTICE, "upload_max_filesize of " ZEND_LONG_FMT " bytes exceeded - file [%s=%s] not saved", PG(upload_max_filesize), param, filename);
    1047             : #endif
    1048           1 :                                         cancel_upload = UPLOAD_ERROR_A;
    1049          47 :                                 } else if (max_file_size && ((zend_long)(total_bytes+blen) > max_file_size)) {
    1050             : #if DEBUG_FILE_UPLOAD
    1051             :                                         sapi_module.sapi_error(E_NOTICE, "MAX_FILE_SIZE of " ZEND_LONG_FMT " bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename);
    1052             : #endif
    1053           1 :                                         cancel_upload = UPLOAD_ERROR_B;
    1054          45 :                                 } else if (blen > 0) {
    1055             : #ifdef PHP_WIN32
    1056             :                                         wlen = write(fd, buff, (unsigned int)blen);
    1057             : #else
    1058          45 :                                         wlen = write(fd, buff, blen);
    1059             : #endif
    1060             : 
    1061          45 :                                         if (wlen == -1) {
    1062             :                                                 /* write failed */
    1063             : #if DEBUG_FILE_UPLOAD
    1064             :                                                 sapi_module.sapi_error(E_NOTICE, "write() failed - %s", strerror(errno));
    1065             : #endif
    1066           0 :                                                 cancel_upload = UPLOAD_ERROR_F;
    1067          45 :                                         } else if (wlen < blen) {
    1068             : #if DEBUG_FILE_UPLOAD
    1069             :                                                 sapi_module.sapi_error(E_NOTICE, "Only %d bytes were written, expected to write %d", wlen, blen);
    1070             : #endif
    1071           0 :                                                 cancel_upload = UPLOAD_ERROR_F;
    1072             :                                         } else {
    1073          45 :                                                 total_bytes += wlen;
    1074             :                                         }
    1075          45 :                                         offset += wlen;
    1076             :                                 }
    1077             : 
    1078             :                                 /* read data for next iteration */
    1079          47 :                                 blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end);
    1080             :                         }
    1081             : 
    1082          51 :                         if (fd != -1) { /* may not be initialized if file could not be created */
    1083          48 :                                 close(fd);
    1084             :                         }
    1085             : 
    1086          51 :                         if (!cancel_upload && !end) {
    1087             : #if DEBUG_FILE_UPLOAD
    1088             :                                 sapi_module.sapi_error(E_NOTICE, "Missing mime boundary at the end of the data for file %s", filename[0] != '\0' ? filename : "");
    1089             : #endif
    1090           1 :                                 cancel_upload = UPLOAD_ERROR_C;
    1091             :                         }
    1092             : #if DEBUG_FILE_UPLOAD
    1093             :                         if (filename[0] != '\0' && total_bytes == 0 && !cancel_upload) {
    1094             :                                 sapi_module.sapi_error(E_WARNING, "Uploaded file size 0 - file [%s=%s] not saved", param, filename);
    1095             :                                 cancel_upload = 5;
    1096             :                         }
    1097             : #endif
    1098          51 :                         if (php_rfc1867_callback != NULL) {
    1099             :                                 multipart_event_file_end event_file_end;
    1100             : 
    1101          51 :                                 event_file_end.post_bytes_processed = SG(read_post_bytes);
    1102          51 :                                 event_file_end.temp_filename = temp_filename->val;
    1103          51 :                                 event_file_end.cancel_upload = cancel_upload;
    1104          51 :                                 if (php_rfc1867_callback(MULTIPART_EVENT_FILE_END, &event_file_end, &event_extra_data) == FAILURE) {
    1105           0 :                                         cancel_upload = UPLOAD_ERROR_X;
    1106             :                                 }
    1107             :                         }
    1108             : 
    1109          51 :                         if (cancel_upload) {
    1110           6 :                                 if (temp_filename) {
    1111           3 :                                         if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */
    1112           3 :                                                 unlink(temp_filename->val);
    1113             :                                         }
    1114           3 :                                         zend_string_release(temp_filename);
    1115             :                                 }
    1116           6 :                                 temp_filename = NULL;
    1117             :                         } else {
    1118          45 :                                 zend_hash_add_ptr(SG(rfc1867_uploaded_files), temp_filename, temp_filename);
    1119             :                         }
    1120             : 
    1121             :                         /* is_arr_upload is true when name of file upload field
    1122             :                          * ends in [.*]
    1123             :                          * start_arr is set to point to 1st [ */
    1124          51 :                         is_arr_upload = (start_arr = strchr(param,'[')) && (param[strlen(param)-1] == ']');
    1125             : 
    1126          51 :                         if (is_arr_upload) {
    1127           4 :                                 array_len = (int)strlen(start_arr);
    1128           4 :                                 if (array_index) {
    1129           2 :                                         efree(array_index);
    1130             :                                 }
    1131           4 :                                 array_index = estrndup(start_arr + 1, array_len - 2);
    1132             :                         }
    1133             : 
    1134             :                         /* Add $foo_name */
    1135          51 :                         if (llen < strlen(param) + MAX_SIZE_OF_INDEX + 1) {
    1136          26 :                                 llen = (int)strlen(param);
    1137          26 :                                 lbuf = (char *) safe_erealloc(lbuf, llen, 1, MAX_SIZE_OF_INDEX + 1);
    1138          26 :                                 llen += MAX_SIZE_OF_INDEX + 1;
    1139             :                         }
    1140             : 
    1141          51 :                         if (is_arr_upload) {
    1142           4 :                                 if (abuf) efree(abuf);
    1143           4 :                                 abuf = estrndup(param, strlen(param)-array_len);
    1144           4 :                                 snprintf(lbuf, llen, "%s_name[%s]", abuf, array_index);
    1145             :                         } else {
    1146          47 :                                 snprintf(lbuf, llen, "%s_name", param);
    1147             :                         }
    1148             : 
    1149             :                         /* The \ check should technically be needed for win32 systems only where
    1150             :                          * it is a valid path separator. However, IE in all it's wisdom always sends
    1151             :                          * the full path of the file on the user's filesystem, which means that unless
    1152             :                          * the user does basename() they get a bogus file name. Until IE's user base drops
    1153             :                          * to nill or problem is fixed this code must remain enabled for all systems. */
    1154          51 :                         s = _basename(internal_encoding, filename);
    1155          51 :                         if (!s) {
    1156           0 :                                 s = filename;
    1157             :                         }
    1158             : 
    1159          51 :                         if (!is_anonymous) {
    1160          49 :                                 safe_php_register_variable(lbuf, s, strlen(s), NULL, 0);
    1161             :                         }
    1162             : 
    1163             :                         /* Add $foo[name] */
    1164          51 :                         if (is_arr_upload) {
    1165           4 :                                 snprintf(lbuf, llen, "%s[name][%s]", abuf, array_index);
    1166             :                         } else {
    1167          47 :                                 snprintf(lbuf, llen, "%s[name]", param);
    1168             :                         }
    1169          51 :                         register_http_post_files_variable(lbuf, s, &PG(http_globals)[TRACK_VARS_FILES], 0);
    1170          51 :                         efree(filename);
    1171          51 :                         s = NULL;
    1172             : 
    1173             :                         /* Possible Content-Type: */
    1174          83 :                         if (cancel_upload || !(cd = php_mime_get_hdr_value(header, "Content-Type"))) {
    1175          32 :                                 cd = "";
    1176             :                         } else {
    1177             :                                 /* fix for Opera 6.01 */
    1178          19 :                                 s = strchr(cd, ';');
    1179          19 :                                 if (s != NULL) {
    1180           1 :                                         *s = '\0';
    1181             :                                 }
    1182             :                         }
    1183             : 
    1184             :                         /* Add $foo_type */
    1185          51 :                         if (is_arr_upload) {
    1186           4 :                                 snprintf(lbuf, llen, "%s_type[%s]", abuf, array_index);
    1187             :                         } else {
    1188          47 :                                 snprintf(lbuf, llen, "%s_type", param);
    1189             :                         }
    1190          51 :                         if (!is_anonymous) {
    1191          49 :                                 safe_php_register_variable(lbuf, cd, strlen(cd), NULL, 0);
    1192             :                         }
    1193             : 
    1194             :                         /* Add $foo[type] */
    1195          51 :                         if (is_arr_upload) {
    1196           4 :                                 snprintf(lbuf, llen, "%s[type][%s]", abuf, array_index);
    1197             :                         } else {
    1198          47 :                                 snprintf(lbuf, llen, "%s[type]", param);
    1199             :                         }
    1200          51 :                         register_http_post_files_variable(lbuf, cd, &PG(http_globals)[TRACK_VARS_FILES], 0);
    1201             : 
    1202             :                         /* Restore Content-Type Header */
    1203          51 :                         if (s != NULL) {
    1204           1 :                                 *s = ';';
    1205             :                         }
    1206          51 :                         s = "";
    1207             : 
    1208             :                         {
    1209             :                                 /* store temp_filename as-is (in case upload_tmp_dir
    1210             :                                  * contains escapeable characters. escape only the variable name.) */
    1211             :                                 zval zfilename;
    1212             : 
    1213             :                                 /* Initialize variables */
    1214          51 :                                 add_protected_variable(param);
    1215             : 
    1216             :                                 /* if param is of form xxx[.*] this will cut it to xxx */
    1217          51 :                                 if (!is_anonymous) {
    1218          49 :                                         if (temp_filename) {
    1219          43 :                                                 ZVAL_STR_COPY(&zfilename, temp_filename);
    1220             :                                         } else {
    1221           6 :                                                 ZVAL_EMPTY_STRING(&zfilename);
    1222             :                                         }
    1223          49 :                                         safe_php_register_variable_ex(param, &zfilename, NULL, 1);
    1224             :                                 }
    1225             : 
    1226             :                                 /* Add $foo[tmp_name] */
    1227          51 :                                 if (is_arr_upload) {
    1228           4 :                                         snprintf(lbuf, llen, "%s[tmp_name][%s]", abuf, array_index);
    1229             :                                 } else {
    1230          47 :                                         snprintf(lbuf, llen, "%s[tmp_name]", param);
    1231             :                                 }
    1232          51 :                                 add_protected_variable(lbuf);
    1233          51 :                                 if (temp_filename) {
    1234          45 :                                         ZVAL_STR_COPY(&zfilename, temp_filename);
    1235             :                                 } else {
    1236           6 :                                         ZVAL_EMPTY_STRING(&zfilename);
    1237             :                                 }
    1238          51 :                                 register_http_post_files_variable_ex(lbuf, &zfilename, &PG(http_globals)[TRACK_VARS_FILES], 1);
    1239             :                         }
    1240             : 
    1241             :                         {
    1242             :                                 zval file_size, error_type;
    1243          51 :                                 int size_overflow = 0;
    1244             :                                 char file_size_buf[65];
    1245             : 
    1246          51 :                                 ZVAL_LONG(&error_type, cancel_upload);
    1247             : 
    1248             :                                 /* Add $foo[error] */
    1249          51 :                                 if (cancel_upload) {
    1250           6 :                                         ZVAL_LONG(&file_size, 0);
    1251             :                                 } else {
    1252          45 :                                         if (total_bytes > ZEND_LONG_MAX) {
    1253             : #ifdef PHP_WIN32
    1254             :                                                 if (_i64toa_s(total_bytes, file_size_buf, 65, 10)) {
    1255             :                                                         file_size_buf[0] = '0';
    1256             :                                                         file_size_buf[1] = '\0';
    1257             :                                                 }
    1258             : #else
    1259             :                                                 {
    1260             :                                                         int __len = snprintf(file_size_buf, 65, "%lld", total_bytes);
    1261             :                                                         file_size_buf[__len] = '\0';
    1262             :                                                 }
    1263             : #endif
    1264             :                                                 size_overflow = 1;
    1265             : 
    1266             :                                         } else {
    1267          45 :                                                 ZVAL_LONG(&file_size, total_bytes);
    1268             :                                         }
    1269             :                                 }
    1270             : 
    1271          51 :                                 if (is_arr_upload) {
    1272           4 :                                         snprintf(lbuf, llen, "%s[error][%s]", abuf, array_index);
    1273             :                                 } else {
    1274          47 :                                         snprintf(lbuf, llen, "%s[error]", param);
    1275             :                                 }
    1276          51 :                                 register_http_post_files_variable_ex(lbuf, &error_type, &PG(http_globals)[TRACK_VARS_FILES], 0);
    1277             : 
    1278             :                                 /* Add $foo_size */
    1279          51 :                                 if (is_arr_upload) {
    1280           4 :                                         snprintf(lbuf, llen, "%s_size[%s]", abuf, array_index);
    1281             :                                 } else {
    1282          47 :                                         snprintf(lbuf, llen, "%s_size", param);
    1283             :                                 }
    1284          51 :                                 if (!is_anonymous) {
    1285          49 :                                         if (size_overflow) {
    1286           0 :                                                 ZVAL_STRING(&file_size, file_size_buf);
    1287             :                                         }
    1288          49 :                                         safe_php_register_variable_ex(lbuf, &file_size, NULL, size_overflow);
    1289             :                                 }
    1290             : 
    1291             :                                 /* Add $foo[size] */
    1292          51 :                                 if (is_arr_upload) {
    1293           4 :                                         snprintf(lbuf, llen, "%s[size][%s]", abuf, array_index);
    1294             :                                 } else {
    1295          47 :                                         snprintf(lbuf, llen, "%s[size]", param);
    1296             :                                 }
    1297          51 :                                 if (size_overflow) {
    1298           0 :                                         ZVAL_STRING(&file_size, file_size_buf);
    1299             :                                 }
    1300          51 :                                 register_http_post_files_variable_ex(lbuf, &file_size, &PG(http_globals)[TRACK_VARS_FILES], size_overflow);
    1301             :                         }
    1302          51 :                         efree(param);
    1303             :                 }
    1304             :         }
    1305             : 
    1306             : fileupload_done:
    1307          34 :         if (php_rfc1867_callback != NULL) {
    1308             :                 multipart_event_end event_end;
    1309             : 
    1310          34 :                 event_end.post_bytes_processed = SG(read_post_bytes);
    1311          34 :                 php_rfc1867_callback(MULTIPART_EVENT_END, &event_end, &event_extra_data);
    1312             :         }
    1313             : 
    1314          34 :         if (lbuf) efree(lbuf);
    1315          34 :         if (abuf) efree(abuf);
    1316          34 :         if (array_index) efree(array_index);
    1317          34 :         zend_hash_destroy(&PG(rfc1867_protected_variables));
    1318          34 :         zend_llist_destroy(&header);
    1319          34 :         if (mbuff->boundary_next) efree(mbuff->boundary_next);
    1320          34 :         if (mbuff->boundary) efree(mbuff->boundary);
    1321          34 :         if (mbuff->buffer) efree(mbuff->buffer);
    1322          34 :         if (mbuff) efree(mbuff);
    1323             : }
    1324             : /* }}} */
    1325             : 
    1326       21049 : SAPI_API void php_rfc1867_set_multibyte_callbacks(
    1327             :                                         php_rfc1867_encoding_translation_t encoding_translation,
    1328             :                                         php_rfc1867_get_detect_order_t get_detect_order,
    1329             :                                         php_rfc1867_set_input_encoding_t set_input_encoding,
    1330             :                                         php_rfc1867_getword_t getword,
    1331             :                                         php_rfc1867_getword_conf_t getword_conf,
    1332             :                                         php_rfc1867_basename_t basename) /* {{{ */
    1333             : {
    1334       21049 :         php_rfc1867_encoding_translation = encoding_translation;
    1335       21049 :         php_rfc1867_get_detect_order = get_detect_order;
    1336       21049 :         php_rfc1867_set_input_encoding = set_input_encoding;
    1337       21049 :         php_rfc1867_getword = getword;
    1338       21049 :         php_rfc1867_getword_conf = getword_conf;
    1339       21049 :         php_rfc1867_basename = basename;
    1340       21049 : }
    1341             : /* }}} */
    1342             : 
    1343             : /*
    1344             :  * Local variables:
    1345             :  * tab-width: 4
    1346             :  * c-basic-offset: 4
    1347             :  * End:
    1348             :  * vim600: sw=4 ts=4 fdm=marker
    1349             :  * vim<600: sw=4 ts=4
    1350             :  */

Generated by: LCOV version 1.10

Generated at Sun, 05 Jul 2015 15:45:02 +0000 (45 hours ago)

Copyright © 2005-2015 The PHP Group
All rights reserved.