Recursion on Request - php

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.

Related

Telegram Bot callBackQuery php,laravel

I want to implement a pagination for telegram bot with inlinekeyboard with nutgram in laravel but when I use inlineKeyboard tow times I get this error:
Bad Request: message is not modified: specified new message content and reply markup are exactly the same as a current content and reply markup of the message
This is my code :
public function start(Nutgram $bot)
{
$message = $this->getRecords();
//$bot->sendMessage(implode(PHP_EOL,$message));
$this->menuText($message)
->addButtonRow(
InlineKeyboardButton::make('◀', callback_data: 'pre#handlePage'),
InlineKeyboardButton::make('▶', callback_data: 'next#handlePage')
)
->orNext('none')
->showMenu();
}
public function handlePage(Nutgram $bot)
{
$bot->answerCallbackQuery(['recived',true]);
$page = $bot->callbackQuery()->data;
if($page === 'next')
{
self::$page = (self::$page)+1;
$posts = $this->getRecords();
try {
$this->menuText($posts )
->orNext('none')
->showMenu();
} catch (\Throwable $th) {
Storage::put('public/error.txt',$th->getMessage());
}
return;
}
self::$page = (self::$page == 0) ? (self::$page)+1 : (self::$page)-1;
$posts = $this->getRecords();
try {
$this->menuText($posts)
->orNext('none')
->showMenu();
} catch (\Throwable $th) {
Storage::put('public/error.txt',$th->getMessage());
}
}
How can I use inlineKeyboard with callBackQuery for many times?

How to callback request until desired result in Guzzle?

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

"start_batch was called incorrectly" on gRPC unary call

I make an unary call from PHP code like that:
public function getByIDs(array $ids): array
{
$request = new GetByIDsRequest();
$request->setIDs($ids);
$grpcRequest = $this->client->GetByIDs($request, [], ['timeout' => $this->waitTimeout]);
$response = $this->callWithRetries($grpcRequest);
if (!$response->isOk()) {
$status = $response->getStatus();
throw new GrpcServerException(__FUNCTION__, $status->getDetails(), (int)$status->getCode());
}
... // business logic here
}
private function callWithRetries(\Grpc\UnaryCall $grpcRequest): GrpcUnaryCallResponse
{
$response = null;
for ($attempt = 0; $attempt <= self::$maxRetries; $attempt++) {
if ($attempt > 0) {
usleep(mt_rand(1, 5) * self::$waitBeforeRetry);
}
$response = $this->unaryCall($grpcRequest);
$status = $response->getStatus()->getCode();
if ($response->isOk() || !self::isRetryable($status)) {
return $response;
}
}
return $response;
}
protected function unaryCall(UnaryCall $call): GrpcUnaryCallResponse
{
[$response, $status] = $call->wait();
return new GrpcUnaryCallResponse(
$response,
new GrpcStatus($status)
);
}
Sometimes I get the LogicException with message "start_batch was called incorrectly". Any thoughts how to deal with that exception and what is the root cause?
After some investigation I found out that the problem occurs because of reusing the instance of \Grpc\UnaryCall in retries. You must not do that otherwise you get a core dump.
The reason we got the LogicException but not a core dump is using a patched gRPC extension.
Some more technical details you can find in this issue

Codeigniter 3: Can't catch database error using try catch block

