PHPIndex

This page lists files in the current directory. You can view content, get download/execute commands for Wget, Curl, or PowerShell, or filter the list using wildcards (e.g., `*.sh`).

OpenSans-Light.ttf
wget 'https://sme10.lists2.roe3.org/speedtest/results/OpenSans-Light.ttf'
View Content
OpenSans-Semibold.ttf
wget 'https://sme10.lists2.roe3.org/speedtest/results/OpenSans-Semibold.ttf'
View Content
idObfuscation.php
wget 'https://sme10.lists2.roe3.org/speedtest/results/idObfuscation.php'
View Content
<?php

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;
}

/**
 * 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;
}
json.php
wget 'https://sme10.lists2.roe3.org/speedtest/results/json.php'
View Content
<?php

error_reporting(0);
header('Content-Type: application/json; charset=utf-8');

require_once 'telemetry_db.php';

/**
 * @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, '.', '');
    }

    return number_format($d, 0, '.', '');
}

/**
 * @param array $speedtest
 *
 * @return array
 */
function formatSpeedtestData($speedtest)
{
    // format values for the image
    $speedtest['dl'] = format($speedtest['dl']);
    $speedtest['ul'] = format($speedtest['ul']);
    $speedtest['ping'] = format($speedtest['ping']);
    $speedtest['jitter'] = format($speedtest['jitter']);
    $speedtest['timestamp'] = $speedtest['timestamp'];

    $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 = '';
    }

    $speedtest['ispinfo'] = $ispinfo;

    return $speedtest;
}

$speedtest = getSpeedtestUserById($_GET['id']);
if (!is_array($speedtest)) {
    echo '{}';
} else {
    $speedtest = formatSpeedtestData($speedtest);
    echo json_encode(array('timestamp'=>$speedtest['timestamp'],'download'=>$speedtest['dl'],'upload'=>$speedtest['ul'],'ping'=>$speedtest['ping'],'jitter'=>$speedtest['jitter'],'ispinfo'=>$speedtest['ispinfo']));
}
sanitycheck.php
wget 'https://sme10.lists2.roe3.org/speedtest/results/sanitycheck.php'
View Content
<?php
require_once 'telemetry_settings.php';
require_once 'telemetry_db.php';
require_once '../backend/getIP_util.php';

error_reporting(E_ALL);

$pass="<span class='Pass'>Pass</span>";
$failed="<span class='Failed'>failed</span>";
$na="<span class='na'>N/A</span>";
?>

<html>
<head>
<title>Speed Test installation sanity check</title>
<style>
	table,th,td { border: 1px solid;}
	.Pass   { color:green;}
	.Failed { color:red;}
	.na     { color:orange;}
	.SectionHeading { font-style: italic;}
</style>
</head>
<body>
<table><tr><th>Item</th><th>Status</th><th>Comment</th></tr>
<tr><td colspan="3" class='SectionHeading'>PHP extensions</td></tr>

<tr><td>gd</td><td>
<?php
if(extension_loaded('gd')){
	echo $pass;
} else {
	echo $failed;
}
?>
</td><td>Used to render result images.</td></tr>

<tr><td>openssl</td><td>
<?php
if(extension_loaded('openssl')){
	echo $pass;
} else {
	echo $failed;
}
?>
</td><td></td></tr>

<tr><td>pdo_sqlsrv</td><td>
<?php
if(!isset($db_type) || $db_type != 'mssql'){
	echo $na;
}elseif(extension_loaded('pdo_sqlsrv')){
	echo $pass;
} else {
	echo $failed;
}
?>
</td><td>Only required if using MS SQL.</td></tr>

<tr><td>pdo_mysql</td><td>
<?php
if(!isset($db_type) || $db_type != 'mysql'){
	echo $na;
}elseif(extension_loaded('pdo_mysql')){
	echo $pass;
} else {
	echo $failed;
}
?>
</td><td>Only required if using mysql.</td></tr>

<tr><td>pdo_sqlite</td><td>
<?php
if(!isset($db_type) || $db_type != 'sqlite'){
	echo $na;
}elseif(extension_loaded('pdo_sqlite')){
	echo $pass;
} else {
	echo $failed;
}
?>
</td><td>Only required if using sqlite.</td></tr>


<tr><td>pdo_pgsql</td><td>
<?php
if(!isset($db_type) || $db_type != 'postgresql'){
	echo $na;
}elseif(extension_loaded('pdo_pgsql')){
	echo $pass;
} else {
	echo $failed;
}
?>
</td><td>Only required if using postgresql.</td></tr>


