Is this a properly formatted POST request? - php

Is the below code a properly formatted POST request? It seems as those the entire contents are being passed via the URI and not via POST. I only have a very primitive understanding of PHP and URL requests in general so the server-side code has been included below as well.
I noticed this was an issue while attempting to upload base64 encoded images (as demonstrated below) to the server. Upon submitting the request, the server would return an error stating the that URI exceeds the maximum length, which leads me to believe that this isn't a proper approach to submitting a POST request. The entire process works if the image is only 10x10px, but that isn't going to do the trick and the main priority here is understanding the correct approach.
What is the proper approach to submitting a POST request, similar to the below example?
How can the POST data be received by the server and will the JSON need slashed stripped if it is properly submitted via POST?
Swift
if let imageData = UIImagePNGRepresentation(self.image!) {
let encodedImage = imageData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
let dict = ["barcode":self.barcode, "imageData":encodedImage]
let json = JSONStringify(dict, prettyPrinted: false)
let jsonEncoded = CFURLCreateStringByAddingPercentEscapes(
nil, json, nil, "!*'();:#&=+$,/?%#[]", CFStringBuiltInEncodings.UTF8.rawValue)
let server:String = GlobalVars.serverAddress
let phpFile:String = "/php/Inventory/UpdateItemImage.php"
let baseURL = NSURL(string: "\(server)\(phpFile)")
let url = NSURL(string: "?json=\(jsonEncoded)", relativeToURL: baseURL)
let cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData
let request = NSMutableURLRequest(URL: url!, cachePolicy: cachePolicy, timeoutInterval: 10.0)
request.HTTPMethod = "POST"
let dataString = ""
let requestBodyData = (dataString as NSString).dataUsingEncoding(NSUTF8StringEncoding)
request.HTTPBody = requestBodyData
var response: NSURLResponse? = nil
do {
let reply = try NSURLConnection.sendSynchronousRequest(request, returningResponse:&response)
return true
} catch {
return false
}
}
PHP
<?php
// Setup DB connection etc..
//..
//Define passed variables
$json = $_GET['json'];
$json = stripslashes($json);
$fieldArray = json_decode($json);
$barcode = $fieldArray->{"barcode"};
$imageData = $fieldArray->{"imageData"};
// etc....
?>

Related

Swift POST Request (Base64 Image) to PHP Script

After reading through numerous similar questions I still don't understand what the problem is here.
I'm trying to send a Base64 encoded image to a simple PHP script, here's my Swift code:
func sendImage(encodedImage: String) {
let url = URL(string: "http://www.site.whatever/image_upload.php")
var request = URLRequest(url: url!)
let postString = "encoded_image=\(encodedImage)"
let postData = postString.data(using: String.Encoding.utf8)
request.httpMethod = "POST"
request.httpBody = postData
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request) {
data, response, error in
if error != nil {
// Handle error
return
}
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print(responseString)
}
task.resume()
}
Simple PHP Script
$request_method = $_SERVER["REQUEST_METHOD"];
switch ($request_method) {
case 'POST':
if (isset($_POST["encoded_image"])) {
// POST parameter has been set successfully
$return = ["POSTSET?" => "Yes"];
echo json_encode($return);
}
// POST parameter was not set
$return = ["POSTSET" => "No"];
echo json_encode($return);
}
Problem:
With
let postString = "encoded_image=\(encodedImage)"
Where encodedImage is set with:
let encodedImage = image.pngData()!.base64EncodedString()
it returns {"POSTSET?","No"} // POST was not sent
With
let postString = "encoded_image=some_random_string"
it returns {"POSTSET?","Yes"} // POST sent successfully
I don't know why it works perfectly until I try and send a Base64.
Thoughts:
Is request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") the correct content type?
Should I be setting a content length since the Base64 string is so long?
Should request.httpBody be encoded using something other than String.Encoding.utf8?
Should my PHP be expecting something different to what Swift is sending?
Any insight would be helpful, thanks.
The string length I was seeing for a Base64 encoded PNG was around 12 million characters on average. The server on which the PHP script is running isn't capable of accepting the request and would result in an error.
I sent a JPG to the API instead, the Base64 string is closer to 3 million when sent like this.
let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
let imageData = image.jpegData(compressionQuality: 1)!
let encodedImage = imageData.base64EncodedString()
This successfully sends the image, allowing me to decode and save on the back end.

retrieve json data through $_POST from post request of alamofire swift3?

