Press "Enter" to skip to content

深入理解PHP原理之文件上传

今天研究PHP注册POST/GET大变量的时候,看到了关于这块的一些东西,跟踪了半天,,先记录下来,免得以后再如此麻烦的跟踪

处理器注册:

   [mod_php5.c, mod_php5模块初始化] php_init_handler(server_rec *s, pool *p)
	->[main/SAPI.c]sapi_startup(&apache_sapi_module)
		->[main/SAPI.c] sapi_globals_ctor(&sapi_globals)
			->[main/php_content_types.c]php_setup_sapi_content_types(TSRMLS_C)
				->[main/php_content_types.c php_post_entries如下]sapi_register_post_entries(php_post_entries TSRMLS_CC)
					->[main/SAPI.c]sapi_register_post_entry(p TSRMLS_CC)

如下面的代码,共注册了俩个处理器,分别处理post数据和文件上传。
注1:G(http_globals)[TRACK_VARS_COOKIE]这部分,可以参看我较早前的 在PHP Module中获取$_GET/$_POST/$_COOKIE的方法研究

  [main/rfc1867.h]
      #define MULTIPART_CONTENT_TYPE "multipart/form-data"
  [main/php_content_types.h]
     #define DEFAULT_POST_CONTENT_TYPE "application/x-www-form-urlencoded"
  [main/SAPI.c]
     struct _sapi_post_entry {
    	char *content_type;
    	uint content_type_len;
    	void (*post_reader)(TSRMLS_D);
    	void (*post_handler)(char *content_type_dup, void *arg TSRMLS_DC);
	};
  [main/php_content_types.c]
	static sapi_post_entry php_post_entries[] = {
    	{ DEFAULT_POST_CONTENT_TYPE, sizeof(DEFAULT_POST_CONTENT_TYPE)-1, sapi_read_standard_form_data, php_std_post_handler },
    	{ MULTIPART_CONTENT_TYPE,    sizeof(MULTIPART_CONTENT_TYPE)-1,    NULL,                         rfc1867_post_handler },
    	{ NULL, 0, NULL, NULL }
};
 

那么对于rfc1867_post_handler函数来说,我罗列出源码如下, 加了我的注释.

SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler)
{
        char *boundary, *s=NULL, *boundary_end = NULL, *start_arr=NULL, *array_index=NULL;
        char *temp_filename=NULL, *lbuf=NULL, *abuf=NULL;
        int boundary_len=0, total_bytes=0, cancel_upload=0, is_arr_upload=0, array_len=0;
        int max_file_size=0, skip_upload=0, anonindex=0, is_anonymous;
        zval *http_post_files=NULL; HashTable *uploaded_files=NULL;
#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
        int str_len = 0, num_vars = 0, num_vars_max = 2*10, *len_list = NULL;
        char **val_list = NULL;
#endif
        zend_bool magic_quotes_gpc;
        multipart_buffer *mbuff;
        zval *array_ptr = (zval *) arg;
        int fd=-1;
        zend_llist header;
        void *event_extra_data = NULL;
        int llen = 0;
		//检查是否超出最大上传文件大小
        if (SG(request_info).content_length > SG(post_max_size)) {
                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));
                return;
        }
        //取得上传文件的分隔符
        boundary = strstr(content_type_dup, "boundary");
        if (!boundary || !(boundary=strchr(boundary, '='))) {
                sapi_module.sapi_error(E_WARNING, "Missing boundary in multipart/form-data POST data");
                return;
        }
        boundary++;
        boundary_len = strlen(boundary);
        if (boundary[0] == '"') {
                boundary++;
                boundary_end = strchr(boundary, '"');
                if (!boundary_end) {
                        sapi_module.sapi_error(E_WARNING, "Invalid boundary in multipart/form-data POST data");
                        return;
                }
        } else {
                /* search for the end of the boundary */
                boundary_end = strchr(boundary, ',');
        }
        if (boundary_end) {
                boundary_end[0] = '';
                boundary_len = boundary_end-boundary;
        }
        /* Initialize the buffer */
        if (!(mbuff = multipart_buffer_new(boundary, boundary_len))) {
                sapi_module.sapi_error(E_WARNING, "Unable to initialize the input buffer");
                return;
        }
        //初始化$_FILE变量
        zend_hash_init(&PG(rfc1867_protected_variables), 5, NULL, NULL, 0);
        ALLOC_HASHTABLE(uploaded_files);
        zend_hash_init(uploaded_files, 5, NULL, (dtor_func_t) free_estring, 0);
        SG(rfc1867_uploaded_files) = uploaded_files;
        ALLOC_ZVAL(http_post_files);
        array_init(http_post_files);
        INIT_PZVAL(http_post_files);
        PG(http_globals)[TRACK_VARS_FILES] = http_post_files; //TRACK_VARS_FILE正是_FILE在php_core_globals.http_globals中的index (注1)
