I've got a pretty particular issue today. I've created a multipart/form-data header in iOS, which is then sent to a PHP script on my web server. It works fine with only strings as data, but when I attempt to append an image to the header, it returns 403. Here's the function that attempts to connect:
func uploadImage(image: UIImage) {
var url: NSURL = NSURL(string: "https://example.com/uploadPicture.php")!
var request: NSMutableURLRequest = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
var boundary = NSString(format: "dsfghjkergsalkj")
var contentType = NSString(format: "multipart/form-data; boundary=%@", boundary)
request.addValue(contentType, forHTTPHeaderField: "Content-Type")
request.timeoutInterval = 60
var body = NSMutableData()
body.appendData(NSString(format: "--%@\r\n", boundary).dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(NSString(format: "Content-Disposition: form-data; name=\"image-name\"\r\n\r\n").dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("yay".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(NSString(format: "--%@\r\n", boundary).dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(NSString(format: "Content-Type: image/png\r\n").dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(NSString(format: "Content-Transfer-Encoding: binary\r\n").dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(NSString(format: "Content-Disposition: form-data; name=\"profile-img\"; filename=\"profile.png\"\r\n\r\n").dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(NSData(data: UIImagePNGRepresentation(image)))
//println(NSData(data: UIImagePNGRepresentation(image)))
body.appendData(NSString(format: "--%@\r\n", boundary).dataUsingEncoding(NSUTF8StringEncoding)!)
request.HTTPBody = body
let task = NSURLSession(configuration: .defaultSessionConfiguration(), delegate: nil, delegateQueue: NSOperationQueue.mainQueue()).dataTaskWithRequest(request) {
data, response, error in
if (error != nil) {
println("Error Submitting Request: \(error)")
return
}
var err: NSError?
var userData: [String: String]!
userData = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as? [String: String]
if(userData != nil) {
println(data)
println(userData)
} else {
println(data)
println("No data recieved.")
}
}
task.resume()
}
It should return a JSON associative array that either has 'true' or 'false' under the key 'data', as shown here.
if(isset($_FILES['profile-img'])) {
$arr = ['data': 'true'];
} else {
$arr = ['data': 'false'];
}
echo json_encode($arr);
Instead it returns a long list of hex bytes, which is the 403 forbidden page.
Commenting out body.appendData(NSData(data: UIImagePNGRepresentation(image)))
allows the connection to work.
What might be causing this? I've tried everything I could think of.
EDIT: Here's the full PHP page, not much.
<?php
error_reporting(E_ALL);
ini_set('display errors', 1);
if(isset($_FILES['profile-img'])) {
$arr = ['data': 'true'];
} else {
$arr = ['data': 'false'];
}
echo json_encode($arr);
/*$uploaddir = './uploads/';
$file = basename($_FILES['profile_img']['name']);
$uploadfile = $uploaddir . $file;
if (move_uploaded_file($_FILES['profile_img']['tmp_name'], $uploadfile)) {
$arr = ['data': 'true'];
} else {
$arr = ['data': 'false'];
}
echo json_encode($arr);*/
?>
You are likely not constructing a MIME multipart submission that PHP is decoding correctly. The spec for these is here.
CRLF
sequence after it. You can accomplish this by ending your header strings with \r\n
. There should be an extra CRLF
sequence after the final header line and before the data in each part.Content-Transfer-Encoding: binary
to this part.