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