#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
        if (php_mb_encoding_translation(TSRMLS_C)) {
                val_list = (char **)ecalloc(num_vars_max+2, sizeof(char *));
                len_list = (int *)ecalloc(num_vars_max+2, sizeof(int));
        }
#endif
        zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0);
        if (php_rfc1867_callback != NULL) {
                multipart_event_start event_start;
                event_start.content_length = SG(request_info).content_length;
                if (php_rfc1867_callback(MULTIPART_EVENT_START, &event_start, &event_extra_data TSRMLS_CC) == FAILURE) {
                        goto fileupload_done;
                }
        }
        while (!multipart_buffer_eof(mbuff TSRMLS_CC))
        {
                char buff[FILLUNIT];
                char *cd=NULL,*param=NULL,*filename=NULL, *tmp=NULL;
                size_t blen=0, wlen=0;
                off_t offset;
                zend_llist_clean(&header);
                if (!multipart_buffer_headers(mbuff, &header TSRMLS_CC)) {
                        goto fileupload_done;
                }
                if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) {
                        char *pair=NULL;
                        int end=0;
                        while (isspace(*cd)) {
                                ++cd;
                        }
                        while (*cd && (pair = php_ap_getword(&cd, ';')))
                        {
                                char *key=NULL, *word = pair;
                                while (isspace(*cd)) {
                                        ++cd;
                                }
                                if (strchr(pair, '=')) {
                                        key = php_ap_getword(&pair, '=');
                                        if (!strcasecmp(key, "name")) {
                                                if (param) {
                                                        efree(param);
                                                }
                                                param = php_ap_getword_conf(&pair TSRMLS_CC);
                                        } else if (!strcasecmp(key, "filename")) {
                                                if (filename) {
                                                        efree(filename);
                                                }
                                                filename = php_ap_getword_conf(&pair TSRMLS_CC);
                                        }
                                }
                                if (key) {
                                        efree(key);
                                }
                                efree(word);
                        }
                        /* Normal form variable, safe to read all data into memory */
                        if (!filename && param) {
                                unsigned int value_len;
                                char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC);
                                unsigned int new_val_len; /* Dummy variable */
                                if (!value) {
                                        value = estrdup("");
                                }
                                if (sapi_module.input_filter(PARSE_POST, param, &value, value_len, &new_val_len TSRMLS_CC)) {
                                        if (php_rfc1867_callback != NULL) {
                                                multipart_event_formdata event_formdata;
                                                size_t newlength = 0;
                                                event_formdata.post_bytes_processed = SG(read_post_bytes);
                                                event_formdata.name = param;
                                                event_formdata.value = &value;
                                                event_formdata.length = new_val_len;
                                                event_formdata.newlength = &newlength;
                                                if (php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC) == FAILURE) {
                                                        efree(param);
                                                        efree(value);
                                                        continue;
                                                }
                                                new_val_len = newlength;
                                        }
#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
                                        if (php_mb_encoding_translation(TSRMLS_C)) {
                                                php_mb_gpc_stack_variable(param, value, &val_list, &len_list,
                                                                                                  &num_vars, &num_vars_max TSRMLS_CC);
                                        } else {
                                                safe_php_register_variable(param, value, new_val_len, array_ptr, 0 TSRMLS_CC);
                                        }
#else
                                        safe_php_register_variable(param, value, new_val_len, array_ptr, 0 TSRMLS_CC);
#endif
                                } else if (php_rfc1867_callback != NULL) {
                                        multipart_event_formdata event_formdata;
                                        event_formdata.post_bytes_processed = SG(read_post_bytes);
                                        event_formdata.name = param;
                                        event_formdata.value = &value;
                                        event_formdata.length = value_len;
                                        event_formdata.newlength = NULL;
                                        php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC);
                                }
                                if (!strcasecmp(param, "MAX_FILE_SIZE")) {
                                        max_file_size = atol(value);
                                }
                                efree(param);
                                efree(value);
                                continue;
                        }
                        /* If file_uploads=off, skip the file part */
                        if (!PG(file_uploads)) {
                                skip_upload = 1;
                        }
                        /* Return with an error if the posted data is garbled */
                        if (!param && !filename) {
                                sapi_module.sapi_error(E_WARNING, "File Upload Mime headers garbled");
                                goto fileupload_done;
                        }
                        if (!param) {
                                is_anonymous = 1;
                                param = emalloc(MAX_SIZE_ANONNAME);
                                snprintf(param, MAX_SIZE_ANONNAME, "%u", anonindex++);
                        } else {
                                is_anonymous = 0;
                        }
                        /* New Rule: never repair potential malicious user input */
                        if (!skip_upload) {
                                char *tmp = param;
                                long c = 0;
                                while (*tmp) {
                                        if (*tmp == '[') {
                                                c++;
                                        } else if (*tmp == ']') {
                                                c--;
                                                if (tmp[1] && tmp[1] != '[') {
                                                        skip_upload = 1;
                                                        break;
                                                }
                                        }
                                        if (c < 0) {
                                                skip_upload = 1;
                                                break;
                                        }
                                        tmp++;
                                }
                        }
                        total_bytes = cancel_upload = 0;
                        if (!skip_upload) {
                                /* Handle file */
                                fd = php_open_temporary_fd_ex(PG(upload_tmp_dir), "php", &temp_filename, 1 TSRMLS_CC);
                                if (fd==-1) {
                                        sapi_module.sapi_error(E_WARNING, "File upload error - unable to create a temporary file");
                                        cancel_upload = UPLOAD_ERROR_E;
                                }
                        }
                        if (!skip_upload && php_rfc1867_callback != NULL) {
                                multipart_event_file_start event_file_start;
                                event_file_start.post_bytes_processed = SG(read_post_bytes);
                                event_file_start.name = param;
                                event_file_start.filename = &filename;
                                if (php_rfc1867_callback(MULTIPART_EVENT_FILE_START, &event_file_start, &event_extra_data TSRMLS_CC) == FAILURE) {
                                        if (temp_filename) {
                                                if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */
                                                        close(fd);
                                                        unlink(temp_filename);
                                                }
                                                efree(temp_filename);
                                        }
                                        temp_filename="";
                                        efree(param);
                                        efree(filename);
                                        continue;
                                }
                        }
                        if (skip_upload) {
                                efree(param);
                                efree(filename);
                                continue;
                        }
                        if(strlen(filename) == 0) {
#if DEBUG_FILE_UPLOAD
                                sapi_module.sapi_error(E_NOTICE, "No file uploaded");
#endif
                                cancel_upload = UPLOAD_ERROR_D;
                        }
                        offset = 0;
                        end = 0;
                        while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC)))
                        {
                                if (php_rfc1867_callback != NULL) {
                                        multipart_event_file_data event_file_data;
                                        event_file_data.post_bytes_processed = SG(read_post_bytes);
                                        event_file_data.offset = offset;
                                        event_file_data.data = buff;
                                        event_file_data.length = blen;
                                        event_file_data.newlength = &blen;
                                        if (php_rfc1867_callback(MULTIPART_EVENT_FILE_DATA, &event_file_data, &event_extra_data TSRMLS_CC) == FAILURE) {
                                                cancel_upload = UPLOAD_ERROR_X;
                                                continue;
                                        }
                                }
                                if (PG(upload_max_filesize) > 0 && total_bytes > PG(upload_max_filesize)) {
#if DEBUG_FILE_UPLOAD
                                        sapi_module.sapi_error(E_NOTICE, "upload_max_filesize of %ld bytes exceeded - file [%s=%s] not saved", PG(upload_max_filesize), param, filename);
#endif
                                        cancel_upload = UPLOAD_ERROR_A;
                                } else if (max_file_size && (total_bytes > max_file_size)) {
#if DEBUG_FILE_UPLOAD
                                        sapi_module.sapi_error(E_NOTICE, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename);
#endif
                                        cancel_upload = UPLOAD_ERROR_B;
                                } else if (blen > 0) {
                                        wlen = write(fd, buff, blen);
                                        if (wlen == -1) {
                                                /* write failed */
#if DEBUG_FILE_UPLOAD
                                                sapi_module.sapi_error(E_NOTICE, "write() failed - %s", strerror(errno));
#endif
                                                cancel_upload = UPLOAD_ERROR_F;
                                        } else if (wlen < blen) {
#if DEBUG_FILE_UPLOAD
                                                sapi_module.sapi_error(E_NOTICE, "Only %d bytes were written, expected to write %d", wlen, blen);
#endif
                                                cancel_upload = UPLOAD_ERROR_F;
                                        } else {
                                                total_bytes += wlen;
                                        }
                                        offset += wlen;
                                }
                        }
                        if (fd!=-1) { /* may not be initialized if file could not be created */
                                close(fd);
                        }
                        if (!cancel_upload && !end) {
#if DEBUG_FILE_UPLOAD
                                sapi_module.sapi_error(E_NOTICE, "Missing mime boundary at the end of the data for file %s", strlen(filename) > 0 ? filename : "");
#endif
                                cancel_upload = UPLOAD_ERROR_C;
                        }
