* Digest Authentication for Trusted Numbers Manipulation and CLI Mapping

See introduction to XMLAPI for details on Authentication:

https://support.sippysoft.com/a/solutions/articles/106909


#!/usr/bin/env php
<?php

class HTTPSDigestAuthTransport
{
    private $username;
    private $password;
    private $host;

    public function __construct($url)
    {
        $parsedUrl = parse_url($url);
        $this->username = $parsedUrl['user'];
        $this->password = $parsedUrl['pass'];
        $this->host = $parsedUrl['host'];
    }

    public function request($method, $params)
    {
        $handler = '/xmlapi/xmlapi';
        $url = "https://" . $this->host . $handler;

        $requestBody = $this->encode_request($method, $params);

        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
        curl_setopt($ch, CURLOPT_USERPWD, "$this->username:$this->password");
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: text/xml',
            'User-Agent: PHP-Client/1.0'
        ));

        $response = curl_exec($ch);

        if (curl_errno($ch)) {
            throw new Exception('Request Error: ' . curl_error($ch));
        }

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if ($httpCode != 200) {
            throw new Exception("Protocol Error: $httpCode " . curl_error($ch) . "\nResponse: " . $response);
        }

        curl_close($ch);

        return $this->decode_response($response);
    }

    private function encode_request($method, $params)
    {
        $xml = new SimpleXMLElement('<?xml version="1.0"?><methodCall></methodCall>');
        $xml->addChild('methodName', $method);
        $paramsNode = $xml->addChild('params');
        $paramNode = $paramsNode->addChild('param');
        $valueNode = $paramNode->addChild('value');
        $this->add_xml_value($valueNode, $params);
        return $xml->asXML();
    }

    private function add_xml_value($xml, $value)
    {
        if (is_array($value)) {
            if ($this->is_assoc($value)) {
                $structNode = $xml->addChild('struct');
                foreach ($value as $key => $item) {
                    $memberNode = $structNode->addChild('member');
                    $memberNode->addChild('name', $key);
                    $this->add_xml_value($memberNode->addChild('value'), $item);
                }
            } else {
                $arrayNode = $xml->addChild('array')->addChild('data');
                foreach ($value as $item) {
                    $this->add_xml_value($arrayNode->addChild('value'), $item);
                }
            }
        } elseif (is_int($value)) {
            $xml->addChild('int', $value);
        } elseif (is_string($value)) {
            $xml->addChild('string', $value);
        } else {
            $xml->addChild('string', $value);
        }
    }

    private function is_assoc($array)
    {
        return array_keys($array) !== range(0, count($array) - 1);
    }

    private function decode_response($response)
    {
        $xml = simplexml_load_string($response);
        if ($xml === false) {
            throw new Exception('Failed to parse XML response');
        }
        return json_decode(json_encode($xml), true);
    }
}

class Client
{
    private $transport;

    public function __construct($url)
    {
        $this->transport = new HTTPSDigestAuthTransport($url);
    }

    public function addCLIMapping($params)
    {
        return $this->transport->request('addCLIMapping', $params);
    }

    public function listCLIMappings($params)
    {
        return $this->transport->request('listCLIMappings', $params);
    }
}

// Configurable variables
$username = 'username';
$password = 'password';
$server = '1.2.3.4';
$i_account = 34;
$cli = '123456';
$lang = 'en';

$url = "https://$username:$password@$server/xmlapi/xmlapi";
$client = new Client($url);

try {
    // Add a mapping
    $res = $client->addCLIMapping(['i_account' => $i_account, 'cli' => $cli, 'lang' => $lang]);
    print_r($res);

    // Retrieve list of trusted numbers
    $res = $client->listCLIMappings(['i_account' => $i_account]);
    if ($res['result'] == 'OK') {
        foreach ($res['list'] as $cli) {
            echo $cli['value'] . "\n";
        }
    }
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage() . "\n";
}
?>