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: 533 597 89.3 %
Date: 2014-07-25 Functions: 28 29 96.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Fri, 25 Jul 2014 16:54:34 +0000 (8 hours ago)

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