Upload files to "system/plugin"
Signed-off-by: kevin <kevin@codelab.nestict.africa>
This commit is contained in:
BIN
system/plugin/.DS_Store
vendored
Normal file
BIN
system/plugin/.DS_Store
vendored
Normal file
Binary file not shown.
2
system/plugin/.gitattributes
vendored
Normal file
2
system/plugin/.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
420
system/plugin/CreateHotspotUser.php
Normal file
420
system/plugin/CreateHotspotUser.php
Normal file
@@ -0,0 +1,420 @@
|
||||
<?php
|
||||
function Alloworigins()
|
||||
{
|
||||
header("Access-Control-Allow-Origin: *");
|
||||
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
|
||||
header("Access-Control-Allow-Headers: Content-Type");
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
exit;
|
||||
}
|
||||
$requestUri = $_SERVER['REQUEST_URI'];
|
||||
$queryString = parse_url($requestUri, PHP_URL_QUERY);
|
||||
$type = null;
|
||||
if ($queryString) {
|
||||
parse_str($queryString, $queryParameters);
|
||||
if (isset($queryParameters['type'])) {
|
||||
$type = $queryParameters['type'];
|
||||
if ($type === "grant") {
|
||||
CreateHostspotUser();
|
||||
exit;
|
||||
} elseif ($type === "verify") {
|
||||
VerifyHotspot();
|
||||
exit;
|
||||
} elseif ($type === "reconnect") {
|
||||
ReconnectUser();
|
||||
exit;
|
||||
} elseif ($type === "voucher") {
|
||||
ReconnectVoucher();
|
||||
exit;
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'code' => 400, 'message' => 'The parameter is not present in the URL.']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ReconnectVoucher() {
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$rawData = file_get_contents('php://input');
|
||||
$postData = json_decode($rawData, true);
|
||||
|
||||
if (!isset($postData['voucher_code'], $postData['account_id'])) {
|
||||
echo json_encode(['status' => 'error', 'code' => 400, 'message' => 'Missing accountId or voucherCode field']);
|
||||
return;
|
||||
}
|
||||
|
||||
$accountId = $postData['account_id'];
|
||||
$voucherCode = $postData['voucher_code'];
|
||||
|
||||
$voucher = ORM::for_table('tbl_voucher')
|
||||
->where('code', $voucherCode)
|
||||
->where('status', '0')
|
||||
->find_one();
|
||||
|
||||
if (!$voucher) {
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'Resultcode' => '1',
|
||||
'voucher' => 'Not Found',
|
||||
'message' => 'Invalid Voucher code'
|
||||
]);
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($voucher['status'] == '1') {
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'Resultcode' => '3',
|
||||
'voucher' => 'Used',
|
||||
'message' => 'Voucher code is already used'
|
||||
]);
|
||||
exit();
|
||||
}
|
||||
|
||||
$planId = $voucher['id_plan'];
|
||||
$routername = $voucher['routers'];
|
||||
|
||||
$router = ORM::for_table('tbl_routers')
|
||||
->where('name', $routername)
|
||||
->find_one();
|
||||
|
||||
if (!$router) {
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => 'Router not found'
|
||||
]);
|
||||
exit();
|
||||
}
|
||||
|
||||
$routerId = $router['id'];
|
||||
|
||||
if (!ORM::for_table('tbl_plans')->where('id', $planId)->count() || !ORM::for_table('tbl_routers')->where('id', $routerId)->count()) {
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => 'Unable to process your request, please refresh the page'
|
||||
]);
|
||||
exit();
|
||||
}
|
||||
|
||||
$user = ORM::for_table('tbl_customers')->where('username', $accountId)->find_one();
|
||||
if (!$user) {
|
||||
// Create a new user if not exists
|
||||
$user = ORM::for_table('tbl_customers')->create();
|
||||
$user->username = $accountId;
|
||||
$user->password = '1234';
|
||||
$user->fullname = $accountId;
|
||||
$user->email = $accountId . '@gmail.com';
|
||||
$user->phonenumber = $accountId;
|
||||
$user->pppoe_password = '1234';
|
||||
$user->address = '';
|
||||
$user->service_type = 'Hotspot';
|
||||
}
|
||||
|
||||
$user->router_id = $routerId;
|
||||
$user->save();
|
||||
|
||||
// Update the voucher with the user ID
|
||||
$voucher->user = $user->id;
|
||||
$voucher->status = '1'; // Mark as used
|
||||
$voucher->save();
|
||||
|
||||
if (Package::rechargeUser($user->id, $routername, $planId, 'Voucher', $voucherCode)) {
|
||||
echo json_encode([
|
||||
'status' => 'success',
|
||||
'Resultcode' => '2',
|
||||
'voucher' => 'activated',
|
||||
'message' => 'Voucher code has been activated',
|
||||
'username' => $user->username
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to recharge user package'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
function ReconnectUser()
|
||||
{
|
||||
header('Content-Type: application/json');
|
||||
$rawData = file_get_contents('php://input');
|
||||
$postData = json_decode($rawData, true);
|
||||
if (!$postData) {
|
||||
echo json_encode(['status' => 'error', 'code' => 400, 'message' => 'Invalid JSON DATA']);
|
||||
exit();
|
||||
}
|
||||
|
||||
if (!isset($postData['mpesa_code'])) {
|
||||
echo json_encode(['status' => 'error', 'code' => 400, 'message' => 'missing required fields']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$mpesaCode = $postData['mpesa_code'];
|
||||
|
||||
// Query the payment gateway table
|
||||
$payment = ORM::for_table('tbl_payment_gateway')
|
||||
->where('gateway_trx_id', $mpesaCode)
|
||||
->find_one();
|
||||
|
||||
if (!$payment) {
|
||||
$data = array(['status' => 'error', "Resultcode" => "1", 'user' => "Not Found", 'message' => 'Invalid Mpesa Transaction code']);
|
||||
echo json_encode($data);
|
||||
exit();
|
||||
}
|
||||
|
||||
$username = $payment['username'];
|
||||
|
||||
// Query the user recharges table
|
||||
$recharge = ORM::for_table('tbl_user_recharges')
|
||||
->where('username', $username)
|
||||
->order_by_desc('id')
|
||||
->find_one();
|
||||
|
||||
if ($recharge) {
|
||||
$status = $recharge['status'];
|
||||
if ($status == 'on') {
|
||||
$data = array(
|
||||
"Resultcode" => "2",
|
||||
"user" => "Active User",
|
||||
"username" => $username,
|
||||
"tyhK" => "1234", // Replace with the actual password or token
|
||||
"Message" => "We have verified your transaction under the Mpesa Transaction $mpesaCode. Please don't leave this page as we are redirecting you.",
|
||||
"Status" => "success"
|
||||
);
|
||||
} elseif ($status == "off") {
|
||||
$data = array(
|
||||
"Resultcode" => "3",
|
||||
"user" => "Expired User",
|
||||
"Message" => "We have verified your transaction under the Mpesa Transaction $mpesaCode. But your Package is already Expired. Please buy a new Package.",
|
||||
"Status" => "danger"
|
||||
);
|
||||
} else {
|
||||
$data = array(
|
||||
"Message" => "Unexpected status value",
|
||||
"Status" => "error"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$data = array(
|
||||
"Message" => "Recharge information not found",
|
||||
"Status" => "error"
|
||||
);
|
||||
}
|
||||
|
||||
echo json_encode($data);
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
function VerifyHotspot() {
|
||||
header('Content-Type: application/json');
|
||||
$rawData = file_get_contents('php://input');
|
||||
$postData = json_decode($rawData, true);
|
||||
|
||||
if (!$postData) {
|
||||
echo json_encode(['Resultcode' => 'error', 'Message' => 'Invalid JSON data']);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($postData['account_id'])) {
|
||||
echo json_encode(['Resultcode' => 'error', 'Message' => 'Missing required fields']);
|
||||
return;
|
||||
}
|
||||
|
||||
$accountId = $postData['account_id'];
|
||||
$user = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $accountId)
|
||||
->order_by_desc('id')
|
||||
->find_one();
|
||||
|
||||
if ($user) {
|
||||
$status = $user->status;
|
||||
$mpesacode = $user->gateway_trx_id;
|
||||
$res = $user->pg_paid_response;
|
||||
|
||||
if ($status == 2 && !empty($mpesacode)) {
|
||||
echo json_encode([
|
||||
"Resultcode" => "3",
|
||||
"Message" => "We have received your transaction under the Mpesa Transaction $mpesacode. Please do not leave this page as we are redirecting you.",
|
||||
"Status" => "success"
|
||||
]);
|
||||
} elseif ($res == "Not enough balance") {
|
||||
echo json_encode([
|
||||
"Resultcode" => "2",
|
||||
"Message" => "Insufficient Balance for the transaction",
|
||||
"Status" => "danger"
|
||||
]);
|
||||
} elseif ($res == "Wrong Mpesa pin") {
|
||||
echo json_encode([
|
||||
"Resultcode" => "2",
|
||||
"Message" => "You entered Wrong Mpesa pin, please resubmit",
|
||||
"Status" => "danger"
|
||||
]);
|
||||
} elseif ($status == 4) {
|
||||
echo json_encode([
|
||||
"Resultcode" => "2",
|
||||
"Message" => "You cancelled the transaction, you can enter phone number again to activate",
|
||||
"Status" => "info"
|
||||
]);
|
||||
} elseif (empty($mpesacode)) {
|
||||
echo json_encode([
|
||||
"Resultcode" => "1",
|
||||
"Message" => "A payment pop up has been sent to your phone. Please enter PIN to continue (Please do not leave or reload the page until redirected).",
|
||||
"Status" => "primary"
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
echo json_encode([
|
||||
"Resultcode" => "error",
|
||||
"Message" => "User not found"
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function CreateHostspotUser()
|
||||
{
|
||||
header('Content-Type: application/json');
|
||||
$rawData = file_get_contents('php://input');
|
||||
$postData = json_decode($rawData, true);
|
||||
if (!$postData) {
|
||||
echo json_encode(['status' => 'error', 'code' => 400, 'message' => 'Invalid JSON DATA' . $postData . ' n tes ']);
|
||||
} else {
|
||||
$phone = $postData['phone_number'];
|
||||
$planId = $postData['plan_id'];
|
||||
$routerId = $postData['router_id'];
|
||||
$accountId = $postData['account_id'];
|
||||
|
||||
|
||||
|
||||
if (!isset( $postData['phone_number'], $postData['plan_id'], $postData['router_id'], $postData['account_id'])) {
|
||||
echo json_encode(['status' => 'error', 'code' => 400, 'message' => 'missing required fields' . $postData, 'phone' => $phone, 'planId' => $planId, 'routerId' => $routerId, 'accountId' => $accountId]);
|
||||
} else {
|
||||
$phone = (substr($phone, 0, 1) == '+') ? str_replace('+', '', $phone) : $phone;
|
||||
$phone = (substr($phone, 0, 1) == '0') ? preg_replace('/^0/', '254', $phone) : $phone;
|
||||
$phone = (substr($phone, 0, 1) == '7') ? preg_replace('/^7/', '2547', $phone) : $phone; //cater for phone number prefix 2547XXXX
|
||||
$phone = (substr($phone, 0, 1) == '1') ? preg_replace('/^1/', '2541', $phone) : $phone; //cater for phone number prefix 2541XXXX
|
||||
$phone = (substr($phone, 0, 1) == '0') ? preg_replace('/^01/', '2541', $phone) : $phone;
|
||||
$phone = (substr($phone, 0, 1) == '0') ? preg_replace('/^07/', '2547', $phone) : $phone;
|
||||
if (strlen($phone) !== 12) {
|
||||
echo json_encode(['status' => 'error', 'code' => 1, 'message' => 'Phone number ' . $phone . ' is invalid. Please confirm.']);
|
||||
}
|
||||
if (strlen($phone) == 12 && !empty($planId) && !empty($routerId)) {
|
||||
$PlanExist = ORM::for_table('tbl_plans')->where('id', $planId)->count() > 0;
|
||||
$RouterExist = ORM::for_table('tbl_routers')->where('id', $routerId)->count() > 0;
|
||||
if (!$PlanExist || !$RouterExist)
|
||||
echo json_encode(["status" => "error", "message" => "Unable to process your request, please refresh the page."]);
|
||||
}
|
||||
$Userexist = ORM::for_table('tbl_customers')->where('username', $accountId)->find_one();
|
||||
if ($Userexist) {
|
||||
$Userexist->router_id = $routerId;
|
||||
$Userexist->save();
|
||||
InitiateStkpush($phone, $planId, $accountId, $routerId);
|
||||
} else {
|
||||
try {
|
||||
$defpass = '1234';
|
||||
$defaddr = 'netXtreme';
|
||||
$defmail = $phone . '@gmail.com';
|
||||
$createUser = ORM::for_table('tbl_customers')->create();
|
||||
$createUser->username = $accountId;
|
||||
$createUser->password = $defpass;
|
||||
$createUser->fullname = $phone;
|
||||
$createUser->router_id = $routerId;
|
||||
$createUser->phonenumber = $phone;
|
||||
$createUser->pppoe_password = $defpass;
|
||||
$createUser->address = $defaddr;
|
||||
$createUser->email = $defmail;
|
||||
$createUser->service_type = 'Hotspot';
|
||||
if ($createUser->save()) {
|
||||
InitiateStkpush($phone, $planId, $accountId, $routerId);
|
||||
} else {
|
||||
echo json_encode(["status" => "error", "message" => "There was a system error when registering user, please contact support."]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(["status" => "error", "message" => "Error creating user: " . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function InitiateStkpush($phone, $planId, $accountId, $routerId)
|
||||
{
|
||||
$gateway = ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'payment_gateway')
|
||||
->find_one();
|
||||
$gateway = ($gateway) ? $gateway->value : null;
|
||||
if ($gateway == "MpesatillStk") {
|
||||
$url = U . "plugin/initiatetillstk";
|
||||
} elseif ($gateway == "BankStkPush") {
|
||||
$url = U . "plugin/initiatebankstk";
|
||||
} elseif ($gateway == "mpesa") {
|
||||
$url = U . "plugin/initiatempesa";
|
||||
} else {
|
||||
$url = null; // or handle the default case appropriately
|
||||
}
|
||||
$Planname = ORM::for_table('tbl_plans')
|
||||
->where('id', $planId)
|
||||
->order_by_desc('id')
|
||||
->find_one();
|
||||
$Findrouter = ORM::for_table('tbl_routers')
|
||||
->where('id', $routerId)
|
||||
->order_by_desc('id')
|
||||
->find_one();
|
||||
$rname = $Findrouter->name;
|
||||
$price = $Planname->price;
|
||||
$Planname = $Planname->name_plan;
|
||||
$Checkorders = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $accountId)
|
||||
->where('status', 1)
|
||||
->order_by_desc('id')
|
||||
->find_many();
|
||||
if ($Checkorders) {
|
||||
foreach ($Checkorders as $Dorder) {
|
||||
$Dorder->delete();
|
||||
}
|
||||
}
|
||||
try {
|
||||
$d = ORM::for_table('tbl_payment_gateway')->create();
|
||||
$d->username = $accountId;
|
||||
$d->gateway = $gateway;
|
||||
$d->plan_id = $planId;
|
||||
$d->plan_name = $Planname;
|
||||
$d->routers_id = $routerId;
|
||||
$d->routers = $rname;
|
||||
$d->price = $price;
|
||||
$d->payment_method = $gateway;
|
||||
$d->payment_channel = $gateway;
|
||||
$d->created_date = date('Y-m-d H:i:s');
|
||||
$d->paid_date = date('Y-m-d H:i:s');
|
||||
$d->expired_date = date('Y-m-d H:i:s');
|
||||
$d->pg_url_payment = $url;
|
||||
$d->status = 1;
|
||||
$d->save();
|
||||
} catch (Exception $e) {
|
||||
error_log('Error saving payment gateway record: ' . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
SendSTKcred($phone, $url, $accountId);
|
||||
}
|
||||
|
||||
function SendSTKcred($phone, $url, $accountId )
|
||||
{
|
||||
$link = $url;
|
||||
$fields = array(
|
||||
'username' => $accountId,
|
||||
'phone' => $phone,
|
||||
'channel' => 'Yes',
|
||||
);
|
||||
$postvars = http_build_query($fields);
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $link);
|
||||
curl_setopt($ch, CURLOPT_POST, count($fields));
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $postvars);
|
||||
$result = curl_exec($ch);
|
||||
}
|
||||
|
||||
Alloworigins();
|
||||
636
system/plugin/c2b.php
Normal file
636
system/plugin/c2b.php
Normal file
@@ -0,0 +1,636 @@
|
||||
<?php
|
||||
|
||||
register_menu("Mpesa C2B Settings", true, "c2b_settings", 'SETTINGS', '', '', "");
|
||||
register_menu("Mpesa Transactions", true, "c2b_overview", 'AFTER_REPORTS', 'fa fa-paypal', '', "");
|
||||
|
||||
try {
|
||||
$db = ORM::get_db();
|
||||
$tableCheckQuery = "CREATE TABLE IF NOT EXISTS tbl_mpesa_transactions (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
TransID VARCHAR(255) NOT NULL,
|
||||
TransactionType VARCHAR(255) NOT NULL,
|
||||
TransTime VARCHAR(255) NOT NULL,
|
||||
TransAmount DECIMAL(10, 2) NOT NULL,
|
||||
BusinessShortCode VARCHAR(255) NOT NULL,
|
||||
BillRefNumber VARCHAR(255) NOT NULL,
|
||||
OrgAccountBalance DECIMAL(10, 2) NOT NULL,
|
||||
MSISDN VARCHAR(255) NOT NULL,
|
||||
FirstName VARCHAR(255) NOT NULL,
|
||||
CustomerID VARCHAR(255) NOT NULL,
|
||||
PackageName VARCHAR(255) NOT NULL,
|
||||
PackagePrice VARCHAR(255) NOT NULL,
|
||||
TransactionStatus VARCHAR(255) NOT NULL,
|
||||
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
)";
|
||||
$db->exec($tableCheckQuery);
|
||||
} catch (PDOException $e) {
|
||||
echo "Error creating the table: " . $e->getMessage();
|
||||
} catch (Exception $e) {
|
||||
echo "An unexpected error occurred: " . $e->getMessage();
|
||||
}
|
||||
|
||||
function c2b_overview()
|
||||
{
|
||||
global $ui, $config;
|
||||
_admin();
|
||||
$ui->assign('_title', 'Mpesa C2B Payment Overview');
|
||||
$ui->assign('_system_menu', '');
|
||||
$admin = Admin::_info();
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
// Check user type for access
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
exit;
|
||||
}
|
||||
|
||||
$query = ORM::for_table('tbl_mpesa_transactions')->order_by_desc('TransTime');
|
||||
$payments = $query->find_many();
|
||||
|
||||
if (
|
||||
(empty($config['mpesa_c2b_consumer_key']) || empty($config['mpesa_c2b_consumer_secret']) || empty($config['mpesa_c2b_business_code']))
|
||||
&& !$config['c2b_registered']
|
||||
) {
|
||||
$ui->assign('message', '<em>' . Lang::T("You haven't registered your validation and verification URLs. Please register URLs by clicking ") . ' <a href="' . APP_URL . '/index.php?_route=plugin/c2b_settings"> Register URL </a>' . '</em>');
|
||||
}
|
||||
$ui->assign('payments', $payments);
|
||||
$ui->assign('xheader', '<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.11.5/css/jquery.dataTables.css">');
|
||||
$ui->display('c2b_overview.tpl');
|
||||
}
|
||||
|
||||
function c2b_settings()
|
||||
{
|
||||
global $ui, $admin, $config;
|
||||
$ui->assign('_title', Lang::T("Mpesa C2B Settings [Offline Payment]"));
|
||||
$ui->assign('_system_menu', 'settings');
|
||||
$admin = Admin::_info();
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
|
||||
if (_post('save') == 'save') {
|
||||
$mpesa_c2b_consumer_key = _post('mpesa_c2b_consumer_key');
|
||||
$mpesa_c2b_consumer_secret = _post('mpesa_c2b_consumer_secret');
|
||||
$mpesa_c2b_business_code = _post('mpesa_c2b_business_code');
|
||||
$mpesa_c2b_env = _post('mpesa_c2b_env');
|
||||
$mpesa_c2b_api = _post('mpesa_c2b_api');
|
||||
$mpesa_c2b_low_fee = _post('mpesa_c2b_low_fee') ? 1 : 0;
|
||||
$mpesa_c2b_bill_ref = _post('mpesa_c2b_bill_ref');
|
||||
|
||||
$errors = [];
|
||||
if (empty($mpesa_c2b_consumer_key)) {
|
||||
$errors[] = Lang::T('Mpesa C2B Consumer Key is required.');
|
||||
}
|
||||
if (empty($mpesa_c2b_consumer_secret)) {
|
||||
$errors[] = Lang::T('Mpesa C2B Consumer Secret is required.');
|
||||
}
|
||||
if (empty($mpesa_c2b_business_code)) {
|
||||
$errors[] = Lang::T('Mpesa C2B Business Code is required.');
|
||||
}
|
||||
if (empty($mpesa_c2b_env)) {
|
||||
$errors[] = Lang::T('Mpesa C2B Environment is required.');
|
||||
}
|
||||
if (empty($mpesa_c2b_api)) {
|
||||
$errors[] = Lang::T('Mpesa C2B API URL is required.');
|
||||
}
|
||||
|
||||
if (empty($mpesa_c2b_bill_ref)) {
|
||||
$errors[] = Lang::T('Mpesa Bill Ref Number Type is required.');
|
||||
}
|
||||
|
||||
if (!empty($errors)) {
|
||||
$ui->assign('message', implode('<br>', $errors));
|
||||
$ui->display('c2b_settings.tpl');
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = [
|
||||
'mpesa_c2b_consumer_key' => $mpesa_c2b_consumer_key,
|
||||
'mpesa_c2b_consumer_secret' => $mpesa_c2b_consumer_secret,
|
||||
'mpesa_c2b_business_code' => $mpesa_c2b_business_code,
|
||||
'mpesa_c2b_env' => $mpesa_c2b_env,
|
||||
'mpesa_c2b_api' => $mpesa_c2b_api,
|
||||
'mpesa_c2b_low_fee' => $mpesa_c2b_low_fee,
|
||||
'mpesa_c2b_bill_ref' => $mpesa_c2b_bill_ref,
|
||||
];
|
||||
|
||||
// Update or insert settings in the database
|
||||
foreach ($settings as $key => $value) {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
|
||||
if ($d) {
|
||||
$d->value = $value;
|
||||
$d->save();
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_appconfig')->create();
|
||||
$d->setting = $key;
|
||||
$d->value = $value;
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
|
||||
if ($admin) {
|
||||
_log('[' . $admin['username'] . ']: ' . Lang::T('Settings Saved Successfully'));
|
||||
}
|
||||
r2(U . 'plugin/c2b_settings', 's', Lang::T('Settings Saved Successfully'));
|
||||
}
|
||||
|
||||
if (!empty($config['mpesa_c2b_consumer_key'] && $config['mpesa_c2b_consumer_secret'] && $config['mpesa_c2b_business_code']) && !$config['c2b_registered']) {
|
||||
$ui->assign('message', '<em>' . Lang::T("You haven't registered your validation and verification URLs, Please register URLs by clicking ") . ' <a href="' . APP_URL . '/index.php?_route=plugin/c2b_settings"> Register URL </a>' . '</em>');
|
||||
}
|
||||
$ui->assign('_c', $config);
|
||||
$ui->assign('companyName', $config['CompanyName']);
|
||||
$ui->display('c2b_settings.tpl');
|
||||
}
|
||||
|
||||
function c2b_generateAccessToken()
|
||||
{
|
||||
global $config;
|
||||
$mpesa_c2b_env = $config['mpesa_c2b_env'] ?? null;
|
||||
$mpesa_c2b_consumer_key = $config['mpesa_c2b_consumer_key'] ?? null;
|
||||
$mpesa_c2b_consumer_secret = $config['mpesa_c2b_consumer_secret'] ?? null;
|
||||
$access_token_url = match ($mpesa_c2b_env) {
|
||||
"live" => 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials',
|
||||
"sandbox" => 'https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials',
|
||||
};
|
||||
$headers = ['Content-Type:application/json; charset=utf8'];
|
||||
$curl = curl_init($access_token_url);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
|
||||
curl_setopt($curl, CURLOPT_HEADER, FALSE);
|
||||
curl_setopt($curl, CURLOPT_USERPWD, "$mpesa_c2b_consumer_key:$mpesa_c2b_consumer_secret");
|
||||
$result = curl_exec($curl);
|
||||
$result = json_decode($result);
|
||||
if (isset($result->access_token)) {
|
||||
return $result->access_token;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function c2b_registerUrl()
|
||||
{
|
||||
global $config;
|
||||
if (
|
||||
(empty($config['mpesa_c2b_consumer_key']) || empty($config['mpesa_c2b_consumer_secret']) || empty($config['mpesa_c2b_business_code']))
|
||||
&& !$config['c2b_registered']
|
||||
) {
|
||||
r2(U . 'plugin/c2b_settings', 'e', Lang::T('Please setup your M-Pesa C2B settings first'));
|
||||
exit;
|
||||
}
|
||||
$access_token = c2b_generateAccessToken();
|
||||
switch ($access_token) {
|
||||
case null:
|
||||
r2(U . 'plugin/c2b_settings', 'e', Lang::T('Failed to generate access token'));
|
||||
exit;
|
||||
default:
|
||||
$BusinessShortCode = $config['mpesa_c2b_business_code'] ?? null;
|
||||
$mpesa_c2b_env = $config['mpesa_c2b_env'] ?? null;
|
||||
$confirmationUrl = U . 'plugin/c2b_confirmation';
|
||||
$validationUrl = U . 'plugin/c2b_validation';
|
||||
$mpesa_c2b_api = $config['mpesa_c2b_api'] ?? null;
|
||||
$registerurl = match ($mpesa_c2b_env) {
|
||||
"live" => match ($mpesa_c2b_api) {
|
||||
"v1" => 'https://api.safaricom.co.ke/mpesa/c2b/v1/registerurl',
|
||||
"v2" => 'https://api.safaricom.co.ke/mpesa/c2b/v2/registerurl',
|
||||
},
|
||||
"sandbox" => 'https://sandbox.safaricom.co.ke/mpesa/c2b/v1/registerurl',
|
||||
};
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, $registerurl);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type:application/json',
|
||||
"Authorization:Bearer $access_token"
|
||||
]);
|
||||
$data = [
|
||||
'ShortCode' => $BusinessShortCode,
|
||||
'ResponseType' => 'Completed',
|
||||
'ConfirmationURL' => $confirmationUrl,
|
||||
'ValidationURL' => $validationUrl
|
||||
];
|
||||
$data_string = json_encode($data);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
|
||||
$curl_response = curl_exec($curl);
|
||||
$data = json_decode($curl_response);
|
||||
if (isset($data->ResponseCode) && $data->ResponseCode == 0) {
|
||||
try {
|
||||
$d = ORM::for_table('tbl_appconfig')->create();
|
||||
$d->setting = 'c2b_registered';
|
||||
$d->value = '1';
|
||||
$d->save();
|
||||
} catch (Exception $e) {
|
||||
_log("Failed to save M-Pesa C2B URL to database.\n\n" . $e->getMessage());
|
||||
sendTelegram("Failed to save M-Pesa C2B URL to database.\n\n" . $e->getMessage());
|
||||
}
|
||||
sendTelegram("M-Pesa C2B URL registered successfully");
|
||||
r2(U . 'plugin/c2b_settings', 's', "M-Pesa C2B URL registered successfully");
|
||||
} else {
|
||||
$errorMessage = $data->errorMessage;
|
||||
sendTelegram("Resister M-Pesa C2B URL Failed\n\n" . json_encode($curl_response, JSON_PRETTY_PRINT));
|
||||
r2(U . 'plugin/c2b_settings', 'e', "Failed to register M-Pesa C2B URL Error $errorMessage");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function c2b_webhook_log($data)
|
||||
{
|
||||
$logFile = 'pages/mpesa-webhook.html';
|
||||
$logEntry = date('Y-m-d H:i:s') . "<pre>" . htmlspecialchars($data, ENT_QUOTES, 'UTF-8') . "</pre>\n";
|
||||
|
||||
if (file_put_contents($logFile, $logEntry, FILE_APPEND) === false) {
|
||||
sendTelegram("Failed to write to log file: $logFile");
|
||||
}
|
||||
}
|
||||
|
||||
function c2b_isValidSafaricomIP($ip)
|
||||
{
|
||||
$config = c2b_config();
|
||||
$safaricomIPs = [
|
||||
'196.201.214.0/24',
|
||||
'196.201.213.0/24',
|
||||
'196.201.212.0/24',
|
||||
'172.69.79.0/24',
|
||||
'172.69.0.0/24',
|
||||
'0.0.0.0/0',
|
||||
];
|
||||
if ($config['mpesa_c2b_env'] == 'sandbox') {
|
||||
$safaricomIPs[] = '::1';
|
||||
}
|
||||
|
||||
foreach ($safaricomIPs as $range) {
|
||||
if (c2b_ipInRange($ip, $range)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function c2b_ipInRange($ip, $range)
|
||||
{
|
||||
list($subnet, $bits) = explode('/', $range);
|
||||
$ip = ip2long($ip);
|
||||
$subnet = ip2long($subnet);
|
||||
$mask = -1 << (32 - $bits);
|
||||
$subnet &= $mask;
|
||||
return ($ip & $mask) == $subnet;
|
||||
}
|
||||
|
||||
function c2b_confirmation()
|
||||
{
|
||||
|
||||
global $config;
|
||||
header("Content-Type: application/json");
|
||||
|
||||
$clientIP = $_SERVER['REMOTE_ADDR'];
|
||||
|
||||
if (!c2b_isValidSafaricomIP($clientIP)) {
|
||||
c2b_logAndNotify("Unauthorized request from IP: {$clientIP}");
|
||||
http_response_code(403);
|
||||
echo json_encode(["ResultCode" => 1, "ResultDesc" => "Unauthorized"]);
|
||||
return;
|
||||
}
|
||||
|
||||
$mpesaResponse = file_get_contents('php://input');
|
||||
if ($mpesaResponse === false) {
|
||||
c2b_logAndNotify("Failed to get input stream.");
|
||||
return;
|
||||
}
|
||||
|
||||
c2b_webhook_log('Received webhook request');
|
||||
c2b_webhook_log($mpesaResponse);
|
||||
|
||||
$content = json_decode($mpesaResponse);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
c2b_logAndNotify("Failed to decode JSON response: " . json_last_error_msg());
|
||||
return;
|
||||
}
|
||||
c2b_webhook_log('Decoded JSON data successfully');
|
||||
|
||||
if (!class_exists('Package')) {
|
||||
c2b_logAndNotify("Error: Package class does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($config['mpesa_c2b_bill_ref'])) {
|
||||
switch ($config['mpesa_c2b_bill_ref']) {
|
||||
case 'phone':
|
||||
$customer = ORM::for_table('tbl_customers')
|
||||
->where('phonenumber', $content->BillRefNumber)
|
||||
->find_one();
|
||||
break;
|
||||
|
||||
case 'username':
|
||||
$customer = ORM::for_table('tbl_customers')
|
||||
->where('username', $content->BillRefNumber)
|
||||
->find_one();
|
||||
break;
|
||||
|
||||
case 'id':
|
||||
$customer = ORM::for_table('tbl_customers')
|
||||
->where('id', $content->BillRefNumber)
|
||||
->find_one();
|
||||
break;
|
||||
|
||||
default:
|
||||
$customer = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$customer) {
|
||||
sendTelegram("Validation failed: No account found for BillRefNumber: $content->BillRefNumber");
|
||||
_log("Validation failed: No account found for BillRefNumber: $content->BillRefNumber");
|
||||
echo json_encode(["ResultCode" => "C2B00012", "ResultDesc" => "Invalid Account Number"]);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
_log("Configuration error: mpesa_c2b_bill_ref not set.");
|
||||
sendTelegram("Configuration error: mpesa_c2b_bill_ref not set.");
|
||||
}
|
||||
|
||||
|
||||
$bills = c2b_billing($customer->id);
|
||||
if (!$bills) {
|
||||
c2b_logAndNotify("No matching bill found for BillRefNumber: {$content->BillRefNumber}");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($bills as $bill) {
|
||||
c2b_handleBillPayment($content, $customer, $bill);
|
||||
}
|
||||
|
||||
echo json_encode(["ResultCode" => 0, "ResultDesc" => "Accepted"]);
|
||||
}
|
||||
|
||||
|
||||
function c2b_handleBillPayment($content, $customer, $bill)
|
||||
{
|
||||
$amountToPay = $bill['price'];
|
||||
$amountPaid = $content->TransAmount;
|
||||
$channel_mode = "Mpesa C2B - {$content->TransID}";
|
||||
$customerBalance = $customer->balance;
|
||||
$currentBalance = $customerBalance + $amountPaid;
|
||||
$customerID = $customer->id;
|
||||
|
||||
try {
|
||||
$transaction = c2b_storeTransaction($content, $bill['namebp'], $amountToPay, $customerID);
|
||||
} catch (Exception $e) {
|
||||
c2b_handleException("Failed to save transaction", $e);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($currentBalance >= $amountToPay) {
|
||||
$excessAmount = $currentBalance - $amountToPay;
|
||||
try {
|
||||
$result = Package::rechargeUser($customer->id, $bill['routers'], $bill['plan_id'], 'mpesa', $channel_mode);
|
||||
if (!$result) {
|
||||
c2b_logAndNotify("Mpesa Payment Successful, but failed to activate the package for customer {$customer->username}.");
|
||||
} else {
|
||||
if ($excessAmount > 0) {
|
||||
$customer->balance = $excessAmount;
|
||||
$customer->save();
|
||||
} else {
|
||||
$customer->balance = 0;
|
||||
$customer->save();
|
||||
}
|
||||
c2b_sendPaymentSuccessMessage($customer, $amountPaid, $bill['namebp']);
|
||||
$transaction->transactionStatus = 'Completed';
|
||||
$transaction->save();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
c2b_handleException("Error during package activation", $e);
|
||||
}
|
||||
} else {
|
||||
c2b_updateCustomerBalance($customer, $currentBalance, $amountPaid);
|
||||
$neededToActivate = $amountToPay - $currentBalance;
|
||||
c2b_sendBalanceUpdateMessage($customer, $amountPaid, $currentBalance, $neededToActivate);
|
||||
$transaction->transactionStatus = 'Completed';
|
||||
$transaction->save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function c2b_storeTransaction($content, $packageName, $packagePrice, $customerID)
|
||||
{
|
||||
ORM::get_db()->beginTransaction();
|
||||
try {
|
||||
$transaction = ORM::for_table('tbl_mpesa_transactions')
|
||||
->where('TransID', $content->TransID)
|
||||
->find_one();
|
||||
|
||||
if ($transaction) {
|
||||
// Update existing transaction
|
||||
$transaction->TransactionType = $content->TransactionType;
|
||||
$transaction->TransTime = $content->TransTime;
|
||||
$transaction->TransAmount = $content->TransAmount;
|
||||
$transaction->BusinessShortCode = $content->BusinessShortCode;
|
||||
$transaction->BillRefNumber = $content->BillRefNumber;
|
||||
$transaction->OrgAccountBalance = $content->OrgAccountBalance;
|
||||
$transaction->MSISDN = $content->MSISDN;
|
||||
$transaction->FirstName = $content->FirstName;
|
||||
$transaction->PackageName = $packageName;
|
||||
$transaction->PackagePrice = $packagePrice;
|
||||
$transaction->customerID = $customerID;
|
||||
$transaction->transactionStatus = 'Pending';
|
||||
} else {
|
||||
// Create new transaction
|
||||
$transaction = ORM::for_table('tbl_mpesa_transactions')->create();
|
||||
$transaction->TransID = $content->TransID;
|
||||
$transaction->TransactionType = $content->TransactionType;
|
||||
$transaction->TransTime = $content->TransTime;
|
||||
$transaction->TransAmount = $content->TransAmount;
|
||||
$transaction->BusinessShortCode = $content->BusinessShortCode;
|
||||
$transaction->BillRefNumber = $content->BillRefNumber;
|
||||
$transaction->OrgAccountBalance = $content->OrgAccountBalance;
|
||||
$transaction->MSISDN = $content->MSISDN;
|
||||
$transaction->FirstName = $content->FirstName;
|
||||
$transaction->PackageName = $packageName;
|
||||
$transaction->PackagePrice = $packagePrice;
|
||||
$transaction->customerID = $customerID;
|
||||
$transaction->transactionStatus = 'Pending';
|
||||
}
|
||||
$transaction->save();
|
||||
ORM::get_db()->commit();
|
||||
return $transaction;
|
||||
} catch (Exception $e) {
|
||||
ORM::get_db()->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
function c2b_logAndNotify($message)
|
||||
{
|
||||
_log($message);
|
||||
sendTelegram($message);
|
||||
}
|
||||
|
||||
function c2b_handleException($message, $e)
|
||||
{
|
||||
$fullMessage = "$message: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine();
|
||||
c2b_logAndNotify($fullMessage);
|
||||
}
|
||||
|
||||
function c2b_updateCustomerBalance($customer, $newBalance, $amountPaid)
|
||||
{
|
||||
try {
|
||||
$customer->balance = $newBalance;
|
||||
$customer->save();
|
||||
c2b_logAndNotify("Payment of KES {$amountPaid} has been added to the balance of customer {$customer->username}.");
|
||||
} catch (Exception $e) {
|
||||
c2b_handleException("Failed to update customer balance", $e);
|
||||
}
|
||||
}
|
||||
|
||||
function c2b_sendPaymentSuccessMessage($customer, $amountPaid, $packageName)
|
||||
{
|
||||
$config = c2b_config();
|
||||
$message = "Dear {$customer->fullname}, your payment of KES {$amountPaid} has been received and your plan {$packageName} has been successfully activated. Thank you for choosing {$config['CompanyName']}.";
|
||||
c2b_sendNotification($customer, $message);
|
||||
}
|
||||
|
||||
function c2b_sendBalanceUpdateMessage($customer, $amountPaid, $currentBalance, $neededToActivate)
|
||||
{
|
||||
$config = c2b_config();
|
||||
$message = "Dear {$customer->fullname}, your payment of KES {$amountPaid} has been received and added to your account balance. Your current balance is KES {$currentBalance}.";
|
||||
if ($neededToActivate > 0) {
|
||||
$message .= " To activate your package, you need to add KES {$neededToActivate} more to your account.";
|
||||
} else {
|
||||
$message .= " Your current balance is sufficient to activate your package.";
|
||||
}
|
||||
$message .= "\n" . $config['CompanyName'];
|
||||
c2b_sendNotification($customer, $message);
|
||||
}
|
||||
|
||||
function c2b_sendNotification($customer, $message)
|
||||
{
|
||||
try {
|
||||
Message::sendSMS($customer->phonenumber, $message);
|
||||
Message::sendWhatsapp($customer->phonenumber, $message);
|
||||
} catch (Exception $e) {
|
||||
c2b_handleException("Failed to send SMS/WhatsApp message", $e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function c2b_validation()
|
||||
{
|
||||
header("Content-Type: application/json");
|
||||
$mpesaResponse = file_get_contents('php://input');
|
||||
|
||||
$config = c2b_config();
|
||||
$content = json_decode($mpesaResponse);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
sendTelegram("Failed to decode JSON response.");
|
||||
_log("Failed to decode JSON response.");
|
||||
echo json_encode(["ResultCode" => "C2B00016", "ResultDesc" => "Invalid JSON format"]);
|
||||
return;
|
||||
}
|
||||
|
||||
$BillRefNumber = $content->BillRefNumber;
|
||||
$TransAmount = $content->TransAmount;
|
||||
|
||||
if (isset($config['mpesa_c2b_bill_ref'])) {
|
||||
switch ($config['mpesa_c2b_bill_ref']) {
|
||||
case 'phone':
|
||||
$customer = ORM::for_table('tbl_customers')
|
||||
->where('phonenumber', $content->BillRefNumber)
|
||||
->find_one();
|
||||
break;
|
||||
|
||||
case 'username':
|
||||
$customer = ORM::for_table('tbl_customers')
|
||||
->where('username', $content->BillRefNumber)
|
||||
->find_one();
|
||||
break;
|
||||
|
||||
case 'id':
|
||||
$customer = ORM::for_table('tbl_customers')
|
||||
->where('id', $content->BillRefNumber)
|
||||
->find_one();
|
||||
break;
|
||||
|
||||
default:
|
||||
$customer = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$customer) {
|
||||
sendTelegram("Validation failed: No account found for BillRefNumber: $BillRefNumber");
|
||||
_log("Validation failed: No account found for BillRefNumber: $BillRefNumber");
|
||||
echo json_encode(["ResultCode" => "C2B00012", "ResultDesc" => "Invalid Account Number"]);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
_log("Configuration error: mpesa_c2b_bill_ref not set.");
|
||||
sendTelegram("Configuration error: mpesa_c2b_bill_ref not set.");
|
||||
}
|
||||
|
||||
|
||||
$bills = c2b_billing($customer->id);
|
||||
|
||||
if (!$bills) {
|
||||
sendTelegram("Validation failed: No bill found for BillRefNumber: $BillRefNumber");
|
||||
_log("Validation failed: No bill found for BillRefNumber: $BillRefNumber");
|
||||
echo json_encode(["ResultCode" => "C2B00012", "ResultDesc" => "Invalid Bill Reference"]);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($bills as $bill) {
|
||||
}
|
||||
|
||||
$billAmount = $bill['price'];
|
||||
if (!$config['mpesa_c2b_low_fee']) {
|
||||
if ($TransAmount < $billAmount) {
|
||||
sendTelegram("Validation failed: Insufficient amount. Transferred: $TransAmount, Required: $billAmount");
|
||||
_log("Validation failed: Insufficient amount. Transferred: $TransAmount, Required: $billAmount");
|
||||
echo json_encode(["ResultCode" => "C2B00013", "ResultDesc" => "Invalid or Insufficient Amount"]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sendTelegram("Validation successful for BillRefNumber: $BillRefNumber with amount: $TransAmount");
|
||||
_log("Validation successful for BillRefNumber: $BillRefNumber with amount: $TransAmount");
|
||||
echo json_encode(["ResultCode" => 0, "ResultDesc" => "Accepted"]);
|
||||
}
|
||||
|
||||
function c2b_billing($id)
|
||||
{
|
||||
$d = ORM::for_table('tbl_user_recharges')
|
||||
->selects([
|
||||
'customer_id',
|
||||
'username',
|
||||
'plan_id',
|
||||
'namebp',
|
||||
'recharged_on',
|
||||
'recharged_time',
|
||||
'expiration',
|
||||
'time',
|
||||
'status',
|
||||
'method',
|
||||
'plan_type',
|
||||
['tbl_user_recharges.routers', 'routers'],
|
||||
['tbl_user_recharges.type', 'type'],
|
||||
'admin_id',
|
||||
'prepaid'
|
||||
])
|
||||
->select('tbl_plans.price', 'price')
|
||||
->left_outer_join('tbl_plans', array('tbl_plans.id', '=', 'tbl_user_recharges.plan_id'))
|
||||
->where('customer_id', $id)
|
||||
->find_many();
|
||||
return $d;
|
||||
}
|
||||
|
||||
function c2b_config()
|
||||
{
|
||||
$result = ORM::for_table('tbl_appconfig')->find_many();
|
||||
foreach ($result as $value) {
|
||||
$config[$value['setting']] = $value['value'];
|
||||
}
|
||||
return $config;
|
||||
}
|
||||
48
system/plugin/clear_cache.php
Normal file
48
system/plugin/clear_cache.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
register_menu("Clear System Cache", true, "clear_cache", 'SETTINGS', '');
|
||||
|
||||
function clear_cache()
|
||||
{
|
||||
global $ui;
|
||||
_admin();
|
||||
$ui->assign('_title', 'Clear Cache');
|
||||
$ui->assign('_system_menu', 'settings');
|
||||
$admin = Admin::_info();
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
// Check user type for access
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
exit;
|
||||
}
|
||||
|
||||
$compiledCacheDir = 'ui/compiled';
|
||||
$templateCacheDir = 'system/cache';
|
||||
|
||||
try {
|
||||
// Clear the compiled cache
|
||||
$files = scandir($compiledCacheDir);
|
||||
foreach ($files as $file) {
|
||||
if ($file !== '.' && $file !== '..' && is_file($compiledCacheDir . '/' . $file)) {
|
||||
unlink($compiledCacheDir . '/' . $file);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the template cache
|
||||
$templateCacheFiles = glob($templateCacheDir . '/*.{json,temp}', GLOB_BRACE);
|
||||
foreach ($templateCacheFiles as $file) {
|
||||
if (is_file($file)) {
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
// Cache cleared successfully
|
||||
_log('[' . ($admin['fullname'] ?? 'Unknown Admin') . ']: ' . Lang::T(' Cleared the system cache '), $admin['user_type']);
|
||||
r2(U . 'dashboard', 's', Lang::T("Cache cleared successfully!"));
|
||||
} catch (Exception $e) {
|
||||
// Error occurred while clearing the cache
|
||||
_log('[' . ($admin['fullname'] ?? 'Unknown Admin') . ']: ' . Lang::T(' Error occurred while clearing the cache: ' . $e->getMessage()), $admin['user_type']);
|
||||
r2(U . 'dashboard', 'e', Lang::T("Error occurred while clearing the cache: ") . $e->getMessage());
|
||||
}
|
||||
}
|
||||
907
system/plugin/download.php
Normal file
907
system/plugin/download.php
Normal file
@@ -0,0 +1,907 @@
|
||||
<?php
|
||||
include '../../config.php';
|
||||
$mysqli = new mysqli($db_host, $db_user, $db_password, $db_name);
|
||||
|
||||
if ($mysqli->connect_error) {
|
||||
die("Connection failed: " . $mysqli->connect_error);
|
||||
}
|
||||
|
||||
// Function to get a setting value
|
||||
function getSettingValue($mysqli, $setting) {
|
||||
$query = $mysqli->prepare("SELECT value FROM tbl_appconfig WHERE setting = ?");
|
||||
$query->bind_param("s", $setting);
|
||||
$query->execute();
|
||||
$result = $query->get_result();
|
||||
if ($row = $result->fetch_assoc()) {
|
||||
return $row['value'];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// Fetch hotspot title and description from tbl_appconfig
|
||||
$hotspotTitle = getSettingValue($mysqli, 'hotspot_title');
|
||||
$description = getSettingValue($mysqli, 'description');
|
||||
$phone = getSettingValue($mysqli, 'phone');
|
||||
$company = getSettingValue($mysqli, 'CompanyName');
|
||||
|
||||
// Fetch router name and router ID from tbl_appconfig
|
||||
$routerName = getSettingValue($mysqli, 'router_name');
|
||||
$routerId = getSettingValue($mysqli, 'router_id');
|
||||
|
||||
// Fetch available plans
|
||||
|
||||
$planQuery = "SELECT id, type, name_plan, price, validity, validity_unit FROM tbl_plans WHERE routers = ? AND type = 'Hotspot'";
|
||||
$planStmt = $mysqli->prepare($planQuery);
|
||||
$planStmt->bind_param("s", $routerName);
|
||||
$planStmt->execute();
|
||||
$planResult = $planStmt->get_result();
|
||||
|
||||
|
||||
$htmlContent = "";
|
||||
$htmlContent .= "<!DOCTYPE html>\n";
|
||||
$htmlContent .= "<html lang=\"en\">\n";
|
||||
$htmlContent .= "<head>\n";
|
||||
$htmlContent .= " <meta charset=\"UTF-8\">\n";
|
||||
$htmlContent .= " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n";
|
||||
$htmlContent .= " <title>$company</title>\n";
|
||||
$htmlContent .= " <script src=\"https://cdn.tailwindcss.com\"></script>\n";
|
||||
$htmlContent .= " <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css\">\n";
|
||||
$htmlContent .= " <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/glider-js@1.7.7/glider.min.css\" />\n";
|
||||
$htmlContent .= " <script src=\"https://cdn.jsdelivr.net/npm/glider-js@1.7.7/glider.min.js\"></script>\n";
|
||||
$htmlContent .= " <link rel=\"preconnect\" href=\"https://cdn.jsdelivr.net\">\n";
|
||||
$htmlContent .= " <link rel=\"preconnect\" href=\"https://cdnjs.cloudflare.com\" crossorigin>\n";
|
||||
$htmlContent .= " <link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap\">\n";
|
||||
$htmlContent .= " <style>\n";
|
||||
$htmlContent .= " :root {\n";
|
||||
$htmlContent .= " --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n";
|
||||
$htmlContent .= " --secondary-gradient: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);\n";
|
||||
$htmlContent .= " --success-gradient: linear-gradient(135deg, #10b981 0%, #059669 100%);\n";
|
||||
$htmlContent .= " --card-bg: rgba(255, 255, 255, 0.95);\n";
|
||||
$htmlContent .= " --glass-bg: rgba(255, 255, 255, 0.1);\n";
|
||||
$htmlContent .= " --backdrop-blur: blur(10px);\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " .glass-card {\n";
|
||||
$htmlContent .= " background: var(--card-bg);\n";
|
||||
$htmlContent .= " backdrop-filter: var(--backdrop-blur);\n";
|
||||
$htmlContent .= " border: 1px solid rgba(255, 255, 255, 0.2);\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " .gradient-text {\n";
|
||||
$htmlContent .= " background: var(--primary-gradient);\n";
|
||||
$htmlContent .= " -webkit-background-clip: text;\n";
|
||||
$htmlContent .= " -webkit-text-fill-color: transparent;\n";
|
||||
$htmlContent .= " background-clip: text;\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " .floating-label {\n";
|
||||
$htmlContent .= " position: relative;\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " .floating-label input:focus + label,\n";
|
||||
$htmlContent .= " .floating-label input:not(:placeholder-shown) + label {\n";
|
||||
$htmlContent .= " transform: translateY(-1.5rem) scale(0.85);\n";
|
||||
$htmlContent .= " color: #1e40af;\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " .floating-label label {\n";
|
||||
$htmlContent .= " position: absolute;\n";
|
||||
$htmlContent .= " left: 0.75rem;\n";
|
||||
$htmlContent .= " top: 0.75rem;\n";
|
||||
$htmlContent .= " transition: all 0.2s ease-in-out;\n";
|
||||
$htmlContent .= " pointer-events: none;\n";
|
||||
$htmlContent .= " color: #6b7280;\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " .card-hover {\n";
|
||||
$htmlContent .= " transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " .card-hover:hover {\n";
|
||||
$htmlContent .= " transform: translateY(-4px);\n";
|
||||
$htmlContent .= " box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " .btn-modern {\n";
|
||||
$htmlContent .= " background: var(--primary-gradient);\n";
|
||||
$htmlContent .= " transition: all 0.3s ease;\n";
|
||||
$htmlContent .= " position: relative;\n";
|
||||
$htmlContent .= " overflow: hidden;\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " .btn-modern::before {\n";
|
||||
$htmlContent .= " content: '';\n";
|
||||
$htmlContent .= " position: absolute;\n";
|
||||
$htmlContent .= " top: 0;\n";
|
||||
$htmlContent .= " left: -100%;\n";
|
||||
$htmlContent .= " width: 100%;\n";
|
||||
$htmlContent .= " height: 100%;\n";
|
||||
$htmlContent .= " background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);\n";
|
||||
$htmlContent .= " transition: left 0.5s;\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " .btn-modern:hover::before {\n";
|
||||
$htmlContent .= " left: 100%;\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " .btn-modern:hover {\n";
|
||||
$htmlContent .= " transform: translateY(-2px);\n";
|
||||
$htmlContent .= " box-shadow: 0 10px 20px rgba(30, 64, 175, 0.4);\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " .pulse-animation {\n";
|
||||
$htmlContent .= " animation: pulse 2s infinite;\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " @keyframes pulse {\n";
|
||||
$htmlContent .= " 0%, 100% { opacity: 1; }\n";
|
||||
$htmlContent .= " 50% { opacity: 0.7; }\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " </style>\n";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$htmlContent .= "</head>\n";
|
||||
$htmlContent .= "<body class=\"font-sans antialiased text-gray-900 bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 min-h-screen font-inter\">\n";
|
||||
$htmlContent .= " <!-- Hero Section -->\n";
|
||||
$htmlContent .= " <div class=\"relative overflow-hidden\" style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\">\n";
|
||||
$htmlContent .= " <!-- Background Pattern -->\n";
|
||||
$htmlContent .= " <div class=\"absolute inset-0 bg-gradient-to-br from-slate-600/20 via-gray-600/20 to-slate-700/20\"></div>\n";
|
||||
$htmlContent .= " <div class=\"absolute inset-0 bg-[url('data:image/svg+xml,%3Csvg width=\"60\" height=\"60\" viewBox=\"0 0 60 60\" xmlns=\"http://www.w3.org/2000/svg\"%3E%3Cg fill=\"none\" fill-rule=\"evenodd\"%3E%3Cg fill=\"%23ffffff\" fill-opacity=\"0.05\"%3E%3Ccircle cx=\"30\" cy=\"30\" r=\"2\"/%3E%3C/g%3E%3C/g%3E%3C/svg%3E')] opacity-30\"></div>\n";
|
||||
$htmlContent .= " \n";
|
||||
$htmlContent .= " <div class=\"relative mx-auto max-w-screen-2xl px-4 py-4 md:px-6\">\n";
|
||||
$htmlContent .= " <div class=\"glass-card relative mx-auto max-w-2xl rounded-2xl p-4 shadow-xl backdrop-blur-xl\">\n";
|
||||
$htmlContent .= " <div class=\"text-center space-y-3\">\n";
|
||||
$htmlContent .= " <div class=\"space-y-1\">\n";
|
||||
$htmlContent .= " <h1 class=\"text-2xl md:text-3xl font-black text-gray-800 mb-1\">$company</h1>\n";
|
||||
$htmlContent .= " <div class=\"w-16 h-0.5 bg-gray-600 mx-auto rounded-full\"></div>\n";
|
||||
$htmlContent .= " <p class=\"text-lg font-semibold text-gray-700\">HOTSPOT LOGIN</p>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " \n";
|
||||
$htmlContent .= " <div class=\"bg-white/90 rounded-lg p-2 mb-1 shadow-sm\">\n";
|
||||
$htmlContent .= " <p class=\"text-xs text-gray-700 italic leading-relaxed\">\n";
|
||||
$htmlContent .= " Empowering businesses with reliable WiFi solutions and seamless connectivity across Kenya.\n";
|
||||
$htmlContent .= " </p>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " \n";
|
||||
$htmlContent .= " <div class=\"bg-white/90 rounded-xl p-3 backdrop-blur-sm shadow-sm\">\n";
|
||||
$htmlContent .= " <h3 class=\"text-sm font-bold text-gray-800 mb-2\">How to Connect</h3>\n";
|
||||
$htmlContent .= " <div class=\"grid grid-cols-2 gap-2 text-gray-700\">\n";
|
||||
$htmlContent .= " <div class=\"flex items-center space-x-2\">\n";
|
||||
$htmlContent .= " <span class=\"flex-shrink-0 w-5 h-5 bg-blue-500 text-white rounded-full flex items-center justify-center text-xs font-bold\">1</span>\n";
|
||||
$htmlContent .= " <span class=\"text-xs\">Click on your preferred package</span>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <div class=\"flex items-center space-x-2\">\n";
|
||||
$htmlContent .= " <span class=\"flex-shrink-0 w-5 h-5 bg-blue-500 text-white rounded-full flex items-center justify-center text-xs font-bold\">2</span>\n";
|
||||
$htmlContent .= " <span class=\"text-xs\">Enter Mpesa No.</span>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <div class=\"flex items-center space-x-2\">\n";
|
||||
$htmlContent .= " <span class=\"flex-shrink-0 w-5 h-5 bg-blue-500 text-white rounded-full flex items-center justify-center text-xs font-bold\">3</span>\n";
|
||||
$htmlContent .= " <span class=\"text-xs\">Enter pin</span>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <div class=\"flex items-center space-x-2\">\n";
|
||||
$htmlContent .= " <span class=\"flex-shrink-0 w-5 h-5 bg-blue-500 text-white rounded-full flex items-center justify-center text-xs font-bold\">4</span>\n";
|
||||
$htmlContent .= " <span class=\"text-xs\">Wait to be connected</span>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " \n";
|
||||
$htmlContent .= " <div class=\"bg-white/90 rounded-lg p-2 border border-gray-200/50 shadow-sm\">\n";
|
||||
$htmlContent .= " <p class=\"text-sm font-medium text-gray-700\">\n";
|
||||
$htmlContent .= " <i class=\"fas fa-phone-alt text-blue-500 mr-2\"></i>\n";
|
||||
$htmlContent .= " For any enquiries contact: <a href=\"tel:$phone\" class=\"font-bold text-blue-600 hover:text-blue-800 transition-colors duration-200\">$phone</a>\n";
|
||||
$htmlContent .= " </p>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$htmlContent .= " <!-- Voucher Section -->\n";
|
||||
$htmlContent .= " <div class=\"py-3 sm:py-4 lg:py-5\">\n";
|
||||
$htmlContent .= " <div class=\"mx-auto max-w-screen-2xl px-4 md:px-6\">\n";
|
||||
$htmlContent .= " <div class=\"mx-auto max-w-md\">\n";
|
||||
$htmlContent .= " <div class=\"glass-card rounded-xl p-4 shadow-lg backdrop-blur-xl\">\n";
|
||||
$htmlContent .= " <div class=\"text-center space-y-2\">\n";
|
||||
$htmlContent .= " <div class=\"w-12 h-12 bg-blue-500 rounded-full flex items-center justify-center mx-auto\">\n";
|
||||
$htmlContent .= " <i class=\"fas fa-ticket-alt text-white text-lg\"></i>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <h3 class=\"text-lg font-bold text-gray-800\">Have a Voucher Code?</h3>\n";
|
||||
$htmlContent .= " <p class=\"text-sm text-gray-600\">Redeem your voucher for instant access</p>\n";
|
||||
$htmlContent .= " <button type=\"button\" class=\"w-full flex items-center justify-center gap-3 rounded-xl bg-gradient-to-r from-purple-500 to-pink-500 px-8 py-4 text-center text-sm font-semibold text-white shadow-lg hover:shadow-xl transform hover:-translate-y-1 transition-all duration-200 focus:outline-none focus:ring-4 focus:ring-purple-300 md:text-base\" onclick=\"redeemVoucher()\">\n";
|
||||
$htmlContent .= " <i class=\"fas fa-gift text-lg\"></i>\n";
|
||||
$htmlContent .= " Redeem Voucher\n";
|
||||
$htmlContent .= " </button>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$htmlContent .= " <!-- Packages Section -->\n";
|
||||
$htmlContent .= " <div class=\"py-3 sm:py-4 lg:py-5\">\n";
|
||||
$htmlContent .= " <div class=\"mx-auto max-w-screen-2xl px-4 md:px-6\">\n";
|
||||
$htmlContent .= " <div class=\"text-center mb-4\">\n";
|
||||
$htmlContent .= " <h2 class=\"text-xl font-bold text-gray-800 mb-1\">Choose Your Package</h2>\n";
|
||||
$htmlContent .= " <p class=\"text-sm text-gray-600\">Select the perfect plan for your internet needs</p>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <div class=\"mx-auto max-w-6xl grid grid-cols-2 sm:grid-cols-2 lg:grid-cols-4 xl:grid-cols-4 gap-3\" id=\"cards-container\">\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
|
||||
$htmlContent .= " <!-- Reconnection & Login Section -->\n";
|
||||
$htmlContent .= " <div class=\"py-3 sm:py-4 lg:py-5\">\n";
|
||||
$htmlContent .= " <div class=\"mx-auto max-w-screen-2xl px-4 md:px-6\">\n";
|
||||
$htmlContent .= " <div class=\"max-w-2xl mx-auto space-y-4\">\n";
|
||||
$htmlContent .= " <!-- Reconnection Card -->\n";
|
||||
$htmlContent .= " <div class=\"glass-card rounded-xl p-4 shadow-lg backdrop-blur-xl\">\n";
|
||||
$htmlContent .= " <div class=\"text-center mb-3\">\n";
|
||||
$htmlContent .= " <div class=\"w-10 h-10 bg-blue-500 rounded-full flex items-center justify-center mx-auto mb-2\">\n";
|
||||
$htmlContent .= " <i class=\"fas fa-redo text-white text-sm\"></i>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <h3 class=\"text-lg font-bold text-gray-800 mb-1\">Reconnect with M-Pesa Code</h3>\n";
|
||||
$htmlContent .= " <p class=\"text-sm text-gray-600\">Enter your M-Pesa transaction code to reconnect</p>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <div class=\"floating-label mb-3\">\n";
|
||||
$htmlContent .= " <input type=\"text\" id=\"mpesaCodeInput\" name=\"mpesa_code\" placeholder=\"\" class=\"w-full rounded-lg border-2 border-gray-200 bg-white/80 px-3 py-2 text-gray-800 outline-none ring-2 ring-transparent transition-all duration-200 focus:border-blue-500 focus:ring-blue-100 focus:bg-white text-sm\" />\n";
|
||||
$htmlContent .= " <label for=\"mpesaCodeInput\" class=\"text-gray-500 font-medium text-sm\">Mpesa Code or Mpesa Message</label>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <button id=\"reconnectBtn\" class=\"btn-modern w-full flex items-center justify-center gap-2 rounded-lg px-4 py-2 text-white font-semibold transition-all duration-300 text-sm\">\n";
|
||||
$htmlContent .= " <i class=\"fas fa-wifi text-lg\"></i>\n";
|
||||
$htmlContent .= " Reconnect Now\n";
|
||||
$htmlContent .= " </button>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " \n";
|
||||
$htmlContent .= " <!-- Login Card -->\n";
|
||||
$htmlContent .= " <div class=\"glass-card rounded-xl p-4 shadow-lg backdrop-blur-xl\">\n";
|
||||
$htmlContent .= " <div class=\"text-center mb-6\">\n";
|
||||
$htmlContent .= " <div class=\"w-16 h-16 bg-green-500 rounded-full flex items-center justify-center mx-auto mb-4\">\n";
|
||||
$htmlContent .= " <i class=\"fas fa-user-check text-white text-2xl\"></i>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <h3 class=\"text-2xl font-bold text-gray-800 mb-2\">Already Have an Active Package?</h3>\n";
|
||||
$htmlContent .= " <p class=\"text-gray-600\">Login with your account details</p>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <form id=\"loginForm\" class=\"space-y-6\" name=\"login\" action=\"$(link-login-only)\" method=\"post\" $(if chap-id)onSubmit=\"return doLogin()\" $(endif)>\n";
|
||||
$htmlContent .= " <input type=\"hidden\" name=\"dst\" value=\"$(link-orig)\" />\n";
|
||||
$htmlContent .= " <input type=\"hidden\" name=\"popup\" value=\"true\" />\n";
|
||||
$htmlContent .= " <div class=\"floating-label\">\n";
|
||||
$htmlContent .= " <input id=\"usernameInput\" name=\"username\" type=\"text\" value=\"\" placeholder=\"\" class=\"w-full rounded-xl border-2 border-gray-200 bg-white/80 px-4 py-4 text-gray-800 outline-none ring-2 ring-transparent transition-all duration-200 focus:border-green-500 focus:ring-green-100 focus:bg-white\" />\n";
|
||||
$htmlContent .= " <label for=\"username\" class=\"text-gray-500 font-medium\">Username or Account Number</label>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <input type=\"hidden\" name=\"password\" value=\"1234\">\n";
|
||||
$htmlContent .= " <button id=\"submitBtn\" class=\"btn-modern w-full flex items-center justify-center gap-3 rounded-xl px-6 py-4 text-white font-semibold transition-all duration-300\" type=\"button\" onclick=\"submitLogin()\">\n";
|
||||
$htmlContent .= " <i class=\"fas fa-sign-in-alt text-lg\"></i>\n";
|
||||
$htmlContent .= " Connect Now\n";
|
||||
$htmlContent .= " </button>\n";
|
||||
$htmlContent .= " </form>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <!-- Footer -->\n";
|
||||
$htmlContent .= " <div class=\"py-4 sm:py-6\">\n";
|
||||
$htmlContent .= " <div class=\"mx-auto max-w-screen-2xl px-4 md:px-6\">\n";
|
||||
$htmlContent .= " <div class=\"glass-card rounded-xl p-4 text-center backdrop-blur-xl\">\n";
|
||||
$htmlContent .= " <div class=\"flex items-center justify-center space-x-2 mb-4\">\n";
|
||||
$htmlContent .= " <div class=\"w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center\">\n";
|
||||
$htmlContent .= " <i class=\"fas fa-wifi text-white text-sm\"></i>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <span class=\"text-lg font-bold text-gray-800\">Powered by NestICT</span>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <p class=\"text-sm text-gray-600 mb-4\">\n";
|
||||
$htmlContent .= " © " . date("Y") . " Billing System\n";
|
||||
$htmlContent .= " </p>\n";
|
||||
$htmlContent .= " <div class=\"flex flex-col sm:flex-row items-center justify-center space-y-2 sm:space-y-0 sm:space-x-6 mb-4\">\n";
|
||||
$htmlContent .= " <a href=\"tel:+254705042522\" class=\"inline-flex items-center text-blue-600 hover:text-blue-800 transition-colors duration-200\">\n";
|
||||
$htmlContent .= " <i class=\"fas fa-phone text-blue-500 mr-2\"></i>\n";
|
||||
$htmlContent .= " <span>+254705042522</span>\n";
|
||||
$htmlContent .= " </a>\n";
|
||||
$htmlContent .= " <a href=\"mailto:sales@nestict.net\" class=\"inline-flex items-center text-blue-600 hover:text-blue-800 transition-colors duration-200\">\n";
|
||||
$htmlContent .= " <i class=\"fas fa-envelope text-blue-500 mr-2\"></i>\n";
|
||||
$htmlContent .= " <span>sales@nestict.net</span>\n";
|
||||
$htmlContent .= " </a>\n";
|
||||
$htmlContent .= " <a href=\"https://wa.me/254705042522\" target=\"_blank\" class=\"inline-flex items-center text-blue-600 hover:text-blue-800 transition-colors duration-200\">\n";
|
||||
$htmlContent .= " <i class=\"fab fa-whatsapp text-blue-500 mr-2\"></i>\n";
|
||||
$htmlContent .= " <span>WhatsApp</span>\n";
|
||||
$htmlContent .= " </a>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <a href=\"https://www.nestict.africa/\" target=\"_blank\" class=\"inline-flex items-center text-blue-600 hover:text-blue-800 transition-colors duration-200\">\n";
|
||||
$htmlContent .= " <span class=\"mr-2\">Visit NestICT</span>\n";
|
||||
$htmlContent .= " <i class=\"fas fa-external-link-alt text-xs\"></i>\n";
|
||||
$htmlContent .= " </a>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= "</body>\n";
|
||||
|
||||
// Add the closing script section as well, if necessary
|
||||
$htmlContent .= "<script>\n";
|
||||
// Add any required JavaScript here
|
||||
$htmlContent .= "</script>\n";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$htmlContent .= "<script>\n";
|
||||
$htmlContent .= "function fetchData() {\n";
|
||||
$htmlContent .= " let domain = '" . APP_URL . "/';\n";
|
||||
$htmlContent .= " let siteUrl = domain + \"/index.php?_route=plugin/hotspot_plan\";\n";
|
||||
$htmlContent .= " let request = new XMLHttpRequest();\n";
|
||||
$htmlContent .= " const routerName = encodeURIComponent(\"$routerName\");\n";
|
||||
$htmlContent .= " const dataparams = `routername=\${routerName}`;\n";
|
||||
$htmlContent .= " request.open(\"POST\", siteUrl, true);\n";
|
||||
$htmlContent .= " request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');\n";
|
||||
$htmlContent .= " request.onload = () => {\n";
|
||||
$htmlContent .= " if (request.readyState === XMLHttpRequest.DONE) {\n";
|
||||
$htmlContent .= " if (request.status === 200) {\n";
|
||||
$htmlContent .= " let fetchedData = JSON.parse(request.responseText);\n";
|
||||
$htmlContent .= " populateCards(fetchedData);\n";
|
||||
$htmlContent .= " } else {\n";
|
||||
$htmlContent .= " console.log(`Error \${request.status}: \${request.statusText}`);\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " };\n";
|
||||
$htmlContent .= " request.onerror = () => {\n";
|
||||
$htmlContent .= " console.error(\"Network error\");\n";
|
||||
$htmlContent .= " };\n";
|
||||
$htmlContent .= " request.send(dataparams);\n";
|
||||
$htmlContent .= "}\n";
|
||||
|
||||
$htmlContent .= "function populateCards(data) {\n";
|
||||
$htmlContent .= " var cardsContainer = document.getElementById('cards-container');\n";
|
||||
$htmlContent .= " cardsContainer.innerHTML = ''; // Clear existing content\n";
|
||||
|
||||
$htmlContent .= " // Sort the plans by price in ascending order\n";
|
||||
$htmlContent .= " data.data.forEach(router => {\n";
|
||||
$htmlContent .= " // Sort hotspot plans by price\n";
|
||||
$htmlContent .= " router.plans_hotspot.sort((a, b) => parseFloat(a.price) - parseFloat(b.price));\n";
|
||||
|
||||
$htmlContent .= " router.plans_hotspot.forEach(item => {\n";
|
||||
$htmlContent .= " var cardDiv = document.createElement('div');\n";
|
||||
$htmlContent .= " cardDiv.className = 'glass-card card-hover rounded-2xl shadow-xl backdrop-blur-xl overflow-hidden flex flex-col mx-auto w-full max-w-xs group';\n";
|
||||
$htmlContent .= " cardDiv.innerHTML = `\n";
|
||||
$htmlContent .= " <div class=\"relative bg-gradient-to-r from-blue-500 to-blue-600 text-white p-3\">\n";
|
||||
$htmlContent .= " <div class=\"absolute top-3 right-3 w-3 h-3 bg-white/30 rounded-full\"></div>\n";
|
||||
$htmlContent .= " <h2 class=\"text-base font-bold text-center mb-2\" style=\"font-size: clamp(0.875rem, 2vw, 1.125rem); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\">\n";
|
||||
$htmlContent .= " \${item.planname}\n";
|
||||
$htmlContent .= " </h2>\n";
|
||||
$htmlContent .= " <div class=\"w-12 h-0.5 bg-white/50 rounded-full mx-auto\"></div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <div class=\"p-3 flex-grow flex flex-col justify-between\">\n";
|
||||
$htmlContent .= " <div class=\"text-center mb-3\">\n";
|
||||
$htmlContent .= " <div class=\"mb-2\">\n";
|
||||
$htmlContent .= " <span class=\"text-2xl font-black text-gray-800\">\${item.currency}</span>\n";
|
||||
$htmlContent .= " <span class=\"text-3xl font-black text-blue-600\">\${item.price}</span>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <div class=\"bg-gradient-to-r from-slate-50 to-gray-100 rounded-lg p-2\">\n";
|
||||
$htmlContent .= " <p class=\"text-sm font-semibold text-gray-700 flex items-center justify-center\">\n";
|
||||
$htmlContent .= " <i class=\"fas fa-clock text-blue-500 mr-2\"></i>\n";
|
||||
$htmlContent .= " Valid for \${item.validity} \${item.timelimit}\n";
|
||||
$htmlContent .= " </p>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " </div>\n";
|
||||
$htmlContent .= " <button class=\"w-full bg-gradient-to-r from-gray-800 to-gray-900 text-white hover:from-gray-900 hover:to-black font-semibold py-3 px-4 rounded-xl transition-all duration-200 transform hover:-translate-y-0.5 shadow-lg hover:shadow-xl flex items-center justify-center gap-2 text-sm\"\n";
|
||||
$htmlContent .= " onclick=\"handlePhoneNumberSubmission('\${item.planId}', '\${item.routerId}', '\${item.price}'); return false;\"\n";
|
||||
$htmlContent .= " data-plan-id=\"\${item.planId}\"\n";
|
||||
$htmlContent .= " data-router-id=\"\${item.routerId}\">\n";
|
||||
$htmlContent .= " <i class=\"fas fa-shopping-cart text-base\"></i>\n";
|
||||
$htmlContent .= " <span>Buy Now</span>\n";
|
||||
$htmlContent .= " </button>\n";
|
||||
$htmlContent .= " `;\n";
|
||||
$htmlContent .= " cardsContainer.appendChild(cardDiv);\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= "}\n";
|
||||
$htmlContent .= "fetchData();\n";
|
||||
$htmlContent .= "</script>\n";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$htmlContent .= "<script src=\"https://cdn.jsdelivr.net/npm/sweetalert2@11\"></script>\n";
|
||||
$htmlContent .= "<script>\n";
|
||||
$htmlContent .= " function formatPhoneNumber(phoneNumber) {\n";
|
||||
$htmlContent .= " if (phoneNumber.startsWith('+')) {\n";
|
||||
$htmlContent .= " phoneNumber = phoneNumber.substring(1);\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " if (phoneNumber.startsWith('0')) {\n";
|
||||
$htmlContent .= " phoneNumber = '254' + phoneNumber.substring(1);\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " if (phoneNumber.match(/^(7|1)/)) {\n";
|
||||
$htmlContent .= " phoneNumber = '254' + phoneNumber;\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " return phoneNumber;\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= "\n";
|
||||
$htmlContent .= " function setCookie(name, value, days) {\n";
|
||||
$htmlContent .= " var expires = \"\";\n";
|
||||
$htmlContent .= " if (days) {\n";
|
||||
$htmlContent .= " var date = new Date();\n";
|
||||
$htmlContent .= " date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));\n";
|
||||
$htmlContent .= " expires = \"; expires=\" + date.toUTCString();\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " document.cookie = name + \"=\" + (value || \"\") + expires + \"; path=/\";\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= "\n";
|
||||
$htmlContent .= " function getCookie(name) {\n";
|
||||
$htmlContent .= " var nameEQ = name + \"=\";\n";
|
||||
$htmlContent .= " var ca = document.cookie.split(';');\n";
|
||||
$htmlContent .= " for (var i = 0; i < ca.length; i++) {\n";
|
||||
$htmlContent .= " var c = ca[i];\n";
|
||||
$htmlContent .= " while (c.charAt(0) == ' ') c = c.substring(1, c.length);\n";
|
||||
$htmlContent .= " if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " return null;\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= "\n";
|
||||
$htmlContent .= " function generateAccountId() {\n";
|
||||
$htmlContent .= " return 'ACC' + Math.floor(10000 + Math.random() * 90000); // Generate a random number between 10000 and 99999\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= "\n";
|
||||
|
||||
$htmlContent .= "var loginTimeout; // Variable to store the timeout ID\n";
|
||||
$htmlContent .= "function handlePhoneNumberSubmission(planId, routerId, price) {\n";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$htmlContent .= " var msg = \"You are about to pay Kes: \" + price + \". Enter phone number below and click pay now to initialize payment\";\n";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$htmlContent .= " const regexp = /\\\${([^{}]+)}/g;\n";
|
||||
$htmlContent .= " let result = msg.replace(regexp, function(ignore, key) {\n";
|
||||
$htmlContent .= " return eval(key);\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " swal.fire({\n";
|
||||
$htmlContent .= " title: 'Enter Your Mpesa Number',\n";
|
||||
$htmlContent .= " input: 'number',\n";
|
||||
$htmlContent .= " inputAttributes: {\n";
|
||||
$htmlContent .= " required: 'true'\n";
|
||||
$htmlContent .= " },\n";
|
||||
$htmlContent .= " inputValidator: function(value) {\n";
|
||||
$htmlContent .= " if (value === '') {\n";
|
||||
$htmlContent .= " return 'You need to write your phonenumber!';\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " },\n";
|
||||
$htmlContent .= " text: result,\n";
|
||||
$htmlContent .= " showCancelButton: true,\n";
|
||||
$htmlContent .= " confirmButtonColor: '#3085d6',\n";
|
||||
$htmlContent .= " cancelButtonColor: '#d33',\n";
|
||||
$htmlContent .= " confirmButtonText: 'Pay Now',\n";
|
||||
$htmlContent .= " showLoaderOnConfirm: true,\n";
|
||||
$htmlContent .= " preConfirm: (phoneNumber) => {\n";
|
||||
$htmlContent .= " var formattedPhoneNumber = formatPhoneNumber(phoneNumber);\n";
|
||||
$htmlContent .= " var accountId = getCookie('accountId');\n";
|
||||
$htmlContent .= " if (!accountId) {\n";
|
||||
$htmlContent .= " accountId = generateAccountId(); // Generate a new account ID\n";
|
||||
$htmlContent .= " setCookie('accountId', accountId, 7); // Set account ID as a cookie\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " document.getElementById('usernameInput').value = accountId; // Use account ID as the new username\n";
|
||||
$htmlContent .= " console.log(\"Phone number for autofill:\", formattedPhoneNumber);\n";
|
||||
$htmlContent .= "\n";
|
||||
$htmlContent .= " return fetch('" . APP_URL . "/index.php?_route=plugin/CreateHotspotuser&type=grant', {\n";
|
||||
$htmlContent .= " method: 'POST',\n";
|
||||
$htmlContent .= " headers: {'Content-Type': 'application/json'},\n";
|
||||
$htmlContent .= " body: JSON.stringify({phone_number: formattedPhoneNumber, plan_id: planId, router_id: routerId, account_id: accountId}),\n";
|
||||
$htmlContent .= " })\n";
|
||||
$htmlContent .= " .then(response => {\n";
|
||||
$htmlContent .= " if (!response.ok) throw new Error('Network response was not ok');\n";
|
||||
$htmlContent .= " return response.json();\n";
|
||||
$htmlContent .= " })\n";
|
||||
$htmlContent .= " .then(data => {\n";
|
||||
$htmlContent .= " if (data.status === 'error') throw new Error(data.message);\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " title: 'Processing..',\n";
|
||||
$htmlContent .= " html: `A payment request has been sent to your phone. Please wait while we process your payment.`,\n";
|
||||
$htmlContent .= " showConfirmButton: false,\n";
|
||||
$htmlContent .= " allowOutsideClick: false,\n";
|
||||
$htmlContent .= " didOpen: () => {\n";
|
||||
$htmlContent .= " Swal.showLoading();\n";
|
||||
$htmlContent .= " checkPaymentStatus(formattedPhoneNumber);\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " return formattedPhoneNumber;\n";
|
||||
$htmlContent .= " })\n";
|
||||
$htmlContent .= " .catch(error => {\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " title: 'Oops...',\n";
|
||||
$htmlContent .= " text: error.message,\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " },\n";
|
||||
$htmlContent .= " allowOutsideClick: () => !Swal.isLoading()\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= "}\n";
|
||||
$htmlContent .= "\n";
|
||||
$htmlContent .= "function checkPaymentStatus(phoneNumber) {\n";
|
||||
$htmlContent .= " let checkInterval = setInterval(() => {\n";
|
||||
$htmlContent .= " $.ajax({\n";
|
||||
$htmlContent .= " url: '" . APP_URL . "/index.php?_route=plugin/CreateHotspotuser&type=verify',\n";
|
||||
$htmlContent .= " method: 'POST',\n";
|
||||
$htmlContent .= " data: JSON.stringify({account_id: document.getElementById('usernameInput').value}),\n";
|
||||
$htmlContent .= " contentType: 'application/json',\n";
|
||||
$htmlContent .= " dataType: 'json',\n";
|
||||
$htmlContent .= " success: function(data) {\n";
|
||||
$htmlContent .= " console.log('Raw Response:', data); // Debugging\n";
|
||||
$htmlContent .= " if (data.Resultcode === '3') { // Success\n";
|
||||
$htmlContent .= " clearInterval(checkInterval);\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " icon: 'success',\n";
|
||||
$htmlContent .= " title: 'Payment Successful',\n";
|
||||
$htmlContent .= " text: data.Message,\n";
|
||||
$htmlContent .= " showConfirmButton: false\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " if (loginTimeout) {\n";
|
||||
$htmlContent .= " clearTimeout(loginTimeout);\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " loginTimeout = setTimeout(function() {\n";
|
||||
$htmlContent .= " document.getElementById('loginForm').submit();\n";
|
||||
$htmlContent .= " }, 2000);\n";
|
||||
$htmlContent .= " } else if (data.Resultcode === '2') { // Error\n";
|
||||
$htmlContent .= " clearInterval(checkInterval);\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " title: 'Payment Issue',\n";
|
||||
$htmlContent .= " text: data.Message,\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " } else if (data.Resultcode === '1') { // Primary\n";
|
||||
$htmlContent .= " // Continue checking\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " },\n";
|
||||
$htmlContent .= " error: function(xhr, textStatus, errorThrown) {\n";
|
||||
$htmlContent .= " console.log('Error: ' + errorThrown);\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " }, 2000);\n";
|
||||
$htmlContent .= "\n";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$htmlContent .= " setTimeout(() => {\n";
|
||||
$htmlContent .= " clearInterval(checkInterval);\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " icon: 'warning',\n";
|
||||
$htmlContent .= " title: 'Timeout',\n";
|
||||
$htmlContent .= " text: 'Payment verification timed out. Please try again.',\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " }, 600000); // Stop checking after 60 seconds\n";
|
||||
$htmlContent .= "}\n";
|
||||
$htmlContent .= "</script>\n";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$htmlContent .= "</script>\n";
|
||||
$htmlContent .= "<script>\n";
|
||||
$htmlContent .= "var loginTimeout; // Variable to store the timeout ID\n";
|
||||
$htmlContent .= "function redeemVoucher() {\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " title: 'Redeem Voucher',\n";
|
||||
$htmlContent .= " input: 'text',\n";
|
||||
$htmlContent .= " inputPlaceholder: 'Enter voucher code',\n";
|
||||
$htmlContent .= " inputValidator: function(value) {\n";
|
||||
$htmlContent .= " if (!value) {\n";
|
||||
$htmlContent .= " return 'You need to enter a voucher code!';\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " },\n";
|
||||
$htmlContent .= " confirmButtonColor: '#3085d6',\n";
|
||||
$htmlContent .= " cancelButtonColor: '#d33',\n";
|
||||
$htmlContent .= " confirmButtonText: 'Redeem',\n";
|
||||
$htmlContent .= " showLoaderOnConfirm: true,\n";
|
||||
$htmlContent .= " preConfirm: (voucherCode) => {\n";
|
||||
$htmlContent .= " var accountId = voucherCode;\n";
|
||||
$htmlContent .= " if (!accountId) {\n";
|
||||
$htmlContent .= " accountId = voucherCode;\n";
|
||||
$htmlContent .= " setCookie('accountId', accountId, 7);\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " return fetch('" . APP_URL . "/index.php?_route=plugin/CreateHotspotuser&type=voucher', {\n";
|
||||
$htmlContent .= " method: 'POST',\n";
|
||||
$htmlContent .= " headers: {'Content-Type': 'application/json'},\n";
|
||||
$htmlContent .= " body: JSON.stringify({voucher_code: voucherCode, account_id: accountId}),\n";
|
||||
$htmlContent .= " })\n";
|
||||
$htmlContent .= " .then(response => {\n";
|
||||
$htmlContent .= " if (!response.ok) throw new Error('Network response was not ok');\n";
|
||||
$htmlContent .= " return response.json();\n";
|
||||
$htmlContent .= " })\n";
|
||||
$htmlContent .= " .then(data => {\n";
|
||||
$htmlContent .= " if (data.status === 'error') throw new Error(data.message);\n";
|
||||
$htmlContent .= " return data;\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " },\n";
|
||||
$htmlContent .= " allowOutsideClick: () => !Swal.isLoading()\n";
|
||||
$htmlContent .= " }).then((result) => {\n";
|
||||
$htmlContent .= " if (result.isConfirmed) {\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " icon: 'success',\n";
|
||||
$htmlContent .= " title: 'Voucher Redeemed',\n";
|
||||
$htmlContent .= " text: result.value.message,\n";
|
||||
$htmlContent .= " showConfirmButton: false,\n";
|
||||
$htmlContent .= " allowOutsideClick: false,\n";
|
||||
$htmlContent .= " didOpen: () => {\n";
|
||||
$htmlContent .= " Swal.showLoading();\n";
|
||||
$htmlContent .= " var username = result.value.username;\n";
|
||||
$htmlContent .= " console.log('Received username from server:', username);\n";
|
||||
$htmlContent .= " var usernameInput = document.querySelector('input[name=\"username\"]');\n";
|
||||
$htmlContent .= " if (usernameInput) {\n";
|
||||
$htmlContent .= " console.log('Found username input element.');\n";
|
||||
$htmlContent .= " usernameInput.value = username;\n";
|
||||
$htmlContent .= " loginTimeout = setTimeout(function() {\n";
|
||||
$htmlContent .= " var loginForm = document.getElementById('loginForm');\n";
|
||||
$htmlContent .= " if (loginForm) {\n";
|
||||
$htmlContent .= " loginForm.submit();\n";
|
||||
$htmlContent .= " } else {\n";
|
||||
$htmlContent .= " console.error('Login form not found.');\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " title: 'Error',\n";
|
||||
$htmlContent .= " text: 'Login form not found. Please try again.',\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " }, 2000);\n";
|
||||
$htmlContent .= " } else {\n";
|
||||
$htmlContent .= " console.error('Username input element not found.');\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " title: 'Error',\n";
|
||||
$htmlContent .= " text: 'Username input not found. Please try again.',\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " }).catch(error => {\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " title: 'Oops...',\n";
|
||||
$htmlContent .= " text: error.message,\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= "}\n";
|
||||
$htmlContent .= "</script>\n";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$htmlContent .= "<script>\n";
|
||||
$htmlContent .= "var loginTimeout; // Variable to store the timeout ID\n";
|
||||
$htmlContent .= "document.addEventListener('DOMContentLoaded', function() {\n";
|
||||
$htmlContent .= " document.getElementById('reconnectBtn').addEventListener('click', function() {\n";
|
||||
$htmlContent .= " var mpesaCode = document.getElementById('mpesaCodeInput').value;\n";
|
||||
$htmlContent .= " var firstWord = mpesaCode.split(' ')[0]; // Get the first word in the MPESA code\n";
|
||||
$htmlContent .= " fetch('" . APP_URL . "/index.php?_route=plugin/CreateHotspotuser&type=reconnect', {\n";
|
||||
$htmlContent .= " method: 'POST',\n";
|
||||
$htmlContent .= " headers: {'Content-Type': 'application/json'},\n";
|
||||
$htmlContent .= " body: JSON.stringify({mpesa_code: firstWord}),\n"; // Sending only the first word of the MPESA code\n";
|
||||
$htmlContent .= " })\n";
|
||||
$htmlContent .= " .then(response => response.json())\n";
|
||||
$htmlContent .= " .then(data => {\n";
|
||||
$htmlContent .= " if (data.Status === 'success') {\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " icon: 'success',\n";
|
||||
$htmlContent .= " title: 'Reconnection Successful',\n";
|
||||
$htmlContent .= " text: data.Message,\n";
|
||||
$htmlContent .= " showConfirmButton: false,\n";
|
||||
$htmlContent .= " allowOutsideClick: false,\n";
|
||||
$htmlContent .= " didOpen: () => {\n";
|
||||
$htmlContent .= " Swal.showLoading();\n";
|
||||
$htmlContent .= " var username = data.username; // Replace with actual JSON field name\n";
|
||||
$htmlContent .= " console.log('Received username from server:', username);\n";
|
||||
$htmlContent .= " var usernameInput = document.querySelector('input[name=\"username\"]');\n";
|
||||
$htmlContent .= " if (usernameInput) {\n";
|
||||
$htmlContent .= " console.log('Found username input element.');\n";
|
||||
$htmlContent .= " usernameInput.value = username;\n";
|
||||
$htmlContent .= " loginTimeout = setTimeout(function() {\n";
|
||||
$htmlContent .= " var loginForm = document.getElementById('loginForm');\n";
|
||||
$htmlContent .= " if (loginForm) {\n";
|
||||
$htmlContent .= " loginForm.submit();\n";
|
||||
$htmlContent .= " } else {\n";
|
||||
$htmlContent .= " console.error('Login form not found.');\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " title: 'Error',\n";
|
||||
$htmlContent .= " text: 'Login form not found. Please try again.',\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " }, 2000);\n";
|
||||
$htmlContent .= " } else {\n";
|
||||
$htmlContent .= " console.error('Username input element not found.');\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " title: 'Error',\n";
|
||||
$htmlContent .= " text: 'Username input not found. Please try again.',\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " } else {\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " title: 'Reconnection Failed',\n";
|
||||
$htmlContent .= " text: data.Message,\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " }\n";
|
||||
$htmlContent .= " })\n";
|
||||
$htmlContent .= " .catch(error => {\n";
|
||||
$htmlContent .= " console.error('Error:', error);\n";
|
||||
$htmlContent .= " Swal.fire({\n";
|
||||
$htmlContent .= " title: 'Error',\n";
|
||||
$htmlContent .= " text: 'Failed to reconnect. Please try again later.',\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= "});\n";
|
||||
$htmlContent .= "</script>\n";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$htmlContent .= "<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js\"></script>\n";
|
||||
$htmlContent .= "<script>\n";
|
||||
$htmlContent .= "document.addEventListener('DOMContentLoaded', function() {\n";
|
||||
$htmlContent .= " // Ensure the button is correctly targeted by its ID.\n";
|
||||
$htmlContent .= " var submitBtn = document.getElementById('submitBtn');\n";
|
||||
$htmlContent .= " \n";
|
||||
$htmlContent .= " // Add a click event listener to the \"Login Now\" button.\n";
|
||||
$htmlContent .= " submitBtn.addEventListener('click', function(event) {\n";
|
||||
$htmlContent .= " event.preventDefault(); // Prevent the default button action.\n";
|
||||
$htmlContent .= " \n";
|
||||
$htmlContent .= " // Optional: Log to console for debugging purposes.\n";
|
||||
$htmlContent .= " console.log(\"Login Now button clicked.\");\n";
|
||||
$htmlContent .= " \n";
|
||||
$htmlContent .= " // Direct form submission, bypassing the doLogin function for simplicity.\n";
|
||||
$htmlContent .= " var form = document.getElementById('loginForm');\n";
|
||||
$htmlContent .= " form.submit(); // Submit the form directly.\n";
|
||||
$htmlContent .= " });\n";
|
||||
$htmlContent .= "});\n";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$htmlContent .= "</script>\n";
|
||||
$htmlContent .= "</html>\n";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$planStmt->close();
|
||||
$mysqli->close();
|
||||
// Check if the download parameter is set
|
||||
if (isset($_GET['download']) && $_GET['download'] == '1') {
|
||||
// Prepare the HTML content for download
|
||||
// ... build your HTML content ...
|
||||
|
||||
// Specify the filename for the download
|
||||
$filename = "login.html";
|
||||
|
||||
// Send headers to force download
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Disposition: attachment; filename='.basename($filename));
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate');
|
||||
header('Pragma: public');
|
||||
header('Content-Length: ' . strlen($htmlContent));
|
||||
|
||||
// Output the content
|
||||
echo $htmlContent;
|
||||
|
||||
// Prevent any further output
|
||||
exit;
|
||||
}
|
||||
|
||||
// Regular page content goes here
|
||||
// ... HTML and PHP code to display the page ...
|
||||
|
||||
|
||||
12
system/plugin/error_log
Normal file
12
system/plugin/error_log
Normal file
@@ -0,0 +1,12 @@
|
||||
[06-Jul-2024 15:05:25 UTC] PHP Fatal error: Uncaught Error: Undefined constant "request" in /home/codevibe/kejos.codevibeisp.co.ke/system/plugin/download.php:154
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in /home/codevibe/kejos.codevibeisp.co.ke/system/plugin/download.php on line 154
|
||||
[06-Jul-2024 15:05:28 UTC] PHP Fatal error: Uncaught Error: Undefined constant "request" in /home/codevibe/kejos.codevibeisp.co.ke/system/plugin/download.php:154
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in /home/codevibe/kejos.codevibeisp.co.ke/system/plugin/download.php on line 154
|
||||
[06-Jul-2024 17:35:47 UTC] PHP Fatal error: Uncaught Error: Undefined constant "request" in /home/codevibe/kejos.codevibeisp.co.ke/system/plugin/download.php:154
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in /home/codevibe/kejos.codevibeisp.co.ke/system/plugin/download.php on line 154
|
||||
79
system/plugin/hotspot_plan.php
Normal file
79
system/plugin/hotspot_plan.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
// Assuming you have ORM or database access configured correctly
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['routername'])) {
|
||||
// Example of fetching data (simplified)
|
||||
$routerName = $_POST['routername'];
|
||||
|
||||
// Fetch routers and plans from database (replace with your actual ORM or database queries)
|
||||
$routers = ORM::for_table('tbl_routers')->find_many();
|
||||
$plans_hotspot = ORM::for_table('tbl_plans')->where('type', 'Hotspot')->find_many();
|
||||
|
||||
// Fetch bandwidth limits for all plans
|
||||
$bandwidth_limits = ORM::for_table('tbl_bandwidth')->find_many();
|
||||
$bandwidth_map = [];
|
||||
foreach ($bandwidth_limits as $limit) {
|
||||
$bandwidth_map[$limit['plan_id']] = [
|
||||
'downlimit' => $limit['rate_down'],
|
||||
'uplimit' => $limit['rate_up'],
|
||||
];
|
||||
}
|
||||
|
||||
// Fetch currency from tbl_appconfig using the correct column names
|
||||
$currency_config = ORM::for_table('tbl_appconfig')->where('setting', 'currency_code')->find_one();
|
||||
$currency = $currency_config ? $currency_config->value : 'Ksh'; // Default to 'Ksh' if not found
|
||||
|
||||
// Initialize empty data array to store router-specific plans
|
||||
$data = [];
|
||||
|
||||
// Process each router to filter and collect hotspot plans
|
||||
foreach ($routers as $router) {
|
||||
if ($router['name'] === $routerName) { // Check if router name matches POSTed routername
|
||||
$routerData = [
|
||||
'name' => $router['name'],
|
||||
'router_id' => $router['id'],
|
||||
'description' => $router['description'],
|
||||
'plans_hotspot' => [],
|
||||
];
|
||||
|
||||
// Filter and collect hotspot plans associated with the router
|
||||
foreach ($plans_hotspot as $plan) {
|
||||
if ($router['name'] == $plan['routers']) {
|
||||
$plan_id = $plan['id'];
|
||||
$bandwidth_data = isset($bandwidth_map[$plan_id]) ? $bandwidth_map[$plan_id] : [];
|
||||
|
||||
// Construct payment link using $_url
|
||||
$paymentlink = "https://codevibeisp.co.ke/index.php?_route=plugin/hotspot_pay&routerName={$router['name']}&planId={$plan['id']}&routerId={$router['id']}";
|
||||
|
||||
// Prepare plan data to be sent in JSON response
|
||||
$routerData['plans_hotspot'][] = [
|
||||
'plantype' => $plan['type'],
|
||||
'planname' => $plan['name_plan'],
|
||||
'currency' => $currency,
|
||||
'price' => $plan['price'],
|
||||
'validity' => $plan['validity'],
|
||||
'device' => $plan['shared_users'],
|
||||
'datalimit' => $plan['data_limit'],
|
||||
'timelimit' => $plan['validity_unit'] ?? null,
|
||||
'downlimit' => $bandwidth_data['downlimit'] ?? null,
|
||||
'uplimit' => $bandwidth_data['uplimit'] ?? null,
|
||||
'paymentlink' => $paymentlink,
|
||||
'planId' => $plan['id'],
|
||||
'routerName' => $router['name'],
|
||||
'routerId' => $router['id']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Add router data to $data array
|
||||
$data[] = $routerData;
|
||||
}
|
||||
}
|
||||
|
||||
// Respond with JSON data
|
||||
// header('Content-Type: application/json');
|
||||
// header('Access-Control-Allow-Origin: *'); // Adjust this based on your CORS requirements
|
||||
echo json_encode(['data' => $data], JSON_PRETTY_PRINT);
|
||||
exit();
|
||||
}
|
||||
?>
|
||||
229
system/plugin/hotspot_settings.php
Normal file
229
system/plugin/hotspot_settings.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
|
||||
$conn = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_password);
|
||||
function hotspot_settings() {
|
||||
global $ui, $conn;
|
||||
_admin();
|
||||
$admin = Admin::_info();
|
||||
$ui->assign('_title', 'Hotspot Dashboard');
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
// Check if form is submitted
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Update Hotspot Title
|
||||
$newHotspotTitle = isset($_POST['hotspot_title']) ? trim($_POST['hotspot_title']) : '';
|
||||
if (!empty($newHotspotTitle)) {
|
||||
$updateStmt = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'hotspot_title'");
|
||||
$updateStmt->execute([$newHotspotTitle]);
|
||||
}
|
||||
|
||||
// Add similar logic for FAQ fields here
|
||||
// FAQ Headline 1 Posting To Database
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$newFaqHeadline1 = isset($_POST['frequently_asked_questions_headline1']) ? trim($_POST['frequently_asked_questions_headline1']) : '';
|
||||
if (!empty($newFaqHeadline1)) {
|
||||
$updateFaqStmt1 = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'frequently_asked_questions_headline1'");
|
||||
$updateFaqStmt1->execute([$newFaqHeadline1]);
|
||||
}
|
||||
}
|
||||
|
||||
// FAQ Headline 2 Posting To Database
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$newFaqHeadline1 = isset($_POST['frequently_asked_questions_headline2']) ? trim($_POST['frequently_asked_questions_headline2']) : '';
|
||||
if (!empty($newFaqHeadline1)) {
|
||||
$updateFaqStmt1 = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'frequently_asked_questions_headline2'");
|
||||
$updateFaqStmt1->execute([$newFaqHeadline1]);
|
||||
}
|
||||
}
|
||||
|
||||
// FAQ Headline 3 Posting To Database
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$newFaqHeadline1 = isset($_POST['frequently_asked_questions_headline3']) ? trim($_POST['frequently_asked_questions_headline3']) : '';
|
||||
if (!empty($newFaqHeadline1)) {
|
||||
$updateFaqStmt1 = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'frequently_asked_questions_headline3'");
|
||||
$updateFaqStmt1->execute([$newFaqHeadline1]);
|
||||
}
|
||||
}
|
||||
|
||||
// FAQ Answer 1 Posting To Database
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$newFaqHeadline1 = isset($_POST['frequently_asked_questions_answer1']) ? trim($_POST['frequently_asked_questions_answer1']) : '';
|
||||
if (!empty($newFaqHeadline1)) {
|
||||
$updateFaqStmt1 = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'frequently_asked_questions_answer1'");
|
||||
$updateFaqStmt1->execute([$newFaqHeadline1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FAQ Answer 2 Posting To Database
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$newFaqHeadline1 = isset($_POST['frequently_asked_questions_answer2']) ? trim($_POST['frequently_asked_questions_answer2']) : '';
|
||||
if (!empty($newFaqHeadline1)) {
|
||||
$updateFaqStmt1 = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'frequently_asked_questions_answer2'");
|
||||
$updateFaqStmt1->execute([$newFaqHeadline1]);
|
||||
}
|
||||
}
|
||||
|
||||
// FAQ Answer 3 Posting To Database
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$newFaqHeadline1 = isset($_POST['frequently_asked_questions_answer3']) ? trim($_POST['frequently_asked_questions_answer3']) : '';
|
||||
if (!empty($newFaqHeadline1)) {
|
||||
$updateFaqStmt1 = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'frequently_asked_questions_answer3'");
|
||||
$updateFaqStmt1->execute([$newFaqHeadline1]);
|
||||
}
|
||||
}
|
||||
|
||||
// FAQ Description Posting To Database
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$newFaqHeadline1 = isset($_POST['description']) ? trim($_POST['description']) : '';
|
||||
if (!empty($newFaqHeadline1)) {
|
||||
$updateFaqStmt1 = $conn->prepare("UPDATE tbl_appconfig SET value = ? WHERE setting = 'description'");
|
||||
$updateFaqStmt1->execute([$newFaqHeadline1]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Get router name from user input
|
||||
$routerName = isset($_POST['router_name']) ? trim($_POST['router_name']) : '';
|
||||
|
||||
if (!empty($routerName)) {
|
||||
// Fetch the router ID based on the router name
|
||||
$routerStmt = $conn->prepare("SELECT id FROM tbl_routers WHERE name = :router_name");
|
||||
$routerStmt->execute(['router_name' => $routerName]);
|
||||
$router = $routerStmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($router) {
|
||||
// Update router_id in tbl_appconfig
|
||||
$updateRouterIdStmt = $conn->prepare("UPDATE tbl_appconfig SET value = :router_id WHERE setting = 'router_id'");
|
||||
$updateRouterIdStmt->execute(['router_id' => $router['id']]);
|
||||
|
||||
// Update router_name in tbl_appconfig
|
||||
$updateRouterNameStmt = $conn->prepare("UPDATE tbl_appconfig SET value = :router_name WHERE setting = 'router_name'");
|
||||
$updateRouterNameStmt->execute(['router_name' => $routerName]);
|
||||
} else {
|
||||
// Handle the case where no matching router is found
|
||||
// For example, you can set an error message or take any other appropriate action
|
||||
}
|
||||
}
|
||||
// Other form handling code (if any)
|
||||
}
|
||||
|
||||
|
||||
// Redirect with a success message
|
||||
r2(U . "plugin/hotspot_settings", 's', "Settings Saved");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Fetch the current hotspot title from the database
|
||||
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'hotspot_title'");
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$hotspotTitle = $result ? $result['value'] : '';
|
||||
|
||||
// Assign the fetched title to the template
|
||||
$ui->assign('hotspot_title', $hotspotTitle);
|
||||
|
||||
|
||||
|
||||
|
||||
// Fetch the current faq headline 1 from the database
|
||||
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'frequently_asked_questions_headline1'");
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$headline1 = $result ? $result['value'] : '';
|
||||
|
||||
// Assign the fetched title to the template
|
||||
$ui->assign('frequently_asked_questions_headline1', $headline1);
|
||||
|
||||
|
||||
// Fetch the current faq headline 2 from the database
|
||||
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'frequently_asked_questions_headline2'");
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$headline2 = $result ? $result['value'] : '';
|
||||
|
||||
// Assign the fetched title to the template
|
||||
$ui->assign('frequently_asked_questions_headline2', $headline2);
|
||||
|
||||
|
||||
|
||||
// Fetch the current faq headline 3 from the database
|
||||
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'frequently_asked_questions_headline3'");
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$headline3 = $result ? $result['value'] : '';
|
||||
|
||||
// Assign the fetched title to the template
|
||||
$ui->assign('frequently_asked_questions_headline3', $headline3);
|
||||
|
||||
|
||||
// Fetch the current faq Answer1 from the database
|
||||
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'frequently_asked_questions_answer1'");
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$answer1 = $result ? $result['value'] : '';
|
||||
|
||||
// Assign the fetched title to the template
|
||||
$ui->assign('frequently_asked_questions_answer1', $answer1);
|
||||
|
||||
// Fetch the current faq Answer2 from the database
|
||||
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'frequently_asked_questions_answer2'");
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$answer2 = $result ? $result['value'] : '';
|
||||
|
||||
// Assign the fetched title to the template
|
||||
$ui->assign('frequently_asked_questions_answer2', $answer2);
|
||||
|
||||
// Fetch the current faq Answer 3 from the database
|
||||
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'frequently_asked_questions_answer3'");
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$answer3 = $result ? $result['value'] : '';
|
||||
|
||||
// Assign the fetched title to the template
|
||||
$ui->assign('frequently_asked_questions_answer3', $answer3);
|
||||
|
||||
// Fetch the current faq description from the database
|
||||
$stmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'description'");
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$description = $result ? $result['value'] : '';
|
||||
|
||||
// Assign the fetched title to the template
|
||||
$ui->assign('description', $description);
|
||||
|
||||
|
||||
|
||||
/// Fetch the current router name from the database for display in the form
|
||||
$routerIdStmt = $conn->prepare("SELECT value FROM tbl_appconfig WHERE setting = 'router_id'");
|
||||
$routerIdStmt->execute();
|
||||
$routerIdResult = $routerIdStmt->fetch(PDO::FETCH_ASSOC);
|
||||
if ($routerIdResult) {
|
||||
$routerStmt = $conn->prepare("SELECT name FROM tbl_routers WHERE id = :router_id");
|
||||
$routerStmt->execute(['router_id' => $routerIdResult['value']]);
|
||||
$router = $routerStmt->fetch(PDO::FETCH_ASSOC);
|
||||
if ($router) {
|
||||
$ui->assign('router_name', $router['name']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Render the template
|
||||
$ui->display('hotspot_settings.tpl');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
system/plugin/index.html
Normal file
BIN
system/plugin/index.html
Normal file
Binary file not shown.
137
system/plugin/initiatePaybillStk.php
Normal file
137
system/plugin/initiatePaybillStk.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
function initiatePaybillPayment()
|
||||
{
|
||||
// Ensure POST variables are set and sanitize input
|
||||
$username = isset($_POST['username']) ? filter_var($_POST['username'], FILTER_SANITIZE_STRING) : null;
|
||||
$phone = isset($_POST['phone']) ? filter_var($_POST['phone'], FILTER_SANITIZE_STRING) : null;
|
||||
|
||||
if (!$username || !$phone) {
|
||||
echo "<script>toastr.error('Invalid input data');</script>";
|
||||
return;
|
||||
}
|
||||
|
||||
// Normalize phone number
|
||||
$phone = preg_replace(['/^\+/', '/^0/', '/^7/', '/^1/'], ['', '254', '2547', '2541'], $phone);
|
||||
|
||||
// Retrieve bank details from the database
|
||||
$bankaccount = ORM::for_table('tbl_appconfig')->where('setting', 'PaybillAcc')->find_one();
|
||||
$bankname = ORM::for_table('tbl_appconfig')->where('setting', 'PaybillName')->find_one();
|
||||
$bankaccount = $bankaccount ? $bankaccount->value : null;
|
||||
$bankname = $bankname ? $bankname->value : null;
|
||||
|
||||
if (!$bankaccount || !$bankname) {
|
||||
echo "<script>toastr.error('Could not complete the payment req, please contact admin');</script>";
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for existing user details
|
||||
$CheckId = ORM::for_table('tbl_customers')->where('username', $username)->order_by_desc('id')->find_one();
|
||||
$CheckUser = ORM::for_table('tbl_customers')->where('phonenumber', $phone)->find_many();
|
||||
$UserId = $CheckId ? $CheckId->id : null;
|
||||
|
||||
if ($CheckUser) {
|
||||
ORM::for_table('tbl_customers')->where('phonenumber', $phone)->where_not_equal('id', $UserId)->delete_many();
|
||||
}
|
||||
|
||||
// Retrieve payment gateway record
|
||||
$PaymentGatewayRecord = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $username)
|
||||
->where('status', 1)
|
||||
->order_by_desc('id')
|
||||
->find_one();
|
||||
|
||||
if (!$PaymentGatewayRecord) {
|
||||
echo "<script>toastr.error('Could not complete the payment req, please contact administrator');</script>";
|
||||
return;
|
||||
}
|
||||
|
||||
// Update user phone number
|
||||
$ThisUser = ORM::for_table('tbl_customers')->where('username', $username)->order_by_desc('id')->find_one();
|
||||
if ($ThisUser) {
|
||||
$ThisUser->phonenumber = $phone;
|
||||
$ThisUser->save();
|
||||
}
|
||||
|
||||
$amount = $PaymentGatewayRecord->price;
|
||||
|
||||
// Safaricom API credentials
|
||||
$consumerKey = 'YOUR_CONSUMER_KEY';
|
||||
$consumerSecret = 'YOUR_CONSUMER_SECRET';
|
||||
|
||||
// Get access token
|
||||
$access_token_url = 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
|
||||
$curl = curl_init($access_token_url);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type:application/json; charset=utf8']);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
|
||||
curl_setopt($curl, CURLOPT_USERPWD, "$consumerKey:$consumerSecret");
|
||||
$result = curl_exec($curl);
|
||||
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
curl_close($curl);
|
||||
|
||||
if ($status !== 200) {
|
||||
echo "<script>toastr.error('Failed to get access token');</script>";
|
||||
return;
|
||||
}
|
||||
|
||||
$result = json_decode($result);
|
||||
$access_token = $result->access_token;
|
||||
|
||||
// Initiate Paybill payment
|
||||
$paybill_url = 'https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
|
||||
$Timestamp = date("YmdHis");
|
||||
$BusinessShortCode = 'YOUR_BUSINESS_SHORTCODE';
|
||||
$Passkey = 'YOUR_PASSKEY';
|
||||
$Password = base64_encode($BusinessShortCode . $Passkey . $Timestamp);
|
||||
$CallBackURL = U . 'callback/PaybillCallback';
|
||||
|
||||
$curl_post_data = [
|
||||
'BusinessShortCode' => $BusinessShortCode,
|
||||
'Password' => $Password,
|
||||
'Timestamp' => $Timestamp,
|
||||
'TransactionType' => 'CustomerPayBillOnline',
|
||||
'Amount' => $amount,
|
||||
'PartyA' => $phone,
|
||||
'PartyB' => $BusinessShortCode,
|
||||
'PhoneNumber' => $phone,
|
||||
'CallBackURL' => $CallBackURL,
|
||||
'AccountReference' => $bankaccount,
|
||||
'TransactionDesc' => 'PayBill Payment'
|
||||
];
|
||||
|
||||
$curl = curl_init($paybill_url);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type:application/json', 'Authorization:Bearer ' . $access_token]);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($curl_post_data));
|
||||
$curl_response = curl_exec($curl);
|
||||
curl_close($curl);
|
||||
|
||||
$mpesaResponse = json_decode($curl_response);
|
||||
$responseCode = $mpesaResponse->ResponseCode;
|
||||
$resultDesc = $mpesaResponse->resultDesc;
|
||||
$MerchantRequestID = $mpesaResponse->MerchantRequestID;
|
||||
$CheckoutRequestID = $mpesaResponse->CheckoutRequestID;
|
||||
|
||||
if ($responseCode == "0") {
|
||||
date_default_timezone_set('Africa/Nairobi');
|
||||
$now = date("Y-m-d H:i:s");
|
||||
|
||||
$PaymentGatewayRecord->pg_paid_response = $resultDesc;
|
||||
$PaymentGatewayRecord->username = $username;
|
||||
$PaymentGatewayRecord->checkout = $CheckoutRequestID;
|
||||
$PaymentGatewayRecord->payment_method = 'Mpesa PayBill';
|
||||
$PaymentGatewayRecord->payment_channel = 'Mpesa PayBill';
|
||||
$PaymentGatewayRecord->save();
|
||||
|
||||
if (!empty($_POST['channel'])) {
|
||||
echo json_encode(["status" => "success", "message" => "Enter Pin to complete"]);
|
||||
} else {
|
||||
echo "<script>toastr.success('Enter Mpesa Pin to complete');</script>";
|
||||
}
|
||||
} else {
|
||||
echo "<script>toastr.error('We could not complete the payment for you, please contact administrator');</script>";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
307
system/plugin/initiatebankstk.php
Normal file
307
system/plugin/initiatebankstk.php
Normal file
@@ -0,0 +1,307 @@
|
||||
<?php
|
||||
|
||||
function initiatebankstk()
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$username=$_POST['username'];
|
||||
$phone=$_POST['phone'];
|
||||
|
||||
|
||||
|
||||
$phone = (substr($phone, 0,1) == '+') ? str_replace('+', '', $phone) : $phone;
|
||||
$phone = (substr($phone, 0,1) == '0') ? preg_replace('/^0/', '254', $phone) : $phone;
|
||||
$phone = (substr($phone, 0,1) == '7') ? preg_replace('/^7/', '2547', $phone) : $phone; //cater for phone number prefix 2547XXXX
|
||||
$phone = (substr($phone, 0,1) == '1') ? preg_replace('/^1/', '2541', $phone) : $phone; //cater for phone number prefix 2541XXXX
|
||||
$phone = (substr($phone, 0,1) == '0') ? preg_replace('/^01/', '2541', $phone) : $phone;
|
||||
$phone = (substr($phone, 0,1) == '0') ? preg_replace('/^07/', '2547', $phone) : $phone;
|
||||
|
||||
|
||||
|
||||
|
||||
// Get bank configuration (original approach - direct account number)
|
||||
$bank_config = ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'Stkbankacc')
|
||||
->find_one();
|
||||
|
||||
$bankaccount = ($bank_config) ? $bank_config->value : null;
|
||||
|
||||
// Get bank name
|
||||
$bank_name_config = ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'Stkbankname')
|
||||
->find_one();
|
||||
|
||||
$bankname = ($bank_name_config) ? $bank_name_config->value : null;
|
||||
|
||||
// echo $bankname;
|
||||
|
||||
|
||||
$CheckId = ORM::for_table('tbl_customers')
|
||||
->where('username', $username)
|
||||
->order_by_desc('id')
|
||||
->find_one();
|
||||
|
||||
$CheckUser = ORM::for_table('tbl_customers')
|
||||
->where('phonenumber', $phone)
|
||||
->find_many();
|
||||
|
||||
$UserId=$CheckId->id;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (empty($bankaccount) || empty($bankname)) {
|
||||
|
||||
|
||||
echo $error="<script>toastr.error('Could not complete the payment req, please contact admin');</script>";
|
||||
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$getpaybill = ORM::for_table('tbl_banks')
|
||||
->where('name', $bankname)
|
||||
->find_one();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$paybill=$getpaybill->paybill;
|
||||
|
||||
|
||||
|
||||
// echo $paybill;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$cburl = U . 'callback/BankStkPush' ;
|
||||
|
||||
|
||||
$PaymentGatewayRecord = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $username)
|
||||
->where('status', 1) // Add this line to filter by status
|
||||
->order_by_desc('id')
|
||||
->find_one();
|
||||
|
||||
|
||||
|
||||
$ThisUser= ORM::for_table('tbl_customers')
|
||||
->where('username', $username)
|
||||
->order_by_desc('id')
|
||||
->find_one();
|
||||
|
||||
|
||||
|
||||
$ThisUser->phonenumber=$phone;
|
||||
// $ThisUser->username=$phone;
|
||||
$ThisUser->save();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$amount=$PaymentGatewayRecord->price;
|
||||
|
||||
if(!$PaymentGatewayRecord){
|
||||
|
||||
echo $error="<script>toastr.error('Could not complete the payment req, please contact administrator');</script>";
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$consumerKey = '3AmVP1WFDQn7GrDH8GcSSKxcAvnJdZGC'; //Fill with your app Consumer Key
|
||||
$consumerSecret = '71Lybl6jUtxM0F35'; // Fill with your app Secret
|
||||
|
||||
$headers = ['Content-Type:application/json; charset=utf8'];
|
||||
|
||||
$access_token_url = 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
|
||||
|
||||
$curl = curl_init($access_token_url);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
|
||||
curl_setopt($curl, CURLOPT_HEADER, FALSE);('');
|
||||
|
||||
curl_setopt($curl, CURLOPT_USERPWD, $consumerKey.':'.$consumerSecret);
|
||||
$result = curl_exec($curl);
|
||||
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
$result = json_decode($result);
|
||||
|
||||
$access_token = $result->access_token;
|
||||
|
||||
// echo $access_token;
|
||||
|
||||
curl_close($curl);
|
||||
|
||||
|
||||
// Initiate Stk push
|
||||
|
||||
$stk_url = 'https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
|
||||
$PartyA = $phone; // This is your phone number,
|
||||
$AccountReference = $bankaccount;
|
||||
$TransactionDesc = 'TestMapayment';
|
||||
$Amount = $amount;
|
||||
$BusinessShortCode='4122323';
|
||||
$Passkey='aaebecea73082fa56af852606106b1316d5b4dfa2f12d0088800b0b88e4bb6e3';
|
||||
$Timestamp = date("YmdHis",time());
|
||||
$Password = base64_encode($BusinessShortCode.$Passkey.$Timestamp);
|
||||
$CallBackURL = $cburl;
|
||||
|
||||
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, $stk_url);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type:application/json','Authorization:Bearer '.$access_token)); //setting custom header
|
||||
|
||||
|
||||
$curl_post_data = array(
|
||||
//Fill in the request parameters with valid values
|
||||
'BusinessShortCode' => $BusinessShortCode,
|
||||
'Password' => $Password,
|
||||
'Timestamp' => $Timestamp,
|
||||
'TransactionType' => 'CustomerPayBillOnline',
|
||||
'Amount' => $Amount,
|
||||
'PartyA' => $PartyA,
|
||||
'PartyB' => $paybill,
|
||||
'PhoneNumber' => $PartyA,
|
||||
'CallBackURL' => $CallBackURL,
|
||||
'AccountReference' => $AccountReference,
|
||||
'TransactionDesc' => $TransactionDesc
|
||||
);
|
||||
|
||||
$data_string = json_encode($curl_post_data);
|
||||
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
|
||||
|
||||
$curl_response = curl_exec($curl);
|
||||
//print_r($curl_response);
|
||||
|
||||
// echo $curl_response;
|
||||
// die;
|
||||
|
||||
$mpesaResponse = json_decode($curl_response);
|
||||
|
||||
|
||||
|
||||
|
||||
$responseCode = $mpesaResponse->ResponseCode;
|
||||
$resultDesc = $mpesaResponse->resultDesc;
|
||||
$MerchantRequestID = $mpesaResponse->MerchantRequestID;
|
||||
$CheckoutRequestID = $mpesaResponse->CheckoutRequestID;
|
||||
|
||||
|
||||
if($responseCode=="0"){
|
||||
date_default_timezone_set('Africa/Nairobi');
|
||||
$now=date("Y-m-d H:i:s");
|
||||
|
||||
// $username=$phone;
|
||||
|
||||
$PaymentGatewayRecord->pg_paid_response = $resultDesc;
|
||||
$PaymentGatewayRecord->username = $username;
|
||||
$PaymentGatewayRecord->checkout = $CheckoutRequestID;
|
||||
$PaymentGatewayRecord->payment_method = 'Mpesa Stk Push';
|
||||
$PaymentGatewayRecord->payment_channel = 'Mpesa Stk Push';
|
||||
$PaymentGatewayRecord->save();
|
||||
|
||||
|
||||
|
||||
if(!empty($_POST['channel'])){
|
||||
|
||||
echo json_encode(["status" => "success", "message" => "Enter Pin to complete"]);
|
||||
|
||||
}else{
|
||||
echo $error="<script>toastr.success('Enter Mpesa Pin to complete');</script>";
|
||||
|
||||
}
|
||||
|
||||
}else{
|
||||
|
||||
echo $error="<script>toastr.error('We could not complete the payment for you, please contact administrator');</script>";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
||||
148
system/plugin/initiatempesa.php
Normal file
148
system/plugin/initiatempesa.php
Normal file
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
function initiatempesa()
|
||||
{
|
||||
$username = $_POST['username'];
|
||||
$phone = $_POST['phone'];
|
||||
$phone = (substr($phone, 0, 1) == '+') ? str_replace('+', '', $phone) : $phone;
|
||||
$phone = (substr($phone, 0, 1) == '0') ? preg_replace('/^0/', '254', $phone) : $phone;
|
||||
$phone = (substr($phone, 0, 1) == '7') ? preg_replace('/^7/', '2547', $phone) : $phone; //cater for phone number prefix 2547XXXX
|
||||
$phone = (substr($phone, 0, 1) == '1') ? preg_replace('/^1/', '2541', $phone) : $phone; //cater for phone number prefix 2541XXXX
|
||||
$phone = (substr($phone, 0, 1) == '0') ? preg_replace('/^01/', '2541', $phone) : $phone;
|
||||
$phone = (substr($phone, 0, 1) == '0') ? preg_replace('/^07/', '2547', $phone) : $phone;
|
||||
$CheckId = ORM::for_table('tbl_customers')
|
||||
->where('username', $username)
|
||||
->order_by_desc('id')
|
||||
->find_one();
|
||||
$CheckUser = ORM::for_table('tbl_customers')
|
||||
->where('phonenumber', $phone)
|
||||
->find_many();
|
||||
$UserId = $CheckId->id;
|
||||
|
||||
$CallBackURL = U . 'callback/mpesa';
|
||||
$PaymentGatewayRecord = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $username)
|
||||
->where('status', 1) // Add this line to filter by status
|
||||
->order_by_desc('id')
|
||||
->find_one();
|
||||
$ThisUser = ORM::for_table('tbl_customers')
|
||||
->where('username', $username)
|
||||
->order_by_desc('id')
|
||||
->find_one();
|
||||
$ThisUser->phonenumber = $phone;
|
||||
$ThisUser->save();
|
||||
$amount = $PaymentGatewayRecord->price;
|
||||
if (!$PaymentGatewayRecord) {
|
||||
echo json_encode(["status" => "error", "message" => "Could not complete the payment req, please contact administrator"]);
|
||||
}
|
||||
// Get the M-Pesa mpesa_env
|
||||
$mpesa_env = ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'mpesa_env')
|
||||
->find_one();
|
||||
$mpesa_env = ($mpesa_env) ? $mpesa_env->value : null;
|
||||
// Get the M-Pesa consumer key
|
||||
$mpesa_consumer_key = ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'mpesa_consumer_key')
|
||||
->find_one();
|
||||
$mpesa_consumer_key = ($mpesa_consumer_key) ? $mpesa_consumer_key->value : null;
|
||||
// Get the M-Pesa consumer secret
|
||||
$mpesa_consumer_secret = ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'mpesa_consumer_secret')
|
||||
->find_one();
|
||||
$mpesa_consumer_secret = ($mpesa_consumer_secret) ? $mpesa_consumer_secret->value : null;
|
||||
$mpesa_business_code = ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'mpesa_business_code')
|
||||
->find_one();
|
||||
$mpesa_business_code = ($mpesa_business_code) ? $mpesa_business_code->value : null;
|
||||
$mpesa_shortcode_type = ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'mpesa_shortcode_type')
|
||||
->find_one();
|
||||
if ($mpesa_shortcode_type == 'BuyGoods') {
|
||||
$mpesa_buygoods_till_number = ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'mpesa_buygoods_till_number')
|
||||
->find_one();
|
||||
$mpesa_buygoods_till_number = ($mpesa_buygoods_till_number) ? $mpesa_buygoods_till_number->value : null;
|
||||
$PartyB = $mpesa_buygoods_till_number;
|
||||
$Type_of_Transaction = 'CustomerBuyGoodsOnline';
|
||||
} else {
|
||||
$PartyB = $mpesa_business_code;
|
||||
$Type_of_Transaction = 'CustomerPayBillOnline';
|
||||
}
|
||||
$Passkey = ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'mpesa_pass_key')
|
||||
->find_one();
|
||||
$Passkey = ($Passkey) ? $Passkey->value : null;
|
||||
$Time_Stamp = date("Ymdhis");
|
||||
$password = base64_encode($mpesa_business_code . $Passkey . $Time_Stamp);
|
||||
if ($mpesa_env == "live") {
|
||||
$OnlinePayment = 'https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
|
||||
$Token_URL = 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
|
||||
} elseif ($mpesa_env == "sandbox") {
|
||||
$OnlinePayment = 'https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
|
||||
$Token_URL = 'https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
|
||||
} else {
|
||||
return json_encode(["Message" => "invalid application status"]);
|
||||
};
|
||||
$headers = ['Content-Type:application/json; charset=utf8'];
|
||||
$curl = curl_init($Token_URL);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
|
||||
curl_setopt($curl, CURLOPT_HEADER, FALSE);
|
||||
curl_setopt($curl, CURLOPT_USERPWD, $mpesa_consumer_key . ':' . $mpesa_consumer_secret);
|
||||
$result = curl_exec($curl);
|
||||
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
$result = json_decode($result);
|
||||
$access_token = $result->access_token;
|
||||
curl_close($curl);
|
||||
$password = base64_encode($mpesa_business_code . $Passkey . $Time_Stamp);
|
||||
$stkpushheader = ['Content-Type:application/json', 'Authorization:Bearer ' . $access_token];
|
||||
//INITIATE CURL
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, $OnlinePayment);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $stkpushheader); //setting custom header
|
||||
$curl_post_data = array(
|
||||
//Fill in the request parameters with valid values
|
||||
'BusinessShortCode' => $mpesa_business_code,
|
||||
'Password' => $password,
|
||||
'Timestamp' => $Time_Stamp,
|
||||
'TransactionType' => $Type_of_Transaction,
|
||||
'Amount' => $amount,
|
||||
'PartyA' => $phone,
|
||||
'PartyB' => $PartyB,
|
||||
'PhoneNumber' => $phone,
|
||||
'CallBackURL' => $CallBackURL,
|
||||
'AccountReference' => $username,
|
||||
'TransactionDesc' => 'Payment for ' . $username
|
||||
);
|
||||
$data_string = json_encode($curl_post_data);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
|
||||
$curl_response = curl_exec($curl);
|
||||
$curl_Tranfer2_response = json_decode($curl_response);
|
||||
if (isset($curl_Tranfer2_response->ResponseCode) && $curl_Tranfer2_response->ResponseCode == "0") {
|
||||
$resultDesc = $curl_Tranfer2_response->resultDesc;
|
||||
$CheckoutRequestID = $curl_Tranfer2_response->CheckoutRequestID;
|
||||
date_default_timezone_set('Africa/Nairobi');
|
||||
$now = date("Y-m-d H:i:s");
|
||||
// $username=$phone;
|
||||
$PaymentGatewayRecord->pg_paid_response = $resultDesc;
|
||||
$PaymentGatewayRecord->username = $username;
|
||||
$PaymentGatewayRecord->checkout = $CheckoutRequestID;
|
||||
$PaymentGatewayRecord->payment_method = 'Mpesa Stk Push';
|
||||
$PaymentGatewayRecord->payment_channel = 'Mpesa Stk Push';
|
||||
$saveGateway = $PaymentGatewayRecord->save();
|
||||
if ($saveGateway) {
|
||||
if (!empty($_POST['channel'])) {
|
||||
echo json_encode(["status" => "success", "message" => "Enter Mpesa Pin to complete $mpesa_business_code $Type_of_Transaction , Party B: $PartyB, Amount: $amount, Phone: $phone, CheckoutRequestID: $CheckoutRequestID"]);
|
||||
} else {
|
||||
echo "<script>toastr.success('Enter Mpesa Pin to complete');</script>";
|
||||
}
|
||||
} else {
|
||||
echo json_encode(["status" => "error", "message" => "Failed to save the payment gateway record"]);
|
||||
}
|
||||
} else {
|
||||
$errorMessage = $curl_Tranfer2_response->errorMessage;
|
||||
echo json_encode(["status" => "error", "message" => $errorMessage]);
|
||||
}
|
||||
}
|
||||
232
system/plugin/initiatetillstk.php
Normal file
232
system/plugin/initiatetillstk.php
Normal file
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
function initiatetillstk()
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
$username=$_POST['username'];
|
||||
$phone=$_POST['phone'];
|
||||
|
||||
|
||||
|
||||
|
||||
$phone = (substr($phone, 0,1) == '+') ? str_replace('+', '', $phone) : $phone;
|
||||
$phone = (substr($phone, 0,1) == '0') ? preg_replace('/^0/', '254', $phone) : $phone;
|
||||
$phone = (substr($phone, 0,1) == '7') ? preg_replace('/^7/', '2547', $phone) : $phone; //cater for phone number prefix 2547XXXX
|
||||
$phone = (substr($phone, 0,1) == '1') ? preg_replace('/^1/', '2541', $phone) : $phone; //cater for phone number prefix 2541XXXX
|
||||
$phone = (substr($phone, 0,1) == '0') ? preg_replace('/^01/', '2541', $phone) : $phone;
|
||||
$phone = (substr($phone, 0,1) == '0') ? preg_replace('/^07/', '2547', $phone) : $phone;
|
||||
|
||||
|
||||
$consumer_key = ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'mpesa_till_consumer_key')
|
||||
->find_one();
|
||||
|
||||
$consumer_secret = ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'mpesa_till_consumer_secret')
|
||||
->find_one();
|
||||
|
||||
$consumer_secret = ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'mpesa_till_consumer_secret')
|
||||
->find_one();
|
||||
|
||||
$BusinessShortCode= ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'mpesa_till_shortcode_code')
|
||||
->find_one();
|
||||
|
||||
$PartyB= ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'mpesa_till_partyb')
|
||||
->find_one();
|
||||
|
||||
|
||||
$LipaNaMpesaPasskey= ORM::for_table('tbl_appconfig')
|
||||
->where('setting', 'mpesa_till_pass_key')
|
||||
->find_one();
|
||||
|
||||
|
||||
|
||||
$consumer_key = ($consumer_key) ? $consumer_key->value : null;
|
||||
$consumer_secret = ($consumer_secret) ? $consumer_secret->value : null;
|
||||
$BusinessShortCode = ($BusinessShortCode) ? $BusinessShortCode->value : null;
|
||||
$PartyB = ($PartyB) ? $PartyB->value : null;
|
||||
$LipaNaMpesaPasskey = ($LipaNaMpesaPasskey) ? $LipaNaMpesaPasskey->value : null;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$cburl = U . 'callback/MpesatillStk' ;
|
||||
|
||||
|
||||
//
|
||||
|
||||
$CheckId = ORM::for_table('tbl_customers')
|
||||
->where('username', $username)
|
||||
->order_by_desc('id')
|
||||
->find_one();
|
||||
|
||||
$CheckUser = ORM::for_table('tbl_customers')
|
||||
->where('phonenumber', $phone)
|
||||
->find_many();
|
||||
|
||||
$UserId=$CheckId->id;
|
||||
|
||||
|
||||
|
||||
$PaymentGatewayRecord = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $username)
|
||||
->where('status', 1) // Add this line to filter by status
|
||||
->order_by_desc('id')
|
||||
->find_one();
|
||||
|
||||
$ThisUser= ORM::for_table('tbl_customers')
|
||||
->where('username', $username)
|
||||
->order_by_desc('id')
|
||||
->find_one();
|
||||
|
||||
|
||||
|
||||
$ThisUser->phonenumber=$phone;
|
||||
// $ThisUser->username=$phone;
|
||||
$ThisUser->save();
|
||||
|
||||
|
||||
$amount=$PaymentGatewayRecord->price;
|
||||
|
||||
if(!$PaymentGatewayRecord){
|
||||
|
||||
echo $error="<script>toastr.success('Unable to proess payment, please reload the page');</script>";
|
||||
die();
|
||||
|
||||
}
|
||||
|
||||
|
||||
$TransactionType = 'CustomerBuyGoodsOnline';
|
||||
$tokenUrl = 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';
|
||||
$phone= $phone;
|
||||
$lipaOnlineUrl = 'https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest';
|
||||
// $amount= '1';
|
||||
$CallBackURL = $cburl;
|
||||
date_default_timezone_set('Africa/Nairobi');
|
||||
$timestamp = date("YmdHis");
|
||||
$password = base64_encode($BusinessShortCode . $LipaNaMpesaPasskey . $timestamp);
|
||||
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, $tokenUrl);
|
||||
$credentials = base64_encode($consumer_key . ':' . $consumer_secret);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Authorization: Basic ' . $credentials));
|
||||
curl_setopt($curl, CURLOPT_HEADER, false);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||
$curl_response = curl_exec($curl);
|
||||
|
||||
$token = json_decode($curl_response)->access_token;
|
||||
$curl2 = curl_init();
|
||||
curl_setopt($curl2, CURLOPT_URL, $lipaOnlineUrl);
|
||||
curl_setopt($curl2, CURLOPT_HTTPHEADER, array('Content-Type:application/json', 'Authorization:Bearer ' . $token));
|
||||
|
||||
|
||||
|
||||
$curl2_post_data = [
|
||||
'BusinessShortCode' => $BusinessShortCode,
|
||||
'Password' => $password,
|
||||
'Timestamp' => $timestamp,
|
||||
'TransactionType' => $TransactionType,
|
||||
'Amount' => $amount,
|
||||
'PartyA' => $phone,
|
||||
'PartyB' => $PartyB,
|
||||
'PhoneNumber' => $phone,
|
||||
'CallBackURL' => $CallBackURL,
|
||||
'AccountReference' => 'Payment For Goods',
|
||||
'TransactionDesc' => 'Payment for goods',
|
||||
];
|
||||
|
||||
$data2_string = json_encode($curl2_post_data);
|
||||
|
||||
curl_setopt($curl2, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl2, CURLOPT_POST, true);
|
||||
curl_setopt($curl2, CURLOPT_POSTFIELDS, $data2_string);
|
||||
curl_setopt($curl2, CURLOPT_HEADER, false);
|
||||
curl_setopt($curl2, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
curl_setopt($curl2, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
$curl_response = curl_exec($curl2);
|
||||
|
||||
$curl_response1 = curl_exec($curl);
|
||||
//($curl_response);
|
||||
|
||||
//echo $curl_response;
|
||||
|
||||
$mpesaResponse = json_decode($curl_response);
|
||||
|
||||
|
||||
//echo $phone;
|
||||
|
||||
$responseCode = $mpesaResponse->ResponseCode;
|
||||
$MerchantRequestID = $mpesaResponse->MerchantRequestID;
|
||||
$CheckoutRequestID = $mpesaResponse->CheckoutRequestID;
|
||||
$resultDesc = $mpesaResponse->CustomerMessage;
|
||||
// file_put_contents('stk.log',$curl_response,FILE_APPEND);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// echo $cburl;
|
||||
|
||||
$responseCode = $responseCode;
|
||||
if($responseCode=="0"){
|
||||
date_default_timezone_set('Africa/Nairobi');
|
||||
$now=date("Y-m-d H:i:s");
|
||||
|
||||
|
||||
// $username=$phone;
|
||||
|
||||
|
||||
$PaymentGatewayRecord->pg_paid_response = $resultDesc;
|
||||
$PaymentGatewayRecord->checkout = $CheckoutRequestID;
|
||||
$PaymentGatewayRecord->username = $username;
|
||||
$PaymentGatewayRecord->payment_method = 'Mpesa Stk Push';
|
||||
$PaymentGatewayRecord->payment_channel = 'Mpesa Stk Push';
|
||||
$PaymentGatewayRecord->save();
|
||||
|
||||
if(!empty($_POST['channel'])){
|
||||
|
||||
echo json_encode(["status" => "success", "message" => "Enter Pin to complete","phone"=> $phone]);
|
||||
|
||||
}else{
|
||||
echo $error="<script>toastr.success('Enter Mpesa Pin to complete');</script>";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}else{
|
||||
|
||||
echo "There is an issue with the transaction, please wait for 0 seconds then try again";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
46
system/plugin/log.php
Normal file
46
system/plugin/log.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
use PEAR2\Net\RouterOS;
|
||||
use PEAR2\Net\RouterOS\Client;
|
||||
use PEAR2\Net\RouterOS\Request;
|
||||
|
||||
// Fungsi untuk menampilkan log monitor
|
||||
register_menu("Router Logs", true, "log_ui", 'NETWORK');
|
||||
|
||||
function log_ui() {
|
||||
global $ui, $routes;
|
||||
_admin();
|
||||
$ui->assign('_title', 'Log Mikrotik');
|
||||
$ui->assign('_system_menu', 'Log Mikrotik');
|
||||
$admin = Admin::_info();
|
||||
$ui->assign('_admin', $admin);
|
||||
$routers = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
|
||||
$routerId = $routes['2'] ?? ($routers ? $routers[0]['id'] : null); // Memastikan ada router yang aktif
|
||||
$logs = fetchLogs($routerId); // Mengambil log dari router yang dipilih
|
||||
$ui->assign('logs', $logs);
|
||||
|
||||
$ui->display('log.tpl');
|
||||
}
|
||||
|
||||
// Fungsi untuk mengambil logs dari MikroTik
|
||||
function fetchLogs($routerId) {
|
||||
if (!$routerId) {
|
||||
return []; // Mengembalikan array kosong jika router tidak tersedia
|
||||
}
|
||||
|
||||
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($routerId);
|
||||
if (!$mikrotik) {
|
||||
return []; // Mengembalikan array kosong jika router tidak ditemukan
|
||||
}
|
||||
|
||||
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$request = new Request('/log/print');
|
||||
$response = $client->sendSync($request);
|
||||
|
||||
$logs = [];
|
||||
foreach ($response as $entry) {
|
||||
$logs[] = $entry->getIterator()->getArrayCopy(); // Mengumpulkan data dari setiap entry
|
||||
}
|
||||
|
||||
return $logs;
|
||||
}
|
||||
215022
system/plugin/oui_database.txt
Normal file
215022
system/plugin/oui_database.txt
Normal file
File diff suppressed because it is too large
Load Diff
418
system/plugin/pppoe_monitor.php
Normal file
418
system/plugin/pppoe_monitor.php
Normal file
@@ -0,0 +1,418 @@
|
||||
<?php
|
||||
|
||||
use PEAR2\Net\RouterOS;
|
||||
|
||||
|
||||
function pppoe()
|
||||
{
|
||||
global $ui, $routes;
|
||||
_admin();
|
||||
$ui->assign('_title', 'PPPoE Monitor');
|
||||
$ui->assign('_system_menu', 'PPPoE Monitor');
|
||||
$admin = Admin::_info();
|
||||
$ui->assign('_admin', $admin);
|
||||
$routers = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
|
||||
$router = $routes['2'] ?? $routers[0]['id'];
|
||||
$ui->assign('routers', $routers);
|
||||
$ui->assign('router', $router);
|
||||
$ui->assign('interfaces', pppoe_monitor_router_getInterface());
|
||||
|
||||
$ui->display('pppoe_monitor.tpl');
|
||||
}
|
||||
|
||||
function pppoe_monitor_router_getInterface()
|
||||
{
|
||||
global $routes;
|
||||
$routerId = $routes['2'] ?? null;
|
||||
|
||||
if (!$routerId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($routerId);
|
||||
|
||||
if (!$mikrotik) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$interfaces = $client->sendSync(new RouterOS\Request('/interface/print'));
|
||||
|
||||
$interfaceList = [];
|
||||
foreach ($interfaces as $interface) {
|
||||
$name = $interface->getProperty('name');
|
||||
$interfaceList[] = $name; // Jangan menghapus karakter < dan > dari nama interface
|
||||
}
|
||||
|
||||
return $interfaceList;
|
||||
}
|
||||
|
||||
function pppoe_get_combined_users() {
|
||||
global $routes;
|
||||
$router = $routes['2'];
|
||||
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($router);
|
||||
|
||||
if (!$mikrotik) {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['error' => 'Router not found']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
|
||||
// Fetch PPP online users
|
||||
$pppUsers = $client->sendSync(new RouterOS\Request('/ppp/active/print'));
|
||||
$interfaceTraffic = $client->sendSync(new RouterOS\Request('/interface/print'));
|
||||
$pppSecrets = $client->sendSync(new RouterOS\Request('/ppp/secret/print'));
|
||||
|
||||
|
||||
$interfaceData = [];
|
||||
foreach ($interfaceTraffic as $interface) {
|
||||
$name = $interface->getProperty('name');
|
||||
if (empty($name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$interfaceData[$name] = [
|
||||
'status' => $interface->getProperty('running') === 'true' ? 'Connected' : 'Disconnected',
|
||||
'txBytes' => intval($interface->getProperty('tx-byte')),
|
||||
'rxBytes' => intval($interface->getProperty('rx-byte')),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
$pppUserList = [];
|
||||
foreach ($pppUsers as $pppUser) {
|
||||
$username = $pppUser->getProperty('name');
|
||||
if (empty($username)) {
|
||||
continue;
|
||||
}
|
||||
$address = $pppUser->getProperty('address');
|
||||
$uptime = $pppUser->getProperty('uptime');
|
||||
$service = $pppUser->getProperty('service');
|
||||
$callerid = $pppUser->getProperty('caller-id');
|
||||
$bytes_in = $pppUser->getProperty('limit-bytes-in');
|
||||
$bytes_out = $pppUser->getProperty('limit-bytes-out');
|
||||
$id = $pppUser->getProperty('.id');
|
||||
|
||||
$interfaceName = "<pppoe-$username>";
|
||||
|
||||
if (isset($interfaceData[$interfaceName])) {
|
||||
$trafficData = $interfaceData[$interfaceName];
|
||||
$txBytes = $trafficData['txBytes'];
|
||||
$rxBytes = $trafficData['rxBytes'];
|
||||
$status = $trafficData['status'];
|
||||
} else {
|
||||
$txBytes = 0;
|
||||
$rxBytes = 0;
|
||||
$status = 'Disconnected';
|
||||
}
|
||||
|
||||
// Get device information
|
||||
$manufacturer = "Unknown";
|
||||
if ($callerid) {
|
||||
$manufacturer = get_manufacturer_from_mac($callerid);
|
||||
}
|
||||
|
||||
// Check if MAC is bound in ppp secrets
|
||||
$isBound = false;
|
||||
foreach ($pppSecrets as $secret) {
|
||||
if ($secret->getProperty('name') === $username && $secret->getProperty('caller-id') === $callerid) {
|
||||
$isBound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$pppUserList[$username] = [
|
||||
'id' => $id,
|
||||
'username' => $username,
|
||||
'address' => $address,
|
||||
'uptime' => $uptime,
|
||||
'service' => $service,
|
||||
'caller_id' => $callerid,
|
||||
'bytes_in' => $bytes_in,
|
||||
'bytes_out' => $bytes_out,
|
||||
'tx' => pppoe_monitor_router_formatBytes($txBytes),
|
||||
'rx' => pppoe_monitor_router_formatBytes($rxBytes),
|
||||
'total' => pppoe_monitor_router_formatBytes($txBytes + $rxBytes),
|
||||
'status' => $status,
|
||||
'manufacturer' => $manufacturer,
|
||||
'is_bound' => $isBound
|
||||
];
|
||||
}
|
||||
|
||||
// Convert the user list to a regular array for JSON encoding
|
||||
$userList = array_values($pppUserList);
|
||||
|
||||
// Return the combined user list as JSON
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($userList);
|
||||
} catch (Exception $e) {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
function get_manufacturer_from_mac($mac_address) {
|
||||
// Normalize the MAC address
|
||||
$mac_address = strtoupper(preg_replace('/[^A-F0-9]/', '', $mac_address));
|
||||
|
||||
// Check if MAC address is valid (at least 6 hex characters required)
|
||||
if (strlen($mac_address) < 6) {
|
||||
return 'Invalid MAC address';
|
||||
}
|
||||
|
||||
// Construct the API URL
|
||||
$url = "https://www.macvendorlookup.com/api/v2/{$mac_address}";
|
||||
|
||||
// Initialize cURL session
|
||||
$ch = curl_init();
|
||||
|
||||
// Set cURL options
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // For testing purposes, handle SSL properly in production
|
||||
|
||||
// Execute cURL request
|
||||
$response = curl_exec($ch);
|
||||
|
||||
// Check for cURL errors
|
||||
if (curl_errno($ch)) {
|
||||
$error = curl_error($ch);
|
||||
curl_close($ch);
|
||||
return "Error: $error";
|
||||
}
|
||||
|
||||
// Get HTTP response code
|
||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
// Check if API returned a valid response
|
||||
if ($http_code === 204) {
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
// Decode JSON response
|
||||
$data = json_decode($response, true);
|
||||
|
||||
// Check if the response contains manufacturer information
|
||||
if (isset($data[0]['company'])) {
|
||||
return trim($data[0]['company']);
|
||||
} else {
|
||||
return 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
function pppoe_monitor_router_formatMaxLimit($max_limit) {
|
||||
$limits = explode('/', $max_limit);
|
||||
if (count($limits) == 2) {
|
||||
$downloadLimit = intval($limits[0]);
|
||||
$uploadLimit = intval($limits[1]);
|
||||
$formattedDownloadLimit = ceil($downloadLimit / (1024 * 1024)) . ' MB';
|
||||
$formattedUploadLimit = ceil($uploadLimit / (1024 * 1024)) . ' MB';
|
||||
return $formattedDownloadLimit . '/' . $formattedUploadLimit;
|
||||
}
|
||||
return 'N/A';
|
||||
}
|
||||
|
||||
// Fungsi untuk menghitung total data yang digunakan per harinya
|
||||
|
||||
function pppoe_monitor_router_formatBytes($bytes, $precision = 2)
|
||||
{
|
||||
$units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
$bytes = max($bytes, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
$bytes /= pow(1024, $pow);
|
||||
return round($bytes, $precision) . ' ' . $units[$pow];
|
||||
}
|
||||
|
||||
function pppoe_monitor_router_traffic()
|
||||
{
|
||||
$interface = $_GET["interface"]; // Ambil interface dari parameter GET
|
||||
|
||||
// Contoh koneksi ke MikroTik menggunakan library tertentu (misalnya menggunakan ORM dan MikroTik API wrapper)
|
||||
global $routes;
|
||||
$router = $routes['2'];
|
||||
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($router);
|
||||
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
|
||||
try {
|
||||
$results = $client->sendSync(
|
||||
(new RouterOS\Request('/interface/monitor-traffic'))
|
||||
->setArgument('interface', $interface)
|
||||
->setArgument('once', '')
|
||||
);
|
||||
|
||||
$rows = array();
|
||||
$rows2 = array();
|
||||
$labels = array();
|
||||
|
||||
foreach ($results as $result) {
|
||||
$ftx = $result->getProperty('tx-bits-per-second');
|
||||
$frx = $result->getProperty('rx-bits-per-second');
|
||||
|
||||
// Timestamp dalam milidetik (millisecond)
|
||||
$timestamp = time() * 1000;
|
||||
|
||||
$rows[] = $ftx;
|
||||
$rows2[] = $frx;
|
||||
$labels[] = $timestamp; // Tambahkan timestamp ke dalam array labels
|
||||
}
|
||||
|
||||
$result = array(
|
||||
'labels' => $labels,
|
||||
'rows' => array(
|
||||
'tx' => $rows,
|
||||
'rx' => $rows2
|
||||
)
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => $e->getMessage());
|
||||
}
|
||||
|
||||
// Set header untuk respons JSON
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($result);
|
||||
}
|
||||
|
||||
function pppoe_monitor_router_online()
|
||||
{
|
||||
global $routes;
|
||||
$router = $routes['2'];
|
||||
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($router);
|
||||
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$pppUsers = $client->sendSync(new RouterOS\Request('/ppp/active/print'));
|
||||
|
||||
$pppoeInterfaces = [];
|
||||
|
||||
foreach ($pppUsers as $pppUser) {
|
||||
$username = $pppUser->getProperty('name');
|
||||
$interfaceName = "<pppoe-$username>"; // Tambahkan karakter < dan >
|
||||
|
||||
// Ensure interface name is not empty and it's not already in the list
|
||||
if (!empty($interfaceName) && !in_array($interfaceName, $pppoeInterfaces)) {
|
||||
$pppoeInterfaces[] = $interfaceName;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the list of PPPoE interfaces
|
||||
return $pppoeInterfaces;
|
||||
}
|
||||
|
||||
function pppoe_monitor_router_delete_ppp_user()
|
||||
{
|
||||
global $routes;
|
||||
$router = $routes['2'];
|
||||
$id = $_POST['id']; // Ambil .id dari POST data
|
||||
|
||||
// Cek apakah ID ada di POST data
|
||||
if (empty($id)) {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'ID is missing.']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ambil detail router dari database
|
||||
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($router);
|
||||
|
||||
if (!$mikrotik) {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'Router not found.']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Dapatkan klien MikroTik
|
||||
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
|
||||
if (!$client) {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'Failed to connect to the router.']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Buat permintaan untuk menghapus koneksi aktif PPPoE
|
||||
$request = new RouterOS\Request('/ppp/active/remove');
|
||||
$request->setArgument('.id', $id); // Gunakan .id yang sesuai
|
||||
$client->sendSync($request);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => true, 'message' => 'PPPoE user successfully deleted.']);
|
||||
} catch (Exception $e) {
|
||||
// Log error untuk debugging
|
||||
error_log('Failed to delete PPPoE user: ' . $e->getMessage());
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'Failed to delete PPPoE user: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// NEW FUNCTIONS:
|
||||
|
||||
// Fungsi untuk menghitung total data yang digunakan per harinya
|
||||
function pppoe_monitor_router_daily_data_usage()
|
||||
{
|
||||
global $routes;
|
||||
$router = $routes['2'];
|
||||
$mikrotik = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($router);
|
||||
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
|
||||
// Ambil semua pengguna aktif PPPoE
|
||||
$pppUsers = $client->sendSync(new RouterOS\Request('/ppp/active/print'));
|
||||
$interfaceTraffic = $client->sendSync(new RouterOS\Request('/interface/print'));
|
||||
|
||||
// Array untuk menyimpan data penggunaan harian
|
||||
$daily_usage = [];
|
||||
|
||||
// Looping untuk setiap pengguna PPPoE
|
||||
foreach ($pppUsers as $pppUser) {
|
||||
$username = $pppUser->getProperty('name');
|
||||
$interfaceName = "<pppoe-$username>"; // Nama interface sesuai format PPPoE
|
||||
|
||||
// Ambil data traffic untuk interface ini
|
||||
$interfaceData = [];
|
||||
foreach ($interfaceTraffic as $interface) {
|
||||
$name = $interface->getProperty('name');
|
||||
if ($name === $interfaceName) {
|
||||
$interfaceData = [
|
||||
'txBytes' => intval($interface->getProperty('tx-byte')),
|
||||
'rxBytes' => intval($interface->getProperty('rx-byte'))
|
||||
];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Hitung total penggunaan harian
|
||||
$txBytes = $interfaceData['txBytes'] ?? 0;
|
||||
$rxBytes = $interfaceData['rxBytes'] ?? 0;
|
||||
$totalDataMB = ($txBytes + $rxBytes) / (1024 * 1024); // Konversi ke MB
|
||||
|
||||
// Ambil tanggal dari waktu saat ini
|
||||
$date = date('Y-m-d', time());
|
||||
|
||||
// Jika belum ada data untuk tanggal ini, inisialisasi
|
||||
if (!isset($daily_usage[$date])) {
|
||||
$daily_usage[$date] = [
|
||||
'total' => 0,
|
||||
'users' => []
|
||||
];
|
||||
}
|
||||
|
||||
// Tambahkan penggunaan harian untuk pengguna ini
|
||||
$daily_usage[$date]['total'] += $totalDataMB;
|
||||
$daily_usage[$date]['users'][] = [
|
||||
'username' => $username,
|
||||
'tx' => pppoe_monitor_router_formatBytes($txBytes),
|
||||
'rx' => pppoe_monitor_router_formatBytes($rxBytes),
|
||||
'total' => pppoe_monitor_router_formatBytes($txBytes + $rxBytes)
|
||||
];
|
||||
}
|
||||
|
||||
// Kembalikan hasil dalam format JSON
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($daily_usage); // $daily_usage adalah array yang berisi data harian dalam format yang sesuai
|
||||
}
|
||||
// Fungsi untuk mendapatkan pengguna terbatas pada MikroTik
|
||||
BIN
system/plugin/user.png
Normal file
BIN
system/plugin/user.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 281 KiB |
Reference in New Issue
Block a user