Back to index

php5  5.3.10
rfc1867.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Rasmus Lerdorf <rasmus@php.net>                             |
00016    |          Jani Taskinen <jani@php.net>                                |
00017    +----------------------------------------------------------------------+
00018  */
00019 
00020 /* $Id: rfc1867.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 /*
00023  *  This product includes software developed by the Apache Group
00024  *  for use in the Apache HTTP server project (http://www.apache.org/).
00025  *
00026  */
00027 
00028 #include <stdio.h>
00029 #include "php.h"
00030 #include "php_open_temporary_file.h"
00031 #include "zend_globals.h"
00032 #include "php_globals.h"
00033 #include "php_variables.h"
00034 #include "rfc1867.h"
00035 #include "ext/standard/php_string.h"
00036 
00037 #define DEBUG_FILE_UPLOAD ZEND_DEBUG
00038 
00039 PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra TSRMLS_DC) = NULL;
00040 
00041 #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
00042 #include "ext/mbstring/mbstring.h"
00043 
00044 static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC);
00045 
00046 #define SAFE_RETURN { \
00047        php_mb_flush_gpc_variables(num_vars, val_list, len_list, array_ptr TSRMLS_CC); \
00048        if (lbuf) efree(lbuf); \
00049        if (abuf) efree(abuf); \
00050        if (array_index) efree(array_index); \
00051        zend_hash_destroy(&PG(rfc1867_protected_variables)); \
00052        zend_llist_destroy(&header); \
00053        if (mbuff->boundary_next) efree(mbuff->boundary_next); \
00054        if (mbuff->boundary) efree(mbuff->boundary); \
00055        if (mbuff->buffer) efree(mbuff->buffer); \
00056        if (mbuff) efree(mbuff); \
00057        return; }
00058 
00059 void php_mb_flush_gpc_variables(int num_vars, char **val_list, int *len_list, zval *array_ptr  TSRMLS_DC) /* {{{ */
00060 {
00061        int i;
00062        if (php_mb_encoding_translation(TSRMLS_C)) {
00063               if (num_vars > 0 &&
00064                      php_mb_gpc_encoding_detector(val_list, len_list, num_vars, NULL TSRMLS_CC) == SUCCESS) {
00065                      php_mb_gpc_encoding_converter(val_list, len_list, num_vars, NULL, NULL TSRMLS_CC);
00066               }
00067               for (i = 0; i<num_vars; i += 2) {
00068                      safe_php_register_variable(val_list[i], val_list[i+1], len_list[i+1], array_ptr, 0 TSRMLS_CC);
00069                      efree(val_list[i]);
00070                      efree(val_list[i+1]);
00071               }
00072               efree(val_list);
00073               efree(len_list);
00074        }
00075 }
00076 /* }}} */
00077 
00078 void php_mb_gpc_realloc_buffer(char ***pval_list, int **plen_list, int *num_vars_max, int inc  TSRMLS_DC) /* {{{ */
00079 {
00080        /* allow only even increments */
00081        if (inc & 1) {
00082               inc++;
00083        }
00084        (*num_vars_max) += inc;
00085        *pval_list = (char **)erealloc(*pval_list, (*num_vars_max+2)*sizeof(char *));
00086        *plen_list = (int *)erealloc(*plen_list, (*num_vars_max+2)*sizeof(int));
00087 }
00088 /* }}} */
00089 
00090 void php_mb_gpc_stack_variable(char *param, char *value, char ***pval_list, int **plen_list, int *num_vars, int *num_vars_max TSRMLS_DC) /* {{{ */
00091 {
00092        char **val_list = *pval_list;
00093        int *len_list = *plen_list;
00094 
00095        if (*num_vars >= *num_vars_max) {
00096               php_mb_gpc_realloc_buffer(pval_list, plen_list, num_vars_max, 16 TSRMLS_CC);
00097               /* in case realloc relocated the buffer */
00098               val_list = *pval_list;
00099               len_list = *plen_list;
00100        }
00101 
00102        val_list[*num_vars] = (char *)estrdup(param);
00103        len_list[*num_vars] = strlen(param);
00104        (*num_vars)++;
00105        val_list[*num_vars] = (char *)estrdup(value);
00106        len_list[*num_vars] = strlen(value);
00107        (*num_vars)++;
00108 }
00109 /* }}} */
00110 
00111 #else
00112 
00113 #define SAFE_RETURN { \
00114        if (lbuf) efree(lbuf); \
00115        if (abuf) efree(abuf); \
00116        if (array_index) efree(array_index); \
00117        zend_hash_destroy(&PG(rfc1867_protected_variables)); \
00118        zend_llist_destroy(&header); \
00119        if (mbuff->boundary_next) efree(mbuff->boundary_next); \
00120        if (mbuff->boundary) efree(mbuff->boundary); \
00121        if (mbuff->buffer) efree(mbuff->buffer); \
00122        if (mbuff) efree(mbuff); \
00123        return; }
00124 #endif
00125 
00126 /* The longest property name we use in an uploaded file array */
00127 #define MAX_SIZE_OF_INDEX sizeof("[tmp_name]")
00128 
00129 /* The longest anonymous name */
00130 #define MAX_SIZE_ANONNAME 33
00131 
00132 /* Errors */
00133 #define UPLOAD_ERROR_OK   0  /* File upload succesful */
00134 #define UPLOAD_ERROR_A    1  /* Uploaded file exceeded upload_max_filesize */
00135 #define UPLOAD_ERROR_B    2  /* Uploaded file exceeded MAX_FILE_SIZE */
00136 #define UPLOAD_ERROR_C    3  /* Partially uploaded */
00137 #define UPLOAD_ERROR_D    4  /* No file uploaded */
00138 #define UPLOAD_ERROR_E    6  /* Missing /tmp or similar directory */
00139 #define UPLOAD_ERROR_F    7  /* Failed to write file to disk */
00140 #define UPLOAD_ERROR_X    8  /* File upload stopped by extension */
00141 
00142 void php_rfc1867_register_constants(TSRMLS_D) /* {{{ */
00143 {
00144        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_OK",         UPLOAD_ERROR_OK, CONST_CS | CONST_PERSISTENT);
00145        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_INI_SIZE",   UPLOAD_ERROR_A,  CONST_CS | CONST_PERSISTENT);
00146        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FORM_SIZE",  UPLOAD_ERROR_B,  CONST_CS | CONST_PERSISTENT);
00147        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL",    UPLOAD_ERROR_C,  CONST_CS | CONST_PERSISTENT);
00148        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE",    UPLOAD_ERROR_D,  CONST_CS | CONST_PERSISTENT);
00149        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E,  CONST_CS | CONST_PERSISTENT);
00150        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_CANT_WRITE", UPLOAD_ERROR_F,  CONST_CS | CONST_PERSISTENT);
00151        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_EXTENSION",  UPLOAD_ERROR_X,  CONST_CS | CONST_PERSISTENT);
00152 }
00153 /* }}} */
00154 
00155 static void normalize_protected_variable(char *varname TSRMLS_DC) /* {{{ */
00156 {
00157        char *s = varname, *index = NULL, *indexend = NULL, *p;
00158 
00159        /* overjump leading space */
00160        while (*s == ' ') {
00161               s++;
00162        }
00163 
00164        /* and remove it */
00165        if (s != varname) {
00166               memmove(varname, s, strlen(s)+1);
00167        }
00168 
00169        for (p = varname; *p && *p != '['; p++) {
00170               switch(*p) {
00171                      case ' ':
00172                      case '.':
00173                             *p = '_';
00174                             break;
00175               }
00176        }
00177 
00178        /* find index */
00179        index = strchr(varname, '[');
00180        if (index) {
00181               index++;
00182               s = index;
00183        } else {
00184               return;
00185        }
00186 
00187        /* done? */
00188        while (index) {
00189               while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') {
00190                      index++;
00191               }
00192               indexend = strchr(index, ']');
00193               indexend = indexend ? indexend + 1 : index + strlen(index);
00194 
00195               if (s != index) {
00196                      memmove(s, index, strlen(index)+1);
00197                      s += indexend-index;
00198               } else {
00199                      s = indexend;
00200               }
00201 
00202               if (*s == '[') {
00203                      s++;
00204                      index = s;
00205               } else {
00206                      index = NULL;
00207               }
00208        }
00209        *s = '\0';
00210 }
00211 /* }}} */
00212 
00213 static void add_protected_variable(char *varname TSRMLS_DC) /* {{{ */
00214 {
00215        int dummy = 1;
00216 
00217        normalize_protected_variable(varname TSRMLS_CC);
00218        zend_hash_add(&PG(rfc1867_protected_variables), varname, strlen(varname)+1, &dummy, sizeof(int), NULL);
00219 }
00220 /* }}} */
00221 
00222 static zend_bool is_protected_variable(char *varname TSRMLS_DC) /* {{{ */
00223 {
00224        normalize_protected_variable(varname TSRMLS_CC);
00225        return zend_hash_exists(&PG(rfc1867_protected_variables), varname, strlen(varname)+1);
00226 }
00227 /* }}} */
00228 
00229 static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) /* {{{ */
00230 {
00231        if (override_protection || !is_protected_variable(var TSRMLS_CC)) {
00232               php_register_variable_safe(var, strval, val_len, track_vars_array TSRMLS_CC);
00233        }
00234 }
00235 /* }}} */
00236 
00237 static void safe_php_register_variable_ex(char *var, zval *val, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) /* {{{ */
00238 {
00239        if (override_protection || !is_protected_variable(var TSRMLS_CC)) {
00240               php_register_variable_ex(var, val, track_vars_array TSRMLS_CC);
00241        }
00242 }
00243 /* }}} */
00244 
00245 static void register_http_post_files_variable(char *strvar, char *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) /* {{{ */
00246 {
00247        int register_globals = PG(register_globals);
00248 
00249        PG(register_globals) = 0;
00250        safe_php_register_variable(strvar, val, strlen(val), http_post_files, override_protection TSRMLS_CC);
00251        PG(register_globals) = register_globals;
00252 }
00253 /* }}} */
00254 
00255 static void register_http_post_files_variable_ex(char *var, zval *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) /* {{{ */
00256 {
00257        int register_globals = PG(register_globals);
00258 
00259        PG(register_globals) = 0;
00260        safe_php_register_variable_ex(var, val, http_post_files, override_protection TSRMLS_CC);
00261        PG(register_globals) = register_globals;
00262 }
00263 /* }}} */
00264 
00265 static int unlink_filename(char **filename TSRMLS_DC) /* {{{ */
00266 {
00267        VCWD_UNLINK(*filename);
00268        return 0;
00269 }
00270 /* }}} */
00271 
00272 void destroy_uploaded_files_hash(TSRMLS_D) /* {{{ */
00273 {
00274        zend_hash_apply(SG(rfc1867_uploaded_files), (apply_func_t) unlink_filename TSRMLS_CC);
00275        zend_hash_destroy(SG(rfc1867_uploaded_files));
00276        FREE_HASHTABLE(SG(rfc1867_uploaded_files));
00277 }
00278 /* }}} */
00279 
00280 /* {{{ Following code is based on apache_multipart_buffer.c from libapreq-0.33 package. */
00281 
00282 #define FILLUNIT (1024 * 5)
00283 
00284 typedef struct {
00285 
00286        /* read buffer */
00287        char *buffer;
00288        char *buf_begin;
00289        int  bufsize;
00290        int  bytes_in_buffer;
00291 
00292        /* boundary info */
00293        char *boundary;
00294        char *boundary_next;
00295        int  boundary_next_len;
00296 
00297 } multipart_buffer;
00298 
00299 typedef struct {
00300        char *key;
00301        char *value;
00302 } mime_header_entry;
00303 
00304 /*
00305  * Fill up the buffer with client data.
00306  * Returns number of bytes added to buffer.
00307  */
00308 static int fill_buffer(multipart_buffer *self TSRMLS_DC)
00309 {
00310        int bytes_to_read, total_read = 0, actual_read = 0;
00311 
00312        /* shift the existing data if necessary */
00313        if (self->bytes_in_buffer > 0 && self->buf_begin != self->buffer) {
00314               memmove(self->buffer, self->buf_begin, self->bytes_in_buffer);
00315        }
00316 
00317        self->buf_begin = self->buffer;
00318 
00319        /* calculate the free space in the buffer */
00320        bytes_to_read = self->bufsize - self->bytes_in_buffer;
00321 
00322        /* read the required number of bytes */
00323        while (bytes_to_read > 0) {
00324 
00325               char *buf = self->buffer + self->bytes_in_buffer;
00326 
00327               actual_read = sapi_module.read_post(buf, bytes_to_read TSRMLS_CC);
00328 
00329               /* update the buffer length */
00330               if (actual_read > 0) {
00331                      self->bytes_in_buffer += actual_read;
00332                      SG(read_post_bytes) += actual_read;
00333                      total_read += actual_read;
00334                      bytes_to_read -= actual_read;
00335               } else {
00336                      break;
00337               }
00338        }
00339 
00340        return total_read;
00341 }
00342 
00343 /* eof if we are out of bytes, or if we hit the final boundary */
00344 static int multipart_buffer_eof(multipart_buffer *self TSRMLS_DC)
00345 {
00346        if ( (self->bytes_in_buffer == 0 && fill_buffer(self TSRMLS_CC) < 1) ) {
00347               return 1;
00348        } else {
00349               return 0;
00350        }
00351 }
00352 
00353 /* create new multipart_buffer structure */
00354 static multipart_buffer *multipart_buffer_new(char *boundary, int boundary_len)
00355 {
00356        multipart_buffer *self = (multipart_buffer *) ecalloc(1, sizeof(multipart_buffer));
00357 
00358        int minsize = boundary_len + 6;
00359        if (minsize < FILLUNIT) minsize = FILLUNIT;
00360 
00361        self->buffer = (char *) ecalloc(1, minsize + 1);
00362        self->bufsize = minsize;
00363 
00364        spprintf(&self->boundary, 0, "--%s", boundary);
00365 
00366        self->boundary_next_len = spprintf(&self->boundary_next, 0, "\n--%s", boundary);
00367 
00368        self->buf_begin = self->buffer;
00369        self->bytes_in_buffer = 0;
00370 
00371        return self;
00372 }
00373 
00374 /*
00375  * Gets the next CRLF terminated line from the input buffer.
00376  * If it doesn't find a CRLF, and the buffer isn't completely full, returns
00377  * NULL; otherwise, returns the beginning of the null-terminated line,
00378  * minus the CRLF.
00379  *
00380  * Note that we really just look for LF terminated lines. This works
00381  * around a bug in internet explorer for the macintosh which sends mime
00382  * boundaries that are only LF terminated when you use an image submit
00383  * button in a multipart/form-data form.
00384  */
00385 static char *next_line(multipart_buffer *self)
00386 {
00387        /* look for LF in the data */
00388        char* line = self->buf_begin;
00389        char* ptr = memchr(self->buf_begin, '\n', self->bytes_in_buffer);
00390 
00391        if (ptr) {    /* LF found */
00392 
00393               /* terminate the string, remove CRLF */
00394               if ((ptr - line) > 0 && *(ptr-1) == '\r') {
00395                      *(ptr-1) = 0;
00396               } else {
00397                      *ptr = 0;
00398               }
00399 
00400               /* bump the pointer */
00401               self->buf_begin = ptr + 1;
00402               self->bytes_in_buffer -= (self->buf_begin - line);
00403 
00404        } else {      /* no LF found */
00405 
00406               /* buffer isn't completely full, fail */
00407               if (self->bytes_in_buffer < self->bufsize) {
00408                      return NULL;
00409               }
00410               /* return entire buffer as a partial line */
00411               line[self->bufsize] = 0;
00412               self->buf_begin = ptr;
00413               self->bytes_in_buffer = 0;
00414        }
00415 
00416        return line;
00417 }
00418 
00419 /* Returns the next CRLF terminated line from the client */
00420 static char *get_line(multipart_buffer *self TSRMLS_DC)
00421 {
00422        char* ptr = next_line(self);
00423 
00424        if (!ptr) {
00425               fill_buffer(self TSRMLS_CC);
00426               ptr = next_line(self);
00427        }
00428 
00429        return ptr;
00430 }
00431 
00432 /* Free header entry */
00433 static void php_free_hdr_entry(mime_header_entry *h)
00434 {
00435        if (h->key) {
00436               efree(h->key);
00437        }
00438        if (h->value) {
00439               efree(h->value);
00440        }
00441 }
00442 
00443 /* finds a boundary */
00444 static int find_boundary(multipart_buffer *self, char *boundary TSRMLS_DC)
00445 {
00446        char *line;
00447 
00448        /* loop thru lines */
00449        while( (line = get_line(self TSRMLS_CC)) )
00450        {
00451               /* finished if we found the boundary */
00452               if (!strcmp(line, boundary)) {
00453                      return 1;
00454               }
00455        }
00456 
00457        /* didn't find the boundary */
00458        return 0;
00459 }
00460 
00461 /* parse headers */
00462 static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header TSRMLS_DC)
00463 {
00464        char *line;
00465        mime_header_entry prev_entry, entry;
00466        int prev_len, cur_len;
00467 
00468        /* didn't find boundary, abort */
00469        if (!find_boundary(self, self->boundary TSRMLS_CC)) {
00470               return 0;
00471        }
00472 
00473        /* get lines of text, or CRLF_CRLF */
00474 
00475        while( (line = get_line(self TSRMLS_CC)) && strlen(line) > 0 )
00476        {
00477               /* add header to table */
00478               char *key = line;
00479               char *value = NULL;
00480 
00481               /* space in the beginning means same header */
00482               if (!isspace(line[0])) {
00483                      value = strchr(line, ':');
00484               }
00485 
00486               if (value) {
00487                      *value = 0;
00488                      do { value++; } while(isspace(*value));
00489 
00490                      entry.value = estrdup(value);
00491                      entry.key = estrdup(key);
00492 
00493               } else if (zend_llist_count(header)) { /* If no ':' on the line, add to previous line */
00494 
00495                      prev_len = strlen(prev_entry.value);
00496                      cur_len = strlen(line);
00497 
00498                      entry.value = emalloc(prev_len + cur_len + 1);
00499                      memcpy(entry.value, prev_entry.value, prev_len);
00500                      memcpy(entry.value + prev_len, line, cur_len);
00501                      entry.value[cur_len + prev_len] = '\0';
00502 
00503                      entry.key = estrdup(prev_entry.key);
00504 
00505                      zend_llist_remove_tail(header);
00506               } else {
00507                      continue;
00508               }
00509 
00510               zend_llist_add_element(header, &entry);
00511               prev_entry = entry;
00512        }
00513 
00514        return 1;
00515 }
00516 
00517 static char *php_mime_get_hdr_value(zend_llist header, char *key)
00518 {
00519        mime_header_entry *entry;
00520 
00521        if (key == NULL) {
00522               return NULL;
00523        }
00524 
00525        entry = zend_llist_get_first(&header);
00526        while (entry) {
00527               if (!strcasecmp(entry->key, key)) {
00528                      return entry->value;
00529               }
00530               entry = zend_llist_get_next(&header);
00531        }
00532 
00533        return NULL;
00534 }
00535 
00536 static char *php_ap_getword(char **line, char stop)
00537 {
00538        char *pos = *line, quote;
00539        char *res;
00540 
00541        while (*pos && *pos != stop) {
00542               if ((quote = *pos) == '"' || quote == '\'') {
00543                      ++pos;
00544                      while (*pos && *pos != quote) {
00545                             if (*pos == '\\' && pos[1] && pos[1] == quote) {
00546                                    pos += 2;
00547                             } else {
00548                                    ++pos;
00549                             }
00550                      }
00551                      if (*pos) {
00552                             ++pos;
00553                      }
00554               } else ++pos;
00555        }
00556        if (*pos == '\0') {
00557               res = estrdup(*line);
00558               *line += strlen(*line);
00559               return res;
00560        }
00561 
00562        res = estrndup(*line, pos - *line);
00563 
00564        while (*pos == stop) {
00565               ++pos;
00566        }
00567 
00568        *line = pos;
00569        return res;
00570 }
00571 
00572 static char *substring_conf(char *start, int len, char quote TSRMLS_DC)
00573 {
00574        char *result = emalloc(len + 2);
00575        char *resp = result;
00576        int i;
00577 
00578        for (i = 0; i < len; ++i) {
00579               if (start[i] == '\\' && (start[i + 1] == '\\' || (quote && start[i + 1] == quote))) {
00580                      *resp++ = start[++i];
00581               } else {
00582 #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
00583                      if (php_mb_encoding_translation(TSRMLS_C)) {
00584                             size_t j = php_mb_gpc_mbchar_bytes(start+i TSRMLS_CC);
00585                             while (j-- > 0 && i < len) {
00586                                    *resp++ = start[i++];
00587                             }
00588                             --i;
00589                      } else {
00590                             *resp++ = start[i];
00591                      }
00592 #else
00593                      *resp++ = start[i];
00594 #endif
00595               }
00596        }
00597 
00598        *resp = '\0';
00599        return result;
00600 }
00601 
00602 static char *php_ap_getword_conf(char **line TSRMLS_DC)
00603 {
00604        char *str = *line, *strend, *res, quote;
00605 
00606 #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
00607        if (php_mb_encoding_translation(TSRMLS_C)) {
00608               int len=strlen(str);
00609               php_mb_gpc_encoding_detector(&str, &len, 1, NULL TSRMLS_CC);
00610        }
00611 #endif
00612 
00613        while (*str && isspace(*str)) {
00614               ++str;
00615        }
00616 
00617        if (!*str) {
00618               *line = str;
00619               return estrdup("");
00620        }
00621 
00622        if ((quote = *str) == '"' || quote == '\'') {
00623               strend = str + 1;
00624 look_for_quote:
00625               while (*strend && *strend != quote) {
00626                      if (*strend == '\\' && strend[1] && strend[1] == quote) {
00627                             strend += 2;
00628                      } else {
00629                             ++strend;
00630                      }
00631               }
00632               if (*strend && *strend == quote) {
00633                      char p = *(strend + 1);
00634                      if (p != '\r' && p != '\n' && p != '\0') {
00635                             strend++;
00636                             goto look_for_quote;
00637                      }
00638               }
00639 
00640               res = substring_conf(str + 1, strend - str - 1, quote TSRMLS_CC);
00641 
00642               if (*strend == quote) {
00643                      ++strend;
00644               }
00645 
00646        } else {
00647 
00648               strend = str;
00649               while (*strend && !isspace(*strend)) {
00650                      ++strend;
00651               }
00652               res = substring_conf(str, strend - str, 0 TSRMLS_CC);
00653        }
00654 
00655        while (*strend && isspace(*strend)) {
00656               ++strend;
00657        }
00658 
00659        *line = strend;
00660        return res;
00661 }
00662 
00663 /*
00664  * Search for a string in a fixed-length byte string.
00665  * If partial is true, partial matches are allowed at the end of the buffer.
00666  * Returns NULL if not found, or a pointer to the start of the first match.
00667  */
00668 static void *php_ap_memstr(char *haystack, int haystacklen, char *needle, int needlen, int partial)
00669 {
00670        int len = haystacklen;
00671        char *ptr = haystack;
00672 
00673        /* iterate through first character matches */
00674        while( (ptr = memchr(ptr, needle[0], len)) ) {
00675 
00676               /* calculate length after match */
00677               len = haystacklen - (ptr - (char *)haystack);
00678 
00679               /* done if matches up to capacity of buffer */
00680               if (memcmp(needle, ptr, needlen < len ? needlen : len) == 0 && (partial || len >= needlen)) {
00681                      break;
00682               }
00683 
00684               /* next character */
00685               ptr++; len--;
00686        }
00687 
00688        return ptr;
00689 }
00690 
00691 /* read until a boundary condition */
00692 static int multipart_buffer_read(multipart_buffer *self, char *buf, int bytes, int *end TSRMLS_DC)
00693 {
00694        int len, max;
00695        char *bound;
00696 
00697        /* fill buffer if needed */
00698        if (bytes > self->bytes_in_buffer) {
00699               fill_buffer(self TSRMLS_CC);
00700        }
00701 
00702        /* look for a potential boundary match, only read data up to that point */
00703        if ((bound = php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 1))) {
00704               max = bound - self->buf_begin;
00705               if (end && php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 0)) {
00706                      *end = 1;
00707               }
00708        } else {
00709               max = self->bytes_in_buffer;
00710        }
00711 
00712        /* maximum number of bytes we are reading */
00713        len = max < bytes-1 ? max : bytes-1;
00714 
00715        /* if we read any data... */
00716        if (len > 0) {
00717 
00718               /* copy the data */
00719               memcpy(buf, self->buf_begin, len);
00720               buf[len] = 0;
00721 
00722               if (bound && len > 0 && buf[len-1] == '\r') {
00723                      buf[--len] = 0;
00724               }
00725 
00726               /* update the buffer */
00727               self->bytes_in_buffer -= len;
00728               self->buf_begin += len;
00729        }
00730 
00731        return len;
00732 }
00733 
00734 /*
00735   XXX: this is horrible memory-usage-wise, but we only expect
00736   to do this on small pieces of form data.
00737 */
00738 static char *multipart_buffer_read_body(multipart_buffer *self, unsigned int *len TSRMLS_DC)
00739 {
00740        char buf[FILLUNIT], *out=NULL;
00741        int total_bytes=0, read_bytes=0;
00742 
00743        while((read_bytes = multipart_buffer_read(self, buf, sizeof(buf), NULL TSRMLS_CC))) {
00744               out = erealloc(out, total_bytes + read_bytes + 1);
00745               memcpy(out + total_bytes, buf, read_bytes);
00746               total_bytes += read_bytes;
00747        }
00748 
00749        if (out) {
00750               out[total_bytes] = '\0';
00751        }
00752        *len = total_bytes;
00753 
00754        return out;
00755 }
00756 /* }}} */
00757 
00758 /*
00759  * The combined READER/HANDLER
00760  *
00761  */
00762 
00763 SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
00764 {
00765        char *boundary, *s = NULL, *boundary_end = NULL, *start_arr = NULL, *array_index = NULL;
00766        char *temp_filename = NULL, *lbuf = NULL, *abuf = NULL;
00767        int boundary_len = 0, total_bytes = 0, cancel_upload = 0, is_arr_upload = 0, array_len = 0;
00768        int max_file_size = 0, skip_upload = 0, anonindex = 0, is_anonymous;
00769        zval *http_post_files = NULL;
00770        HashTable *uploaded_files = NULL;
00771 #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
00772        int str_len = 0, num_vars = 0, num_vars_max = 2*10, *len_list = NULL;
00773        char **val_list = NULL;
00774 #endif
00775        multipart_buffer *mbuff;
00776        zval *array_ptr = (zval *) arg;
00777        int fd = -1;
00778        zend_llist header;
00779        void *event_extra_data = NULL;
00780        int llen = 0;
00781        int upload_cnt = INI_INT("max_file_uploads");
00782 
00783        if (SG(post_max_size) > 0 && SG(request_info).content_length > SG(post_max_size)) {
00784               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));
00785               return;
00786        }
00787 
00788        /* Get the boundary */
00789        boundary = strstr(content_type_dup, "boundary");
00790        if (!boundary) {
00791               int content_type_len = strlen(content_type_dup);
00792               char *content_type_lcase = estrndup(content_type_dup, content_type_len);
00793 
00794               php_strtolower(content_type_lcase, content_type_len);
00795               boundary = strstr(content_type_lcase, "boundary");
00796               if (boundary) {
00797                      boundary = content_type_dup + (boundary - content_type_lcase);
00798               }
00799               efree(content_type_lcase);
00800        }
00801 
00802        if (!boundary || !(boundary = strchr(boundary, '='))) {
00803               sapi_module.sapi_error(E_WARNING, "Missing boundary in multipart/form-data POST data");
00804               return;
00805        }
00806 
00807        boundary++;
00808        boundary_len = strlen(boundary);
00809 
00810        if (boundary[0] == '"') {
00811               boundary++;
00812               boundary_end = strchr(boundary, '"');
00813               if (!boundary_end) {
00814                      sapi_module.sapi_error(E_WARNING, "Invalid boundary in multipart/form-data POST data");
00815                      return;
00816               }
00817        } else {
00818               /* search for the end of the boundary */
00819               boundary_end = strpbrk(boundary, ",;");
00820        }
00821        if (boundary_end) {
00822               boundary_end[0] = '\0';
00823               boundary_len = boundary_end-boundary;
00824        }
00825 
00826        /* Initialize the buffer */
00827        if (!(mbuff = multipart_buffer_new(boundary, boundary_len))) {
00828               sapi_module.sapi_error(E_WARNING, "Unable to initialize the input buffer");
00829               return;
00830        }
00831 
00832        /* Initialize $_FILES[] */
00833        zend_hash_init(&PG(rfc1867_protected_variables), 5, NULL, NULL, 0);
00834 
00835        ALLOC_HASHTABLE(uploaded_files);
00836        zend_hash_init(uploaded_files, 5, NULL, (dtor_func_t) free_estring, 0);
00837        SG(rfc1867_uploaded_files) = uploaded_files;
00838 
00839        ALLOC_ZVAL(http_post_files);
00840        array_init(http_post_files);
00841        INIT_PZVAL(http_post_files);
00842        PG(http_globals)[TRACK_VARS_FILES] = http_post_files;
00843 
00844 #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
00845        if (php_mb_encoding_translation(TSRMLS_C)) {
00846               val_list = (char **)ecalloc(num_vars_max+2, sizeof(char *));
00847               len_list = (int *)ecalloc(num_vars_max+2, sizeof(int));
00848        }
00849 #endif
00850        zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0);
00851 
00852        if (php_rfc1867_callback != NULL) {
00853               multipart_event_start event_start;
00854 
00855               event_start.content_length = SG(request_info).content_length;
00856               if (php_rfc1867_callback(MULTIPART_EVENT_START, &event_start, &event_extra_data TSRMLS_CC) == FAILURE) {
00857                      goto fileupload_done;
00858               }
00859        }
00860 
00861        while (!multipart_buffer_eof(mbuff TSRMLS_CC))
00862        {
00863               char buff[FILLUNIT];
00864               char *cd = NULL, *param = NULL, *filename = NULL, *tmp = NULL;
00865               size_t blen = 0, wlen = 0;
00866               off_t offset;
00867 
00868               zend_llist_clean(&header);
00869 
00870               if (!multipart_buffer_headers(mbuff, &header TSRMLS_CC)) {
00871                      goto fileupload_done;
00872               }
00873 
00874               if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) {
00875                      char *pair = NULL;
00876                      int end = 0;
00877 
00878                      while (isspace(*cd)) {
00879                             ++cd;
00880                      }
00881 
00882                      while (*cd && (pair = php_ap_getword(&cd, ';')))
00883                      {
00884                             char *key = NULL, *word = pair;
00885 
00886                             while (isspace(*cd)) {
00887                                    ++cd;
00888                             }
00889 
00890                             if (strchr(pair, '=')) {
00891                                    key = php_ap_getword(&pair, '=');
00892 
00893                                    if (!strcasecmp(key, "name")) {
00894                                           if (param) {
00895                                                  efree(param);
00896                                           }
00897                                           param = php_ap_getword_conf(&pair TSRMLS_CC);
00898                                    } else if (!strcasecmp(key, "filename")) {
00899                                           if (filename) {
00900                                                  efree(filename);
00901                                           }
00902                                           filename = php_ap_getword_conf(&pair TSRMLS_CC);
00903                                    }
00904                             }
00905                             if (key) {
00906                                    efree(key);
00907                             }
00908                             efree(word);
00909                      }
00910 
00911                      /* Normal form variable, safe to read all data into memory */
00912                      if (!filename && param) {
00913                             unsigned int value_len;
00914                             char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC);
00915                             unsigned int new_val_len; /* Dummy variable */
00916 
00917                             if (!value) {
00918                                    value = estrdup("");
00919                             }
00920 
00921                             if (sapi_module.input_filter(PARSE_POST, param, &value, value_len, &new_val_len TSRMLS_CC)) {
00922                                    if (php_rfc1867_callback != NULL) {
00923                                           multipart_event_formdata event_formdata;
00924                                           size_t newlength = new_val_len;
00925 
00926                                           event_formdata.post_bytes_processed = SG(read_post_bytes);
00927                                           event_formdata.name = param;
00928                                           event_formdata.value = &value;
00929                                           event_formdata.length = new_val_len;
00930                                           event_formdata.newlength = &newlength;
00931                                           if (php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC) == FAILURE) {
00932                                                  efree(param);
00933                                                  efree(value);
00934                                                  continue;
00935                                           }
00936                                           new_val_len = newlength;
00937                                    }
00938 
00939 #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
00940                                    if (php_mb_encoding_translation(TSRMLS_C)) {
00941                                           php_mb_gpc_stack_variable(param, value, &val_list, &len_list, &num_vars, &num_vars_max TSRMLS_CC);
00942                                    } else {
00943                                           safe_php_register_variable(param, value, new_val_len, array_ptr, 0 TSRMLS_CC);
00944                                    }
00945 #else
00946                                    safe_php_register_variable(param, value, new_val_len, array_ptr, 0 TSRMLS_CC);
00947 #endif
00948                             } else if (php_rfc1867_callback != NULL) {
00949                                    multipart_event_formdata event_formdata;
00950 
00951                                    event_formdata.post_bytes_processed = SG(read_post_bytes);
00952                                    event_formdata.name = param;
00953                                    event_formdata.value = &value;
00954                                    event_formdata.length = value_len;
00955                                    event_formdata.newlength = NULL;
00956                                    php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC);
00957                             }
00958 
00959                             if (!strcasecmp(param, "MAX_FILE_SIZE")) {
00960                                    max_file_size = atol(value);
00961                             }
00962 
00963                             efree(param);
00964                             efree(value);
00965                             continue;
00966                      }
00967 
00968                      /* If file_uploads=off, skip the file part */
00969                      if (!PG(file_uploads)) {
00970                             skip_upload = 1;
00971                      } else if (upload_cnt <= 0) {
00972                             skip_upload = 1;
00973                             sapi_module.sapi_error(E_WARNING, "Maximum number of allowable file uploads has been exceeded");
00974                      }
00975 
00976                      /* Return with an error if the posted data is garbled */
00977                      if (!param && !filename) {
00978                             sapi_module.sapi_error(E_WARNING, "File Upload Mime headers garbled");
00979                             goto fileupload_done;
00980                      }
00981 
00982                      if (!param) {
00983                             is_anonymous = 1;
00984                             param = emalloc(MAX_SIZE_ANONNAME);
00985                             snprintf(param, MAX_SIZE_ANONNAME, "%u", anonindex++);
00986                      } else {
00987                             is_anonymous = 0;
00988                      }
00989 
00990                      /* New Rule: never repair potential malicious user input */
00991                      if (!skip_upload) {
00992                             long c = 0;
00993                             tmp = param;
00994 
00995                             while (*tmp) {
00996                                    if (*tmp == '[') {
00997                                           c++;
00998                                    } else if (*tmp == ']') {
00999                                           c--;
01000                                           if (tmp[1] && tmp[1] != '[') {
01001                                                  skip_upload = 1;
01002                                                  break;
01003                                           }
01004                                    }
01005                                    if (c < 0) {
01006                                           skip_upload = 1;
01007                                           break;
01008                                    }
01009                                    tmp++;
01010                             }
01011                      }
01012 
01013                      total_bytes = cancel_upload = 0;
01014                      temp_filename = NULL;
01015                      fd = -1;
01016 
01017                      if (!skip_upload && php_rfc1867_callback != NULL) {
01018                             multipart_event_file_start event_file_start;
01019 
01020                             event_file_start.post_bytes_processed = SG(read_post_bytes);
01021                             event_file_start.name = param;
01022                             event_file_start.filename = &filename;
01023                             if (php_rfc1867_callback(MULTIPART_EVENT_FILE_START, &event_file_start, &event_extra_data TSRMLS_CC) == FAILURE) {
01024                                    temp_filename = "";
01025                                    efree(param);
01026                                    efree(filename);
01027                                    continue;
01028                             }
01029                      }
01030 
01031                      if (skip_upload) {
01032                             efree(param);
01033                             efree(filename);
01034                             continue;
01035                      }
01036 
01037                      if (strlen(filename) == 0) {
01038 #if DEBUG_FILE_UPLOAD
01039                             sapi_module.sapi_error(E_NOTICE, "No file uploaded");
01040 #endif
01041                             cancel_upload = UPLOAD_ERROR_D;
01042                      }
01043 
01044                      offset = 0;
01045                      end = 0;
01046                      
01047                      if (!cancel_upload) {
01048                             /* only bother to open temp file if we have data */
01049                             blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC);
01050 #if DEBUG_FILE_UPLOAD
01051                             if (blen > 0) {
01052 #else
01053                             /* in non-debug mode we have no problem with 0-length files */
01054                             {
01055 #endif
01056                                    fd = php_open_temporary_fd_ex(PG(upload_tmp_dir), "php", &temp_filename, 1 TSRMLS_CC);
01057                                    upload_cnt--;
01058                                    if (fd == -1) {
01059                                           sapi_module.sapi_error(E_WARNING, "File upload error - unable to create a temporary file");
01060                                           cancel_upload = UPLOAD_ERROR_E;
01061                                    }
01062                             }
01063                      }
01064 
01065                      while (!cancel_upload && (blen > 0))
01066                      {
01067                             if (php_rfc1867_callback != NULL) {
01068                                    multipart_event_file_data event_file_data;
01069 
01070                                    event_file_data.post_bytes_processed = SG(read_post_bytes);
01071                                    event_file_data.offset = offset;
01072                                    event_file_data.data = buff;
01073                                    event_file_data.length = blen;
01074                                    event_file_data.newlength = &blen;
01075                                    if (php_rfc1867_callback(MULTIPART_EVENT_FILE_DATA, &event_file_data, &event_extra_data TSRMLS_CC) == FAILURE) {
01076                                           cancel_upload = UPLOAD_ERROR_X;
01077                                           continue;
01078                                    }
01079                             }
01080 
01081                             if (PG(upload_max_filesize) > 0 && (total_bytes+blen) > PG(upload_max_filesize)) {
01082 #if DEBUG_FILE_UPLOAD
01083                                    sapi_module.sapi_error(E_NOTICE, "upload_max_filesize of %ld bytes exceeded - file [%s=%s] not saved", PG(upload_max_filesize), param, filename);
01084 #endif
01085                                    cancel_upload = UPLOAD_ERROR_A;
01086                             } else if (max_file_size && ((total_bytes+blen) > max_file_size)) {
01087 #if DEBUG_FILE_UPLOAD
01088                                    sapi_module.sapi_error(E_NOTICE, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename);
01089 #endif
01090                                    cancel_upload = UPLOAD_ERROR_B;
01091                             } else if (blen > 0) {
01092                                    wlen = write(fd, buff, blen);
01093 
01094                                    if (wlen == -1) {
01095                                           /* write failed */
01096 #if DEBUG_FILE_UPLOAD
01097                                           sapi_module.sapi_error(E_NOTICE, "write() failed - %s", strerror(errno));
01098 #endif
01099                                           cancel_upload = UPLOAD_ERROR_F;
01100                                    } else if (wlen < blen) {
01101 #if DEBUG_FILE_UPLOAD
01102                                           sapi_module.sapi_error(E_NOTICE, "Only %d bytes were written, expected to write %d", wlen, blen);
01103 #endif
01104                                           cancel_upload = UPLOAD_ERROR_F;
01105                                    } else {
01106                                           total_bytes += wlen;
01107                                    }
01108                                    offset += wlen;
01109                             }
01110 
01111                             /* read data for next iteration */
01112                             blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC);
01113                      }
01114 
01115                      if (fd != -1) { /* may not be initialized if file could not be created */
01116                             close(fd);
01117                      }
01118 
01119                      if (!cancel_upload && !end) {
01120 #if DEBUG_FILE_UPLOAD
01121                             sapi_module.sapi_error(E_NOTICE, "Missing mime boundary at the end of the data for file %s", strlen(filename) > 0 ? filename : "");
01122 #endif
01123                             cancel_upload = UPLOAD_ERROR_C;
01124                      }
01125 #if DEBUG_FILE_UPLOAD
01126                      if (strlen(filename) > 0 && total_bytes == 0 && !cancel_upload) {
01127                             sapi_module.sapi_error(E_WARNING, "Uploaded file size 0 - file [%s=%s] not saved", param, filename);
01128                             cancel_upload = 5;
01129                      }
01130 #endif
01131                      if (php_rfc1867_callback != NULL) {
01132                             multipart_event_file_end event_file_end;
01133 
01134                             event_file_end.post_bytes_processed = SG(read_post_bytes);
01135                             event_file_end.temp_filename = temp_filename;
01136                             event_file_end.cancel_upload = cancel_upload;
01137                             if (php_rfc1867_callback(MULTIPART_EVENT_FILE_END, &event_file_end, &event_extra_data TSRMLS_CC) == FAILURE) {
01138                                    cancel_upload = UPLOAD_ERROR_X;
01139                             }
01140                      }
01141 
01142                      if (cancel_upload) {
01143                             if (temp_filename) {
01144                                    if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */
01145                                           unlink(temp_filename);
01146                                    }
01147                                    efree(temp_filename);
01148                             }
01149                             temp_filename = "";
01150                      } else {
01151                             zend_hash_add(SG(rfc1867_uploaded_files), temp_filename, strlen(temp_filename) + 1, &temp_filename, sizeof(char *), NULL);
01152                      }
01153 
01154                      /* is_arr_upload is true when name of file upload field
01155                       * ends in [.*]
01156                       * start_arr is set to point to 1st [ */
01157                      is_arr_upload =      (start_arr = strchr(param,'[')) && (param[strlen(param)-1] == ']');
01158 
01159                      if (is_arr_upload) {
01160                             array_len = strlen(start_arr);
01161                             if (array_index) {
01162                                    efree(array_index);
01163                             }
01164                             array_index = estrndup(start_arr + 1, array_len - 2);
01165                      }
01166 
01167                      /* Add $foo_name */
01168                      if (llen < strlen(param) + MAX_SIZE_OF_INDEX + 1) {
01169                             llen = strlen(param);
01170                             lbuf = (char *) safe_erealloc(lbuf, llen, 1, MAX_SIZE_OF_INDEX + 1);
01171                             llen += MAX_SIZE_OF_INDEX + 1;
01172                      }
01173 
01174                      if (is_arr_upload) {
01175                             if (abuf) efree(abuf);
01176                             abuf = estrndup(param, strlen(param)-array_len);
01177                             snprintf(lbuf, llen, "%s_name[%s]", abuf, array_index);
01178                      } else {
01179                             snprintf(lbuf, llen, "%s_name", param);
01180                      }
01181 
01182 #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
01183                      if (php_mb_encoding_translation(TSRMLS_C)) {
01184                             if (num_vars >= num_vars_max) {
01185                                    php_mb_gpc_realloc_buffer(&val_list, &len_list, &num_vars_max, 1 TSRMLS_CC);
01186                             }
01187                             val_list[num_vars] = filename;
01188                             len_list[num_vars] = strlen(filename);
01189                             num_vars++;
01190                             if (php_mb_gpc_encoding_detector(val_list, len_list, num_vars, NULL TSRMLS_CC) == SUCCESS) {
01191                                    str_len = strlen(filename);
01192                                    php_mb_gpc_encoding_converter(&filename, &str_len, 1, NULL, NULL TSRMLS_CC);
01193                             }
01194                             s = php_mb_strrchr(filename, '\\' TSRMLS_CC);
01195                             if ((tmp = php_mb_strrchr(filename, '/' TSRMLS_CC)) > s) {
01196                                    s = tmp;
01197                             }
01198                             num_vars--;
01199                             goto filedone;
01200                      }
01201 #endif
01202                      /* The \ check should technically be needed for win32 systems only where
01203                       * it is a valid path separator. However, IE in all it's wisdom always sends
01204                       * the full path of the file on the user's filesystem, which means that unless
01205                       * the user does basename() they get a bogus file name. Until IE's user base drops
01206                       * to nill or problem is fixed this code must remain enabled for all systems. */
01207                      s = strrchr(filename, '\\');
01208                      if ((tmp = strrchr(filename, '/')) > s) {
01209                             s = tmp;
01210                      }
01211 #ifdef PHP_WIN32
01212                      if (PG(magic_quotes_gpc)) {
01213                             if ((tmp = strrchr(s ? s : filename, '\'')) > s) {
01214                                    s = tmp;
01215                             }
01216                             if ((tmp = strrchr(s ? s : filename, '"')) > s) {
01217                                    s = tmp;
01218                             }
01219                      }
01220 #endif
01221 
01222 #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
01223 filedone:
01224 #endif
01225 
01226                      if (!is_anonymous) {
01227                             if (s && s >= filename) {
01228                                    safe_php_register_variable(lbuf, s+1, strlen(s+1), NULL, 0 TSRMLS_CC);
01229                             } else {
01230                                    safe_php_register_variable(lbuf, filename, strlen(filename), NULL, 0 TSRMLS_CC);
01231                             }
01232                      }
01233 
01234                      /* Add $foo[name] */
01235                      if (is_arr_upload) {
01236                             snprintf(lbuf, llen, "%s[name][%s]", abuf, array_index);
01237                      } else {
01238                             snprintf(lbuf, llen, "%s[name]", param);
01239                      }
01240                      if (s && s >= filename) {
01241                             register_http_post_files_variable(lbuf, s+1, http_post_files, 0 TSRMLS_CC);
01242                      } else {
01243                             register_http_post_files_variable(lbuf, filename, http_post_files, 0 TSRMLS_CC);
01244                      }
01245                      efree(filename);
01246                      s = NULL;
01247 
01248                      /* Possible Content-Type: */
01249                      if (cancel_upload || !(cd = php_mime_get_hdr_value(header, "Content-Type"))) {
01250                             cd = "";
01251                      } else {
01252                             /* fix for Opera 6.01 */
01253                             s = strchr(cd, ';');
01254                             if (s != NULL) {
01255                                    *s = '\0';
01256                             }
01257                      }
01258 
01259                      /* Add $foo_type */
01260                      if (is_arr_upload) {
01261                             snprintf(lbuf, llen, "%s_type[%s]", abuf, array_index);
01262                      } else {
01263                             snprintf(lbuf, llen, "%s_type", param);
01264                      }
01265                      if (!is_anonymous) {
01266                             safe_php_register_variable(lbuf, cd, strlen(cd), NULL, 0 TSRMLS_CC);
01267                      }
01268 
01269                      /* Add $foo[type] */
01270                      if (is_arr_upload) {
01271                             snprintf(lbuf, llen, "%s[type][%s]", abuf, array_index);
01272                      } else {
01273                             snprintf(lbuf, llen, "%s[type]", param);
01274                      }
01275                      register_http_post_files_variable(lbuf, cd, http_post_files, 0 TSRMLS_CC);
01276 
01277                      /* Restore Content-Type Header */
01278                      if (s != NULL) {
01279                             *s = ';';
01280                      }
01281                      s = "";
01282 
01283                      {
01284                             /* store temp_filename as-is (without magic_quotes_gpc-ing it, in case upload_tmp_dir
01285                              * contains escapeable characters. escape only the variable name.) */
01286                             zval zfilename;
01287 
01288                             /* Initialize variables */
01289                             add_protected_variable(param TSRMLS_CC);
01290 
01291                             /* if param is of form xxx[.*] this will cut it to xxx */
01292                             if (!is_anonymous) {
01293                                    ZVAL_STRING(&zfilename, temp_filename, 1);
01294                                    safe_php_register_variable_ex(param, &zfilename, NULL, 1 TSRMLS_CC);
01295                             }
01296 
01297                             /* Add $foo[tmp_name] */
01298                             if (is_arr_upload) {
01299                                    snprintf(lbuf, llen, "%s[tmp_name][%s]", abuf, array_index);
01300                             } else {
01301                                    snprintf(lbuf, llen, "%s[tmp_name]", param);
01302                             }
01303                             add_protected_variable(lbuf TSRMLS_CC);
01304                             ZVAL_STRING(&zfilename, temp_filename, 1);
01305                             register_http_post_files_variable_ex(lbuf, &zfilename, http_post_files, 1 TSRMLS_CC);
01306                      }
01307 
01308                      {
01309                             zval file_size, error_type;
01310 
01311                             error_type.value.lval = cancel_upload;
01312                             error_type.type = IS_LONG;
01313 
01314                             /* Add $foo[error] */
01315                             if (cancel_upload) {
01316                                    file_size.value.lval = 0;
01317                                    file_size.type = IS_LONG;
01318                             } else {
01319                                    file_size.value.lval = total_bytes;
01320                                    file_size.type = IS_LONG;
01321                             }
01322 
01323                             if (is_arr_upload) {
01324                                    snprintf(lbuf, llen, "%s[error][%s]", abuf, array_index);
01325                             } else {
01326                                    snprintf(lbuf, llen, "%s[error]", param);
01327                             }
01328                             register_http_post_files_variable_ex(lbuf, &error_type, http_post_files, 0 TSRMLS_CC);
01329 
01330                             /* Add $foo_size */
01331                             if (is_arr_upload) {
01332                                    snprintf(lbuf, llen, "%s_size[%s]", abuf, array_index);
01333                             } else {
01334                                    snprintf(lbuf, llen, "%s_size", param);
01335                             }
01336                             if (!is_anonymous) {
01337                                    safe_php_register_variable_ex(lbuf, &file_size, NULL, 0 TSRMLS_CC);
01338                             }
01339 
01340                             /* Add $foo[size] */
01341                             if (is_arr_upload) {
01342                                    snprintf(lbuf, llen, "%s[size][%s]", abuf, array_index);
01343                             } else {
01344                                    snprintf(lbuf, llen, "%s[size]", param);
01345                             }
01346                             register_http_post_files_variable_ex(lbuf, &file_size, http_post_files, 0 TSRMLS_CC);
01347                      }
01348                      efree(param);
01349               }
01350        }
01351 
01352 fileupload_done:
01353        if (php_rfc1867_callback != NULL) {
01354               multipart_event_end event_end;
01355 
01356               event_end.post_bytes_processed = SG(read_post_bytes);
01357               php_rfc1867_callback(MULTIPART_EVENT_END, &event_end, &event_extra_data TSRMLS_CC);
01358        }
01359 
01360        SAFE_RETURN;
01361 }
01362 /* }}} */
01363 
01364 /*
01365  * Local variables:
01366  * tab-width: 4
01367  * c-basic-offset: 4
01368  * End:
01369  * vim600: sw=4 ts=4 fdm=marker
01370  * vim<600: sw=4 ts=4
01371  */