├── index_screenshot.png ├── .gitignore ├── init.php ├── collector.php ├── README.md └── index.php /index_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhannad0/mikrotik-traffic-counter/HEAD/index_screenshot.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Ignore DB file 2 | *.sqlite 3 | 4 | #Ignore mikrotik configuration 5 | mikrotik_configuration.txt 6 | -------------------------------------------------------------------------------- /init.php: -------------------------------------------------------------------------------- 1 | query('CREATE TABLE IF NOT EXISTS "devices" ( 12 | "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 13 | "sn" TEXT, 14 | "comment" VARCHAR, 15 | "last_check" DATETIME, 16 | "last_tx" INT, 17 | "last_rx" INT 18 | )'); 19 | 20 | // Base table for detailed traffic 21 | $db->query('CREATE TABLE IF NOT EXISTS "traffic" ( 22 | "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 23 | "device_id" INT, 24 | "timestamp" DATETIME, 25 | "tx" INT, 26 | "rx" INT 27 | )'); 28 | -------------------------------------------------------------------------------- /collector.php: -------------------------------------------------------------------------------- 1 | &tx=&rx= 4 | */ 5 | 6 | require("init.php"); 7 | 8 | // Check input data 9 | if (isset($_GET['sn']) 10 | and isset($_GET['tx']) and is_numeric($_GET['tx']) 11 | and isset($_GET['rx']) and is_numeric($_GET['rx'])) { 12 | $device_serial = substr($_GET['sn'], 0, 12); 13 | } else { 14 | echo 'fail'; 15 | exit; 16 | } 17 | 18 | // Check if device exists 19 | $getDevice = $db->prepare('SELECT id, sn, comment, last_check, last_tx, last_rx FROM devices WHERE sn="'.$device_serial.'"'); 20 | $result = $getDevice->execute(); 21 | $device = $result->fetchArray(SQLITE3_ASSOC); 22 | if (empty($device)) { 23 | //Add new device 24 | $addDevice = $db->prepare('INSERT INTO devices (sn, last_check, last_tx, last_rx) 25 | VALUES (:serial, :time, :tx, :rx)'); 26 | $addDevice->bindValue(':serial', $device_serial); 27 | $addDevice->bindValue(':time', date('Y-m-d H:i:s')); 28 | $addDevice->bindValue(':tx', $_GET['tx']); 29 | $addDevice->bindValue(':rx', $_GET['rx']); 30 | $addDevice->execute(); 31 | $device['id'] = $db->lastInsertRowid(); 32 | } 33 | else { 34 | //Update last received data 35 | $updateData = $db->prepare('UPDATE devices SET last_check=:time, last_tx=:tx, last_rx=:rx WHERE id=:id'); 36 | $updateData->bindValue(':id', $device['id']); 37 | $updateData->bindValue(':time', date('Y-m-d H:i:s')); 38 | $updateData->bindValue(':tx', $_GET['tx']); 39 | $updateData->bindValue(':rx', $_GET['rx']); 40 | $updateData->execute(); 41 | } 42 | 43 | //Update traffic data 44 | $updateTraffic = $db->prepare('INSERT INTO traffic (device_id, timestamp, tx, rx) 45 | VALUES (:id, :time, :tx, :rx)'); 46 | $updateTraffic->bindValue(':id', $device['id']); 47 | $updateTraffic->bindValue(':time', date('Y-m-d H:i:s')); 48 | $updateTraffic->bindValue(':tx', $_GET['tx']); 49 | $updateTraffic->bindValue(':rx', $_GET['rx']); 50 | $updateTraffic->execute(); 51 | 52 | echo 'traffic data updated'; 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple Mikrotik Traffic Counter 2 | A simple PHP application to collect interface statistics from Mikrotik router and display the usage (upload/download). 3 | You can host this application anywhere on the network or Internet. 4 | 5 | ### Features 6 | - Collect tx/rx stats from routerboard. 7 | - Display hourly graph. 8 | - Display daily/weekly/monthly summary. 9 | 10 | ## Usage 11 | Setup the Mikrotik router to collect and send the stats to the application first. 12 | 13 | 1. Create firewall mangle rules that will collect the traffic stats. 14 | ``` 15 | /ip firewall mangle 16 | add chain=forward src-address=192.168.88.0/24 out-interface=pppoe-out1 action=passthrough comment=local-wan-tx 17 | add chain=forward dst-address=192.168.88.0/24 in-interface=pppoe-out1 action=passthrough comment=local-wan-rx 18 | ``` 19 | Here, I am monitoring usage for a specific subnet, going through a PPP connection for Internet. 20 | 21 | 2. Add the following script that will get the data and send it to the application. 22 | ``` 23 | :local wantxcomment "local-wan-tx" 24 | :local wanrxcomment "local-wan-rx" 25 | :local sysnumber [/system routerboard get value-name=serial-number] 26 | :local txbytes [/ip firewall mangle get [/ip firewall mangle find comment="$wantxcomment"] bytes] 27 | :local rxbytes [/ip firewall mangle get [/ip firewall mangle find comment="$wanrxcomment"] bytes] 28 | /tool fetch url=("http:///collector.php\?sn=$sysnumber&tx=$txbytes&rx=$rxbytes") mode=http keep-result=no 29 | /ip firewall mangle reset-counters [/ip firewall mangle find comment="$wantxcomment"] 30 | /ip firewall mangle reset-counters [/ip firewall mangle find comment="$wanrxcomment"] 31 | :log info ("cleared counters for all mangle rules") 32 | ``` 33 | Edit the `` to match where application is hosted. 34 | 35 | 3. Set a scheduler to run the script at 1 hour intervals. 36 | ``` 37 | /system scheduler add name="upload-traffic-count-local" interval=1h on-event= 35 | 57 | 58 | 59 |
60 | 61 | 62 | prepare('SELECT sum(tx) as sumtx, sum(rx) as sumrx FROM traffic WHERE device_id = ? AND timestamp >= ? AND timestamp <= ?'); 68 | $daily->bindValue(1, $_GET['id']); 69 | $daily->bindValue(2, date('Y-m-d 00:00:00')); 70 | $daily->bindValue(3, date('Y-m-d 23:59:59')); 71 | $result = $daily->execute(); 72 | #print_r($result->fetchArray(SQLITE3_ASSOC)); 73 | $dailyTraffic = $result->fetchArray(SQLITE3_ASSOC); 74 | //display results 75 | echo "Daily Stats
"; 76 | echo "From: ".date('Y-m-d 00:00:00')." to ".date('Y-m-d 23:59:59')."
"; 77 | echo "TX: ".round(($dailyTraffic['sumtx']/1024/1024),2)." Mb "; 78 | echo "RX: ".round(($dailyTraffic['sumrx']/1024/1024),2)." Mb "; 79 | echo "Total: ".round((($dailyTraffic['sumtx']+$dailyTraffic['sumrx'])/1024/1024),2)." Mb
"; 80 | echo "
"; 81 | 82 | //get weekly stats 83 | //getting sunday and saturday dates for current week 84 | $today = new DateTime(); 85 | $currentWeekDay = $today->format('w'); 86 | $firstdayofweek = clone $today; 87 | $lastdayofweek = clone $today; 88 | 89 | ($currentWeekDay != '0')?$firstdayofweek->modify('last Sunday'):''; 90 | ($currentWeekDay != '6')?$lastdayofweek->modify('next Saturday'):''; 91 | 92 | #echo $firstdayofweek->format('Y-m-d 00:00:00').' to '.$lastdayofweek->format('Y-m-d 23:59:59'); 93 | 94 | //query the db 95 | $weekly = $db->prepare('SELECT sum(tx) as sumtx, sum(rx) as sumrx FROM traffic WHERE device_id = ? AND timestamp >= ? AND timestamp <= ?'); 96 | $weekly->bindValue(1, $_GET['id']); 97 | $weekly->bindValue(2, $firstdayofweek->format('Y-m-d 00:00:00')); 98 | $weekly->bindValue(3, $lastdayofweek->format('Y-m-d 23:59:59')); 99 | $result = $weekly->execute(); 100 | #print_r($weeklyTraffic->fetchArray(SQLITE3_ASSOC)); 101 | $weeklyTraffic = $result->fetchArray(SQLITE3_ASSOC); 102 | //display results 103 | echo "Weekly Stats
"; 104 | echo "From: ".$firstdayofweek->format('Y-m-d 00:00:00')." to ".$lastdayofweek->format('Y-m-d 23:59:59')."
"; 105 | echo "TX: ".round(($weeklyTraffic['sumtx']/1024/1024),2)." Mb "; 106 | echo "RX: ".round(($weeklyTraffic['sumrx']/1024/1024),2)." Mb "; 107 | echo "Total: ".round((($weeklyTraffic['sumtx']+$weeklyTraffic['sumrx'])/1024/1024),2)." Mb
"; 108 | echo "
"; 109 | 110 | //get monthly stats 111 | //query the db 112 | $monthly = $db->prepare('SELECT sum(tx) as sumtx, sum(rx) as sumrx FROM traffic WHERE device_id = ? AND timestamp >= ? AND timestamp <= ?'); 113 | $monthly->bindValue(1, $_GET['id']); 114 | $monthly->bindValue(2, date('Y-m-01 00:00:00')); 115 | $monthly->bindValue(3, date('Y-m-t 23:59:59')); 116 | $result = $monthly->execute(); 117 | #print_r($monthlyTraffic->fetchArray(SQLITE3_ASSOC)); 118 | $monthlyTraffic = $result->fetchArray(SQLITE3_ASSOC); 119 | //display results 120 | echo "Monthly Stats
"; 121 | echo "From: ".date('Y-m-01 00:00:00')." to ".date('Y-m-t 23:59:59')."
"; 122 | echo "TX: ".round(($monthlyTraffic['sumtx']/1024/1024),2)." Mb "; 123 | echo "RX: ".round(($monthlyTraffic['sumrx']/1024/1024),2)." Mb "; 124 | echo "Total: ".round((($monthlyTraffic['sumtx']+$monthlyTraffic['sumrx'])/1024/1024),2)." Mb
"; 125 | echo "
"; 126 | 127 | $result->finalize(); 128 | } 129 | else { 130 | $result = $db->query('SELECT * FROM devices'); 131 | if(empty($result->fetchArray(SQLITE3_ASSOC))) { 132 | echo "No devices found.
"; 133 | } 134 | else { 135 | $result = $db->query('SELECT * FROM devices'); 136 | while ($device = $result->fetchArray(SQLITE3_ASSOC)){ 137 | echo ''.$device['sn'].' ('.$device['comment'].') Last check: '.$device['last_check'].'
'; 138 | } 139 | } 140 | $result->finalize(); 141 | } 142 | ?> 143 | 144 | --------------------------------------------------------------------------------