无法将带有 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
所以服务器无法理解您消息中的文件名。
如果您没有服务器访问权限,调试语句也可以帮助您在客户端查看错误。
希望能帮助您入门。
我在 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
所以服务器无法理解您消息中的文件名。 如果您没有服务器访问权限,调试语句也可以帮助您在客户端查看错误。
希望能帮助您入门。