MySQL, Asterisk Dialplans and call forwarding - mysql

How do I get Asterisk to forward incoming calls based on matching the incoming call number with a number to forward to? Both numbers are stored in a MySQL database.

Sorry for the long code sample, but more than half of it is debugging code to help you get it set up.
I'm assuming your server already has a modern version of PHP (at /usr/bin/php) with the PDO library, and that you have a database table named fwd_table with columns caller_id and destination.
In /var/lib/asterisk/agi-bin get a copy of the PHP AGI library. Then create a file named something like forward_by_callerid.agi that contains:
#!/usr/bin/php
<?php
ini_set('display_errors','false'); //Supress errors getting sent to the Asterisk process
require('phpagi.php');
$agi = new AGI();
try {
$pdo = new PDO('mysql:host='.$db_hostname.';dbname='.$db_database.';charset=UTF-8', $db_user, $db_pass);
} catch (PDOException $e) {
$agi->conlog("FAIL: Error connecting to the database! " . $e->getMessage());
die();
}
$find_fwd_by_callerid = $pdo->prepare('SELECT destination FROM fwd_table WHERE caller_id=? ');
$caller_id = $agi->request['agi_callerid'];
if($callerid=="unknown" or $callerid=="private" or $callerid==""){
$agi->conlog("Call came in without caller id, I give up");
exit;
}else{
$agi->conlog("Call came in with caller id number $caller_id.");
}
if($find_fwd_by_callerid->execute(array($caller_id)) === false){
$agi->conlog("Database problem searching for forward destination (find_fwd_by_callerid), croaking");
exit;
}
$found_fwds = $find_fwd_by_callerid->fetchAll();
if(count($found_fwds) > 0){
$destination = $found_contacts[0]['destination'];
$agi->set_variable('FWD_TO', $destination);
$agi->conlog("Caller ID matched, setting FWD_TO variable to ''");
}
?>
Then from the dial plan you can call it like this:
AGI(forward_by_callerid.agi)
And if your database has a match, it will set the variable FWD_TO with goodness. Please edit your question if you need more help getting this integrated into your dial plan.

This article should do the trick. It's about 3 lines of code and some simple queries to add and remove forwarding rules.

The solution I was looking for ended up looking like this:
[default]
exten => _X.,1,Set(ARRAY(${EXTEN}_phone)=${DTC_ICF(phone_number,${EXTEN})})
exten => _X.,n(callphone),Dial(SIP/metaswitch/${${EXTEN}_phone},26)
exten => _X.,n(end),Hangup()

Related

Adldap2 authentication always returns true - Yii2

I'm working in Yii2 with the Adldap extension found here: https://github.com/Adldap2/Adldap2
I'm running into an issue when I try to authenticate users on my ldap server. I can successfully make a connection and and retrieve user data, but when trying to authenticate if a user's username and password are correct or not, it always returns true, even if the creds are wrong. Below is my code snippet (with the config array not showing of course):
$ad->addProvider($config);
try {
// If a successful connection is made to your server, the provider will be returned.
$provider = $ad->connect();
//User below does return the correct information from the ldap server
$user = $provider->search()->users()->find('quillin');
try{
$provider->auth()->attempt("wrongUsername","wrongPassword");
die("WIN");
}catch( Exception $e ){
die("Exception " . $e);
}
}catch (\Adldap\Auth\BindException $e) {
die( "There was an issue binding / connecting to the server. <br />" . $e);
}
No matter what I put in for the username and password fields, it always returns true and hits the die("WIN"); line. In my composer.json file, i'm using "adldap2/adldap2": "v7.0.*"
I have also tried to bind the user using the following:
try{
$provider->auth()->attempt("wrongUsername","wrongPassword", $bindAsUser = true);
die("WIN");
}catch( Exception $e ){
die("lose :(");
die("Exception " . $e);
}
And that also always returns true;
I figured this out and will explain here in anyone else has the same issue.
1) $provider->auth()->attempt() should be wrapped in an IF, and not a try/catch.
2) The first parameter, $username, is actually looking for the userprincipalname, the docs had made it sound like it was looking instead for a username.
After that, I was able to authenticate the user successfully.