guys, i am having problem of posting json data through alamofire 4 with swift3 and also the problem of retrieving the json data at XAMPP server side using php.
My swift 3 code did trigger the php script at XAMPP, but somehow i can't get it through $_POST variable in php
Here is my code,
func uploadImage(image: UIImage){
//Now use image to create into NSData format
let imageData:NSData = UIImagePNGRepresentation(image)! as NSData
//convert the nsdata to base64 encoded string
let strBase64:String = imageData.base64EncodedString(options: .lineLength64Characters)
// let parameters = ["image": strBase64] as Dictionary
let parameters = ["image": strBase64]
print(strBase64)
Alamofire.request("http://localhost/Test/api/UploadPhoto.php",method: .post, parameters: parameters, encoding: JSONEncoding.default).response { response in
print(response)
}
}
Here is my server side code(the script did get triggered by the call from alamofire, but somehow i just can't get the data through calling$_POST["image"])
<?php
//scripts below did get triggered, but can't get the json data through calling $_POST["image"];
$imageString = $_POST["image"];
$filename_path = md5(time().uniqid()).".png";
$data = base64_decode($imageString);
file_put_contents('../AllImages/'.$filename_path, $data);
echo json_encode($_POST["image"]);
?>
if possible, please help me, i have been struggled for nearly a week, but can't find many clues
Thank you
i have found a way to solve this problem, basically, i used urlsession.shared.datatask to help me instead of alamofire with the post request,
here is my ios side code
func uploadImage(image: UIImage, completionHandler: #escaping (String) ->()){
// Now use image to create into NSData format
let imageData:NSData = UIImagePNGRepresentation(image)! as NSData
//convert the nsdata to base64 encoded string
let strBase64:String = imageData.base64EncodedString(options: .lineLength64Characters)
// prepare json data
let json: [String: Any] = ["image": strBase64]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
// create post request
let url = URL(string: "http://10.10.10.72/Test/api/UploadPhoto.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
// insert json data to the request
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
do {
guard let data = data else {
throw JSONError.NoData
}
guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: AnyObject] else {
throw JSONError.ConversionFailed
}
completionHandler(json["sign"] as! String)
} catch let error as JSONError {
print(error.rawValue)
} catch let error as NSError {
print(error.debugDescription)
}
}
task.resume()
}
i used dictionary to store my data, and converted it to json data format to be sent to server
let json: [String: Any] = ["image": strBase64]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
Then at the php side, i retrieved it by using
$entityBody = file_get_contents('php://input');
, then i decoded from json which produced me an array and i can access my value by referencing image, so full php side of code as below:
<?php
//get the posted json data
$entityBody = file_get_contents('php://input');
//decode the json data
$decoded = json_decode($entityBody, TRUE);
$imageString = $decoded["image"];
//create a unique name for the image
$filename_path = md5(time().uniqid()).".png";
//converted the image string back to image
$data = base64_decode($imageString);
//put it on the desired location
file_put_contents('../AllImages/uploads/signature/'.$filename_path, $data);
$response = array();
//create the response
$response['sign'] = '../AllImages/uploads/signature/'.$filename_path;
echo json_encode($response);
?>
do note here, i encode the json data again to be sent back as a response from php to my ios side, and you need to decode the response from json, so the full idea is if you encode the value to json from one side, you need to decode it from another side to access the value properly, correct me if i am wrong, i am glad that my app is up and running now with all the requests now :D

How to send a POST request in Swift with a variable

I am trying to send a POST request to a web server, however the value I am trying to send is in a variable named temperatureValue. The web server looks for the POST variable "temperature". This is how I am declaring my postData. How do I pass in this variable?
let postData = NSMutableData(data: "temperature=temperatureValue".dataUsingEncoding(NSUTF8StringEncoding)!)
The rest of the code for the POST is included below, but my main question is how to format the above to allow my variable temperatureValue to be saved into postData.
//Assign the url post address, post the data to the php page
let request = NSMutableURLRequest(URL: NSURL(string: "http://pi.access.com/stateBlinds.php")!,
cachePolicy: .UseProtocolCachePolicy,
timeoutInterval: 10.0)
request.HTTPMethod = "POST"
request.HTTPBody = postData
let session = NSURLSession.sharedSession()
let dataTask = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? NSHTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
You can use string interpolation:
let temperatureValue = 10.5
request.HTTPBody = "temperature=\(temperatureValue)".dataUsingEncoding(NSUTF8StringEncoding)
If temperatureValue is an optional, though, you have to unwrap it.
let temperatureValue: Double? = 10.5
let postString: String
if let value = temperatureValue {
postString = "temperature=\(value)"
} else {
postString = "temperature="
}
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
Also note that this very simple example works only if dealing with very simple "values" (e.g. just alphanumeric with no spaces or special characters). If you take this pattern and try it with general strings, you have to percent-escape the value. But for simple numeric values, the above will suffice.