#if DEBUG_FILE_UPLOAD
                        if(strlen(filename) > 0 && total_bytes == 0 && !cancel_upload) {
                                sapi_module.sapi_error(E_WARNING, "Uploaded file size 0 - file [%s=%s] not saved", param, filename);
                                cancel_upload = 5;
                        }
#endif
                        if (php_rfc1867_callback != NULL) {
                                multipart_event_file_end event_file_end;
                                event_file_end.post_bytes_processed = SG(read_post_bytes);
                                event_file_end.temp_filename = temp_filename;
                                event_file_end.cancel_upload = cancel_upload;
                                if (php_rfc1867_callback(MULTIPART_EVENT_FILE_END, &event_file_end, &event_extra_data TSRMLS_CC) == FAILURE) {
                                        cancel_upload = UPLOAD_ERROR_X;
                                }
                        }
                        if (cancel_upload) {
                                if (temp_filename) {
                                        if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */
                                                unlink(temp_filename);
                                        }
                                        efree(temp_filename);
                                }
                                temp_filename="";
                        } else {
                                zend_hash_add(SG(rfc1867_uploaded_files), temp_filename, strlen(temp_filename) + 1, &temp_filename, sizeof(char *), NULL);
                        }
                        /* is_arr_upload is true when name of file upload field
                         * ends in [.*]
                         * start_arr is set to point to 1st [
                         */
                        is_arr_upload = (start_arr = strchr(param,'[')) && (param[strlen(param)-1] == ']');
                        if (is_arr_upload) {
                                array_len = strlen(start_arr);
                                if (array_index) {
                                        efree(array_index);
                                }
                                array_index = estrndup(start_arr+1, array_len-2);
                        }
                        /* Add $foo_name */
                        if (llen < strlen(param) + MAX_SIZE_OF_INDEX + 1) {
                                llen = strlen(param);
                                lbuf = (char *) safe_erealloc(lbuf, llen, 1, MAX_SIZE_OF_INDEX + 1);
                                llen += MAX_SIZE_OF_INDEX + 1;
                        }
                        if (is_arr_upload) {
                                if (abuf) efree(abuf);
                                abuf = estrndup(param, strlen(param)-array_len);
                                snprintf(lbuf, llen, "%s_name[%s]", abuf, array_index);
                        } else {
                                snprintf(lbuf, llen, "%s_name", param);
                        }
