Skip to content

Instantly share code, notes, and snippets.

@hardikamal
Created June 11, 2019 08:05
Show Gist options
  • Save hardikamal/100b8a845858f3bf2b08d859963132bd to your computer and use it in GitHub Desktop.
Save hardikamal/100b8a845858f3bf2b08d859963132bd to your computer and use it in GitHub Desktop.
Uploading a file with SWIFT via POST multipart/form-data (PHP)
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
}
}
}
<?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",
]);
}
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)
}
})
}
}
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)
}
})
}
}
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")
})
}
}
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