簡介
上傳文件到服務器是一個比較常用的操作,最基本的方式是通過POST上傳,文件以二進制形式,作爲一個參數傳遞,但是這個POST的結構相當複雜,且必須完全符合HTTP標準。
文件上傳的POST格式
該POST主要由下面幾個部分構成。
請求頭
1.Content-Length(請求體的二進制大小)- 注意這裏的二進制大小應該根據請求體計算
2.Content-Type multipart/form-data; boundary=(分隔符)
- 注意這裏的分隔符與請求體的分隔符有關,但不完全一致。
請求體
基本格式示例- 這裏的分隔符就是上面的分隔符,但是前面要多加兩個
'-'
。
--分隔符 Content-Disposition: form-data; name="uploadFile"; filename="button.png" Content-Type: image/png (此處空兩行) <二進制內容> --分隔符 Content-Disposition: form-data; name="submit" (此處空兩行) Submit --分隔符-- (此處空一行)
- 注意到最後的分隔符後面跟了
--
,這個代表結束符,並且後面要跟一個空行。
格式說明
普通參數
普通參數的構成如下:Content-Disposition: form-data; name="參數名" (此處空兩行) 參數值 --分隔符
多個參數可以連續拼接。
文件參數
文件參數與普通參數類似,只是多了一行MineType的說明,該說明告訴服務器文件的類型。Content-Disposition: form-data; name="uploadFile"; filename="button.png" Content-Type: image/png (此處空兩行) <二進制內容> --分隔符
將二者連起來就構成了完整的文件上傳POST信息,到這裏我們可以理解,該POST不僅發送了文件數據,還發送了一個參數。
- 這裏的分隔符就是上面的分隔符,但是前面要多加兩個
文件上傳的服務器php腳本
要讓post請求發揮作用,必須藉助php腳本實現對post的處理,換句話說,我們的post請求應該發送給該php腳本,腳本的代碼如下:(注意修改uploadPath爲自己服務器想要接收文件的路徑)
<?php header("Content-type: text/html; charset=utf-8"); // 配置文件需要上傳到服務器的路徑,需要允許所有用戶有可寫權限,否則無法上傳! $uploadPath = '../uploads/'; $IOS_forKey=$_FILES["uploadFile"]; if ($IOS_forKey["error"] > 0) { echo "傳入參數錯誤:" . $IOS_forKey["error"] . "<br />"; } else { echo "文件: " . $IOS_forKey["name"] . "<br />"; echo "類型: " . $IOS_forKey["type"] . "<br />"; echo "大小: " . ($IOS_forKey["size"] / 1024) . " Kb<br />"; echo "臨時文件: " . $IOS_forKey["tmp_name"] . "<br />"; chmod($uploadPath . $IOS_forKey["name"], 0666); if (file_exists($uploadPath . $IOS_forKey["name"])) { echo $IOS_forKey["name"] . "文件已經存在!"; } else { move_uploaded_file($IOS_forKey["tmp_name"], $uploadPath . $IOS_forKey["name"]); echo "上傳文件保存在: " . $uploadPath . $IOS_forKey["name"]; } } ?>
通過iOS設備上傳文件
想要通過iOS設備上傳文件,一般的做法是根據上面的結構創建URLRequset,然後發送該request到服務器請求上面的php腳本,實現文件的上傳,具體的代碼如下。
爲了方便插入二進制文件數據,我們直接使用data拼接,因此對於每一段字符串都需要轉爲data,這就是DataWithStr宏的作用。
爲了適配各個系統的換行符,使用\r\n。
FileBoundary就是上文提到的分隔符。
HTTP請求頭的contentLength需要待請求體拼接完畢後才能得到,因此最後才賦值。
#import "ViewController.h"
#import "UploadFile.h"
#define FileBoundary @"-----------------------------test"
#define EndLine @"-----------------------------test--\r\n"
#define NewLine @"\r\n"
#define DataWithStr(str) [str dataUsingEncoding:NSUTF8StringEncoding]
@interface ViewController ()
@end
@implementation ViewController
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self upload];
}
- (void)upload{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://127.0.0.1/lesson2/upload.php"]];
request.HTTPMethod = @"POST";
// 設置請求頭
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",FileBoundary];
[request setValue:contentType forHTTPHeaderField:@"Content-Type"];
// 設置請求體
NSMutableData *body = [NSMutableData data];
[body appendData:DataWithStr(@"--")];
[body appendData:DataWithStr(FileBoundary)];
[body appendData:DataWithStr(NewLine)];
[body appendData:DataWithStr(@"Content-Disposition: form-data; name=\"uploadFile\"; filename=\"test.png\"")];
[body appendData:DataWithStr(NewLine)];
[body appendData:DataWithStr(@"Content-Type: image/png")];
[body appendData:DataWithStr(NewLine)];
[body appendData:DataWithStr(NewLine)];
UIImage *img = [UIImage imageNamed:@"test.png"];
NSData *imgData = UIImagePNGRepresentation(img);
[body appendData:imgData];
[body appendData:DataWithStr(NewLine)];
// 其他參數
[body appendData:DataWithStr(@"--")];
[body appendData:DataWithStr(FileBoundary)];
[body appendData:DataWithStr(@"Content-Disposition: form-data; name=\"param1\"")];
[body appendData:DataWithStr(NewLine)];
[body appendData:DataWithStr(NewLine)];
[body appendData:DataWithStr(@"value1")];
[body appendData:DataWithStr(NewLine)];
[body appendData:DataWithStr(@"--")];
[body appendData:DataWithStr(EndLine)];
[request setValue:[NSString stringWithFormat:@"%ld",body.length] forHTTPHeaderField:@"Content-Length"];
request.HTTPBody = body;
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",result);
}];
}
@end