JSON decode failed - json

Following is the code snippet where I am observing error: "malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before "(end of string)") at"
Error observed is at the decode_json line. Can someone point out what is the error?
my $serverurl = "http://mycompany.net/rest/api/2/";
my $username = 'my.email#domain.com';
my $password = "mypassword\#2019";
my $i ;
my $test;
my $headers = {Accept => 'application/json', Authorization => 'Basic ' .encode_base64($username . ':' . $password)};
my $client = REST::Client->new();
my $idartinstance;
my $idartinstance1;
if (!$idartinstance)
{
print " Trying to Connect to URL using REST client interface \n\n";
$idartinstance1 = $client->GET($serverurl."serverinfo",$headers);
$idartinstance = decode_json($idartinstance1->responseContent());
}
When I print $idartinstance, I get this:
REST::Client=HASH(0x8682024)->responseContent()
Does this mean, it is not able to find REST client?
[EDIT] I have modified the script as below and no difference in the errors.
my $serverurl = "https://mycompany.net/rest/api/3/";
my $username = 'my.email#domain.com';
my $password = 'pf9fCdkGXmi4pMHiwIh74A0D';
my $headers = {Accept => 'application/json', Authorization => 'Basic ' . encode_base64($username . ':' . $password)};
my $client = REST::Client->new();
if (!$idartinstance)
{
print " Trying to Connect to JIRA using REST client interface \n\n";
$client->GET($serverurl."serverInfo", $headers);
print $client->responseContent();
$idartinstance = decode_json($client->responseContent());
}
Now I have used encoded password. Error is same: malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before "(end of string)"). Tried accessing "https://mycompany.net/rest/api/3/serverInfo" via web browser and able to get the details.

Once you get a response, you have to check that its what you want.
if( $client->responseCode() eq '200' ){
print "Success\n";
}
You may also want to check that the content-type is what you expect. If it's supposed to be JSON, check that it is:
if( $client->responseHeader('Content-Type') =~ m|\Aapplication/json\b| ) {
print "Got JSON\n";
}
Once you've established that you have what you wanted, pass the message body off to the JSON decoder.
my $data = decode_json($client->responseContent());
You might also try to catch errors where you should have valid JSON but don't. The block eval can handle that (and see the many sources of the proper employment of eval for its best use):
my $data = eval { decode_json(...) };
I find that I tend to get the wrong content in two situations:
the wrong endpoint, from which a 404 handler returns HTML
a captive portal, which also returns HTML

I think you're misreading the documentation for the module. From the synopsis there, the example that most closely resembles yours is the first one:
my $client = REST::Client->new();
$client->GET('http://example.com/dir/file.xml');
print $client->responseContent();
Notice, in particular, that this example does nothing with the return value from GET(). In your example you do the equivalent of this:
my $client = REST::Client->new();
my $resp = $client->GET('http://example.com/dir/file.xml');
print $resp->responseContent();
As it happens, although there is no documented return value from GET() [Update: I was wrong here - see the first comment - but the return value is really only intended for chaining method calls], it actually returns the object that it was passed, so your approach should work. But it's generally a bad idea to not follow the documentation.
So what is actually going wrong? Well, I'm not sure. As I said, your approach should (accidentally) work. But the error message you're getting tells us that what you're passing to decode_json() is a REST::Client object, not a string containing JSON. I don't think that's how your code should work. Perhaps the code you've shown us isn't actually the code you're running.
The best approach to debug this is to follow the advice from Quentin in the first comment on your question - print the value that you're trying to pass to decode_json() before passing it to the function. In fact, that's good general programming advice - originally write out your code step by step, and only combine steps once you know that the individual steps are working correctly.
Using your variable names, I think your code should look like this:
my $client = REST::Client->new();
# ...other code...
$client->GET($serverurl."serverinfo", $headers);
print $client->responseContent();
# And, only once you've established that
# $client->responseContent() returns what
# you expect, you can add this:
$idartinstance = decode_json($client->responseContent());
If the print() statement doesn't show you JSON, then update your question to add whatever is printed and we'll take a further look.

Related

GuzzleHttp - Get JSON encoded body

I created an API client for my company to fetch orders from our distributors. I need to acknowledge download of orders back to them with a PUT. The PUT is working properly but I get an error on their confirmation of my acknowledgement.
Using Postman, I get a JSON body message back.
When I PUT a acknowledgement back, I get the following error:
Type error: Argument 1 passed to GuzzleHttp\Client::send() must
implement interface Psr\Http\Message\RequestInterface, instance of
GuzzleHttp\Psr7\Response given, called in
/var/www/orders/app/Http/Controllers/edi/OrderController.php on line 86
This is line 86:
$response = $client->send($apirequest);
The relevant code:
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client as GuzzleHttpClient;
use GuzzleHttp\Psr7\Stream;
use Illuminate\Support\Facades\Input;
use Response;
use XmlParser;
use Psr\Http\Message\RequestInterface;
public function orderConfirm()
{
$uri = config('services.orders.orderack');
$formdata = Input::all();
$orders = Input::get('orders');
try {
$client = new GuzzleHttpClient([
'headers'=> [
'Authorization' => '$user',
'ContractID' => '$contract',
'Content-Type' => 'application/json']
]);
$apirequest = $client->request('PUT', $uri,
['body' => json_encode(
[
$orders
]
)]
);
$response = $client->send($apirequest);
$contents = (string) $response->getBody();
return $contents;
}
catch (RequestException $ex) {
//Exception Handling
echo $ex;
}
Output from Postman was:
"Number of Orders Acknowledged: 1"
from other posts on SO, this:
$contents = (string) $response->getBody();
is the way to get the body and other people fixed their problems, but it's not working for me.
Obviously I'm still missing something here!
Calling $client->request() actually does the request (which is why it's returning an instance of GuzzleHttp\Psr7\Response) instead of building a request object to send later. You don't need to tell the client to send anything because it's already been sent; you just need to set the $response variable to the value of the call to $client->request().
This can be seen in the Body example in their PSR7 documentation.
$response = $client->request('GET', 'http://httpbin.org/get');
To build a request object manually, you will have to create an instance of GuzzleHttp\Psr7\Request using its constructor, as documented under Requests.
// Create a request using a completely custom HTTP method
$request = new \GuzzleHttp\Psr7\Request('MOVE', 'http://httpbin.org/move');
echo $request->getMethod();
// MOVE

Fetching JSON in Perl

I've been working building an emulator in Perl and one of the issues I'm facing is parsing JSON files located in the computer. When I try fetching them from my server, they work fine...
method getContent(\#arrURLS) {
my %arrInfo;
my $resUserAgent = Mojo::UserAgent->new;
foreach my $strURL (#arrURLS) {
$resUserAgent->get($strURL => sub {
my($resUserAgent, $tx) = #_;
if ($tx->success) {
my $strName = basename($strURL, '.json');
my $arrData = $tx->res->body;
$arrInfo{$strName} = $arrData;
}
Mojo::IOLoop->stop;
});
Mojo::IOLoop->start;
}
return \%arrInfo;
}
Let's assume #arrURLS is:
my #arrURLS = ("file:///C:/Users/Test/Desktop/JSONS/first.json", "file:///C:/Users/Test/Desktop/JSONS/second.json");
The above url's are the one's that aren't working, however if I change that to:
my #arrURLS = ("http://127.0.0.1/test/json/first.json", "http://127.0.0.1/test/json/second.json");
it works.
Also I would like to use something better than Mojo::UserAgent because it seems a bit slow, when I was using Coro with LWP::Simple it was much faster but unfortunately Coro is broken in Perl 5.22...
User Agents are mainly for downloading files through http. They are usually not expected to handle filesystem URIs. You need to open and read the file yourself, or use a module like File::Slurp that does it for you.
It could look something like this.
use File::Slurp 'read_file';
method getContent(\#arrURLS) {
my %arrInfo;
my $resUserAgent = Mojo::UserAgent->new;
foreach my $strURL (#arrURLS) {
if (substr($strURL, 0, 4) eq 'file') {
$arrInfo{basename($strURL, '.json')} = read_file($strURL);
} else {
$resUserAgent->get($strURL => sub {
my($resUserAgent, $tx) = #_;
if ($tx->success) {
my $strName = basename($strURL, '.json');
my $arrData = $tx->res->body;
$arrInfo{$strName} = $arrData;
}
Mojo::IOLoop->stop;
});
Mojo::IOLoop->start;
}
}
return \%arrInfo;
}
Myself using WWW::Mechanize for all such tasks. From the doc:
WWW::Mechanize is a proper subclass of LWP::UserAgent and you can also
use any of LWP::UserAgent's methods.
what means you can feed it with file:// type URLs too.
For example, the following one-liner dumps your passwd file.
perl -MWWW::Mechanize -E 'say WWW::Mechanize->new->get("file://etc/passwd")->content'
or an example without any error handling...
use 5.014;
use warnings;
use WWW::Mechanize;
my $mech = WWW::Mechanize->new;
$mech->get('file://some/path');
say $mech->content;
Anyway, probably is better to use for local files some file-based utility, myself using for all file-things the Path::Tiny module, which has (not limited only) an method for file slurping, such:
use Path::Tiny;
my $content = path('/some/path')->slurp;
or just plain perl:
open my $fh, '<', '/some/file' or die "...";
my $content = do { local $/; <$fh> };
close $fh;
It's important always to say what additional modules you're using. I think your code uses Method::Signatures, and I've tested the code below only to check that it compiles with that module in place
Mojolicious is an excellent tool for its purpose, but it is focused on HTTP URLs. LWP::UserAgent is much more general-purpose, and the documentation for LWP says this
Provides an object oriented model of HTTP-style communication. Within this framework we currently support access to http, https, gopher, ftp, news, file, and mailto resources
Your method becomes something like this. It's untested
method get_content(\#urls) {
my %info;
my $ua = LWP::UserAgent->new;
for my $url (#urls) {
my $res = $ua->get($url);
die $res->status_line unless $res->is_success;
my $name = basename($url) . '.json';
my $data = $res->decoded_content;
$info{$name} = $data;
}
\%info;
}
I would also encourage you to drop Hungarian notation in the context of Perl code, as the language already has its sigils that denote the data type
#arrURLS duplicates the information that this arrURLS is an array, while %arrInfo is just wrong as this arrInfo is a hash. $arrData is actually a scalar, although perhaps some indicator that it is also a reference may help, and $arrURLS[0] is also a scalar (hence the dollar)
There is also nothing to stop you using $arrURLS (which is a completely separate variable from #arrURLS)

Lua cURL POST Invalid Json [Pusher API]

I am attempting to use cURL with the Pusher API (pusher.com). However I keep getting the response "Invalid JSON provided (could not parse)". Any help would be appreciated, here is my trigger function:
function trigger(name, data, channel)
string_to_sign = "POST\n/apps/"..pusher_app_id.."/events\n"..params
signature = hmac.digest("sha256", string_to_sign, pusher_secret)
md5 = md5.sumhexa('{"name":"foo","channel":"test-channel","data":"{\"some\":\"data\"}"}');
c = curl.new()
c:setopt(curl.OPT_URL, pusher_server..'apps/'..pusher_app_id..'/events'..'?'..params..'&auth_signature='..signature..'&body_md5='..md5)
c:setopt(curl.OPT_POST, true)
c:setopt(curl.OPT_HTTPHEADER, "Content-Type: application/json")
c:setopt(curl.OPT_POSTFIELDS, '{"name":"'..name..'","channel":"'..channel..'","data":"{\"some\":\"data\"}"}')
c:perform()
c:close()
end
If I print the JSON I am putting in OPT_POSTFIELDS and paste it into a json validator, it is indeed completely valid. According to the docs this is the proper usage for /events and my authentication is also working fine.
I had gone back through my function applying the suggestions moteus commented and was able to resolve my problem by fixing the md5 and applying it to the signature. I am also using the luajson module to take care of encoding. This seemed to fix the issue.
function trigger(name, data, channel)
data_table = {
["name"] = name,
["channel"] = channel,
["data"] = data
}
json_data = json.encode(data_table)
md5 = md5.sumhexa(json_data)
string_to_sign = "POST\n/apps/"..pusher_app_id.."/events\n"..params.."&body_md5="..md5
signature = hmac.digest("sha256", string_to_sign, pusher_secret)
c:setopt(curl.OPT_URL, pusher_server..'apps/'..pusher_app_id..'/events'..'?'..params..'&auth_signature='..signature..'&body_md5='..md5)
c:setopt(curl.OPT_POST, true)
c:setopt(curl.OPT_HTTPHEADER, "Content-Type: application/json")
c:setopt(curl.OPT_POSTFIELDS, json_data)
c:perform()
c:close()
end

JSON feeds context within Drupal 7

I'm trying to connect to a REST web service with Drupal 7. Data is supplied via a url and I want to pull it into the D7 site to create and populate nodes. I'm using the feeds module to map the content and the JSONPath parser as the parser. I have also included Feeds HTTPFetcher Append Headers module so that I can add custom headers in to make sure it is JSON being returned and not badly formatted xml which I was getting before.
Custom headers:
Accept|application/json
Content-Type|application/json
I have a url that looks like http://192.136.0.31:8080/places/getAll
Further to the above I have the Devel module in place which is returning the feed array in the page using the code below in my template.php:
$request = drupal_http_request('http://192.136.0.31:8080/places/getAll', $options);
dpm(drupal_json_decode($request->data));
This is what Devel returns:
... (Array, 1192 elements)
0 (Array, 17 elements)
Address1 (String, 19 characters ) 1-2 The Road name
Address2 (String, 9 characters ) Shuinnad
The problem I'm having is getting this into feeds and mapping to the relevant fields. I don't know what should go in the context field - I have tried $...*, $.*, $...[*] but no luck.
When I click on an Array element from the devel output it shows $...[0]['Address1'] which suggests that should be the context - no luck.
Quick Update - using the drupal_json_decode function I can split the array out how I need to using php
foreach ($json as $section => $items) {
foreach ($items as $key => $value) {
//if ($key == 'Address1') {
echo "$section:\t$key\t: $value<br>";
//}
// check whether the current item is an array!
if(is_array($value)) {
echo "$key is sub array:<br />";
foreach($value as $subKey => $subValue)
echo "$subKey:\t$subValue<br />";
}
}
}
The question still stands, how do I replicate that in Feeds using the JSON parser?
You may need to try this module: Feeds JSONPath Parser
See this tutorial
Context: is where you put the JSONPath expression that represents the path to the array representing your data. For instance, in my file, this would be $.albums.data.*. If this were a PHP array, that would be basically
foreach($facebook['albums']['data'] as $value);
See more at: http://glassdimly.com/blog/tech/drupal-7-feeds-extensible-parsers-jsonpath-map-json-fields/feeds-extensible-parsers#sthash.BrIutjfl.dpuf

Post JSON to Codeigniter controller

I am trying to receive and parse a JSON object sent in a POST request using Codeigniter but I cannot "find" it.
This is my controller code:
public function parse () {
$json = $this->input->post();
$json = stripslashes($json);
$json = json_decode($json);
print_r($json);
}
This is my JSON object:
{"data":"value"}
This is the correct way to do it.
$input_data = json_decode(trim(file_get_contents('php://input')), true);
$post = json_decode($this->security->xss_clean($this->input->raw_input_stream));
When you use $this->input->raw_input_stream you can read it multiple times and its basically the same as file_get_contents('php://input'). This works on CI3. I don't know if it works on CI2.
Try this code, it will output an array with all your parameters.
$this->input->raw_input_stream;
$input_data = json_decode($this->input->raw_input_stream, true);
$input_data will return array
Try this instead
$json = $this->input->post('data');
$json = stripslashes($json);
$json = json_decode($json);
print_r($json);
You need to pass in the key of the data variable you want from the post array as an argument to post()
Firze's answer is correct but here is a more elaborated answer. I am not allowed to comment so I am posting it as an answer.
It has to do with CodeIgniter not being able to fetch JSON. jQuery does some under the hood tricks and transforms your data into form-data-x, that's why it works when you don't specify the content type, don't encode your object, or other situations.
If you want a pure JSON the solution is to use $this->input->raw_input_stream to fetch your JSON and decode it using php's json_decode. Check the full answer and code below:
Retrieve JSON POST data in CodeIgniter
controller:
puplic function exam(){
$obj = file_get_contents('php://input');
$edata = json_decode($obj);
echo $edata->name;
}
Go to post man->type->post
url:http://www.exam.com/exam
formate:json
{
"name":"atm fahim"
}
==>send
make sure you have POST data, using $this->input->post() it will always return empty, you should put on the input type name $this->input->post('name_of_input_text')
Are you sure you're POSTing the data and not doing a GET instead? I ran into this issue earlier today (which is how I found this question) and I was doing a POST but using JSONP which seems to be done with a GET.
CodeIgniter has a function called get_post that will get the data from wherever it happens to be.
$this->input->get_post_string('data');
I hope this helps you out.
You can do it manually like so if you'd like.
function get_post($index = '', $xss_clean = FALSE){
if ( ! isset($_POST[$index]) )
{
return $this->get($index, $xss_clean);
}
else
{
return $this->post($index, $xss_clean);
}
}
I know this is an old post, but for others looking, this might be helpful:
On the browser side, I create my data packet using code similar to this pattern:
var form_data = { };
$.each($('#mvt_dialog_form').serializeArray(), function() {
form_data[this.name] = this.value;
});
// add the address data to the payload
var result = {
form_data: form_data,
locations: addressData,
selected_location: selectedLocation
};
// now wrap it all up with a pretty bow
// Seriously, the key:value format is required for codeigniter INPUT class to be able to "see"
var movement = {
movement_dlg: JSON.stringify(result)
};
I then "post" movement to the server.
In the controller, I then use the following logic:
// Perform XSS filtering
$postData = $this->input->post(NULL, TRUE);
$result = json_decode($postData['movement_dlg']);
Just add correct content type to your request header
Content-Type: application/json
In order to use the standard CI methods.
In index.php, insert a couple of lines:
$json = json_decode(trim(file_get_contents('php://input')), true);
if(!empty($json)) {
$_POST = $json;
}
Either implement in the bootstrap.
RIP Codigniter...(
try
json_decode(array($this->input->post()))
OR
$tmp[] = (array)json_decode($this->input->post());
print_r($tmp);