Error disconnecting Asterisk Manager - php

I am using Asterisk Manager to get events on incoming calls. I want to disconnect the Manager when a "Ring" event is received.
Below is my code which checks the "Ring" event upon receiving a call. My code disconnects the Manager, but also generates an error. Sometimes the error message appears multiple times.
What am I doing wrong?
<?php
require_once('phpagi/phpagi.php');
function newstatus($ecode,$data,$server,$port){
if (!isset($data['ChannelStateDesc'])){
$data['ChannelStateDesc'] = '';
}
print_r($data);
if ($data['Event'] == "Newchannel" && $data['ChannelStateDesc'] == "Ring") {
echo "Call Ringing!!!\n";
global $asm;
$asm->disconnect();
}
}
$e = 'ENTERQUEUE';
if ($e == 'ENTERQUEUE'){
$asm = new AGI_AsteriskManager();
$asm->connect();
$asm->add_event_handler("Newchannel", "newstatus");
$asm->wait_response(true);
}
Error Message:
PHP Warning: fgets(): 9 is not a valid stream resource in /scripts/phpagi/phpagi-asmanager.php on line 158

With $asm->connect(); you open a socket,
with $asm->disconnect(); you close the socket.
The Problem is, disconnect closes the socket in the eventcallback, but wait_response is a eventloop and the eventhandler get called again on a disconnected state.
If a request was just sent, wait_response will return the response. Otherwise, it will loop forever, handling events.
If you have remaining code, you could call that code (function) in the event handler (ie, new_status). If you want to do something on every event, you could register a wildcard event handler.
function newstatus($ecode, $data, $server, $port)
{
// ...
echo "Call Ringing!!!\n";
do_something($data);
// ...no disconnect necessary
}
function on_all_events(...)
{
// ...
}
function do_something($data)
{
var_dump($data);
}
add_event_handler('*', 'on_all_events');

Related

Does mysqli::reap_async_query() have side effects?

