I am working on a project wherein I'd like to select an image and then upload it to the server. I am able to click the upload image button, select an image, and change the image in the iOS simulator but the upload fails. When I include a print(request)
after the request.httpBody = creatBodyWithParams()
statement, it shows that the original url has not changed. I am using XAMPP to set up a virtual server and php to communicate with it.
My code:
// upload image button clicked
@IBAction func edit_click(_ sender: Any) {
// select image
let picker = UIImagePickerController()
picker.delegate = self
//picker.sourceType = UIImagePickerControllerSourceType.photoLibrary
picker.allowsEditing = true
self.present(picker, animated: true, completion: nil)
}
// selected image
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
avaImg.image = info[UIImagePickerControllerEditedImage] as? UIImage
self.dismiss(animated: true, completion: nil)
// call function of uploading image file to server
uploadImage()
}
// create body of HTTP request to upload image file
func createBodyWithParams(parameters: [String : String]?, filePathKey: String?, imageDataKey: NSData, boundary: String) -> NSData {
let body = NSMutableData();
if parameters != nil {
for (key, value) in parameters! {
body.appendString(string: "--\(boundary)\r\n")
body.appendString(string: "Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.appendString(string: "\(value)\r\n")
}
}
let filename = "image.jpg"
let mimetype = "image/jpg"
body.appendString(string: "--\(boundary)\r\n")
body.appendString(string: "Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n")
body.appendString(string: "Content-Type: \(mimetype)\r\n\r\n")
body.append(imageDataKey as Data)
body.appendString(string: "\r\n")
body.appendString(string: "--\(boundary)--\r\n")
return body
}
// upload image to server
func uploadImage() {
let id = user!["id"] as! String
let address = URL(string: "http://localhost/project/uploadImage.php")!
var request = URLRequest(url: address)
request.httpMethod = "POST"
let param = ["id" : id]
let boundary = "Boundary-\(NSUUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let imageData = UIImageJPEGRepresentation(avaImg.image!, 0.5)
if imageData == nil {
return
}
request.httpBody = createBodyWithParams(parameters: param, filePathKey: "file", imageDataKey: imageData! as NSData, boundary: boundary) as Data
// launch session
let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
// get main queue to communicate back to user
DispatchQueue.main.async {
if error == nil {
do {
let json = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary
guard let parseJSON = json else {
print("error while parsing")
return
}
print(parseJSON)
} catch {
print("Caught an error: \(error)")
}
} else {
print(error)
}
}
})
task.resume()
}
With the following extension:
// creating protocol of appending string to var of type data
extension NSMutableData {
appendString(string : String) {
let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
append(data!)
}
}
I have consulted the following pages for help and have tried changing my code to reflect the differences in their approaches but I am left banging my head against the wall.
Uploading image with other parameters in SWIFT
Upload image with parameters in Swift
http://www.kaleidosblog.com/how-to-upload-images-using-swift-2-send-multipart-post-request
EDIT 1:
Forgot error message (dur): Caught an error: Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
Error is occurring somewhere in the do
statement. I think something is going on with the request
because testing http://localhost/project/uploadImage.php
in my browser returns the array {"message":"Missing required information"}
EDIT 2: PHP Code
uploadImage.php
<?php
// report all errors except E_NOTICE
error_reporting(E_ALL & ~E_NOTICE);
// Part 1: Upload File
// Step 1: check data passed to this php file
if (empty($_REQUEST["id"])) {
$returnArray["message"] = "Missing required information";
print json_encode($returnArray);
return;
}
// request user id
$id = htmlentities($_REQUEST["id"]);
// step 2: create a folder for user with id as folder name
$folder = "/Applications/XAMPP/xamppfiles/htdocs/project/image/" . $id;
// if folder doesn't exist
if (!file_exists($folder)) {
mkdir($folder, 0777, true);
}
// step 3: move uploaded file
$folder = $folder . "/" . basename($_FILES["file"]["name"]);
if (move_uploaded_file($_FILES["file"]["tempname"], $folder)) {
$returnArray["status"] = "200";
$returnArray["message"] = "The file has been uploaded successfully.";
} else {
$returnArray["status"] = "300";
$returnArray["message"] = "Error while uploading.";
}
// Part 2: Updating image path
// build secure connection
$file = parse_ini_file("../../../project.ini");
// store variable information from ini file in php as variables
$host = trim($file["dbhost"]);
$user = trim($file["dbuser"]);
$pass = trim($file["dbpass"]);
$name = trim($file["dbname"]);
// include access.php to call connect function from access.php file
require ("secure/access.php");
$access = new access($host, $user, $pass, $name);
$access->connect();
// STEP 5: save path to uploaded file in database
$path = "http://localhost/project/image/" . $id . "/ava.jpg";
$access->updateImagePath($path, $id);
// STEP 6: get new user information after updating
$user = $access->selectUserViaID($id);
$returnArray["id"] = $user["id"];
$returnArray["username"] = $user["username"];
$returnArray["fullname"] = $user["fullname"];
$returnArray["email"] = $user["email"];
$returnArray["image"] = $user["image"];
// Step 7. Close Connection
$access->disconnect();
// Step 8. feedback array to app
echo json_encode($returnArray);
?>
Notice: Undefined index: tempname in /Applications/XAMPP/xamppfiles/htdocs/project/uploadImage.php on line 31
{"status":"300","message":"Error while uploading.","id":"98","username":"username","fullname":"full name","email":"*****@me.com","image":"http:\/\/localhost\/project\/image\/98\/ava,jpg"}` – nsmedira Feb 18 '17 at 00:43