I've looked up other solutions to this question but I don't fully understand what they're doing, and I can't get mine to work.
Here's my swift code
let imageData = UIImageJPEGRepresentation(image, 1.0)
if(imageData == nil ) { return }
let request = NSMutableURLRequest(URL: NSURL(string: ip)!) //ip is a string variable holding my correct ip address
request.HTTPMethod = "POST"
request.setValue("Keep-Alive", forHTTPHeaderField: "Connection")
let postString = "id=\(id)&"
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
let body = NSMutableData()
body.appendData(postString.dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(imageData!)
request.HTTPBody = body
let task = session.uploadTaskWithRequest(request, fromData: imageData!)
task.resume()
And here's my PHP file
<?php
if (move_uploaded_file($_FILES['file']['tmp_name'], "image.jpg")) {
echo "File uploaded: ".$_FILES["file"]["name"];
}
else {
echo "File not uploaded";
}
?>
I have valid read and write access to the "image.jpg" file which sits on the front of my server, but it will still say that it could not upload the file. Any thoughts?
You're submitting the image as part of the POST request body. It won't be accessible using $_FILES.
You can Base-64 encode the image data, send the post string "id=\(id)&image=\(base64EncodedImageData)", then retrieve and decode it using $_POST.
You may want to consider using a networking library like Alamofire.
The manual and not recommended way: Change your PHP code to generate JSON responses.
echo json_encode(array("success" => true,
"filename" => basename($_FILES['image']['name']));
But as was mentioned you should let Alamofire do that for you. You can use MSProgress for a visual progress update in Alamofire.
let apiToken = "ABCDE"
Alamofire.upload(
.POST,
"http://sample.com/api/upload",
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(data: imageData, name: "yourParamName", fileName: "imageFileName.jpg", mimeType: "image/jpeg")
multipartFormData.appendBodyPart(data: apiToken.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"api_token")
multipartFormData.appendBodyPart(data: otherBodyParamValue.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"otherBodyParamName")
},
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.progress { (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in
print("Uploading Avatar \(totalBytesWritten) / \(totalBytesExpectedToWrite)")
dispatch_async(dispatch_get_main_queue(),{
/**
* Update UI Thread about the progress
*/
})
}
upload.responseJSON { (JSON) in
dispatch_async(dispatch_get_main_queue(),{
//Show Alert in UI
print("Avatar uploaded");
})
}
case .Failure(let encodingError):
//Show Alert in UI
print("Avatar uploaded");
}
}
);
Related
I uploaded an image using almofire and it is being uploaded to the correct path I require.
However, I need to get some of the responses that are in my PHP backend code into my swift such as the filepath.
An image to make my question more clear and precise about what I want to get from the .responseJSON
In the image below is my response from the PHP code, I want to get the value of the filepath in swift. How can I achieve that?
Here is my code:
PHP:
<?php
if (empty($_FILES["image"])) {
$response = array("error" => "nodata");
}
else {
$response['error'] = "NULL";
$filename = uniqid() . ".jpg";
if (move_uploaded_file($_FILES['image']['tmp_name'], "../propertyImages/" . $filename)) {
$response['status'] = "success";
$response['filepath'] = "https://example.com/WebService/propertyImages/" . $filename;
$response['filename'] = "".$_FILES["file"]["name"];
} else{
$response['status'] = "Failure";
$response['error'] = "".$_FILES["image"]["error"];
$response['name'] = "".$_FILES["image"]["name"];
$response['path'] = "".$_FILES["image"]["tmp_name"];
$response['type'] = "".$_FILES["image"]["type"];
$response['size'] = "".$_FILES["image"]["size"];
}
}
echo json_encode($response);
?>
Swift Code:
self.imageData = propImage.image!.jpegData(compressionQuality: 0.5)!
let headers: HTTPHeaders = [
"Content-type": "multipart/form-data"
]
AF.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(self.imageData!, withName: "image" , fileName: "file.jpg", mimeType: "image/jpeg")
},
to:"https://example.com/WebService/api/uploadPropImage.php", method: .post , headers: headers)
.responseJSON { resp in
//let responseString: String = String(data: self.imageData!, encoding: .utf8)!
print(resp) //this prints all the responses from the PHP code, my problem is how do i get a specific response, such as the filepath only and so on?
}
EDIT:
I tried some of the solutions, this one seems to be the one that will work but still gives an error reading
"No exact matches in call to class method 'jsonObject'"
Updated code:
AF.upload(multipartFormData: { multipartFormData in multipartFormData.append(self.imageData!, withName: "image" , fileName: "file.jpg", mimeType: "image/jpeg")}, to:"https://example.com/WebService/api/uploadPropImage.php", method: .post , headers: headers).responseJSON {
result in
do{
if let jsonResults = try JSONSerialization.jsonObject(with: result, options: []) as? [String: Any] { //error in this line
let filePath = jsonResults["filepath"] as? String
}
}catch{
print("ERROR")
}
Then just decode your response:
if let jsonResults = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
let filePath = jsonResults["filepath"] as? String // here is your value
}
The value of the responseJSON block, is a Result. It's a basic concept used frequently, so you need to learn how do handle it. Common practice is then to use a switch.
let headers: HTTPHeaders = ["Content-type": "multipart/form-data"]
AF.upload(multipartFormData: { multipartFormData in
multipartFormData.append(self.imageData!, withName: "image" , fileName: "file.jpg", mimeType: "image/jpeg")
},
to:"https://example.com/WebService/api/uploadPropImage.php", method: .post , headers: headers)
.responseJSON { result in
switch result {
case .success(let json):
guard let dictionary = json as? [String: Any] else { print("Response JSON is not a dictionary"); return }
guard let filePath = json["filePath"] as? String else { print("filePath key is not present in "\(json)" or is not a String"); return }
print("Filepath: \(filePath)")
case .failure(let error):
print("Error: \(error)")
}
}
Now, it might be better to use a Codable struct to parse your response and call responseDecodable() instead of using responseJSON() which will use JSONSerialization, method which is by the way deprecated and will be removed in next Alamofire major release.
Here is my swift code that uploads the file from application.
final class UploadService {
// I'm renting a remote server and the php code is on that
private let videoUploadPath = "http://myUploadPath.php"
var uploadsSession: URLSession!
var activeUploads: [URL: Upload] = [:]
func startUpload(medium: Medium) {
guard let url = URL(string: videoUploadPath) else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
let upload = Upload(medium: medium)
upload.task = self.uploadsSession.uploadTask(with: request, fromFile: medium.avUrlAsset.url)
upload.task?.resume()
upload.isUploading = true
activeUploads[upload.medium.avUrlAsset.url] = upload
}
}
Note that I have to use
func uploadTask(with request: URLRequest, fromFile fileURL: URL) -> URLSessionUploadTask
// Apple documentation:
Parameters
request
A URL request object that provides the URL, cache policy, request type,
and so on. The body stream and body data in this request object are ignored.
to upload video from phone, since that's the only method that allows background upload (videos are normally pretty big, therefore I HAVE TO make background upload possible). However, this function discard all body data.
Here is the my PHP code that receives the uploaded file and stores it in the desired location:
$directory = "../storage/videos/";
$destination = $directory . basename($_FILES["file"]["name"]);
if (move_uploaded_file($_FILES["file"]["tmp_name"], $destination)) {
$returnArray["status"] = "200";
$returnArray["message"] = "Upload success";
echo json_encode($returnArray);
} else {
$returnArray["status"] = "300";
$returnArray["message"] = "Upload failed" . $_FILES["file"]["error"];
echo json_encode($returnArray);
return;
}
To be honest, I know it won't succeed, because I have no way to specify the file type and name, which are required by $_FILES["file"]["name"] in the PHP code.
Therefore, my question is, how to specify file name and type to be uploaded? Since the function
func uploadTask(with request: URLRequest, fromFile fileURL: URL) -> URLSessionUploadTask
discards all http body data, as I mentioned, perhaps making an http header that contains the file type and name? OR, is there another way for PHP to receive the file I just uploaded? For now, the $_FIELS is completely empty. I'm new to PHP, sorry if I didn't say it clearly enough.
Also, for Content-Type, I was using multipart/form-data when I upload an image to change user's profile image, I append the image data together with other data like uid, then attach those data as the body data in the http body. But now, I need to upload a single file, because all body data in the request will be ignored per iOS requirement. How can I do this?
Many days stuck in this, please help. Many thanks!!
There is a way to keep the URLSession.shared.uploadTask call and use the raw data on the PHP side. Here's an example that worked for me with JSON data:
Using sample code from https://developer.apple.com/documentation/foundation/url_loading_system/uploading_data_to_a_website for the Swift side
SWIFT side:
struct Order: Codable {
let customerId: String
let items: [String]
}
// ...
let order = Order(customerId: "12345",
items: ["Cheese pizza", "Diet soda"])
guard let uploadData = try? JSONEncoder().encode(order) else {
return
}
let url = URL(string: "https://example.com/upload.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.uploadTask(with: request, from: uploadData) { data, response, error in
if let error = error {
print ("error: \(error)")
return
}
guard let response = response as? HTTPURLResponse,
(200...299).contains(response.statusCode) else {
print ("server error")
return
}
if let mimeType = response.mimeType,
mimeType == "application/json",
let data = data,
let dataString = String(data: data, encoding: .utf8) {
print ("got data: \(dataString)")
}
}
task.resume()
PHP side: (upload.php)
<?php
header('Content-Type: application/json; charset=utf-8');
$response = array();
try {
$uploaddir = './uploads/';
$uploadfile = $uploaddir . 'test.json';
$rawdata = file_get_contents('php://input');
if (!file_put_contents($uploadfile, $rawdata)) {
throw new RuntimeException('Failed to create file.');
}
$response = array(
"status" => "success",
"error" => false,
"message" => "File created successfully"
);
echo json_encode($response);
} catch (RuntimeException $e) {
$response = array(
"status" => "error",
"error" => true,
"message" => $e->getMessage()
);
echo json_encode($response);
}
?>
This will also write binary data into a file. In this simple case, there is no need to know the file name or content type. It may not work for a generic case, but this way of proceeding allows you to keep using URLSession.shared.uploadTask and avoid HTTP Body parameters.
HTH.
Code Revised based on suggestion solution but still not working. Videos are uploading as 0 bytes. I have an app where a user should be able to record a video from their phone and when 'Use Video' is selected it uploads the video to our PHP Server. The file is uploading successfully and based on the size shown it is not empty. However when I go to play the video in the app or even directly through the browser it won't play. There's no issue with the playback code as I've hardcoded links to other videos on other sites and it works fine. Code is below, any help is much appreciated.
// Finished recording a video
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
print("Got a video")
if let pickedVideo:URL = (info[UIImagePickerControllerMediaURL] as? URL) {
// Save video to the main photo album
let selectorToCall = #selector(CameraVideoViewController.videoWasSavedSuccessfully(_:didFinishSavingWithError:context:))
UISaveVideoAtPathToSavedPhotosAlbum(pickedVideo.relativePath, self, selectorToCall, nil)
imageSelected = true
uuid = UUID().uuidString
if imageSelected == true {
saveFileName = "video-\(uuid).mp4"
}
// Save the video to the app directory so we can play it later
let videoData = try? Data(contentsOf: pickedVideo)
let paths = NSSearchPathForDirectoriesInDomains(
FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let documentsDirectory: URL = URL(fileURLWithPath: paths[0])
let dataPath = documentsDirectory.appendingPathComponent(saveFileName)
try! videoData?.write(to: dataPath, options: [])
print("Saved to " + dataPath.absoluteString)
imagePicker.dismiss(animated: true, completion: {
// Anything you want to happen when the user saves an video
self.encodeVideo(dataPath: dataPath)
self.uploadVideo(videoData!)
})
} }
// MP4 Conversion of video
func encodeVideo(dataPath: URL){
let avAsset = AVURLAsset(url: dataPath)
let startDate = Date()
let exportSession = AVAssetExportSession(asset: avAsset, presetName: AVAssetExportPresetPassthrough)
let docDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let myDocPath = NSURL(fileURLWithPath: docDir).appendingPathComponent("temp.mp4")?.absoluteString
let docDir2 = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as NSURL
let filePath = docDir2.appendingPathComponent("rendered-Video.mp4")
//uploadVideo(filePath)
//self.encodeVideo(dataPath: dataPath)
deleteFile(filePath!)
if FileManager.default.fileExists(atPath: myDocPath!){
do{
try FileManager.default.removeItem(atPath: myDocPath!)
}catch let error{
print(error)
}
}
//self.uploadVideo((myDocPath as AnyObject) as! URL)
exportSession?.outputURL = filePath
exportSession?.outputFileType = AVFileType.mp4
exportSession?.shouldOptimizeForNetworkUse = true
let start = CMTimeMakeWithSeconds(0.0, 0)
let range = CMTimeRange(start: start, duration: avAsset.duration)
exportSession?.timeRange = range
exportSession!.exportAsynchronously{() -> Void in
switch exportSession!.status{
case .failed:
print("\(exportSession!.error!)")
case .cancelled:
print("Export cancelled")
case .completed:
let endDate = Date()
let time = endDate.timeIntervalSince(startDate)
print(time)
print("Successful")
print(exportSession?.outputURL ?? "")
default:
break
}
}
}
func deleteFile(_ filePath:URL) {
guard FileManager.default.fileExists(atPath: filePath.path) else {
return
}
do {
try FileManager.default.removeItem(atPath: filePath.path)
}catch{
fatalError("Unable to delete file: \(error) : \(#function).")
}
}
// Create Params
func createBodyWithParams(_ parameters: [String: String]?, filePathKey: String?, videoData: Data, boundary: String) -> Data {
var body = ""
if let params = parameters {
for (key, value) in params {
body += "--\(boundary)\r\n"
body += "Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n"
body += "\(value)\r\n"
}
}
var filename = ""
if imageSelected {
filename = "video-\(uuid).mp4"
}
let mimetype = "video/mp4"
body += "--\(boundary)\r\n"
body += "Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n"
body += "Content-Type: \(mimetype)\r\n\r\n"
body += String(data: videoData, encoding: .utf8)!
body += "\r\n"
body += "--\(boundary)--\r\n"
return Data(body.utf8)
}
// function sending request to PHP to upload a file
func uploadVideo(_ videoData: Data) {
let id = user!["id"] as! String
uuid = UUID().uuidString
let url = URL(string: "http://www.foo.com/videoposts.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let param = [
"id" : id,
"uuid" : uuid
]
// body
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
// if picture is selected, compress it by half
let imageData = Data()
// ... body
request.httpBody = createBodyWithParams(param, filePathKey: "file", videoData: imageData, boundary: boundary)
// launch session
URLSession.shared.dataTask(with: request) { data, response, error in
// get main queu to communicate back to user
DispatchQueue.main.async(execute: {
if error == nil {
do {
// json containes $returnArray from php
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
// declare new var to store json inf
guard let parseJSON = json else {
print("Error while parsing")
return
}
// get message from $returnArray["message"]
let message = parseJSON["message"]
// if there is some message - post is made
if message != nil {
// reset UI
self.postBtn.alpha = 0.4
self.imageSelected = false
// switch to another scene
self.tabBarController?.selectedIndex = 4
}
} catch {
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = "\(error)"
appDelegate.infoView(message: message, color: colorSmoothRed)
})
return
}
} else {
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = error!.localizedDescription
appDelegate.infoView(message: message, color: colorSmoothRed)
})
return
}
})
}.resume()
}
Okay, I did code something to actually encode and upload a video.
Unfortunately, doing a multipart/form-data in URLSession is actually pretty hard, so I used Alamofire to actually upload the video.
This is the code in parts:
UIImagePickerControllerDelegate (this is the one you should modify, check the //TODO comments)
// MARK: UIImagePickerControllerDelegate
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
print("Cancelled video operation.")
dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
guard let mediaType = info[UIImagePickerControllerMediaType] as? String else {
print("Error with media type. Cancelling.")
dismiss(animated: true, completion: nil)
return;
}
print("Media type: \(mediaType)")
if ( mediaType == "public.movie" ) { // Video selected
let videoURL: URL
if info[UIImagePickerControllerMediaURL] != nil {
videoURL = info[UIImagePickerControllerMediaURL] as! URL
}
else {
videoURL = info[UIImagePickerControllerReferenceURL] as! URL
}
if ( picker.sourceType == .camera ) {
// The original video came from the camera, so it's considered new
// Save it to the photo library
saveVideo(url: videoURL, albumName: "MyApp")
}
// Dismiss the media picker and then re-encode the video
dismiss(animated: true) {
self.exportVideoToMP4(url: videoURL) { (exportedVideoURL) in
guard let tempURL = exportedVideoURL else {
print("ERROR: Unknown error. The exported video URL is nil.")
return
}
print("Temporary video successfully exported to: \(tempURL.absoluteString)")
// TODO: Add your own POST parameters
let uuid = UUID().uuidString
let params = [
"uuid" : uuid,
"user" : "myUserNameOrWhatever"
]
// TODO: Change the parameters for uploading
self.upload( to: "http://yourweb.com/uploadVideo.php", // The URL to send the upload to
videoURL: tempURL, // The file URL of the temporary video file
parameters: params, // The POST parameters you want to send along with the upload
fileName: "vid-\(uuid).mp4", // The filename you want the server to receive.
fieldName: "video_file" // This is "name" from <input type="file" name="video_file" ... /> in HTML
) { (response) in
guard let resp = response else {
print("ERROR: Empty or unrecognizable response from server.")
return
}
print("Video uploaded. RESPONSE: \(resp)")
//: TODO Parse the server response after uploading
}
}
}
}
}
Photo Library helper methods
// MARK: Photo Library
func saveVideo(url: URL, albumName: String) {
// Check authorization status before trying to save the video
switch PHPhotoLibrary.authorizationStatus() {
case .notDetermined:
PHPhotoLibrary.requestAuthorization() { (status) in
switch status {
case .authorized:
self.saveVideo(url: url, albumName: albumName) // Re-try to save the video after authorization
return
default:
return
}
}
case .authorized:
// Save the video to the Photo Library here
if let assetCollection = assetCollection(albumName: albumName) {
// Asset collection exists, insert directly
insertVideo(url: url, assetCollection: assetCollection)
}
else {
// Asset collection doesn't exist, create it and then insert
PHPhotoLibrary.shared().performChanges({
PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: albumName)
}, completionHandler: { (success, error) in
guard success else {
print("ERROR: \(error!.localizedDescription)")
return
}
let createdAssetCollection = self.assetCollection(albumName: albumName)!
self.insertVideo(url: url, assetCollection: createdAssetCollection)
})
}
return
default:
// Not authorized
print("Not authorized to save a video to the Photo Library.")
return
}
}
func assetCollection(albumName: String) -> PHAssetCollection? {
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format:"title == '\(albumName)'")
let fetchResult = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .albumRegular, options: fetchOptions)
return fetchResult.firstObject
}
func insertVideo(url: URL?, assetCollection: PHAssetCollection) {
guard let videoURL = url else {
print("ERROR: The URL to insert into the Photo Library is empty.")
return
}
PHPhotoLibrary.shared().performChanges({
let createAssetRequest = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL)
let assetPlaceholder = createAssetRequest?.placeholderForCreatedAsset
let changeRequest = PHAssetCollectionChangeRequest(for: assetCollection)
let enumeration: NSArray = [assetPlaceholder!]
changeRequest?.addAssets(enumeration)
}, completionHandler: { (success, error) in
guard success else {
print("ERROR: \(error!.localizedDescription)")
return
}
print("Video saved successfully to the Photo Library album.")
})
}
Video Uploading (using Alamofire, installed from CocoaPods)
// MARK: Video upload
func upload(to uploadAddress: String, videoURL: URL, parameters: [String:Any]?, fileName: String, fieldName: String, _ completion: ((String?) -> Void)?) {
Alamofire.upload(multipartFormData: { (multipartFormData) in
// Add the video file (if data is correct)
if let videoData = FileManager.default.contents(atPath: videoURL.path) {
multipartFormData.append(videoData, withName: fileName)
}
// Add the post params (if available)
if let params = parameters {
for (key, value) in params {
multipartFormData.append( (value as! String).data(using: .utf8)! , withName: key)
}
}
}, to: uploadAddress)
{ (result) in
switch result {
case .success(let upload, _, _):
upload.responseString { (response) in
if let completionHandler = completion {
completionHandler(response.result.value)
}
}
case .failure(let encodingError):
print("ERROR: \(encodingError.localizedDescription)")
if let completionHandler = completion {
completionHandler(nil)
}
}
}
}
AVFoundation (the encoding method)
// MARK: AVFoundation
func exportVideoToMP4(url: URL, _ completion: #escaping ((URL?) -> Void)) {
// Show some sort of indicator here, as this could take a while
// Generate a temporary URL path to export the video
let relativePath = "myAppTempVideoExport.mp4";
let outputFilePath = NSTemporaryDirectory() + relativePath;
print("Temp file path: \(outputFilePath)")
// If there's any temp file from before at that path, delete it
if FileManager.default.fileExists(atPath: outputFilePath) {
do {
try FileManager.default.removeItem(atPath: outputFilePath)
}
catch {
print("ERROR: Can't remove temporary file from before. Cancelling export.")
completion(nil)
return
}
}
// Export session setup
let outputFileURL = URL(fileURLWithPath: outputFilePath)
let asset = AVAsset(url: url) // Original (source) video
// The original video codec is probably HEVC, so we'll force the system to re-encode it at the highest quality in MP4
// You probably want to use medium quality if this video is intended to be uploaded (as this example is doing)
if let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) {
exportSession.outputURL = outputFileURL
exportSession.outputFileType = .mp4
exportSession.exportAsynchronously {
// Hide the indicator for the export session
switch exportSession.status {
case .completed:
print("Video export completed.")
completion(outputFileURL)
return
case .failed:
print("ERROR: Video export failed. \(exportSession.error!.localizedDescription)")
completion(nil)
return
case .cancelled:
print("Video export cancelled.")
completion(nil)
return
default:
break
}
}
}
else {
print("ERROR: Cannot create an AVAssetExportSession.")
return
}
}
Now, for this to work, you obviously have to record a video, import frameworks and specify that your view controller conforms to protocols, so:
import AVFoundation
import Photos
import Alamofire
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
let imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
imagePicker.sourceType = .camera
imagePicker.delegate = self
imagePicker.showsCameraControls = true
imagePicker.allowsEditing = true
imagePicker.mediaTypes = ["public.movie"]
DispatchQueue.main.async {
self.present(self.imagePicker, animated: true, completion: nil)
}
}
}
I hope this is useful to you, feel free to ask.
Working on a Swift project, and apparently the file I'm uploading isn't an image. I'm also using the Alamofire utility.
let uuid = NSUUID().UUIDString
print ("MARK -- UUID is " + uuid)
let image = imageView.image
Alamofire.upload(.POST, "{RETRACTED}", multipartFormData: {
multipartFormData in
if let imageData = UIImageJPEGRepresentation(image!, 0.6) {
multipartFormData.appendBodyPart(data: imageData, name: uuid, fileName: uuid + ".png", mimeType: "image/png")
}
}, encodingCompletion: {
encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.responseJSON { response in
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
if let JSON = response.result.value {
print ("JSON \(JSON)")
self.displayAlert("Uploaded!", message: "{RETRACTED}", responseButtonText: "{RETRACTED}")
}
}
case .Failure(let encodingError):
print(encodingError)
}
})
Here's the JSON response (I also have the PHP server side code if needed):
JSON {
response = "That file wasn't an image (Only .png and .jpg/.jpeg images are accepted). The type is ";
responseCode = 0;
}
Thanks guys.
You are sending an jpg image, but specifying mime type for png. Change mime type to "image/jpeg" or send a png file.
I'm using this code (Swift) to upload an image that user selected from their photos to a server:
let imageFormatted = UIImageJPEGRepresentation(imageView.image!, 0.5);
let uuid = NSUUID().UUIDString
print ("MARK -- UUID is " + uuid)
Alamofire.upload(
.POST,
"http://www.memer.onlie/upload.php",
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(data: imageFormatted!, name: "imagefile",
fileName: uuid + ".jpg", mimeType: "image/jpeg")
},
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.validate()
upload.responseJSON { response in
dispatch_async(dispatch_get_main_queue()) {
self.displayAlert("Uploaded!", message: "Your meme was uploaded, and you might see it in the app soon!", responseButtonText: "<3")
}
var json = JSON(data: response.data!)
print ("MARK -- JSON response: " + json["response"].stringValue)
}
print ("MARK -- Upload success!")
case .Failure(let encodingError):
print(encodingError)
print ("MARK -- Upload failure!")
self.displayAlert("Issue uploading.", message: "There was an issue uploading your meme.", responseButtonText: "Aww :(")
}
}
)
No image is being uploaded to the server. What can I correct to get this to work?
Edited code.
This thread helps you understand what you have not considered and what you need to do to solve the issue. I guess you need to set request header and body part properly. If you use Alamofire and have to use 'multipart/form-data' encoding type, you can write code like this.
Alamofire.upload(.POST, destURL, headers: yourHeader, multipartFormData: { multipartFormData in
if let imageData = UIImageJPEGRepresentation(image, 0.5) {
multipartFormData.appendBodyPart(data: imageData, name:"file", fileName: "imagefile", mimeType: "image/jpg")
}
// Append parameters you should send
for (key, value) in parameters {
multipartFormData.appendBodyPart(data: value.dataUsingEncoding(NSUTF8StringEncoding)!, name: key)
}
}, encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.validate()
upload.responseJSON { response in
// do something if response is success
}
case .Failure(_):
// do something if response is fail
}
})