#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
                        if (php_mb_encoding_translation(TSRMLS_C)) {
                                if (num_vars>=num_vars_max){
                                        php_mb_gpc_realloc_buffer(&val_list, &len_list, &num_vars_max,
                                                                                          1 TSRMLS_CC);
                                }
                                val_list[num_vars] = filename;
                                len_list[num_vars] = strlen(filename);
                                num_vars++;
                                if(php_mb_gpc_encoding_detector(val_list, len_list, num_vars, NULL TSRMLS_CC) == SUCCESS) {
                                        str_len = strlen(filename);
                                        php_mb_gpc_encoding_converter(&filename, &str_len, 1, NULL, NULL TSRMLS_CC);
                                }
                                s = php_mb_strrchr(filename, '\' TSRMLS_CC);
                                if ((tmp = php_mb_strrchr(filename, '/' TSRMLS_CC)) > s) {
                                        s = tmp;
                                }
                                num_vars--;
                                goto filedone;
                        }
#endif
                        /* The  check should technically be needed for win32 systems only where
                         * it is a valid path separator. However, IE in all it's wisdom always sends
                         * the full path of the file on the user's filesystem, which means that unless
                         * the user does basename() they get a bogus file name. Until IE's user base drops
                         * to nill or problem is fixed this code must remain enabled for all systems.
                         */
                        s = strrchr(filename, '\');
                        if ((tmp = strrchr(filename, '/')) > s) {
                                s = tmp;
                        }
#ifdef PHP_WIN32
                        if (PG(magic_quotes_gpc)) {
                                s = s ? s : filename;
                                tmp = strrchr(s, ''');
                                s = tmp > s ? tmp : s;
                                tmp = strrchr(s, '"');
                                s = tmp > s ? tmp : s;
                        }
#endif
#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
filedone:
#endif
                        if (!is_anonymous) {
                                if (s && s > filename) {
                                        safe_php_register_variable(lbuf, s+1, strlen(s+1), NULL, 0 TSRMLS_CC);
                                } else {
                                        safe_php_register_variable(lbuf, filename, strlen(filename), NULL, 0 TSRMLS_CC);
                                }
                        }
                        /* Add $foo[name] */
                        if (is_arr_upload) {
                                snprintf(lbuf, llen, "%s[name][%s]", abuf, array_index);
                        } else {
                                snprintf(lbuf, llen, "%s[name]", param);
                        }
                        if (s && s > filename) {
                                register_http_post_files_variable(lbuf, s+1, http_post_files, 0 TSRMLS_CC);
                        } else {
                                register_http_post_files_variable(lbuf, filename, http_post_files, 0 TSRMLS_CC);
                        }
                        efree(filename);
                        s = NULL;
                        /* Possible Content-Type: */
                        if (cancel_upload || !(cd = php_mime_get_hdr_value(header, "Content-Type"))) {
                                cd = "";
                        } else {
                                /* fix for Opera 6.01 */
                                s = strchr(cd, ';');
                                if (s != NULL) {
                                        *s = '';
                                }
                        }
                        /* Add $foo_type */
                        if (is_arr_upload) {
                                snprintf(lbuf, llen, "%s_type[%s]", abuf, array_index);
                        } else {
                                snprintf(lbuf, llen, "%s_type", param);
                        }
                        if (!is_anonymous) {
                                safe_php_register_variable(lbuf, cd, strlen(cd), NULL, 0 TSRMLS_CC);
                        }
                        /* Add $foo[type] */
                        if (is_arr_upload) {
                                snprintf(lbuf, llen, "%s[type][%s]", abuf, array_index);
                        } else {
                                snprintf(lbuf, llen, "%s[type]", param);
                        }
                        register_http_post_files_variable(lbuf, cd, http_post_files, 0 TSRMLS_CC);
                        /* Restore Content-Type Header */
                        if (s != NULL) {
                                *s = ';';
                        }
                        s = "";
                        /* Initialize variables */
                        add_protected_variable(param TSRMLS_CC);
                        magic_quotes_gpc = PG(magic_quotes_gpc);
                        PG(magic_quotes_gpc) = 0;
                        /* if param is of form xxx[.*] this will cut it to xxx */
                        if (!is_anonymous) {
                                safe_php_register_variable(param, temp_filename, strlen(temp_filename), NULL, 1 TSRMLS_CC);
                        }
                        /* Add $foo[tmp_name] */
                        if (is_arr_upload) {
                                snprintf(lbuf, llen, "%s[tmp_name][%s]", abuf, array_index);
                        } else {
                                snprintf(lbuf, llen, "%s[tmp_name]", param);
                        }
                        add_protected_variable(lbuf TSRMLS_CC);
                        register_http_post_files_variable(lbuf, temp_filename, http_post_files, 1 TSRMLS_CC);
                        PG(magic_quotes_gpc) = magic_quotes_gpc;
                        {
                                zval file_size, error_type;
                                error_type.value.lval = cancel_upload;
                                error_type.type = IS_LONG;
                                /* Add $foo[error] */
                                if (cancel_upload) {
                                        file_size.value.lval = 0;
                                        file_size.type = IS_LONG;
                                } else {
                                        file_size.value.lval = total_bytes;
                                        file_size.type = IS_LONG;
                                }
                                if (is_arr_upload) {
                                        snprintf(lbuf, llen, "%s[error][%s]", abuf, array_index);
                                } else {
                                        snprintf(lbuf, llen, "%s[error]", param);
                                }
                                register_http_post_files_variable_ex(lbuf, &error_type, http_post_files, 0 TSRMLS_CC);
                                /* Add $foo_size */
                                if (is_arr_upload) {
                                        snprintf(lbuf, llen, "%s_size[%s]", abuf, array_index);
                                } else {
                                        snprintf(lbuf, llen, "%s_size", param);
                                }
                                if (!is_anonymous) {
                                        safe_php_register_variable_ex(lbuf, &file_size, NULL, 0 TSRMLS_CC);
                                }
                                /* Add $foo[size] */
                                if (is_arr_upload) {
                                        snprintf(lbuf, llen, "%s[size][%s]", abuf, array_index);
                                } else {
                                        snprintf(lbuf, llen, "%s[size]", param);
                                }
                                register_http_post_files_variable_ex(lbuf, &file_size, http_post_files, 0 TSRMLS_CC);
                        }
                        efree(param);
                }
        }
fileupload_done:
        if (php_rfc1867_callback != NULL) {
                multipart_event_end event_end;
                event_end.post_bytes_processed = SG(read_post_bytes);
                php_rfc1867_callback(MULTIPART_EVENT_END, &event_end, &event_extra_data TSRMLS_CC);
        }
        SAFE_RETURN;
}

19 Comments

  1. […] 关于php_rfc1867_callback是什么,可以看哥学社另一哥鸟哥的分析http://www.laruence.com/2008/11/07/586.html三.总结 在探测临时文件大小的时候,APC和 uploadprogress其实是大同小异的方法,先记录,再取大小百分比。 关于哥学社:哥学社是一个自由博客组织,以提高原创技术博客质量,为成员博客增加更有效评论,由来自腾讯、百度、盛大、人人网、新浪、奇虎、TOM等各大企业的哥们共同起草发起。 关于五四陈: 54chen(陈臻),人人网分布式存储研究人员,业余时间混迹于各技术组织且乐此不疲。目前关注实施PHP培训。对flex等前端技术有一点研究。 个人技术站点:http://www.54chen.com/ 。可以通过电子邮件czhttp@gmail.com 联系到他。 本文提及的文章:http://www.php.net/releases/5_2_0.phphttp://www.ibm.com/developerworks/cn/opensource/os-php-v525/http://www.laruence.com/2008/11/07/586.html   […]

  2. […] 关于php_rfc1867_callback是什么,可以看哥学社另一哥鸟哥的分析 http://www.laruence.com/2008/11/07/586.html […]

  3. zvaly
    zvaly November 9, 2008

    新来这2篇文章很喜欢,尤其是文件上传,曾经研究过文件上传流程,没有你这么细,要检讨啦~~

    • 雪候鸟
      雪候鸟 November 10, 2008

      呵呵,那就好, 只是现在还只是整理出来个大体框架,最好能有问题驱动, 才能找到一些可以被应用的features,

  4. 3gwind
    3gwind November 8, 2008

    就是你用什么工具跟踪的,我对这个比较感兴趣

  5. blankyao
    blankyao November 7, 2008

    鸟哥同学,能不能介绍下你是用的啥方法跟踪的?或者说在分析调试的时候用的啥方法?

    • 雪候鸟
      雪候鸟 November 7, 2008

      大胆猜测,小心求证
      呵呵.

      • blankyao
        blankyao November 8, 2008

        在这个求证的过程中是不是一遍遍的修改编译调试,最后得到结果?

        • 雪候鸟
          雪候鸟 November 9, 2008

          一般不需要,除非是实在通过猜测流程走不下去了才需要这样.

Comments are closed.