diff --git a/README.md b/README.md index 48bdd2f..98284d0 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Only modern browsers are supported (IE11, latest Edge, latest Chrome, latest Fir * Jitter * IP Address * Telemetry (optional) +* Results sharing (optional) ## Requirements - A reasonably fast web server with PHP (see doc.md for details and use without PHP) diff --git a/doc.md b/doc.md index 74c92ff..00a2932 100644 --- a/doc.md +++ b/doc.md @@ -1,7 +1,7 @@ # HTML5 Speedtest > by Federico Dossena -> Version 4.5.5, April 25, 2018 +> Version 4.6, August 7, 2018 > [https://github.com/adolfintel/speedtest/](https://github.com/adolfintel/speedtest/) @@ -19,8 +19,8 @@ First of all, the requirements to run this test: * Apple Safari 7.1+ * Opera 18+ * Client side, the test can use up to 500 megabytes of RAM -* Server side, you'll need a fast connection (at least 100 Mbps recommended), and the web server must accept large POST requests (up to 20 megabytes). - Apache2 and PHP are recommended, but not mandatory. +* Server side, you'll need a fast connection (at least 100 Mbps recommended), and the web server must accept large POST requests (up to 20 megabytes). + The recommended setup is: GNU/Linux, Apache2, PHP, MySQL database (if you want to use telemetry). If this looks good, let's proceed and see how to use the test. @@ -37,7 +37,7 @@ To install the test on your server, upload the following files: * `empty.php` * one of the examples -Later we'll see how to use the test without PHP, and how to configure the telemetry if you want to use it. +Later we'll see how to use the test without PHP, and how to configure the telemetry and result sharing if you want to use that. __Important:__ keep all the files together; all paths are relative to the js file @@ -51,7 +51,10 @@ Start by copying one of the included examples. Here's a description for each of * `example-customSettings2.html`: A modified version of `example-pretty.html` showing how to make a custom test with only download and upload * `example-gauges.html`: The most sophisticated example, with the same functions as `example-pretty.html` but also gauges and progress indicators for each test. This is the nicest example included, and also a good starting point, but drawing the gauges may slow down the test on slow devices like a Raspberry Pi * `example-chart.html`: The old example5.html, showing how to use the test with the Chart.js library + +These 2 examples require some additional server configuration, discussed in the Telemetry section: * `example-telemetry.html`: A modified version of `example-pretty.html` with basic telemetry turned on. See the section on Telemetry for details +* `example-telemetry-resultsSharing.html`: A modified version of `example-telemetry.html` with results sharing. This is the most complete and most complex example, showing off all of the speedtest features ### Customizing your example The included examples are good starting places if you want to have a simple speedtest on your site. @@ -114,6 +117,7 @@ w.onmessage = function (event) { var dlProgress = data[6] var ulProgress = data[7] var pingProgress = data[8] + var testId = data[9] if (testState >= 4) { clearInterval(timer) // test is finished or aborted } @@ -157,6 +161,7 @@ format: * __dlProgress__: the progress of the download test as a number between 0 and 1 * __ulProgress__: the progress of the upload test as a number between 0 and 1 * __pingProgress__: the progress of the ping+jitter test as a number between 0 and 1 +* __testId__: when telemetry is active, this is the ID of the test as an integer. This string is empty until the test is finished (testState 4). This ID is used for results sharing Note: clientIp appears before jitterStatus. This is not a mistake, it's to keep the js file compatible with older pages from before the jitter test was introduced. @@ -303,11 +308,12 @@ It is important here to turn off compression, and generate incompressible data. A symlink to `/dev/urandom` is also ok. #### Replacement for `empty.php` -Your replacement must simply respond with a HTTP code 200 and send nothing else. You may want to send additional headers to disable caching. The test assumes that Connection:keep-alive is sent by the server. +Your replacement must simply respond with a HTTP code 200 and send nothing else. You may want to send additional headers to disable caching. The test assumes that Connection:keep-alive is sent by the server. +An empty file can be used for this. #### Replacement for `getIP.php` -Your replacement must simply respond with the client's IP as plaintext. Nothing fancy. -If you want, you can also accept the `isp=true` parameter and also include the ISP info. +Your replacement can simply respond with the client's IP as plaintext or do something more fancy. +If you want, you can also accept the `isp=true` parameter and also include the ISP info. In this case, return a JSON string containing a string called `processedString` with the text that you want to be displayed in the IP address field, and an object called `rawIspInfo` containing whatever you want (will be included in telemetry if enabled). #### JS You need to start the test with your replacements like this: @@ -318,18 +324,18 @@ w.postMessage('start {"url_dl": "newGarbageURL", "url_ul": "newEmptyURL", "url_p ## Telemetry Telemetry currently requires PHP and either MySQL, PostgreSQL or SQLite. Alternatively, it is possible to save to a CSV file. To set up the telemetry, we need to do 4 things: -* copy `telemetry.php` and `telemetry_settings.php` +* copy the `telemetry` folder * edit `telemetry_settings.php` to add your database or CSV settings * create the database * enable telemetry ### Creating the database This step is only for MySQL and PostgreSQL. -Log into your database using phpMyAdmin or a similar software and import the appropriate sql file into an empty database. For MySQL databases use `telemetry_mysql.sql` and for PostgreSQL databases use `telemetry_postgesql.sql`. +Log into your database using phpMyAdmin or a similar software and import the appropriate sql file into an empty database. For MySQL databases use `telemetry_mysql.sql` and for PostgreSQL databases use `telemetry_postgesql.sql`. They're inside the `telemetry` folder. You can delete the files afterwards. If you see a table called `speedtest_users`, empty, you did it right. ### Configuring `telemetry.php` -Open telemetry_settings.php with notepad or a similar text editor. +Open `telemetry_settings.php` with notepad or a similar text editor. Set your preferred database, ``$db_type="mysql";``, ``$db_type="sqlite";``, ``$db_type="postgresql";`` or ``$db_type="csv";`` If you choose to use Sqlite3, you must set the path to your database file: ```php @@ -340,7 +346,7 @@ If you choose to use MySQL, you must also add your database credentials: ```php $MySql_username="USERNAME"; //your database username $MySql_password="PASSWORD"; //your database password -$MySql_hostname="DB_HOSTNAME"; //database address, usually localhost\ +$MySql_hostname="DB_HOSTNAME"; //database address, usually localhost $MySql_databasename="DB_NAME"; //the name of the database where you loaded telemetry_mysql.sql ``` @@ -373,8 +379,23 @@ w.postMessage('start {"telemetry_level":"basic"}') Also, see example-telemetry.html +### Results sharing +This feature generates an image that can be share by the user containing the download, upload, ping, jitter and ISP (if enabled). + +To use this feature, copy the `results` folder. You can customize the style of the generated image by editing the settings in `results/index.php`. + +This feature requires Telemetry to be enabled, and FreeType2 must be installed in PHP (if not already be installed by your distro). + +__Note:__ CSV doesn't currently support this. + +__Important:__ This feature relies on PHP functions `imagefttext` and `imageftbbox` that are well known for being problematic. The most common problem is that they can't find the font files and therefore nothing is drawn. This problem is metioned [here](http://php.net/manual/en/function.imagefttext.php) and was experienced by a lot of users. + ### Seeing the results -At the moment there is no front-end to see the telemetry data; you can connect to the database and see the collected results in the `speedtest_users` table. +A basic front-end for visualizing and searching tests by ID is available in `telemetry/stats.php`. + +A login is required to access the interface. __Important__: change the default password in `telemetry_settings.php`. + +__Note:__ CSV doesn't currently support this. ## Troubleshooting These are the most common issues reported by users, and how to fix them. If you still need help, contact me at [info@fdossena.com](mailto:info@fdossena.com). @@ -400,6 +421,10 @@ Make sure your server is sending the ```Connection:keep-alive``` header Edit getIP.php and replace lines 5-13 with what is more appropriate in your scenario. Example: ```$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];``` +#### The results sharing just generates a blank image +If the image doesn't display and the browser displays a broken image icon, FreeType2 is not installed or configured properly. +If the image is blank, this usually happens because PHP can't find the font files inside the `results` folder. You can fix your PHP config or edit `results/index.php` and use absolute paths for the fonts. This is a [known issue with PHP](http://php.net/manual/en/function.imagefttext.php) and no real solution is known. + ## Known bugs and limitations ### General * The ping/jitter test is measured by seeing how long it takes for an empty XHR to complete. It is not an acutal ICMP ping. Different browsers may also show different results, especially on very fast connections on slow devices. diff --git a/example-telemetry-resultSharing.html b/example-telemetry-resultSharing.html new file mode 100644 index 0000000..3da8691 --- /dev/null +++ b/example-telemetry-resultSharing.html @@ -0,0 +1,296 @@ + + + + + +HTML5 Speedtest + + + + +

HTML5 Speedtest - Telemetry and sharing example

+
+
+
+
+
Download
+ +
+
Mbps
+
+
+
Upload
+ +
+
Mbps
+
+
+
+
+
Ping
+ +
+
ms
+
+
+
Jitter
+ +
+
ms
+
+
+
+ IP Address: +
+ +
+
Basic telemetry is active; results will be saved in your database, without the full log. If the results don't appear, or the sharing panel doesn't appear at the end of the test, check the settings in telemetry_settings.php
+Source code + + + \ No newline at end of file diff --git a/example-telemetryEnabled.html b/example-telemetryEnabled.html index ba253cb..3cd0508 100644 --- a/example-telemetryEnabled.html +++ b/example-telemetryEnabled.html @@ -187,7 +187,7 @@ function initUI(){ IP Address: -
Basic telemetry is active; results will be saved in your database, without the full log. If the results don't appear, check the settings in telemetry.php
+
Basic telemetry is active; results will be saved in your database, without the full log. If the results don't appear, check the settings in telemetry_settings.php
Source code diff --git a/getIP.php b/getIP.php index 7c414c2..e30cde3 100644 --- a/getIP.php +++ b/getIP.php @@ -1,7 +1,11 @@ $ip . " - localhost ipv6 access", 'rawIspInfo' => ""]); die(); } if (strpos($ip, '127.0.0') !== false) { - echo $ip . " - localhost ipv4 access"; + echo json_encode(['processedString' => $ip . " - localhost ipv4 access", 'rawIspInfo' => ""]); die(); } @@ -42,9 +46,11 @@ function distance($latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo) { if (isset($_GET["isp"])) { $isp = ""; + $rawIspInfo=null; try { $json = file_get_contents("https://ipinfo.io/" . $ip . "/json"); $details = json_decode($json, true); + $rawIspInfo=$details; if (array_key_exists("org", $details)) $isp .= $details["org"]; else @@ -87,8 +93,8 @@ if (isset($_GET["isp"])) { } catch (Exception $ex) { $isp = "Unknown ISP"; } - echo $ip . " - " . $isp; + echo json_encode(['processedString' => $ip . " - " . $isp, 'rawIspInfo' => $rawIspInfo]); } else { - echo $ip; + echo json_encode(['processedString' => $ip, 'rawIspInfo' => ""]); } ?> diff --git a/results/OpenSans-Light.ttf b/results/OpenSans-Light.ttf new file mode 100644 index 0000000..0d38189 Binary files /dev/null and b/results/OpenSans-Light.ttf differ diff --git a/results/OpenSans-Semibold.ttf b/results/OpenSans-Semibold.ttf new file mode 100644 index 0000000..1a7679e Binary files /dev/null and b/results/OpenSans-Semibold.ttf differ diff --git a/results/index.php b/results/index.php new file mode 100644 index 0000000..61bb1e3 --- /dev/null +++ b/results/index.php @@ -0,0 +1,123 @@ +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"]; + $jitter=$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"]; + $jitter=$row["jitter"]; + $conn=null; +}else die(); + +$ispinfo=json_decode($ispinfo,true)["processedString"]; +$dash=strrpos($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_1_SIZE,0,$FONT_1,$DL_TEXT); +$ulBbox=imageftbbox($FONT_1_SIZE,0,$FONT_1,$UL_TEXT); +$pingBbox=imageftbbox($FONT_1_SIZE,0,$FONT_1,$PING_TEXT); +$jitBbox=imageftbbox($FONT_1_SIZE,0,$FONT_1,$JIT_TEXT); +$dlMeterBbox=imageftbbox($FONT_2_SIZE,0,$FONT_2,$dl); +$ulMeterBbox=imageftbbox($FONT_2_SIZE,0,$FONT_2,$ul); +$pingMeterBbox=imageftbbox($FONT_2_SIZE,0,$FONT_2,$ping); +$jitMeterBbox=imageftbbox($FONT_2_SIZE,0,$FONT_2,$jit); +$mbpsBbox=imageftbbox($FONT_3_SIZE,0,$FONT_3,$MBPS_TEXT); +$msBbox=imageftbbox($FONT_3_SIZE,0,$FONT_3,$MS_TEXT); +$watermarkBbox=imageftbbox($FONT_WATERMARK_SIZE,0,$FONT_WATERMARK,$WATERMARK_TEXT); +$POSITION_X_WATERMARK=$WIDTH-$watermarkBbox[4]-4*$SCALE; + +imagefilledrectangle($im, 0, 0, $WIDTH, $HEIGHT, $BACKGROUND_COLOR); +imagefttext($im,$FONT_1_SIZE,0,$POSITION_X_DL-$dlBbox[4]/2,$POSITION_Y_1,$TEXT_COLOR_1,$FONT_1,$DL_TEXT); +imagefttext($im,$FONT_1_SIZE,0,$POSITION_X_UL-$ulBbox[4]/2,$POSITION_Y_1,$TEXT_COLOR_1,$FONT_1,$UL_TEXT); +imagefttext($im,$FONT_1_SIZE,0,$POSITION_X_PING-$pingBbox[4]/2,$POSITION_Y_1,$TEXT_COLOR_1,$FONT_1,$PING_TEXT); +imagefttext($im,$FONT_1_SIZE,0,$POSITION_X_JIT-$jitBbox[4]/2,$POSITION_Y_1,$TEXT_COLOR_1,$FONT_1,$JIT_TEXT); +imagefttext($im,$FONT_2_SIZE,0,$POSITION_X_DL-$dlMeterBbox[4]/2,$POSITION_Y_2,$TEXT_COLOR_2,$FONT_2,$dl); +imagefttext($im,$FONT_2_SIZE,0,$POSITION_X_UL-$ulMeterBbox[4]/2,$POSITION_Y_2,$TEXT_COLOR_2,$FONT_2,$ul); +imagefttext($im,$FONT_2_SIZE,0,$POSITION_X_PING-$pingMeterBbox[4]/2,$POSITION_Y_2,$TEXT_COLOR_2,$FONT_2,$ping); +imagefttext($im,$FONT_2_SIZE,0,$POSITION_X_JIT-$jitMeterBbox[4]/2,$POSITION_Y_2,$TEXT_COLOR_2,$FONT_2,$jit); +imagefttext($im,$FONT_3_SIZE,0,$POSITION_X_DL-$mbpsBbox[4]/2,$POSITION_Y_3,$TEXT_COLOR_3,$FONT_3,$MBPS_TEXT); +imagefttext($im,$FONT_3_SIZE,0,$POSITION_X_UL-$mbpsBbox[4]/2,$POSITION_Y_3,$TEXT_COLOR_3,$FONT_3,$MBPS_TEXT); +imagefttext($im,$FONT_3_SIZE,0,$POSITION_X_PING-$msBbox[4]/2,$POSITION_Y_3,$TEXT_COLOR_3,$FONT_3,$MS_TEXT); +imagefttext($im,$FONT_3_SIZE,0,$POSITION_X_JIT-$msBbox[4]/2,$POSITION_Y_3,$TEXT_COLOR_3,$FONT_3,$MS_TEXT); +imagefttext($im,$FONT_4_SIZE,0,$POSITION_X_ISP,$POSITION_Y_4,$TEXT_COLOR_4,$FONT_4,$ispinfo); +imagefttext($im,$FONT_WATERMARK_SIZE,0,$POSITION_X_WATERMARK,$POSITION_Y_WATERMARK,$TEXT_COLOR_WATERMARK,$FONT_WATERMARK,$WATERMARK_TEXT); + +header('Content-Type: image/png'); +imagepng($im); +imagedestroy($im); + +?> \ No newline at end of file diff --git a/speedtest_worker.js b/speedtest_worker.js index fbf1e8c..83a96d6 100644 --- a/speedtest_worker.js +++ b/speedtest_worker.js @@ -1,5 +1,5 @@ /* - HTML5 Speedtest v4.5.5 + HTML5 Speedtest v4.6 by Federico Dossena https://github.com/adolfintel/speedtest/ GNU LGPLv3 License @@ -15,6 +15,12 @@ var clientIp = '' // client's IP address as reported by getIP.php var dlProgress = 0 //progress of download test 0-1 var ulProgress = 0 //progress of upload test 0-1 var pingProgress = 0 //progress of ping+jitter test 0-1 +var testId = 'noID' //test ID (sent back by telemetry if used, the string 'noID' otherwise) + +var HTML_ESCAPE_MAP={'&': '&','<': '<','>': '>','"': '"',"'": '''}; +String.prototype.escapeHtml=function(){ + return this.replace(/[&<>"']/g, function(m){return HTML_ESCAPE_MAP[m]}); +} var log='' //telemetry log function tlog(s){log+=Date.now()+': '+s+'\n'} @@ -46,7 +52,7 @@ var settings = { overheadCompensationFactor: 1.06, //can be changed to compensatie for transport overhead. (see doc.md for some other values) useMebibits: false, //if set to true, speed will be reported in mebibits/s instead of megabits/s telemetry_level: 0, // 0=disabled, 1=basic (results only), 2=full (results+log) - url_telemetry: 'telemetry.php' // path to the script that adds telemetry data to the database + url_telemetry: 'telemetry/telemetry.php' // path to the script that adds telemetry data to the database } var xhr = null // array of currently active xhr requests @@ -69,7 +75,7 @@ function url_sep (url) { return url.match(/\?/) ? '&' : '?'; } this.addEventListener('message', function (e) { var params = e.data.split(' ') if (params[0] === 'status') { // return status - postMessage(testStatus + ';' + dlStatus + ';' + ulStatus + ';' + pingStatus + ';' + clientIp + ';' + jitterStatus + ';' + dlProgress + ';' + ulProgress + ';' + pingProgress) + postMessage(testStatus + ';' + dlStatus + ';' + ulStatus + ';' + pingStatus + ';' + clientIp + ';' + jitterStatus + ';' + dlProgress + ';' + ulProgress + ';' + pingProgress+ ';' + testId) } if (params[0] === 'start' && testStatus === -1) { // start new test testStatus = 0 @@ -125,7 +131,12 @@ this.addEventListener('message', function (e) { var iRun=false,dRun=false,uRun=false,pRun=false; var runNextTest=function(){ if(testStatus==5) return; - if(test_pointer>=settings.test_order.length){testStatus=4; sendTelemetry(); return;} + if(test_pointer>=settings.test_order.length){ //test is finished + if(settings.telemetry_level>0) + sendTelemetry(function(id){testStatus=4; if(id!=-1)testId=id}) + else testStatus=4 + return; + } switch(settings.test_order.charAt(test_pointer)){ case 'I':{test_pointer++; if(iRun) {runNextTest(); return;} else iRun=true; getIp(runNextTest);} break; case 'D':{test_pointer++; if(dRun) {runNextTest(); return;} else dRun=true; testStatus=1; dlTest(runNextTest);} break; @@ -142,7 +153,7 @@ this.addEventListener('message', function (e) { clearRequests() // stop all xhr activity runNextTest=null; if (interval) clearInterval(interval) // clear timer if present - if (settings.telemetry_level > 1) sendTelemetry() + if (settings.telemetry_level > 1) sendTelemetry(function(){}) testStatus = 5; dlStatus = ''; ulStatus = ''; pingStatus = ''; jitterStatus = '' // set test as aborted } }) @@ -161,13 +172,21 @@ function clearRequests () { } // gets client's IP using url_getIp, then calls the done function var ipCalled = false // used to prevent multiple accidental calls to getIp +var ispInfo=""; //used for telemetry function getIp (done) { tlog('getIp') if (ipCalled) return; else ipCalled = true // getIp already called? xhr = new XMLHttpRequest() xhr.onload = function () { tlog("IP: "+xhr.responseText) - clientIp = xhr.responseText + try{ + var data=JSON.parse(xhr.responseText) + clientIp=data.processedString.escapeHtml() + ispInfo=data.rawIspInfo + }catch(e){ + clientIp = xhr.responseText.escapeHtml() + ispInfo='' + } done() } xhr.onerror = function () { @@ -449,15 +468,31 @@ function pingTest (done) { doPing() // start first ping } // telemetry -function sendTelemetry(){ +function sendTelemetry(done){ if (settings.telemetry_level < 1) return xhr = new XMLHttpRequest() - xhr.onload = function () { console.log('TELEMETRY OL '+xhr.responseText) } - xhr.onerror = function () { console.log('TELEMETRY ERROR '+xhr) } + xhr.onload = function () { + try{ + var parts=xhr.responseText.split(' ') + if(parts[0]=='id'){ + try{ + var id=Number(parts[1]) + if(!isNaN(id)) done(id); else done(-1); + }catch(e){done(-1)} + } else done(-1); + }catch(e){ + done(-1) + } + } + xhr.onerror = function () { console.log('TELEMETRY ERROR '+xhr); done(-1) } xhr.open('POST', settings.url_telemetry+url_sep(settings.url_telemetry)+"r="+Math.random(), true); + var telemetryIspInfo={ + processedString: clientIp, + rawIspInfo: (typeof ispInfo === "object")?ispInfo:"" + } try{ var fd = new FormData() - fd.append('ispinfo', clientIp) //clientIp also contains ISP info + fd.append('ispinfo', JSON.stringify(telemetryIspInfo)); fd.append('dl', dlStatus) fd.append('ul', ulStatus) fd.append('ping', pingStatus) @@ -465,7 +500,7 @@ function sendTelemetry(){ fd.append('log', settings.telemetry_level>1?log:"") xhr.send(fd) }catch(ex){ - var postData = 'ispinfo='+encodeURIComponent(clientIp)+'dl='+encodeURIComponent(dlStatus)+'&ul='+encodeURIComponent(ulStatus)+'&ping='+encodeURIComponent(pingStatus)+'&jitter='+encodeURIComponent(jitterStatus)+'&log='+encodeURIComponent(settings.telemetry_level>1?log:'') + var postData = 'ispinfo='+encodeURIComponent(JSON.stringify(telemetryIspInfo))+'&dl='+encodeURIComponent(dlStatus)+'&ul='+encodeURIComponent(ulStatus)+'&ping='+encodeURIComponent(pingStatus)+'&jitter='+encodeURIComponent(jitterStatus)+'&log='+encodeURIComponent(settings.telemetry_level>1?log:'') xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') xhr.send(postData) } diff --git a/speedtest_worker.min.js b/speedtest_worker.min.js index 7794608..efeb13d 100644 --- a/speedtest_worker.min.js +++ b/speedtest_worker.min.js @@ -1 +1 @@ -var testStatus=-1,dlStatus="",ulStatus="",pingStatus="",jitterStatus="",clientIp="",dlProgress=0,ulProgress=0,pingProgress=0,log="";function tlog(s){log+=Date.now()+": "+s+"\n"}function twarn(s){log+=Date.now()+" WARN: "+s+"\n",console.warn(s)}var settings={test_order:"IP_D_U",time_ul:15,time_dl:15,time_ulGraceTime:3,time_dlGraceTime:1.5,count_ping:35,url_dl:"garbage.php",url_ul:"empty.php",url_ping:"empty.php",url_getIp:"getIP.php",getIp_ispInfo:!0,getIp_ispInfo_distance:"km",xhr_dlMultistream:10,xhr_ulMultistream:3,xhr_multistreamDelay:300,xhr_ignoreErrors:1,xhr_dlUseBlob:!1,xhr_ul_blob_megabytes:20,garbagePhp_chunkSize:20,enable_quirks:!0,ping_allowPerformanceApi:!0,overheadCompensationFactor:1.06,useMebibits:!1,telemetry_level:0,url_telemetry:"telemetry.php"},xhr=null,interval=null,test_pointer=0;function url_sep(url){return url.match(/\?/)?"&":"?"}function clearRequests(){if(tlog("stopping pending XHRs"),xhr){for(var i=0;i=settings.test_order.length)return testStatus=4,void sendTelemetry();switch(settings.test_order.charAt(test_pointer)){case"I":if(test_pointer++,iRun)return void runNextTest();iRun=!0,getIp(runNextTest);break;case"D":if(test_pointer++,dRun)return void runNextTest();dRun=!0,testStatus=1,dlTest(runNextTest);break;case"U":if(test_pointer++,uRun)return void runNextTest();uRun=!0,testStatus=3,ulTest(runNextTest);break;case"P":if(test_pointer++,pRun)return void runNextTest();pRun=!0,testStatus=2,pingTest(runNextTest);break;case"_":test_pointer++,setTimeout(runNextTest,1e3);break;default:test_pointer++}}};runNextTest()}"abort"===params[0]&&(tlog("manually aborted"),clearRequests(),runNextTest=null,interval&&clearInterval(interval),1settings.time_dl&&01e3*settings.time_dlGraceTime&&(0settings.time_ul&&01e3*settings.time_ulGraceTime&&(0":">",'"':""","'":"'"};String.prototype.escapeHtml=function(){return this.replace(/[&<>"']/g,function(m){return HTML_ESCAPE_MAP[m]})};var log="";function tlog(s){log+=Date.now()+": "+s+"\n"}function twarn(s){log+=Date.now()+" WARN: "+s+"\n",console.warn(s)}var settings={test_order:"IP_D_U",time_ul:15,time_dl:15,time_ulGraceTime:3,time_dlGraceTime:1.5,count_ping:35,url_dl:"garbage.php",url_ul:"empty.php",url_ping:"empty.php",url_getIp:"getIP.php",getIp_ispInfo:!0,getIp_ispInfo_distance:"km",xhr_dlMultistream:10,xhr_ulMultistream:3,xhr_multistreamDelay:300,xhr_ignoreErrors:1,xhr_dlUseBlob:!1,xhr_ul_blob_megabytes:20,garbagePhp_chunkSize:20,enable_quirks:!0,ping_allowPerformanceApi:!0,overheadCompensationFactor:1.06,useMebibits:!1,telemetry_level:0,url_telemetry:"telemetry/telemetry.php"},xhr=null,interval=null,test_pointer=0;function url_sep(url){return url.match(/\?/)?"&":"?"}function clearRequests(){if(tlog("stopping pending XHRs"),xhr){for(var i=0;i=settings.test_order.length)0settings.time_dl&&01e3*settings.time_dlGraceTime&&(0settings.time_ul&&01e3*settings.time_ulGraceTime&&(0 + + + +HTML5 Speedtest - Stats + + + +

HTML5 Speedtest - Stats

+ + Please set $stats_password in telemetry_settings.php to enable access. + +
+
+

Search test results

+ + + +
+ prepare("select id,timestamp,ip,ispinfo,ua,lang,dl,ul,ping,jitter,log from speedtest_users where id=?"); + $q->bind_param("i",$_POST["id"]); + $q->execute(); + $q->bind_result($id,$timestamp,$ip,$ispinfo,$ua,$lang,$dl,$ul,$ping,$jitter,$log); + } else if($db_type=="sqlite"||$db_type=="postgresql"){ + $q=$conn->prepare("select id,timestamp,ip,ispinfo,ua,lang,dl,ul,ping,jitter,log from speedtest_users where id=?"); + $q->execute(array($id)); + } else die(); + }else{ + if($db_type=="mysql"){ + $q=$conn->prepare("select id,timestamp,ip,ispinfo,ua,lang,dl,ul,ping,jitter,log from speedtest_users order by timestamp desc limit 0,100"); + $q->execute(); + $q->bind_result($id,$timestamp,$ip,$ispinfo,$ua,$lang,$dl,$ul,$ping,$jitter,$log); + } else if($db_type=="sqlite"||$db_type=="postgresql"){ + $q=$conn->prepare("select id,timestamp,ip,ispinfo,ua,lang,dl,ul,ping,jitter,log from speedtest_users order by timestamp desc limit 0,100"); + $q->execute(); + }else die(); + } + while(true){ + $id=null; $timestamp=null; $ip=null; $ispinfo=null; $ua=null; $lang=null; $dl=null; $ul=null; $ping=null; $jitter=null; $log=null; + if($db_type=="mysql"){ + if(!$q->fetch()) break; + } else if($db_type=="sqlite"||$db_type=="postgresql"){ + if(!($row=$q->fetch())) break; + $id=$row["id"]; + $timestamp=$row["timestamp"]; + $ip=$row["ip"]; + $ispinfo=$row["ispinfo"]; + $ua=$row["ua"]; + $lang=$row["lang"]; + $dl=$row["dl"]; + $ul=$row["ul"]; + $ping=$row["ping"]; + $jitter=$row["jitter"]; + $log=$row["log"]; + }else die(); + ?> + + + + + + + + + + +
Test ID
Date and time
IP and ISP Info
User agent and locale
Download speed
Upload speed
Ping
Jitter
Log
+ + +
+

Login

+ + +
+ + + diff --git a/telemetry.php b/telemetry/telemetry.php similarity index 95% rename from telemetry.php rename to telemetry/telemetry.php index f14ba4b..0dcb001 100644 --- a/telemetry.php +++ b/telemetry/telemetry.php @@ -15,8 +15,9 @@ if($db_type=="mysql"){ $conn = new mysqli($MySql_hostname, $MySql_username, $MySql_password, $MySql_databasename) or die("1"); $stmt = $conn->prepare("INSERT INTO speedtest_users (ip,ispinfo,ua,lang,dl,ul,ping,jitter,log) VALUES (?,?,?,?,?,?,?,?,?)") or die("2"); $stmt->bind_param("sssssssss",$ip,$ispinfo,$ua,$lang,$dl,$ul,$ping,$jitter,$log) or die("3"); - $stmt->execute() or die("4"); + $stmt->execute() or die("4"); $stmt->close() or die("5"); + echo "id ".$conn->insert_id; $conn->close() or die("6"); }elseif($db_type=="sqlite"){ @@ -38,6 +39,7 @@ if($db_type=="mysql"){ "); $stmt = $conn->prepare("INSERT INTO speedtest_users (ip,ispinfo,ua,lang,dl,ul,ping,jitter,log) VALUES (?,?,?,?,?,?,?,?,?)") or die("2"); $stmt->execute(array($ip,$ispinfo,$ua,$lang,$dl,$ul,$ping,$jitter,$log)) or die("3"); + echo "id ".$conn->lastInsertId(); $conn = null; }elseif($db_type=="postgresql"){ // Prepare connection parameters for db connection @@ -49,6 +51,7 @@ if($db_type=="mysql"){ $conn = new PDO("pgsql:$conn_host;$conn_db;$conn_user;$conn_password") or die("1"); $stmt = $conn->prepare("INSERT INTO speedtest_users (ip,ispinfo,ua,lang,dl,ul,ping,jitter,log) VALUES (?,?,?,?,?,?,?,?,?)") or die("2"); $stmt->execute(array($ip,$ispinfo,$ua,$lang,$dl,$ul,$ping,$jitter,$log)) or die("3"); + echo "id ".$conn->lastInsertId(); $conn = null; } elseif($db_type=="csv"){ diff --git a/telemetry_mysql.sql b/telemetry/telemetry_mysql.sql similarity index 100% rename from telemetry_mysql.sql rename to telemetry/telemetry_mysql.sql diff --git a/telemetry_postgresql.sql b/telemetry/telemetry_postgresql.sql similarity index 100% rename from telemetry_postgresql.sql rename to telemetry/telemetry_postgresql.sql diff --git a/telemetry_settings.php b/telemetry/telemetry_settings.php similarity index 64% rename from telemetry_settings.php rename to telemetry/telemetry_settings.php index 505a8b1..59dc46e 100644 --- a/telemetry_settings.php +++ b/telemetry/telemetry_settings.php @@ -1,9 +1,10 @@ + + +//IMPORTANT: DO NOT ADD ANYTHING BELOW THIS PHP CLOSING TAGS, NOT EVEN EMPTY LINES! +?> \ No newline at end of file