Sending data to PHP server - ios

I'm trying to set up sending data to a PHP server but I'm having no luck at all.
Here is my PHP code.
<?php
require_once "../config/config.php";
var_dump($_POST);
var_dump($_REQUEST);
// Read request parameters
if(isset($_REQUEST)){
$username = $db->escape($_REQUEST["username"]);
$email = $db->escape($_REQUEST["email"]);
$password = $db->escape($_REQUEST["password"]);
$id = MD5($email);
echo $username;
//$db->query("INSERT INTO user ('id','username','email','password') VALUES ('$id','$username','$email',PASSWORD('$password'))");
$returnValue = $id;
}else{
$returnValue = "No data received";
}
// Send back request in JSON format
echo json_encode($returnValue);
?>
Here is my Swift Code
let request = NSMutableURLRequest(URL: NSURL(string: "http://***************/register.php")!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
let data = "username=JoeBloggs&email=joe#bloggs.com&password=12345"
request.HTTPBody = (data as NSString).dataUsingEncoding(NSUTF8StringEncoding)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
print(response)
let strData = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(strData)
print(error)
}
task.resume()
I'm not concerned about getting a result back yet (I have that working fine). I just can't get any data to the server.
Here is the result from the above script.
Optional(<NSHTTPURLResponse: 0x7ff9b3d6ea90> { URL: http://iep.almartin.co.uk/register.php } { status code: 200, headers {
"Cache-Control" = "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
Connection = close;
"Content-Type" = "text/html; charset=UTF-8";
Date = "Tue, 01 Sep 2015 09:02:46 GMT";
Expires = "Thu, 19 Nov 1981 08:52:00 GMT";
Pragma = "no-cache";
Server = nginx;
"Set-Cookie" = "PHPSESSID=8j2d7oobg9plvdik1dcbqtoq70; path=/";
"Transfer-Encoding" = Identity;
} })
Optional(array(0) {
}
array(0) {
}
<br />
<b>Notice</b>: Undefined index: username in <b>/home/linweb34/i/iep.almartin.co.uk/user/htdocs/register.php</b> on line <b>7</b><br />
<br />
<b>Notice</b>: Undefined index: email in <b>/home/linweb34/i/iep.almartin.co.uk/user/htdocs/register.php</b> on line <b>8</b><br />
<br />
<b>Notice</b>: Undefined index: password in <b>/home/linweb34/i/iep.almartin.co.uk/user/htdocs/register.php</b> on line <b>9</b><br />
"d41d8cd98f00b204e9800998ecf8427e")
nil
As you can see both $_REQUEST and $_POST are returning empty arrays.
What am I doing wrong?

The error clearly says that there is problem with your MySQL usage.
Following are the working code template. It uses PDO for DB connection.
function __construct() {
$this->conn = new PDO('mysql:host=<your hostnam>;dbname=<dbname>', '<user>', '<pass>');
// Generate stack trace on failure.
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
/*
* Write a function and pass your variables
*/
function get_data_from_db($id,$username,$password,$email) {
$stmt = $this->conn->prepare("INSERT INTO `user`(`id`,`username`,`email`,`password`) VALUES (:id,:username,:email,PASSWORD(:password))");
$stmt->execute(array(':id' => $id, ':username' => $username, ':email' => $email, ':password' => $password));
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->closeCursor();
return $data;
}
Now in your code, just add a function call and you are done:
if(isset($_REQUEST)){
$username = $db->escape($_REQUEST["username"]);
$email = $db->escape($_REQUEST["email"]);
$password = $db->escape($_REQUEST["password"]);
$id = MD5($email);
$result = get_result_from_db($id,$username,$password,$email);
echo json_encode($result);
}
Note : Not tested, but it should work.

Found the problem.
It seems these lines are the culprit in my app.
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
It worked fine when I removed them.
Which brings up another question, how do I set up PHP to accept header type "application/json" ?

To send JSON to a server with POST you have to put the data to be sent into a dictionary and serialize the dictionary with NSJSONSerialization
let request = NSMutableURLRequest(URL: NSURL(string: "http://***************/register.php")!)
let session = NSURLSession.sharedSession()
let postData = ["username" : "JoeBloggs", "email" : "joe#bloggs.com", "password" : "12345"]
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(postData, options: NSJSONWritingOptions())
request.HTTPMethod = "POST"
request.setValue("\(jsonData.length)", forHTTPHeaderField:"Content-Length")
request.setValue("application/json", forHTTPHeaderField:"Accept")
request.setValue("application/json", forHTTPHeaderField:"Content-Type")
request.HTTPBody = jsonData
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
print(response)
let strData = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(strData)
print(error)
}
task.resume()
} catch let error as NSError {
print(error)
}

So I followed #vadian answer which didn't work initially. I did some research into why PHP wasn't accepting application/json.
I got it to work by using $HTTP_RAW_POST_DATA instead of $_POST or $_REQUEST in the php file.
However! $HTTP_RAW_POST_DATA is now depreciated but the following code works
$json = file_get_contents('php://input');
$obj = json_decode($json);
Seems like a PHP hack to me but at least it works.

Related

Alamofire and Digest-Auth

I am trying to implement in my Apps Digest-auth but i am struggling, or is not working properly.
I have setup my request as you describe in your AuthenticationTestCase and looks like the following code:
let userName = "***********"
let password = "***********"
let qop = "auth"
let xmlStr: String = "<?xml version=\"1.0\" encoding=\"utf-8\"?><methodCall><methodName>authenticate.login</methodName></methodCall>"
let postData:Data = xmlStr.data(using: String.Encoding.utf8, allowLossyConversion: true)!
let url = URL(string: "https://app.**********.co.uk/service/mobile/digest-auth/\(qop)/\(userName)/\(password)")
var request = URLRequest(url: url!)
request.httpShouldHandleCookies = true
request.setValue("\(String(describing: xmlStr))", forHTTPHeaderField: "Content-Length")
request.setValue("application/xml", forHTTPHeaderField: "Content-Type")
request.setValue("IOS133928234892nil", forHTTPHeaderField: "User-Agent")
request.setValue("application/xml", forHTTPHeaderField: "Accept")
request.httpMethod = "POST"
request.httpBody = postData
AF.request(request)
.authenticate(username: userName, password: password)
.response { response in ........
When I run the above code, I am receiving the following response from the remote server:
Response XML Error:
You must be authenticated to access this resource
Response Error Code: 401
Response Headers:
Optional([AnyHashable("X-Powered-By"): PHP/7.1.33, AnyHashable("Pragma"): no-cache, AnyHashable("Content-Length"): 310, AnyHashable("Date"): Fri, 22 May 2020 09:15:48 GMT, AnyHashable("Server"): Apache/2.4.41 () OpenSSL/1.0.2k-fips PHP/7.1.33, AnyHashable("Cache-Control"): no-store, no-cache, must-revalidate, AnyHashable("Content-Type"): Content-Type: application/xml, AnyHashable("Www-Authenticate"): Digest realm="Mobile",nonce="31JEmMdeSVfXWQ:OT/ndHY6ch/PjqFwA6uutg",opaque="c81e728d9d4c2f636f067f89cc14864c",qop="auth",algorithm="MD5", Digest realm="Mobile",nonce="31JEmMdeSVfXWQ:OT/ndHY6ch/PjqFwA6uutg",opaque="c81e728d9d4c2f636f067f89cc14864c",qop="auth",algorithm="SHA-512-256", Digest realm="Mobile",nonce="31JEmMdeSVfXWQ:OT/ndHY6ch/PjqFwA6uutg",opaque="c81e728d9d4c2f636f067f89cc14864c",qop="auth",algorithm="SHA-256", AnyHashable("Connection"): Keep-Alive, AnyHashable("Keep-Alive"): timeout=5, max=100, AnyHashable("Expires"): Thu, 19 Nov 1981 08:52:00 GMT])
Note: If I do the same request via Postman, it works properly.
It looks like the Alamofire is not properly handling the Digest challenge.
Please could you help me on this issue?

HTTP Post Request data could not be read Swift 3

I've been trying to get data by Http "POST" method.In my php script i have a key call "categoryWise" which has a value called "flower".I put all the necessary codes but it doesn't work and says The data couldn’t be read because it isn’t in the correct format.Please help.
let values = "categoryWise= nature"
let parameter = values.data(using: .utf8)
let url = "https://mahadehasancom.000webhostapp.com/WallpaperApp/php_scripts/getImageByCategory.php"
var request = URLRequest(url: URL(string: url)!)
request.httpMethod = "POST"
request.httpBody = parameter
request.setValue("application/x-content-type-options", forHTTPHeaderField: "Content-Type")
request.setValue("application/x-content-type-options", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if (error != nil)
{
print(error!)
}
else
{
do
{
let fetchData = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
//print(fetchData)
let actorArray = fetchData?["result"] as? NSArray
for actor in actorArray!
{
let nameDict = actor as? NSDictionary
let name = nameDict?["date"] as! String
let countryname = nameDict?["category"] as! String
let imageUrl = nameDict?["url"] as! String
//let pageUrl = nameDict?["url"] as! String
authorArray.append(name)
titleArray.append(countryname)
imageURL.append(imageUrl)
//urlArray.append(pageUrl)
}
DispatchQueue.main.async {
self.CountryNameTable.reloadData()
}
print(authorArray)
print(titleArray)
print(imageURL)
print(urlArray)
}
catch let Error2
{
print(Error2.localizedDescription)
if let string = String(data: data!, encoding: .utf8)
{
print(string)
print(response!)
}
}
}
}
task.resume()
A few observations:
You shared PHP that is using $_POST. That means it's expecting x-www-form-urlencoded request. So, in Swift, you should set Content-Type of the request to be application/x-www-form-urlencoded because that's what you're sending. Likewise, in Swift, the Accept of the request should be application/json because your code will "accept" (or expect) a JSON response.
The values string you've supplied has a space in it. There can be no spaces in the key-value pairs that you send in a x-www-form-urlencoded request. (Note, if you have any non-alphanumeric characters in your values key pairs, you should be percent encoding them.)
In your Swift error handler, in addition to printing the error, you might want to try converting the data to a String, and looking to see what it says, e.g.
if let string = String(data: data!, encoding: .utf8) {
print(string)
}
You might also want to look at response and see what statusCode it reported. Having done that, you subsequently told us that it reported a statusCode of 500.
Status code 500 means that there was some internal error in the web service. (The code is 200 if successful.) This is generally a result of some error with the request not being handled correctly. For example, if the request neglected to format the request correctly and the web service doesn't anticipate/catch that, or if there was some other internal error on the web server, you could get 500 error code. For list of status codes, see http://w3.org/Protocols/rfc2616/rfc2616-sec10.html.
If the text in the body of the response from your web service is not illuminating, you might want to turn on error reporting (see How to get useful error messages in PHP? or How do I catch a PHP Fatal Error) and then look at the body of the response again. For example, you might include the following in your PHP:
<?php
function __fatalHandler() {
$error = error_get_last();
//check if it's a core/fatal error, otherwise it's a normal shutdown
if ($error !== NULL && in_array($error['type'], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING))) {
header("Content-Type: application/json");
$result = Array("success" => false, "error" => $error);
echo json_encode($result);
die;
}
}
register_shutdown_function('__fatalHandler');
// the rest of your PHP here
?>

