Merge pull request #18 from hotspotbilling/Development

Plugin Installer
This commit is contained in:
iBNu Maksum 2023-03-08 13:03:57 +07:00 committed by GitHub
commit b0cac9510d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 628 additions and 179 deletions

View File

@ -23,6 +23,8 @@ Click link to download
Goto Discussionif you want another Payment Gateway
Some documentation
## System Requirements
Most current web servers with PHP & MySQL installed will be capable of running PHPNuxBill
@ -30,7 +32,7 @@ Most current web servers with PHP & MySQL installed will be capable of running P
Minimum Requirements
- Linux or Windows OS
- PHP Version 7.0+
- PHP Version 7.2+
- Both PDO & MySQLi Support
- GD2 Image Library
- CURL support
@ -42,17 +44,51 @@ The problem with windows is hard to set cronjob, better Linux
## Installation
- Rename **pages_template** to **pages**
- Rename **config.sample.php** to **config.php** and make it writeable (chmod 777)
- make writeable folder **ui/cache/** and **ui/compiled**
- Open web and run installation
- set cronjobs or scheduller for **system/cron.php**
- make **config.php** unwriteable (chmod 644)
### Git Clone
clone this repository or download zip or release
See [WIKI](https://github.com/hotspotbilling/phpnuxbill/wiki/Instalation)
1. Rename **pages_template** to **pages**
2. Rename **config.sample.php** to **config.php** and make it writeable (chmod 777)
3. make writeable folder **ui/cache/** and **ui/compiled**
4. Open web and run installation
5. set [cronjob](https://github.com/hotspotbilling/phpnuxbill/wiki/Cron-Jobs) or scheduller for **system/cron.php**
6. make **config.php** unwriteable (chmod 644)
baca [WIKI](https://github.com/hotspotbilling/phpnuxbill/wiki/Instalation)
### Composer install
Go to directory you want to install
Install Composer in your system
```bash
# Debian/Ubuntu
sudo apt install composer
# Centos/Redhat
sudo yum install composer
```
install on curent directory
```bash
composer create-project hotspotbilling/phpnuxbill .
```
install on new directory
```bash
composer create-project hotspotbilling/phpnuxbill phpnuxbill
```
## Manual Installation
1. Download project from [Master Branch](https://github.com/hotspotbilling/phpnuxbill/archive/refs/heads/master.zip) or from [Release](https://github.com/hotspotbilling/phpnuxbill/releases)
2. unzip and upload it to server
3. Rename **pages_template** to **pages**
4. Rename **config.sample.php** to **config.php** and make it writeable (chmod 777)
5. make writeable folder **ui/cache/** and **ui/compiled**
6. Open web and run installation
7. set [cronjob](https://github.com/hotspotbilling/phpnuxbill/wiki/Cron-Jobs) or scheduller for **system/cron.php**
8. make **config.php** unwriteable (chmod 644)
## UPDGRADE
@ -60,9 +96,12 @@ for old version, below Version 6, backup **system/config.php**, delete all file
for version 6 above, just replace all files, using filezilla can choose overwrite if different file size or time.
or git pull if you use git clone
## RADIUS system
Still on development
## Paid Support
Start from Rp 500.000 or $50

16
composer.json Normal file
View File

@ -0,0 +1,16 @@
{
"name": "hotspotbilling/phpnuxbill",
"type": "template",
"description": "PHPNuxBill a Hotspot Billing Software.",
"keywords": ["template"],
"homepage": "https://github.com/hotspotbilling/phpnuxbill",
"license": "MIT",
"authors": [
{
"name": "ibnux",
"email": "me@ibnux.net",
"homepage": "https://ibnux.net",
"role": "Developer"
}
]
}

View File

@ -3,7 +3,7 @@
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
**/
Class App{
class App{
public static function _run(){
return true;
}

56
system/autoload/File.php Normal file
View File

@ -0,0 +1,56 @@
<?php
class File
{
public static function copyFolder($from, $to, $exclude = [])
{
echo "copyFolder($from, $to);<br>";
$files = scandir($from);
print_r($files);
foreach ($files as $file) {
if (is_file($from . $file) && !in_array($file, $exclude)) {
if (file_exists($to . $file)) unlink($to . $file);
rename($from . $file, $to . $file);
echo "rename($from$file, $to$file);<br>";
} else if (is_dir($from . $file) && !in_array($file, ['.', '..'])) {
if (!file_exists($to . $file)) {
echo "mkdir($to$file);;<br>";
mkdir($to . $file);
}
echo "File::copyFolder($from$file, $to$file);<br>";
File::copyFolder($from . $file . DIRECTORY_SEPARATOR, $to . $file . DIRECTORY_SEPARATOR);
}
}
}
public static function deleteFolder($path)
{
$files = scandir($path);
foreach ($files as $file) {
if (is_file($path . $file)) {
echo "unlink($path$file);<br>";
unlink($path . $file);
} else if (is_dir($path . $file) && !in_array($file, ['.', '..'])) {
File::deleteFolder($path . $file . DIRECTORY_SEPARATOR);
echo "rmdir($path$file);<br>";
rmdir($path . $file);
}
}
echo "rmdir($path);<br>";
rmdir($path);
}
/**
* file path fixer
*
* @access public
* @param string $path
* @return string
*/
public static function pathFixer($path)
{
return str_replace("/", DIRECTORY_SEPARATOR, $path);
}
}

View File

@ -8,4 +8,8 @@ class Lang {
public static function T($var) {
return Lang($var);
}
public static function htmlspecialchars($var) {
return htmlspecialchars($var);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
**/
class Message
{
public static function sendTelegram($txt)
{
global $config;
run_hook('send_telegram'); #HOOK
if (!empty($config['telegram_bot']) && !empty($config['telegram_target_id'])) {
file_get_contents('https://api.telegram.org/bot' . $config['telegram_bot'] . '/sendMessage?chat_id=' . $config['telegram_target_id'] . '&text=' . urlencode($txt));
}
}
public static function sendSMS($phone, $txt)
{
global $config;
run_hook('send_sms'); #HOOK
if (!empty($config['sms_url'])) {
$smsurl = str_replace('[number]', urlencode($phone), $config['sms_url']);
$smsurl = str_replace('[text]', urlencode($txt), $smsurl);
file_get_contents($smsurl);
}
}
public static function sendWhatsapp($phone, $txt)
{
global $config;
run_hook('send_whatsapp'); #HOOK
if (!empty($config['wa_url'])) {
$waurl = str_replace('[number]', urlencode($phone), $config['wa_url']);
$waurl = str_replace('[text]', urlencode($txt), $waurl);
file_get_contents($waurl);
}
}
public static function sendExpiredNotification($phone, $name, $package, $textExpired, $via)
{
if (
!empty($phone) && strlen($phone) > 5
&& !empty($textExpired) && in_array($via, ['sms', 'wa'])
) {
$msg = str_replace('[[name]]', "*$name*", $textExpired);
$msg = str_replace('[[package]]', "*$package*", $msg);
if ($via == 'sms') {
Message::sendSMS($phone, $msg);
} else if ($via == 'wa') {
Message::sendWhatsapp($phone, $msg);
}
}
}
}

View File

@ -51,8 +51,8 @@ class Package
if ($b) {
if (!$_c['radius_mode']) {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::removeHotspotUser($client,$c['username']);
Mikrotik::addHotspotUser($client,$p,$c);
Mikrotik::removeHotspotUser($client, $c['username']);
Mikrotik::addHotspotUser($client, $p, $c);
}
$b->customer_id = $id_customer;
@ -84,7 +84,7 @@ class Package
} else {
if (!$_c['radius_mode']) {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::addHotspotUser($client,$p,$c);
Mikrotik::addHotspotUser($client, $p, $c);
}
$d = ORM::for_table('tbl_user_recharges')->create();
@ -115,7 +115,7 @@ class Package
$t->type = "Hotspot";
$t->save();
}
sendTelegram("#u$c[username] #buy #Hotspot \n" . $p['name_plan'] .
Message::sendTelegram("#u$c[username] #buy #Hotspot \n" . $p['name_plan'] .
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
@ -125,8 +125,8 @@ class Package
if ($b) {
if (!$_c['radius_mode']) {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::removePpoeUser($client,$c['username']);
Mikrotik::addPpoeUser($client,$p,$c);
Mikrotik::removePpoeUser($client, $c['username']);
Mikrotik::addPpoeUser($client, $p, $c);
}
$b->customer_id = $id_customer;
@ -158,7 +158,7 @@ class Package
} else {
if (!$_c['radius_mode']) {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::addPpoeUser($client,$p,$c);
Mikrotik::addPpoeUser($client, $p, $c);
}
$d = ORM::for_table('tbl_user_recharges')->create();
@ -189,7 +189,7 @@ class Package
$t->type = "PPPOE";
$t->save();
}
sendTelegram("#u$c[username] #buy #PPPOE \n" . $p['name_plan'] .
Message::sendTelegram("#u$c[username] #buy #PPPOE \n" . $p['name_plan'] .
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
@ -198,7 +198,7 @@ class Package
$in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one();
sendWhatsapp($c['username'], "*$_c[CompanyName]*\n" .
$msg = "*$_c[CompanyName]*\n" .
"$_c[address]\n" .
"$_c[phone]\n" .
"\n\n" .
@ -214,7 +214,13 @@ class Package
"$_L[Created_On] :\n*" . date($_c['date_format'], strtotime($in['recharged_on'])) . " $in[time]*\n" .
"$_L[Expires_On] :\n*" . date($_c['date_format'], strtotime($in['expiration'])) . " $in[time]*\n" .
"\n\n" .
"$_c[note]");
"$_c[note]";
if ($_c['user_notification_payment'] == 'sms') {
Message::sendSMS($c['phonenumber'], $msg);
} else if ($_c['user_notification_payment'] == 'wa') {
Message::sendWhatsapp($c['phonenumber'], $msg);
}
return true;
}
}

View File

@ -1,12 +1,14 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
**/
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
**/
/**
* Validator class
*/
class Validator{
class Validator
{
/**
* String text finder
@ -16,14 +18,15 @@ class Validator{
* @param array $hits
* @return void
*/
private static function textHit($string, $exclude=""){
if(empty($exclude)) return false;
if(is_array($exclude)){
foreach($exclude as $text){
if(strstr($string, $text)) return true;
private static function textHit($string, $exclude = "")
{
if (empty($exclude)) return false;
if (is_array($exclude)) {
foreach ($exclude as $text) {
if (strstr($string, $text)) return true;
}
}else{
if(strstr($string, $exclude)) return true;
} else {
if (strstr($string, $exclude)) return true;
}
return false;
}
@ -37,9 +40,10 @@ class Validator{
* @param int $min
* @return bool
*/
private static function numberBetween($integer, $max=null, $min=0){
if(is_numeric($min) && $integer <= $min) return false;
if(is_numeric($max) && $integer >= $max) return false;
private static function numberBetween($integer, $max = null, $min = 0)
{
if (is_numeric($min) && $integer <= $min) return false;
if (is_numeric($max) && $integer >= $max) return false;
return true;
}
@ -51,8 +55,9 @@ class Validator{
* @param array $exclude
* @return bool
*/
public static function Email($string, $exclude=""){
if(self::textHit($string, $exclude)) return false;
public static function Email($string, $exclude = "")
{
if (self::textHit($string, $exclude)) return false;
return (bool)preg_match("/^([a-z0-9])(([-a-z0-9._])*([a-z0-9]))*\@([a-z0-9])(([a-z0-9-])*([a-z0-9]))+(\.([a-z0-9])([-a-z0-9_-])?([a-z0-9])+)+$/i", $string);
}
@ -63,8 +68,9 @@ class Validator{
* @param strin $string
* @return bool
*/
public static function Url($string, $exclude=""){
if(self::textHit($string, $exclude)) return false;
public static function Url($string, $exclude = "")
{
if (self::textHit($string, $exclude)) return false;
return (bool)preg_match("/^(http|https|ftp):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i", $string);
}
@ -75,7 +81,8 @@ class Validator{
* @param string $string
* @return void
*/
public static function Ip($string){
public static function Ip($string)
{
return (bool)preg_match("/^(1?\d{1,2}|2([0-4]\d|5[0-5]))(\.(1?\d{1,2}|2([0-4]\d|5[0-5]))){3}$/", $string);
}
@ -88,9 +95,10 @@ class Validator{
* @param int $min
* @return bool
*/
public static function Number($integer, $max=null, $min=0){
if(preg_match("/^\-?\+?[0-9e1-9]+$/",$integer)){
if(!self::numberBetween($integer, $max, $min)) return false;
public static function Number($integer, $max = null, $min = 0)
{
if (preg_match("/^\-?\+?[0-9e1-9]+$/", $integer)) {
if (!self::numberBetween($integer, $max, $min)) return false;
return true;
}
return false;
@ -103,8 +111,9 @@ class Validator{
* @param int $integer
* @return bool
*/
public static function UnsignedNumber($integer){
return (bool)preg_match("/^\+?[0-9]+$/",$integer);
public static function UnsignedNumber($integer)
{
return (bool)preg_match("/^\+?[0-9]+$/", $integer);
}
/**
@ -114,8 +123,9 @@ class Validator{
* @param string $string
* @return bool
*/
public static function Float($string){
return (bool)($string==strval(floatval($string)))? true : false;
public static function Float($string)
{
return (bool)($string == strval(floatval($string))) ? true : false;
}
/**
@ -125,7 +135,8 @@ class Validator{
* @param string $string
* @return void
*/
public static function Alpha($string){
public static function Alpha($string)
{
return (bool)preg_match("/^[a-zA-Z]+$/", $string);
}
@ -136,7 +147,8 @@ class Validator{
* @param string $string
* @return void
*/
public static function AlphaNumeric($string){
public static function AlphaNumeric($string)
{
return (bool)preg_match("/^[0-9a-zA-Z]+$/", $string);
}
@ -148,7 +160,8 @@ class Validator{
* @param array $allowed
* @return void
*/
public static function Chars($string, $allowed=array("a-z")){
public static function Chars($string, $allowed = array("a-z"))
{
return (bool)preg_match("/^[" . implode("", $allowed) . "]+$/", $string);
}
@ -161,9 +174,10 @@ class Validator{
* @param int $min
* @return bool
*/
public static function Length($string, $max=null, $min=0){
public static function Length($string, $max = null, $min = 0)
{
$length = strlen($string);
if(!self::numberBetween($length, $max, $min)) return false;
if (!self::numberBetween($length, $max, $min)) return false;
return true;
}
@ -174,7 +188,8 @@ class Validator{
* @param string $string
* @return void
*/
public static function HexColor($string){
public static function HexColor($string)
{
return (bool)preg_match("/^(#)?([0-9a-f]{1,2}){3}$/i", $string);
}
@ -191,7 +206,8 @@ class Validator{
* @param string $string
* @return bool
*/
public static function Date($string){
public static function Date($string)
{
$date = date('Y', strtotime($string));
return ($date == "1970" || $date == '') ? false : true;
}
@ -204,9 +220,10 @@ class Validator{
* @param int $age
* @return bool
*/
public static function OlderThan($string, $age){
public static function OlderThan($string, $age)
{
$date = date('Y', strtotime($string));
if($date == "1970" || $date == '') return false;
if ($date == "1970" || $date == '') return false;
return (date('Y') - $date) > $age ? true : false;
}
@ -217,7 +234,8 @@ class Validator{
* @param string $string
* @return bool
*/
public static function Xml($string){
public static function Xml($string)
{
$Xml = @simplexml_load_string($string);
return ($Xml === false) ? false : true;
}
@ -231,7 +249,8 @@ class Validator{
* @param int $min
* @return bool
*/
public static function FilesizeBetween($file, $max=null, $min=0){
public static function FilesizeBetween($file, $max = null, $min = 0)
{
$filesize = filesize($file);
return self::numberBetween($filesize, $max, $min);
}
@ -247,10 +266,11 @@ class Validator{
* @param int $min_height
* @return void
*/
public static function ImageSizeBetween($image, $max_width="", $min_width=0, $max_height="", $min_height=0){
public static function ImageSizeBetween($image, $max_width = "", $min_width = 0, $max_height = "", $min_height = 0)
{
$size = getimagesize($image);
if(!self::numberBetween($size[0], $max_width, $min_width)) return false;
if(!self::numberBetween($size[1], $max_height, $min_height)) return false;
if (!self::numberBetween($size[0], $max_width, $min_width)) return false;
if (!self::numberBetween($size[1], $max_height, $min_height)) return false;
return true;
}
@ -261,8 +281,10 @@ class Validator{
* @param string $phone
* @return bool
*/
public static function Phone($phone){
$formats = array( '###-###-####',
public static function Phone($phone)
{
$formats = array(
'###-###-####',
'####-###-###',
'(###) ###-###',
'####-####-####',
@ -271,9 +293,10 @@ class Validator{
'###-###-###',
'#####-###-###',
'##########',
'####-##-##-##');
'####-##-##-##'
);
$format = trim(preg_replace("/[0-9]/", "#", $phone));
return (bool)in_array($format, $formats);
}
}
}

View File

@ -228,40 +228,6 @@ function alphanumeric($str, $tambahan = "")
return preg_replace("/[^a-zA-Z0-9" . $tambahan . "]+/", "", $str);
}
function sendTelegram($txt)
{
global $config;
run_hook('send_telegram'); #HOOK
if (!empty($config['telegram_bot']) && !empty($config['telegram_target_id'])) {
file_get_contents('https://api.telegram.org/bot' . $config['telegram_bot'] . '/sendMessage?chat_id=' . $config['telegram_target_id'] . '&text=' . urlencode($txt));
}
}
function sendSMS($phone, $txt)
{
global $config;
run_hook('send_sms'); #HOOK
if (!empty($config['sms_url'])) {
$smsurl = str_replace('[number]', urlencode($phone), $config['sms_url']);
$smsurl = str_replace('[text]', urlencode($txt), $smsurl);
file_get_contents($smsurl);
}
}
function sendWhatsapp($phone, $txt)
{
global $config;
run_hook('send_whatsapp'); #HOOK
if (!empty($config['wa_url'])) {
$waurl = str_replace('[number]', urlencode($phone), $config['wa_url']);
$waurl = str_replace('[text]', urlencode($txt), $waurl);
file_get_contents($waurl);
}
}
function time_elapsed_string($datetime, $full = false)
{
$now = new DateTime;

View File

@ -79,6 +79,7 @@ switch ($action) {
try {
$d->delete();
} catch (Exception $e) {
} catch(Throwable $e){
}
try {
$c->delete();
@ -88,10 +89,12 @@ switch ($action) {
try {
$d->delete();
} catch (Exception $e) {
} catch(Throwable $e){
}
try {
$c->delete();
} catch (Exception $e) {
} catch(Throwable $e){
}
}

View File

@ -0,0 +1,124 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
**/
_admin();
$ui->assign('_title', $_L['Plugin Manager']);
$ui->assign('_system_menu', 'settings');
$plugin_repository = 'https://hotspotbilling.github.io/Plugin-Repository/repository.json';
$action = $routes['1'];
$admin = Admin::_info();
$ui->assign('_admin', $admin);
if ($admin['user_type'] != 'Admin') {
r2(U . "dashboard", 'e', $_L['Do_Not_Access']);
}
$cache = File::pathFixer('system/cache/plugin_repository.json');
if (file_exists($cache) && time() - filemtime($cache) > (24 * 60 * 60)) {
$json = json_decode(file_get_contents($cache), true);
} else {
$data = file_get_contents($plugin_repository);
file_put_contents($cache, $data);
$json = json_decode($data, true);
}
switch ($action) {
case 'install':
if(!is_writeable(File::pathFixer('system/cache/'))){
r2(U . "pluginmanager", 'e', 'Folder system/cache/ is not writable');
}
if(!is_writeable(File::pathFixer('system/plugin/'))){
r2(U . "pluginmanager", 'e', 'Folder system/plugin/ is not writable');
}
set_time_limit(-1);
$tipe = $routes['2'];
$plugin = $routes['3'];
$file = File::pathFixer('system/cache/') . $plugin . '.zip';
if (file_exists($file)) unlink($file);
if ($tipe == 'plugin') {
foreach ($json['plugins'] as $plg) {
if ($plg['id'] == $plugin) {
$fp = fopen($file, 'w+');
$ch = curl_init($plg['github'].'/archive/refs/heads/master.zip');
curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_exec($ch);
curl_close($ch);
fclose($fp);
$zip = new ZipArchive();
$zip->open($file);
$zip->extractTo(File::pathFixer('system/cache/'));
$zip->close();
$folder = File::pathFixer('system/cache/' . $plugin.'-main/');
if(!file_exists($folder)){
$folder = File::pathFixer('system/cache/' . $plugin.'-master/');
}
if(!file_exists($folder)){
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
}
File::copyFolder($folder, File::pathFixer('system/plugin/'), ['README.md','LICENSE']);
File::deleteFolder($folder);
unlink($file);
r2(U . "pluginmanager", 's', 'Plugin '.$plugin.' has been installed');
break;
}
}
break;
} else if ($tipe == 'payment') {
foreach ($json['payment_gateway'] as $plg) {
if ($plg['id'] == $plugin) {
$fp = fopen($file, 'w+');
$ch = curl_init($plg['github'].'/archive/refs/heads/master.zip');
curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_exec($ch);
curl_close($ch);
fclose($fp);
$zip = new ZipArchive();
$zip->open($file);
$zip->extractTo(File::pathFixer('system/cache/'));
$zip->close();
$folder = File::pathFixer('system/cache/' . $plugin.'-main/');
if(!file_exists($folder)){
$folder = File::pathFixer('system/cache/' . $plugin.'-master/');
}
if(!file_exists($folder)){
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
}
File::copyFolder($folder, File::pathFixer('system/paymentgateway/'), ['README.md','LICENSE']);
File::deleteFolder($folder);
unlink($file);
r2(U . "paymentgateway", 's', 'Payment Gateway '.$plugin.' has been installed');
break;
}
}
break;
}
default:
if (class_exists('ZipArchive')) {
$zipExt = true;
} else {
$zipExt = false;
}
$ui->assign('zipExt', $zipExt);
$ui->assign('plugins', $json['plugins']);
$ui->assign('pgs', $json['payment_gateway']);
$ui->display('plugin-manager.tpl');
}

View File

@ -169,7 +169,7 @@ switch ($action) {
$t->type = "Hotspot";
$t->save();
}
sendTelegram( "$admin[fullname] #Recharge Voucher #Hotspot for #u$c[username]\n".$p['name_plan'].
Message::sendTelegram( "$admin[fullname] #Recharge Voucher #Hotspot for #u$c[username]\n".$p['name_plan'].
"\nRouter: ".$server.
"\nPrice: ".$p['price']);
} else {
@ -241,7 +241,7 @@ switch ($action) {
$t->type = "PPPOE";
$t->save();
}
sendTelegram( "$admin[fullname] #Recharge Voucher #PPPOE for #u$c[username]\n".$p['name_plan'].
Message::sendTelegram( "$admin[fullname] #Recharge Voucher #PPPOE for #u$c[username]\n".$p['name_plan'].
"\nRouter: ".$server.
"\nPrice: ".$p['price']);
}
@ -249,7 +249,7 @@ switch ($action) {
$in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one();
$ui->assign('in', $in);
sendWhatsapp($c['username'], "*$config[CompanyName]*\n".
$msg = "*$config[CompanyName]*\n".
"$config[address]\n".
"$config[phone]\n".
"\n\n".
@ -265,8 +265,13 @@ switch ($action) {
"$_L[Created_On] :\n*".date($config['date_format'], strtotime($in['recharged_on']))." $in[time]*\n".
"$_L[Expires_On] :\n*".date($config['date_format'], strtotime($in['expiration']))." $in[time]*\n".
"\n\n".
"$config[note]");
"$config[note]";
if ($_c['user_notification_payment'] == 'sms') {
Message::sendSMS($c['phonenumber'], $msg);
} else if ($_c['user_notification_payment'] == 'wa') {
Message::sendWhatsapp($c['phonenumber'], $msg);
}
$ui->assign('date', $date_now);
$ui->display('invoice.tpl');
@ -631,7 +636,7 @@ switch ($action) {
$v1->user = $c['username'];
$v1->save();
sendTelegram( "$admin[fullname] #Refill #Voucher #Hotspot for #u$c[username]\n".$p['name_plan'].
Message::sendTelegram( "$admin[fullname] #Refill #Voucher #Hotspot for #u$c[username]\n".$p['name_plan'].
"\nCode: ".$code.
"\nRouter: ".$v1['routers'].
"\nPrice: ".$p['price']);
@ -709,7 +714,7 @@ switch ($action) {
$v1->save();
sendTelegram( "$admin[fullname] Refill #Voucher #PPPOE for #u$c[username]\n".$p['name_plan'].
Message::sendTelegram( "$admin[fullname] Refill #Voucher #PPPOE for #u$c[username]\n".$p['name_plan'].
"\nCode: ".$code.
"\nRouter: ".$v1['routers'].
"\nPrice: ".$p['price']);
@ -718,7 +723,7 @@ switch ($action) {
$ui->assign('in', $in);
sendWhatsapp($c['username'], "*$config[CompanyName]*\n".
$msg = "*$config[CompanyName]*\n".
"$config[address]\n".
"$config[phone]\n".
"\n\n".
@ -734,8 +739,13 @@ switch ($action) {
"$_L[Created_On] :\n*".date($config['date_format'], strtotime($in['recharged_on']))." $in[time]*\n".
"$_L[Expires_On] :\n*".date($config['date_format'], strtotime($in['expiration']))." $in[time]*\n".
"\n\n".
"$config[note]");
"$config[note]";
if ($_c['user_notification_payment'] == 'sms') {
Message::sendSMS($c['phonenumber'], $msg);
} else if ($_c['user_notification_payment'] == 'wa') {
Message::sendWhatsapp($c['phonenumber'], $msg);
}
$ui->assign('date', $date_now);
$ui->display('invoice.tpl');
} else {

View File

@ -132,7 +132,7 @@ switch ($do) {
}else{
$otp = rand(100000,999999);
file_put_contents($otpPath, $otp);
sendSMS($username,$config['CompanyName']."\nYour Verification code are: $otp");
Message::sendSMS($username,$config['CompanyName']."\nYour Verification code are: $otp");
$ui->assign('username', $username);
$ui->assign('notify', '<div class="alert alert-success">
<button type="button" class="close" data-dismiss="alert">

View File

@ -210,6 +210,9 @@ switch ($action) {
$telegram_target_id = _post('telegram_target_id');
$sms_url = _post('sms_url');
$wa_url = _post('wa_url');
$user_notification_expired = _post('user_notification_expired');
$user_notification_expired_text = _post('user_notification_expired_text');
$user_notification_payment = _post('user_notification_payment');
$address = _post('address');
$tawkto = _post('tawkto');
$radius_mode = _post('radius_mode')*1;
@ -286,6 +289,38 @@ switch ($action) {
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'user_notification_expired')->find_one();
if($d){
$d->value = $user_notification_expired;
$d->save();
}else{
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'user_notification_expired';
$d->value = $user_notification_expired;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'user_notification_expired_text')->find_one();
if($d){
$d->value = $user_notification_expired_text;
$d->save();
}else{
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'user_notification_expired_text';
$d->value = $user_notification_expired_text;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'user_notification_payment')->find_one();
if($d){
$d->value = $user_notification_payment;
$d->save();
}else{
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'user_notification_payment';
$d->value = $user_notification_payment;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'tawkto')->find_one();
if($d){

View File

@ -123,7 +123,7 @@ switch ($action) {
$v1->user = $c['username'];
$v1->save();
// Telegram to Admin
sendTelegram('#u' . $c['username'] . " Activate #Voucher #Hotspot\n" . $p['name_plan'] .
Message::sendTelegram('#u' . $c['username'] . " Activate #Voucher #Hotspot\n" . $p['name_plan'] .
"\nCode: " . $code .
"\nRouter: " . $v1['routers'] .
"\nPrice: " . $p['price']);
@ -200,7 +200,7 @@ switch ($action) {
$v1->user = $c['username'];
$v1->save();
// Telegram to Admin
sendTelegram('#u' . $c['username'] . " Activate #Voucher #PPPOE\n" . $p['name_plan'] .
Message::sendTelegram('#u' . $c['username'] . " Activate #Voucher #PPPOE\n" . $p['name_plan'] .
"\nCode: " . $code .
"\nRouter: " . $v1['routers'] .
"\nPrice: " . $p['price']);

View File

@ -1,7 +1,8 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
**/
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
**/
require('../config.php');
require('orm.php');
@ -19,8 +20,7 @@ include "autoload/Hookers.php";
//register all plugin
foreach (glob("system/plugin/*.php") as $filename)
{
foreach (glob("system/plugin/*.php") as $filename) {
include $filename;
}
@ -50,54 +50,57 @@ function _autoloader($class)
spl_autoload_register('_autoloader');
$result = ORM::for_table('tbl_appconfig')->find_many();
foreach($result as $value){
$config[$value['setting']]=$value['value'];
foreach ($result as $value) {
$config[$value['setting']] = $value['value'];
}
date_default_timezone_set($config['timezone']);
$d = ORM::for_table('tbl_user_recharges')->where('status','on')->find_many();
$textExpired = $config['user_notification_expired_text'];
$d = ORM::for_table('tbl_user_recharges')->where('status', 'on')->find_many();
run_hook('cronjob'); #HOOK
foreach ($d as $ds){
if($ds['type'] == 'Hotspot'){
$date_now = strtotime(date("Y-m-d H:i:s"));
$expiration = strtotime($ds['expiration'].' '.$ds['time']);
echo $ds['expiration']." : ".$ds['username'];
if ($date_now >= $expiration){
echo " : EXPIRED \r\n";
$u = ORM::for_table('tbl_user_recharges')->where('id',$ds['id'])->find_one();
$c = ORM::for_table('tbl_customers')->where('id',$ds['customer_id'])->find_one();
$m = ORM::for_table('tbl_routers')->where('name',$ds['routers'])->find_one();
foreach ($d as $ds) {
if ($ds['type'] == 'Hotspot') {
$date_now = strtotime(date("Y-m-d H:i:s"));
$expiration = strtotime($ds['expiration'] . ' ' . $ds['time']);
echo $ds['expiration'] . " : " . $ds['username'];
if ($date_now >= $expiration) {
echo " : EXPIRED \r\n";
$u = ORM::for_table('tbl_user_recharges')->where('id', $ds['id'])->find_one();
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
$m = ORM::for_table('tbl_routers')->where('name', $ds['routers'])->find_one();
if(!$_c['radius_mode']){
if (!$_c['radius_mode']) {
$client = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']);
Mikrotik::setHotspotLimitUptime($client,$c['username']);
Mikrotik::removeHotspotActiveUser($client,$c['username']);
Mikrotik::setHotspotLimitUptime($client, $c['username']);
Mikrotik::removeHotspotActiveUser($client, $c['username']);
Message::sendExpiredNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $textExpired, $config['user_notification_expired']);
}
//update database user dengan status off
$u->status = 'off';
$u->save();
} else echo " : ACTIVE \r\n";
} else {
$date_now = strtotime(date("Y-m-d H:i:s"));
$expiration = strtotime($ds['expiration'] . ' ' . $ds['time']);
echo $ds['expiration'] . " : " . $ds['username'];
if ($date_now >= $expiration) {
echo " : EXPIRED \r\n";
$u = ORM::for_table('tbl_user_recharges')->where('id', $ds['id'])->find_one();
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
$m = ORM::for_table('tbl_routers')->where('name', $ds['routers'])->find_one();
if (!$_c['radius_mode']) {
$client = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']);
Mikrotik::disablePpoeUser($client, $c['username']);
Mikrotik::removePpoeActive($client, $c['username']);
Message::sendExpiredNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $textExpired, $config['user_notification_expired']);
}
//update database user dengan status off
$u->status = 'off';
$u->save();
}else echo " : ACTIVE \r\n";
}else{
$date_now = strtotime(date("Y-m-d H:i:s"));
$expiration = strtotime($ds['expiration'].' '.$ds['time']);
echo $ds['expiration']." : ".$ds['username'];
if ($date_now >= $expiration){
echo " : EXPIRED \r\n";
$u = ORM::for_table('tbl_user_recharges')->where('id',$ds['id'])->find_one();
$c = ORM::for_table('tbl_customers')->where('id',$ds['customer_id'])->find_one();
$m = ORM::for_table('tbl_routers')->where('name',$ds['routers'])->find_one();
if(!$_c['radius_mode']){
$client = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']);
Mikrotik::disablePpoeUser($client,$c['username']);
Mikrotik::removePpoeActive($client,$c['username']);
}
$u->status = 'off';
$u->save();
}else echo " : ACTIVE \r\n";
}
$u->status = 'off';
$u->save();
} else echo " : ACTIVE \r\n";
}
}

View File

@ -301,8 +301,18 @@ $_L['Buy_Package'] = 'Buy Package';
$_L['Email'] = 'Email';
$_L['Company_Footer'] = 'Company Footer';
$_L['Will_show_below_user_pages'] = 'Will show below user pages';
$_L['Request_OTP'] = 'Request OTP';
$_L['Verification_Code'] = 'Verification Code';
$_L['SMS_Verification_Code'] = 'SMS Verification Code';
$_L['Please_enter_your_email_address'] = 'Please enter your email address';
$_L['Failed_to_create_Paypal_transaction'] = 'Failed to create Paypal transaction.';
$_L['Request_OTP'] = 'Request OTP';
$_L['Verification_Code'] = 'Verification Code';
$_L['SMS_Verification_Code'] = 'SMS Verification Code';
$_L['Please_enter_your_email_address'] = 'Please enter your email address';
$_L['Failed_to_create_Paypal_transaction'] = 'Failed to create Paypal transaction.';
$_L['Plugin'] = 'Plugin';
$_L['Plugin_Manager'] = 'Plugin Manager';
$_L['Plugin_Manager'] = 'Plugin Manager';
$_L['User_Notification'] = 'User Notification';
$_L['Expired_Notification'] = 'Expired Notification';
$_L['User_will_get_notification_when_package_expired'] = 'User will get notification when package expired';
$_L['Expired_Notification_Message'] = 'Expired Notification Message';
$_L['bnameb_will_be_replaced_with_Customer_Name_bpackageb_will_be_replaced_with_Package_name'] = '<b>[[name]]</b> will be replaced with Customer Name. <b>[[package]]</b> will be replaced with Package name.';
$_L['Payment_Notification'] = 'Payment Notification';
$_L['User_will_get_invoice_notification_when_buy_package_or_package_refilled'] = 'User will get invoice notification when buy package or package refilled';

View File

@ -26,7 +26,7 @@
<label class="col-md-2 control-label">{$_L['Address']}</label>
<div class="col-md-6">
<textarea class="form-control" id="address" name="address"
rows="3">{$_c['address']}</textarea>
rows="3">{Lang::htmlspecialchars($_c['address'])}</textarea>
<span class="help-block">{$_L['You_can_use_html_tag']}</span>
</div>
</div>
@ -100,6 +100,38 @@
</div>
</div>
</div>
<div class="panel-heading">{Lang::T('User Notification')}</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Expired Notification')}</label>
<div class="col-md-6">
<select name="user_notification_expired" id="user_notification_expired" class="form-control">
<option value="none">None</option>
<option value="wa" {if $_c['user_notification_expired'] == 'wa'}selected="selected" {/if}>Whatsapp</option>
<option value="sms" {if $_c['user_notification_expired'] == 'sms'}selected="selected" {/if}>SMS</option>
</select>
<p class="help-block">{Lang::T('User will get notification when package expired')}</p>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Expired Notification Message')}</label>
<div class="col-md-6">
<textarea class="form-control" id="user_notification_expired_text" name="user_notification_expired_text" placeholder="Hello [[name]], your internet package [[package]] has been expired" rows="3">{if $_c['user_notification_expired_text']!=''}{Lang::htmlspecialchars($_c['user_notification_expired_text'])}{else}Hello [[name]], your internet package [[package]] has been expired.{/if}</textarea>
<p class="help-block">{Lang::T('<b>[[name]]</b> will be replaced with Customer Name. <b>[[package]]</b> will be replaced with Package name.')}</p>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Payment Notification')}</label>
<div class="col-md-6">
<select name="user_notification_payment" id="user_notification_payment" class="form-control">
<option value="none">None</option>
<option value="wa" {if $_c['user_notification_payment'] == 'wa'}selected="selected" {/if}>Whatsapp</option>
<option value="sms" {if $_c['user_notification_payment'] == 'sms'}selected="selected" {/if}>SMS</option>
</select>
<p class="help-block">{Lang::T('User will get invoice notification when buy package or package refilled')}</p>
</div>
</div>
</div>
<div class="panel-heading">Tawk.to Chat Widget</div>
<div class="panel-body">
<div class="form-group">
@ -119,7 +151,7 @@ add dst-host=*.tawk.to</pre>
<div class="form-group">
<label class="col-md-2 control-label">Note Invoice</label>
<div class="col-md-6">
<textarea class="form-control" id="note" name="note" rows="3">{$_c['note']}</textarea>
<textarea class="form-control" id="note" name="note" rows="3">{Lang::htmlspecialchars($_c['note'])}</textarea>
<span class="help-block">{$_L['You_can_use_html_tag']}</span>
</div>
</div>

View File

@ -41,7 +41,7 @@
<td>{$ds['rate_up']} {$ds['rate_up_unit']}</td>
<td>
<a href="{$_url}bandwidth/edit/{$ds['id']}" class="btn btn-sm btn-warning">{$_L['Edit']}</a>
<a href="{$_url}bandwidth/delete/{$ds['id']}" id="{$ds['id']}" class="btn btn-danger btn-sm cdelete">{$_L['Delete']}</a>
<a href="{$_url}bandwidth/delete/{$ds['id']}" id="{$ds['id']}" class="btn btn-danger btn-sm" onclick="confirm('{$_L['Delete']}?')" >{$_L['Delete']}</a>
</td>
</tr>
{/foreach}

View File

@ -45,7 +45,7 @@
<td align="center"><a href="{$_url}prepaid/recharge-user/{$ds['id']}" id="{$ds['id']}" class="btn btn-primary btn-sm">{$_L['Recharge']}</a></td>
<td align="center">
<a href="{$_url}customers/edit/{$ds['id']}" class="btn btn-warning btn-sm">{$_L['Edit']}</a>
<a href="{$_url}customers/delete/{$ds['id']}" id="{$ds['id']}" class="btn btn-danger btn-sm cdelete">{$_L['Delete']}</a>
<a href="{$_url}customers/delete/{$ds['id']}" id="{$ds['id']}" class="btn btn-danger btn-sm" onclick="confirm('{$_L['Delete']}?')">{$_L['Delete']}</a>
</td>
</tr>
{/foreach}

63
ui/ui/plugin-manager.tpl Normal file
View File

@ -0,0 +1,63 @@
{include file="sections/header.tpl"}
<div class="row">
<div class="col-sm-12">
<div class="panel panel-primary panel-hovered">
<div class="panel-heading">{Lang::T('Plugin')}</div>
<div class="panel-body row">
{foreach $plugins as $plugin}
<div class="col-md-4">
<div class="box box-hovered mb20 box-primary">
<div class="box-header">
<h3 class="box-title">{$plugin['name']}</h3>
</div>
<div class="box-body">{$plugin['description']}<br><small><i>@{$plugin['author']} Last update: {$plugin['last_update']}</i></small></div>
<div class="box-footer ">
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$plugin['url']}" target="_blank"
class="btn btn-primary"><i class="ion ion-chatboxes"></i> Website</a>
<a href="{$plugin['github']}" target="_blank"
class="btn btn-success"><i class="ion ion-chatboxes"></i> Github</a>
<a {if $zipExt }
href="{$_url}pluginmanager/install/plugin/{$plugin['id']}" onclick="return confirm('Installing plugin will take some time to complete, do not close the page while it loading to install the plugin')"
{else}
href="#" onclick="alert('PHP ZIP extension is not available')"
{/if}
class="btn btn-warning"><i class="ion ion-chatboxes"></i> Install</a>
</div>
</div>
</div>
</div>
{/foreach}
</div>
</div>
<div class="panel panel-primary panel-hovered">
<div class="panel-heading">{Lang::T('Payment Gateway')}</div>
<div class="panel-body row">
{foreach $pgs as $pg}
<div class="col-md-4">
<div class="box box-hovered mb20 box-primary">
<div class="box-header">
<h3 class="box-title">{$pg['name']}</h3>
</div>
<div class="box-body">{$pg['description']}<br><small><i>@{$plugin['author']} Last update: {$plugin['last_update']}</i></small></div>
<div class="box-footer ">
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$pg['url']}" target="_blank"
class="btn btn-primary"><i class="ion ion-chatboxes"></i> Website</a>
<a href="{$pg['github']}" target="_blank"
class="btn btn-success"><i class="ion ion-chatboxes"></i> Github</a>
<a {if $zipExt }
href="{$_url}pluginmanager/install/payment/{$pg['id']}" onclick="return confirm('Installing plugin will take some time to complete, do not close the page while it loading to install the plugin')"
{else}
href="#" onclick="alert('PHP ZIP extension is not available')"
{/if}
class="btn btn-warning"><i class="ion ion-chatboxes"></i> Install</a>
</div>
</div>
</div>
</div>
{/foreach}
</div>
</div>
</div>
{include file="sections/footer.tpl"}

View File

@ -163,7 +163,7 @@
{$_MENU_AFTER_REPORTS}
{/if}
{if $_admin['user_type'] eq 'Admin'}
<li class="{if $_system_menu eq 'network'}active{/if} treeview">
<li class="{if $_system_menu eq 'network'}active{/if} treeview">
<a href="#">
<i class="ion ion-network"></i> <span>{$_L['Network']}</span>
<span class="pull-right-container">
@ -215,6 +215,8 @@
href="{$_url}settings/users">{$_L['Administrator_Users']}</a></li>
<li {if $_routes[1] eq 'dbstatus'}class="active" {/if}><a
href="{$_url}settings/dbstatus">{$_L['Backup_Restore']}</a></li>
<li {if $_routes[1] eq 'dbstatus'}class="active" {/if}><a
href="{$_url}pluginmanager">{Lang::T('Plugin Manager')}</a></li>
{$_MENU_SETTINGS}
</ul>
</li>
@ -240,9 +242,9 @@
<div class="content-wrapper">
<section class="content-header">
<h1>
{$_title}
{$_title}
</h1>
</section>
<section class="content">
{if isset($notify)}{$notify}{/if}
{if isset($notify)}{$notify}{/if}

View File

@ -1,15 +1,14 @@
</section>
</div>
{if isset($_c['CompanyFooter'])}
<footer class="main-footer">
{$_c['CompanyFooter']}
</footer>
{else}
<footer class="main-footer">
PHPNuxBill by <a href="https://github.com/hotspotbilling/phpnuxbill" rel="nofollow noreferrer noopener" target="_blank">iBNuX</a>, Theme by <a href="https://adminlte.io/" rel="nofollow noreferrer noopener" target="_blank">AdminLTE</a>
</footer>
{/if}
</section>
</div>
{if isset($_c['CompanyFooter'])}
<footer class="main-footer">
{$_c['CompanyFooter']}
</footer>
{else}
<footer class="main-footer">
PHPNuxBill by <a href="https://github.com/hotspotbilling/phpnuxbill" rel="nofollow noreferrer noopener" target="_blank">iBNuX</a>, Theme by <a href="https://adminlte.io/" rel="nofollow noreferrer noopener" target="_blank">AdminLTE</a>
</footer>
{/if}
</div>
<script src="ui/ui/scripts/jquery.min.js"></script>

View File

@ -49,7 +49,7 @@
class="btn btn-warning btn-sm">{$_L['Edit']}</a>
{if ($_admin['username']) neq ($ds['username'])}
<a href="{$_url}settings/users-delete/{$ds['id']}" id="{$ds['id']}"
class="btn btn-danger btn-sm cdelete">{$_L['Delete']}</a>
class="btn btn-danger btn-sm" onclick="confirm('{$_L['Delete']}?')">{$_L['Delete']}</a>
{/if}
</td>
</tr>

View File

@ -61,7 +61,7 @@
<td align="center">{if $ds['user'] eq '0'} - {else} {$ds['user']} {/if}</td>
<td>
<a href="{$_url}prepaid/voucher-delete/{$ds['id']}" id="{$ds['id']}"
class="btn btn-danger btn-sm cdelete">{$_L['Delete']}</a>
class="btn btn-danger btn-sm" onclick="confirm('{$_L['Delete']}?')">{$_L['Delete']}</a>
</td>
</tr>
{/foreach}

View File

@ -1,3 +1,3 @@
{
"version": "2022.12.14"
"version": "2023.3.6"
}