Your IP : 216.73.216.224


Current Path : /var/www/html/plugins/membershipprosms/clockwork/clockwork/src/
Upload File :
Current File : /var/www/html/plugins/membershipprosms/clockwork/clockwork/src/Clockwork.php

<?php
/**
* Clockwork PHP API
*
* @package     Clockwork
* @copyright   Mediaburst Ltd 2015
* @license     MIT
* @link        http://www.clockworksms.com
* @version     1.3.2
*/

namespace mediaburst\ClockworkSMS;

/**
* Main Clockwork API Class
*
* @package     Clockwork
* @since       1.0
*/
class Clockwork
{
    /*
    * Version of this class
    */
    public const VERSION           = '2.0.0';

    /**
    * All Clockwork API calls start with BASE_URL
    * @author  Martin Steel
    */
    public const API_BASE_URL      = 'api.clockworksms.com/xml/';

    /**
    * string to append to API_BASE_URL to check authentication
    * @author  Martin Steel
    */
    public const API_AUTH_METHOD   = 'authenticate';

    /**
    * string to append to API_BASE_URL for sending SMS
    * @author  Martin Steel
    */
    public const API_SMS_METHOD    = 'sms';

    /**
    * string to append to API_BASE_URL for checking message credit
    * @author  Martin Steel
    */
    public const API_CREDIT_METHOD = 'credit';

    /**
    * string to append to API_BASE_URL for checking account balance
    * @author  Martin Steel
    */
    public const API_BALANCE_METHOD = 'balance';

    /**
    * Clockwork API Key
    *
    * @var string
    * @author  Martin Steel
    */
    public $key;

    /**
    * Use SSL when making HTTP requests
    *
    * If this is not set, SSL will be used where PHP supports it
    *
    * @var bool
    * @author  Martin Steel
    */
    public $ssl;

    /**
    * Proxy server hostname (Optional)
    *
    * @var string
    * @author  Martin Steel
    */
    public $proxy_host;

    /**
    * Proxy server port (Optional)
    *
    * @var integer
    * @author  Martin Steel
    */
    public $proxy_port;

    /**
    * From address used on text messages
    *
    * @var string (11 characters or 12 numbers)
    * @author  Martin Steel
    */
    public $from;

    /**
    * Allow long SMS messages (Cost up to 3 credits)
    *
    * @var bool
    * @author  Martin Steel
    */
    public $long;

    /**
    * Truncate message text if it is too long
    *
    * @var bool
    * @author  Martin Steel
    */
    public $truncate;

    /**
    * Enables various logging of messages when true.
    *
    * @var bool
    * @author  Martin Steel
    */
    public $log;

    /**
    * What Clockwork should do if you send an invalid character
    *
    * Possible values:
    *      'error'     - Return an error (Messasge is not sent)
    *      'remove'    - Remove the invalid character(s)
    *      'replace'   - Replace invalid characters where possible, remove others
    * @author  Martin Steel
    */
    public $invalid_char_action;

    /**
    * Create a new instance of the Clockwork wrapper
    *
    * @param   string  key         Your Clockwork API Key
    * @param   array   options     Optional parameters for sending SMS
    * @author  Martin Steel
    */
    public function __construct($key, array $options = array())
    {
        if (empty($key)) {
            throw new ClockworkException("Key can't be blank");
        }
        $this->key = $key;


        $this->ssl                  = (\array_key_exists('ssl', $options)) ? $options['ssl'] : null;
        $this->proxy_host           = (\array_key_exists('proxy_host', $options)) ? $options['proxy_host'] : null;
        $this->proxy_port           = (\array_key_exists('proxy_port', $options)) ? $options['proxy_port'] : null;
        $this->from                 = (\array_key_exists('from', $options)) ? $options['from'] : null;
        $this->long                 = (\array_key_exists('long', $options)) ? $options['long'] : null;
        $this->truncate             = (\array_key_exists('truncate', $options)) ? $options['truncate'] : null;
        $this->invalid_char_action  = (\array_key_exists('invalid_char_action', $options)) ? $options['invalid_char_action'] : null;
        $this->log                  = (\array_key_exists('log', $options)) ? $options['log'] : false;
    }