Stop mysql query when press stop button

I got stuck with this problem, I found many posts but seemed it's not useful. So I post again here and hope someone can help me.
Let say I have 2 button, 1 is Start button and 1 is Stop button. When I press start will call ajax function which query very long time. I need when I press Stop will stop immediately this query, not execute anymore.
this is function used to call query and fetch row. (customize Mysqli.php)
public function fetchMultiRowset($params = array()) {
$data = array();
$mysqli = $this->_adapter->getConnection();
$mysqli->multi_query($this->bindParams($this->_sql, $params));
$thread_id = mysqli_thread_id($mysqli);
ignore_user_abort(true);
ob_start();
$index = 0;
do {
if ($result = $mysqli->store_result()) {
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
$data[$index] = $row;
$index++;
echo " ";
ob_flush();
flush();
}
$result->free();
}
}
while ($mysqli->more_results() && $mysqli->next_result());
ob_end_flush();
return $data;
}
Function in Model:
public function select_entries() {
$data = null;
try {
$db = Zend_Db_Adapter_Mysqlicustom::singleton();
$sql = "SELECT * FROM report LIMIT 2000000";
$data = $db->fetchMultiRowset($sql);
$db->closeConnection();
} catch (Exception $exc) {
}
return $data;
}
Controller:
public function testAction(){
$op = $this->report_test->select_entries();
}
In AJAX I used xhr.abort() to stop the AJAX function. But it still runs the query while AJAX was aborted.
How do I stop query? I used Zend Framework.
EDIT: I did not look in detail at your program, now I see that not the query itself is taking so long, but the reading of all the data. So just check every 1000 rows, if the ajax call is still active. Ajax Abort.
Solution in case of a long-running SQL-query:
You would have to allow the application to kill database queries, and you need to implement a more complex interaction between Client and Server, which could lead to security holes if done wrong.
The Start-Request should contain a session and a page id (secure id, so not 3 and 4 and 5 but a non-guessable but unique hash of some kind). The backend then connects this id with the query. This could be done in some extra table of the database, but also via comments in the SQL query, like "Session fid98a08u4j, Page 940jfmkvlz" => s:<session>p:<page>.
/* s:fid98a08u4jp:940jfmkvlz */ select * from ...
If the user presses "stop", you send session and page id to the server. The php-code then fetches the list of your running SQL Queries and searches for session and page and extracts the query id.
Then the php sends a
kill query <id>
to the MySQL-server.
This might lead to trouble when not using transactions, and this might damage replication. And even a kill query might take some time in the state 'killing'.
So be sure that you can and want not to split the long running query into subqueries, which check if the request is still valid every few seconds, or that you do not just want to kill the query for cosmetical reasons.

Can't catch my mysql errors

I am using codeigniter for my server side in php.
I set my email field UNIQUE on my Users table.
The problem is that whatever I tried I can't catch the error mysql generated when trying to insert a duplicate email.
What i tried inside my model:
function insert($arr) {
$query= $this->CI->db->insert('user', $arr);
if($query){
return $this->CI->db->insert_id();
} else {
$msg = $this->CI-db->_error_message();
return $msg;
}
}
The issues goes that everything is fine until I get a duplicate and I actually get NOTHING inside the $msg. I know debug is on from the database config file.
If your database config 'db_debug' => TRUE, your code will exit with showing the error message and you will not able to reach this line $msg = $this->CI-db->_error_message();.
So to catch the error message you need to set the.
db_debug' => FALSE
At CI-2 your above code will work.See more at this question
But At CI-3 those function is not available and it will produce php undefined method error. CI-3 has a method display_error. You can check it.
My solution: If you want the errors you can get it using this line
$msg = $this->db->conn_id->error_list;
This will give you the error lists as array.But remember you need to set db_debug' => FALSE

Solving "MySQL server has gone away" errors

