PageRenderTime 56ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/main/rfc1867.c

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