    /**
    * Send some text messages
    *
    *
    * @author  Martin Steel
    */
    public function send(array $sms)
    {
        if (!\is_array($sms)) {
            throw new ClockworkException('sms parameter must be an array');
        }
        $single_message = $this->is_assoc($sms);

        if ($single_message) {
            $sms = array($sms);
        }

        $req_doc = new \DOMDocument('1.0', 'UTF-8');
        $root = $req_doc->createElement('Message');
        $req_doc->appendChild($root);

        $user_node = $req_doc->createElement('Key');
        $user_node->appendChild($req_doc->createTextNode($this->key));
        $root->appendChild($user_node);

        for ($i = 0; $i < \count($sms); $i++) {
            $single = $sms[$i];

            $sms_node = $req_doc->createElement('SMS');

            // Phone number
            $sms_node->appendChild($req_doc->createElement('To', $single['to']));

            // Message text
            $content_node = $req_doc->createElement('Content');
            $content_node->appendChild($req_doc->createTextNode($single['message']));
            $sms_node->appendChild($content_node);

            // From
            if (\array_key_exists('from', $single) || isset($this->from)) {
                $from_node = $req_doc->createElement('From');
                $from_node->appendChild($req_doc->createTextNode(\array_key_exists('from', $single) ? $single['from'] : $this->from));
                $sms_node->appendChild($from_node);
            }

            // Client ID
            if (\array_key_exists('client_id', $single)) {
                $client_id_node = $req_doc->createElement('ClientID');
                $client_id_node->appendChild($req_doc->createTextNode($single['client_id']));
                $sms_node->appendChild($client_id_node);
            }

            // Long
            if (\array_key_exists('long', $single) || isset($this->long)) {
                $long = \array_key_exists('long', $single) ? $single['long'] : $this->long;
                $long_node = $req_doc->createElement('Long');
                $long_node->appendChild($req_doc->createTextNode($long ? 1 : 0));
                $sms_node->appendChild($long_node);
            }

            // Truncate
            if (\array_key_exists('truncate', $single) || isset($this->truncate)) {
                $truncate = \array_key_exists('truncate', $single) ? $single['truncate'] : $this->truncate;
                $trunc_node = $req_doc->createElement('Truncate');
                $trunc_node->appendChild($req_doc->createTextNode($truncate ? 1 : 0));
                $sms_node->appendChild($trunc_node);
            }

            // Invalid Char Action
            if (\array_key_exists('invalid_char_action', $single) || isset($this->invalid_char_action)) {
                $action = \array_key_exists('invalid_char_action', $single) ? $single['invalid_char_action'] : $this->invalid_char_action;
                switch (strtolower($action)) {
                    case 'error':
                        $sms_node->appendChild($req_doc->createElement('InvalidCharAction', 1));
                        break;
                    case 'remove':
                        $sms_node->appendChild($req_doc->createElement('InvalidCharAction', 2));
                        break;
                    case 'replace':
                        $sms_node->appendChild($req_doc->createElement('InvalidCharAction', 3));
                        break;
                    default:
                        break;
                }
            }

            // Wrapper ID
            $sms_node->appendChild($req_doc->createElement('WrapperID', $i));

            $root->appendChild($sms_node);
        }

        $req_xml = $req_doc->saveXML();

        $resp_xml = $this->postToClockwork(self::API_SMS_METHOD, $req_xml);
        $resp_doc = new \DOMDocument();
        $resp_doc->loadXML($resp_xml);

        $response = array();
        $err_no = null;
        $err_desc = null;

        foreach ($resp_doc->documentElement->childNodes as $doc_child) {
            switch(strtolower($doc_child->nodeName)) {
                case 'sms_resp':
                    $resp = array();
                    $wrapper_id = null;
                    foreach ($doc_child->childNodes as $resp_node) {
                        switch(strtolower($resp_node->nodeName)) {
                            case 'messageid':
                                $resp['id'] = $resp_node->nodeValue;
                                break;
                            case 'errno':
                                $resp['error_code'] = $resp_node->nodeValue;
                                break;
                            case 'errdesc':
                                $resp['error_message'] = $resp_node->nodeValue;
                                break;
                            case 'wrapperid':
                                $wrapper_id = $resp_node->nodeValue;
                                break;
                        }
                    }
                    if (\array_key_exists('error_code', $resp)) {
                        $resp['success'] = 0;
                    } else {
                        $resp['success'] = 1;
                    }
                    $resp['sms'] = $sms[$wrapper_id];
                    array_push($response, $resp);
                    break;
                case 'errno':
                    $err_no = $doc_child->nodeValue;
                    break;
                case 'errdesc':
                    $err_desc = $doc_child->nodeValue;
                    break;
            }
        }

        if (isset($err_no)) {
            throw new ClockworkException($err_desc, $err_no);
        }

        if ($single_message) {
            return $response[0];
        }
        return $response;
    }

