<?php 
/**
* @version		$Id: sms.helper.php 2582 2024-05-07 16:43:56Z IOS $
* @package		Elxis
* @subpackage	Helpers / SMS
* @copyright	Copyright (c) 2006-2024 Elxis CMS (https://www.elxis.org). All rights reserved.
* @license		Elxis Public License ( https://www.elxis.org/elxis-public-license.html )
* @author		Elxis Team ( https://www.elxis.org )
* @description 	Elxis CMS is free software. Read the license for copyright notices and details
*/

defined('_ELXIS_') or die ('Direct access to this location is not allowed');


class elxisSmsHelper {

	private $options = array();
	private $errormsg = '';


	/***************/
	/* CONSTRUCTOR */
	/***************/
	public function __construct() {
	}


	/*********************************/
	/* SET SMS CONFIGURATION OPTIONS */
	/*********************************/
	public function setOptions($options) {
		$this->options = array();
		if (!is_array($options)) { return; }
		$this->options = $options;
	}


	/**********************************************************/
	/* SET SMS CONFIGURATION OPTIONS FROM ELXIS CONFIGURATION */
	/**********************************************************/
	public function setElxisConfigOptions() {
		$this->options = array();
		$sms_params = stripslashes(eFactory::getElxis()->getConfig('SMS_PARAMS'));
		if ($sms_params == '') { return; }
		if (strpos($sms_params, '{') !== 0) { return; }
		$params = json_decode($sms_params, true);
		if ($params) {
			foreach ($params as $k => $v) {
				$this->options[$k] = $v;
			}
		}
	}


	/*********************/
	/* GET ERROR MESSAGE */
	/*********************/
	public function getError() {
		return $this->errormsg;
	}


	/********************/
	/* SEND SMS MESSAGE */
	/********************/
	public function sendMessage($to, $message) {
		$this->errormsg = '';

		if (count($this->options) == 0) {
			$this->errormsg = 'SMS configuration parameters not provided!';
			return false;
		}
		if (trim($to) == '') {
			$this->errormsg = 'Recipient mobile phone number not provided!';
			return false;
		}
		if (trim($message) == '') {
			$this->errormsg = 'Empty message!';
			return false;
		}

        $to = trim(preg_replace('/[^\d]/', '', $to));
        if (preg_match('/^(00)/', $to)) { $to = substr($to, 2); }
		$len = strlen($to);
		if (($to == '') || ($len < 7) || ($len > 20)) {
			$this->errormsg = 'Recipient mobile phone number is empty or wrong!';
			return false;
		}

		$log = isset($this->options['log']) ? $this->options['log'] : 0;
		$provider = isset($this->options['provider']) ? $this->options['provider'] : '';
		if ($provider == '') {
			$this->errormsg = 'No SMS provider configured!';
			return false;
		}

		$func = 'send'.ucfirst($provider);
		if (!method_exists($this, $func)) {
			$this->errormsg = 'Not supported SMS provider '.$provider.'!';
			return false;
		}

		if (!function_exists('curl_init') || !is_callable('curl_exec')) {
			$this->errormsg = 'CURL is not supported by your PHP. Cannot send SMS message!';
			return false;
		}

		$ok = $this->$func($to, $message);
		if (!$ok) {
			if ($log == 1) {
				elxisError::logWarning('SMS ERROR. To: '.$to.' Provider: '.$provider.'. '.$this->errormsg);
			}
		}
		return $ok;
	}


	/***************************************************/
	/* SEND SMS MESSAGE USING CLICKATELL (params: api) */
	/***************************************************/
	private function sendClickatell($to, $message) {
		$apikey = isset($this->options['api']) ? trim($this->options['api']) : '';
		$from = isset($this->options['from']) ? trim($this->options['from']) : '';

		if ($apikey == '') {
			$this->errormsg = 'Clickatell API Key not set!';
			return false;
		}

		$params = array('apiKey' => $apikey, 'to' => $to, 'content' => $message);
		if ($from != '') { $params['from'] = $from; }
		$qs = http_build_query($params);

		$headers = array('Accept: application/json');
		$curlInfo = curl_version();
		$agent = 'ClickatellV2/1.0 curl/'.$curlInfo['version'].' PHP/'.phpversion();

		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, 'https://platform.clickatell.com/messages/http/send?'.$qs);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_FAILONERROR, true);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
		curl_setopt($ch, CURLOPT_USERAGENT, $agent);
		curl_setopt($ch, CURLOPT_HEADER, false);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
		curl_setopt($ch, CURLOPT_TIMEOUT, 20);
		$errormsg = '';
		$result = curl_exec($ch);
		if (curl_errno($ch) == 0) {
			curl_close($ch);
		} else {
			$errormsg = curl_error($ch);
			curl_close($ch);
		}

		if ($errormsg != '') {
			$this->errormsg = $errormsg;
			return false;
		}

		$ok = false;
		if ($result != '') {
			if (strpos($result, '{') === 0) {
				$arr = json_decode($result, true);
				$rcode = isset($arr['responseCode']) ? (int)$arr['responseCode'] : 0;
				if (isset($arr['messages'][0]['error'])) { $errormsg = $arr['messages'][0]['error']; }
				if (in_array($rcode, array(200, 201, 202))) {
					if (isset($arr['messages'][0]['errorCode'])) {
						$errorCode = (int)$arr['messages'][0]['errorCode'];
						if ($errorCode == '') {
							$errorCode = 0;
						} else {
							$errorCode = (int)$errorCode;
						}
						if ($errorCode == 0) { $ok = true; }
					} else if (isset($arr['messages'][0]['accepted'])) {
						$accepted = (int)$arr['messages'][0]['accepted'];
						if ($accepted == 1) { $ok = true; }
					}
				}
			}
		}

		if (!$ok) {
			$this->errormsg = ($errormsg == '') ? 'Sending SMS failed' : $errormsg;
			return false;
		} else {
			return true;
		}
	}


	/************************************************/
	/* SEND SMS MESSAGE USING EASYSMS (params: api) */
	/************************************************/
	private function sendEasysms($to, $message) {
		$apikey = isset($this->options['api']) ? trim($this->options['api']) : '';
		$from = isset($this->options['from']) ? trim($this->options['from']) : '';

		if ($apikey == '') {
			$this->errormsg = 'EasySMS API Key not set!';
			return false;
		}

		$params = array('key' => $apikey, 'to' => $to, 'text' => $message, 'type' => 'json');
		if ($from != '') { $params['from'] = $from; }

		$curlInfo = curl_version();
		$agent = 'Curl/'.$curlInfo['version'].' PHP/'.phpversion();

		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, 'https://easysms.gr/api/sms/send');
		curl_setopt($ch, CURLOPT_POST, true);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_FAILONERROR, true);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_USERAGENT, $agent);
		curl_setopt($ch, CURLOPT_HEADER, false);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 8);
		curl_setopt($ch, CURLOPT_TIMEOUT, 15);
		$errormsg = '';
		$result = curl_exec($ch);
		if (curl_errno($ch) == 0) {
			curl_close($ch);
		} else {
			curl_setopt($ch, CURLOPT_URL, 'https://backup.easysms.gr/api/sms/send');//try backup server
			$result = curl_exec($ch);
			if (curl_errno($ch) == 0) {
				curl_close($ch);
			} else {
				$errormsg = curl_error($ch);
				curl_close($ch);
			}
		}

		if ($errormsg != '') {
			$this->errormsg = $errormsg;
			return false;
		}

		$ok = false;
		if ($result != '') {
			if (strpos($result, '{') === 0) {
				$arr = json_decode($result, true);
				$status = isset($arr['status']) ? (int)$arr['status'] : 0;
				$error = isset($arr['error']) ? (int)$arr['error'] : 0;
				$remarks = isset($arr['remarks']) ? trim($arr['remarks']) : '';
				if ($status == 1) {
					$ok = true;
				} else {
					switch ($error) {
						case 101: $errormsg = 'Check your credentials'; break;
						case 102: $errormsg = 'Parameter to is empty'; break;
						case 103: $errormsg = 'Invalid to parameter'; break;
						case 104: $errormsg = 'Parameter text is empty'; break;
						case 105: $errormsg = 'Not enough balance'; break;
						default: $errormsg = 'Error code '.$error; break;
					}
					if ($remarks != '') { $errormsg = $remarks; }
				}
			}
		}

		if (!$ok) {
			$this->errormsg = ($errormsg == '') ? 'Sending SMS failed' : $errormsg;
			return false;
		} else {
			return true;
		}
	}

	/****************************************************************/
	/* SEND SMS MESSAGE USING VONAGE (params: api, apisecret, from) */
	/****************************************************************/
	private function sendVonage($to, $message) {
		$api_key = isset($this->options['api']) ? trim($this->options['api']) : '';
		$api_secret = isset($this->options['apisecret']) ? trim($this->options['apisecret']) : '';
		$from = isset($this->options['from']) ? trim($this->options['from']) : '';

		if ($api_key == '') {
			$this->errormsg = 'Vonage API Key not set!';
			return false;
		}
		if ($api_secret == '') {
			$this->errormsg = 'Vonage API secret not set!';
			return false;
		}
		if ($from == '') { $from = 'Elxis CMS'; }//Must always be set

		$is_unicode = false;
		for ($i = 0; $i < strlen($message); $i++) {
			if (ord($message[$i]) > 127) { $is_unicode = true; break; }
		}

		$params = array('api_key' => $api_key, 'api_secret' => $api_secret, 'to' => $to, 'from' => $from, 'text' => $message);
		if ($is_unicode) { $params['type'] = 'unicode'; }
		$qs = http_build_query($params);

		$curlInfo = curl_version();
		$agent = 'Curl/'.$curlInfo['version'].' PHP/'.phpversion();

		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, 'https://rest.nexmo.com/sms/json?'.$qs);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_FAILONERROR, true);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_USERAGENT, $agent);
		curl_setopt($ch, CURLOPT_HEADER, false);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
		curl_setopt($ch, CURLOPT_TIMEOUT, 20);
		$errormsg = '';
		$result = curl_exec($ch);
		if (curl_errno($ch) == 0) {
			curl_close($ch);
		} else {
			$errormsg = curl_error($ch);
			curl_close($ch);
		}

		if ($errormsg != '') {
			$this->errormsg = $errormsg;
			return false;
		}

		$ok = false;
		if ($result != '') {
			if (strpos($result, '{') === 0) {
				$arr = json_decode($result, true);
				if (isset($arr['messages'])) {
					if (is_array($arr['messages'])) {
						if (isset($arr['messages'][0]['status'])) {
							$status = (int)$arr['messages'][0]['status'];
							if ($status > 0) {
								if (isset($arr['messages'][0]['error-text'])) {
									$errormsg = $arr['messages'][0]['error-text'];
								}
							} else {
								$ok = true;
							}
						}
					}
				}
			}
		}

		if (!$ok) {
			$this->errormsg = ($errormsg == '') ? 'Sending SMS failed' : $errormsg;
			return false;
		} else {
			return true;
		}
	}


	/***************************************************************/
	/* SEND SMS MESSAGE USING SINCH (params: api, apisecret, from) */
	/***************************************************************/
	private function sendSinch($to, $message) {
		$service_plan_id = isset($this->options['api']) ? trim($this->options['api']) : '';
		$bearer_token = isset($this->options['apisecret']) ? trim($this->options['apisecret']) : '';
		$from = isset($this->options['from']) ? trim($this->options['from']) : '';

		if ($service_plan_id == '') {
			$this->errormsg = 'Service plan ID not set!';
			return false;
		}
		if ($bearer_token == '') {
			$this->errormsg = 'Bearer token not set!';
			return false;
		}
		if ($from == '') { $from = 'Elxis CMS'; }//Required

		$content = array('to' => array($to), 'from' => $from, 'body' => $message);
		$params = json_encode($content);

		$url = 'https://sms.api.sinch.com/xms/v1/'.$service_plan_id.'/batches';
		$curlInfo = curl_version();
		$agent = 'Curl/'.$curlInfo['version'].' PHP/'.phpversion();

		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
		curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
		curl_setopt($ch, CURLOPT_XOAUTH2_BEARER, $bearer_token);
		curl_setopt($ch, CURLOPT_POST, true);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_FAILONERROR, true);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_USERAGENT, $agent);
		curl_setopt($ch, CURLOPT_HEADER, false);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 8);
		curl_setopt($ch, CURLOPT_TIMEOUT, 15);
		$errormsg = '';
		$result = curl_exec($ch);
		if (curl_errno($ch) == 0) {
			curl_close($ch);
		} else {
			$errormsg = curl_error($ch);
			curl_close($ch);
		}

		if ($errormsg != '') {
			$this->errormsg = $errormsg;
			return false;
		}

		$ok = false;
		if ($result != '') {
			if (strpos($result, '{') === 0) {
				$arr = json_decode($result, true);
				$id = isset($arr['id']) ? trim($arr['id']) : '';
				if ($id != '') { $ok = true; }
			}
		}

		if (!$ok) {
			$this->errormsg = ($errormsg == '') ? 'Sending SMS failed' : $errormsg;
			return false;
		} else {
			return true;
		}
	}


	/**************************************************************/
	/* SEND SMS MESSAGE USING INSTASENT (params: apisecret, from) */
	/**************************************************************/
	private function sendInstasent($to, $message) {
		$bearer_token = isset($this->options['apisecret']) ? trim($this->options['apisecret']) : '';
		$from = isset($this->options['from']) ? trim($this->options['from']) : '';

		if ($bearer_token == '') {
			$this->errormsg = 'Bearer token not set!';
			return false;
		}
		if ($from == '') { $from = 'Elxis'; }//Required
		if (strpos($to, '+') !== 0) { $to = '+'.$to; }//requires * prefix

		$is_unicode = false;
		for ($i = 0; $i < strlen($message); $i++) {
			if (ord($message[$i]) > 127) { $is_unicode = true; break; }
		}

		$content = array('to' => $to, 'from' => $from, 'text' => $message, 'allowUnicode' => $is_unicode);
		$params = json_encode($content);

		$url ='https://api.instasent.com/transactional/v1/sms';
		$curlInfo = curl_version();
		$agent = 'Curl/'.$curlInfo['version'].' PHP/'.phpversion();

		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json', 'Authorization: '.$bearer_token, 'Content-Type: application/json'));
		curl_setopt($ch, CURLOPT_ENCODING, '');
		curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
		curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
		curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
		curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_FAILONERROR, true);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_USERAGENT, $agent);
		curl_setopt($ch, CURLOPT_HEADER, false);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 8);
		curl_setopt($ch, CURLOPT_TIMEOUT, 15);
		$errormsg = '';
		$result = curl_exec($ch);
		$info = curl_getinfo($ch);
		$http_code = (int)$info['http_code'];
		if (curl_errno($ch) == 0) {
			curl_close($ch);
		} else {
			$errormsg = curl_error($ch);
			curl_close($ch);
		}

		if ($errormsg != '') {
			$this->errormsg = $errormsg;
			return false;
		}

		switch ($http_code) {
			case 400: $errormsg = 'You request body is malformed or something went wrong with your request'; break;
			case 401: $errormsg = 'You are missing or using bad credentials'; break;
			case 402: $errormsg = 'You are out of money'; break;
			case 413: $errormsg = 'You are sending a large body in your request'; break;
			case 422: $errormsg = 'Some field of your request body is not valid'; break;
			case 429: $errormsg = 'You reached your endpoint rate limit'; break;
			case 500: $errormsg = 'Internal server error on instasent.com'; break;
			case 201: break;//Success
			default: $errormsg = 'Error code '.$http_code; break;
		}
		if ($errormsg != '') {
			$this->errormsg = $errormsg;
			return false;
		}
		return true;
	}

}

?>