<tr><td colspan="3" class='SectionHeading'>Database check</td></tr>
<tr><td>Connecting to DB</td><td>
<?php
	$pdo = getPdo(true);
	if (($pdo instanceof PDO)) {
		echo $pass;
		echo "</td><td></td>";
	} else {
		echo $failed;
		echo "</td><td>". htmlspecialchars($pdo) . "</td>";
	}
?>
</tr>

<tr><td>Insert into DB</td><td>
<?php
	$ip = getClientIp();
	$ispinfo="";
	$extra='{"DBTest":"This is a simple test of the database.  No speed test was done."}';
	$ua = $_SERVER['HTTP_USER_AGENT'];
	$lang = '';
	if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
		$lang = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
	}

	$dl=$ul=$ping=$jitter="";
	$log="";

	$insertResult = insertSpeedtestUser($ip, $ispinfo, $extra, $ua, $lang, $dl, $ul, $ping, $jitter, $log, true);
	
	if(($insertResult instanceof Exception)){
		echo $failed;
		echo "</td><td>";
		echo htmlspecialchars($insertResult->getMessage()) . "</td>";
	} else {
		echo $pass;
		echo "</td><td></td>";
	}
?>
</tr>

<tr><td>Read from DB</td><td>
<?php
	if(!($insertResult instanceof Exception)){
		$QueryResult = getSpeedtestUserById($insertResult,true);
		
		if(($QueryResult instanceof Exception)){
			echo $failed;
			echo "</td><td>";
			echo htmlspecialchars($insertResult->getMessage()) . "</td>";
		} elseif(!is_array($QueryResult)) {
			echo $failed;
			echo "</td><td>Test result not retrieved from database.</td>";
		} else {
			echo $pass;
			echo "</td><td></td>";
		}
	} else {
		echo "</td><td>Insert failed so can't test reading inserted data</td>";
	}
?>
</tr>

</table>
</body>
</html>
<?php
/*
$speedtests = getLatestSpeedtestUsers();
print_r ($speedtests);


echo '   ';
print_r($pdo);
if(!isset($pdo)){
	echo 'got nothing';
}
if($pdo == false){
	echo 'got a false';
}
if (!($pdo instanceof PDO)) {
    echo 'not a PDO';
}
if (($pdo instanceof PDO)) {
    echo 'is PDO';
}


$speedtest = getSpeedtestUserById(1);
print_r ($speedtest);
*/
?>
stats.php
wget 'https://sme10.lists2.roe3.org/speedtest/results/stats.php'
View Content
<?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);
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;
            }
            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 test result for ID "'.htmlspecialchars($_GET['id'], ENT_HTML5, 'UTF-8').'".</div>';
                    } elseif (null === $speedtest) {
                        echo '<div>Could not find a test result for ID "'.htmlspecialchars($_GET['id'], ENT_HTML5, 'UTF-8').'".</div>';
                    } else {
                        $speedtests = [$speedtest];
                    }
                } else {
                    $speedtests = getLatestSpeedtestUsers();
                    if (false === $speedtests) {
                        echo '<div>There was an error trying to fetch latest test results.</div>';
                    } elseif (empty($speedtests)) {
                        echo '<div>Could not find any test 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>
telemetry.php
wget 'https://sme10.lists2.roe3.org/speedtest/results/telemetry.php'
View Content
<?php

require 'telemetry_settings.php';
require_once 'telemetry_db.php';
require_once '../backend/getIP_util.php';

$ip = getClientIp();
$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');

$id = insertSpeedtestUser($ip, $ispinfo, $extra, $ua, $lang, $dl, $ul, $ping, $jitter, $log);
if (false === $id) {
    exit(1);
}

echo 'id '.$id;
telemetry_db.php
wget 'https://sme10.lists2.roe3.org/speedtest/results/telemetry_db.php'
View Content
<?php

require_once 'idObfuscation.php';

define('TELEMETRY_SETTINGS_FILE', 'telemetry_settings.php');

/**
 * @return PDO|false
 */
function getPdo($returnErrorMessage = false)
{
    if (
        !file_exists(TELEMETRY_SETTINGS_FILE)
        || !is_readable(TELEMETRY_SETTINGS_FILE)
    ) {
		if($returnErrorMessage){
			return 'missing TELEMETRY_SETTINGS_FILE';
		}
        return false;
    }

    require TELEMETRY_SETTINGS_FILE;

    if (!isset($db_type)) {
		if($returnErrorMessage){
			return "db_type not set in '" . TELEMETRY_SETTINGS_FILE . "'";
		}
        return false;
    }

    $pdoOptions = [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    ];

    try {
        if ('mssql' === $db_type) {
            if (!isset(
                $MsSql_server,
                $MsSql_databasename,
				$MsSql_WindowsAuthentication
            )) {
				if($returnErrorMessage){
					return "Required MSSQL database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'";
				}
                return false;
            }
			
			if (!$MsSql_WindowsAuthentication and
			    !isset(
						$MsSql_username,
						$MsSql_password
						)
				) {
				if($returnErrorMessage){
					return "Required MSSQL database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'";
				}
                return false;
            }
            $dsn = 'sqlsrv:'
                .'server='.$MsSql_server
                .';Database='.$MsSql_databasename;
			
			if($MsSql_TrustServerCertificate === true){
				$dsn = $dsn . ';TrustServerCertificate=1';
			}
			if($MsSql_TrustServerCertificate === false){
				$dsn = $dsn . ';TrustServerCertificate=0';
			}
			
			if($MsSql_WindowsAuthentication){
				return new PDO($dsn, "", "", $pdoOptions);
			} else {
				return new PDO($dsn, $MsSql_username, $MsSql_password, $pdoOptions);
			}
        }

        if ('mysql' === $db_type) {
            if (!isset(
                $MySql_hostname,
                $MySql_port,
                $MySql_databasename,
                $MySql_username,
                $MySql_password
            )) {
                if($returnErrorMessage){
					return "Required mysql database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'";
				}
				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)) {
				if($returnErrorMessage){
					return "Required sqlite database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'";
				}
                return false;
            }

            $pdo = new PDO('sqlite:'.$Sqlite_db_file, null, null, $pdoOptions);

            # TODO: Why create table only in sqlite mode?
            $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
            )) {
                if($returnErrorMessage){
					return "Required postgresql database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'";
				}
				return false;
            }

            $dsn = 'pgsql:'
                .'host='.$PostgreSql_hostname
                .';dbname='.$PostgreSql_databasename;

            return new PDO($dsn, $PostgreSql_username, $PostgreSql_password, $pdoOptions);
        }
    } catch (Exception $e) {
		if($returnErrorMessage){
			return $e->getMessage();
		}
        return false;
    }

	if($returnErrorMessage){
		return "db_type '" . $db_type . "' not supported";
	}
    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 if returnErrorMessage is false or a error message if returnErrorMessage is true
 */
