问题
I've read quite a lot of topics here on multipart/form-data
. It still doesn't work. I am able to upload a file to my server with 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 at index)
$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);
The code above is one of many versions I have tried. There's no error. The response says the status code is 200. But there's no file in the server. I wonder why it doesn't work? It's not about App Transport Security Settings
. I'm not ready to use Alamofire, yet. Muchos thankos.
回答1:
I debugged your code, simplified and left the debug statements in for clarity. Here is what I came up with:
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()
}
The mentioned 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);
?>
Basically I saw errors like this on the server:
Undefined index: filename in /pathtoserver/uploadimages/uploadtry.php on line 6
So the server could not understand filename in your message. The debug statements help you to see the error also on the client side if you have no server access.
Hope that gets you started.
来源:https://stackoverflow.com/questions/49003256/failing-to-upload-picture-with-multipart-form-data-to-a-server