    /**
    * Check how many SMS credits you have available
    *
    * @return  integer   SMS credits remaining
    * @deprecated Use checkBalance() instead
    * @author  Martin Steel
    */
    public function checkCredit()
    {
        // Create XML doc for request
        $req_doc = new \DOMDocument('1.0', 'UTF-8');
        $root = $req_doc->createElement('Credit');
        $req_doc->appendChild($root);
        $root->appendChild($req_doc->createElement('Key', $this->key));
        $req_xml = $req_doc->saveXML();

        // POST XML to Clockwork
        $resp_xml = $this->postToClockwork(self::API_CREDIT_METHOD, $req_xml);

        // Create XML doc for response
        $resp_doc = new \DOMDocument();
        $resp_doc->loadXML($resp_xml);

        // Parse the response to find credit value

        $err_no = null;
        $err_desc = null;

        foreach ($resp_doc->documentElement->childNodes as $doc_child) {
            switch ($doc_child->nodeName) {
                case 'Credit':
                    $credit = $doc_child->nodeValue;
                    break;
                case 'ErrNo':
                    $err_no = $doc_child->nodeValue;
                    break;
                case 'ErrDesc':
                    $err_desc = $doc_child->nodeValue;
                    break;
                default:
                    break;
            }
        }

        if (isset($err_no)) {
            throw new ClockworkException($err_desc, $err_no);
        }

        return $credit;
    }

    /**
    * Check your account balance
    *
    * @return  array   Array of account balance:
    * @author  Martin Steel
    */
    public function checkBalance()
    {
        // Create XML doc for request
        $req_doc = new \DOMDocument('1.0', 'UTF-8');
        $root = $req_doc->createElement('Balance');
        $req_doc->appendChild($root);
        $root->appendChild($req_doc->createElement('Key', $this->key));
        $req_xml = $req_doc->saveXML();

        // POST XML to Clockwork
        $resp_xml = $this->postToClockwork(self::API_BALANCE_METHOD, $req_xml);

        // Create XML doc for response
        $resp_doc = new \DOMDocument();
        $resp_doc->loadXML($resp_xml);

        // Parse the response to find balance value
        $balance = null;
        $err_no = null;
        $err_desc = null;
        $account_type = null;

        foreach ($resp_doc->documentElement->childNodes as $doc_child) {
            switch ($doc_child->nodeName) {
                case 'Balance':
                    $balance = number_format(\floatval($doc_child->nodeValue), 2);
                    break;
                case 'Currency':
                    foreach ($doc_child->childNodes as $resp_node) {
                        switch ($resp_node->tagName) {
                            case 'Symbol':
                                $symbol = $resp_node->nodeValue;
                                break;
                            case 'Code':
                                $code = $resp_node->nodeValue;
                                break;
                        }
                    }
                    break;
                case 'AccountType':
                    $account_type = $doc_child->nodeValue;
                    break;
                case 'ErrNo':
                    $err_no = $doc_child->nodeValue;
                    break;
                case 'ErrDesc':
                    $err_desc = $doc_child->nodeValue;
                    break;
                default:
                    break;
            }
        }

        if (isset($err_no)) {
            throw new ClockworkException($err_desc, $err_no);
        }

        return array( 'symbol' => $symbol, 'balance' => $balance, 'code' => $code, 'account_type' => $account_type );
    }

    /**
    * Check whether the API Key is valid
    *
    * @return  bool    True indicates a valid key
    * @author  Martin Steel
    */
    public function checkKey()
    {
        // Create XML doc for request
        $req_doc = new \DOMDocument('1.0', 'UTF-8');
        $root = $req_doc->createElement('Authenticate');
        $req_doc->appendChild($root);
        $root->appendChild($req_doc->createElement('Key', $this->key));
        $req_xml = $req_doc->saveXML();

        // POST XML to Clockwork
        $resp_xml = $this->postToClockwork(self::API_AUTH_METHOD, $req_xml);

        // Create XML doc for response
        $resp_doc = new \DOMDocument();
        $resp_doc->loadXML($resp_xml);

        // Parse the response to see if authenticated

        $err_no = null;
        $err_desc = null;

        foreach ($resp_doc->documentElement->childNodes as $doc_child) {
            switch ($doc_child->nodeName) {
                case 'CustID':
                    $cust_id = $doc_child->nodeValue;
                    break;
                case 'ErrNo':
                    $err_no = $doc_child->nodeValue;
                    break;
                case 'ErrDesc':
                    $err_desc = $doc_child->nodeValue;
                    break;
                default:
                    break;
            }
        }

        if (isset($err_no)) {
            throw new ClockworkException($err_desc, $err_no);
        }

        return isset($cust_id);
    }

    /**
    * Make an HTTP POST to Clockwork
    *
    * @param   string   method Clockwork method to call (sms/credit)
    * @param   string   data   Content of HTTP POST
    *
    * @return  string          Response from Clockwork
    * @author  Martin Steel
    */
    protected function postToClockwork($method, $data)
    {
        if ($this->log) {
            $this->logXML("API $method Request XML", $data);
        }

        if (isset($this->ssl)) {
            $ssl = $this->ssl;
        } else {
            $ssl = $this->sslSupport();
        }

        $url = $ssl ? 'https://' : 'http://';
        $url .= self::API_BASE_URL . $method;

        $response = $this->xmlPost($url, $data);

        if ($this->log) {
            $this->logXML("API $method Response XML", $response);
        }

        return $response;
    }