function insertSpeedtestUser($ip, $ispinfo, $extra, $ua, $lang, $dl, $ul, $ping, $jitter, $log, $returnExceptionOnError = false)
{
    $pdo = getPdo();
    if (!($pdo instanceof PDO)) {
		if($returnExceptionOnError){
			return new Exception("Failed to get database connection object");
		}
        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) {
		if($returnExceptionOnError){
			return $e;
		}
        return false;
    }

    if (isObfuscationEnabled()) {
        return obfuscateId($id);
    }

    return $id;
}

/**
 * @param int|string $id
 *
 * @return array|null|false|exception returns the speedtest data as array, null
 *                          if no data is found for the given id or
 *                          false or an exception if there was an error (based on returnExceptionOnError)
 *
 * @throws RuntimeException
 */
function getSpeedtestUserById($id,$returnExceptionOnError = false)
{
    $pdo = getPdo();
    if (!($pdo instanceof PDO)) {
		if($returnExceptionOnError){
			return new Exception("Failed to get database connection object");
		}
        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) {
		if($returnExceptionOnError){
			return $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;
    }

    require TELEMETRY_SETTINGS_FILE;
	
    try {
		$sql = 'SELECT ';
		
		if('mssql' === $db_type) {$sql .= ' TOP(100) ';}
		
		$sql .= ' id, timestamp, ip, ispinfo, ua, lang, dl, ul, ping, jitter, log, extra
            FROM speedtest_users
            ORDER BY timestamp DESC ';
			
		if('mssql' !== $db_type) {$sql .= ' LIMIT 100 ';}
		
        $stmt = $pdo->query($sql);

        $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;
}
telemetry_mssql.sql
wget 'https://sme10.lists2.roe3.org/speedtest/results/telemetry_mssql.sql'
View Content
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[speedtest_users](
	[id] [bigint] IDENTITY(120,1) NOT NULL,
	[timestamp] [datetime] NOT NULL,
	[ip] [nvarchar](max) NOT NULL,
	[ispinfo] [nvarchar](max) NULL,
	[extra] [nvarchar](max) NULL,
	[ua] [nvarchar](max) NOT NULL,
	[lang] [nvarchar](max) NOT NULL,
	[dl] [nvarchar](max) NULL,
	[ul] [nvarchar](max) NULL,
	[ping] [nvarchar](max) NULL,
	[jitter] [nvarchar](max) NULL,
	[log] [nvarchar](max) NULL,
 CONSTRAINT [PK_speedtest_users] PRIMARY KEY CLUSTERED
(
	[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

ALTER TABLE [dbo].[speedtest_users] ADD  CONSTRAINT [DF_speedtest_users_timestamp]  DEFAULT (getdate()) FOR [timestamp]
GO


telemetry_mysql.sql
wget 'https://sme10.lists2.roe3.org/speedtest/results/telemetry_mysql.sql'
View Content
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;

--
-- Database: `speedtest_telemetry`
--

-- --------------------------------------------------------

--
-- Table structure for table `speedtest_users`
--

CREATE TABLE `speedtest_users` (
  `id` int(11) NOT NULL,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `ip` text NOT NULL,
  `ispinfo` text,
  `extra` text,
  `ua` text NOT NULL,
  `lang` text NOT NULL,
  `dl` text,
  `ul` text,
  `ping` text,
  `jitter` text,
  `log` longtext
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

--
-- Indexes for dumped tables
--

--
-- Indexes for table `speedtest_users`
--
ALTER TABLE `speedtest_users`
  ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `speedtest_users`
--
ALTER TABLE `speedtest_users`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;COMMIT;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
telemetry_postgresql.sql
wget 'https://sme10.lists2.roe3.org/speedtest/results/telemetry_postgresql.sql'
View Content
--
-- PostgreSQL database dump
--

-- Dumped from database version 9.6.3
-- Dumped by pg_dump version 9.6.5

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;
SET row_security = off;

--
-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner:
--

CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;


--
-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner:
--

COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';


SET search_path = public, pg_catalog;

SET default_tablespace = '';

SET default_with_oids = false;

--
-- Name: speedtest_users; Type: TABLE; Schema: public; Owner: speedtest
--

CREATE TABLE speedtest_users (
    id integer NOT NULL,
    "timestamp" timestamp without time zone DEFAULT now() NOT NULL,
    ip text NOT NULL,
	ispinfo text,
	extra text,
    ua text NOT NULL,
    lang text NOT NULL,
    dl text,
    ul text,
    ping text,
    jitter text,
    log text
);

-- Commented out the following line because it assumes the user of the speedtest server, @bplower
-- ALTER TABLE speedtest_users OWNER TO speedtest;

--
-- Name: speedtest_users_id_seq; Type: SEQUENCE; Schema: public; Owner: speedtest
--

CREATE SEQUENCE speedtest_users_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;

-- Commented out the following line because it assumes the user of the speedtest server, @bplower
-- ALTER TABLE speedtest_users_id_seq OWNER TO speedtest;

--
-- Name: speedtest_users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: speedtest
--

ALTER SEQUENCE speedtest_users_id_seq OWNED BY speedtest_users.id;


--
-- Name: speedtest_users id; Type: DEFAULT; Schema: public; Owner: speedtest
--

ALTER TABLE ONLY speedtest_users ALTER COLUMN id SET DEFAULT nextval('speedtest_users_id_seq'::regclass);


--
-- Data for Name: speedtest_users; Type: TABLE DATA; Schema: public; Owner: speedtest
--

COPY speedtest_users (id, "timestamp", ip, ua, lang, dl, ul, ping, jitter, log) FROM stdin;
\.


--
-- Name: speedtest_users_id_seq; Type: SEQUENCE SET; Schema: public; Owner: speedtest
--

SELECT pg_catalog.setval('speedtest_users_id_seq', 1, true);


--
-- Name: speedtest_users speedtest_users_pkey; Type: CONSTRAINT; Schema: public; Owner: speedtest
--

ALTER TABLE ONLY speedtest_users
    ADD CONSTRAINT speedtest_users_pkey PRIMARY KEY (id);


--
-- PostgreSQL database dump complete
--

telemetry_settings.php
wget 'https://sme10.lists2.roe3.org/speedtest/results/telemetry_settings.php'
View Content
<?php

// Type of db: "mssql", "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';

// mssql settings
$MsSql_server = 'DB_HOSTNAME';
$MsSql_databasename = 'DB_NAME';
$MsSql_WindowsAuthentication = true;   //true or false
$MsSql_username = 'USERNAME';          //not used if MsSql_WindowsAuthentication is true
$MsSql_password = 'PASSWORD';          //not used if MsSql_WindowsAuthentication is true
$MsSql_TrustServerCertificate = true;  //true, false or comment out for driver default
//Download driver from https://docs.microsoft.com/en-us/sql/connect/php/download-drivers-php-sql-server?view=sql-server-ver16

// Mysql settings
$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';