Cisco phone dialer with PHP

Click and dial can be quite handy and a time saver if you do a lot of calls. Implementing this in a CRM or a web based system is easier then it sounds with Cisco VOIP phones. In this example we will use PHP to call a webservice on the phone and have the phone dial whatever phone number we want.

I picked-up a Cisco 7911G handset from eBay a while back, and combined that with Asterisk as my VOIP PBX. The clever part with the Cisco phones is that they have a lot of webservices that allows you to control various aspects of the phone, including dialing.

A quick note on phone config and authentication

When the phone starts up it fetches a config file (xml) from a TFTP server, in this config file there is an entry called: authenticationURL (see example below). Every webservice request that comes to the phone is first authenticated by calling this URL.

   <deviceSecurityMode>1</deviceSecurityMode>
   <authenticationURL>http://ws.pbx.home.local/authenticate/</authenticationURL>
   <directoryURL>http://ws.pbx.home.local/directory/</directoryURL>
   <idleTimeout>0</idleTimeout>

Since I use Asterisk, I have simply nominated my own authentication URL and use PHP to handle it:

<?php
     print "AUTHORIZED";
     exit;
?>

If you are using Cisco CME and it handles authentication then you should create a low privileged user for webservices.

..and another note on Cisco XML objects

The Cisco IP Phones have push and pull webservices, for our dialer example we are gone use push. Basically we are gone POST an XML snippet to the phone, but it's important to understand that this is not "real" XML.

Read more about "CiscoIPPhone XML Objects" at:

http://www.cisco.com/c/en/us/td/docs/voice_ip_comm/cuipph/all_models/xsi/5_1/english/programming/guide/ipphsv/ip5_1ch2.html

The /CGI/Execute webservice

The webservice we are gone use is YOUR_PHONE_IP/CGI/Execute, and we use HTTP POST when sending the data. The content we are posting is the "CiscoIPPhoneExecute" XML Object:

<CiscoIPPhoneExecute>
  <ExecuteItem Priority="0" URL="Dial:301"/>
</CiscoIPPhoneExecute>

(Priority 0 means "Execute Immediately", 1 is "Execute when idle" and 2 is "Execute if idle")

Let's have a look at what this looks like as a "HTTP POST" packet:

POST /CGI/Execute HTTP/1.0
Host: 192.168.0.129
Authorization: Basic cm9vdDpyb290
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 119

XML=%3CCiscoIPPhoneExecute%3E%3CExecuteItem+Priority%3D%220%22+URL%3D%22Dial%3A301....

Notice the lack of proper XML tags, instead "XML=" is used as the identifier. While if we look at the response below it has a proper XML structure.

HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Date: Sun, 29 Jun 2014 23:53:40 GMT
Expires: Thu, 26 Oct 1995 00:00:00 GMT
Last-Modified: Sun, 29 Jun 2014 23:53:40 GMT
Pragma: no-cache
Content-Length: 148
Server: Allegro-Software-RomPager/4.34

<?xml version="1.0" encoding="utf-8"?>
<CiscoIPPhoneResponse>
<ResponseItem URL="Dial:301" Data="Success" Status="0" />
</CiscoIPPhoneResponse>

PHP code to use Cisco IP Phone webservice

Time to look at some code, below is a working example that will post dial command to a Cisco IP Phone. The username and password (uid/pwd) must be changed to match your system.

In the start I talked a little bit about authentication, and as we can see on the PHP code below it is a simple Base64 encoding: base64_encode($uid.":".$pwd), not much security in there.

Also note that the Cisco IP Phone webservice names and XML objects are case sensitive. Any error messages in regards misspelling are not very helpful and can be a real pain to figure out.

<?php
  // the cisco phone has ip address 192.168.0.129
  // and we are gone tell that phone to dial extension 301.
  // since the priority is 0, it will dial this number even if
  // there is a call in progress..

  $number2dial="301";
  $data='<CiscoIPPhoneExecute><ExecuteItem Priority="0" URL="Dial:'.$number2dial.'"/></CiscoIPPhoneExecute>';
  $ipv4="192.168.0.129";

  $response=cisco_voip_phone_xml_push($ipv4,$data)
  return;


  // push xml-like packet to cisco voip phone...
  function cisco_voip_phone_xml_push($ipv4,$data,$uid="web",$pwd="bot")
  {
     $auth=base64_encode($uid.":".$pwd);
     $xml="XML=".urlencode($data);

     $post="POST /CGI/Execute HTTP/1.0\r\n";
     $post.="Host: $ipv4\r\n";
     $post.="Authorization: Basic $auth\r\n";
     $post.="Connection: close\r\n";
     $post.="Content-Type: application/x-www-form-urlencoded\r\n";
     $post.="Content-Length: ".strlen($xml)."\r\n\r\n";

     $response="";
     $fp=fsockopen($ipv4,80,$errno,$errstr,30);
     if(!$fp) return false;

     fputs($fp,$post.$xml);
     while(!feof($fp))
     {
        $response=fgets($fp,128);
     }
     fclose($fp);
     return $response;
  }
?>

Final thoughts..

Now that we have working code altough a simplified example we could look at implementing it as REST webservice. Then use Javascript and Ajax to call the service whenever a user clicks on phonenumber.

And I made one for myself: http://ws.pbx.home.local/ext/300/dial/301/

I implemented a simple webservice that uses extensions rather then IP address. So in this case extension 300 is told to dial 301, and the webservice looks up the extension to find the ip address in the background.

This phone dialer example is based on working systems using Asterisk and Cisco 7911g, and Cisco CME with 7960 handsets.

Site maintained by tommy@trapv.com.
Page generated in: 0.0172 seconds.
Memory usage: 430616 bytes (peak: 482520 bytes)