Setup sending post request from android to php script - php

Android Retrofit's servise interface:
//#Headers("Authorization: " + BuildConfig.CLIENT_NAME + " " + BuildConfig.CLIENT_PASSWORD)
#FormUrlEncoded
#POST("api/post/report")
Observable<Object> postReport(#Field("message") String message);
Android monitor tells:
--> POST http://<mysite>/api/post/report http/1.1
D/OkHttp: Content-Type: application/x-www-form-urlencoded
D/OkHttp: Content-Length: 104
D/OkHttp: message=%D0%B2%D0%BB%D0%BE%D1%81%D0%B8%3A%20%D1%81%D0%BB%D1%87%D0%BB%D1%8C%D1%8F%D0%B1%D1%8B%D0%B6%D1%8B
D/OkHttp: --> END POST (104-byte body)
I do not know how to catch the Message from PHP.
$_POST - is empty
parse_str(file_get_contents("php://input"), $data);
$data = (object)$data;
Different variants of ^ are also not working. They returns nullable results, empty objects and ext

You are making a POST request.
print_r($_POST);
Should give you the value sent from retrofit.

Ok.ok. I did this:
//#Headers("Authorization: " + BuildConfig.CLIENT_NAME + " " + BuildConfig.CLIENT_PASSWORD)
#POST("api/post/report")
Observable<Object> postReport(#Header("message") String message);
I sent this via Header & catched the message with getHeaders() method...

Related

Empty $request->request and $request->files with multipart/form-data

I am trying to upload a form with a file to my server using AJAX, but Symfony doesn't parse the request body like it should. This is my PHP:
#[Route('/api/upload/file', name: "api_upload_file", methods: ['POST'])]
public function create(Request $request): JsonResponse
{
dump($request->files->all());
dump($request->request->all());
dump($request->getContent());
...
and the dump output (The file part is cut out because it takes a lot of space) :
[]
[]
"""
------WebKitFormBoundaryh4t0I09h9iTRNGme
Content-Disposition: form-data; name="subcategory"
1
------WebKitFormBoundaryh4t0I09h9iTRNGme
Content-Disposition: form-data; name="main_image"; filename=""
Content-Type: application/octet-stream
------WebKitFormBoundaryh4t0I09h9iTRNGme
Content-Disposition: form-data; name="more_images"; filename=""
Content-Type: application/octet-stream
------WebKitFormBoundaryh4t0I09h9iTRNGme
Content-Disposition: form-data; name="original_version"
------WebKitFormBoundaryh4t0I09h9iTRNGme
Content-Disposition: form-data; name="version"
------WebKitFormBoundaryh4t0I09h9iTRNGme
Content-Disposition: form-data; name="original_title"
------WebKitFormBoundaryh4t0I09h9iTRNGme
Content-Disposition: form-data; name="title"
"""
The request clearly gets through so I do not understand why the content is not parsed
Just in case, here is the javascript part : (This looks like JQuery but is not)
form.submit(e => {
e.preventDefault();
let formData = createItemForm.formData();
$.ajax('/api/upload/file', {
headers: {
'Content-Type': 'multipart/form-data'
},
body: formData
})
.then(data => data.json())
.then(json => {
console.log('uploaded');
});
});
How should I do to get the files and the form values in $request->files and $request->request ?
DO NOT specify the Content-Type header yourself, when trying to make such a multipart request. That header needs to include the boundary value (so that the receiver will know how to parse this request) - if you specify it yourself, as just multipart/form-data, then that will be missing.
These request libraries usually know how to properly set it on their own, based on that you are passing in a FormData instance.

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.

What is the equavalent of php getallheaders() function in Angular 4/5?

What is the equavalent of php getallheaders() function in Angular 4/5 ?
I need to get request headers but i can't find this in Angular. I can get only response headers with Angular.
I need to get request header parameters when application start not sending get or post request. In picture i need X-MSISDN and X-IMSI parameters
I try Interceptor class but its only works when i send get or post requests.
Explanation:
I open application with this url : http://localhost:4200/#/
In this time my request header is like this:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Cookie: s_fid=07C355F600B90B3D-291EBB86E5858A2F; s_cc=true; gdslv_s=Less%20than%201%20day; s_vnum=1556196774798%26vn%3D7; s_invisit=true; s_ppvl=login%2520sayfasi%2C100%2C100%2C933%2C375%2C667%2C375%2C667%2C2%2CLP; s_ppv=Welcome%253Atarife%253Aanasayfa%2C100%2C100%2C667%2C375%2C667%2C375%2C667%2C2%2CP; s_ppn=Welcome%3Atarife%3Aanasayfa; gdslv=1524831169979; s_getNewRepeat=1524831169981-Repeat; utag_main=v_id:0162fcdd2735001117d070e941e904072002406a00918$_sn:7$_ss:0$_st:1524832969982$_pn:2%3Bexp-session$ses_id:1524831079859%3Bexp-session$_prevpage:Welcome%3Atarife%3Aanasayfa%3Bexp-1524834769972
Host: localhost:4200
Pragma: no-cache
Referer: http://localhost:4200/
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1
X-IMSI: 286026134103281
X-MSISDN: 905499914581
Request URL : http://localhost:4200/sockjs-node/info?t=1524831359435
I need to take X-IMSI and X-MSISDN parameters.
Following my comment : you could create a service that is in charge of handling all of your headers. That's also a good practice : you centralize the logic of a feature.
Here is an instance of a service that can do that. It can create JSON headers, append new headers to the list, reset them ... See for yourself.
import { Injectable } from '#angular/core';
import { Headers } from '#angular/http';
#Injectable()
export class HeadersManagerService {
private headers: Headers;
constructor() {
this.resetHeaders();
}
resetHeaders() {
this.headers = new Headers();
}
newHeader(key, value) {
this.headers.append(key, value);
}
createJsonHeaders() {
this.resetHeaders();
this.headers.append('Content-Type', 'application/json');
}
getHeaders() {
return this.headers;
}
}
PS: Posting as an answer because it's too long for a comment.
Why don't you try like this
setHeaders() {
const headers = new Headers({
'Content-Type': 'application/x-www-form-urlencoded'
});
const options = new RequestOptions({ headers: headers });
console.log(options.headers);
// return options;
}
In angular if it is object, for example
obj{name:"ABC" , role:"Student"} then Object.keys(obj); will return headers

Receiving a string value from client to server

I am working on Android along with yii-2 php. From my app I am sending some photos in a file using an api call. Along with it I am sending a reference number as shown below.
#Multipart
#POST("installation/photo/save")
Call<ApiResponse> uploadImage(#Header("Authorization") String token, #Part("ref_no") RequestBody ref_no, #Part MultipartBody.Part file);
The call is initialized as shown below
Retrofit retrofit = RetrofitClient.getClient();
RetrofitInterface retrofitInterface = retrofit.create(RetrofitInterface.class);
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("uploaded_file", file.getName(), requestFile);
RequestBody ref_no = createPartFromString("<ref_no>");
ref_no = createPartFromString(installationDetails.getReferenceNo());
Call<ApiResponse> call = retrofitInterface.uploadImage("Bearer " + Common.getAuthKey(mContext),ref_no, body);
call.enqueue(new Callback<ApiResponse>() {
#Override
public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) {
if (response.isSuccessful()) {
Log.d(TAG, response.body().getStatus());
if (response.body().getStatus().equals("OK")) {
snapManager.updateSnapStatus(AssetsManagementContract.SnapEntry.COLUMN_SITE_SNAP, snap.getSnapName(), Constants.SNAP_SYNCED);
Intent broadcastSyc = new Intent();
broadcastSyc.setAction(Common.GetSyncImageAction());
broadcastSyc.putExtra("STATUS", true);
mContext.sendBroadcast(broadcastSyc);
sendImage(mContext);
}
else{
snapManager.updateSnapStatus(AssetsManagementContract.SnapEntry.COLUMN_SITE_SNAP, snap.getSnapName(), Constants.SNAP_CLOSED);
}
} else {
snapManager.updateSnapStatus(AssetsManagementContract.SnapEntry.COLUMN_SITE_SNAP, snap.getSnapName(), Constants.SNAP_CLOSED);
Log.d(TAG, "Error");
}
}
Working of app
User note down the details of installation and take pictures
On closing the form two API's are called
i) API to save/upload installation data to server
ii) API to save/upload images to the server.
The images are uploaded when the Installation API response is returned OK.
OkHttp Log
When the images are pushed to the server below is the call in ok http
--> POST http://ip:port/api/web/v1/installation/photo/save
01-31 08:34:14.723 5762-6086/com.thumbsol.accuratemobileassetsmanagament D/OkHttp: Content-Type: multipart/form-data; boundary=704cd1e5-e4d5-4d2e-be63-81f5fe3f1aef
01-31 08:34:14.723 5762-6086/com.thumbsol.accuratemobileassetsmanagament D/OkHttp: Content-Length: 116027
01-31 08:34:14.724 5762-6086/com.thumbsol.accuratemobileassetsmanagament D/OkHttp: Authorization: Bearer key
01-31 08:34:14.745 5762-6086/com.thumbsol.accuratemobileassetsmanagament D/OkHttp: --704cd1e5-e4d5-4d2e-be63-81f5fe3f1aef
01-31 08:34:14.747 5762-6086/com.thumbsol.accuratemobileassetsmanagament D/OkHttp: Content-Disposition: form-data; name="ref_no"
01-31 08:34:14.748 5762-6086/com.thumbsol.accuratemobileassetsmanagament D/OkHttp: Content-Transfer-Encoding: binary
01-31 08:34:14.748 5762-6086/com.thumbsol.accuratemobileassetsmanagament D/OkHttp: Content-Type: multipart/form-data; charset=utf-8
01-31 08:34:14.754 5762-6086/com.thumbsol.accuratemobileassetsmanagament D/OkHttp: Content-Length: 15
01-31 08:34:14.755 5762-6086/com.thumbsol.accuratemobileassetsmanagament D/OkHttp: 28372250046142R //this is reference number
01-31 08:34:14.755 5762-6086/com.thumbsol.accuratemobileassetsmanagament D/OkHttp: --704cd1e5-e4d5-4d2e-be63-81f5fe3f1aef
01-31 08:34:14.755 5762-6086/com.thumbsol.accuratemobileassetsmanagament D/OkHttp: Content-Disposition: form-data; name="uploaded_file"; filename="28372250046142R_1517369623_site_1.jpg"
01-31 08:34:14.755 5762-6086/com.thumbsol.accuratemobileassetsmanagament D/OkHttp: Content-Type: multipart/form-data
01-31 08:34:14.755 5762-6086/com.thumbsol.accuratemobileassetsmanagament D/OkHttp: Content-Length: 115567
Server Side
At server side below is API code through which images are saved.
public function actionSavephoto()
{
try {
$count = 0;
foreach ($_FILES as $f) {
$dd = pathinfo($f['name']);
if (!isset($dd['extension']) || !in_array($dd['extension'], array('jpg', 'png', 'gif'))) {
return ['status' => 'ERROR', 'uploaded_files' => $count, 'message' => 'Invalid File'];
break;
}
if (move_uploaded_file($f['tmp_name'], Installations::UPLOAD_FOLDER . $f['name'])) {
$count++;
return ['status' => 'OK', 'uploaded_files' => $count];
break;
} else {
return ['status' => 'ERROR', 'uploaded_files' => $count];
break;
}
}
} catch (Exception $x) {
return ['status' => 'ERROR', 'message' => $x->getMessage()];
}
}
The response after var_dump($dd) below is the response that generates.
array(4) {
["dirname"]=>
string(1) "."
["basename"]=>
string(37) "28372230019211U_1517370655_site_1.jpg"
["extension"]=>
string(3) "jpg"
["filename"]=>
string(33) "28372230019211U_1517370655_site_1"
}
In response there is no reference number. How can I get the reference number at server side?
Any help would be highly appreciated.
Check if there is $_POST['ref_no'] present at server side after the call.

Alamofire post request FAILURE error

I'm currently working with Stripe, trying to send a Stripe token to my backend using Alamofire and Heroku. My code is as follows:
func postStripeToken(_ token: STPToken) {
let URL = "https://limitless-fjord-73001.herokuapp.com/charge.php"
let params = ["stripeToken": token.tokenId,
"amount": Int(self.amountTextField.text!)!,
"currency": "usd"] as [String : Any]
Alamofire.request(URL, method: .post, parameters: params)
.responseJSON { response in
print(response.request as Any) // original URL request
print(response.response as Any) // URL response
print(response.data as Any) // server data
print(response.result as Any) // result of response serialization
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}
}
The problem I'm having is that my response.result is printing as FAILURE (see Line 13 above). Everything else seems to be printing fine, including the token and the lines response.request, response.response, and response.data:
Optional(https://limitless-fjord-73001.herokuapp.com/charge.php)
Optional(<NSHTTPURLResponse: 0x600000425400> { URL: https://limitless-fjord-73001.herokuapp.com/charge.php } { status code: 500, headers {
Connection = "keep-alive";
"Content-Length" = 0;
"Content-Type" = "text/html; charset=UTF-8";
Date = "Mon, 29 May 2017 05:58:35 GMT";
Server = Apache;
Via = "1.1 vegur";
} })
Optional(0 bytes)
FAILURE
Any ideas on why I may be getting a failure? Thanks!
It is hard to tell what the problem is from the little you've shown us :)
However, this line:
Optional(<NSHTTPURLResponse: 0x600000425400> { URL: https://limitless-fjord-73001.herokuapp.com/charge.php } { status code: 500, headers {
And more specific this part of the line:
status code: 500, headers
Seems to indicate that you received an error code 500 from your backend, meaning that there was a server side error of some sort.
So, is there a log file somewhere on your server that you could look at and see if it tells you something?
Hope that gives you something to work with.

Categories