1

I am trying to build a simple file uploading iOS app in Swift, but keep getting the following Internal Server Error in the console upon clicking the Upload Image button:

********* response = <NSHTTPURLResponse: 0x7f95284b65c0> { URL: http://website.com/upload.php } { status code: 500, headers {
    Age = 0;
    "Cache-Control" = "max-age=0";
    Connection = "keep-alive";
    "Content-Length" = 655;
    "Content-Type" = "text/html; charset=iso-8859-1";
    Date = "Thu, 30 Jul 2015 04:58:50 GMT";
    Expires = "Thu, 30 Jul 2015 04:58:50 GMT";
    "X-Cache" = MISS;
    "X-Varnish" = 107809910;
} }
********* response data = <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>500 Internal Server Error</title>
</head><body>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error or
misconfiguration and was unable to complete
your request.</p>
<p>Please contact the server administrator at 
 [email protected] to inform them of the time this error occurred,
 and the actions you performed just before this error.</p>
<p>More information about this error may be available
in the server error log.</p>
<p>Additionally, a 404 Not Found
error was encountered while trying to use an ErrorDocument to handle the request.</p>
</body></html>

Here is my Swift View Controller code:

import UIKit

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    @IBOutlet weak var myImageView: UIImageView!
    @IBOutlet weak var myActivityIndicator: UIActivityIndicatorView!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @IBAction func selectPhotoPressed() {
        var myPickerControl = UIImagePickerController()
        myPickerControl.delegate = self
        myPickerControl.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
        self.presentViewController(myPickerControl, animated: true, completion: nil)
    }

    @IBAction func uploadImagePressed() {
        myImageUploadRequest()
    }

    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
        myImageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage
        self.dismissViewControllerAnimated(true, completion: nil)
    }

    func myImageUploadRequest()
    {
        let myURL = NSURL(string: "http://website.com/upload.php");
        let request = NSMutableURLRequest(URL: myURL)
        request.HTTPMethod = "POST"

        let param = [
            "firstName": "John",
            "lastName": "Smith",
            "userID": "1"
        ]
        let boundary = generateBoundaryString()
        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
        let imageData = UIImageJPEGRepresentation(myImageView.image, 1)
        if (imageData == nil) { return; }
        request.HTTPBody = createBodyWithParameters(param, filePathKey: "file", imageDataKey: imageData, boundary: boundary)

        myActivityIndicator.startAnimating();

        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
            data, response, error in

            if error != nil {
                println("error=\(error)")
                return
            }

            // print out response object
            println("********* response = \(response)")

            // print out response bdoy
            let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
            println("********* response data = \(responseString)")

            dispatch_async(dispatch_get_main_queue(), {
                self.myActivityIndicator.stopAnimating()
                self.myImageView.image = nil
            });
        }

        task.resume()
    }

    func createBodyWithParameters(parameters: [String: String]?, filePathKey: String?, imageDataKey: NSData, boundary: String) -> NSData {
        var body = NSMutableData();
        if parameters != nil {
            for (key, value) in parameters! {
                body.appendString("-\(boundary)\r\n")
                body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
                body.appendString("\(value)\r\n")
            }
        }

        let filename = "user-profile.jpg"
        let mimetype = "image/jpg"

        body.appendString("--\(boundary)\r\n")
        body.appendString("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n")
        body.appendString("Content-Type: \(mimetype)\r\n\r\n")
        body.appendData(imageDataKey)
        body.appendString("\r\n")

        body.appendString("--\(boundary)--\r\n")
        return body
    }

    func generateBoundaryString() -> String {
        return "Boundary-\(NSUUID().UUIDString)"
    }
}

extension NSMutableData {
    func appendString(string: String) {
        let data = string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
        appendData(data!)
    }
}

And the following is the backend upload.php file:

<?php
$firstName = $_REQUEST["firstName"];
$lastName = $_REQUEST["lastName"];
$userID = $_REQUEST["userID"];

$target_dir = "uploads";
if (!file_exists($target_dir))
    mkdir($target_dir, 0777, true);

$target_dir .= "/" . basename($_FILES["file"]["name"]);
if (move_uploaded_file($_FILES["files"]["tmp_name"], $target_dir)) {
    echo json_encode([
        "Message" => "The file " . basename($_FILES["file"]["name"]) . "has been uploaded.",
        "Status" => "OK",
        "userID" => $_REQUEST["userID"]
    ]);
} else {
    echo json_encode([
        "Message" => "Sorry, there was an error uploading your file.",
        "Status" => "Error",
        "userID" => $_REQUEST["userID"]
    ]);
}
?>

I am not sure what's wrong here. For troubleshooting, I added ini_set('display_errors', 1); to upload.php as well as changed permissions on the file to 777, but continue to get that message in the console. However, if I simply go to http://website.com/upload.php in my browser, I get {"Message":"Sorry, there was an error uploading your file.","Status":"Error","userID":null}

5
  • What is your error reporting value in php.ini ? Commented Jul 30, 2015 at 5:29
  • I'm not sure what you're referring to, but if you're specifically talking about "error reporting value" in the PHP information page, then it is 32767 Commented Jul 30, 2015 at 5:32
  • You need to debug step by step. Your iOS code is correct, just echo first three variables in php and comment out every thing else to check issues. Step by step add one one line to check issue. Commented Jul 30, 2015 at 5:42
  • Talking about this: php.net/manual/en/function.error-reporting.php Commented Jul 30, 2015 at 6:19
  • @AshishP. I think it's something else. Changed the PHP backend to just <?php ini_set('display_errors', 1); print "hi"; ?> and still get Internal Server Error Commented Jul 30, 2015 at 16:52

1 Answer 1

2

Fix dashes on Boundary createBodyWithParameters as following:

func createBodyWithParameters(parameters: [String: String]?, filePathKey: String?, imageDataKey: NSData, boundary: String) -> NSData {
        let body = NSMutableData();

        if parameters != nil {
            for (key, value) in parameters! {
                body.appendString("--\(boundary)\r\n") // <----- "--" Double Dash
                body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
                body.appendString("\(value)\r\n")
            }
        }

        let filename = "user-profile.jpg"
        let mimetype = "image/jpg"

        body.appendString("--\(boundary)\r\n") // <----- "--" Double Dash
        body.appendString("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n")
        body.appendString("Content-Type: \(mimetype)\r\n\r\n")
        body.appendData(imageDataKey)
        body.appendString("\r\n")

        body.appendString("--\(boundary)--\r\n") // <----- "--" Double Dash

        return body
    }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.