Last active
August 29, 2015 14:27
-
-
Save vsrc/1907d434d6b502ce91a3 to your computer and use it in GitHub Desktop.
Uploading a file with SWIFT via POST multipart/form-data (PHP)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import Alamofire | |
public enum Router:URLRequestConvertible { | |
public static let baseUrlString:String = "http://testapi.example.com" | |
case Upload(fieldName: String, fileName: String, mimeType: String, fileContents: NSData, boundaryConstant:String); | |
var method: Alamofire.Method { | |
switch self { | |
case Upload: | |
return .POST | |
default: | |
return .GET | |
} | |
} | |
var path: String { | |
switch self { | |
case Upload: | |
return "/testupload.php" | |
default: | |
return "/" | |
} | |
} | |
public var URLRequest: NSURLRequest { | |
var URL: NSURL = NSURL(string: ListsRouter.baseUrlString)! | |
var mutableURLRequest = NSMutableURLRequest(URL: URL.URLByAppendingPathComponent(path)) | |
mutableURLRequest.HTTPMethod = method.rawValue | |
switch self { | |
case .Upload(let fieldName, let fileName, let mimeType, let fileContents, let boundaryConstant): | |
let contentType = "multipart/form-data; boundary=" + boundaryConstant | |
var error: NSError? | |
let boundaryStart = "--\(boundaryConstant)\r\n" | |
let boundaryEnd = "--\(boundaryConstant)--\r\n" | |
let contentDispositionString = "Content-Disposition: form-data; name=\"\(fieldName)\"; filename=\"\(fileName)\"\r\n" | |
let contentTypeString = "Content-Type: \(mimeType)\r\n\r\n" | |
// Prepare the HTTPBody for the request. | |
let requestBodyData : NSMutableData = NSMutableData() | |
requestBodyData.appendData(boundaryStart.dataUsingEncoding(NSUTF8StringEncoding)!) | |
requestBodyData.appendData(contentDispositionString.dataUsingEncoding(NSUTF8StringEncoding)!) | |
requestBodyData.appendData(contentTypeString.dataUsingEncoding(NSUTF8StringEncoding)!) | |
requestBodyData.appendData(fileContents) | |
requestBodyData.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) | |
requestBodyData.appendData(boundaryEnd.dataUsingEncoding(NSUTF8StringEncoding)!) | |
mutableURLRequest.setValue(contentType, forHTTPHeaderField: "Content-Type") | |
mutableURLRequest.HTTPBody = requestBodyData | |
return Alamofire.ParameterEncoding.URL.encode(mutableURLRequest, parameters: nil).0 | |
default: | |
return mutableURLRequest | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* File: testupload.php */ | |
$target_dir = "uploads/"; | |
$target_dir = $target_dir . basename($_FILES["uploadFile"]["name"]); | |
if (move_uploaded_file($_FILES["uploadFile"]["tmp_name"], $target_dir)) { | |
echo json_encode([ | |
"Message" => "The file ". basename( $_FILES["uploadFile"]["name"]). " has been uploaded.", | |
"Status" => "OK", | |
]); | |
} else { | |
echo json_encode([ | |
"Message" => "Sorry, there was an error uploading your file.", | |
"Status" => "Error", | |
]); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class UploadController { | |
public typealias CompletionHandler = (obj:AnyObject?, success: Bool?) -> Void | |
public func UploadNative(filePath: NSURL, _ aHandler: CompletionHandler?) -> Void { | |
let url:NSURL? = NSURL(string: "http://testapi.example.com/testupload.php") | |
let cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData | |
var request = NSMutableURLRequest(URL: url!, cachePolicy: cachePolicy, timeoutInterval: 2.0) | |
request.HTTPMethod = "POST" | |
// Set Content-Type in HTTP header. | |
let boundaryConstant = "Boundary-7MA4YWxkTLLu0UIW"; // This should be auto-generated. | |
let contentType = "multipart/form-data; boundary=" + boundaryConstant | |
let fileName = filePath.path!.lastPathComponent | |
let mimeType = "text/csv" | |
let fieldName = "uploadFile" | |
request.setValue(contentType, forHTTPHeaderField: "Content-Type") | |
// Set data | |
var error: NSError? | |
var dataString = "--\(boundaryConstant)\r\n" | |
dataString += "Content-Disposition: form-data; name=\"\(fieldName)\"; filename=\"\(fileName)\"\r\n" | |
dataString += "Content-Type: \(mimeType)\r\n\r\n" | |
dataString += String.stringWithContentsOfFile(filePath.path!, encoding: NSUTF8StringEncoding, error: &error)! | |
dataString += "\r\n" | |
dataString += "--\(boundaryConstant)--\r\n" | |
println(dataString) // This would allow you to see what the dataString looks like. | |
// Set the HTTPBody we'd like to submit | |
let requestBodyData = (dataString as NSString).dataUsingEncoding(NSUTF8StringEncoding) | |
request.HTTPBody = requestBodyData | |
// Make an asynchronous call so as not to hold up other processes. | |
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response, dataObject, error) in | |
if let apiError = error { | |
aHandler?(obj: error, success: false) | |
} else { | |
aHandler?(obj: dataObject, success: true) | |
} | |
}) | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class UploadController { | |
public typealias CompletionHandler = (obj:AnyObject?, success: Bool?) -> Void | |
public func UploadWithAlamofire(filePath: NSURL, _ aHandler: CompletionHandler?) -> Void { | |
// Set Content-Type in HTTP header | |
let boundaryConstant = "Boundary-7MA4YWxkTLLu0UIW"; | |
let contentType = "multipart/form-data; boundary=" + boundaryConstant | |
let accessTokenHeader = "" | |
var fileData : NSData? | |
if let fileContents = NSFileManager.defaultManager().contentsAtPath(filePath.path!) { | |
fileData = fileContents | |
} | |
let fileName = filePath.path!.lastPathComponent | |
let mimeType = "text/csv" | |
let fieldName = "uploadFile" | |
Alamofire.request(ListsRouter.Upload(fieldName: fieldName, fileName: fileName, mimeType: mimeType, fileContents: fileData!, boundaryConstant: boundaryConstant)) | |
.responseJSON {(request, response, JSON, error) in | |
if let apiError = error { | |
completionHandler?(obj: error, success: false) | |
} else { | |
if let status = JSON?.valueForKey("Status") as? NSString { | |
if (status == "OK") { | |
aHandler?(obj: JSON, success: true) | |
} else { | |
aHandler?(obj: JSON, success: false) | |
} | |
} | |
} | |
} | |
} | |
public func UploadNative(filePath: NSURL, _ aHandler: CompletionHandler?) -> Void { | |
let url:NSURL? = NSURL(string: "http://testapi.example.com/testupload.php") | |
let cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData | |
var request = NSMutableURLRequest(URL: url!, cachePolicy: cachePolicy, timeoutInterval: 2.0) | |
request.HTTPMethod = "POST" | |
// Set Content-Type in HTTP header. | |
let boundaryConstant = "Boundary-7MA4YWxkTLLu0UIW"; // This should be auto-generated. | |
let contentType = "multipart/form-data; boundary=" + boundaryConstant | |
let fileName = filePath.path!.lastPathComponent | |
let mimeType = "text/csv" | |
let fieldName = "uploadFile" | |
request.setValue(contentType, forHTTPHeaderField: "Content-Type") | |
// Set data | |
var error: NSError? | |
var dataString = "--\(boundaryConstant)\r\n" | |
dataString += "Content-Disposition: form-data; name=\"\(fieldName)\"; filename=\"\(fileName)\"\r\n" | |
dataString += "Content-Type: \(mimeType)\r\n\r\n" | |
dataString += String(contentsOfFile: filePath.path!, encoding: NSUTF8StringEncoding, error: &error)! | |
dataString += "\r\n" | |
dataString += "--\(boundaryConstant)--\r\n" | |
println(dataString) // This would allow you to see what the dataString looks like. | |
// Set the HTTPBody we'd like to submit | |
let requestBodyData = (dataString as NSString).dataUsingEncoding(NSUTF8StringEncoding) | |
request.HTTPBody = requestBodyData | |
// Make an asynchronous call so as not to hold up other processes. | |
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response, dataObject, error) in | |
if let apiError = error { | |
aHandler?(obj: error, success: false) | |
} else { | |
aHandler?(obj: dataObject, success: true) | |
} | |
}) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import SwiftyUploader // This is the assumed module we're building | |
import XCTest | |
class UploadControllerTests : XCTestCase { | |
override func setUp() { | |
super.setUp() | |
} | |
override func tearDown() { | |
super.tearDown() | |
} | |
func testUploadNative() { | |
// Get hold of an instance of the class containing the method we'd like to test. | |
let myUploadController: UploadController = UploadController() | |
// Get hold of the file we'd like to upload (mydata.csv) which contains comma separated values. | |
let URL: NSURL? = NSBundle(forClass: self.dynamicType).URLForResource("mydata", withExtension: "csv") | |
// Expectations allows us to test asynchronous methods. Hence we're setting up one here. | |
let setUploadExpectation = self.expectationWithDescription("Upload file for processing.") | |
// Upload! | |
myUploadController.UploadNative(URL!, {(responseObject, success) in | |
var message: String? | |
var status: String? | |
// Get an NSData out of the responseObject. | |
let data = responseObject as? NSData | |
// Apply some JSON serialization to the NSData instance. | |
let jsonData: AnyObject? = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: nil) | |
if let jsonObject = jsonData as? Dictionary<String, AnyObject> { | |
if(success == false) { | |
XCTFail("The request sent to TotalSend API Service was unsuccessful.") | |
} else { | |
if let message: NSString = jsonObject["Message"] as? NSString { | |
XCTAssertNotNil(message.containsString(" has been uploaded."), "File should be successfully uploaded.") | |
} | |
if let status = jsonObject["Status"] as? NSString { | |
XCTAssertEqual("OK", status, "Status should be OK.") | |
} | |
} | |
} else { | |
XCTFail("No appropriate response from TotalSend API Service: Received: No JSON Object.") | |
} | |
// Fulfill the expectation that we've set earlier. | |
setUploadExpectation.fulfill() | |
}) | |
// Loop for about 10 seconds until the expectation gets fulfilled. | |
// If it does not within the allocated time, we've got an error. | |
self.waitForExpectationsWithTimeout(10, handler: {(error) in | |
XCTAssertNil(error, "Error") | |
}) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import SwiftyUploader // This is the assumed module we're building | |
import XCTest | |
class UploadControllerTests : XCTestCase { | |
override func setUp() { | |
super.setUp() | |
} | |
override func tearDown() { | |
super.tearDown() | |
} | |
func testUploadWithAlamofire() { | |
// Get hold of an instance of the class containing the method we'd like to test. | |
let myUploadController: UploadController = UploadController() | |
// Get hold of the file we'd like to upload (mydata.csv) which contains comma separated values. | |
let URL: NSURL? = NSBundle(forClass: self.dynamicType).URLForResource("mydata", withExtension: "csv") | |
// Expectations allows us to test asynchronous methods. Hence we're setting up one here. | |
let expectation = self.expectationWithDescription("Upload file via Alamofire for processing.") | |
// Upload! | |
myUploadController.UploadWithAlamofire(URL!, {(responseObject, success) in | |
var message: String? | |
var status: String? | |
if let jsonObject = responseObject as? Dictionary<String, AnyObject> { | |
if(success == false) { | |
XCTFail("The request sent to TotalSend API Service was unsuccessful.") | |
} else { | |
if let message: NSString = jsonObject["Message"] as? NSString { | |
XCTAssertNotNil(message.containsString(" has been uploaded."), "File should be successfully uploaded.") | |
} | |
if let status = jsonObject["Status"] as? NSString { | |
XCTAssertEqual("OK", status, "Status should be OK.") | |
} | |
} | |
} else { | |
XCTFail("No appropriate response from TotalSend API Service: Received: No JSON Object.") | |
} | |
// Fulfill the expectation that we've set earlier. | |
expectation.fulfill() | |
}) | |
// Loop for about 10 seconds until the expectation gets fulfilled. | |
// If it does not within the allocated time, we've got an error. | |
self.waitForExpectationsWithTimeout(10, handler: {(error) in | |
XCTAssertNil(error, "Error") | |
}) | |
} | |
func testUploadNative() { | |
// Get hold of an instance of the class containing the method we'd like to test. | |
let myUploadController: UploadController = UploadController() | |
// Get hold of the file we'd like to upload (mydata.csv) which contains comma separated values. | |
let URL: NSURL? = NSBundle(forClass: self.dynamicType).URLForResource("mydata", withExtension: "csv") | |
// Expectations allows us to test asynchronous methods. Hence we're setting up one here. | |
let setUploadExpectation = self.expectationWithDescription("Upload file for processing.") | |
// Upload! | |
myUploadController.UploadNative(URL!, {(responseObject, success) in | |
var message: String? | |
var status: String? | |
// Get an NSData out of the responseObject. | |
let data = responseObject as? NSData | |
// Apply some JSON serialization to the NSData instance. | |
let jsonData: AnyObject? = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: nil) | |
if let jsonObject = jsonData as? Dictionary<String, AnyObject> { | |
if(success == false) { | |
XCTFail("The request sent to TotalSend API Service was unsuccessful.") | |
} else { | |
if let message: NSString = jsonObject["Message"] as? NSString { | |
XCTAssertNotNil(message.containsString(" has been uploaded."), "File should be successfully uploaded.") | |
} | |
if let status = jsonObject["Status"] as? NSString { | |
XCTAssertEqual("OK", status, "Status should be OK.") | |
} | |
} | |
} else { | |
XCTFail("No appropriate response from TotalSend API Service: Received: No JSON Object.") | |
} | |
// Fulfill the expectation that we've set earlier. | |
setUploadExpectation.fulfill() | |
}) | |
// Loop for about 10 seconds until the expectation gets fulfilled. | |
// If it does not within the allocated time, we've got an error. | |
self.waitForExpectationsWithTimeout(10, handler: {(error) in | |
XCTAssertNil(error, "Error") | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment