Sindbad~EG File Manager
<?php
/**
* SMS Service Class
* Supports multiple African SMS gateways
*/
class SMSService {
private $db;
private $settings;
public function __construct() {
$this->db = Database::getInstance()->getConnection();
$this->loadSettings();
}
/**
* Load SMS settings from database
*/
private function loadSettings() {
$stmt = $this->db->query("SELECT * FROM sms_settings ORDER BY id DESC LIMIT 1");
$this->settings = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$this->settings) {
// Create default settings
$this->db->exec("INSERT INTO sms_settings (gateway_provider, is_enabled, test_mode) VALUES ('africas_talking', 0, 1)");
$this->loadSettings();
}
}
/**
* Check if SMS service is enabled
*/
public function isEnabled() {
return $this->settings && $this->settings['is_enabled'] == 1;
}
/**
* Get current gateway provider
*/
public function getGateway() {
return $this->settings['gateway_provider'] ?? 'africas_talking';
}
/**
* Queue SMS for sending
*/
public function queueSMS($phone, $message, $recipientName = null, $senderId = null, $scheduledAt = null) {
if (!$this->isEnabled()) {
error_log("SMS Service: Not enabled");
return false;
}
// Validate phone number
$phone = $this->formatPhoneNumber($phone);
if (!$phone) {
error_log("SMS Service: Invalid phone number");
return false;
}
// Use default sender ID if not provided
if (!$senderId) {
$senderId = $this->settings['default_sender_name'] ?? $this->settings['at_sender_id'] ?? 'Church';
}
$stmt = $this->db->prepare("
INSERT INTO sms_queue (recipient_phone, recipient_name, message, sender_id, scheduled_at)
VALUES (?, ?, ?, ?, ?)
");
return $stmt->execute([$phone, $recipientName, $message, $senderId, $scheduledAt]);
}
/**
* Send SMS instantly
*/
public function sendInstantSMS($phone, $message, $recipientName = null, $senderId = null) {
if (!$this->isEnabled()) {
return ['success' => false, 'error' => 'SMS service is not enabled'];
}
// Validate phone number
$phone = $this->formatPhoneNumber($phone);
if (!$phone) {
return ['success' => false, 'error' => 'Invalid phone number'];
}
// Use default sender ID if not provided
if (!$senderId) {
$senderId = $this->settings['default_sender_name'] ?? $this->settings['at_sender_id'] ?? 'Church';
}
// Send based on gateway
$gateway = $this->getGateway();
switch ($gateway) {
case 'africas_talking':
return $this->sendViaAfricasTalking($phone, $message, $senderId);
case 'twilio':
return $this->sendViaTwilio($phone, $message);
case 'bulksms_nigeria':
return $this->sendViaBulkSMSNigeria($phone, $message, $senderId);
case 'hubtel':
return $this->sendViaHubtel($phone, $message, $senderId);
case 'clickatell':
return $this->sendViaClickatell($phone, $message);
case 'smsportal':
return $this->sendViaSMSPortal($phone, $message);
case 'arkesel':
return $this->sendViaArkesel($phone, $message, $senderId);
case 'custom':
return $this->sendViaCustomGateway($phone, $message, $senderId);
default:
return ['success' => false, 'error' => 'Unknown gateway: ' . $gateway];
}
}
/**
* Send via Africa's Talking (Kenya, Nigeria, Uganda, etc.)
*/
private function sendViaAfricasTalking($phone, $message, $senderId) {
$apiKey = $this->settings['at_api_key'];
$username = $this->settings['at_username'];
if (!$apiKey || !$username) {
return ['success' => false, 'error' => 'Africa\'s Talking credentials not configured'];
}
if ($this->settings['test_mode']) {
return $this->simulateSMS($phone, $message, 'africas_talking');
}
$url = 'https://api.africastalking.com/version1/messaging';
$data = [
'username' => $username,
'to' => $phone,
'message' => $message,
'from' => $senderId
];
$headers = [
'apiKey: ' . $apiKey,
'Content-Type: application/x-www-form-urlencoded',
'Accept: application/json'
];
$response = $this->sendHTTPRequest($url, 'POST', $data, $headers);
if ($response['success']) {
$result = json_decode($response['body'], true);
if (isset($result['SMSMessageData']['Recipients'][0]['status']) &&
$result['SMSMessageData']['Recipients'][0]['status'] === 'Success') {
$this->logSMS($phone, $message, $senderId, 'africas_talking', 'sent', $response['body']);
return ['success' => true, 'message_id' => $result['SMSMessageData']['Recipients'][0]['messageId'] ?? null];
}
}
$this->logSMS($phone, $message, $senderId, 'africas_talking', 'failed', $response['body'] ?? 'Unknown error');
return ['success' => false, 'error' => $response['error'] ?? 'Failed to send SMS'];
}
/**
* Send via Twilio
*/
private function sendViaTwilio($phone, $message) {
$accountSid = $this->settings['twilio_account_sid'];
$authToken = $this->settings['twilio_auth_token'];
$fromNumber = $this->settings['twilio_from_number'];
if (!$accountSid || !$authToken || !$fromNumber) {
return ['success' => false, 'error' => 'Twilio credentials not configured'];
}
if ($this->settings['test_mode']) {
return $this->simulateSMS($phone, $message, 'twilio');
}
$url = "https://api.twilio.com/2010-04-01/Accounts/{$accountSid}/Messages.json";
$data = [
'To' => $phone,
'From' => $fromNumber,
'Body' => $message
];
$headers = [
'Authorization: Basic ' . base64_encode($accountSid . ':' . $authToken)
];
$response = $this->sendHTTPRequest($url, 'POST', $data, $headers);
if ($response['success']) {
$result = json_decode($response['body'], true);
if (isset($result['sid'])) {
$this->logSMS($phone, $message, $fromNumber, 'twilio', 'sent', $response['body']);
return ['success' => true, 'message_id' => $result['sid']];
}
}
$this->logSMS($phone, $message, $fromNumber, 'twilio', 'failed', $response['body'] ?? 'Unknown error');
return ['success' => false, 'error' => $response['error'] ?? 'Failed to send SMS'];
}
/**
* Send via BulkSMS Nigeria
*/
private function sendViaBulkSMSNigeria($phone, $message, $senderId) {
$apiToken = $this->settings['bulksms_api_token'];
if (!$apiToken) {
return ['success' => false, 'error' => 'BulkSMS Nigeria credentials not configured'];
}
if ($this->settings['test_mode']) {
return $this->simulateSMS($phone, $message, 'bulksms_nigeria');
}
$url = 'https://www.bulksmsnigeria.com/api/v1/sms/create';
$data = [
'api_token' => $apiToken,
'from' => $senderId,
'to' => $phone,
'body' => $message
];
$response = $this->sendHTTPRequest($url, 'POST', $data);
if ($response['success']) {
$result = json_decode($response['body'], true);
if (isset($result['data']['id'])) {
$this->logSMS($phone, $message, $senderId, 'bulksms_nigeria', 'sent', $response['body']);
return ['success' => true, 'message_id' => $result['data']['id']];
}
}
$this->logSMS($phone, $message, $senderId, 'bulksms_nigeria', 'failed', $response['body'] ?? 'Unknown error');
return ['success' => false, 'error' => $response['error'] ?? 'Failed to send SMS'];
}
/**
* Send via Hubtel (Ghana)
*/
private function sendViaHubtel($phone, $message, $senderId) {
$clientId = $this->settings['hubtel_client_id'];
$clientSecret = $this->settings['hubtel_client_secret'];
if (!$clientId || !$clientSecret) {
return ['success' => false, 'error' => 'Hubtel credentials not configured'];
}
if ($this->settings['test_mode']) {
return $this->simulateSMS($phone, $message, 'hubtel');
}
$url = 'https://api.hubtel.com/v1/messages/send';
$data = [
'From' => $senderId,
'To' => $phone,
'Content' => $message
];
$headers = [
'Authorization: Basic ' . base64_encode($clientId . ':' . $clientSecret),
'Content-Type: application/json'
];
$response = $this->sendHTTPRequest($url, 'POST', json_encode($data), $headers);
if ($response['success']) {
$result = json_decode($response['body'], true);
if (isset($result['MessageId'])) {
$this->logSMS($phone, $message, $senderId, 'hubtel', 'sent', $response['body']);
return ['success' => true, 'message_id' => $result['MessageId']];
}
}
$this->logSMS($phone, $message, $senderId, 'hubtel', 'failed', $response['body'] ?? 'Unknown error');
return ['success' => false, 'error' => $response['error'] ?? 'Failed to send SMS'];
}
/**
* Send via Clickatell
*/
private function sendViaClickatell($phone, $message) {
$apiKey = $this->settings['clickatell_api_key'];
if (!$apiKey) {
return ['success' => false, 'error' => 'Clickatell credentials not configured'];
}
if ($this->settings['test_mode']) {
return $this->simulateSMS($phone, $message, 'clickatell');
}
$url = 'https://platform.clickatell.com/messages';
$data = [
'messages' => [
[
'to' => [$phone],
'text' => $message
]
]
];
$headers = [
'Authorization: ' . $apiKey,
'Content-Type: application/json'
];
$response = $this->sendHTTPRequest($url, 'POST', json_encode($data), $headers);
if ($response['success']) {
$result = json_decode($response['body'], true);
if (isset($result['messages'][0]['apiMessageId'])) {
$this->logSMS($phone, $message, null, 'clickatell', 'sent', $response['body']);
return ['success' => true, 'message_id' => $result['messages'][0]['apiMessageId']];
}
}
$this->logSMS($phone, $message, null, 'clickatell', 'failed', $response['body'] ?? 'Unknown error');
return ['success' => false, 'error' => $response['error'] ?? 'Failed to send SMS'];
}
/**
* Send via SMS Portal (South Africa)
*/
private function sendViaSMSPortal($phone, $message) {
$clientId = $this->settings['smsportal_client_id'];
$clientSecret = $this->settings['smsportal_client_secret'];
if (!$clientId || !$clientSecret) {
return ['success' => false, 'error' => 'SMS Portal credentials not configured'];
}
if ($this->settings['test_mode']) {
return $this->simulateSMS($phone, $message, 'smsportal');
}
$url = 'https://rest.smsportal.com/v1/bulkmessages';
$data = [
'messages' => [
[
'content' => $message,
'destination' => $phone
]
]
];
$headers = [
'Authorization: Basic ' . base64_encode($clientId . ':' . $clientSecret),
'Content-Type: application/json'
];
$response = $this->sendHTTPRequest($url, 'POST', json_encode($data), $headers);
if ($response['success']) {
$this->logSMS($phone, $message, null, 'smsportal', 'sent', $response['body']);
return ['success' => true];
}
$this->logSMS($phone, $message, null, 'smsportal', 'failed', $response['body'] ?? 'Unknown error');
return ['success' => false, 'error' => $response['error'] ?? 'Failed to send SMS'];
}
/**
* Send via Arkesel (Ghana)
*/
private function sendViaArkesel($phone, $message, $senderId) {
$apiKey = $this->settings['arkesel_api_key'];
if (!$apiKey) {
return ['success' => false, 'error' => 'Arkesel credentials not configured'];
}
if ($this->settings['test_mode']) {
return $this->simulateSMS($phone, $message, 'arkesel');
}
// Use sender ID from settings if not provided
if (!$senderId) {
$senderId = $this->settings['arkesel_sender_id'] ?? 'Arkesel';
}
$url = 'https://sms.arkesel.com/api/v2/sms/send';
$data = [
'sender' => $senderId,
'message' => $message,
'recipients' => [$phone]
];
$headers = [
'api-key: ' . $apiKey,
'Content-Type: application/json'
];
$response = $this->sendHTTPRequest($url, 'POST', json_encode($data), $headers);
if ($response['success']) {
$result = json_decode($response['body'], true);
if (isset($result['status']) && $result['status'] === 'success') {
$this->logSMS($phone, $message, $senderId, 'arkesel', 'sent', $response['body']);
return ['success' => true, 'message_id' => $result['data']['id'] ?? null];
}
}
$this->logSMS($phone, $message, $senderId, 'arkesel', 'failed', $response['body'] ?? 'Unknown error');
return ['success' => false, 'error' => $response['error'] ?? 'Failed to send SMS'];
}
/**
* Send via custom gateway
*/
private function sendViaCustomGateway($phone, $message, $senderId) {
$url = $this->settings['custom_api_url'];
$apiKey = $this->settings['custom_api_key'];
$method = $this->settings['custom_method'] ?? 'POST';
if (!$url) {
return ['success' => false, 'error' => 'Custom gateway URL not configured'];
}
if ($this->settings['test_mode']) {
return $this->simulateSMS($phone, $message, 'custom');
}
$data = [
'phone' => $phone,
'message' => $message,
'sender_id' => $senderId,
'api_key' => $apiKey
];
$headers = [];
if ($this->settings['custom_headers']) {
$headers = json_decode($this->settings['custom_headers'], true) ?? [];
}
$response = $this->sendHTTPRequest($url, $method, $data, $headers);
if ($response['success']) {
$this->logSMS($phone, $message, $senderId, 'custom', 'sent', $response['body']);
return ['success' => true];
}
$this->logSMS($phone, $message, $senderId, 'custom', 'failed', $response['body'] ?? 'Unknown error');
return ['success' => false, 'error' => $response['error'] ?? 'Failed to send SMS'];
}
/**
* Send HTTP request
*/
private function sendHTTPRequest($url, $method = 'POST', $data = [], $headers = []) {
$ch = curl_init();
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, is_array($data) ? http_build_query($data) : $data);
} elseif ($method === 'GET' && $data) {
$url .= '?' . http_build_query($data);
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
return ['success' => false, 'error' => $error];
}
if ($httpCode >= 200 && $httpCode < 300) {
return ['success' => true, 'body' => $response, 'code' => $httpCode];
}
return ['success' => false, 'error' => 'HTTP ' . $httpCode, 'body' => $response];
}
/**
* Simulate SMS sending (test mode)
*/
private function simulateSMS($phone, $message, $gateway) {
$messageId = 'TEST_' . time() . '_' . rand(1000, 9999);
$this->logSMS($phone, $message, null, $gateway, 'sent', 'TEST MODE - SMS not actually sent');
return ['success' => true, 'message_id' => $messageId, 'test_mode' => true];
}
/**
* Log SMS to database
*/
private function logSMS($phone, $message, $senderId, $gateway, $status, $response = null, $messageId = null) {
$stmt = $this->db->prepare("
INSERT INTO sms_logs (recipient_phone, message, sender_id, gateway_provider, status, gateway_response, gateway_message_id, sent_at)
VALUES (?, ?, ?, ?, ?, ?, ?, NOW())
");
$stmt->execute([$phone, $message, $senderId, $gateway, $status, $response, $messageId]);
}
/**
* Format phone number to international format
*/
private function formatPhoneNumber($phone) {
// Remove spaces, dashes, and parentheses
$phone = preg_replace('/[^0-9+]/', '', $phone);
// If doesn't start with +, assume it needs country code
if (!str_starts_with($phone, '+')) {
// You can add logic here to add default country code
// For now, we'll just prepend + if it starts with country code digits
if (strlen($phone) > 10) {
$phone = '+' . $phone;
}
}
return $phone;
}
/**
* Get SMS statistics
*/
public function getStatistics($days = 30) {
$stmt = $this->db->prepare("
SELECT
COUNT(*) as total,
SUM(CASE WHEN status = 'sent' THEN 1 ELSE 0 END) as sent,
SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed,
gateway_provider
FROM sms_logs
WHERE sent_at >= DATE_SUB(NOW(), INTERVAL ? DAY)
GROUP BY gateway_provider
");
$stmt->execute([$days]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists