Android Kotlin Volley Post String with multiple variable - php

I would like to use POST method to post a string of username and password to a php page but I couldn't find the solution. Thus, i try to use JSONRequest method, but it always gave me the result of Response.ErrorListener. Please help to solve it.
Code for StringRequest:
UserNamePassword = "Name=aaa&Password=bbb"
val queue = Volley.newRequestQueue(this)
val stringRequest = StringRequest(Request.Method.POST, url,
Response.Listener<String> { response ->
// Display the first 500 characters of the response string.
println(response.toString())
}, Response.ErrorListener { println("That didn't work!") })
// Add the request to the RequestQueue.
queue.add(stringRequest)
Code for JSONRequest:
val jsonobj = JSONObject()
jsonobj.put("Name", "aaa")
jsonobj.put("Password", "bbb")
val que = Volley.newRequestQueue(this)
val req = JsonObjectRequest(Request.Method.POST,url,jsonobj,
Response.Listener {
response ->
//println(response["msg"].toString())
println("oooooooooooooookkkkkkkkkkkkkkkkkk")
}, Response.ErrorListener {
println("Error rrrrrrrrrrrrrrr")
}
)
que.add(req)

Trying it
...
}, Response.ErrorListener { error: VolleyError ->
println("Error $error.message")
}
...
we have the follow error message as you said us
06-07 20:46:17.317 10064-10064/com.gph.radiobutton I/Choreographer: Skipped 47 frames! The application may be doing too much work on its main thread.
06-07 20:46:17.320 10064-10064/com.gph.radiobutton I/System.out: Error com.android.volley.ParseError: org.json.JSONException: Value error of type java.lang.String cannot be converted to JSONObject.message
06-07 20:46:17.776 10064-10089/com.gph.radiobutton I/OpenGLRenderer: Davey! duration=1246ms; Flags=0, IntendedVsync=25096758012019, Vsync=25097541345321, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=25097546076936, AnimationStart=25097546158936, PerformTraversalsStart=25097546649936, DrawStart=25097546898936, SyncQueued=25097546932936, SyncStart=25097546989936, IssueDrawCommandsStart=25097547040936, SwapBuffers=25097910009936, FrameCompleted=25098004716936, DequeueBufferDuration=10218000, QueueBufferDuration=5455000,
Then we can see that the problem is another, e.g., an error do occur on your web service and you don't send them as a valid json to the application again.

Related

Dart can not use a response.body as a String

long time listener first time caller.
I make an http request to an API, get a response which I convert to a String variable, which is then used in a subsequent http request however the second request fails.
In tracking the error of my ways I replaced the String variable with an actual string identical to the variable and it works. I got the API to echo back the string it is receiving and it echos back the String that should work as a variable.
here is the PHP function
elseif($_POST['action']=='get_defects'){
$data = get_aircraft_by_token($_POST['token']);
echo $data['Defects'];
}
here is the Dart function
Map<String, String> _getDefects = {
'action': 'get_defects',
'token': _token,
};
await _getHttpRequest(_getDefects);
print(_data);
var parsedJson = jsonDecode(_data) as List;
Defects._defects =
parsedJson.map((jsonItem) => DefectItem.fromJson(jsonItem)).toList();
Defects.saveDefectFile(Defects._defects);
}
}
here is the _getHttpRequest function called...
_getHttpRequest(Map<String, String> _httpRequest) async {
http.Response _response;
String _url = 'https://aircraftdata.flexihubs.com/API/interface.php';
Map<String, String> _header = {
'Content-Type': 'application/x-www-form-urlencoded'
};
_response = await http.post(_url, headers: _header, body: _httpRequest);
_data = _response.body;
}
if I replace
_token = response.body //does not work, response.body=='token'(true)
with
_token = 'token'; //this works no problem
it works? Printing response.body yields 'token', and echoing it yields 'token'; so I am guessing that there is something about the way the encoding works that I do not know, or something else?
Found the issue, thanks to the clue in the comments from Ro.
Solved with String.trim();
I guess there must have been a hidden trailing space that I was unaware of?

JSON request from swift showing empty array in php

I am trying to make a request to a PHP server from my swift app. For some reason php is showing an empty array as the $_REQUEST variable. I have looked through stack overflow and implemented everything I can find that might help, but still getting an empty array in php. Here is the relevant swift code...
func connect(_ pin: String, completion: #escaping(Result<ConnectResponse?, Error>) -> ()) {
let params: [String : Any] = [
"mobile_pin_connect": pin,
"device_info": UIDevice().model,
"additional_info": UIDevice().systemVersion
]
doRequest(params: params) { (data) in
if let data = data {
do {
let res = try JSONDecoder().decode(Dictionary<String, String>.self, from: data)
completion(.success(
ConnectResponse(success: (res["success"] == "true"), connect_id: res["connect_id"] ?? nil, error: res["error"] ?? nil)))
} catch {
completion(.failure(error))
}
} else {
print("in else block")
}
}
}
fileprivate func doRequest(params: [String: Any], completion: #escaping (Data?) -> ()) {
let body = createJsonBody(params)!
self.request.httpBody = body
print("Sending request with thw following variables")
print(String(data: body, encoding: .utf8)!)
print(String(data: self.request.httpBody!, encoding: .utf8))
URLSession.shared.dataTask(with: self.request) { (data, response, error) in
if let error = error {
print("Error in request: \(error)")
completion(nil)
}
let stringResult = String(data: data!, encoding: .utf8)!
let properResult = String(stringResult.map {
$0 == "." ? "=" : $0
})
let decodedData = Data(base64Encoded: properResult)
completion(decodedData)
}.resume()
}
fileprivate func createJsonBody(_ params: [String: Any]) -> Data? {
do {
let jsonData = try JSONSerialization.data(withJSONObject: params)
let body = Data(jsonData).base64EncodedData()
return body
} catch {
print("Unable to create json body: " + error.localizedDescription, error)
return nil
}
}
That sends the request to the server, the setup for the request is in the static var setup...
private static var sharedConnector: ApiConnector = {
let url = URL(string: "https://mywebsiteURLhere.com/api/mobile/challenge")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
let connector = ApiConnector(request)
return connector
}()
So I have the right header values for application/json I have the request method set to post, I am base64encoding the json data and in PHP I have the setup getting php://input...
$rawRequest = file_get_contents("php://input");
and dumping the $_REQUEST variable to an error log, but I always get array\n(\n)\n
it is just showing an empty array
I even did
error_log("Raw request from index.php");
error_log(print_r($rawRequest, true));
and it logs a completely empty line.
I can't figure out why PHP is getting nothing in the request, from everything I have seen online I am doing the request correctly in swift. Any help is really appreciated. Thank you
As per your Swift Code, Can you please replace the following method.
fileprivate func createJsonBody(_ params: [String: Any]) -> Data? {
do {
let jsonData = try JSONSerialization.data(withJSONObject: params)
let body = Data(jsonData)
return body
} catch {
print("Unable to create json body: " + error.localizedDescription, error)
return nil
}
}
You need to replace this line let body = Data(jsonData) with
let body = Data(jsonData).base64EncodedData()
Without seeing your PHP code, it is difficult to determine the entire picture. However, whatever steps you perform to encode your data via the client (Swift) you must reverse to successfully decode the message on the server.
For example, if you prepare and send the request from your client as follows.
Client:
JSON encode data
base-64 encode
send data
The your server must reverse the steps to successfully decode the data.
Server:
recv data
base-64 decode data
JSON decode data
Unless your server requires it, I would remove the base-64 encode step, as it only complicates your encode / decode process.
I have created a working example: https://github.com/stuartcarnie/stackoverflow/tree/master/q59329179
Clone it or pull down the specific code in your own project.
To test, open up a terminal and run the php server:
$ cd q59329179/php
$ php -S localhost:8080 router.php
PHP 7.3.9 Development Server started at Thu Dec 19 10:47:58 2019
Listening on http://localhost:8080
Document root is /Users/stuartcarnie/projects/stackoverflow/q59329179/php
Press Ctrl-C to quit.
Test it works with curl in another terminal session:
$ curl -XPOST localhost:8080 --data-binary '{"string": "foo", "number": 5}'
Note you should see output in the php session:
[Thu Dec 19 11:33:43 2019] Array
(
[string] => foo
[number] => 5
)
Run the Swift test:
$ cd q59329179/swift
$ swift run request
Note again, decoded output in php session:
[Thu Dec 19 11:20:49 2019] Array
(
[string] => string value
[number] => 12345
[bool] =>
)
Your request is probably not arriving through the POST structure, but is kept in the request body.
Try running this as your first PHP operation:
$raw = file_get_contents('php://input');
and see what, if anything, is now into $raw. You should see a Base64 encoded string there, that you need to decode - like this, if you need an array:
$info = json_decode(base64_decode($raw), true);
I've tested your code and it's working fine. The issue might be at your PHP end. I've tested the following code on local server as well as on httpbin
The output from a local server (recent version of XAMPP (php 7.3.12)):
Sending request with thw following variables
eyJhZGRpdGlvbmFsX2luZm8iOiIxMy4yLjIiLCJtb2JpbGVfcGluX2Nvbm5lY3QiOiIxMjM0IiwiZGV2aWNlX2luZm8iOiJpUGhvbmUifQ==
result eyJhZGRpdGlvbmFsX2luZm8iOiIxMy4yLjIiLCJtb2JpbGVfcGluX2Nvbm5lY3QiOiIxMjM0IiwiZGV2aWNlX2luZm8iOiJpUGhvbmUifQ==
message ["additional_info": "13.2.2", "mobile_pin_connect": "1234", "device_info": "iPhone"]
Code:
ApiConnector.swift
import Foundation
import UIKit
class ApiConnector{
var request: URLRequest
private init(request: URLRequest) {
self.request = request
}
public static var sharedConnector: ApiConnector = {
let url = URL(string: "http://localhost/post/index.php")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
let connector = ApiConnector(request: request)
return connector
}()
func connect(_ pin: String, completion: #escaping(Result<Dictionary<String, String>, Error>) -> ()) {
let params: [String : Any] = [
"mobile_pin_connect": pin,
"device_info": UIDevice().model,
"additional_info": UIDevice().systemVersion
]
doRequest(params: params) { (data) in
if let data = data {
do {
let res = try JSONDecoder().decode(Dictionary<String, String>.self, from: data)
completion(.success(res))
} catch {
completion(.failure(error))
}
} else {
print("in else block")
}
}
}
fileprivate func doRequest(params: [String: Any], completion: #escaping (Data?) -> ()) {
let body = createJsonBody(params)!
self.request.httpBody = body
print("Sending request with thw following variables")
print(String(data: body, encoding: .utf8)!)
URLSession.shared.dataTask(with: self.request) { (data, response, error) in
if let error = error {
print("Error in request: \(error)")
completion(nil)
}
let stringResult = String(data: data!, encoding: .utf8)!
print("result \(stringResult)")
let properResult = String(stringResult.map {
$0 == "." ? "=" : $0
})
let decodedData = Data(base64Encoded: properResult)
completion(decodedData)
}.resume()
}
fileprivate func createJsonBody(_ params: [String: Any]) -> Data? {
do {
let jsonData = try JSONSerialization.data(withJSONObject: params)
let body = Data(jsonData).base64EncodedData()
return body
} catch {
print("Unable to create json body: " + error.localizedDescription, error)
return nil
}
}
}
ViewController.swift
import UIKit
class ViewController: UIViewController {
let session = URLSession.shared
override func viewDidLoad() {
super.viewDidLoad()
ApiConnector.sharedConnector.connect("1234") { (result) in
switch result {
case .success(let message):
print("message \(message)")
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
index.php
echo file_get_contents("php://input");
You can verify your code by doing a request to https://httpbin.org/post
output:
Sending request with thw following variables
eyJkZXZpY2VfaW5mbyI6ImlQaG9uZSIsImFkZGl0aW9uYWxfaW5mbyI6IjEzLjIuMiIsIm1vYmlsZV9waW5fY29ubmVjdCI6IjEyMzQifQ==
result {
"args": {},
"data": "eyJkZXZpY2VfaW5mbyI6ImlQaG9uZSIsImFkZGl0aW9uYWxfaW5mbyI6IjEzLjIuMiIsIm1vYmlsZV9waW5fY29ubmVjdCI6IjEyMzQifQ==",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-us",
"Content-Length": "108",
"Content-Type": "application/json; charset=utf-8",
"Host": "httpbin.org",
"User-Agent": "SessionTest/1 CFNetwork/1120 Darwin/19.0.0"
},
"json": null,
"origin": "122.173.135.243, 122.173.135.243",
"url": "https://httpbin.org/post"
}
in else block
If you are running an older version of PHP then You might need HTTP_RAW_POST_DATA
Have look at this SO for more info on PHP side.

Swift - Wait for "dataTaskWithRequest" response before proceeding

I know this question has been asked dozens of times before but unfortunately I'm not knowledgable enough with Swift to adapt those answers to my issue.
Basically I have a function that sends a POST request to a php script on a server but the response seems to take longer to receive than it does for my script to utilise the result. It sends a number variable and receives one as a response so I am also converting it from an 'any_object' to an 'NSNumber'.
From what I understand I need to implement a completion handler but I can't seem to figure out how to get it to work with my code below.
var dataResult: Int = 0
var dataReceived: NSNumber?
func remoteRand() {
let dataToSend = 1
let myUrl = NSURL(string: "http://localhost/scripts/phpScript.php")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let postString = "dataToSend =\(dataToSend)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
dispatch_async(dispatch_get_main_queue()) {
if (error != nil) {
self.displayAlertMessage((error?.localizedDescription)!)
return
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
if let parseJSON = json {
let dataReceived = parseJSON["dataValue"]
self.dataResult = (dataReceived as! NSNumber).integerValue
print("\(self.dataResult) is server response")
}
} catch { print(error)}
}
}
task.resume()
processResult()
}
func processResult() {
print(dataResult)
}
The result I get is:
0
1 is server response
How do I either make it wait for the response before proceeding to the next function or trigger the next function once completion is confirmed?
Thanks in advance!
The task completes on a different thread than which it is called, this is by design so network requests don't stop execution on the main thread. So your block of code is sent off async and processResult is called before the network request is finished. You can put the call in the do block or add a closure to the method that can be called.
func remoteRand(completion: (response: Int) ->()) {
// your code
// process JSON
// get value
completion(dataReceived)
// is passed back, just like the dataTaskWithRequest method to your caller where you can set the property on self, etc.
}
using it somewhere:
remoteRand { [weak self] (response) in
self?.dataResult = response
}

Xcode - Swift - NSURL : "fatal error: unexpectedly found nil while unwrapping an Optional value"

I'm trying to test an OAuth2 implementation in a Xcode Playground, using a PHP API and a Swift client. Basically, my code looks like this
let url = NSURL(string: "http://localhost:9142/account/validate")!
var request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.HTTPBody!.setValue("password", forKey: "grant_type")
// Other values set to the HTTPBody
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { (response, data, error) in
// Handle response here
}
But I keep getting this error when I instantiate the url variable :
fatal error: unexpectedly found nil while unwrapping an Optional value
I tried not unwrapping it when I instantiate it but rather when I use it, it didn't change anything, the error appears on the first time I unwrap it.
It keeps getting even weirder.. The following
let url = NSURL(string: "http://localhost:9142/account/validate")!
println(url)
outputs
http://localhost:9142/account/validate
fatal error: unexpectedly found nil while unwrapping an Optional value
I really don't understand where the error can come from, as I'm really new to Swift
What is happening is you are forced unwrapping the HTTPBody which is set to nil, causing a runtime error at this line:
request.HTTPBody!.setValue("password", forKey: "grant_type")
You need to create an NSData object for your request body and then assign it to the request.HTTPBody as per the following code:
let url = NSURL(string: "http://localhost:9142/account/validate")!
var request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
// Create a parameter dictionary and assign to HTTPBody as NSData
let params = ["grant_type": "password"]
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: NSJSONWritingOptions.allZeros, error: nil)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { (response, data, error) in
// Handle response here
}
I hope this helps solves your problem.
Update:
In order to serialise data without using a JSON serializer, you can create your own similar to below:
func dataWithParameterDictionary(dict: Dictionary<String, String>) -> NSData? {
var paramString = String()
for (key, value) in dict {
paramString += "\(key)=\(value)";
}
return paramString.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
}
and call it like such:
let dict = ["grant_type": "password"]
let data = dataWithParameterDictionary(dict)
request.HTTPBody = data

Cocoa error 3840 The operation couldn’t be completed

I am trying to connect to my localhost API (that I need to build along with the iOS swift app) that returns a json string. The API is written in Laravel 4 framework.
Here is the iOS Swift code to connect and receive the code:
func checkEmail() {
var request = NSMutableURLRequest(URL: NSURL(string: "http://localhost:3306/laravel/rojectapi/checkEmail"))
var session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
var params = ["email":"myemail#me.com", "password":"password"] as Dictionary
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
println("hey")
if(err) {
println(err!.localizedDescription)
}
else {
var success = json["success"] as? Int
println("Success: \(success)")
}
})
task.resume()
}
The Laravel PHP Route:
Route::post('/checkEmail', array(
'as' => 'checkEmail',
'uses' => 'FrontEndController#checkEmail'
));
And then the front-end-controller with the checkEmail method:
public function checkEmail() {
$validator = Validator::make(Input::all(), array(
'email' => 'required|unique:users|email'
));
if($validator->fails()) {
return $validator->messages()->toJson();
} else {
return Response::json(array('success' => true));
}
}
Am I not connecting to the server correctly? I need to do so on my iPhone 5s connected to my laptop, as well as in the emulator. I have tried name.local, localhost:<post> and name.local:<post> in the URL.
Update
I got the code from this tutorial
Either pass NSJSONReadingAllowFragments (.AllowFragments in Swift) or format your JSON properly.
A simple google search revealed that error 3840 is caused due to improperly formatted JSON being passed to the iOS JSON parser.
This occurs if the API is expecting some data from you and you are not able to send it or it is not being received by the APi, try to Echo out the parameter which are received by the API as a response to your iOS Request, It may also occur if you APi Implementation has some error in it, though you may be able to see this error in your Web Console.
I have this error, when i add languages to Localizations in project. When i add language, must change from "localizable strings" to "interface builder storyboard". I mean project of iOS app. Could help you.

Categories