Annotation of embedaddon/php/main/rfc1867.c, revision 1.1.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>