如何在PHP中接收上传的文件?文件由使用Swift编写的iOS应用上传

时间:2018-09-08 02:14:37

标签: php swift upload nsurlsession nsurlsessiondatatask

这是我的快速代码,可以从应用程序上传文件。

final class UploadService {

  // I'm renting a remote server and the php code is on that
  private let videoUploadPath = "http://myUploadPath.php"

  var uploadsSession: URLSession!
  var activeUploads: [URL: Upload] = [:]

  func startUpload(medium: Medium) {

    guard let url = URL(string: videoUploadPath) else { return }

    var request = URLRequest(url: url)
    request.httpMethod = "POST"

    let upload = Upload(medium: medium)
    upload.task = self.uploadsSession.uploadTask(with: request, fromFile: medium.avUrlAsset.url)
    upload.task?.resume()
    upload.isUploading = true
    activeUploads[upload.medium.avUrlAsset.url] = upload
  } 
}

请注意,我必须使用

func uploadTask(with request: URLRequest, fromFile fileURL: URL) -> URLSessionUploadTask

// Apple documentation: Parameters request A URL request object that provides the URL, cache policy, request type, and so on. The body stream and body data in this request object are ignored.

从手机上传视频,因为这是允许后台上传的唯一方法(视频通常很大,因此我必须使后台上传成为可能)。但是,此功能会丢弃所有正文数据。

这是我的PHP代码,用于接收上载的文件并将其存储在所需的位置:

$directory = "../storage/videos/";
$destination = $directory . basename($_FILES["file"]["name"]);

if (move_uploaded_file($_FILES["file"]["tmp_name"], $destination)) {
  $returnArray["status"] = "200";
  $returnArray["message"] = "Upload success";
  echo json_encode($returnArray);
} else {
  $returnArray["status"] = "300";
  $returnArray["message"] = "Upload failed" . $_FILES["file"]["error"];
  echo json_encode($returnArray);
  return;
}

说实话,我知道它不会成功,因为我无法指定PHP代码中$_FILES["file"]["name"]所必需的文件类型和名称。

因此,我的问题是,如何指定要上传的文件名和类型?自功能 func uploadTask(with request: URLRequest, fromFile fileURL: URL) -> URLSessionUploadTask 丢弃所有http正文数据,如我提到的那样,也许是制作包含文件类型和名称的http标头?或者,PHP是否有另一种方式来接收我刚刚上传的文件?现在,$ _FIELS完全为空。我是PHP的新手,很抱歉,如果我说的不够清楚。

另外,对于Content-Type,我在上载图像以更改用户的个人资料图像时使用multipart/form-data,我将图像数据与其他数据(例如uid)附加在一起,然后附加data作为http正文中的正文数据。但是现在,我需要上传一个文件,因为根据iOS的要求,请求中的所有正文数据都将被忽略。我该怎么办?

很多日子都困扰于此,请提供帮助。非常感谢!

1 个答案:

答案 0 :(得分:0)

有一种方法可以保留URLSession.shared.uploadTask调用并在PHP端使用原始数据。这是一个对我有用的JSON数据示例:

使用https://developer.apple.com/documentation/foundation/url_loading_system/uploading_data_to_a_website中的Swift样例代码

SWIFT端:

struct Order: Codable {
    let customerId: String
    let items: [String]
}

// ...

let order = Order(customerId: "12345",
                  items: ["Cheese pizza", "Diet soda"])
guard let uploadData = try? JSONEncoder().encode(order) else {
    return
}
let url = URL(string: "https://example.com/upload.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.uploadTask(with: request, from: uploadData) { data, response, error in
    if let error = error {
        print ("error: \(error)")
        return
    }
    guard let response = response as? HTTPURLResponse,
        (200...299).contains(response.statusCode) else {
        print ("server error")
        return
    }
    if let mimeType = response.mimeType,
        mimeType == "application/json",
        let data = data,
        let dataString = String(data: data, encoding: .utf8) {
        print ("got data: \(dataString)")
    }
}
task.resume()

PHP端:(upload.php)

<?php
header('Content-Type: application/json; charset=utf-8');
$response = array();
try {  
  $uploaddir = './uploads/';
  $uploadfile = $uploaddir . 'test.json';
  $rawdata = file_get_contents('php://input');

  if (!file_put_contents($uploadfile, $rawdata)) {
    throw new RuntimeException('Failed to create file.');
  }
  $response = array(
    "status" => "success",
    "error" => false,
    "message" => "File created successfully"
  );
  echo json_encode($response);
  
} catch (RuntimeException $e) {
  $response = array(
    "status" => "error",
    "error" => true,
    "message" => $e->getMessage()
  );
  echo json_encode($response);
}
?>

这还将把二进制数据写入文件。在这种简单情况下,无需知道文件名或内容类型。对于一般情况,它可能不起作用,但是这种进行方式允许您继续使用URLSession.shared.uploadTask并避免使用HTTP Body参数。 HTH。