NotBramKorsten NotBramKorsten - 1 month ago 18
JSON Question

can't get image upload in swift 3 using Alamofire to work

I have been stuck for three days while trying to get Alamofire to upload an Image. The idea is that Alamofire will send it to a server with some php code. After a lot of trying and looking on different places, some of the code should work, but the server side documentation for Alamofire is horrible.

The recent update to swift 3 doesn't help much answer wise...

Here is my Swift 3 code:

let imageData = UIImageJPEGRepresentation(imageFile!, 1)!

Alamofire.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(imageData, withName: "image", fileName: "image.jpeg", mimeType: "file/jpeg")
},
to: "https://someadress.com/post/upload.php",
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
debugPrint(response)
}
case .failure(let encodingError):
print(encodingError)
}
}
)


This should upload the image to the server, but I have no idea how to properly get the image saved on the server. The server doesn't really need any information of the file, since it will generate a new name for it. It should then send that name back to the app.

I know how to handle JSON in Swift 3 and php, since I've done that before. I also know for sure that at least something gets uploaded to the server, since I have gotten some basic information back.

The PHP code below is almost certainly not good, but it was mostly a test.

<?php
// get the file data
$fileData = file_get_contents('php://input');

// sanitize filename
$fileName = preg_replace("([^\w\s\d\-_~,;:\[\]\(\).])", '', $fileData);
// save to disk

$fileLocation = "../images/" . $fileName;
file_put_contents($fileLocation, $fileData);

if (empty($fileData)) {
$response = array("error" => "no data");
}
else {
$response = array("error" => "ok " . $fileName);
}

echo json_encode($response);
?>


Thanks for any help in advance :)

p.s. I'm new to swift, so please be gentle ;)

Answer

Okay, sooo. I figured it out. It turns out that Alamofire uses the $_FILES function of php. There is no mention of this whatsoever, so let me be the one to try and clear things up. Here is the full PHP code with comments.

<?php

// If the name of the image is not in this array, the app didn't post anything.
if (empty($_FILES["image"])) {
    // So we send a message back saying there is no data...
    $response = array("error" => "nodata");
}
// If there is data
else {
    $response['error'] = "NULL";
    // Setup a filename for the file. Uniqid can be changed to anything, but this makes sure
    // that every file doesn't overwrite anything existing.
    $filename = uniqid() . ".jpg";
    // If the server can move the temporary uploaded file to the server
    if (move_uploaded_file($_FILES['image']['tmp_name'], "../images/" . $filename)) {
        // Send a message back saying everything worked!
        // I also send back a link to the file, and the name.
        $response['status'] = "success";
        $response['filepath'] = "https://i335731.iris.fhict.nl/hypeAPI/images/" . $filename;
        $response['filename'] = "".$_FILES["file"]["name"];

} else{
    // If it can't do that, Send back a failure message, and everything there is / should be form the message
    // Here you can also see how to reach induvidual data from the image, such as the name.
    $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"];
  }
}

// Encode all the responses, and echo them.
// This way Alamofire gets everything it needs to know
echo json_encode($response);
?>

That's basically it. All you have to do is make sure that the name that you send with the Alamofire request matches the name between the '$_FILES' brackets. The temp name is the name of the file in Alamofire.

Here is the Swift 3 code.

// Note that the image needs to be converted to imagedata, in order to work with Alamofire.
let imageData = UIImageJPEGRepresentation(imageFile!, 0.5)!

Alamofire.upload(
            multipartFormData: { multipartFormData in
                // Here is where things would change for you
                // With name is the thing between the $files, and filename is the temp name.
                // Make sure mimeType is the same as the type of imagedata you made!
                multipartFormData.append(imageData, withName: "image", fileName: "image.jpg", mimeType: "image/jpeg")
            },
            to: "https://i335731.iris.fhict.nl/hypeAPI/post/upload.php",
            encodingCompletion: { encodingResult in
                switch encodingResult {
                case .success(let upload, _, _):
                    upload.responseJSON { response in
                        if let result = response.result.value {
                            // Get the json response. From this, we can get all things we send back to the app.
                            let JSON = result as! NSDictionary
                            self.imageServerLocation = JSON.object(forKey: "filepath") as? String
                            debugPrint(response)
                        }
                    }
                case .failure(let encodingError):
                    print(encodingError)
                }
            }
        )

I hope this helps a lot of people who have the same issue! Let me know if there's anything missing or anything you want to know!

Comments