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