I am trying to upload image using below function everything working fine only is i want to send image in post and when i am trying get image getting nothing
This is for call API
Future getUploadImg(access_token,File _image) async {
print("Image: $_image");
String apiUrl = '$_apiUrl/user/upload-profile-image';
final length = await _image.length();
final request = new http.MultipartRequest('POST', Uri.parse(apiUrl));
request.headers['Accesstoken'] = "Bearer $access_token";
request.files.add(new http.MultipartFile('imagefile',_image.openRead(), length));
http.Response response = await http.Response.fromStream(await request.send());
print("Result: ${response.body}");
return json.decode(response.body);
}
My file that is passing to server is:
File: '/storage/emulated/0/Android/data/com.dotsquares.ecomhybrid/files/Pictures/c5df03f7-097d-47ca-a3c5-f896b2a38c086982492957343724084.jpg'
I got the result finally we need to pass string for image sharing my working code if anyone need for help:
Future getUploadImg(access_token,File _image) async {
print("Image: $_image");
var result;
var stream = new http.ByteStream(DelegatingStream.typed(_image.openRead()));
var length = await _image.length();
var uri = Uri.parse('$_apiUrl/user/upload-profile-image');
var request = new http.MultipartRequest("POST", uri);
request.headers['Accesstoken'] = "Bearer $access_token";
var multipartFile = new http.MultipartFile('imagefile', stream, length, filename: basename(_image.path));
request.files.add(multipartFile);
var response = await request.send();
print(" ===================response code ${response.statusCode}");
await response.stream.transform(utf8.decoder).listen((value) {
print(" =====================response value $value");
result = value;
});
return json.decode(result);
}
To avoid the following problems:
write failed
connection closed before ...
Flutter Doctor Error - SocketException: Write failed (OS Error: Broken pipe, errno = 32)
you need to add the correct parameters in the headers.
In my case, these problems occur with uploading images and sending base64 encoded requests. I solved it by adding the following 'connection' header: 'keep-alive':
final response = await this.httpClient.put(
url,
encoding: Utf8Codec(),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
'Accept': "*/*",
'connection': 'keep-alive',
'Accept-Encoding' : 'gzip, deflate, br',
},
body: body,
);
Related
i try to send post request in flutter app like
static Future<List<dynamic>?> postData(data) async {
var body = json.encode(data);
Map<String, String> headers = {"Content-Type": "application/json"};
var url = Uri.http(Config.api, Config.endPoint);
var response = await client.post(url, headers: headers, body: body);
if (response.statusCode == 201) {
var data = jsonDecode(response.body);
return data;
}
return null;
}
this is data was sent
Map data = {
'database': 'school_control_ykt',
'table': 'tablets_helper',
'place': place,
'reason': reason,
'teacher': teacher,
'name': name,
'id_group': id_group
};
postData(data);
but in server side (php) $_POST are empty
i wanna know why $_POST are empty when a send the request in flutter app but in Postman request is send successfully and $_POST have data
enter image description here
Use MultipartRequest as API expect multipart/form-data. Something like this:
var request = MultipartRequest('POST', uri)
..fields = data
var response = await request.send();
This is how I picked a file from device
onPressed: () async {
FilePickerResult? result =
await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: [
'jpg',
'pdf',
'doc'
],
);
List<File> files = result!.paths
.map((path) => File(path!))
.toList();
context
.read<Dropper>()
.fileCheck(result: result);
myfile = files[0];
},
Then I Converted to Uint8List :
Uint8List imgbytes = await myFile.readAsBytes();
Now I am sending that file to Php database
final url = "http://10.0.2.2:8000/api/addSurvey";
final uri = Uri.parse(url);
final response = await api.post(uri, headers: {
'Authorization': token,
}, body: {
"bill_image": imgbytes
}
It throws error msg like this : type 'Uint8List' is not a subtype of type 'String' in type cast
var url = "http://10.0.2.2:8000/api/addSurvey";
Map<String, String> headers = {"Content-Type": "application/json",
'Authorization': token,};
var request = http.MultipartRequest("POST", Uri.parse(url));
if(_image != null){
var pic = await http.MultipartFile.fromBytes('bill_image', imgbytes , filename: 'photo.jpg');
request.files.add(pic);
}
request.send().then((result) async {
http.Response.fromStream(result).then((response) async {
if (response.statusCode == 200)
{
}
else{
}
return response.body;
});
}).catchError((err) => print('merror : '+err.toString())).whenComplete(()
{
});
Try it using multipart request.
if php is accepting parameter as file type File then you need to send image as multipart request i guess.
var headers = {
'Authorization': 'token'
};
var request = http.MultipartRequest('POST', Uri.parse('http://10.0.2.2:8000/api/addSurvey'));
request.files.add(await http.MultipartFile.fromPath('bill_image', 'path to your file'));
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
}
else {
print(response.reasonPhrase);
}
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?
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.
I'm trying to do is submit the device IMEI to be inserted into the database.
However, the returned JSON output from the database shows the IMEI as null.
Here's what's been implemented:
Requester
class Requester
{
....
func postRequest(_ url: URL, headers : Dictionary<String,String>?, data: Data?, callback : #escaping (_ response: HTTPResponseWithData) -> Void) -> Void
{
let request = Factory.httpRequest(url, method: "POST", headers: headers, data: data)
let task = URLSession.shared.dataTask(with: request as URLRequest, completionHandler: {
data, response, error in
print("RESPONSE: \(response)");
})
task.resume()
}
....
}
Factory
class Factory
{
func httpRequest(_ url: URL, method: String, headers: Dictionary<String, String>?, data: Data?) -> URLRequest
{
var request = URLRequest(url: url)
request.httpMethod = method
if headers != nil
{
for (field, value) in headers!
{
request.addValue(value, forHTTPHeaderField: field)
}
}
if data != nil
{
request.httpBody = data
}
return request
}
}
MainVC
let requester = Requester()
#IBAction func sendRequest(_ sender: Any)
{
var json: Dictionary<String, Any> = [:]
json["imei"] = myIMEI
do
{
let data = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
post(theData: data)
}
catch let error as NSError
{
print(error.localizedDescription)
}
}
func post(theData: Data) -> Void
{
self.requester.postRequest("www.url.com", headers: nil, data: theData, callback: {(response: HTTPResponseWithData) -> Void in
if response.statusCode == 200 && response.data != nil && HTTPHeader.isContentTypeJSON(response.mimeType)
{
print(response.data!)
do
{
if let test = try JSONSerialization.jsonObject(with: response.data!, options: JSONSerialization.ReadingOptions()) as? Dictionary<String, Any>
{
print("test = \(test)")
}
}
catch
{
print("ERROR parsing data")
}
}
else
{
}
});
}
What I get back from the output is:
test = ["imei": <null>]
I've looked at numerous questions and answers on SO regarding this, and besides my implementation being in different classes, I don't see what could possibly be wrong.
Here's some snippet of the PHP code:
header("Content-Type: application/json");
$imei = $_POST["imei"];
$something_else = $_POST["something_else"];
$mysqli = new mysqli($host, $userid, $password, $database);
if ($mysqli->connect_errno)
{
echo json_encode(array("success" => false, "message" => $mysqli->connect_error, "sqlerrno" => $mysqli->connect_errno));
exit();
}
echo json_encode( array('imei'=>$imei) );
What exactly is wrong with my POST request implementation that is not allowing me to submit the IMEI to the database?
If it helps, the RESPONSE output is:
RESPONSE: Optional( { URL:
http://www.url.com } { status code: 200, headers {
Connection = "Keep-Alive";
"Content-Type" = "application/json";
Date = "Mon, 02 Jan 2017 08:07:54 GMT";
"Keep-Alive" = "timeout=2, max=96";
Server = Apache;
"Transfer-Encoding" = Identity; } })
UPDATE: After further testing, I replaced the above php code after the header with the following code, and now the imei is reported:
$handle = fopen("php://input", "rb");
$raw_post_data = '';
while (!feof($handle))
{
$raw_post_data .= fread($handle, 8192);
}
fclose($handle);
$request_data = json_decode($raw_post_data, true);
$imei = $request_data["imei"];
I'm confused, why is it the case that the updated php code works but the one involving $_POST does not?
See the $_POST documentation which says it is:
An associative array of variables passed to the current script via the HTTP POST method when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request.
But you're not doing x-www-form-urlencoded request. You're performing an application/json request. So you can't use $_POST. Use php://input (e.g., as discussed here: iOS Send JSON data in POST request using NSJSONSerialization).