diff --git a/backend/garbage.php b/backend/garbage.php index e2fcc78..89ab6c9 100644 --- a/backend/garbage.php +++ b/backend/garbage.php @@ -1,31 +1,63 @@ 1024) { + return 1024; + } + + return (int) $_GET['ckSize']; } -// Download follows... -header('Content-Description: File Transfer'); -header('Content-Type: application/octet-stream'); -header('Content-Disposition: attachment; filename=random.dat'); -header('Content-Transfer-Encoding: binary'); -// Never cache me -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'); + +/** + * @return void + */ +function sendHeaders() +{ + header('HTTP/1.1 200 OK'); + + if (isset($_GET['cors'])) { + header('Access-Control-Allow-Origin: *'); + header('Access-Control-Allow-Methods: GET, POST'); + } + + // Indicate a file download + header('Content-Description: File Transfer'); + header('Content-Type: application/octet-stream'); + header('Content-Disposition: attachment; filename=random.dat'); + header('Content-Transfer-Encoding: binary'); + + // Cache settings: never cache this request + 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'); +} + +// Determine how much data we should send +$chunks = getChunkCount(); + // Generate data -$data=openssl_random_pseudo_bytes(1048576); +$data = openssl_random_pseudo_bytes(1048576); + // Deliver chunks of 1048576 bytes -$chunks=isset($_GET['ckSize']) ? intval($_GET['ckSize']) : 4; -if(empty($chunks)){$chunks = 4;} -if($chunks>1024){$chunks = 1024;} -for($i=0;$i<$chunks;$i++){ +sendHeaders(); +for ($i = 0; $i < $chunks; $i++) { echo $data; flush(); } -?> diff --git a/backend/getIP.php b/backend/getIP.php index 7d7c400..a2ed9a0 100644 --- a/backend/getIP.php +++ b/backend/getIP.php @@ -1,59 +1,177 @@ $ip . " - localhost IPv6 access", 'rawIspInfo' => ""]); - die(); + // simplified IPv6 link-local address (should match fe80::/10) + if (stripos($ip, 'fe80:') === 0) { + return 'link-local IPv6 access'; + } + + // anything within the 127/8 range is localhost ipv4, the ip must start with 127.0 + if (strpos($ip, '127.') === 0) { + return 'localhost IPv4 access'; + } + + // 10/8 private IPv4 + if (strpos($ip, '10.') === 0) { + return 'private IPv4 access'; + } + + // 172.16/12 private IPv4 + if (preg_match('/^172\.(1[6-9]|2\d|3[01])\./', $ip) === 1) { + return 'private IPv4 access'; + } + + // 192.168/16 private IPv4 + if (strpos($ip, '192.168.') === 0) { + return 'private IPv4 access'; + } + + // IPv4 link-local + if (strpos($ip, '169.254.') === 0) { + return 'link-local IPv4 access'; + } + + return null; } -if (stripos($ip, 'fe80:') === 0) { // simplified IPv6 link-local address (should match fe80::/10) - echo json_encode(['processedString' => $ip . " - link-local IPv6 access", 'rawIspInfo' => ""]); - die(); + +/** + * @return string + */ +function getIpInfoTokenString() +{ + if ( + !file_exists(API_KEY_FILE) + || !is_readable(API_KEY_FILE) + ) { + return ''; + } + + require API_KEY_FILE; + + if (empty($IPINFO_APIKEY)) { + return ''; + } + + return '?token='.$IPINFO_APIKEY; } -if (strpos($ip, '127.') === 0) { //anything within the 127/8 range is localhost ipv4, the ip must start with 127.0 - echo json_encode(['processedString' => $ip . " - localhost IPv4 access", 'rawIspInfo' => ""]); - die(); + +/** + * @param string $ip + * + * @return array|null + */ +function getIspInfo($ip) +{ + $json = file_get_contents('https://ipinfo.io/'.$ip.'/json'.getIpInfoTokenString()); + if (!is_string($json)) { + return null; + } + + $data = json_decode($json, true); + if (!is_array($data)) { + return null; + } + + return $data; } -if (strpos($ip, '10.') === 0) { // 10/8 private IPv4 - echo json_encode(['processedString' => $ip . " - private IPv4 access", 'rawIspInfo' => ""]); - die(); + +/** + * @param array|null $rawIspInfo + * + * @return string + */ +function getIsp($rawIspInfo) +{ + if ( + !is_array($rawIspInfo) + || !array_key_exists('org', $rawIspInfo) + || !is_string($rawIspInfo['org']) + || empty($rawIspInfo['org']) + ) { + return 'Unknown ISP'; + } + + // Remove AS##### from ISP name, if present + return preg_replace('/AS\\d+\\s/', '', $rawIspInfo['org']); } -if (preg_match('/^172\.(1[6-9]|2\d|3[01])\./', $ip) === 1) { // 172.16/12 private IPv4 - echo json_encode(['processedString' => $ip . " - private IPv4 access", 'rawIspInfo' => ""]); - die(); -} -if (strpos($ip, '192.168.') === 0) { // 192.168/16 private IPv4 - echo json_encode(['processedString' => $ip . " - private IPv4 access", 'rawIspInfo' => ""]); - die(); -} -if (strpos($ip, '169.254.') === 0) { // IPv4 link-local - echo json_encode(['processedString' => $ip . " - link-local IPv4 access", 'rawIspInfo' => ""]); - die(); + +/** + * @return string|null + */ +function getServerLocation() +{ + $serverLoc = null; + if ( + file_exists(SERVER_LOCATION_CACHE_FILE) + && is_readable(SERVER_LOCATION_CACHE_FILE) + ) { + require SERVER_LOCATION_CACHE_FILE; + } + if (is_string($serverLoc) && !empty($serverLoc)) { + return $serverLoc; + } + + $json = file_get_contents('https://ipinfo.io/json'.getIpInfoTokenString()); + if (!is_string($json)) { + return null; + } + + $details = json_decode($json, true); + if ( + !is_array($details) + || !array_key_exists('loc', $details) + || !is_string($details['loc']) + || empty($details['loc']) + ) { + return null; + } + + $serverLoc = $details['loc']; + $cacheData = " $ip . " - " . $isp, 'rawIspInfo' => $rawIspInfo]); -} else { - echo json_encode(['processedString' => $ip, 'rawIspInfo' => ""]); + + $unit = $_GET['distance']; + $clientLocation = $rawIspInfo['loc']; + $serverLocation = getServerLocation(); + + if (!is_string($serverLocation)) { + return null; + } + + return calculateDistance( + $serverLocation, + $clientLocation, + $unit + ); } -?> + +/** + * @param string $clientLocation + * @param string $serverLocation + * @param string $unit + * + * @return string + */ +function calculateDistance($clientLocation, $serverLocation, $unit) +{ + list($clientLatitude, $clientLongitude) = explode(',', $clientLocation); + list($serverLatitude, $serverLongitude) = explode(',', $serverLocation); + $dist = distance( + $clientLatitude, + $clientLongitude, + $serverLatitude, + $serverLongitude + ); + + if ('mi' === $unit) { + $dist /= 1.609344; + $dist = round($dist, -1); + if ($dist < 15) { + $dist = '<15'; + } + + return $dist.' mi'; + } + + if ('km' === $unit) { + $dist = round($dist, -1); + if ($dist < 20) { + $dist = '<20'; + } + + return $dist.' km'; + } + + return null; +} + +/** + * @return void + */ +function sendHeaders() +{ + header('Content-Type: application/json; charset=utf-8'); + + if (isset($_GET['cors'])) { + header('Access-Control-Allow-Origin: *'); + header('Access-Control-Allow-Methods: GET, POST'); + } + + 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'); +} + +/** + * @param string $ip + * @param string|null $ipInfo + * @param string|null $distance + * @param array|null $rawIspInfo + * + * @return void + */ +function sendResponse( + $ip, + $ipInfo = null, + $distance = null, + $rawIspInfo = null +) { + $processedString = $ip; + if (is_string($ipInfo)) { + $processedString .= ' - '.$ipInfo; + } + + if ( + is_array($rawIspInfo) + && array_key_exists('country', $rawIspInfo) + ) { + $processedString .= ', '.$rawIspInfo['country']; + } + if (is_string($distance)) { + $processedString .= ' ('.$distance.')'; + } + + sendHeaders(); + echo json_encode([ + 'processedString' => $processedString, + 'rawIspInfo' => $rawIspInfo ?: '', + ]); +} + +$ip = getClientIp(); + +$localIpInfo = getLocalOrPrivateIpInfo($ip); +// local ip, no need to fetch further information +if (is_string($localIpInfo)) { + sendResponse($ip, $localIpInfo); + exit; +} + +if (!isset($_GET['isp'])) { + sendResponse($ip); + exit; +} + +$rawIspInfo = getIspInfo($ip); +$isp = getIsp($rawIspInfo); +$distance = getDistance($rawIspInfo); + +sendResponse($ip, $isp, $distance, $rawIspInfo); diff --git a/backend/getIP_ipInfo_apikey.php b/backend/getIP_ipInfo_apikey.php index 49da1dc..e200c3f 100644 --- a/backend/getIP_ipInfo_apikey.php +++ b/backend/getIP_ipInfo_apikey.php @@ -1,3 +1,4 @@ \ No newline at end of file + +// put your token between the quotes if you have one +$IPINFO_APIKEY = ''; diff --git a/results/idObfuscation.php b/results/idObfuscation.php index 3b4482a..f7dd8a5 100644 --- a/results/idObfuscation.php +++ b/results/idObfuscation.php @@ -1,43 +1,72 @@ >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 = " \ No newline at end of file +/** + * 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; +} diff --git a/results/index.php b/results/index.php index a9dac38..bfd6025 100644 --- a/results/index.php +++ b/results/index.php @@ -1,164 +1,224 @@ 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']); + $speedtest['timestamp'] = $speedtest['timestamp']; -$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']; + $timestamp = $data['timestamp']; + + // 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_TIMESTAMP = tryFont("OpenSans-Light"); + $FONT_TIMESTAMP_SIZE = 8 * $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_TIMESTAMP = imagecolorallocate($im, 160, 160, 160); + $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_X_TIMESTAMP= 4 * $SCALE; + $POSITION_Y_TIMESTAMP = 223 * $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); + // timestamp + imagefttext($im, $FONT_TIMESTAMP_SIZE, 0, $POSITION_X_TIMESTAMP, $POSITION_Y_TIMESTAMP, $TEXT_COLOR_TIMESTAMP, $FONT_TIMESTAMP, $timestamp); + // 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); diff --git a/results/stats.php b/results/stats.php index 1e6ff1c..be35a6e 100644 --- a/results/stats.php +++ b/results/stats.php @@ -1,6 +1,10 @@ -
-Test ID | =htmlspecialchars(($enable_id_obfuscation?(obfuscateId($id)." (deobfuscated: ".$id.")"):$id), ENT_HTML5, 'UTF-8') ?> |
---|---|
Date and time | =htmlspecialchars($timestamp, ENT_HTML5, 'UTF-8') ?> |
IP and ISP Info | =$ip ?> =htmlspecialchars($ispinfo, ENT_HTML5, 'UTF-8') ?> |
User agent and locale | =$ua ?> =htmlspecialchars($lang, ENT_HTML5, 'UTF-8') ?> |
Download speed | =htmlspecialchars($dl, ENT_HTML5, 'UTF-8') ?> |
Upload speed | =htmlspecialchars($ul, ENT_HTML5, 'UTF-8') ?> |
Ping | =htmlspecialchars($ping, ENT_HTML5, 'UTF-8') ?> |
Jitter | =htmlspecialchars($jitter, ENT_HTML5, 'UTF-8') ?> |
Log | =htmlspecialchars($log, ENT_HTML5, 'UTF-8') ?> |
Extra info | =htmlspecialchars($extra, ENT_HTML5, 'UTF-8') ?> |
Test ID | += htmlspecialchars($speedtest['id_formatted'], ENT_HTML5, 'UTF-8') ?> | +
---|---|
Date and time | += htmlspecialchars($speedtest['timestamp'], ENT_HTML5, 'UTF-8') ?> | +
IP and ISP Info | +
+ = htmlspecialchars($speedtest['ip'], ENT_HTML5, 'UTF-8') ?> + = htmlspecialchars($speedtest['ispinfo'], ENT_HTML5, 'UTF-8') ?> + |
+
User agent and locale | += htmlspecialchars($speedtest['ua'], ENT_HTML5, 'UTF-8') ?> + = htmlspecialchars($speedtest['lang'], ENT_HTML5, 'UTF-8') ?> + |
+
Download speed | += htmlspecialchars($speedtest['dl'], ENT_HTML5, 'UTF-8') ?> | +
Upload speed | += htmlspecialchars($speedtest['ul'], ENT_HTML5, 'UTF-8') ?> | +
Ping | += htmlspecialchars($speedtest['ping'], ENT_HTML5, 'UTF-8') ?> | +
Jitter | += htmlspecialchars($speedtest['jitter'], ENT_HTML5, 'UTF-8') ?> | +
Log | += htmlspecialchars($speedtest['log'], ENT_HTML5, 'UTF-8') ?> | +
Extra info | += htmlspecialchars($speedtest['extra'], ENT_HTML5, 'UTF-8') ?> | +