Microsoft SQL Server support and Sanity Check page (#569)
* 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 <tr> to sanitycheck.php
This commit is contained in:
parent
97e0390680
commit
5956e07a7a
|
@ -29,7 +29,7 @@ Works with mobile versions too.
|
||||||
## Server requirements
|
## Server requirements
|
||||||
* A reasonably fast web server with Apache 2 (nginx, IIS also supported)
|
* A reasonably fast web server with Apache 2 (nginx, IIS also supported)
|
||||||
* PHP 5.4 (other backends also available)
|
* 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
|
* A fast! internet connection
|
||||||
|
|
||||||
## Installation videos
|
## Installation videos
|
||||||
|
|
189
results/sanitycheck.php
Normal file
189
results/sanitycheck.php
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
<?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 sqlite.</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);
|
||||||
|
*/
|
||||||
|
?>
|
|
@ -7,18 +7,24 @@ define('TELEMETRY_SETTINGS_FILE', 'telemetry_settings.php');
|
||||||
/**
|
/**
|
||||||
* @return PDO|false
|
* @return PDO|false
|
||||||
*/
|
*/
|
||||||
function getPdo()
|
function getPdo($returnErrorMessage = false)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!file_exists(TELEMETRY_SETTINGS_FILE)
|
!file_exists(TELEMETRY_SETTINGS_FILE)
|
||||||
|| !is_readable(TELEMETRY_SETTINGS_FILE)
|
|| !is_readable(TELEMETRY_SETTINGS_FILE)
|
||||||
) {
|
) {
|
||||||
|
if($returnErrorMessage){
|
||||||
|
return 'missing TELEMETRY_SETTINGS_FILE';
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
require TELEMETRY_SETTINGS_FILE;
|
require TELEMETRY_SETTINGS_FILE;
|
||||||
|
|
||||||
if (!isset($db_type)) {
|
if (!isset($db_type)) {
|
||||||
|
if($returnErrorMessage){
|
||||||
|
return "db_type not set in '" . TELEMETRY_SETTINGS_FILE . "'";
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +33,47 @@ function getPdo()
|
||||||
];
|
];
|
||||||
|
|
||||||
try {
|
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 ('mysql' === $db_type) {
|
||||||
if (!isset(
|
if (!isset(
|
||||||
$MySql_hostname,
|
$MySql_hostname,
|
||||||
|
@ -35,7 +82,10 @@ function getPdo()
|
||||||
$MySql_username,
|
$MySql_username,
|
||||||
$MySql_password
|
$MySql_password
|
||||||
)) {
|
)) {
|
||||||
return false;
|
if($returnErrorMessage){
|
||||||
|
return "Required mysql database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$dsn = 'mysql:'
|
$dsn = 'mysql:'
|
||||||
|
@ -48,6 +98,9 @@ function getPdo()
|
||||||
|
|
||||||
if ('sqlite' === $db_type) {
|
if ('sqlite' === $db_type) {
|
||||||
if (!isset($Sqlite_db_file)) {
|
if (!isset($Sqlite_db_file)) {
|
||||||
|
if($returnErrorMessage){
|
||||||
|
return "Required sqlite database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'";
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +133,10 @@ function getPdo()
|
||||||
$PostgreSql_username,
|
$PostgreSql_username,
|
||||||
$PostgreSql_password
|
$PostgreSql_password
|
||||||
)) {
|
)) {
|
||||||
return false;
|
if($returnErrorMessage){
|
||||||
|
return "Required postgresql database settings missing in '" . TELEMETRY_SETTINGS_FILE . "'";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$dsn = 'pgsql:'
|
$dsn = 'pgsql:'
|
||||||
|
@ -90,9 +146,15 @@ function getPdo()
|
||||||
return new PDO($dsn, $PostgreSql_username, $PostgreSql_password, $pdoOptions);
|
return new PDO($dsn, $PostgreSql_username, $PostgreSql_password, $pdoOptions);
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
if($returnErrorMessage){
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($returnErrorMessage){
|
||||||
|
return "db_type '" . $db_type . "' not supported";
|
||||||
|
}
|
||||||
return false;
|
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();
|
$pdo = getPdo();
|
||||||
if (!($pdo instanceof PDO)) {
|
if (!($pdo instanceof PDO)) {
|
||||||
|
if($returnExceptionOnError){
|
||||||
|
return new Exception("Failed to get database connection object");
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,6 +194,9 @@ function insertSpeedtestUser($ip, $ispinfo, $extra, $ua, $lang, $dl, $ul, $ping,
|
||||||
]);
|
]);
|
||||||
$id = $pdo->lastInsertId();
|
$id = $pdo->lastInsertId();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
if($returnExceptionOnError){
|
||||||
|
return $e;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,16 +210,19 @@ function insertSpeedtestUser($ip, $ispinfo, $extra, $ua, $lang, $dl, $ul, $ping,
|
||||||
/**
|
/**
|
||||||
* @param int|string $id
|
* @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
|
* 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
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
function getSpeedtestUserById($id)
|
function getSpeedtestUserById($id,$returnExceptionOnError = false)
|
||||||
{
|
{
|
||||||
$pdo = getPdo();
|
$pdo = getPdo();
|
||||||
if (!($pdo instanceof PDO)) {
|
if (!($pdo instanceof PDO)) {
|
||||||
|
if($returnExceptionOnError){
|
||||||
|
return new Exception("Failed to get database connection object");
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +241,9 @@ function getSpeedtestUserById($id)
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
if($returnExceptionOnError){
|
||||||
|
return $e;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,14 +269,20 @@ function getLatestSpeedtestUsers()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
require TELEMETRY_SETTINGS_FILE;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->query(
|
$sql = 'SELECT ';
|
||||||
'SELECT
|
|
||||||
id, timestamp, ip, ispinfo, ua, lang, dl, ul, ping, jitter, log, extra
|
if('mssql' === $db_type) {$sql .= ' TOP(100) ';}
|
||||||
|
|
||||||
|
$sql .= ' id, timestamp, ip, ispinfo, ua, lang, dl, ul, ping, jitter, log, extra
|
||||||
FROM speedtest_users
|
FROM speedtest_users
|
||||||
ORDER BY timestamp DESC
|
ORDER BY timestamp DESC ';
|
||||||
LIMIT 100'
|
|
||||||
);
|
if('mssql' !== $db_type) {$sql .= ' LIMIT 100 ';}
|
||||||
|
|
||||||
|
$stmt = $pdo->query($sql);
|
||||||
|
|
||||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
|
30
results/telemetry_mssql.sql
Normal file
30
results/telemetry_mssql.sql
Normal file
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Type of db: "mysql", "sqlite" or "postgresql"
|
// Type of db: "mssql", "mysql", "sqlite" or "postgresql"
|
||||||
$db_type = 'mysql';
|
$db_type = 'mysql';
|
||||||
// Password to login to stats.php. Change this!!!
|
// Password to login to stats.php. Change this!!!
|
||||||
$stats_password = 'PASSWORD';
|
$stats_password = 'PASSWORD';
|
||||||
|
@ -12,6 +12,15 @@ $redact_ip_addresses = false;
|
||||||
// Sqlite3 settings
|
// Sqlite3 settings
|
||||||
$Sqlite_db_file = '../../speedtest_telemetry.sql';
|
$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 settings
|
||||||
$MySql_username = 'USERNAME';
|
$MySql_username = 'USERNAME';
|
||||||
$MySql_password = 'PASSWORD';
|
$MySql_password = 'PASSWORD';
|
||||||
|
|
Loading…
Reference in a new issue