    /**
    * Make a HTTP POST
    *
    * cURL will be used if available, otherwise tries the PHP stream functions
    *
    * @param   string url      URL to send to
    * @param   string data     Data to POST
    * @return  string          Response returned by server
    * @author  Martin Steel
    */
    protected function xmlPost($url, $data)
    {
        if (\extension_loaded('curl')) {
            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
            curl_setopt($ch, CURLOPT_USERAGENT, 'Clockwork PHP Wrapper/1.0' . self::VERSION);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
            curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
            if (isset($this->proxy_host) && isset($this->proxy_port)) {
                curl_setopt($ch, CURLOPT_PROXY, $this->proxy_host);
                curl_setopt($ch, CURLOPT_PROXYPORT, $this->proxy_port);
            }

            $response = curl_exec($ch);
            $info = curl_getinfo($ch);

            if ($response === false || $info['http_code'] != 200) {
                throw new \Exception('HTTP Error calling Clockwork API - HTTP Status: ' . $info['http_code'] . ' - cURL Erorr: ' . curl_error($ch));
            } elseif (curl_errno($ch) > 0) {
                throw new \Exception('HTTP Error calling Clockwork API - cURL Error: ' . curl_error($ch));
            }

            curl_close($ch);

            return $response;
        } elseif (\function_exists('stream_get_contents')) {
            // Enable error Track Errors
            $track = ini_get('track_errors');
            ini_set('track_errors', true);

            $params = array('http' => array(
            'method'  => 'POST',
            'header'  => "Content-Type: text/xml\r\nUser-Agent: mediaburst PHP Wrapper/" . self::VERSION . "\r\n",
            'content' => $data,
            ));

            if (isset($this->proxy_host) && isset($this->proxy_port)) {
                $params['http']['proxy'] = 'tcp://' . $this->proxy_host . ':' . $this->proxy_port;
                $params['http']['request_fulluri'] = true;
            }

            $ctx = stream_context_create($params);
            $fp = @fopen($url, 'rb', false, $ctx);
            if (!$fp) {
                ini_set('track_errors', $track);
                throw new \Exception("HTTP Error calling Clockwork API - fopen Error: $php_errormsg");
            }
            $response = @stream_get_contents($fp);
            if ($response === false) {
                ini_set('track_errors', $track);
                throw new \Exception("HTTP Error calling Clockwork API - stream Error: $php_errormsg");
            }
            ini_set('track_errors', $track);

            return $response;
        }
        throw new \Exception('Clockwork requires PHP5 with cURL or HTTP stream support');
    }

    /**
    * Does the server/HTTP wrapper support SSL
    *
    * This is a best guess effort, some servers have weird setups where even
    * though cURL is compiled with SSL support is still fails to make
    * any requests.
    *
    * @return bool     True if SSL is supported
    * @author  Martin Steel
    */
    protected function sslSupport()
    {
        $ssl = false;
        // See if PHP is compiled with cURL
        if (\extension_loaded('curl')) {
            $version = curl_version();
            $ssl = ($version['features'] & CURL_VERSION_SSL) ? true : false;
        } elseif (\extension_loaded('openssl')) {
            $ssl = true;
        }

        return $ssl;
    }

    /**
    * Log some XML, tidily if possible, in the PHP error log
    *
    * @param   string  log_msg The log message to prepend to the XML
    * @param   string  xml     An XML formatted string
    *
    * @return  void
    * @author  Martin Steel
    */
    protected function logXML($log_msg, $xml)
    {
        // Tidy if possible
        if (class_exists('tidy')) {
            $tidy = new \tidy();
            $config = array(
            'indent'     => true,
            'input-xml'  => true,
            'output-xml' => true,
            'wrap'       => 200,
            );
            $tidy->parseString($xml, $config, 'utf8');
            $tidy->cleanRepair();
            $xml = $tidy;
        }
        // Output
        error_log("Clockwork $log_msg: $xml");
    }

    /**
    * Check if an array is associative
    *
    * @param   array $array Array to check
    * @return  bool
    * @author  Martin Steel
    */
    protected function is_assoc($array)
    {
        return (bool) \count(array_filter(array_keys($array), 'is_string'));
    }

    /**
     * Check if a number is a valid MSISDN
     *
     * @param string $val Value to check
     * @return bool True if valid MSISDN
     * @author James Inman
     * @since 1.3.0
     * @todo Take an optional country code and check that the number starts with it
     */
    public static function is_valid_msisdn($val)
    {
        return preg_match('/^[1-9][0-9]{7,12}$/', $val);
    }
}