It works fine for a few calls, but if there are a large amount of data and I have to make the request multiple times
This is my code:
function run() {
global $client;
$promise = $client->requestAsync('GET', 'http://localhost/test');
$promise->then(
function (ResponseInterface $res) {
if ($res->getStatusCode() != 200 || $res->getBody() != "OK") run();
echo $res->getBody();
},
function (RequestException $e) {
run();
}
);
$response = $promise->wait();
echo json_encode($response);
}
The amount of memory allowed is exhausted when calling me to run the code. It does not work as I would like. What I am doing wrong?
Any help is appreciated
Related
I am trying to configure the Binary.com API, but with some difficulties.
I need to get the message back, but that's not the right way.
In function, if I ask to return the array, it does not return. But if I send a print, the result is displayed on the screen.
See:
require __DIR__ . '/vendor/autoload.php';
$loop = \React\EventLoop\Factory::create();
$connector = new \Ratchet\Client\Connector($loop);
$GLOBALS['app_id'] = XXX;
class Bot {
public static function authorize($loop, $connector, $token, $ret = null) {
if (!is_array($ret)) {
$connector('wss://ws.binaryws.com/websockets/v3?app_id=' . $GLOBALS['app_id'])->then(function ($conn) use ($loop, $token) {
$conn->send("{\"authorize\": \"" . $token . "\"}");
$conn->on('message', function (\Ratchet\RFC6455\Messaging\MessageInterface $msg) use ($conn) {
$conn->close();
Bot::authorize(null, null, json_decode($msg, true));
});
}, function ($e) {
Bot::authorize(null, null, $e->getMessage());
$loop->stop();
});
$loop->run();
}
print_r($ret); //Data is displayed on screen
return $ret;
}
}
$bot = Bot::authorize($loop, $connector, 'a1-tokenxxx');
print_r($bot); //Data is not displayed on screen
See the comments.
Why is this happening?
What is the correct way to return promise data?
I want to add a query parameter in my GET Route, which is this one:
$app->get('/rooms', function (ServerRequestInterface $request, ResponseInterface $response, $args) {
try {
$room = new \Riecken\PBS\controller\RoomController();
$result = $room->getRoomsWithDetails();
$response = $response->withJson($result);
$response = $response->withStatus(200);
return $response;
}catch(Exception $e) {
$response->getBody()->write($e->getMessage());
return $response->withStatus($e->getCode());
}
});
What I want to do is that I only want to execute this function when I type "expandAll".
I googled it and I could find something in the Slim documentation:
https://www.slimframework.com/docs/v3/objects/request.html
But I dont know how to implement it.
So in my case:
If "expandAll" I want to execute the function you see above (getRoomWithDetails(), else I want to execute another function.
Is that possible?
Thanky you very much!
You could just pass the required query parameters to getRoomsWithDetails or you just add a if condition.
Example
$app->get('/rooms', function (ServerRequestInterface $request, ResponseInterface $response, $args) {
try {
$expandAll = $request->getParam('expandAll');
$room = new \Riecken\PBS\controller\RoomController();
if ($expandAll) {
$result = $room->getRoomsWithDetails();
} else {
$result = $room->anotherMethod();
}
$response = $response->withJson($result);
$response = $response->withStatus(200);
return $response;
} catch(Exception $e) {
$response = $response->withJson(['error' => ['message' => $e->getMessage()]]);
return $response->withStatus(500);
}
});
I am developing some Request with Symfony to get an SSL Report from SSLLabs.
Problem: If I send this Request, I get a Response and check one Parameter. There are three Options for this Parameter ("ERROR", "IN_PROGRESS", "READY") which I have to handle.
public function getSSLReport(string $request)
{
try{
$result = null;
$httpClient = new \GuzzleHttp\Client();
$response = $httpClient->request('GET', 'https://api.ssllabs.com/api/v3/analyze?host='.$request.'&all=on');
$result = json_decode($response->getBody()->getContents(), true);
if($result['status'] == "READY") {
return new JsonResponse($result);
} else if($result['status'] == "ERROR") {
return new JsonResponse($result['statusMessage']);
} else {
$this->getSSLReport($request);
}
}catch (\Exception $ex)
{
return new JsonResponse($ex);
}
}
I am using some Recursion to call this Method again if the $result is IN_PROGRESS. But the Request is Pending all the Time, and canceled after 30 seconds.
If I get some Response where "status" == "READY" it works fine.
Add sleep to wait for a couple of seconds:
if($result['status'] === "READY") {
return new JsonResponse($result);
}
if($result['status'] === "ERROR") {
return new JsonResponse($result['statusMessage']);
}
if($result['status'] === "IN_PROGRESS") {
sleep(5);
return $this->getSSLReport($request);
}
throw new \Exception('Unknown status from SSLLabs');
What I've changed:
removed the else and replaced elseif by if.
Replaced == by ====.
Throw an exception when the status from the API is unknown by your code. Instead of retrying, the script should exit in case of an unknown status.
function myfunc($finalArray){
$url = "https://reqres.in/api/users";
$client = new GuzzleHttp\Client();
$countOfSuccess = 0;
$request = new \GuzzleHttp\Psr7\Request('POST', $url);
$promise = $client->sendAsync($request)->then(function ($response) use ($finalArray,$countOfSuccess) {
$countOfSuccess ++ ;
echo $countOfSuccess;
echo count($finalArray);
if(myresponse is valid){
return "Successfully"; // Want to return from there
}
});
$promise->wait();
}
Below is the if condition return. The call is coming inside the if
if(myresponse is valid){
return "Successfully"; // Want to return from there
}
So this return is not working and the calling function doesn't get the return value
According to documentation (https://github.com/guzzle/promises#synchronous-wait), you should be able to do something like this:
$promise = $client->sendAsync($request);
$promise->then(function ($response) use ($finalArray,$countOfSuccess, &$promise) {
$countOfSuccess ++ ;
echo $countOfSuccess;
echo count($finalArray);
if(myresponse is valid){
$promise->resolve('Success');
}
});
echo $promise->wait(); // should return 'Success'
Can u tell me how to get response of multiple async task at once or is there any way possible to check whether all async task are completed or not in guzzle.
You probably need all() function from Guzzle's promises library.
There are more functions to combine and introspect promises, take a look at the source code.
Not sure what is the correct way to display in a php page a Psr7 Guzzle Response.
Right now, I am doing:
use GuzzleHttp\Psr7\BufferStream;
use GuzzleHttp\Psr7\Response;
class Main extends \pla\igg\Main
{
function __construct()
{
$stream = new BufferStream();
$stream->write("Hello I am a buffer");
$response = new Response();
$response = $response->withBody($stream);
$response = $response->withStatus('201');
$response = $response->withHeader("Content-type", "text/plain");
$response = $response->withAddedHeader("IGG", "0.4.0");
//Outputing the response
http_response_code($response->getStatusCode());
foreach ($response->getHeaders() as $strName => $arrValue)
{
foreach ($arrValue as $strValue)
{
header("{$strName}:{$strValue}");
}
}
echo $response->getBody()->getContents();
}
}
Is there a more OOP way to display the response?
A more OOP way of doing the same thing is to create a Sender object that requires a ResponseInterface in its constructor. This class would be responsible for setting headers, clearing buffers and render the response:
use Psr\Http\Message\ResponseInterface;
class Sender
{
protected $response;
public function __construct(ResponseInterface $response)
{
$this->response = $response;
}
public function send(): void
{
$this->sendHeaders();
$this->sendContent();
$this->clearBuffers();
}
protected function sendHeaders(): void
{
$response = $this->response;
$headers = $response->getHeaders();
$version = $response->getProtocolVersion();
$status = $response->getStatusCode();
$reason = $response->getReasonPhrase();
$httpString = sprintf('HTTP/%s %s %s', $version, $status, $reason);
// custom headers
foreach ($headers as $key => $values) {
foreach ($values as $value) {
header($key.': '.$value, false);
}
}
// status
header($httpString, true, $status);
}
protected function sendContent()
{
echo (string) $this->response->getBody();
}
protected function clearBuffers()
{
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
} elseif (PHP_SAPI !== 'cli') {
$this->closeOutputBuffers();
}
}
private function closeOutputBuffers()
{
if (ob_get_level()) {
ob_end_flush();
}
}
}
Use it like this:
$sender = new Sender($response);
$sender->send();
Better yet, you could inject the Sender into your app object and transform it in a class variable, so you'd call it like this:
function renderAllMyCoolStuff()
{
$this->sender->send();
}
I'll leave it as a reader's exercise to implement getters and setters for the Response object, plus a method to receive some content string and transform it into a Response object internally.
Guzzle is a library for doing HTTP calls inside your app, it has nothing to do with the end user communication.
If you need to send specific headers to your end user, just use http_response_code() (that you are already using), header() and echo. Or see the docs for your framework, if you use one (Symfony, Slim, whatever).