Refactor results/ PHP code (#369)

* put code to insert and query data from database into separate file

* simplify obfuscation salt file handling

* use new DB interaction functions in telemetry.php

* use new DB interaction functions in stats.php

and fix indentation levels

* format telemetry settings file

* use new function for interacting with DB in index.php

* move drawing of the image into function and try to comment each section with what it does

* reorder lines for parts of the image to align with the order they appear on the image

* bugfix: display obfuscated and deobfuscated id in stats if id obfuscation is enabled

* improve error handling

* add missing PHPDocs to functions

* imageftbbox returns an array on success and false on failure so to check if the font is usable, check if we got an array

* fix dsn for postgres

* fix limit sql statement for postgresql

* remove obsolete require statement

* use require instead of require_once since the settings file might need to be loaded multiple times

because it just contains plain variables which will just get loaded into the current scope

* move require statements to the top of the file

* make sure files are readable before requiring them

* add constant to refer to the telemetry settings file and check if it is readable before loading it

* return null if no speedtest result was found for the given id and show according message to the user instead of just exiting

* use existing constant instead of string for telemetry settings file name

* uniformly use single quotes instead of double quotes as most code places already used single quotes

* somehow some tabs sneaked in, replace them to uniformly use spaces

* mysql now uses pdo, too, reflect that in the requirements documentation

* pass username and password as constructor parameters instead of via DSN
This commit is contained in:
Bernd Stellwag 2020-10-20 07:43:48 +02:00 committed by GitHub
parent c6a36e68c4
commit fb7575b67b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 709 additions and 445 deletions

View file

@ -80,7 +80,10 @@ function getLocalOrPrivateIpInfo($ip)
*/
function getIpInfoTokenString()
{
if (!file_exists(API_KEY_FILE)) {
if (
!file_exists(API_KEY_FILE)
|| !is_readable(API_KEY_FILE)
) {
return '';
}
@ -139,7 +142,10 @@ function getIsp($rawIspInfo)
function getServerLocation()
{
$serverLoc = null;
if (file_exists(SERVER_LOCATION_CACHE_FILE)) {
if (
file_exists(SERVER_LOCATION_CACHE_FILE)
&& is_readable(SERVER_LOCATION_CACHE_FILE)
) {
require SERVER_LOCATION_CACHE_FILE;
}
if (is_string($serverLoc) && !empty($serverLoc)) {

4
doc.md
View file

@ -44,7 +44,7 @@ Server side, you'll need:
* PHP 5.4 or newer, a 64-bit version is strongly recommended
* OpenSSL and its PHP module (this is usually installed automatically by most distros)
* If you want to store test results (telemetry), one of the following:
- MySQL/MariaDB and the mysqli PHP module
- MySQL/MariaDB and its PHP PDO module
- PostgreSQL and its PHP PDO module
- SQLite 3 and its PHP PDO module
* If you want to enable results sharing:
@ -137,7 +137,7 @@ Requirements:
* Apache 2 (nginx and IIS also supported). A fast connection is not mandatory, but is still recommended
* PHP 5.4 or newer
* If you want to store test results (telemetry), one of the following:
- MySQL/MariaDB and the mysqli PHP module
- MySQL/MariaDB and its PHP PDO module
- PostgreSQL and its PHP PDO module
- SQLite 3 and its PHP PDO module
* If you want to enable results sharing:

View file

@ -1,43 +1,72 @@
<?php
function getObfuscationSalt(){
$saltFile=dirname(__FILE__)."/idObfuscation_salt.php";
if(file_exists($saltFile)){
require $saltFile;
}else{
$bytes=openssl_random_pseudo_bytes(4);
$sf=fopen($saltFile,"w");
fwrite($sf,chr(60)."?php\n");
fwrite($sf,'$OBFUSCATION_SALT=0x'.bin2hex($bytes).";\n");
fwrite($sf,"?".chr(62));
fclose($sf);
require $saltFile;
}
return isset($OBFUSCATION_SALT)?$OBFUSCATION_SALT:0;
}
/*
This is a simple reversible hash function I made for encoding and decoding test IDs.
It is not cryptographically secure, don't use it to hash passwords or something!
*/
function obfdeobf($id,$dec){
$salt=getObfuscationSalt()&0xFFFFFFFF;
$id=$id&0xFFFFFFFF;
if($dec){
$id=$id^$salt;
$id=(($id&0xAAAAAAAA)>>1)|($id&0x55555555)<<1;
$id=(($id&0x0000FFFF)<<16)|(($id&0xFFFF0000)>>16);
return $id;
}else{
$id=(($id&0x0000FFFF)<<16)|(($id&0xFFFF0000)>>16);
$id=(($id&0xAAAAAAAA)>>1)|($id&0x55555555)<<1;
return $id^$salt;
}
}
function obfuscateId($id){
return str_pad(base_convert(obfdeobf($id+1,false),10,36),7,0,STR_PAD_LEFT);
}
function deobfuscateId($id){
return obfdeobf(base_convert($id,36,10),true)-1;
define('ID_OBFUSCATION_SALT_FILE', __DIR__.'/idObfuscation_salt.php');
/**
* @return string|int
*/
function getObfuscationSalt()
{
if (!file_exists(ID_OBFUSCATION_SALT_FILE)) {
$bytes = openssl_random_pseudo_bytes(4);
$saltData = "<?php\n\n\$OBFUSCATION_SALT = 0x".bin2hex($bytes).";\n";
file_put_contents(ID_OBFUSCATION_SALT_FILE, $saltData);
}
if (
file_exists(ID_OBFUSCATION_SALT_FILE)
&& is_readable(ID_OBFUSCATION_SALT_FILE)
) {
require ID_OBFUSCATION_SALT_FILE;
}
return isset($OBFUSCATION_SALT) ? $OBFUSCATION_SALT : 0;
}
//IMPORTANT: DO NOT ADD ANYTHING BELOW THE PHP CLOSING TAG, NOT EVEN EMPTY LINES!
?>
/**
* This is a simple reversible hash function I made for encoding and decoding test IDs.
* It is not cryptographically secure, don't use it to hash passwords or something!
*
* @param int|string $id
* @param bool $dec
*
* @return int|string
*/
function obfdeobf($id, $dec)
{
$salt = getObfuscationSalt() & 0xFFFFFFFF;
$id &= 0xFFFFFFFF;
if ($dec) {
$id ^= $salt;
$id = (($id & 0xAAAAAAAA) >> 1) | ($id & 0x55555555) << 1;
$id = (($id & 0x0000FFFF) << 16) | (($id & 0xFFFF0000) >> 16);
return $id;
}
$id = (($id & 0x0000FFFF) << 16) | (($id & 0xFFFF0000) >> 16);
$id = (($id & 0xAAAAAAAA) >> 1) | ($id & 0x55555555) << 1;
return $id ^ $salt;
}
/**
* @param int $id
*
* @return string
*/
function obfuscateId($id)
{
return str_pad(base_convert(obfdeobf($id + 1, false), 10, 36), 7, 0, STR_PAD_LEFT);
}
/**
* @param string $id
*
* @return int
*/
function deobfuscateId($id)
{
return obfdeobf(base_convert($id, 36, 10), true) - 1;
}

View file

@ -1,164 +1,213 @@
<?php
$WATERMARK_TEXT="LibreSpeed";
require_once 'telemetry_db.php';
error_reporting(0);
putenv('GDFONTPATH=' . realpath('.'));
function tryFont($name){
$rp=realpath('.');
if(imageftbbox(12,0,$name,"M")[5]==0){
$name=$rp."/".$name.".ttf";
if(imageftbbox(12,0,$name,"M")[5]==0){
return null;
}
}
return $name;
}
function format($d){
if($d<10) return number_format($d,2,".","");
if($d<100) return number_format($d,1,".","");
return number_format($d,0,".","");
putenv('GDFONTPATH='.realpath('.'));
/**
* @param string $name
*
* @return string|null
*/
function tryFont($name)
{
if (is_array(imageftbbox(12, 0, $name, 'M'))) {
return $name;
}
$fullPathToFont = realpath('.').'/'.$name.'.ttf';
if (is_array(imageftbbox(12, 0, $fullPathToFont, 'M'))) {
return $fullPathToFont;
}
return null;
}
$SCALE=1.25;
$WIDTH=400*$SCALE;
$HEIGHT=229*$SCALE;
$im=imagecreatetruecolor($WIDTH,$HEIGHT);
$BACKGROUND_COLOR=imagecolorallocate($im,255,255,255);
$FONT_LABEL=tryFont("OpenSans-Semibold");
$FONT_LABEL_SIZE=14*$SCALE;
$FONT_LABEL_SIZE_BIG=16*$SCALE;
$FONT_METER=tryFont("OpenSans-Light");
$FONT_METER_SIZE=20*$SCALE;
$FONT_METER_SIZE_BIG=22*$SCALE;
$FONT_MEASURE=tryFont("OpenSans-Semibold");
$FONT_MEASURE_SIZE=12*$SCALE;
$FONT_MEASURE_SIZE_BIG=12*$SCALE;
$FONT_ISP=tryFont("OpenSans-Semibold");
$FONT_ISP_SIZE=9*$SCALE;
$FONT_WATERMARK=tryFont("OpenSans-Light");
$FONT_WATERMARK_SIZE=8*$SCALE;
$TEXT_COLOR_LABEL=imagecolorallocate($im,40,40,40);
$TEXT_COLOR_DL_METER=imagecolorallocate($im,96,96,170);
$TEXT_COLOR_UL_METER=imagecolorallocate($im,96,96,96);
$TEXT_COLOR_PING_METER=imagecolorallocate($im,170,96,96);
$TEXT_COLOR_JIT_METER=imagecolorallocate($im,170,96,96);
$TEXT_COLOR_MEASURE=imagecolorallocate($im,40,40,40);
$TEXT_COLOR_ISP=imagecolorallocate($im,40,40,40);
$TEXT_COLOR_WATERMARK=imagecolorallocate($im,160,160,160);
$POSITION_Y_DL_LABEL=105*$SCALE;
$POSITION_Y_UL_LABEL=105*$SCALE;
$POSITION_Y_PING_LABEL=24*$SCALE;
$POSITION_Y_JIT_LABEL=24*$SCALE;
$POSITION_Y_DL_METER=143*$SCALE;
$POSITION_Y_UL_METER=143*$SCALE;
$POSITION_Y_PING_METER=60*$SCALE;
$POSITION_Y_JIT_METER=60*$SCALE;
$POSITION_Y_DL_MEASURE=169*$SCALE;
$POSITION_Y_UL_MEASURE=169*$SCALE;
$POSITION_Y_PING_MEASURE=60*$SCALE;
$POSITION_Y_JIT_MEASURE=60*$SCALE;
$POSITION_Y_ISP=205*$SCALE;
$POSITION_X_DL=120*$SCALE;
$POSITION_X_UL=280*$SCALE;
$POSITION_X_PING=125*$SCALE;
$POSITION_X_JIT=275*$SCALE;
$POSITION_X_ISP=4*$SCALE;
$SMALL_SEP=8*$SCALE;
$SEPARATOR_Y=211*$SCALE;
$SEPARATOR_COLOR=imagecolorallocate($im,192,192,192);
$POSITION_Y_WATERMARK=223*$SCALE;
$DL_TEXT="Download";
$UL_TEXT="Upload";
$PING_TEXT="Ping";
$JIT_TEXT="Jitter";
$MBPS_TEXT="Mbps";
$MS_TEXT="ms";
/**
* @param int|float $d
*
* @return string
*/
function format($d)
{
if ($d < 10) {
return number_format($d, 2, '.', '');
}
if ($d < 100) {
return number_format($d, 1, '.', '');
}
$id=$_GET["id"];
include_once('telemetry_settings.php');
require 'idObfuscation.php';
if($enable_id_obfuscation) $id=deobfuscateId($id);
$conn=null; $q=null;
$ispinfo=null; $dl=null; $ul=null; $ping=null; $jit=null;
if($db_type=="mysql"){
$conn = new mysqli($MySql_hostname, $MySql_username, $MySql_password, $MySql_databasename, $MySql_port);
$q = $conn->prepare("select ispinfo,dl,ul,ping,jitter from speedtest_users where id=?");
$q->bind_param("i",$id);
$q->execute();
$q->bind_result($ispinfo,$dl,$ul,$ping,$jit);
$q->fetch();
}else if($db_type=="sqlite"){
$conn = new PDO("sqlite:$Sqlite_db_file") or die();
$q=$conn->prepare("select ispinfo,dl,ul,ping,jitter from speedtest_users where id=?") or die();
$q->execute(array($id)) or die();
$row=$q->fetch() or die();
$ispinfo=$row["ispinfo"];
$dl=$row["dl"];
$ul=$row["ul"];
$ping=$row["ping"];
$jit=$row["jitter"];
$conn=null;
}else if($db_type=="postgresql"){
$conn_host = "host=$PostgreSql_hostname";
$conn_db = "dbname=$PostgreSql_databasename";
$conn_user = "user=$PostgreSql_username";
$conn_password = "password=$PostgreSql_password";
$conn = new PDO("pgsql:$conn_host;$conn_db;$conn_user;$conn_password") or die();
$q=$conn->prepare("select ispinfo,dl,ul,ping,jitter from speedtest_users where id=?") or die();
$q->execute(array($id)) or die();
$row=$q->fetch() or die();
$ispinfo=$row["ispinfo"];
$dl=$row["dl"];
$ul=$row["ul"];
$ping=$row["ping"];
$jit=$row["jitter"];
$conn=null;
}else die();
return number_format($d, 0, '.', '');
}
$dl=format($dl);
$ul=format($ul);
$ping=format($ping);
$jit=format($jit);
/**
* @param array $speedtest
*
* @return array
*/
function formatSpeedtestDataForImage($speedtest)
{
// format values for the image
$speedtest['dl'] = format($speedtest['dl']);
$speedtest['ul'] = format($speedtest['ul']);
$speedtest['ping'] = format($speedtest['ping']);
$speedtest['jit'] = format($speedtest['jitter']);
$ispinfo=json_decode($ispinfo,true)["processedString"];
$dash=strpos($ispinfo,"-");
if(!($dash===FALSE)){
$ispinfo=substr($ispinfo,$dash+2);
$par=strrpos($ispinfo,"(");
if(!($par===FALSE)) $ispinfo=substr($ispinfo,0,$par);
}else $ispinfo="";
$ispinfo = json_decode($speedtest['ispinfo'], true)['processedString'];
$dash = strpos($ispinfo, '-');
if ($dash !== false) {
$ispinfo = substr($ispinfo, $dash + 2);
$par = strrpos($ispinfo, '(');
if ($par !== false) {
$ispinfo = substr($ispinfo, 0, $par);
}
} else {
$ispinfo = '';
}
$dlBbox=imageftbbox($FONT_LABEL_SIZE_BIG,0,$FONT_LABEL,$DL_TEXT);
$ulBbox=imageftbbox($FONT_LABEL_SIZE_BIG,0,$FONT_LABEL,$UL_TEXT);
$pingBbox=imageftbbox($FONT_LABEL_SIZE,0,$FONT_LABEL,$PING_TEXT);
$jitBbox=imageftbbox($FONT_LABEL_SIZE,0,$FONT_LABEL,$JIT_TEXT);
$dlMeterBbox=imageftbbox($FONT_METER_SIZE_BIG,0,$FONT_METER,$dl);
$ulMeterBbox=imageftbbox($FONT_METER_SIZE_BIG,0,$FONT_METER,$ul);
$pingMeterBbox=imageftbbox($FONT_METER_SIZE,0,$FONT_METER,$ping);
$jitMeterBbox=imageftbbox($FONT_METER_SIZE,0,$FONT_METER,$jit);
$mbpsBbox=imageftbbox($FONT_MEASURE_SIZE_BIG,0,$FONT_MEASURE,$MBPS_TEXT);
$msBbox=imageftbbox($FONT_MEASURE_SIZE,0,$FONT_MEASURE,$MS_TEXT);
$watermarkBbox=imageftbbox($FONT_WATERMARK_SIZE,0,$FONT_WATERMARK,$WATERMARK_TEXT);
$POSITION_X_WATERMARK=$WIDTH-$watermarkBbox[4]-4*$SCALE;
$speedtest['ispinfo'] = $ispinfo;
imagefilledrectangle($im, 0, 0, $WIDTH, $HEIGHT, $BACKGROUND_COLOR);
imagefttext($im,$FONT_LABEL_SIZE_BIG,0,$POSITION_X_DL-$dlBbox[4]/2,$POSITION_Y_DL_LABEL,$TEXT_COLOR_LABEL,$FONT_LABEL,$DL_TEXT);
imagefttext($im,$FONT_LABEL_SIZE_BIG,0,$POSITION_X_UL-$ulBbox[4]/2,$POSITION_Y_UL_LABEL,$TEXT_COLOR_LABEL,$FONT_LABEL,$UL_TEXT);
imagefttext($im,$FONT_LABEL_SIZE,0,$POSITION_X_PING-$pingBbox[4]/2,$POSITION_Y_PING_LABEL,$TEXT_COLOR_LABEL,$FONT_LABEL,$PING_TEXT);
imagefttext($im,$FONT_LABEL_SIZE,0,$POSITION_X_JIT-$jitBbox[4]/2,$POSITION_Y_JIT_LABEL,$TEXT_COLOR_LABEL,$FONT_LABEL,$JIT_TEXT);
imagefttext($im,$FONT_METER_SIZE_BIG,0,$POSITION_X_DL-$dlMeterBbox[4]/2,$POSITION_Y_DL_METER,$TEXT_COLOR_DL_METER,$FONT_METER,$dl);
imagefttext($im,$FONT_METER_SIZE_BIG,0,$POSITION_X_UL-$ulMeterBbox[4]/2,$POSITION_Y_UL_METER,$TEXT_COLOR_UL_METER,$FONT_METER,$ul);
imagefttext($im,$FONT_METER_SIZE,0,$POSITION_X_PING-$pingMeterBbox[4]/2-$msBbox[4]/2-$SMALL_SEP/2,$POSITION_Y_PING_METER,$TEXT_COLOR_PING_METER,$FONT_METER,$ping);
imagefttext($im,$FONT_METER_SIZE,0,$POSITION_X_JIT-$jitMeterBbox[4]/2-$msBbox[4]/2-$SMALL_SEP/2,$POSITION_Y_JIT_METER,$TEXT_COLOR_JIT_METER,$FONT_METER,$jit);
imagefttext($im,$FONT_MEASURE_SIZE_BIG,0,$POSITION_X_DL-$mbpsBbox[4]/2,$POSITION_Y_DL_MEASURE,$TEXT_COLOR_MEASURE,$FONT_MEASURE,$MBPS_TEXT);
imagefttext($im,$FONT_MEASURE_SIZE_BIG,0,$POSITION_X_UL-$mbpsBbox[4]/2,$POSITION_Y_UL_MEASURE,$TEXT_COLOR_MEASURE,$FONT_MEASURE,$MBPS_TEXT);
imagefttext($im,$FONT_MEASURE_SIZE,0,$POSITION_X_PING+$pingMeterBbox[4]/2+$SMALL_SEP/2-$msBbox[4]/2,$POSITION_Y_PING_MEASURE,$TEXT_COLOR_MEASURE,$FONT_MEASURE,$MS_TEXT);
imagefttext($im,$FONT_MEASURE_SIZE,0,$POSITION_X_JIT+$jitMeterBbox[4]/2+$SMALL_SEP/2-$msBbox[4]/2,$POSITION_Y_JIT_MEASURE,$TEXT_COLOR_MEASURE,$FONT_MEASURE,$MS_TEXT);
imagefttext($im,$FONT_ISP_SIZE,0,$POSITION_X_ISP,$POSITION_Y_ISP,$TEXT_COLOR_ISP,$FONT_ISP,$ispinfo);
imagefttext($im,$FONT_WATERMARK_SIZE,0,$POSITION_X_WATERMARK,$POSITION_Y_WATERMARK,$TEXT_COLOR_WATERMARK,$FONT_WATERMARK,$WATERMARK_TEXT);
imagefilledrectangle($im, 0, $SEPARATOR_Y, $WIDTH, $SEPARATOR_Y, $SEPARATOR_COLOR);
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);
return $speedtest;
}
?>
/**
* @param array $speedtest
*
* @return void
*/
function drawImage($speedtest)
{
// format values for the image
$data = formatSpeedtestDataForImage($speedtest);
$dl = $data['dl'];
$ul = $data['ul'];
$ping = $data['ping'];
$jit = $data['jitter'];
$ispinfo = $data['ispinfo'];
// initialize the image
$SCALE = 1.25;
$SMALL_SEP = 8 * $SCALE;
$WIDTH = 400 * $SCALE;
$HEIGHT = 229 * $SCALE;
$im = imagecreatetruecolor($WIDTH, $HEIGHT);
$BACKGROUND_COLOR = imagecolorallocate($im, 255, 255, 255);
// configure fonts
$FONT_LABEL = tryFont('OpenSans-Semibold');
$FONT_LABEL_SIZE = 14 * $SCALE;
$FONT_LABEL_SIZE_BIG = 16 * $SCALE;
$FONT_METER = tryFont('OpenSans-Light');
$FONT_METER_SIZE = 20 * $SCALE;
$FONT_METER_SIZE_BIG = 22 * $SCALE;
$FONT_MEASURE = tryFont('OpenSans-Semibold');
$FONT_MEASURE_SIZE = 12 * $SCALE;
$FONT_MEASURE_SIZE_BIG = 12 * $SCALE;
$FONT_ISP = tryFont('OpenSans-Semibold');
$FONT_ISP_SIZE = 9 * $SCALE;
$FONT_WATERMARK = tryFont('OpenSans-Light');
$FONT_WATERMARK_SIZE = 8 * $SCALE;
// configure text colors
$TEXT_COLOR_LABEL = imagecolorallocate($im, 40, 40, 40);
$TEXT_COLOR_PING_METER = imagecolorallocate($im, 170, 96, 96);
$TEXT_COLOR_JIT_METER = imagecolorallocate($im, 170, 96, 96);
$TEXT_COLOR_DL_METER = imagecolorallocate($im, 96, 96, 170);
$TEXT_COLOR_UL_METER = imagecolorallocate($im, 96, 96, 96);
$TEXT_COLOR_MEASURE = imagecolorallocate($im, 40, 40, 40);
$TEXT_COLOR_ISP = imagecolorallocate($im, 40, 40, 40);
$SEPARATOR_COLOR = imagecolorallocate($im, 192, 192, 192);
$TEXT_COLOR_WATERMARK = imagecolorallocate($im, 160, 160, 160);
// configure positioning or the different parts on the image
$POSITION_X_PING = 125 * $SCALE;
$POSITION_Y_PING_LABEL = 24 * $SCALE;
$POSITION_Y_PING_METER = 60 * $SCALE;
$POSITION_Y_PING_MEASURE = 60 * $SCALE;
$POSITION_X_JIT = 275 * $SCALE;
$POSITION_Y_JIT_LABEL = 24 * $SCALE;
$POSITION_Y_JIT_METER = 60 * $SCALE;
$POSITION_Y_JIT_MEASURE = 60 * $SCALE;
$POSITION_X_DL = 120 * $SCALE;
$POSITION_Y_DL_LABEL = 105 * $SCALE;
$POSITION_Y_DL_METER = 143 * $SCALE;
$POSITION_Y_DL_MEASURE = 169 * $SCALE;
$POSITION_X_UL = 280 * $SCALE;
$POSITION_Y_UL_LABEL = 105 * $SCALE;
$POSITION_Y_UL_METER = 143 * $SCALE;
$POSITION_Y_UL_MEASURE = 169 * $SCALE;
$POSITION_X_ISP = 4 * $SCALE;
$POSITION_Y_ISP = 205 * $SCALE;
$SEPARATOR_Y = 211 * $SCALE;
$POSITION_Y_WATERMARK = 223 * $SCALE;
// configure labels
$MBPS_TEXT = 'Mbps';
$MS_TEXT = 'ms';
$PING_TEXT = 'Ping';
$JIT_TEXT = 'Jitter';
$DL_TEXT = 'Download';
$UL_TEXT = 'Upload';
$WATERMARK_TEXT = 'LibreSpeed';
// create text boxes for each part of the image
$mbpsBbox = imageftbbox($FONT_MEASURE_SIZE_BIG, 0, $FONT_MEASURE, $MBPS_TEXT);
$msBbox = imageftbbox($FONT_MEASURE_SIZE, 0, $FONT_MEASURE, $MS_TEXT);
$pingBbox = imageftbbox($FONT_LABEL_SIZE, 0, $FONT_LABEL, $PING_TEXT);
$pingMeterBbox = imageftbbox($FONT_METER_SIZE, 0, $FONT_METER, $ping);
$jitBbox = imageftbbox($FONT_LABEL_SIZE, 0, $FONT_LABEL, $JIT_TEXT);
$jitMeterBbox = imageftbbox($FONT_METER_SIZE, 0, $FONT_METER, $jit);
$dlBbox = imageftbbox($FONT_LABEL_SIZE_BIG, 0, $FONT_LABEL, $DL_TEXT);
$dlMeterBbox = imageftbbox($FONT_METER_SIZE_BIG, 0, $FONT_METER, $dl);
$ulBbox = imageftbbox($FONT_LABEL_SIZE_BIG, 0, $FONT_LABEL, $UL_TEXT);
$ulMeterBbox = imageftbbox($FONT_METER_SIZE_BIG, 0, $FONT_METER, $ul);
$watermarkBbox = imageftbbox($FONT_WATERMARK_SIZE, 0, $FONT_WATERMARK, $WATERMARK_TEXT);
$POSITION_X_WATERMARK = $WIDTH - $watermarkBbox[4] - 4 * $SCALE;
// put the parts together to draw the image
imagefilledrectangle($im, 0, 0, $WIDTH, $HEIGHT, $BACKGROUND_COLOR);
// ping
imagefttext($im, $FONT_LABEL_SIZE, 0, $POSITION_X_PING - $pingBbox[4] / 2, $POSITION_Y_PING_LABEL, $TEXT_COLOR_LABEL, $FONT_LABEL, $PING_TEXT);
imagefttext($im, $FONT_METER_SIZE, 0, $POSITION_X_PING - $pingMeterBbox[4] / 2 - $msBbox[4] / 2 - $SMALL_SEP / 2, $POSITION_Y_PING_METER, $TEXT_COLOR_PING_METER, $FONT_METER, $ping);
imagefttext($im, $FONT_MEASURE_SIZE, 0, $POSITION_X_PING + $pingMeterBbox[4] / 2 + $SMALL_SEP / 2 - $msBbox[4] / 2, $POSITION_Y_PING_MEASURE, $TEXT_COLOR_MEASURE, $FONT_MEASURE, $MS_TEXT);
// jitter
imagefttext($im, $FONT_LABEL_SIZE, 0, $POSITION_X_JIT - $jitBbox[4] / 2, $POSITION_Y_JIT_LABEL, $TEXT_COLOR_LABEL, $FONT_LABEL, $JIT_TEXT);
imagefttext($im, $FONT_METER_SIZE, 0, $POSITION_X_JIT - $jitMeterBbox[4] / 2 - $msBbox[4] / 2 - $SMALL_SEP / 2, $POSITION_Y_JIT_METER, $TEXT_COLOR_JIT_METER, $FONT_METER, $jit);
imagefttext($im, $FONT_MEASURE_SIZE, 0, $POSITION_X_JIT + $jitMeterBbox[4] / 2 + $SMALL_SEP / 2 - $msBbox[4] / 2, $POSITION_Y_JIT_MEASURE, $TEXT_COLOR_MEASURE, $FONT_MEASURE, $MS_TEXT);
// dl
imagefttext($im, $FONT_LABEL_SIZE_BIG, 0, $POSITION_X_DL - $dlBbox[4] / 2, $POSITION_Y_DL_LABEL, $TEXT_COLOR_LABEL, $FONT_LABEL, $DL_TEXT);
imagefttext($im, $FONT_METER_SIZE_BIG, 0, $POSITION_X_DL - $dlMeterBbox[4] / 2, $POSITION_Y_DL_METER, $TEXT_COLOR_DL_METER, $FONT_METER, $dl);
imagefttext($im, $FONT_MEASURE_SIZE_BIG, 0, $POSITION_X_DL - $mbpsBbox[4] / 2, $POSITION_Y_DL_MEASURE, $TEXT_COLOR_MEASURE, $FONT_MEASURE, $MBPS_TEXT);
// ul
imagefttext($im, $FONT_LABEL_SIZE_BIG, 0, $POSITION_X_UL - $ulBbox[4] / 2, $POSITION_Y_UL_LABEL, $TEXT_COLOR_LABEL, $FONT_LABEL, $UL_TEXT);
imagefttext($im, $FONT_METER_SIZE_BIG, 0, $POSITION_X_UL - $ulMeterBbox[4] / 2, $POSITION_Y_UL_METER, $TEXT_COLOR_UL_METER, $FONT_METER, $ul);
imagefttext($im, $FONT_MEASURE_SIZE_BIG, 0, $POSITION_X_UL - $mbpsBbox[4] / 2, $POSITION_Y_UL_MEASURE, $TEXT_COLOR_MEASURE, $FONT_MEASURE, $MBPS_TEXT);
// isp
imagefttext($im, $FONT_ISP_SIZE, 0, $POSITION_X_ISP, $POSITION_Y_ISP, $TEXT_COLOR_ISP, $FONT_ISP, $ispinfo);
// separator
imagefilledrectangle($im, 0, $SEPARATOR_Y, $WIDTH, $SEPARATOR_Y, $SEPARATOR_COLOR);
// watermark
imagefttext($im, $FONT_WATERMARK_SIZE, 0, $POSITION_X_WATERMARK, $POSITION_Y_WATERMARK, $TEXT_COLOR_WATERMARK, $FONT_WATERMARK, $WATERMARK_TEXT);
// send the image to the browser
header('Content-Type: image/png');
imagepng($im);
}
$speedtest = getSpeedtestUserById($_GET['id']);
if (!is_array($speedtest)) {
exit(1);
}
drawImage($speedtest);

View file

@ -1,6 +1,10 @@
<?php
session_start();
error_reporting(0);
require 'telemetry_settings.php';
require_once 'telemetry_db.php';
header('Content-Type: text/html; charset=utf-8');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0, s-maxage=0');
header('Cache-Control: post-check=0, pre-check=0', false);
@ -8,163 +12,158 @@ header('Pragma: no-cache');
?>
<!DOCTYPE html>
<html>
<head>
<title>LibreSpeed - Stats</title>
<style type="text/css">
html,body{
margin:0;
padding:0;
border:none;
width:100%; min-height:100%;
}
html{
background-color: hsl(198,72%,35%);
font-family: "Segoe UI","Roboto",sans-serif;
}
body{
background-color:#FFFFFF;
box-sizing:border-box;
width:100%;
max-width:70em;
margin:4em auto;
box-shadow:0 1em 6em #00000080;
padding:1em 1em 4em 1em;
border-radius:0.4em;
}
h1,h2,h3,h4,h5,h6{
font-weight:300;
margin-bottom: 0.1em;
}
h1{
text-align:center;
}
table{
margin:2em 0;
width:100%;
}
table, tr, th, td {
border: 1px solid #AAAAAA;
}
th {
width: 6em;
}
td {
word-break: break-all;
}
</style>
</head>
<body>
<h1>LibreSpeed - Stats</h1>
<?php
include_once("telemetry_settings.php");
require "idObfuscation.php";
if($stats_password=="PASSWORD"){
?>
Please set $stats_password in telemetry_settings.php to enable access.
<?php
}else if($_SESSION["logged"]===true){
if($_GET["op"]=="logout"){
$_SESSION["logged"]=false;
?><script type="text/javascript">window.location=location.protocol+"//"+location.host+location.pathname;</script><?php
}else{
$conn=null;
if($db_type=="mysql"){
$conn = new mysqli($MySql_hostname, $MySql_username, $MySql_password, $MySql_databasename, $MySql_port);
}else if($db_type=="sqlite"){
$conn = new PDO("sqlite:$Sqlite_db_file");
} else if($db_type=="postgresql"){
$conn_host = "host=$PostgreSql_hostname";
$conn_db = "dbname=$PostgreSql_databasename";
$conn_user = "user=$PostgreSql_username";
$conn_password = "password=$PostgreSql_password";
$conn = new PDO("pgsql:$conn_host;$conn_db;$conn_user;$conn_password");
}else die();
?>
<form action="stats.php" method="GET"><input type="hidden" name="op" value="logout" /><input type="submit" value="Logout" /></form>
<form action="stats.php" method="GET">
<h3>Search test results</h6>
<input type="hidden" name="op" value="id" />
<input type="text" name="id" id="id" placeholder="Test ID" value=""/>
<input type="submit" value="Find" />
<input type="submit" onclick="document.getElementById('id').value=''" value="Show last 100 tests" />
</form>
<?php
$q=null;
if($_GET["op"]=="id"&&!empty($_GET["id"])){
$id=$_GET["id"];
if($enable_id_obfuscation) $id=deobfuscateId($id);
if($db_type=="mysql"){
$q=$conn->prepare("select id,timestamp,ip,ispinfo,ua,lang,dl,ul,ping,jitter,log,extra from speedtest_users where id=?");
$q->bind_param("i",$id);
$q->execute();
$q->store_result();
$q->bind_result($id,$timestamp,$ip,$ispinfo,$ua,$lang,$dl,$ul,$ping,$jitter,$log,$extra);
} else if($db_type=="sqlite"||$db_type=="postgresql"){
$q=$conn->prepare("select id,timestamp,ip,ispinfo,ua,lang,dl,ul,ping,jitter,log,extra from speedtest_users where id=?");
$q->execute(array($id));
} else die();
}else{
if($db_type=="mysql"){
$q=$conn->prepare("select id,timestamp,ip,ispinfo,ua,lang,dl,ul,ping,jitter,log,extra from speedtest_users order by timestamp desc limit 0,100");
$q->execute();
$q->store_result();
$q->bind_result($id,$timestamp,$ip,$ispinfo,$ua,$lang,$dl,$ul,$ping,$jitter,$log,$extra);
} else if($db_type=="sqlite"||$db_type=="postgresql"){
$q=$conn->prepare("select id,timestamp,ip,ispinfo,ua,lang,dl,ul,ping,jitter,log,extra from speedtest_users order by timestamp desc limit 100");
$q->execute();
}else die();
}
while(true){
$id=null; $timestamp=null; $ip=null; $ispinfo=null; $ua=null; $lang=null; $dl=null; $ul=null; $ping=null; $jitter=null; $log=null; $extra=null;
if($db_type=="mysql"){
if(!$q->fetch()) break;
} else if($db_type=="sqlite"||$db_type=="postgresql"){
if(!($row=$q->fetch())) break;
$id=$row["id"];
$timestamp=$row["timestamp"];
$ip=$row["ip"];
$ispinfo=$row["ispinfo"];
$ua=$row["ua"];
$lang=$row["lang"];
$dl=$row["dl"];
$ul=$row["ul"];
$ping=$row["ping"];
$jitter=$row["jitter"];
$log=$row["log"];
$extra=$row["extra"];
}else die();
?>
<table>
<tr><th>Test ID</th><td><?=htmlspecialchars(($enable_id_obfuscation?(obfuscateId($id)." (deobfuscated: ".$id.")"):$id), ENT_HTML5, 'UTF-8') ?></td></tr>
<tr><th>Date and time</th><td><?=htmlspecialchars($timestamp, ENT_HTML5, 'UTF-8') ?></td></tr>
<tr><th>IP and ISP Info</th><td><?=$ip ?><br/><?=htmlspecialchars($ispinfo, ENT_HTML5, 'UTF-8') ?></td></tr>
<tr><th>User agent and locale</th><td><?=$ua ?><br/><?=htmlspecialchars($lang, ENT_HTML5, 'UTF-8') ?></td></tr>
<tr><th>Download speed</th><td><?=htmlspecialchars($dl, ENT_HTML5, 'UTF-8') ?></td></tr>
<tr><th>Upload speed</th><td><?=htmlspecialchars($ul, ENT_HTML5, 'UTF-8') ?></td></tr>
<tr><th>Ping</th><td><?=htmlspecialchars($ping, ENT_HTML5, 'UTF-8') ?></td></tr>
<tr><th>Jitter</th><td><?=htmlspecialchars($jitter, ENT_HTML5, 'UTF-8') ?></td></tr>
<tr><th>Log</th><td><?=htmlspecialchars($log, ENT_HTML5, 'UTF-8') ?></td></tr>
<tr><th>Extra info</th><td><?=htmlspecialchars($extra, ENT_HTML5, 'UTF-8') ?></td></tr>
</table>
<?php
}
?>
<?php
}
}else{
if($_GET["op"]=="login"&&$_POST["password"]===$stats_password){
$_SESSION["logged"]=true;
?><script type="text/javascript">window.location=location.protocol+"//"+location.host+location.pathname;</script><?php
}else{
?>
<form action="stats.php?op=login" method="POST">
<h3>Login</h3>
<input type="password" name="password" placeholder="Password" value=""/>
<input type="submit" value="Login" />
</form>
<?php
}
}
?>
</body>
<head>
<title>LibreSpeed - Stats</title>
<style type="text/css">
html,body{
margin:0;
padding:0;
border:none;
width:100%; min-height:100%;
}
html{
background-color: hsl(198,72%,35%);
font-family: "Segoe UI","Roboto",sans-serif;
}
body{
background-color:#FFFFFF;
box-sizing:border-box;
width:100%;
max-width:70em;
margin:4em auto;
box-shadow:0 1em 6em #00000080;
padding:1em 1em 4em 1em;
border-radius:0.4em;
}
h1,h2,h3,h4,h5,h6{
font-weight:300;
margin-bottom: 0.1em;
}
h1{
text-align:center;
}
table{
margin:2em 0;
width:100%;
}
table, tr, th, td {
border: 1px solid #AAAAAA;
}
th {
width: 6em;
}
td {
word-break: break-all;
}
div {
margin: 1em 0;
}
</style>
</head>
<body>
<h1>LibreSpeed - Stats</h1>
<?php
if (!isset($stats_password) || $stats_password === 'PASSWORD') {
?>
Please set $stats_password in telemetry_settings.php to enable access.
<?php
} elseif ($_SESSION['logged'] === true) {
if ($_GET['op'] === 'logout') {
$_SESSION['logged'] = false;
?><script type="text/javascript">window.location=location.protocol+"//"+location.host+location.pathname;</script><?php
} else {
?>
<form action="stats.php" method="GET"><input type="hidden" name="op" value="logout" /><input type="submit" value="Logout" /></form>
<form action="stats.php" method="GET">
<h3>Search test results</h3>
<input type="hidden" name="op" value="id" />
<input type="text" name="id" id="id" placeholder="Test ID" value=""/>
<input type="submit" value="Find" />
<input type="submit" onclick="document.getElementById('id').value=''" value="Show last 100 tests" />
</form>
<?php
if ($_GET['op'] === 'id' && !empty($_GET['id'])) {
$speedtest = getSpeedtestUserById($_GET['id']);
$speedtests = [];
if (false === $speedtest) {
echo '<div>There was an error trying to fetch the speedtest result for ID "'.$_GET['id'].'".</div>';
} elseif (null === $speedtest) {
echo '<div>Could not find a speedtest result for ID "'.$_GET['id'].'".</div>';
} else {
$speedtests = [$speedtest];
}
} else {
$speedtests = getLatestSpeedtestUsers();
if (false === $speedtests) {
echo '<div>There was an error trying to fetch latest speedtest results.</div>';
} elseif (empty($speedtests)) {
echo '<div>Could not find any speedtest results in database.</div>';
}
}
foreach ($speedtests as $speedtest) {
?>
<table>
<tr>
<th>Test ID</th>
<td><?= htmlspecialchars($speedtest['id_formatted'], ENT_HTML5, 'UTF-8') ?></td>
</tr>
<tr>
<th>Date and time</th>
<td><?= htmlspecialchars($speedtest['timestamp'], ENT_HTML5, 'UTF-8') ?></td>
</tr>
<tr>
<th>IP and ISP Info</th>
<td>
<?= htmlspecialchars($speedtest['ip'], ENT_HTML5, 'UTF-8') ?><br/>
<?= htmlspecialchars($speedtest['ispinfo'], ENT_HTML5, 'UTF-8') ?>
</td>
</tr>
<tr>
<th>User agent and locale</th>
<td><?= htmlspecialchars($speedtest['ua'], ENT_HTML5, 'UTF-8') ?><br/>
<?= htmlspecialchars($speedtest['lang'], ENT_HTML5, 'UTF-8') ?>
</td>
</tr>
<tr>
<th>Download speed</th>
<td><?= htmlspecialchars($speedtest['dl'], ENT_HTML5, 'UTF-8') ?></td>
</tr>
<tr>
<th>Upload speed</th>
<td><?= htmlspecialchars($speedtest['ul'], ENT_HTML5, 'UTF-8') ?></td>
</tr>
<tr>
<th>Ping</th>
<td><?= htmlspecialchars($speedtest['ping'], ENT_HTML5, 'UTF-8') ?></td>
</tr>
<tr>
<th>Jitter</th>
<td><?= htmlspecialchars($speedtest['jitter'], ENT_HTML5, 'UTF-8') ?></td>
</tr>
<tr>
<th>Log</th>
<td><?= htmlspecialchars($speedtest['log'], ENT_HTML5, 'UTF-8') ?></td>
</tr>
<tr>
<th>Extra info</th>
<td><?= htmlspecialchars($speedtest['extra'], ENT_HTML5, 'UTF-8') ?></td>
</tr>
</table>
<?php
}
}
} elseif ($_GET['op'] === 'login' && $_POST['password'] === $stats_password) {
$_SESSION['logged'] = true;
?><script type="text/javascript">window.location=location.protocol+"//"+location.host+location.pathname;</script><?php
} else {
?>
<form action="stats.php?op=login" method="POST">
<h3>Login</h3>
<input type="password" name="password" placeholder="Password" value=""/>
<input type="submit" value="Login" />
</form>
<?php
}
?>
</body>
</html>

View file

@ -1,81 +1,42 @@
<?php
include_once('telemetry_settings.php');
require 'idObfuscation.php';
$ip=($_SERVER['REMOTE_ADDR']);
$ispinfo=($_POST["ispinfo"]);
$extra=($_POST["extra"]);
$ua=($_SERVER['HTTP_USER_AGENT']);
$lang=""; if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) $lang=($_SERVER['HTTP_ACCEPT_LANGUAGE']);
$dl=($_POST["dl"]);
$ul=($_POST["ul"]);
$ping=($_POST["ping"]);
$jitter=($_POST["jitter"]);
$log=($_POST["log"]);
require 'telemetry_settings.php';
require_once 'telemetry_db.php';
if($redact_ip_addresses){
$ip="0.0.0.0";
$ipv4_regex='/(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/';
$ipv6_regex='/(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/';
$hostname_regex='/"hostname":"([^\\\\"]|\\\\")*"/';
$ispinfo=preg_replace($ipv4_regex,"0.0.0.0",$ispinfo);
$ispinfo=preg_replace($ipv6_regex,"0.0.0.0",$ispinfo);
$ispinfo=preg_replace($hostname_regex,"\"hostname\":\"REDACTED\"",$ispinfo);
$log=preg_replace($ipv4_regex,"0.0.0.0",$log);
$log=preg_replace($ipv6_regex,"0.0.0.0",$log);
$log=preg_replace($hostname_regex,"\"hostname\":\"REDACTED\"",$log);
$ip = $_SERVER['REMOTE_ADDR'];
$ispinfo = $_POST['ispinfo'];
$extra = $_POST['extra'];
$ua = $_SERVER['HTTP_USER_AGENT'];
$lang = '';
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$lang = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
}
$dl = $_POST['dl'];
$ul = $_POST['ul'];
$ping = $_POST['ping'];
$jitter = $_POST['jitter'];
$log = $_POST['log'];
if (isset($redact_ip_addresses) && true === $redact_ip_addresses) {
$ip = '0.0.0.0';
$ipv4_regex = '/(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/';
$ipv6_regex = '/(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/';
$hostname_regex = '/"hostname":"([^\\\\"]|\\\\")*"/';
$ispinfo = preg_replace($ipv4_regex, '0.0.0.0', $ispinfo);
$ispinfo = preg_replace($ipv6_regex, '0.0.0.0', $ispinfo);
$ispinfo = preg_replace($hostname_regex, '"hostname":"REDACTED"', $ispinfo);
$log = preg_replace($ipv4_regex, '0.0.0.0', $log);
$log = preg_replace($ipv6_regex, '0.0.0.0', $log);
$log = preg_replace($hostname_regex, '"hostname":"REDACTED"', $log);
}
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0, s-maxage=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
if($db_type=="mysql"){
$conn = new mysqli($MySql_hostname, $MySql_username, $MySql_password, $MySql_databasename, $MySql_port) or die("1");
$stmt = $conn->prepare("INSERT INTO speedtest_users (ip,ispinfo,extra,ua,lang,dl,ul,ping,jitter,log) VALUES (?,?,?,?,?,?,?,?,?,?)") or die("2");
$stmt->bind_param("ssssssssss",$ip,$ispinfo,$extra,$ua,$lang,$dl,$ul,$ping,$jitter,$log) or die("3");
$stmt->execute() or die("4");
$stmt->close() or die("5");
$id=$conn->insert_id;
echo "id ".($enable_id_obfuscation?obfuscateId($id):$id);
$conn->close() or die("6");
}elseif($db_type=="sqlite"){
$conn = new PDO("sqlite:$Sqlite_db_file") or die("1");
$conn->exec("
CREATE TABLE IF NOT EXISTS `speedtest_users` (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`ispinfo` text,
`extra` text,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ip` text NOT NULL,
`ua` text NOT NULL,
`lang` text NOT NULL,
`dl` text,
`ul` text,
`ping` text,
`jitter` text,
`log` longtext
);
");
$stmt = $conn->prepare("INSERT INTO speedtest_users (ip,ispinfo,extra,ua,lang,dl,ul,ping,jitter,log) VALUES (?,?,?,?,?,?,?,?,?,?)") or die("2");
$stmt->execute(array($ip,$ispinfo,$extra,$ua,$lang,$dl,$ul,$ping,$jitter,$log)) or die("3");
$id=$conn->lastInsertId();
echo "id ".($enable_id_obfuscation?obfuscateId($id):$id);
$conn = null;
}elseif($db_type=="postgresql"){
// Prepare connection parameters for db connection
$conn_host = "host=$PostgreSql_hostname";
$conn_db = "dbname=$PostgreSql_databasename";
$conn_user = "user=$PostgreSql_username";
$conn_password = "password=$PostgreSql_password";
// Create db connection
$conn = new PDO("pgsql:$conn_host;$conn_db;$conn_user;$conn_password") or die("1");
$stmt = $conn->prepare("INSERT INTO speedtest_users (ip,ispinfo,extra,ua,lang,dl,ul,ping,jitter,log) VALUES (?,?,?,?,?,?,?,?,?,?)") or die("2");
$stmt->execute(array($ip,$ispinfo,$extra,$ua,$lang,$dl,$ul,$ping,$jitter,$log)) or die("3");
$id=$conn->lastInsertId();
echo "id ".($enable_id_obfuscation?obfuscateId($id):$id);
$conn = null;
$id = insertSpeedtestUser($ip, $ispinfo, $extra, $ua, $lang, $dl, $ul, $ping, $jitter, $log);
if (false === $id) {
exit(1);
}
else die("-1");
?>
echo 'id '.$id;

220
results/telemetry_db.php Normal file
View file

@ -0,0 +1,220 @@
<?php
require_once 'idObfuscation.php';
define('TELEMETRY_SETTINGS_FILE', 'telemetry_settings.php');
/**
* @return PDO|false
*/
function getPdo()
{
if (
!file_exists(TELEMETRY_SETTINGS_FILE)
|| !is_readable(TELEMETRY_SETTINGS_FILE)
) {
return false;
}
require TELEMETRY_SETTINGS_FILE;
if (!isset($db_type)) {
return false;
}
$pdoOptions = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
];
try {
if ('mysql' === $db_type) {
if (!isset(
$MySql_hostname,
$MySql_port,
$MySql_databasename,
$MySql_username,
$MySql_password
)) {
return false;
}
$dsn = 'mysql:'
.'host='.$MySql_hostname
.';port='.$MySql_port
.';dbname='.$MySql_databasename;
return new PDO($dsn, $MySql_username, $MySql_password, $pdoOptions);
}
if ('sqlite' === $db_type) {
if (!isset($Sqlite_db_file)) {
return false;
}
$pdo = new PDO('sqlite:'.$Sqlite_db_file, null, null, $pdoOptions);
$pdo->exec('
CREATE TABLE IF NOT EXISTS `speedtest_users` (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`ispinfo` text,
`extra` text,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ip` text NOT NULL,
`ua` text NOT NULL,
`lang` text NOT NULL,
`dl` text,
`ul` text,
`ping` text,
`jitter` text,
`log` longtext
);
');
return $pdo;
}
if ('postgresql' === $db_type) {
if (!isset(
$PostgreSql_hostname,
$PostgreSql_databasename,
$PostgreSql_username,
$PostgreSql_password
)) {
return false;
}
$dsn = 'pgsql:'
.'host='.$PostgreSql_hostname
.';dbname='.$PostgreSql_databasename;
return new PDO($dsn, $PostgreSql_username, $PostgreSql_password, $pdoOptions);
}
} catch (Exception $e) {
return false;
}
return false;
}
/**
* @return bool
*/
function isObfuscationEnabled()
{
require TELEMETRY_SETTINGS_FILE;
return
isset($enable_id_obfuscation)
&& true === $enable_id_obfuscation;
}
/**
* @return string|false returns the id of the inserted column or false on error
*/
function insertSpeedtestUser($ip, $ispinfo, $extra, $ua, $lang, $dl, $ul, $ping, $jitter, $log)
{
$pdo = getPdo();
if (!($pdo instanceof PDO)) {
return false;
}
try {
$stmt = $pdo->prepare(
'INSERT INTO speedtest_users
(ip,ispinfo,extra,ua,lang,dl,ul,ping,jitter,log)
VALUES (?,?,?,?,?,?,?,?,?,?)'
);
$stmt->execute([
$ip, $ispinfo, $extra, $ua, $lang, $dl, $ul, $ping, $jitter, $log
]);
$id = $pdo->lastInsertId();
} catch (Exception $e) {
return false;
}
if (isObfuscationEnabled()) {
return obfuscateId($id);
}
return $id;
}
/**
* @param int|string $id
*
* @return array|null|false returns the speedtest data as array, null
* if no data is found for the given id or
* false if there was an error
*
* @throws RuntimeException
*/
function getSpeedtestUserById($id)
{
$pdo = getPdo();
if (!($pdo instanceof PDO)) {
return false;
}
if (isObfuscationEnabled()) {
$id = deobfuscateId($id);
}
try {
$stmt = $pdo->prepare(
'SELECT
id, timestamp, ip, ispinfo, ua, lang, dl, ul, ping, jitter, log, extra
FROM speedtest_users
WHERE id = :id'
);
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
} catch (Exception $e) {
return false;
}
if (!is_array($row)) {
return null;
}
$row['id_formatted'] = $row['id'];
if (isObfuscationEnabled()) {
$row['id_formatted'] = obfuscateId($row['id']).' (deobfuscated: '.$row['id'].')';
}
return $row;
}
/**
* @return array|false
*/
function getLatestSpeedtestUsers()
{
$pdo = getPdo();
if (!($pdo instanceof PDO)) {
return false;
}
try {
$stmt = $pdo->query(
'SELECT
id, timestamp, ip, ispinfo, ua, lang, dl, ul, ping, jitter, log, extra
FROM speedtest_users
ORDER BY timestamp DESC
LIMIT 100'
);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $i => $row) {
$rows[$i]['id_formatted'] = $row['id'];
if (isObfuscationEnabled()) {
$rows[$i]['id_formatted'] = obfuscateId($row['id']).' (deobfuscated: '.$row['id'].')';
}
}
} catch (Exception $e) {
return false;
}
return $rows;
}

View file

@ -1,26 +1,26 @@
<?php
$db_type="mysql"; //Type of db: "mysql", "sqlite" or "postgresql"
$stats_password="PASSWORD"; //password to login to stats.php. Change this!!!
$enable_id_obfuscation=false; //if set to true, test IDs will be obfuscated to prevent users from guessing URLs of other tests
$redact_ip_addresses=false; //if set to true, IP addresses will be redacted from IP and ISP info fields, as well as the log
// Type of db: "mysql", "sqlite" or "postgresql"
$db_type = 'mysql';
// Password to login to stats.php. Change this!!!
$stats_password = 'PASSWORD';
// If set to true, test IDs will be obfuscated to prevent users from guessing URLs of other tests
$enable_id_obfuscation = false;
// If set to true, IP addresses will be redacted from IP and ISP info fields, as well as the log
$redact_ip_addresses = false;
// Sqlite3 settings
$Sqlite_db_file = "../../speedtest_telemetry.sql";
$Sqlite_db_file = '../../speedtest_telemetry.sql';
// Mysql settings
$MySql_username="USERNAME";
$MySql_password="PASSWORD";
$MySql_hostname="DB_HOSTNAME";
$MySql_databasename="DB_NAME";
$MySql_port="3306";
$MySql_username = 'USERNAME';
$MySql_password = 'PASSWORD';
$MySql_hostname = 'DB_HOSTNAME';
$MySql_databasename = 'DB_NAME';
$MySql_port = '3306';
// Postgresql settings
$PostgreSql_username="USERNAME";
$PostgreSql_password="PASSWORD";
$PostgreSql_hostname="DB_HOSTNAME";
$PostgreSql_databasename="DB_NAME";
//IMPORTANT: DO NOT ADD ANYTHING BELOW THIS PHP CLOSING TAG, NOT EVEN EMPTY LINES!
?>
$PostgreSql_username = 'USERNAME';
$PostgreSql_password = 'PASSWORD';
$PostgreSql_hostname = 'DB_HOSTNAME';
$PostgreSql_databasename = 'DB_NAME';