Submitting properly escaped JSON to PHP in a POST request with Swift

I have been struggling to get a web service to work with a native Swift application when a user is attempting to upload data using the "&" character, amongst others.
After various attempts at escaping the request, I am at a loss and looking for some advice to solving this. I have included a some code from both the Swift application and the PHP scripts for reference. The data is able to be posted to the server (I am using FileMaker Server PHP API), but not when the "&" is included in a user-submitted value as the JSON is being cut short when PHP hits that character.
The postData argument in the Swift request sample is a dictionary in JSON format, which is encoded using the below code from JSONStringify:
func JSONStringify(value: AnyObject, prettyPrinted: Bool = false) -> String {
let options = NSJSONWritingOptions.PrettyPrinted
if NSJSONSerialization.isValidJSONObject(value) {
do {
let data = try NSJSONSerialization.dataWithJSONObject(value, options: options)
if let string = NSString(data: data, encoding: NSUTF8StringEncoding) {
return string as String
}
} catch {
return ""
}
}
return ""
}
Swift Request
class func returnAnyObject (phpFile:String, postData:String) -> AnyObject? {
let server:String = "http://myserver.com"
let url = NSURL(string: "\(server)\(phpFile)")
let cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData
let request = NSMutableURLRequest(URL: url!, cachePolicy: cachePolicy, timeoutInterval: 10.0)
request.HTTPMethod = "POST"
// set data
let dataString = postData.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
let requestBodyData = (dataString as NSString).dataUsingEncoding(NSUTF8StringEncoding)
request.HTTPBody = requestBodyData
var response: NSURLResponse? = nil
do {
let reply: NSData = try NSURLConnection.sendSynchronousRequest(request, returningResponse:&response)
if let results = NSString(data:reply, encoding:NSUTF8StringEncoding) {
return results
} else {
return nil
}
} catch {
return nil
}
}
PHP
Below is the relevant portion of the PHP script. Perhaps there is some step I am missing with this as well?
<?php
error_reporting(E_ERROR | E_WARNING | E_PARSE);
$req1 = '../../FileMaker.php';
$req2 = '../../FM_Connect.php';
require_once $req1;
require_once $req2;
//set fixed variables
$layout = 'php_Lineitems';
//Define passed variables
$json = $_POST['json'];
$json = stripslashes($json);
$fieldArray = json_decode($json); // This is now an associative array
?>
Don't put the JSON as a string, you don't need to stringify it, should be of NSData type.
Then you set that in the body of your request directly.
Note on the PHP side you won't be able to access $_POST['json'].
You will need to change your code to:
$json = json_decode(file_get_contents('php://input'));

POST with swift and API

