I have a problem trying to upload an image in swift to a PHP server. Everything looks good till the php processes the file. In that moment I get the error.
The relevant part of the swift code is:
func myImageUploadRequest(image: UIImage, realfilename: String)
{
let myUrl = NSURL(string: "http://www.ignistudios.com/boda/postImage.php");
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST";
let param = [
"firstName" : "username",
"lastName" : "lastname",
"userId" : "9"
]
let boundary = generateBoundaryString()
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let imageData = UIImageJPEGRepresentation(image, 1)
print(imageData.debugDescription)
if(imageData==nil) { return; }
request.HTTPBody = createBodyWithParameters(param, filePathKey: "file", realfilename: realfilename, imageDataKey: imageData!, boundary: boundary)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
// You can print out response object
print("******* response = \(response)")
// Print out reponse body
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("****** response data = \(responseString!)")
}
task.resume()
}
func createBodyWithParameters(parameters: [String: String]?, filePathKey: String?, realfilename: 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 = realfilename
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)"
}
And the php is
<?php
$uploaddir = '/fotos/';
$uploadfile = $uploaddir . basename($_FILES['file']['name']);
echo "<p>";
if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
echo "File is valid, and was successfully uploaded.\n";
} else {
echo "Upload failed";
}
echo "</p>";
echo '<pre>';
echo 'Here is some more debugging info:';
print_r($_FILES);
print "</pre>";
?>
And last, the error I get is:
****** response data =
Upload failedHere is some more debugging info:Array
(
[file] => Array
(
[name] => Optional(\"boda20160428_135709.jpg\")
[type] =>
[tmp_name] =>
[error] => 1
[size] => 0
)
)
Any tip would be very much appreciated.
It looks like Marc B has commented with the answer which is that it is a PHP file upload size issue.
However in cases like this it is worth testing each link in the chain separately. For example testing and reviewing the output of createBodyWithParameters. Create a test and run it there to check that the headers are properly formed. Especially make sure that the string encoding is correct. I'm not familiar with the appendString method on NSMutableData.
It should be possible to feed that output more directly into the server to eliminate other potential issues.
The correct answer is that the image is too big and you need to compress the image before uploading it, using this
UIImageJPEGRepresentation(image,0.2)
When the image is small enough you will get your tmp name
Related
I am trying to upload a file (in this case I'm trying with an image, but I would need to be able to upload any kind of file, especially a video file) to my server.
This is my PHP code, and it works fine on a server-side:
<?php include '_config.php';
if ($_FILES["file"]["error"] > 0) {
echo "Error: " .$_FILES["file"]["error"]. "<br>";
} else {
// Check file size
if ($_FILES["file"]["size"] > 20485760) { // 20 MB
echo "ERROR: Your file is larger than 20 MB. Please upload a smaller one.";
} else { uploadImage(); }
}// ./ If
// UPLOAD IMAGE ------------------------------------------
function uploadImage() {
// generate a unique random string
$randomStr = generateRandomString();
$filePath = "uploads/".$randomStr;
// upload image into the 'uploads' folder
move_uploaded_file($_FILES['file']['tmp_name'], $filePath);
// echo the link of the uploaded image
echo $filePath;
}
// GENERATE A RANDOM STRING ---------------------------------------
function generateRandomString() {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i<20; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString."_".$_POST['fileName'];
}
?>
This is my Swift 5 function:
func uploadFile(_ aImage:UIImage, maxWidth:CGFloat, completion: #escaping (_ fileURL:String?) -> Void) {
showHUD()
let image = scaleImageToMaxWidth(image: aImage, newWidth: maxWidth)
// Generate a random filename
var filename = ""
for _ in 0..<20 {
let randomChar = Int(arc4random() % UInt32(charsForRand.count))
filename += charsForRand[randomChar]
}
filename += "__image.jpg"
print("FILENAME: \(filename)")
let boundary = UUID().uuidString
let fieldName = "reqtype"
let fieldValue = "fileupload"
let fieldName2 = "userhash"
let fieldValue2 = "caa3dce4fcb36cfdf9258ad9c"
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
var urlRequest = URLRequest(url: URL(string: DATABASE_PATH + "upload-file.php")!)
urlRequest.httpMethod = "POST"
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var data = Data()
data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
data.append("Content-Disposition: form-data; name=\"\(fieldName)\"\r\n\r\n".data(using: .utf8)!)
data.append("\(fieldValue)".data(using: .utf8)!)
data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
data.append("Content-Disposition: form-data; name=\"\(fieldName2)\"\r\n\r\n".data(using: .utf8)!)
data.append("\(fieldValue2)".data(using: .utf8)!)
data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
data.append("Content-Disposition: form-data; name=\"fileToUpload\"; fileName=\"\(filename)\"\r\n".data(using: .utf8)!)
data.append("Content-Type: image/png\r\n\r\n".data(using: .utf8)!)
data.append(image.jpegData(compressionQuality: 1.0)!)
data.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
// Send a POST request to the URL, with the data we created earlier
session.uploadTask(with: urlRequest, from: data, completionHandler: { responseData, response, error in
if error != nil { print("\(error!.localizedDescription)") }
guard let responseData = responseData else {
DispatchQueue.main.async {
self.simpleAlert("Something went wrong while uploading, try again.")
}
completion(nil)
return
}
if let response = String(data: responseData, encoding: .utf8) {
completion("\(DATABASE_PATH)\(response)")
print("UPLOAD URL: \(DATABASE_PATH)\(response)")
}
}).resume()
}
I call that function in my ViewController as follows:
uploadFile(UIImage(named: "default_avatar")!, maxWidth: 300) { (fileURL) in
if fileURL != nil {
print("FILE URL: \(fileURL!)")
}
}
But this is what I get in the Xcode console:
FILE URL: https://example.com/uploads/8iWQOrwr0wgNDor8XNhX_
UPLOAD URL: https://example.com/uploads/8iWQOrwr0wgNDor8XNhX_
This means that my function doesn't append "__image.jpg" string to the filename variable, and it also doesn't upload my image to the uploads folder on my server.
What am I doing wrong? If I call my PHP script from a form with an input of type file, it works like a charm., so my PHP script is fine, so I'm surely doing something wrong in the Swift function.
I've found a solution, here's my edited Swift 5 function, which now can also accept mp4 video files, not just jpg or png images:
func uploadFile(fileData:Data, fileName:String , completion: #escaping (_ fileURL:String?, _ error:String?) -> Void) {
print("FILENAME: \(fileName)")
let boundary: String = "------VohpleBoundary4QuqLuM1cE5lMwCy"
let contentType: String = "multipart/form-data; boundary=\(boundary)"
let request = NSMutableURLRequest()
request.url = URL(string: DATABASE_PATH + "upload-file.php")
request.httpShouldHandleCookies = false
request.timeoutInterval = 60
request.httpMethod = "POST"
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
let body = NSMutableData()
body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
body.append("Content-Disposition: form-data; name=\"fileName\"\r\n\r\n".data(using: String.Encoding.utf8)!)
body.append("\(fileName)\r\n".data(using: String.Encoding.utf8)!)
body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
body.append("Content-Disposition: form-data; name=\"file\"; filename=\"file\"\r\n".data(using: String.Encoding.utf8)!)
// File is an image
if fileName.hasSuffix(".jpg") {
body.append("Content-Type:image/png\r\n\r\n".data(using: String.Encoding.utf8)!)
// File is a video
} else if fileName.hasSuffix(".mp4") {
body.append("Content-Type:video/mp4\r\n\r\n".data(using: String.Encoding.utf8)!)
}
body.append(fileData)
body.append("\r\n".data(using: String.Encoding.utf8)!)
body.append("--\(boundary)--\r\n".data(using: String.Encoding.utf8)!)
request.httpBody = body as Data
let session = URLSession.shared
let task = session.dataTask(with: request as URLRequest) { (data, response, error) in
guard let _:Data = data as Data?, let _:URLResponse = response, error == nil else {
DispatchQueue.main.async { completion(nil, error!.localizedDescription) }
return
}
if let response = String(data: data!, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue)) {
print("XSUploadFile -> RESPONSE: " + DATABASE_PATH + response)
DispatchQueue.main.async { completion(DATABASE_PATH + response, nil) }
// NO response
} else { DispatchQueue.main.async { completion(nil, E_401) } }// ./ If response
}; task.resume()
}
Here's how I use that function:
let imageData = UIImage(named: "my_img")!.jpegData(compressionQuality: 1)
uploadFile(fileData: imageData!, fileName: "image.jpg") { (fileURL, e) in
if e == nil {
print("FILE URL: " + fileURL!)
}}
This works 100%.
func convertImageToBase64(image: UIImage) -> String {
let imageData = UIImagePNGRepresentation(image)
let base64String = imageData?.base64EncodedString(options:.lineLength64Characters)
return base64String!
}// end convertImageToBase64
Swift code is here (base 64 encode part) :
let base64string = self.convertImageToBase64(image: self.pro_images.image!)
let imgbase64str = base64string.replacingOccurrences(of:"+", with: "%2B")
request.httpMethod = "POST"
let postString = ("email=\(savedValue!)&image=\(imgbase64str)&subject=\(self.analy_title.text!)&content=\(self.analy_text.text!)")
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, ....
php code is here :
if($image != "null"){
if(file_put_contents($upload_path,base64_decode($image))){
I want to upload my base64 encode image
but I can't got original picture.
because picture is not display.
How to solve this problem ?
I am trying to sent input from the user to a php script to have it ultimately passed to an SQL server, Most of the code runs but having problem with submitting the data.
#IBAction func submit(_ sender: AnyObject) {
let requestURL = URL(string: "*****")
let request = NSMutableURLRequest(url:requestURL!)
request.httpMethod = "POST"
let song=txt1.text!
let artist=txt2.text!
let album=txt3.text!
let year=txt4.text!
let genre=txt5.text!
let songPost = "song=" + (song as String)
let artistPost = "&artist=" + (artist as String)
let albumPost = "&album=" + (album as String)
let yearPost = "&year=" + (year as String)
let genrePost = "&genre=" + (genre as String)
request.httpBody = songPost.data(using: String.Encoding.utf8);
request.httpBody = artistPost.data(using: String.Encoding.utf8);
request.httpBody = albumPost.data(using: String.Encoding.utf8);
request.httpBody = yearPost.data(using: String.Encoding.utf8);
request.httpBody = genrePost.data(using: String.Encoding.utf8);
--->>let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
print(response)
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
}
task.resume()
Having an issue with the urlsession.shared.datatask line of code. Compiler error says "ambigious reference to member'dataTask(with:completionhandler:)"
What can get this code to work and how can I verify that this information was passed on the app?
The reason you get that error message is because you are passing NSMutableURLRequest where URLRequest is needed.
Changing this line:
let request = NSMutableURLRequest(url:requestURL!)
to this:
var request = URLRequest(url:requestURL!)
should fix it.
But I recommend a little more fixes to make your request successfully sent to the server:
let requestURL = URL(string: "*****")
//You should use `URLRequest` in Swift 3, mutability is represented by `var`
var request = URLRequest(url:requestURL!)
request.httpMethod = "POST"
//UITextField.text can be nil, you should treat nil cases
//(Generally avoid using forced unwrapping `!` as far as you can.)
let song = txt1.text ?? ""
let artist = txt2.text ?? ""
let album = txt3.text ?? ""
let year = txt4.text ?? ""
let genre = txt5.text ?? ""
//`song`,... are all Strings, you have no need to add `as String`
let songPost = "song=" + song
let artistPost = "&artist=" + artist
let albumPost = "&album=" + album
let yearPost = "&year=" + year
let genrePost = "&genre=" + genre
//You need to make a single data containing all params
//(Creating a concatenated String and getting `data` later would be another way.)
var data = Data()
data.append(songPost.data(using: String.Encoding.utf8)!)
data.append(artistPost.data(using: String.Encoding.utf8)!)
data.append(albumPost.data(using: String.Encoding.utf8)!)
data.append(yearPost.data(using: String.Encoding.utf8)!)
data.append(genrePost.data(using: String.Encoding.utf8)!)
request.httpBody = data
let task = URLSession.shared.dataTask(with: request) { data, response, error in
...
I have read all the other threads but my problem is a mix of those. So I am trying to send some content over to a php server through HTTP in swift. Everything works fine until I append an image base64 content to the body of the http tag. I checked the php backend max post size, wasnt it. I copy pasted the image content that was generated in swift and pasted it in chrome and image was there, so image is not faulty.
This is the sample code of what I have
let url = NSURL(string: "https:example.com/endpoint")
// let session = NSURLSession.sharedSession();
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
var body = "csrf_token=" + (token.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())! as String)
body += "&email=" + (email?.text)!
body += "&first_name=" + (firstName?.text)!
body += "&last_name=" + (lastName?.text)!
body += "&password=" + password!.text!
//body += "&image_content=" + imageContent
body += "&confirm_password=" + confirmPassword!.text!
body += "&provider=" + provider
body += "&pictureURL=" + pictureURL
request.HTTPBody = body.dataUsingEncoding(NSUTF8StringEncoding)
request.addValue("https:example.com/", forHTTPHeaderField: "origin")
request.addValue("https:example.com/endpoint", forHTTPHeaderField: "referrer")
let task = session.dataTaskWithRequest(request) {
(
let data, let response, let error) in
guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
print("error")
print(data)
print(response)
return;
}
let dataString = NSString(data :data!, encoding: NSUTF8StringEncoding);
print(dataString)
if ((response as! NSHTTPURLResponse).statusCode == 200) {
dispatch_async(dispatch_get_main_queue(), {
self.performSegueWithIdentifier("loginAfterSignup", sender: nil)
})
}
else {
dispatch_async(dispatch_get_main_queue(), {
print((response as! NSHTTPURLResponse).statusCode)
print("error code, could not sign up and login")
})
}
}
task.resume()
So when I uncomment the line with the base64 string content, I go to the throwback call and it prints the "error".
I have no clue why its not sent through http. Is there a rule I have to obey? Do I have to set a certain http header once I append a large string? Am I missing something here?
Thanks
Yep, it was a stupid Apache settings error. I have previously modified max_post_size and got nothing. However this time I modified the max request body parameter and I could finally send data to the server.
So i followed this suggestion: https://stackoverflow.com/a/27014372/4751488.
When i run my script the photo wont upload. I get no error on the JSON response only that the image has not been uploaded. Anny ideas?
my main function:
var image : UIImage = UIImage(named:"record")!
let imageData2 = UIImagePNGRepresentation(image)
imageViewController.image = image
var parameters = [
"pic" :NetData(data: imageData2!, mimeType: MimeType.ImageJpeg ,filename: "customName.jpg"),
"otherParm" :"Value"
]
let urlRequest = self.urlRequestWithComponents("http://www.xxx.xx/uploadPhoto.php", parameters: parameters)
Alamofire.upload(urlRequest.0, urlRequest.1)
.progress { (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in
println("\(totalBytesWritten) / \(totalBytesExpectedToWrite)")
}
.responseJSON { (request, response, JSON, error) in
println("REQUEST \(request)")
println("RESPONSE \(response)")
println("JSON \(JSON)")
println("ERROR \(error)")
}
and my urlRequestWithComponents looks like this :
func urlRequestWithComponents(urlString:String, parameters:NSDictionary) -> (URLRequestConvertible, NSData) {
// create url request to send
var mutableURLRequest = NSMutableURLRequest(URL: NSURL(string: urlString)!)
mutableURLRequest.HTTPMethod = Alamofire.Method.POST.rawValue
//let boundaryConstant = "myRandomBoundary12345"
let boundaryConstant = "NET-POST-boundary-\(arc4random())-\(arc4random())"
let contentType = "multipart/form-data;boundary="+boundaryConstant
mutableURLRequest.setValue(contentType, forHTTPHeaderField: "Content-Type")
// create upload data to send
let uploadData = NSMutableData()
// add parameters
for (key, value) in parameters {
uploadData.appendData("\r\n--\(boundaryConstant)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
if value is NetData {
// add image
var postData = value as! NetData
//uploadData.appendData("Content-Disposition: form-data; name=\"\(key)\"; filename=\"\(postData.filename)\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
// append content disposition
var filenameClause = " filename=\"\(postData.filename)\""
let contentDispositionString = "Content-Disposition: form-data; name=\"\(key)\";\(filenameClause)\r\n"
let contentDispositionData = contentDispositionString.dataUsingEncoding(NSUTF8StringEncoding)
uploadData.appendData(contentDispositionData!)
// append content type
//uploadData.appendData("Content-Type: image/png\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) // mark this.
let contentTypeString = "Content-Type: \(postData.mimeType.getString())\r\n\r\n"
let contentTypeData = contentTypeString.dataUsingEncoding(NSUTF8StringEncoding)
uploadData.appendData(contentTypeData!)
uploadData.appendData(postData.data)
}else{
uploadData.appendData("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n\(value)".dataUsingEncoding(NSUTF8StringEncoding)!)
}
}
uploadData.appendData("\r\n--\(boundaryConstant)--\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
// return URLRequestConvertible and NSData
return (Alamofire.ParameterEncoding.URL.encode(mutableURLRequest, parameters: nil).0, uploadData)
}
php code :
<?php
// In PHP versions earlier than 4.1.0, $HTTP_POST_FILES should be used instead
// of $_FILES.
$uploaddir = "/var/www/html/upload/uploads/";
// PS: custom filed name : pic
$uploadfile = $uploaddir . basename($_FILES['pic']['name']);
if (move_uploaded_file($_FILES["pic"]["tmp_name"], $target_file)) {
$array = array ("code" => "1", "message" => "successfully");
} else {
$array = array ("code" => "0", "message" => "Possible file upload attack!".$uploadfile);
}
echo json_encode ( $array );
?>
rsponse in xcode:
JSON Optional({
code = 0;
message = "Possible file upload attack!/var/www/html/upload/uploads/customName.jpg";})
ERROR nil
Old topic but if you're looking for an answer, you use the function move_uploaded_file with the var $target_file which is not initialized.
You should have used $uploadfile