I am developing an administrator website.
There is a section that, when a button is pressed, sends a request to my Symfony backend and the Symfony backend makes an HTTP request to another API that responds with a raw Excel file.
The flow Im trying to make is:
Admin panel [http request] -> Symfony Backend [http request] -> Another API [Generate file and streams it back]
Another API [Streamed Excel file] -> Symfony Backend [Consume the stream] -> Admin panel [Save in device]
I tried doing it like this:
ReportsService
public function reserves_report(String $date1, String $date2): FileForwardResponse {
// This calls to the API to get the streamed file
$guestTypesHttpResponse = $this->httpClient->request(
'GET',
$this->get_endpoint('reports') . "/" . $date1 . "/" . $date2
);
// This class is just to organize things
return new FileForwardResponse(
$guestTypesHttpResponse->getHeaders(),
$guestTypesHttpResponse->getContent(),
);
}
Controller
public function reserves_report(): Response
{
$this->sessionService->singUserIn();
$fileResponse = $this->reportsService->reserves_report($date1, $date2);
return new Response(
$fileResponse->content,
200,
$fileResponse->headers,
);
}
What I was expecting to do is to recive the entire streamed file from the API to the Symfony backend and then use the headers from the API to make it available to download from the client since the headers looks like this:
+headers: array:12 [▶
"connection" => array:1 [▶
0 => "Keep-Alive"
]
"keep-alive" => array:1 [▶
0 => "timeout=5, max=100"
]
"x-ratelimit-limit" => array:1 [▶
0 => "600"
]
"x-ratelimit-remaining" => array:1 [▶
0 => "596"
]
"content-type" => array:1 [▶
0 => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=UTF-8"
]
"content-disposition" => array:1 [▶
0 => "attachment; filename="filename.xlsx""
]
"expires" => array:1 [▶
0 => "Mon, 26 Jul 1997 05:00:00 GMT"
]
"last-modified" => array:1 [▶
0 => "Sat, 11 Feb 2023 15:51:36"
]
"cache-control" => array:1 [▶
0 => "cache, must-revalidate"
]
"pragma" => array:1 [▶
0 => "public"
]
"transfer-encoding" => array:1 [▶
0 => "chunked"
]
"date" => array:1 [▶
0 => "Sat, 11 Feb 2023 21:51:36 GMT"
]
]
And the response content looks like this:
What I got when I hit my Symfony endpoint is a 0 bytes file named filename.
If I hit the APIs endpoint from the browser directly it downloads it just right but I would like to know if there is any way to do it through Symfony http request.
Related
I am trying to send vacancies to the Google Indexing API whenever we receive them from our vacancy provider. However, despite having set all the appropriate permissions, I keep receiving 403 status codes.
I have followed the "Prerequisites for the Indexing API" guide and created a Service account. In my case, I have 4 entries for the domain in Google Search Console, so I followed MarcQuay's answer and added the service account to all 4 entries.
I use the following code to implement the Google API Client and make my calls. The method sendGoogleRequest() is called for every vacancy that we receive.
// Google API setup
function sendGoogleRequest(array $aData, int $sStatus = 0)
{
global $DOMAIN, $GOOGLE_AUTH_CONFIG, $GOOGLE_AUTH_SCOPE, $GOOGLE_API_ENDPOINT;
$googleClient = new Google_Client();
$googleClient->useApplicationDefaultCredentials();
$googleClient->addScope([$GOOGLE_AUTH_SCOPE]);
// Update Google Indexing API. This will notify Google that the URL should be crawled again.
$httpClient = $googleClient->authorize();
$endpoint = $GOOGLE_API_ENDPOINT;
$sJobUrl = $DOMAIN . '/vacancies/' . $aData['url'];
$sType = "";
if (!empty($sStatus)) {
switch ($sStatus) {
case 1:
$sType = "URL_UPDATED";
break;
case 2:
$sType = "URL_DELETED";
break;
}
}
$content = "{
\"url\": \"$sJobUrl\",
\"type\": \"$sType\"
}";
$response = $httpClient->post($endpoint, ['body' => $content]);
$status_code = $response->getStatusCode();
return $status_code;
}
I have tried debugging it and it seems that '$credentials' is empty in $googleClient->authorize()
$authHandler = $this->getAuthHandler();
if ($credentials) {
$callback = $this->config['token_callback'];
$http = $authHandler->attachCredentials($http, $credentials, $callback);
} elseif ($token) {
$http = $authHandler->attachToken($http, $token, (array) $scopes);
} elseif ($key = $this->config['developer_key']) {
$http = $authHandler->attachKey($http, $key);
}
return $http;
However I have no idea what could be the cause of this.
Using this code returns a '403' for every call. After having browsed the internet for quite some time now, I can seem to find a definite answer, except for 'make sure the service account is an owner' but as previously stated, this is already the case.
I hope someone can help me out, since I have been stuck on this for longer than I'd like to admit.
If any more information is required I'll gladly update my answer.
EDIT: As per request, here is the full error message return by the $httpClient->post() call.
Response {#268 ▼
-reasonPhrase: "Forbidden"
-statusCode: 403
-headers: array:11 [▼
"Vary" => array:3 [▼
0 => "X-Origin"
1 => "Referer"
2 => "Origin,Accept-Encoding"
]
"Content-Type" => array:1 [▼
0 => "application/json; charset=UTF-8"
]
"Date" => array:1 [▼
0 => "Tue, 24 Sep 2019 11:25:29 GMT"
]
"Server" => array:1 [▼
0 => "ESF"
]
"Cache-Control" => array:1 [▼
0 => "private"
]
"X-XSS-Protection" => array:1 [▼
0 => "0"
]
"X-Frame-Options" => array:1 [▼
0 => "SAMEORIGIN"
]
"X-Content-Type-Options" => array:1 [▼
0 => "nosniff"
]
"Alt-Svc" => array:1 [▼
0 => "quic=":443"; ma=2592000; v="46,43,39""
]
"Accept-Ranges" => array:1 [▼
0 => "none"
]
"Transfer-Encoding" => array:1 [▼
0 => "chunked"
]
]
-headerNames: array:11 [▼
"vary" => "Vary"
"content-type" => "Content-Type"
"date" => "Date"
"server" => "Server"
"cache-control" => "Cache-Control"
"x-xss-protection" => "X-XSS-Protection"
"x-frame-options" => "X-Frame-Options"
"x-content-type-options" => "X-Content-Type-Options"
"alt-svc" => "Alt-Svc"
"accept-ranges" => "Accept-Ranges"
"transfer-encoding" => "Transfer-Encoding"
]
-protocol: "1.1"
-stream: Stream {#256 ▼
-stream: stream resource #123 ▼
wrapper_type: "PHP"
stream_type: "TEMP"
mode: "w+b"
unread_bytes: 0
seekable: true
uri: "php://temp"
options: []
}
-size: null
-seekable: true
-readable: true
-writable: true
-uri: "php://temp"
-customMetadata: []
}
}
I ended up fixing this issue by using a Service account as AuthConfig
// Initialize Google_Client to submit vacancies to Indexing API
$googleClient = new Google_Client();
$googleClient->setAuthConfig($GOOGLE_AUTH_CONFIG);
$googleClient->addScope([$GOOGLE_AUTH_SCOPE]);
$googleClient->setAccessType("offline");
$googleClient is used for every call
function sendGoogleRequest(array $aData, int $sStatus = 0, Google_Client $google_Client) {
global $DOMAIN;
$sJobUrl = 'https://MY-DOMAIN.com/' . $aData['url'];
$sType = "";
if (!empty($sStatus)) {
switch ($sStatus) {
case 1:
$sType = "URL_UPDATED";
break;
case 2:
$sType = "URL_DELETED";
break;
}
}
$urlNotification = new Google_Service_Indexing_UrlNotification();
$urlNotification->setType($sType);
$urlNotification->setUrl($sJobUrl);
$indexingService = new Google_Service_Indexing($google_Client);
$response = $indexingService->urlNotifications->publish($urlNotification);
return $response;
}
This script is then called once per day and posts every URL to the Indexing API. To not exceed the limit of 250 requests per day, make sure you exclude vacancies that should no longer be indexed.
i have a little problem with my json response.
I dumped it in my php code, and the result is what i attached here
How can I dump the statusText ?
I've already tried to decode it, and i've tried this too:
dump($myVar['statusText']);
or something like that
(to obtain the dump of my json i've posted, i've just did
dump($myVar); )
JsonResponse {#325
#data: "{"code":"OK","status":"ok","data":{"UUID":"f239ae18-98af-4224-8b4f-7713c71a5576","order":{something here },"orderRows":[something else here}}"
#callback: null
#encodingOptions: 271
+headers: ResponseHeaderBag {#326
#computedCacheControl: array:2 [
"no-cache" => true
"private" => true
]
#cookies: []
#headerNames: array:4 [
"content-type" => "Content-Type"
"access-control-allow-origin" => "Access-Control-Allow-Origin"
"cache-control" => "Cache-Control"
"date" => "Date"
]
#headers: array:4 [
"content-type" => array:1 [
0 => "application/json; charset=utf-8"
]
"access-control-allow-origin" => array:1 [
0 => "*"
]
"cache-control" => array:1 [
0 => "no-cache, private"
]
"date" => array:1 [
0 => "Mon, 06 May 2019 08:15:28 GMT"
]
]
#cacheControl: []
}
#content: "{"code":"OK","status":"ok","data":{"UUID":"f239ae18-98af-4224-8b4f-7713c71a5576","order":{something},"orderRows":[something else}}"
#version: "1.0"
#statusCode: 200
#statusText: "OK"
#charset: null
}
Just wanna see
"status" => 'ok' and my life would be perfect :D
Looking at this output, it looks like the code is stored in the content also.
"status":"ok"
For this reason, following this documentation on the getData() method, you should be able to retrieve the status:
$data = $myVar->getData();
var_dump($data->status);
It is expected that this would return a string of "ok".
why laravel doesn't accept vars with underscore from request header?
I made a simple request example with a variable: "token_auth" with value 123 , but inside in my route doesn't get this value.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class Test extends Controller
{
public function teste(Request $request){
dd($request->header());
}
}
only prints header with no underscore:
array:9 [
"thisheadernounderline" => array:1 [
0 => "312321"
]
"cache-control" => array:1 [
0 => "no-cache"
]
"postman-token" => array:1 [
0 => "3c461fd1-5bea-4100-9926-81c14cb5810c"
]
"user-agent" => array:1 [
0 => "PostmanRuntime/7.1.1"
]
"accept" => array:1 [
0 => "*/*"
]
"host" => array:1 [
0 => "localhost"
]
"cookie" => array:1 [
0 => "XSRF-TOKEN=eyJpdiI6IkJwM3pjVkFBb2hxS2d4MDFcL2srM0h3PT0iLCJ2YWx1ZSI6IiszRzhoTzV0VzN5YUkydUNUTGR5aENVd291ZW01SkZ4V2ZxQkNDTGJwbDlyMFFJZGxzNnorMkF0VUNTbHpoRndLV3FmbndJWFhkXC9cL3IzOGZvN25zN3c9PSIsIm1hYyI6IjQwZWQ1YmJhM2VjM2I3N2RiNWZlYjcwYjZmYzQ0NDk5YjkwZDc4YzRjNGQwZjQxNDVkOGU1NDU0MTA0OWI2YWYifQ%3D%3D; laravel_session=eyJpdiI6IitSckpmOFI1TmpuXC9SSUt2QVY3VlFRPT0iLCJ2YWx1ZSI6IlwvVk1EaDdYdDNxRTZLNytRcnZDTlNiaVlFTWVRVmNUOHlyVnFia0pDeE9HNWpNa3QrWlBsNnNoVEduVkhrMUhkYURoNDI4cW9RdXVHU0lIS0JZN2REQT09IiwibWFjIjoiNWJmYmJmNTdmMzJkZjQ1OGQ4NTM1NjhhMzQxNDk5NWUxOTA5OGVjOThkODkyNDgwZTA2NzEyYjFlZmE2YjVjOSJ9"
]
"accept-encoding" => array:1 [
0 => "gzip, deflate"
]
"connection" => array:1 [
0 => "keep-alive"
]
]
is there any workaround to solve this?
And I cant change this because this variable comes from an API (aready asked to change but they wont wanna change).
Already tried with laravel 5.4 and laravel 5.6.
ps: with simple php works fine (no laravel framework)
This worked for my scenario.
I used this workaround in Laravel to solve my problem:
foreach (getallheaders() as $name => $value) {
echo "$name: $value\n";
}
output:
token_auth: 123
cache-control: no-cache
Postman-Token: f5bf7878-1f64-4ee8-907a-991d73ab8667
User-Agent: PostmanRuntime/7.1.1
Accept: */*
Host: localhost
cookie: XSRF-TOKEN=eyJpdiI6IkJwM3pjVkFBb2hxS2d4MDFcL2srM0h3PT0iLCJ2YWx1ZSI6IiszRzhoTzV0VzN5YUkydUNUTGR5aENVd291ZW01SkZ4V2ZxQkNDTGJwbDlyMFFJZGxzNnorMkF0VUNTbHpoRndLV3FmbndJWFhkXC9cL3IzOGZvN25zN3c9PSIsIm1hYyI6IjQwZWQ1YmJhM2VjM2I3N2RiNWZlYjcwYjZmYzQ0NDk5YjkwZDc4YzRjNGQwZjQxNDVkOGU1NDU0MTA0OWI2YWYifQ%3D%3D; laravel_session=eyJpdiI6IitSckpmOFI1TmpuXC9SSUt2QVY3VlFRPT0iLCJ2YWx1ZSI6IlwvVk1EaDdYdDNxRTZLNytRcnZDTlNiaVlFTWVRVmNUOHlyVnFia0pDeE9HNWpNa3QrWlBsNnNoVEduVkhrMUhkYURoNDI4cW9RdXVHU0lIS0JZN2REQT09IiwibWFjIjoiNWJmYmJmNTdmMzJkZjQ1OGQ4NTM1NjhhMzQxNDk5NWUxOTA5OGVjOThkODkyNDgwZTA2NzEyYjFlZmE2YjVjOSJ9
accept-encoding: gzip, deflate
Connection: keep-alive
Short:
What do I have to do with the result of the sendEmail() method of the SES-API from Amazon AWS?
Long:
I have successfully installed the "aws/aws-sdk-php": "^3.38" via composer in a PHP project.
I have successfully sent emails over the formula:
$client = new SesClient( $sesParameters );
$result = $client->sendEmail( $emailSesArgs );
It works.
I receive a result like this one:
Result {#433 ▼
-data: array:2 [▼
"MessageId" => "0102015fd3c21fd2-98a104e2-0c3f-4078-90ed-0be3a12ae812-000000"
"#metadata" => array:4 [▼
"statusCode" => 200
"effectiveUri" => "https://email.eu-west-1.amazonaws.com"
"headers" => array:4 [▼
"x-amzn-requestid" => "e27b7805-cd11-11e7-9d57-cd9600d88c96"
"content-type" => "text/xml"
"content-length" => "326"
"date" => "Sun, 19 Nov 2017 10:10:35 GMT"
]
"transferStats" => array:1 [▼
"http" => array:1 [▼
0 => []
]
]
]
]
}
Questions
The questions are...
What should I do with this result, further than exploring the 200 OK result in real time?
What operations can I perform afterwards using this MessageId?
I've observed that if I send an email to an invalid address, this also returns 200 OK. Probably this is more an "acknowledge" that the send-email "request" has been submitted than actually processing of it. Can I use the result to further read the "status" of the deilvey itself via API to discover if the email was successfully delivered?
Thanks!
What I do is I track message deliveries, bounces and complaints using the message ID by configuring SNS topics (SES > Domains > example.com > Notifications) that trigger an AWS Lambda function (SNS > Topics > Subscriptions), which in turn stores/updates the delivery status in a DynamoDB table for later query operations.
I am trying to obtain a JSON response from an end point using Guzzle 6.2 with Laravel 5.3.
I am using the following code to make a get request:
$client = new GuzzleHttp\Client([
'base_uri' => 'https://192.xx.xxx.xx6/',
'timeout' => 2.0
]);
$response = $client->request('GET',
'/fineract-provider/api/v1/clients/388?tenantIdentifier=default&pretty=true', [
'verify' => false,
'auth' => ['<username>', '<password>']
]
);
var_dump($response);
Which outputs the following response:
Response {#282
-reasonPhrase: "OK"
-statusCode: 200
-headers: array:7 [
"Server" => array:1 [
0 => "Apache-Coyote/1.1"
]
"Access-Control-Allow-Origin" => array:1 [
0 => "*"
]
"Access-Control-Allow-Methods" => array:1 [
0 => "GET, POST, PUT, DELETE, OPTIONS"
]
"Content-Type" => array:1 [
0 => "application/json"
]
"Transfer-Encoding" => array:1 [
0 => "chunked"
]
"Vary" => array:1 [
0 => "Accept-Encoding"
]
"Date" => array:1 [
0 => "Sat, 04 Feb 2017 15:51:10 GMT"
]
]
-headerNames: array:7 [
"server" => "Server"
"access-control-allow-origin" => "Access-Control-Allow-Origin"
"access-control-allow-methods" => "Access-Control-Allow-Methods"
"content-type" => "Content-Type"
"transfer-encoding" => "Transfer-Encoding"
"vary" => "Vary"
"date" => "Date"
]
-protocol: "1.1"
-stream: Stream {#280
-stream: stream resource #297
wrapper_type: "PHP"
stream_type: "TEMP"
mode: "w+b"
unread_bytes: 0
seekable: true
uri: "php://temp"
options: []
}
-size: null
-seekable: true
-readable: true
-writable: true
-uri: "php://temp"
-customMetadata: []
}
}
But this is not the response I expect. However, when I make the same request in my browser it gives the correct output as below:
What am I doing wrong here?
The Response object contains more information than just the response. You can get the actual output like this:
$output = (string)$response->getBody();
It might be necessary (in certain cases) to cast the result to a string, because the actual result is a stream.
Guzzle documentation: Responses