Download File With Guzzle - php

I'm attempting to retrieve a file attachment with Guzzle. The file isn't available directly through an endpoint, but the download is initiated via the end point and downloaded to my browser. Can I retrieve this file with Guzzle?
I successfully login to the site, but what is saved to my file is the html of the site not the download. The file contents seems to come through when I make the request with insomnia rest client, but not with Guzzle.
$client = new GuzzleHttp\Client();
$cookieJar = new \GuzzleHttp\Cookie\CookieJar();
$response = $client->post('https://test.com/login', [
'form_params' => [
'username' => $username,
'password' => $password,
'action' => 'login'
],
'cookies' => $cookieJar
]);
$resource = fopen(__DIR__.'/../../feeds/test.xls', 'w');
$stream = GuzzleHttp\Psr7\stream_for($resource);
$response = $client->request('GET', 'https://test.com/download', ['sink' => $stream]);

If you want to perform an authentication step and then a download step, you'll need to make sure the cookies are persisted across both requests. Right now you're only passing your $cookieJar variable to the first one.
The explicit way of doing this would be to add it to the options for the second request:
['sink' => $stream, 'cookies' => $cookieJar]
but it might be easier to take advantage of the option in the client constructor itself:
$client = new GuzzleHttp\Client(['cookies' => true);
That means that every request (with that client) will automatically use a shared cookie jar, and you don't need to worry about passing it into each request separately.

You should send Content-Disposition header in order to specify that the client should receive file downloading as a response. According to your GET HTTP request which will capture the contents into the $stream resource, finally you can output these contents to browser with stream_get_contents.
<?php
// your 3rd party end-point authentication
...
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment; filename="test.xls"');
$resource = fopen(__DIR__.'/../../feeds/test.xls', 'w');
$stream = GuzzleHttp\Psr7\stream_for($resource);
$response = $client->request('GET', 'https://test.com/download', ['sink' => $stream]);
echo stream_get_contents($stream);

Related

forcing guzzle to download the zip files

Need help downloading the the json response zip files.
I am using guzzle json response from the remote server which returns filenames and modification dates to me. i want to download all these zip files to my storage folder of local server..
so it would work like this
remote server gives json response filenames
i take the filenames and create my link and force guzzle to download those files to my local server.
Here is my code
ini_set('max_execution_time', '0');
$url = "https://feeds.example.com/zips/publisher/";
try
{
$client = new GuzzleHttp\Client();
$res = $client->request('GET', $url, [
'auth' => ['username', 'password'],
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json'
],
]);
$responses = json_decode($res->getBody()->getContents());
foreach ($responses->incrementalFeed as $feed)
{
$downloadLink = $url . $feed->name;
$client->get($downloadLink, ['auth' => ['username', 'password']]);
Storage::put($feed->name, $downloadLink);
}
}
catch (ClientException $e) {
echo $e->getMessage();
}
it downloads all the zip files to my storage folder but all the file are like 1kb , empty .. however in remote website those files are like from 10mb to 600mbs
what am i doing wrong here?
You’re not downloading anything.
You need to use guzzle again to download the files
e.g
$response = $client->get($downloadLink);
Storage::put($feed->name, $response->getBody());

Guzzle 6 download file

Need help using Guzzle 6 for downloading a file from a rest API. I don't want the file to be saved locally but downloaded from web browser. Code so far below, but believe I am missing something?
<?php
//code for Guzzle etc removed
$responsesfile = $client->request('GET', 'documents/1234/content',
[
'headers' => [
'Cache-Control' => 'no-cache',
'Content-Type' => 'application/pdf',
'Content-Type' => 'Content-Disposition: attachment; filename="test"'
]
]
);
return $responsesfile;
?>
Just do research inside Guzzle's docs, for example here
Pass a string to specify the path to a file that will store the contents of the response body:
$client->request('GET', '/stream/20', ['sink' => '/path/to/file']);
Pass a resource returned from fopen() to write the response to a PHP stream:
$resource = fopen('/path/to/file', 'w');
$client->request('GET', '/stream/20', ['sink' => $resource]);
Pass a Psr\Http\Message\StreamInterface object to stream the response body to an open PSR-7 stream.
$resource = fopen('/path/to/file', 'w');
$stream = GuzzleHttp\Psr7\stream_for($resource);
$client->request('GET', '/stream/20', ['save_to' => $stream]);
stream_for is deprecated in version 7.2. You can use
GuzzleHttp\Psr7\Utils::streamFor($resource) instead.
First of all, Content-Type header only makes sense when you send something (POST/PUT), but not for GET requests.
Secondly, what is your issue? Guzzle by default does not store the response body (file) somewhere, so you can work with it inside your app, like $responsesfile->getBody().