I have written some code in PHP that returns the html content from .edu domains. A brief introduction is given here: Errors regarding Web Crawler in PHP
The crawler works fine when the number of links to crawl are small (something around 40 URLS) but I am getting "MySQL server has gone away" error after this number.
I am storing html content as longtext in MySQL tables and I am not getting why the error arrives after at least 40-50 insertions.
Any help in this regard is highly appreciated.
Please note that I have already altered the wait_timeout and max_allowed_packet to accomodate my queries and the php code and now I don't know what to do. Please help me in this regard.
You might be inclined to handle this problem by "pinging" the mysql server before a query. This is a bad idea. For more on why, check this SO post: Should I ping mysql server before each query?
The best way to handle the issue is by wrapping queries inside try/catch blocks and catching any database exceptions so that you can handle them appropriately. This is especially important in long running and/or daemon type scripts. So, here's a very basic example using a "connection manager" to control access to DB connections:
class DbPool {
private $connections = array();
function addConnection($id, $dsn) {
$this->connections[$id] = array(
'dsn' => $dsn,
'conn' => null
);
}
function getConnection($id) {
if (!isset($this->connections[$id])) {
throw new Exception('Invalid DB connection requested');
} elseif (isset($this->connections[$id]['conn'])) {
return $this->connections[$id]['conn'];
} else {
try {
// for mysql you need to supply user/pass as well
$conn = new PDO($dsn);
// Tell PDO to throw an exception on error
// (like "MySQL server has gone away")
$conn->setAttribute(
PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION
);
$this->connections[$id]['conn'] = $conn;
return $conn;
} catch (PDOException $e) {
return false;
}
}
}
function close($id) {
if (!isset($this->connections[$id])) {
throw new Exception('Invalid DB connection requested');
}
$this->connections[$id]['conn'] = null;
}
}
class Crawler {
private $dbPool;
function __construct(DbPool $dbPool) {
$this->dbPool = $dbPool;
}
function crawl() {
// craw and store data in $crawledData variable
$this->save($crawledData);
}
function saveData($crawledData) {
if (!$conn = $this->dbPool->getConnection('write_conn') {
// doh! couldn't retrieve DB connection ... handle it
} else {
try {
// perform query on the $conn database connection
} catch (Exception $e) {
$msg = $e->getMessage();
if (strstr($msg, 'MySQL server has gone away') {
$this->dbPool->close('write_conn');
$this->saveData($val);
} else {
// some other error occurred
}
}
}
}
}
I have another answer that deals with what I think is a similar problem, and it would require a similar answer. Basically, you can use the mysql_ping() function to test the connection before your insert. Before MySQL 5.0.14, mysql_ping() would automatically reconnect the server, but now you have to build your own reconnect logic. Something similar to this should work for you:
function check_dbconn($connection) {
if (!mysql_ping($connection)) {
mysql_close($connection);
$connection = mysql_connect('server', 'username', 'password');
mysql_select_db('db',$connection);
}
return $connection;
}
foreach($array as $value) {
$dbconn = check_dbconn($dbconn);
$sql="insert into collected values('".$value."')";
$res=mysql_query($sql, $dbconn);
//then some extra code.
}
I was facing "Mysql server has gone away" error while using Mysql connector 5.X, replacing dll to the last version solved the problem.
Are you opening a single DB connection and reusing it? Is it possible that its a simple timeout? You might be better served by opening a new DB connection for each of your read/write operations (IE contact .edu, get text, open DB, write text, close db, repeat).
Also how are you using the handle? Is it possible that it has hit an error and has 'gone away' for that reason?
Well This is what I am doing now based on rdlowrey's suggestion and I guess this is also right.
public function url_db_html($sourceLink = NULL, $source) {
$source = mysql_real_escape_string($source);
$query = "INSERT INTO html (id, sourceLink, sourceCode)
VALUES (NULL,('$sourceLink') , ('$source'))";
try {
if(mysql_query($query, $this->connection)==FALSE) {
$msg = mysql_errno($this->connection) . ": " . mysql_error($this->connection);
throw new DbException($msg);
}
} catch (DbException $e) {
echo "<br><br>Catched!!!<br><br>";
if(strstr($e->getMessage(), 'MySQL server has gone away')) {
$this->connection = mysql_connect("localhost", "root", "");
mysql_select_db("crawler1", $this->connection);
}
}
}
So once the query has failed to execute, the script will skip it but will make sure the connection is re-established.
However, my web crawler is crashing when files such as .jpg, .bmp, .pdf, etc are encountered. Is there a way to skip those urls containing these extensions. I am using preg_match and has given pdf and doc to match. Yet I want the function to skip all links containing extensions such as mp3, pdf, etc. Is this possible??

session_regenerate_id and database handler

i am using database handler for my sessions which working fine but now i stack into a problem on authentication.
When user login with username/password i do session_regenerate_id and after that i am trying to select the current session_id.
Here is my code
session_regenerate_id();
echo $checkQ=" SELECT * FROM my_sessions WHERE id='".session_id()."' ";
......
but i dont get any results. The session_id is the correct one.
After finish load the page and copy paste the SQL Command to phpMyAdmin i get the results.
I know thats its stupid but the only reason i can think of is that session_regenerate_id() "is too slow" so when i try to read the session_id at next line the session_id has not created in database yet.
Can anyone help me!
I know it has been a while, I hope you have found an answer since this was posted, but I'll add my solution for posterity's sake.
The call to session_generate_id() will cause the value of session_id() to change:
<?php
$before = session_id();
session_regenerate_id();
$after = session_id();
var_dump($before == $after); // outputs false
This problem manifested for me because in the session write handler I was doing this (without such bogus method names, of course):
<?php
class MySQLHandler
{
function read($id)
{
$row = $this->doSelectSql($id);
if ($row) {
$this->foundSessionDuringRead = true;
}
// snip
}
function write($id, $data)
{
if ($this->foundSessionDuringRead) {
$this->doUpdateSql($id, $data);
}
else {
$this->doInsertSql($id, $data);
}
}
}
The write() method worked fine if session_regenerate_id() was never called. If it was called, however, the $id argument to write() is different to the $id passed to read(), so the update won't find any records with the new $id because they've never been inserted.
Some people suggest to use MySQL's "REPLACE INTO" syntax, but that deletes and replaces the row, which plays merry havoc if you want to have a creation date column. What I did to fix the problem was to hold on to the session ID that was passed to read, then update the session ID in the database during write using the id passed to read as the key:
<?php
class MySQLHandler
{
function read($id)
{
$row = $this->doSelectSql($id);
if ($row) {
$this->rowSessionId = $id;
}
// snip
}
function write($id, $data)
{
if ($this->rowSessionId) {
$stmt = $this->pdo->prepare("UPDATE session SET session_id=:id, data=:data WHERE session_id=:rowSessionId AND session_name=:sessionName");
$stmt->bindValue(':id', $id);
$stmt->bindValue(':rowSessionId', $this->rowSessionId);
$stmt->bindValue(':data', $data);
$stmt->bindValue(':sessionName', $this->sessionName);
$stmt->execute();
}
else {
$this->doInsertSql($id, $data);
}
}
}
I think I'm having the same problem you are having. It's unclear to me whether this is a PHP (cache) feature or a bug.
The issue is that, when using a custom SessionHandler and calling session_regenerate_id(true), the new session is not created until the script terminates. I have confirmed that by doing the same thing you did: SELECTing the new session id from the database. And the new session is not there. However, after the script finishes, it is.
This is how I fixed it:
$old_id = session_id();
// If you SELECT your DB and search for $old_id, it will be there.
session_regenerate_id(TRUE);
$new_id = session_id();
// If you SELECT your DB for either $old_id or $new_id, none will be there.
session_write_close();
session_start();
// If you SELECT your DB for $new_id, it will be there.
Therefore the solution (workaround) I came about was to force PHP to write the session. I hope this helps.