From 5956e07a7a0c8abd06f6a7a92a8b00277f3497d4 Mon Sep 17 00:00:00 2001 From: Tracy-B Date: Mon, 31 Jul 2023 18:10:56 +1200 Subject: [PATCH] Microsoft SQL Server support and Sanity Check page (#569) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Create telemetry_mssql.sql SQL to create the speedtest_users table on Microsoft SQL server. This SQL is based on the original templates, and continues to uses nvarchar for all fields as the templates do – even though some of the fields should be int. * Added support for Microsoft SQL Server * New sanitycheck.php page plus required updates to telemetry_db.php Created a sanity check page to verify that the required PHP extensions are installed, and that it is possible to connect to the database. * Update README.md - MS SQL support Added mention of Microsoft SQL Server as a supported DB engine. * Added missing to sanitycheck.php --- README.md | 2 +- results/sanitycheck.php | 189 +++++++++++++++++++++++++++++++++ results/telemetry_db.php | 108 ++++++++++++++++--- results/telemetry_mssql.sql | 30 ++++++ results/telemetry_settings.php | 11 +- 5 files changed, 324 insertions(+), 16 deletions(-) create mode 100644 results/sanitycheck.php create mode 100644 results/telemetry_mssql.sql diff --git a/README.md b/README.md index 8df4371..dd5bbe0 100755 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Works with mobile versions too. ## Server requirements * A reasonably fast web server with Apache 2 (nginx, IIS also supported) * PHP 5.4 (other backends also available) -* MySQL database to store test results (optional, PostgreSQL and SQLite also supported) +* MySQL database to store test results (optional, Microsoft SQL Server, PostgreSQL and SQLite also supported) * A fast! internet connection ## Installation videos diff --git a/results/sanitycheck.php b/results/sanitycheck.php new file mode 100644 index 0000000..133b683 --- /dev/null +++ b/results/sanitycheck.php @@ -0,0 +1,189 @@ +Pass"; +$failed="failed"; +$na="N/A"; +?> + + + +Speed Test installation sanity check + + + + + + + + + + + + + + + + + + + + + +"; + } else { + echo $failed; + echo ""; + } +?> + + +"; + } else { + echo $pass; + echo ""; + } +?> + + +"; + } elseif(!is_array($QueryResult)) { + echo $failed; + echo ""; + } else { + echo $pass; + echo ""; + } + } else { + echo ""; + } +?> + + +
ItemStatusComment
PHP extensions
gd + +Used to render result images.
openssl + +
pdo_sqlsrv + +Only required if using MS SQL.
pdo_mysql + +Only required if using mysql.
pdo_sqlite + +Only required if using sqlite.
pdo_pgsql + +Only required if using sqlite.
Database check
Connecting to DB +". htmlspecialchars($pdo) . "
Insert into DB +"; + echo htmlspecialchars($insertResult->getMessage()) . "
Read from DB +"; + echo htmlspecialchars($insertResult->getMessage()) . "Test result not retrieved from database.Insert failed so can't test reading inserted data
+ + + \ No newline at end of file diff --git a/results/telemetry_db.php b/results/telemetry_db.php index 6a1aee3..e516638 100755 --- a/results/telemetry_db.php +++ b/results/telemetry_db.php @@ -7,18 +7,24 @@ define('TELEMETRY_SETTINGS_FILE', 'telemetry_settings.php'); /** * @return PDO|false */ -function getPdo() +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; } @@ -27,6 +33,47 @@ function getPdo() ]; 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, $MySql_username, $MySql_password, $pdoOptions); + } + } + if ('mysql' === $db_type) { if (!isset( $MySql_hostname, @@ -35,7 +82,10 @@ function getPdo() $MySql_username, $MySql_password )) { - return false; + if($returnErrorMessage){ + return "Required mysql database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'"; + } + return false; } $dsn = 'mysql:' @@ -48,6 +98,9 @@ function getPdo() if ('sqlite' === $db_type) { if (!isset($Sqlite_db_file)) { + if($returnErrorMessage){ + return "Required sqlite database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'"; + } return false; } @@ -80,7 +133,10 @@ function getPdo() $PostgreSql_username, $PostgreSql_password )) { - return false; + if($returnErrorMessage){ + return "Required postgresql database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'"; + } + return false; } $dsn = 'pgsql:' @@ -90,9 +146,15 @@ function getPdo() 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; } @@ -109,12 +171,15 @@ function isObfuscationEnabled() } /** - * @return string|false returns the id of the inserted column or false on error + * @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) +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; } @@ -129,6 +194,9 @@ function insertSpeedtestUser($ip, $ispinfo, $extra, $ua, $lang, $dl, $ul, $ping, ]); $id = $pdo->lastInsertId(); } catch (Exception $e) { + if($returnExceptionOnError){ + return $e; + } return false; } @@ -142,16 +210,19 @@ function insertSpeedtestUser($ip, $ispinfo, $extra, $ua, $lang, $dl, $ul, $ping, /** * @param int|string $id * - * @return array|null|false returns the speedtest data as array, null + * @return array|null|false|exception returns the speedtest data as array, null * if no data is found for the given id or - * false if there was an error + * false or an exception if there was an error (based on returnExceptionOnError) * * @throws RuntimeException */ -function getSpeedtestUserById($id) +function getSpeedtestUserById($id,$returnExceptionOnError = false) { $pdo = getPdo(); if (!($pdo instanceof PDO)) { + if($returnExceptionOnError){ + return new Exception("Failed to get database connection object"); + } return false; } @@ -170,6 +241,9 @@ function getSpeedtestUserById($id) $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); } catch (Exception $e) { + if($returnExceptionOnError){ + return $e; + } return false; } @@ -195,14 +269,20 @@ function getLatestSpeedtestUsers() return false; } + require TELEMETRY_SETTINGS_FILE; + try { - $stmt = $pdo->query( - 'SELECT - id, timestamp, ip, ispinfo, ua, lang, dl, ul, ping, jitter, log, extra + $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 - LIMIT 100' - ); + ORDER BY timestamp DESC '; + + if('mssql' !== $db_type) {$sql .= ' LIMIT 100 ';} + + $stmt = $pdo->query($sql); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); diff --git a/results/telemetry_mssql.sql b/results/telemetry_mssql.sql new file mode 100644 index 0000000..6c68d84 --- /dev/null +++ b/results/telemetry_mssql.sql @@ -0,0 +1,30 @@ +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 + + diff --git a/results/telemetry_settings.php b/results/telemetry_settings.php index 78bc343..ea19938 100755 --- a/results/telemetry_settings.php +++ b/results/telemetry_settings.php @@ -1,6 +1,6 @@