I am having trouble making this work I keep getting a 400 bad request response. Any help is greatly appreciated as this is my first attempt at both coding perl and using JSON. I had to remove some of the sensitive data as this is something for work. The point of this script is to simply hit the URL sending the POST data via JSON and print the response.
#!/usr/bin/perl
use strict;
use warnings;
use LWP::UserAgent;
use HTTP::Request::Common;
use JSON;
my $ua = LWP::UserAgent->new;
my $req = POST 'URL IS HERE';
my $res = $ua->request($req);
my $json = '{"warehouseId": "ID",
"tagMap":
{"cameraId":["Name of camera"]
},
"searchStartTimeStamp": 0,
"searchEndTimeStamp": 100000000000000,
"pageSize": 1,
"client":
{"id": "username",
"type": "person"}
}';
$req->header( 'Content-Type' => 'application/json' );
$req->content( $json );
if ($res->is_success) {
print $req->content( $json );
print $res->content;
} else {
print $res->status_line . "\n";
}
exit 0;
You perform the request before you have fully populated it! This line does the request:
my $res = $ua->request($req);
but a few lines later, you fill some fields:
$req->header( 'Content-Type' => 'application/json' );
$req->content( $json );
Try swapping that around:
my $json = ...;
my $ua = LWP::UserAgent->new;
my $req = POST 'URL IS HERE';
$req->header( 'Content-Type' => 'application/json' );
$req->content( $json );
my $res = $ua->request($req);
Oh, never $res->content. The value of that method is not generally something usable. You always want
$res->decoded_content;
Related
I am parsing JSON data which is in .json file. Here I have 2 formats of JSON data files.
I could parse first JSON file - file is shown below:
file1.json
{
"sequence" : [ {
"type" : "type_value",
"attribute" : {
"att1" : "att1_val",
"att2" : "att2_val",
"att3" : "att3_val",
"att_id" : "1"
}
} ],
"current" : 0,
"next" : 1
}
Here is my script:
#/usr/lib/perl
use strict;
use warnings;
use Data::Dumper;
use JSON;
my $filename = $ARGV[0]; #Pass json file as an argument
print "FILE:$filename\n";
my $json_text = do {
open(my $json_fh, "<:encoding(UTF-8)", $filename)
or die("Can't open \$filename\": $!\n");
local $/;
<$json_fh>
};
my $json = JSON->new;
my $data = $json->decode($json_text);
my $aref = $data->{sequence};
my %Hash;
for my $element (#$aref) {
my $a = $element->{attribute};
next if(!$a);
my $aNo = $a->{att_id};
$Hash{$aNo}{'att1'} = $a->{att1};
$Hash{$aNo}{'att2'} = $a->{att2};
$Hash{$aNo}{'att3'} = $a->{att3};
}
print Dumper \%Hash;
Everything is getting stored in %Hash and when I print Dumper of the %Hash I am getting following result.
$VAR1 = {
'1' => {
'att1' => 'att1_val',
'att2' => 'att2_val',
'att3' => 'att3_val'
}
};
But when I parse second set of JSON file, I am getting empty hash by using the above script.
Output:
$VAR1 = {};
Here is the JSON file -
file2.json
{
"sequence" : [ {
"type" : "loop",
"quantity" : 8,
"currentIteration" : 0,
"sequence" : [ {
"type" : "type_value",
"attribute" : {
"att1" : "att1_val",
"att2" : "att2_val",
"att3" : "att3_val",
"att_id" : "1"
}
} ]
} ]
}
We can see two sequence in above JSON data file, which is causing the problem.
Can somebody tell me what I am missing in the script inorder to parse file2.json.
One possibility might be to check the type field to differentiate between the two file formats:
# [...]
for my $element (#$aref) {
if ( $element->{type} eq "loop" ) {
my $aref2 = $element->{sequence};
for my $element2 ( #$aref2 ) {
get_attrs( $element2, \%Hash );
}
}
else {
get_attrs( $element, \%Hash );
}
}
sub get_attrs {
my ( $element, $hash ) = #_;
my $a = $element->{attribute};
return if(!$a);
my $aNo = $a->{att_id};
$hash->{$aNo}{'att1'} = $a->{att1};
$hash->{$aNo}{'att2'} = $a->{att2};
$hash->{$aNo}{'att3'} = $a->{att3};
}
Please see the following code if it fits your requirements
#!/usr/bin/env perl
#
# vim: ai:sw=4:ts=4
#
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
use JSON;
my $debug = 0; # debug flag
my $filename = shift; # Pass json file as an argument
say "FILE: $filename";
open(my $json_fh, "<:encoding(UTF-8)", $filename)
or die("Can't open \$filename\": $!\n");
my $json_data = do { local $/; <$json_fh> };
close $json_fh;
my $json = JSON->new;
my $data = $json->decode($json_data);
say Dumper($data) if $debug;
my $data_ref;
my %Hash;
$data_ref = $data->{sequence}[0]{attribute}
if $filename eq 'file1.json';
$data_ref = $data->{sequence}[0]{sequence}[0]{attribute}
if $filename eq 'file2.json';
say Dumper($data_ref) if $debug;
my #fields = qw/att1 att2 att3/;
my $aNo = $data_ref->{att_id};
my %data_hash;
#data_hash{#fields} = $data_ref->{#fields};
$Hash{$aNo} = \%data_hash;
say Dumper(\%Hash);
Hi all i'm new at perl but i have few experience in other language.
So i made a simple code that get JSON file from internet here a telegram bot, but when i display it i got no probleme but when i decoded it with dedcode_json i dont have at all the same output :///
Here the output of the server :
Received reply: {"ok":true,"result":{"id":0000,"first_name":"[MAGA]"}}
and now the output of the decoded anwser :
$VAR1 = {
'ok' => bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' ),
'result' => {
'id' => 0000,
'username' => 'MAGA_bot',
'first_name' => '[MAGA]'
}
};
how can i just get the 'result' part of the decoded json ?
here my code :
#!/usr/bin/perl
use warnings;
use LWP::UserAgent;
use Data::Dumper;
use JSON;
my $ua = LWP::UserAgent->new;
my $destination = "http://api.telegram.org/bot<TOKEN>/getMe";
my $req = HTTP::Request->new(GET => $destination);
my $succes;
my $json;
my $resp = $ua->request($req);
if ($resp->is_success) {
my $message = $resp->decoded_content;
print "Received reply: $message\n";
$succes = "yes";
$json = $message;
} else {
print "HTTP POST error code: ", $resp->code, "\n";
print "HTTP POST error message: ", $resp->message, "\n";
}
print "Encoding the JSON file \n";
if ($succes eq "yes") {
my $decoded_json = decode_json($json);
print Dumper($decoded_json);
} elsif ($succes ne "yes") {
print "Parsing JSON failed\n";
}
Since the decoded JSON is converted into a Perl hash reference in this case, you access it as such:
my $result = $decoded_json->{result};
print "$result->{first_name}\n";
Output:
[MAGA]
If you only want to display part of a complex data structure, then just print that part of the data structure.
print Dumper $decoded_json->{result};
i try to read a json data , so when the response with status ok (200) i can get data correctly in json format , but the webservice return a message if there is no item to return so he generate a message like that :
{"message " : "item not found" }
the problem is when symfony find that the response it not found he throw an exception not found while i want to just return the message that the webservice provide .
this is my controller code:
/**
*
* #Get("/getUserByUid/{uid}")
*/
public function getUserByUidAction($uid)
{
$url = self::Ws_URL . self::Ws_PORT . self::Ws_GetUserByUID . $uid;
$headers = array() ;
$headers[] = "auth_token: ".self::Ws_Token ;
$headers[] = "Content-Type: application/json" ;
$arrContextOptions=array(
"ssl"=>array(
"verify_peer"=>false,
"verify_peer_name"=>false,
),
"http" =>array(
"method" => "GET",
"header" => "auth_token: ".self::Ws_Token
)
);
$response = file_get_contents($url, true, stream_context_create($arrContextOptions));
return New Response($response) ;
}
If the web service is RESTFull then return a http code 404 with the above message {"message " : "item not found" }, then file_get_contents does not fetch the content of the file because the 404 is saying Does not exist. To get the full response and http code use curl instead.
My JSON file contains some 3000 lines of content like below:
{
"product": [
{
"data": [
{
"number":"111",
"price":"3170",
"stock":"1"
},
{
"number":"222",
"price":"3170",
"stock":"1"
},
{
"number":"333",
"price":"3749",
"stock":"1"
}
],
"object":"apple",
"id":"54529"
},
{
"data":[],
"object":"orange",
"id":"54524"
}
]
}
I need to parse them really quick.
Below is my code. It's not working ..
use strict;
use warnings;
use JSON qw( );
my $filename = 'mob.json';
my $json_text = do
{
open(my $json_fh, "<:encoding(UTF-8)", $filename);
local $/;
<$json_fh>
};
my $json = JSON->new;
my $data = $json->decode($json_text);
for ( #{$data->{'product'}} )
{
print $_->{data}[0]->{number};
}
I need to get the number, price, stock and object, id as well.
Your code works fine. Almost. I made a couple of tweaks.
You alluded to speed at the beginning. Not clear if you wanted a quick answer, or a quicker way to parse lots of information. If it's the former, read on. If it's the latter, make sure you have JSON::XS installed.
Style-wise I find it painful to look at.
The use of a do{} to read the file makes me want to hurt myself. But, you used 3-param open. Kudos.
You need to deference the array value from the hash
You need to handle empty values in the data or you'll keep getting warnings
This code parses your JSON and outputs it, substuting empty vals with 'undefined':
use strict;
use warnings;
use JSON qw( );
my $filename = 'mob.json';
my $json_text = do {
open(my $json_fh, "<:encoding(UTF-8)", $filename);
local $/;
<$json_fh>;
};
my $json = JSON->new()->utf8(1);
my $data = $json->decode($json_text);
for my $product ( #{$data->{'product'}} ){
my ($name, $id) = map { $product->{$_} // 'undefined' } qw(name id);
print sprintf("Product: %s (%s)\n", $name, $id);
foreach my $data ( #{$product->{'data'}} ) {
my ($number, $price, $stock) =
map { $data->{$_}//'undefined' } qw(number price stock);
print sprintf(
" number: %s, price: %s, stock: %s\n",
$number,
$price,
$stock,
);
}
print "\n";
}
I'm making a "Download" controller using Symfony 2, that has the sole purpose of sending headers so that I can force a .csv file download, but it isn't working properly.
$response = new Response();
$response->headers->set('Content-Type', "text/csv");
$response->headers->set('Content-Disposition', 'attachment; filename="'.$fileName.'"');
$response->headers->set('Pragma', "no-cache");
$response->headers->set('Expires', "0");
$response->headers->set('Content-Transfer-Encoding', "binary");
$response->headers->set('Content-Length', filesize($fileName));
$response->prepare();
$response->sendHeaders();
$response->setContent(readfile($fileName));
$response->sendContent();
$fileName is a "info.csv" string. Such are my actions inside my controller, there's no return statement. When I tried returning the Response Object, the contents of the file were displayed in the browser, not my intended result.
The problem I've found is that in some pages I do get my info.csv file, but in anothers all I get is a message:
No webpage was found for the web address: http://mywebpage.com/download
Error 6 (net::ERR_FILE_NOT_FOUND): The file or directory could not be found.
I'm completely sure the file exists, so there must be another thing wrong. Also, routing.yml is working correctly, since I do get the file from other pages that also link to that path.
The Apache error log doesn't show anything about it.
Has anyone forced the download of a .csv file on Symfony 2 before? If so, what am I doing wrong?
Here is a minimal example that works just fine in production:
class MyController
public function myAction()
$response = $this->render('ZaysoAreaBundle:Admin:Team/list.csv.php',$tplData);
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename="teams.csv"');
return $response;
You can replace the render call with new response and response->setContent if you like.
Your comment about no return statement inside a controller is puzzling. Controllers return a response. Let the framework take care of sending the stuff to the browser.
I realize this post is kind of old and that there is, oddly enough, practically no good resources on how to do a CSV Export in symfony 2 besides this post at stackoverflow.
Anyways I used the example above for a client contest site and it worked quite well. But today I received an e-mail and after testing it myself, the code had broken - I was able to get the download working with a small amount of results, but the database now exporting over 31,000 rows it either simply showed the text or with chrome, just basically did nothing.
For anyone having issue with a large data export, this is what I manged to get to work, basically doing what Cerad suggested as an alternate way:
$filename = "export_".date("Y_m_d_His").".csv";
$response = $this->render('AppDefaultBundle:Default:csvfile.html.twig', array('data' => $data));
$response->setStatusCode(200);
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Description', 'Submissions Export');
$response->headers->set('Content-Disposition', 'attachment; filename='.$filename);
$response->headers->set('Content-Transfer-Encoding', 'binary');
$response->headers->set('Pragma', 'no-cache');
$response->headers->set('Expires', '0');
$response->prepare();
$response->sendHeaders();
$response->sendContent();
EDIT: After more testing and upping the max seconds allowed, I realized the previous code was printing out the headers at the top so I've updated the code.
THis worked for me to export CSV and JSON.
Twig files are named : export.csv.twig, export.json.twig
The Controller :
class PrototypeController extends Controller {
public function exportAction(Request $request) {
$data = array("data" => "test");
$format = $request->getRequestFormat();
if ($format == "csv") {
$response = $this->render('PrototypeBundle:Prototype:export.' . $format . '.twig', array('data' => $data));
$filename = "export_".date("Y_m_d_His").".csv";
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename='.$filename);
return $response;
} else if ($format == "json") {
return new Response(json_encode($data));
}
}
}
The Routing :
prototype_export:
pattern: /export/{_format}
defaults: { _controller: PrototypeBundle:Prototype:export, _format: json }
requirements:
_format: csv|json
The Twigs:
export.csv.twig (do your comma seperated thing here, this is just a test)
{% for row in data %}
{{ row }}
{% endfor %}
export.json.twig (data is sent json_encoded, this file is empty)
Hope this helps!
This is how I managed to get Silex to return a csv:
// $headers in an array of strings
// $results are the records returned by a PDO query
$stream = function() use ($headers, $results) {
$output = fopen('php://output', 'w');
fputcsv($output, $headers);
foreach ($results as $rec)
{
fputcsv($output, $rec);
}
fclose($output);
};
return $app->stream($stream, 200, array(
'Content-Type' => 'text/csv',
'Content-Description' => 'File Transfer',
'Content-Disposition' => 'attachment; filename="test.csv"',
'Expires' => '0',
'Cache-Control' => 'must-revalidate',
'Pragma' => 'public',
));
You may also need to do some Jiggery Pokery with Javascript (I was downloading Via AJAX) but this post was all I needed to get it working.
simple function you can use for every case to export an csv for download...
public function getResponse(array $data, $filename, $headers = array())
{
if(substr(strtolower($filename), -4) == '.csv') {
$filename = substr($filename, 0, -4);
}
$tmpFile = $this
->_getContainer()
->get('kernel')
->getRootDir()
. '/../var/tmp_'.substr(md5(time()),0,5);
if(file_exists($tmpFile)) unlink($tmpFile);
$handle = fopen($tmpFile, 'w');
foreach ($data as $i => $row) {
$row = (array) $row;
if($i == 0) fputcsv($handle, array_keys($row));
fputcsv($handle, $row);
}
fclose($handle);
$Response = new Response(file_get_contents($tmpFile));
unlink($tmpFile);
$filename = preg_replace('[^a-z0-9A-Z_]', '', $filename);
$headers = array_merge([
'Expires' => 'Tue, 01 Jul 1970 06:00:00 GMT',
'Cache-Control' => 'max-age=0, no-cache, must-revalidate, proxy-revalidate',
'Content-Disposition' => 'attachment; filename='.$filename.'.csv',
'Content-Type' => 'text/csv',
'Content-Transfer-Encoding' => 'binary',
], $headers);
foreach ($headers as $key => $val) {
$Response->headers->set($key, $val);
}
return $Response;
}
How about using Sonata's Exporter:
use Exporter\Writer\CsvWriter;
/**
* #param array $orders
*/
public function exportToCsv($orders)
{
$rootdir = $this->get('kernel')->getRootDir();
$filename = $rootdir . '/data/orders.csv';
unlink($filename);
$csvExport = new CsvWriter($filename);
$csvExport->open();
foreach ($orders as $order)
{
$csvExport->write($order);
}
$csvExport->close();
return;
}
It crashes if the file already exists, thus the unlink-command.