I've a problem when I try to send a POST request to my API on my server, I've followed many many different tutorials but it still doesn't work.
I know than my problem is with the POST request but I can't solve it !
So this is my code in Swift and my API in php : (and yes I've replaced the xxxx by the real IDs in my code)
To sum up server receive the request and for example if I manually enter a pseudo it works, It's really the POST method who doesn't work.. The server doesn't receive the POST parameter
Swift code :
var request = NSMutableURLRequest(URL: NSURL(string: "http://localhost:8888/academy/test.php")!)
var session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
var params = ["pseudo":"test"] as Dictionary<String, String>
var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
println("Response: \(response)")
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Body: \(strData)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
if(err != nil) {
println(err!.localizedDescription)
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: '\(jsonStr)'")
}
else {
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
if let parseJSON = json {
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
var success = parseJSON["success"] as? Int
println("Succes: \(success)")
}
else {
// Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: \(jsonStr)")
}
}
})
task.resume()*/
PHP Code :
$BDD_hote = 'xxxxx';
$BDD_bd = 'xxxxx';
$BDD_utilisateur = 'xxxxx';
$BDD_mot_passe = 'xxxxx';
try{
$bdd = new PDO('mysql:host='.$BDD_hote.';dbname='.$BDD_bd, $BDD_utilisateur, $BDD_mot_passe);
$bdd->exec("SET CHARACTER SET utf8");
$bdd->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
}
catch(PDOException $e){
echo 'Erreur : '.$e->getMessage();
echo 'N° : '.$e->getCode();
}
$pseudo = addslashes($_POST["pseudo"]);
$req = $bdd->query("SELECT * from users WHERE pseudo='$pseudo'");
$resultArray = array();
$donnees = $req->fetch();
echo json_encode($donnees);
Thanks by advance :)
As others have pointed out, the encoding of the request is not quite right. Your server code is not expecting JSON request, but rather is using $_POST variables (which means that the request should have Content-Type of application/x-www-form-urlencoded). So that's what you should create. For example in Swift 3 and later:
var request = URLRequest(url: url)
request.httpMethod = "POST"
let parameters = ["somekey" : "valueforkey"]
request.setContent(with: parameters)
let task = session.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error ?? "Unknown error")
return
}
// your response parsing code here
}
task.resume()
The setContent method would take a dictionary of the form ["key1": "foo", "key2" : "bar"] and populate the httpBody with something that looks like key1=foo&key2=bar. If you do that, the server will be able to parse the $_POST from the request.
extension URLRequest {
/// Set body and header for x-www-form-urlencoded request
///
/// - Parameter parameters: Simple string dictionary of parameters to be encoded in body of request
mutating func setContent(with parameters: [String: String]) {
setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let array = parameters.map { entry -> String in
let key = entry.key.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)!
let value = entry.value.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)!
return key + "=" + value
}
httpBody = array.joined(separator: "&").data(using: .utf8)!
}
}
Note, this also percent-encodes the values (and, just in case, the keys, too), which is critical. While others have advised using addingPercentEncoding with .urlQueryAllowed, sadly that will not do the job, as it will let certain reserved characters (notably +) pass unescaped. Most web services will interpret the + as a space, in conformance with the x-www-form-urlencoded spec. So, adapting an approach adopted by Alamofire, I define a character set which will encode values with the various delimiters:
extension CharacterSet {
/// Returns the character set for characters allowed in the individual parameters within a query URL component.
///
/// The query component of a URL is the component immediately following a question mark (?).
/// For example, in the URL `http://www.example.com/index.php?key1=value1#jumpLink`, the query
/// component is `key1=value1`. The individual parameters of that query would be the key `key1`
/// and its associated value `value1`.
///
/// According to RFC 3986, the set of unreserved characters includes
///
/// `ALPHA / DIGIT / "-" / "." / "_" / "~"`
///
/// In section 3.4 of the RFC, it further recommends adding `/` and `?` to the list of unescaped characters
/// for the sake of compatibility with some erroneous implementations, so this routine also allows those
/// to pass unescaped.
static var urlQueryValueAllowed: CharacterSet = {
let generalDelimitersToEncode = ":#[]#" // does not include "?" or "/" due to RFC 3986 - Section 3.4
let subDelimitersToEncode = "!$&'()*+,;="
var allowed = CharacterSet.urlQueryAllowed
allowed.remove(charactersIn: generalDelimitersToEncode + subDelimitersToEncode)
return allowed
}()
}
For Swift 2 rendition, see previous revision of this answer.
Try this:
let myURL = NSURL(string: "http://localhost:8888/academy/test.php")!
let request = NSMutableURLRequest(URL: myURL)
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
let bodyStr:String = "pseudo=test"
request.HTTPBody = bodyStr.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
// Your completion handler code here
}
task.resume()
You have to encode your data using UTF8 string encoding. If you need to set more than one field&value pairs for request body, you can change the body string, for example, "pseudo=test&language=swift". In fact, I usually create an extension for NSMutableURLRequest and add a method which takes a dictionary as parameter and sets the content of this map(dictionary) as HTTPBody using correct encoding. This may work for you:
extension NSMutableURLRequest {
func setBodyContent(contentMap: Dictionary<String, String>) {
var firstOneAdded = false
let contentKeys:Array<String> = Array(contentMap.keys)
for contentKey in contentKeys {
if(!firstOneAdded) {
contentBodyAsString += contentKey + "=" + contentMap[contentKey]!
firstOneAdded = true
}
else {
contentBodyAsString += "&" + contentKey + "=" + contentMap[contentKey]!
}
}
contentBodyAsString = contentBodyAsString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
self.HTTPBody = contentBodyAsString.dataUsingEncoding(NSUTF8StringEncoding)
}
}
And you can use this as:
request.setBodyContent(params)
I hope this helps you!
the following php code is for receiving application/url+encode encoded post message. please refer https://en.wikipedia.org/wiki/Percent-encoding
$_POST["pseudo"]
and your swift code was sending a JSON encoded string data. They are incompatible.
If you don't want to change the php code, in Swift you should send url-encode format message, li:
// UPDATED with corrections from #Rob
var params = ["param1":"value1", "papam2": "value 2"]
var body = ""
for (key, value) in params {
body = body.stringByAppendingString(key)
body = body.stringByAppendingString("=")
body = body.stringByAppendingString(value.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!)
body = body.stringByAppendingString("&")
}
body = body.substringToIndex(advance(body.startIndex, countElements(body)-1)) // remove the last "&"
request.HTTPBody = body.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)

Categories