Send Body as raw using Guzzle

I am trying to use Guzzle to send POST request to my web service. this service accepts body as raw. It works fine when I use postman but I doesn't using Guzzle. when using Guzzle, I get only the webservice description as I put the web service URL in the browser.
here is my code:
$body = "CA::Read:PackageItems (CustomerId='xxxxxx',AllPackages=TRUE);";
$headers = [
....
....
];
$client = new Client();
$response = $client->request('POST', 'http://172.19.34.67:9882/TisService',$headers,$body);
echo $body = $response->getBody();
seems headers or body doesn't pass through.
Try like this
$response = $client->request('POST', 'http://172.19.34.67:9882/TisService',['headers' => $headers, 'body' => $body]);
I have recently had to implement Guzzle for the first time and it is a fairly simple library to use.
First I created a new Client
// Passed in our options with just our base_uri in
$client = new Client(["base_uri" => "http://example.com"]);
I then created a POST request, not how I am using new Request instead of $client->request(... though. This doesn't really matter to much that I've used new Request though.
// Create a simple request object of type 'POST' with our remaining URI
// our headers and the body of our request.
$request = new Request('POST', '/api/v1/user/', $this->_headers, $this->body);
so in essence it would look like:
$request = new Request('POST', '/api/v1/user/', ['Content-Type' => "application/json, 'Accept' => "application/json"], '{"username": "myuser"}');
$this->headers is a simple key-value pair array of our request headers making sure to set the Content-Type header and $this->body is a simple string object, in my case it forms a JSON body.
I can simply then just call the $client->send(... method to send the request like:
// send would return us our ResponseInterface object as long as an exception wasn't thrown.
$rawResponse = $client->send($request, $this->_options);
$this->_options is a simple key-value pair array again simple to the headers array but this includes things like timeout for the request.
For me I have created a simple Factory object called HttpClient that constructs the whole Guzzle request for me this is why I just create a new Request object instead of calling $client->request(... which will also send the request.
What you essentially need to do to send data as raw is to json_encode an array of your $data and send it in the request body.
$request = new Request(
'POST',
$url,
['Content-Type' => 'application/json', 'Accept' => 'application/json'],
\GuzzleHttp\json_encode($data)
);
$response = $client->send($request);
$content = $response->getBody()->getContents();
Using guzzle Request GuzzleHttp\Psr7\Request; and Client GuzzleHttp\Client

How can I send Cookies with Guzzlehttp/guzzle 6?

I need to send a request with custom cookies.
I have tried to set cookieJar like this:
$cookieJar = CookieJar::fromArray(array($cookieName=>$cookieStr),
'api.mobra.in');
$res = $this->guzzleClient->request($requestMethod, $url,
[
'cookies' => [$cookieJar]
]
);
But it is getting an error
cookies must be an instance of GuzzleHttp\Cookie\CookieJarInterface
Please suggest example or explain in details.
I gone through documents but they have not mentioned in detail.
Thank you!
use GuzzleHttp\Cookie\CookieJar;
$cookieJar = CookieJar::fromArray([
'cookie_name' => 'cookie_value'
], 'example.com');
$client->request('GET', '/get', ['cookies' => $cookieJar]);
You can read the documentation here.
One more way to add a cookie to the request with Guzzle:
$url = 'https://www.example.com';
$request_options = [
'headers' => ['Cookie' => 'COOKIE_NAME=VALUE']
];
$response = $this->httpClient->request('GET', $url, $request_options);
Guzzle can maintain a cookie session for you if instructed using the cookies request option. When sending a request, the cookies option must be set to an instance of GuzzleHttp\Cookie\CookieJarInterface.
// Use a specific cookie jar
$jar = new \GuzzleHttp\Cookie\CookieJar;
$r = $client->request('GET', 'http://httpbin.org/cookies', [
'cookies' => $jar
]);
You can set cookies to true in a client constructor if you would like to use a shared cookie jar for all requests.
// Use a shared client cookie jar
$client = new \GuzzleHttp\Client(['cookies' => true]);
$r = $client->request('GET', 'http://httpbin.org/cookies');
Check too the full quickstart.
For sending cookie with Guzzle Http in laravel you can use this sample code:
//your address
$address = "http://example.com/xyz";
//your cookie
$coockie = ['Cookie' => "Key=Value"];
//your request
$res = Http::withOptions([
'headers' => $coockie
])->get($address);

Mock Slim endpoint POST requests with PHPUnit

I want to test the endpoints of my Slim application with PHPUnit. I'm struggling to mock POST requests, as the request body is always empty.
I've tried the approach as described here: Slim Framework endpoint unit testing. (adding the environment variable slim-input)
I've tried writing to php://input directly, but I've found out php://input is read only (the hard way)
The emulation of the environment works correctly as for example the REQUEST_URI is always as expected. I've found out that the body of the request is read out in Slim\Http\RequestBody from php://input.
Notes:
I want to avoid calling the controller methods directly, so I can test everything, including endpoints.
I want to avoid guzzle because it sends an actual request. I do not want to have a server running while testing the application.
my test code so far:
//inherits from Slim/App
$this->app = new SyncApiApp();
// write json to //temp, does not work
$tmp_handle = fopen('php://temp', 'w+');
fwrite($tmp_handle, $json);
rewind($tmp_handle);
fclose($tmp_handle);
//override environment
$this->app->container["environment"] =
Environment::mock(
[
'REQUEST_METHOD' => 'POST',
'REQUEST_URI' => '/1.0/' . $relativeLink,
'slim.input' => $json,
'SERVER_NAME' => 'localhost',
'CONTENT_TYPE' => 'application/json;charset=utf8'
]
);
//run the application
$response = $this->app->run();
//result: the correct endpoint is reached, but $request->getBody() is empty
Whole project (be aware that I've simplified the code on stackoverflow):
https://github.com/famoser/SyncApi/blob/master/Famoser.SyncApi.Webpage/tests/Famoser/SyncApi/Tests/
Note 2:
I've asked at the slimframework forum, link:
http://discourse.slimframework.com/t/mock-slim-endpoint-post-requests-with-phpunit/973. I'll keep both stackoverflow and discourse.slimframework up to date what is happening.
Note 3:
There is a currently open pull request of mine for this feature: https://github.com/slimphp/Slim/pull/2086
There was help over at http://discourse.slimframework.com/t/mock-slim-endpoint-post-requests-with-phpunit/973/7, the solution was to create the Request from scratch, and write to the request body.
//setup environment vals to create request
$env = Environment::mock();
$uri = Uri::createFromString('/1.0/' . $relativeLink);
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new RequestBody();
$uploadedFiles = UploadedFile::createFromEnvironment($env);
$request = new Request('POST', $uri, $headers, $cookies, $serverParams, $body, $uploadedFiles);
//write request data
$request->write(json_encode([ 'key' => 'val' ]));
$request->getBody()->rewind();
//set method & content type
$request = $request->withHeader('Content-Type', 'application/json');
$request = $request->withMethod('POST');
//execute request
$app = new App();
$resOut = $app($request, new Response());
$resOut->getBody()->rewind();
$this->assertEquals('full response text', $resOut->getBody()->getContents());
The original blog post which helped to answer was at http://glenneggleton.com/page/slim-unit-testing

Categories