mirror of
https://github.com/librespeed/speedtest.git
synced 2026-08-04 14:48:38 +00:00
Merge remote-tracking branch 'origin/master' into newdesign
# Conflicts: # doc.md # docker/ui.php # index.html # package.json # speedtest.js
This commit is contained in:
commit
eda4148bcb
9 changed files with 83 additions and 22 deletions
10
.github/workflows/docker-publish.yml
vendored
10
.github/workflows/docker-publish.yml
vendored
|
|
@ -59,19 +59,19 @@ jobs:
|
|||
|
||||
# Set up QEMU for multi-arch builds
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
# Set up BuildKit Docker container builder to be able to build
|
||||
# multi-platform images and export cache
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
|
|
@ -81,7 +81,7 @@ jobs:
|
|||
# https://github.com/docker/metadata-action
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: ${{ matrix.image }}
|
||||
tags: |
|
||||
|
|
@ -98,7 +98,7 @@ jobs:
|
|||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: ${{ matrix.dockerfile }}
|
||||
|
|
|
|||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -4,3 +4,6 @@ db-dir/
|
|||
.vscode/
|
||||
node_modules/
|
||||
package-lock.json
|
||||
results/speedtest_telemetry.db
|
||||
results/speedtest_telemetry.db-shm
|
||||
results/speedtest_telemetry.db-wal
|
||||
|
|
|
|||
|
|
@ -59,6 +59,10 @@ A template to build an Android client for your LibreSpeed installation is availa
|
|||
|
||||
A command line client is available [here](https://github.com/librespeed/speedtest-cli).
|
||||
|
||||
## .NET client
|
||||
|
||||
A .NET client library is available in the [`LibreSpeed.NET`](https://github.com/Memphizzz/LibreSpeed.NET) repo ([NuGet](https://www.nuget.org/packages/LibreSpeed.NET)), maintained by [MemphiZ](https://github.com/Memphizzz).
|
||||
|
||||
## Development
|
||||
|
||||
If you want to contribute or develop with LibreSpeed, see [DEVELOPMENT.md](DEVELOPMENT.md) for information about using npm for development tasks, linting, and formatting.
|
||||
|
|
|
|||
|
|
@ -134,11 +134,11 @@ function getIspInfo_ipinfoApi($ip){
|
|||
]);
|
||||
}
|
||||
|
||||
if (PHP_MAJOR_VERSION >= 8){
|
||||
if (PHP_VERSION_ID >= 80100){
|
||||
require_once("geoip2.phar");
|
||||
}
|
||||
function getIspInfo_ipinfoOfflineDb($ip){
|
||||
if (PHP_MAJOR_VERSION < 8 || !file_exists(OFFLINE_IPINFO_DB_FILE) || !is_readable(OFFLINE_IPINFO_DB_FILE)){
|
||||
if (PHP_VERSION_ID < 80100 || !file_exists(OFFLINE_IPINFO_DB_FILE) || !is_readable(OFFLINE_IPINFO_DB_FILE)){
|
||||
return null;
|
||||
}
|
||||
$reader = new MaxMind\Db\Reader(OFFLINE_IPINFO_DB_FILE);
|
||||
|
|
|
|||
|
|
@ -1,19 +1,55 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Normalize and validate an IP address candidate from a request header.
|
||||
*
|
||||
* Trims whitespace, takes the first comma-separated token (for XFF-like
|
||||
* headers that may contain a chain of addresses), and validates the result
|
||||
* with filter_var().
|
||||
*
|
||||
* @param string $raw Raw header value.
|
||||
* @param int $extraFlags Additional FILTER_FLAG_* flags (e.g. FILTER_FLAG_IPV6).
|
||||
*
|
||||
* @return string|false The validated IP string, or false on failure.
|
||||
*/
|
||||
function normalizeCandidateIp($raw, $extraFlags = 0)
|
||||
{
|
||||
$ip = trim($raw);
|
||||
// For XFF-like values, take the first address before a comma.
|
||||
if (($pos = strpos($ip, ',')) !== false) {
|
||||
$ip = trim(substr($ip, 0, $pos));
|
||||
}
|
||||
if ($ip === '') {
|
||||
return false;
|
||||
}
|
||||
return filter_var($ip, FILTER_VALIDATE_IP, $extraFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function getClientIp() {
|
||||
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
|
||||
$ip = $_SERVER['HTTP_CLIENT_IP'];
|
||||
} elseif (!empty($_SERVER['HTTP_X_REAL_IP'])) {
|
||||
$ip = $_SERVER['HTTP_X_REAL_IP'];
|
||||
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||
$ip = preg_replace('/,.*/', '', $ip); # hosts are comma-separated, client is first
|
||||
} else {
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
function getClientIp()
|
||||
{
|
||||
// Cloudflare IPv6 header — must be a valid IPv6 address.
|
||||
if (!empty($_SERVER['HTTP_CF_CONNECTING_IPV6'])) {
|
||||
$ip = normalizeCandidateIp($_SERVER['HTTP_CF_CONNECTING_IPV6'], FILTER_FLAG_IPV6);
|
||||
if ($ip !== false) {
|
||||
return preg_replace('/^::ffff:/', '', $ip);
|
||||
}
|
||||
}
|
||||
|
||||
return preg_replace('/^::ffff:/', '', $ip);
|
||||
// Other forwarding / proxy headers — accept any valid IP.
|
||||
foreach (['HTTP_CLIENT_IP', 'HTTP_X_REAL_IP', 'HTTP_X_FORWARDED_FOR'] as $header) {
|
||||
if (!empty($_SERVER[$header])) {
|
||||
$ip = normalizeCandidateIp($_SERVER[$header]);
|
||||
if ($ip !== false) {
|
||||
return preg_replace('/^::ffff:/', '', $ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback: REMOTE_ADDR is set by the web server and is always a single IP.
|
||||
$ip = normalizeCandidateIp($_SERVER['REMOTE_ADDR'] ?? '');
|
||||
if ($ip !== false) {
|
||||
return preg_replace('/^::ffff:/', '', $ip);
|
||||
}
|
||||
return $_SERVER['REMOTE_ADDR'] ?? '';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,7 +121,9 @@ if [[ "$TELEMETRY" == "true" && ("$MODE" == "frontend" || "$MODE" == "standalone
|
|||
sed -i s/\$db_type\ =\ \'.*\'/\$db_type\ =\ \'sqlite\'\/g /var/www/html/results/telemetry_settings.php
|
||||
fi
|
||||
|
||||
sed -i s/\$Sqlite_db_file\ =\ \'.*\'/\$Sqlite_db_file=\'\\\/database\\\/db.sql\'/g /var/www/html/results/telemetry_settings.php
|
||||
# Override SQLite database path for Docker environment
|
||||
# In Docker, we use /database/db.sql which is outside the web-accessible directory
|
||||
sed -i s/\$Sqlite_db_file\ =\ .*\'/\$Sqlite_db_file=\'\\\/database\\\/db.sql\'/g /var/www/html/results/telemetry_settings.php
|
||||
sed -i s/\$stats_password\ =\ \'.*\'/\$stats_password\ =\ \'$PASSWORD\'/g /var/www/html/results/telemetry_settings.php
|
||||
|
||||
if [ "$ENABLE_ID_OBFUSCATION" == "true" ]; then
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ function startStop(){
|
|||
if(testId!=null){
|
||||
var shareURL=window.location.href.substring(0,window.location.href.lastIndexOf("/"))+"/results/?id="+testId;
|
||||
I("resultsImg").src=shareURL;
|
||||
I("resultsImg").alt="Download: "+uiData.dlStatus+" Mbps, Upload: "+uiData.ulStatus+" Mbps, Ping: "+uiData.pingStatus+" ms, Jitter: "+uiData.jitterStatus+" ms";
|
||||
I("resultsURL").value=shareURL;
|
||||
I("testId").innerHTML=testId;
|
||||
I("shareArea").style.display="";
|
||||
|
|
|
|||
|
|
@ -104,6 +104,21 @@ function getPdo($returnErrorMessage = false)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Check if directory exists and is writable
|
||||
$db_dir = dirname($Sqlite_db_file);
|
||||
if (!is_dir($db_dir)) {
|
||||
if ($returnErrorMessage) {
|
||||
return "SQLite database directory does not exist: " . $db_dir . ". Please create it and ensure it's writable by the web server.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!is_writable($db_dir)) {
|
||||
if ($returnErrorMessage) {
|
||||
return "SQLite database directory is not writable: " . $db_dir . ". Please ensure the web server has write permissions (e.g., chmod 755 or 775).";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$pdo = new PDO('sqlite:'.$Sqlite_db_file, null, null, $pdoOptions);
|
||||
|
||||
# TODO: Why create table only in sqlite mode?
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
// Type of db: "mssql", "mysql", "sqlite" or "postgresql"
|
||||
$db_type = 'mysql';
|
||||
$db_type = 'sqlite';
|
||||
// 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
|
||||
|
|
@ -10,7 +10,7 @@ $enable_id_obfuscation = false;
|
|||
$redact_ip_addresses = false;
|
||||
|
||||
// Sqlite3 settings
|
||||
$Sqlite_db_file = '../../speedtest_telemetry.sql';
|
||||
$Sqlite_db_file = __DIR__ . '/../../speedtest_telemetry.db';
|
||||
|
||||
// mssql settings
|
||||
$MsSql_server = 'DB_HOSTNAME';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue