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

Generated by: LCOV version 1.10

Generated at Tue, 22 Jul 2014 01:33:25 +0000 (10 days ago)

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