I'm maintaining a project based on legacy code that was written by an external company. We are in the process of fixing a lot of PHP errors in this code base and one of them comes from a call to mysqli::reap_async_query() :
mysqli::reap_async_query(): Connection not opened, clear or has been
closed
This happens only on the first call to this function:
function mysqlQuery($sql, $getLastId = false, $die = true, $alwaysDie = false, $async = false)
{
#$GLOBALS['con']->reap_async_query(); // This is what is triggering the error
if ($async) {
$result = $GLOBALS['con']->query($sql, MYSQLI_ASYNC);
} else {
$result = $GLOBALS['con']->query($sql);
}
if (!$result) {
if ($alwaysDie or ($_ENV['ENV_MODE'] === 'dev' and $die)) {
die('Etwas stimmte mit dem Query nicht: ' . $GLOBALS['con']->error . '<br/>Ganzes Query: ' . $sql);
}
return false;
} else {
$lastId = mysqlLastId();
if ($getLastId == true) {
return $lastId;
} else {
return $result;
}
}
}
Note that $GLOBALS['con'] is an instance of mysqli.
The code is calling mysqlQuery() with no specific parameter:
$result = mysqlQuery("SELECT * FROM someTable");
According to the Git history, the call to #$GLOBALS['con']->reap_async_query(); was added to support async SQL queries. But reading the PHP doc, it doesn't seem to be useful here at all since we are not storing its return value.
So my question is: is there a reason for it to be here, does calling it even without reading its return value have any important side effect ?
I might just remove this call completely if it is useless.
Also, why is it triggering this error ? I understand that trying to read a result before any query has been executed could trigger an error but the error indicates that the connection is not active, which does not seem to be the case.
Is there a reason for it [mysqli::reap_async_query()] to be here, does calling it even without reading its return value has any important side effect ?
The return value is not assigned to a local variable, however it is still returned.
So the original interest was in calling that function. And for what for, has been written about in the commit message.
According to the Git history, the call to #$GLOBALS['con']->reap_async_query(); was added to support async SQL queries.
Let's consider this example:
$con->query('SELECT SLEEP(5) as `zzzZZZ...Schnarch...Schmatz..zzz`', MYSQLI_ASYNC);
$con->reap_async_query();
How long does it take to execute this code?
This is the reason how that call supports async queries. If an async query would still run on the connection (it has not been reaped yet), every new query would fail.
So add of the call in-so-far supports async SQL queries as it allows to fire one on the same (shared) connection that might be in use for other queries, too.
Additionally you ask:
Also, why is it triggering this error ? I understand that trying to read a result before any query has been executed could trigger an error but the error indicates that the connection is not active, which does not seem to be the case.
Let's take a look at the error, actually a message on the diagnostic channel:
PHP Warning: mysqli::reap_async_query(): Connection not opened, clear or has been closed in ...
As we know the connection has been opened and has not been closed, the last point might be it:
[...] Connection [...] clear [...]
Now I have not programmed that error message, but my reading of it is that there is no async query running yet on the (open) connection - the connection is clear.
It produces a warning as this might not be intended (there is no need to reap a clear connection normally) and henceforth as with your function this is intended, the call is prefixed with the error suppression operator (#).
Thanks to #hakre's answer i understand that this call is there to get rid of the queue of async queries and i plan to fix it with a static flag to check if one is pending before calling #$GLOBALS['con']->reap_async_query():
function mysqlQuery($sql, $getLastId = false, $die = true, $alwaysDie = false, $async = false)
{
static $asyncPending = false;
if (true === $asyncPending) {
#$GLOBALS['con']->reap_async_query();
$asyncPending = false;
}
if ($async) {
$result = $GLOBALS['con']->query($sql, MYSQLI_ASYNC);
$asyncPending = true;
} else {
$result = $GLOBALS['con']->query($sql);
}
if (!$result) {
if ($alwaysDie or ($_ENV['ENV_MODE'] === 'dev' and $die)) {
die('Etwas stimmte mit dem Query nicht: ' . $GLOBALS['con']->error . '<br/>Ganzes Query: ' . $sql);
}
return false;
} else {
$lastId = mysqlLastId();
if ($getLastId == true) {
return $lastId;
} else {
return $result;
}
}
}

How to close the request after its complete using Guzzle 6.x Client

I have a task to identify the existence of the links. As a result I am using guzzle client to identify if the link is existence or not, i.e if the response header received is 200, then the link is existence else not.
Below is my code snippet
public function checkUrl($url) {
$result['isValid'] = false;
try {
$response = $this->client->get($url, ['verify', false]);
} catch (\Exception $ex) {
$result['isValid'] = false;
$result['message'] = 'Some error message';
return $result;
}
if ($response->getStatusCode() == Response::STATUS_CODE_200) {
$result['isValid'] = true;
}
$result['message'] = 'Success - ' . $response->getStatusCode();
$response->getBody()->close();
return $result;
}
where $this->client is initialized to GuzzleHttp\Client object once in the constructor
When I run my script, after some time it throws me the error as follows:
PHP Fatal error: Uncaught ErrorException: include(/project/vendor/zendframework/zend-view/src/Model/ConsoleModel.php): failed to open stream: Too many open files
And when I check the list of open files using the command lsof -p <process id> -n, I noticed that there lots of open files are as a result of guzzle request (i.e curl responses) and it seems to be the cause of this exception.
Is there any suggestion for the solution through which I can close those responses?

Messages not getting sent via ZMQ

Currently, i am trying a simple code of sending/receiving messages using ZMQ. The code is as below
/* Create new queue object, there needs to be a server at the other end */
$queue = new ZMQSocket(new ZMQContext(), ZMQ::SOCKET_REQ);
$queue->connect("tcp://127.0.0.1:5555");
/* Assign socket 1 to the queue, send and receive */
$retries = 5;
$sending = true;
/* Start a loop */
do {
try {
/* Try to send / receive */
if ($sending) {
echo "Sending message\n";
$queue->send("This is a message", ZMQ::MODE_NOBLOCK);
$sending = false;
} else {
echo "Got response: " . $queue->recv(ZMQ::MODE_NOBLOCK) . "\n";
echo 'Complete';
break;
}
} catch (ZMQSocketException $e) {
/* EAGAIN means that the operation would have blocked, retry */
if ($e->getCode() === ZMQ::ERR_EAGAIN) {
echo " - Got EAGAIN, retrying ($retries)\n";
} else {
die(" - Error: " . $e->getMessage());
}
}
/* Sleep a bit between operations */
usleep(5);
} while (--$retries);
When i run this script in console, my output is
Sending message
Got response:
Complete
I believe that though there are no errors thrown, but still my message is not actually sent. I also ran netstat command but i didn't found any process listening on port 5555. Ideally there should be one(current). But no exception is thrown while making connection.
Is there something which i am missing?
When you say no process is listening on port 5555, it probably means that your server is not up and running. Your client will not throw any errors even if there is no server, it just sets up and waits for the server to come online (with your particular setup here, at least).
In this case, since you're using non-blocking mode, it'll send your message on the first pass through the loop (why are you sending the message in the loop at all?), but it won't actually send anything because the server isn't there. Then it'll attempt to receive on the second pass through the loop, but since the socket isn't ready to receive it looks like it'll just fail silently, without throwing an exception. Since no exception is thrown, it gets to your break statement, quits the loop, and you're done.
First things first, your send call should happen before the loop, it's something you want to do only once.
Then, when you recv, store the result in a variable and test for emptiness. Leave the try/catch code. The result should be something like this:
/* Create new queue object, there needs to be a server at the other end */
$queue = new ZMQSocket(new ZMQContext(), ZMQ::SOCKET_REQ);
$queue->connect("tcp://127.0.0.1:5555");
/* Assign socket 1 to the queue, send and receive */
$retries = 5;
echo "Sending message\n";
$queue->send("This is a message", ZMQ::MODE_NOBLOCK);
/* Start a loop */
do {
try {
/* Try to receive */
$response = $queue->recv(ZMQ::MODE_NOBLOCK);
if (!empty($response)) {
echo "Got response: " . $response . "\n";
echo 'Complete';
break;
}
else {
echo "we probably haven't even sent the original request yet, retrying ($retries)\n";
}
}
catch (ZMQSocketException $e) {
/* EAGAIN means that the operation would have blocked, retry */
if ($e->getCode() === ZMQ::ERR_EAGAIN) {
echo " - Got EAGAIN, retrying ($retries)\n";
} else {
die(" - Error: " . $e->getMessage());
}
}
/* Sleep a bit between operations */
usleep(5);
} while (--$retries);
echo "END OF LINE";
... keep in mind this is a minor fix to the client code that makes it behave a little more rationally, I still believe your actual problem is that the server isn't running.
Please add the server code. You are showing the client code. Since the problem seems to be in the server, and you also state that the server is not visible with netstat, the problem is most probably there.

Getting PHP Catchable fatal error: Object of class Services_Twilio_TinyHttp could not be converted to string

I am setting up Twilio and trying to send a simpe sms to my personal phone. but all i get is this error in title + this happens on Services/Twilio/Resource.php on line 127:
public function __toString() {
$out = array();
foreach ($this as $key => $value) {
if ($key !== "client" && $key !== "subresources") {
$out[$key] = (string)$value; <----------------HERE
}
}
return json_encode($out);
}
My code on controller look like this:
$client = new Services_Twilio($AccountSid, $AuthToken);
try {
foreach($listUsers as $user){
$sms = $client->account->sms_messages->create(
$phone, // From this number
$user['phone'], // To this number
$message
);
}
$data['results'] = "success";
$data['message'] = "Your message have been sent successfully";
echo json_encode($data);
} catch (Services_Twilio_RestException $e) {
$data['results'] = "error";
$data['message'] = $e->getMessage();
echo json_encode($data);
}
I am sitting for hours now, can't seem to figure out the problem. Maybe some one have used this Twilio and could give me a hint atleast where to look..
Whole error:
PHP Catchable fatal error: Object of class Services_Twilio_TinyHttp could not be converted to string in ../Services/Twilio/Resource.php on line 127, referer:
Errors are not Exceptions, they are not thrown and cannot be catched. Errors can be handled by error handlers registered with set_error_handler. Now, there are several fatal error types like E_ERROR or E_CORE_ERROR, which cannot be handled by any error handler; these errors are fatal and stop script execution, period (or full stop if you prefer ;)). But there's also an E_RECOVERABLE_ERROR, which is described as such:
Catchable fatal error. It indicates that a probably dangerous error occurred, but did not leave the Engine in an unstable state. If the error is not caught by a user defined handle (see also set_error_handler()), the application aborts as it was an E_ERROR.
http://www.php.net/manual/en/errorfunc.constants.php
So you could handle these errors with a custom error handler. You should mostly do that to possibly write custom error logs or send alert mails, but you should nonetheless terminate the script afterwards (though you are not forced to). It's just being described as a "catchable error", though it has nothing to do with try..catch.
The cause of the error in your case is that you're trying to cast an object to a string, but the object doesn't like that. You should look at the documentation for the class how the object wants to be treated and how you can get the data you want out of it. (string) does not work, plain and simple.
You should be able to convert any of the resources, eg $client->account, $message = $client->account->messages->get('MM123') to a string, by calling echo on it or similar.
It looks like somewhere you are trying to cast the http client ($client->http) to a string. The http client doesn't define a tostring method.

Analyze every function I call

I want to analyze the result of each function that I call. If this result is a exception or is false then the script ends. I can do this manually, but it is a big waste of time to call a control function for each new function.
Can I configure PHP to set this error function automatically?
Check the comments , will give you and idea of how to register callbacks .
How do I catch a PHP Fatal Error
Here are some steps I ll suggest :
a) register register_shutdown_function or other callback functions to track your exceptiosn
b) Each function call Should throw an exception when there is error
c) call_back function catches the exception
d) echo custom output
check my comment on above reference question
You mean the call_user_func and call_user_func_array functions?
function error ($funcName, $funcParameter) {
try {
$params = func_get_args();
unset($params[0]);
call_user_func_array($funcName, $params) or exit ("Error !");
}
catch (exception $e) {
exit ("Error !");
}
}

Categories