Authenticate Client certificate and get response from server

I am working on get data from client server(ratin24 API). The API basically work after Authentication means I have one certificate and I was authenticate it with NSURLSession "didReceiveChallenge" delegate method. Everything is working fine but now issue is that I Got only header parts as a response not BOTY. so how to get actual data from there. I Pass XML Parameter in request body and the response should be XML but Got only header so please help me how to get BODY data in this situation.
let xmlString = "<?xml version='1.0' encoding='ISO-8859-1'?><TICKETANYWHERE><COUPON VER='1.0'><TEMPLATELIST /></COUPON></TICKETANYWHERE>"
let xmlData = xmlString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let request = NSMutableURLRequest(URL: NSURL(string: "My URL")!)
request.HTTPMethod = "POST"
request.HTTPBody = xmlData
request.addValue("text/html; charset=ISO-8859-1", forHTTPHeaderField: "Content-Type")
struct SessionProperties {
static let identifier : String! = "url_session_background_download"
}
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let backgroundSession = NSURLSession(configuration: configuration, delegate:self as? NSURLSessionDelegate, delegateQueue: NSOperationQueue.mainQueue())
let downloadTask = backgroundSession.downloadTaskWithRequest(request){ (data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
let statusCode = httpResponse.statusCode
if (statusCode == 200) {
print("Everyone is fine, file downloaded successfully.")
}
}
downloadTask.resume()
Response Data (only Header) body ? :
status code: 200, headers {
Connection = close;
"Content-Length" = 23113;
"Content-Type" = "text/html; charset=ISO-8859-1";
Date = "Mon, 27 Jun 2016 11:36:12 GMT";
Server = "Apache/2.2.15 (CentOS)";
}
The response object isn't supposed to contain the body data. An NSURLResponse object contains only metadata, such as the status code and headers. The actual body data should be in the NSData object for a data task, or in the provided file for a download task.
Note that for a download task the first parameter is an NSURL, not an NSData object. That NSURL contains the location of a file on disk from which you must immediately read the response data in your completion handler or move the file to a permanent location.

AFNetworking post parameters not encoding

I'm getting an error using AFNetworking 2.0 while using post method in Swift language because the body isn't encoded as it should be, here is my code:
let manager = AFHTTPRequestOperationManager()
manager.securityPolicy.allowInvalidCertificates = true;
let reqSerializer: AFJSONRequestSerializer = AFJSONRequestSerializer()
reqSerializer.setValue("T-Rex", forHTTPHeaderField: "User-Agent")
reqSerializer.setValue("no-cache", forHTTPHeaderField: "Cache-Control")
reqSerializer.setValue("apikey", forHTTPHeaderField: "Authorization")
manager.requestSerializer = reqSerializer
let resSerializer: AFJSONResponseSerializer = AFJSONResponseSerializer()
resSerializer.acceptableContentTypes = ["text/html", "application/json"]
manager.responseSerializer = resSerializer;
let params: NSDictionary = ["userName" : userName, "passWord" : passWord]
manager.POST(Constants.apiURL.url + "users/login",
parameters:params,
success: { (operation: AFHTTPRequestOperation!, responseObject: AnyObject!) in
NSLog("Success! Response is \(responseObject.description)")
},
failure: { (operation: AFHTTPRequestOperation!, error: NSError!) in
NSLog("Failure! Error is: \(error.localizedDescription)")
})
Debugging the request I get:
POST 'http://api.cc/users/login': {
Accept = "application/json";
"Accept-Language" = "pt;q=1, fr;q=0.9, en;q=0.8";
Authorization = apikey;
"Cache-Control" = "no-cache";
"Content-Type" = "application/json";
"User-Agent" = "T-Rex";
} {"passWord":"123","userName":"123"}
and my server answer:
400 'http://api.cc/users/login' [0.7545 s]: {
Age = 0;
Connection = "keep-alive";
"Content-Length" = 83;
"Content-Type" = "application/json";
Date = "Sun, 06 Sep 2015 01:03:00 GMT";
Server = "nginx/1.8.0";
Via = "1.1 varnish-v4";
"X-Varnish" = 950329;
} {"error":true,"message":"Required field(s) userName, passWord is missing or empty"}
I don't know why the username and password is encoded like this:
{"passWord":"123","userName":"123"}
instead of this:
{"passWord:123&userName":123"}
Should AFHTTPRequestSerializer instead of AFJSONRequestSerializer.
Problem solved.

Receiving projects list using JIRA API

I want make simple JIRA assistant for iOS but cannot figure out why API call return empty array.
For example, using this code i'm trying to get projects list:
let request = NSMutableURLRequest(URL: "http://myjira.atlassian.net/rest/api/2/project".URL!)
request.addValue("Basic " + emailAndPasswordAsb64String, forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.HTTPMethod = "GET"
let session = NSURLSession.sharedSession()
session.dataTaskWithRequest(request) { (data, response, error) -> Void in
guard let data = data, responseString = NSString(data: data, encoding: NSUTF8StringEncoding) as? String where !responseString.isEmpty else {
print("No valid response!", appendNewline: true)
return
}
print("Response: " + responseString, appendNewline: true)
}.resume()
But getting this: Response: []
I'm also tried to use some other API, for example api/2/dashboard, but received this:
Response: {"startAt":0,"maxResults":20,"total":0,"dashboards":[]}
Using api/2/myself i received this:
Response: <?xml version="1.0" encoding="UTF-8" standalone="yes"?><status><status-code>401</status-code><message>Client must be authenticated to access this resource.</message></status>
Maybe i missed something and project can be invisible? But for basic authorization i'm using administrator login and password.
Finally figured it out!
I did two mistakes:
http is wrong, https is right!
emailAndPasswordAsb64String was created using email and password, it's wrong! User should type in username instead of email! For administrator account username is admin by default.
Hope this will help someone!

Resources