I'm working on an api, it handles the requests which comes from clients, then gets the response from server(developed using codeigniter 3) and forwards that back to client.
But, in case of any database errors, like duplicate id, or null values, the model class cannot handle that error to display a proper error message. I've tried the try catch block but not succeeded yet.
Here's the model:
public function add() {
try {
$this->db->trans_start(FALSE);
$this->db->insert('users', $preparedData);
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) {
throw new Exception("Database error:");
return false;
}
return TRUE;
} catch (Exception $e) {
log_message('error: ',$e->getMessage());
return;
}
}
One thing to mention, I've set db_debug to FALSE.
Any help would be appreciated.
As for CI 3, below code gets database error code and error message. db_debug is set to FALSE.
public function add() {
try {
$this->db->trans_start(FALSE);
$this->db->insert('users', $preparedData);
$this->db->trans_complete();
// documentation at
// https://www.codeigniter.com/userguide3/database/queries.html#handling-errors
// says; "the error() method will return an array containing its code and message"
$db_error = $this->db->error();
if (!empty($db_error)) {
throw new Exception('Database error! Error Code [' . $db_error['code'] . '] Error: ' . $db_error['message']);
return false; // unreachable retrun statement !!!
}
return TRUE;
} catch (Exception $e) {
// this will not catch DB related errors. But it will include them, because this is more general.
log_message('error: ',$e->getMessage());
return;
}
}
Refer to documentation at https://www.codeigniter.com/userguide3/database/queries.html#handling-errors
saying
If you need to get the last error that has occurred, the error() method will return an array containing its code and message.
It is a bit incomplete in my opinion because it does not show error code and error message in the example code.
I just lost an hour trying to figure out why I can't get the error in my code. You have to check for an error after each statement! Working solution:
function insertUpdate($data) {
$order = $data->order;
$order_products = $data->order_products;
$this->db->trans_start();
$order->user_id = $this->session->user_id;
$error = "OK";
if (!$this->db->insert('_order', $order)) {
$error = $this->db->error()["message"];
}
$id = $this->db->insert_id();
foreach ($order_products as $row) {
$row->order_id = $id;
if (!$this->db->insert('_order_product', $row)) {
$error = $this->db->error()["message"];
break;
}
}
$order_code = substr(md5($id), 0, 6);
if (!$this->db->where('order_id', $id)) {
$error = $this->db->error()["message"];
}
if (!$this->db->update('_order', ["order_code" => $order_code])) {
$error = $this->db->error()["message"];
}
$this->db->trans_complete();
return [
'result' => $error, 'order_code' => $order_code
];
}
Suggestion in above code
Remove line $this->db->trans_complete();
If we see $this->db->error() after completing transaction it will be always empty
Remove semicolon - log_message('error :',$e->getMessage());
return;
public function add()
{
try {
$this->db->trans_start(FALSE);
$this->db->insert('users', $preparedData);
// documentation at
// https://www.codeigniter.com/userguide3/database/queries.html#handling-errors
// says; "the error() method will return an array containing its code and message"
$db_error = $this->db->error();
if (!empty($db_error)) {
throw new Exception('Database error! Error Code [' . $db_error['code'] . '] Error: ' . $db_error['message']);
return false; // unreachable return statement !!!`enter code here`
}
return TRUE;
} catch (Exception $e) {
// this will not catch DB related `enter code here`errors. But it will include them, because this is more general.
log_message('error ',$e->getMessage());
return;
}
}

If condition on save laravel

I had 2 tables. driver and part_time_available in the same form, when I select driver type = parttime, it'll show part_time_available field(day, start_time, end_time).
How to make condition if user choose fulltime. it didn't store part_time_available field to database.
here's my savehandler code so far :
public function saveHandler(Request $request, $obj)
{
try {
DB::beginTransaction();
$obj->fill($request->all());
if (!$obj->save()) {
throw new ValidationException($obj->errors());
}
foreach($request->parttimeAvailabilities as $pta) {
\Log::info($pta);
if (empty($pta['id'])) {
$parttimeAvailability = new PartTimeAvailability();
}
else {
$parttimeAvailability = PartTimeAvailability::find($pta['id']);
}
$parttimeAvailability->driver()->associate($obj);
$pta['driver_id'] = isset($pta['driver_id']);
$parttimeAvailability->day = $pta['day'];
$parttimeAvailability->start_time = isset($pta['start_time']) ? $pta['start_time'] : '00:00:00';
$parttimeAvailability->end_time = isset($pta['end_time']) ? $pta['end_time'] : '00:00:00';
$parttimeAvailability->available = isset($pta['available']);
$parttimeAvailability->save();
};
$obj->save();
if (!$parttimeAvailability->save()) {
throw new ValidationException($parttimeAvailability->errors());
}
DB::commit();
return $this->sendSuccessResponse($request);
} catch (ValidationException $e) {
DB::rollback();
\Log::error($e->errors);
return $this->sendErrorResponse($request, $e->errors);
} catch (Exception $e) {
DB::rollback();
\Log::error($e->getMessage());
return $this->sendErrorResponse($request,'Unable to process. Please contact system Administrator');
}
}
I mean before running foreach, it needs to check it's parttime or not.
any idea ?
You can give a condition before the whole foreach loop. such as:
if($request->get('driver_type') != 'full_time'){
foreach loop
}

Categories