python上传工具实现

用python模拟浏览器上传文件。

server端的程序:

 1 <?php
 2 $upload_file = "***".$_FILES['userfile']['name'];
 3 if (is_uploaded_file($_FILES['userfile']['tmp_name']))
 4 {
 5     if(!move_uploaded_file($_FILES['userfile']['tmp_name'],$upload_file))
 6     {
 7         echo "fail";
 8     }else{
 9         echo "success";
10         echo $_FILES["userfile"]["name"];
11     }
12 }else
13 {
14     echo "fail";
15 }
16 echo "\n";
17 var_dump($_REQUEST);
18 var_dump($_FILES);
19 ?>

客户端程序:
模拟rfc1867给服务器发包:

 1 '''
 2 @note: rfc1867
 3 '''
 4 import httplib
 5 import os
 6 import time
 7 import mimetypes
 8 
 9 host = "***"
10 selector = "/***/upload.php"
11 
12 def get_packet_head(file_name, boundary):
13     def get_boundary(boundary):
14         return "--%s" % boundary
15     def get_file_type(file_name):
16         return mimetypes.guess_type(file_name)[0] or 'application/octet-stream'
17     
18     head = []
19     head.append(get_boundary(boundary))
20     head.append('Content-Disposition: form-data; name="userfile"; filename="%s"' % file_name)
21     head.append("Content-Type: %s" % get_file_type(file_name))
22     head.append("")
23     head.append("")
24     return "\r\n".join(head)
25 
26 def get_packet_tail(boundary):
27     def get_boundary_end(boundary):
28         return "--%s--" % boundary
29     tail = []
30     tail.append("")
31     tail.append(get_boundary_end(boundary))
32     return "\r\n".join(tail)
33 
34 def send_packet(file_path):
35     boundary = int(time.time() * 100)
36     file_name = os.path.basename(file_path)
37     
38     packet_head = get_packet_head(file_name, boundary)
39     packet_tail = get_packet_tail(boundary)
40     content_length = len(packet_head) + len(packet_tail) + os.path.getsize(file_path)
41     http_conn = httplib.HTTPConnection(host)
42     http_conn.putrequest("POST", selector)
43     http_conn.putheader("Content-Length", str(content_length))
44     http_conn.putheader("Content-Type", "multipart/form-data; boundary=%s" % boundary)
45     http_conn.endheaders()
46     http_conn.send(packet_head)
47     fp = open(file_path, "rb")
48     chunk_size = 1024
49     while True:
50         data = fp.read(chunk_size)
51         if not data:
52             break
53         http_conn.send(data)
54     http_conn.send(packet_tail)
55     print http_conn.getresponse().read()
56     
57 send_packet("tmp.txt")

个人觉得这个协议很坑,居然有boundary这种看起来这么随意的东西存在。
顺便说一下,编码过程中被自己挖的坑坑的很惨,事情是这样的:过程中手贱修改了Content-Disposition中的name字段,然后又大脑短路没有同步服务器端代码,导致怎么执行都echo "fail"。
当时真是有种吃了xx的感觉。抓包看内容,发现前后两次的包的大小不太一样,然后就发现name字段的诡异,后知后觉的我,到这个时候还没有发现问题所在,随手将name改回了"userfile",everything works ok!!!
擦擦,我天真的以为这个字段不能用"_",navie! 直到我瞥了一眼服务器代码里面的$_FILES['userfile'],摔!!!!好吧,自作孽不可活。。。
顺便说一句,The Girl with the Dragon Tattoo 真心不错。
再顺便说一句,今年可能要过双十一了,so kurushiiiiiiiiiii....

 

posted @ 2012-10-28 21:34  Abstr  阅读(410)  评论(0)    收藏  举报