无法将带有 multipart/form-data 的图片上传到服务器

Failing to Upload Picture with multipart/form-data to a Server

我在 multipart/form-data 上阅读了很多主题。它仍然不起作用。我可以使用 URLSession.shared.uploadTask.

将文件上传到我的服务器
class MainViewController: UIViewController {
    @IBOutlet weak var pictureView: UIImageView!

    @IBAction func postTapped(_ sender: UIButton) {
        postData()
    }

    func postData() {
        var request = URLRequest(url: URL(string: "http://www.mywebsite.com/upload.php")!)
        request.httpMethod = "POST"
        request.timeoutInterval = 30.0

        guard let imageData = UIImagePNGRepresentation(pictureView.image!) else {
            print("oops")
            return
        }

        let uuid = UUID().uuidString
        let CRLF = "\r\n"
        let filename = uuid + ".png"   // file name
        let formName = uuid + ".png"   // file name in the form
        let type = "image/png"     // file type
        let titleData = "hoge"      // title
        let titleName = uuid + ".png"     // title name in the form
        let boundary = String(format: "----iOSURLSessionBoundary.%08x%08x", arc4random(), arc4random())
        var body = Data()
        // form data //
        body.append(("--\(boundary)" + CRLF).data(using: .utf8)!)
        body.append(("Content-Disposition: form-data; name=\"\(titleName)\"" + CRLF + CRLF).data(using: .utf8)!)
        body.append(titleData.data(using: .utf8)!)
        body.append(CRLF.data(using: .utf8)!)
        // file data //
        body.append(("--\(boundary)" + CRLF).data(using: .utf8)!)
        body.append(("Content-Disposition: form-data; name=\"\(formName)\"; filename=\"\(filename)\"" + CRLF).data(using: .utf8)!)
        body.append(("Content-Type: \(type)" + CRLF + CRLF).data(using: .utf8)!)
        body.append(imageData)
        body.append(CRLF.data(using: .utf8)!)
        // footer //
        body.append(("--\(boundary)--" + CRLF).data(using: .utf8)!)
        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
        request.setValue("\(body.count)", forHTTPHeaderField: "Content-Length")
        request.httpBody = body
        let session = URLSession(configuration: .default)
        session.dataTask(with: request) { (data, response, error) in
            if let error = error {
                print(error)
            }
            if let respose = response {
                print(respose)
            }
        }
        .resume()
    }
}

PHP(upload.php 在索引处)

$dir = __DIR__ . '/upload/';
$path = $dir . basename($_FILES['filename']['name']);

$data['result'] = 'failure';
if (move_uploaded_file($_FILES['filename']['tmp_name'], $path)) {
    chmod($path, 0777);
    $data['result'] = date("H:i:s") . ' ' . $_POST['title'] . ' success';
}

header('Content-Type: application/json');
echo json_encode($data);

上面的代码是我尝试过的众多版本之一。没有错误。响应说状态代码是 200。但是服务器中没有文件。我想知道为什么它不起作用?这与 App Transport Security Settings 无关。我还没有准备好使用 Alamofire。非常感谢。

我调试了你的代码,简化了调试语句,为了清晰起见,我保留了调试语句。这是我想出的:

func postData() {
    var request = URLRequest(url: URL(string: "http://localhost/uploadimages/uploadtry.php")!)
    request.httpMethod = "POST"
    request.timeoutInterval = 30.0

    guard let imageData = UIImagePNGRepresentation(pictureView.image!) else {
        print("oops")
        return
    }

    let CRLF = "\r\n"
    let filename = "user.png"
    let formName = "file"
    let type = "image/png"     // file type

    let boundary = String(format: "----iOSURLSessionBoundary.%08x%08x", arc4random(), arc4random())

    var body = Data()

    // file data //
    body.append(("--\(boundary)" + CRLF).data(using: .utf8)!)
    body.append(("Content-Disposition: form-data; name=\"\(formName)\"; filename=\"\(filename)\"" + CRLF).data(using: .utf8)!)
    body.append(("Content-Type: \(type)" + CRLF + CRLF).data(using: .utf8)!)
    body.append(imageData as Data)
    body.append(CRLF.data(using: .utf8)!)

    // footer //
    body.append(("--\(boundary)--" + CRLF).data(using: .utf8)!)
    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

    //TW debug the body data.
    let theString:NSString = NSString(data: body as Data, encoding: String.Encoding.ascii.rawValue)!
    print(theString)

    request.setValue("\(body.count)", forHTTPHeaderField: "Content-Length")

    request.httpBody = body
    let session = URLSession(configuration: .default)
    session.dataTask(with: request) { (data, response, error) in
        if let error = error {
            print(error)
        }
        if let respose = response {
            print(respose)
        }
        // TW
        if let data = data {
            // This gives us same as server log

            // You can print out response object
            print("******* response = \(String(describing: response))")

            print(data.count)
            // you can use data here

            // Print out reponse body
            let responseString = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
            print("****** response data = \(responseString!)")

        }

        }
        .resume()
}

提到的uploadtry.php

<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);

$dir = 'media';
$path = $dir . "/" . basename($_FILES['file']['name']);


$data['result'] = 'failure';
if (move_uploaded_file($_FILES['file']['tmp_name'], $path)) {
    chmod($path, 0777);
    $data['result'] = ' success';
}

header('Content-Type: application/json');
echo json_encode($data);


?>

基本上我在服务器上看到这样的错误:

Undefined index: filename in /pathtoserver/uploadimages/uploadtry.php on line 6

所以服务器无法理解您消息中的文件名。 如果您没有服务器访问权限,调试语句也可以帮助您在客户端查看错误。

希望能帮助您入门。