preloaded image preloaded image preloaded image

PHP-Based Speed Test

Do you have the need? The need... for speed?

Note: This script is an adaptation of a script posted by user "neel_basu" on codingforums.com. Credit for the idea and original code goes to him, but I have fixed some calculation problems and made this an AJAX-based script now...

Basically, this script takes a fairly large file (say 2-3 MB, for good results) and loads it via AJAX. When the AJAX request is complete, the javascript compares the start and end times and calculates your download speed from the host server. Pretty neat stuff!

This is the script in action:

  bits Bytes
   
[ speeds are only relative to your connection speed with this website ]

 

And here's the code that makes this all work:

<?php ##################################################################################################### # Note: I realize that KB and KiB have a commonly misunderstood formulation and I realize that # # I am using "KB" and "MB" where I am truly calculating "KiB" and "MiB," respectively. Since # # most people are used to seeing this information presented incorrectly, I am keeping that # # tradition. If you prefer to see actual "KB" and "MB" ratings, just alter the $divisor variable # # below to make the adjustment. # ##################################################################################################### $data_file = "dilbert.zip"; // $data_file should be some generic binary file - this script was tested with a 3 MB zip file of some Dilbert comic strips. The file should be sufficiently large so that the latency from the initial HTTP request itself does not skew the results by much. $filesize = filesize($data_file); $divisor = 1024; //set this to 1000 instead of 1024 if you want true KB and MB, rather than mis-labeled KiB and MiB that we are most used to seeing... if(isset($_GET['ajax'])){ // if it's an ajax call we just read and print the binary file's contents... $fd = fopen ($data_file, "rb+"); $contents = fread ($fd, $filesize); ob_start(print $contents); ob_end_flush(); fclose ($fd); exit(0); } else{ // if this visit is not an AJAX request we display the page itself... ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title>Bandwidth Test</title> <script type="text/javascript"> //<!-- var time; var starttime; var endtime; var downloadtime; var kbps; var ksec; var mbps; var msec; var ajax_run = new XMLHttpRequest(); function addCommas(nStr){ nStr += ''; x = nStr.split('.'); x1 = x[0]; x2 = x.length > 1 ? '.' + x[1] : ''; var rgx = /(\d+)(\d{3})/; while (rgx.test(x1)) { x1 = x1.replace(rgx, '$1' + ',' + '$2'); } return x1 + x2; } function ajax_bandwidth_test(){ cancel_any_pending_ajax(); disable_table(); send_ajax_call(); } function cancel_any_pending_ajax(){ if(ajax_run.readyState){ if (ajax_run.readyState != 0 && ajax_run.readyState != 4){ ajax_run.abort(); } } } function disable_table(){ var action_row = document.getElementById('action_row'); var spans = action_row.getElementsByTagName('span'); var link = action_row.getElementsByTagName('a')[0]; link.style.zIndex = -1; if (spans.length>1){ spans[1].className = 'disabled'; spans[2].className = 'disabled'; } var status_box = document.getElementById('status'); status_box.innerHTML = "Testing Your Current Bandwidth..."; document.title = "Bandwidth Test | Running..."; } function send_ajax_call(){ var result = ''; var x = new Date(); x = x.getTime(); var url = '<?php print $_SERVER['REQUEST_URI']; ?>?ajax='+x; //you will need to change the "?" to a "&" if your URI already has some $_GET variables in it... if (window.XMLHttpRequest){ // code for IE7+, Firefox, Chrome, Opera, Safari ajax_run = new XMLHttpRequest(); } else{ // code for IE6, IE5 ajax_run = new ActiveXObject("Microsoft.XMLHTTP"); } ajax_run.onreadystatechange = function(){ if (ajax_run.readyState==4 && ajax_run.status==200){ result = ajax_run.responseBody; //ie won't work with responseText, but responseBody will work just fine... if (result!=''){ //no point in printing the binary result to the page, just update the speed test results... update_results(); } else{ alert('Speed test failed!'); } } else if (ajax_run.readyState==1){ //connected to server, start the timer... time = new Date(); starttime = time.getTime(); document.getElementById('status').innerHTML = "Testing Your Current Bandwidth... Connected..." } else if (ajax_run.readyState==2){ //server is processing the request... document.getElementById('status').innerHTML = "Testing Your Current Bandwidth... Loading..." } else if (ajax_run.readyState==4 && ajax_run.status!=200){ alert('Speed test failed! (' + ajax_run.status + ')'); } } ajax_run.open("GET",url,true); ajax_run.send(); } function update_results(){ time = new Date(); endtime = time.getTime(); if (endtime == starttime){ downloadtime = 0; } else{ downloadtime = (endtime - starttime)/1000; } kbytes_of_data = <?php print $filesize/$divisor; ?>; mbytes_of_data = <?php print $filesize/$divisor/$divisor; ?>; ksec = kbytes_of_data / downloadtime; msec = mbytes_of_data / downloadtime; kbps = addCommas(Math.round(ksec * 8192)/1000); mbps = addCommas(Math.round(msec * 8192)/1000); ksec = addCommas(Math.round(ksec*100)/100); msec = addCommas(Math.round(msec*100)/100); var action_row = document.getElementById('action_row'); var cells = action_row.getElementsByTagName('td'); var link = document.getElementById('trigger'); var title = "Bandwidth Test | "; var text = ''; if (msec>1){ cells[1].innerHTML = "<span>" + mbps + " mbps</span>"; cells[2].innerHTML = "<span>" + msec + " MB/s</span>"; title += msec + " MB/s"; text += addCommas(Math.round(mbytes_of_data*100)/100) + ' MB of data transferred in ' + downloadtime + ' seconds...'; } else{ cells[1].innerHTML = "<span>" + kbps + " kbps</span>"; cells[2].innerHTML = "<span>" + ksec + " KB/s</span>"; title += ksec + " KB/s"; text += addCommas(Math.round(kbytes_of_data*100)/100) + ' KB of data transferred in ' + downloadtime + ' seconds...'; } document.title = title; document.getElementById('status').innerHTML = text; link.style.zIndex = 1; } //--> </script> <style type="text/css"> *{margin:0;padding:0;} body{padding:20px;background:#fff;} table{border-collapse:collapse;position:relative;z-index:0;} th,td{border:1px solid #000;cursor:default;} th{padding:2px 5px;font-weight:bold;text-align:center;font-size:16px;} td{width:120px;text-align:right;} td span{padding:2px 5px;display:block;line-height:20px;} td:first-child{width:110px;text-align:left;} th:first-child{border-top:0;border-left:0;} a{text-decoration:none;font-weight:bold;font-family:tahoma;font-size:12px;display:block;color:#333;padding:5px;text-align:center;position:relative;z-index:1;} a:hover{background-color:#333;color:#fff;} a,a:hover,a:focus,a:active{outline:0;} #link_box{position:relative;} #link_mask{display:block;width:100%;height:100%;background:transparent;position:absolute;top:0;left:0;z-index:0;padding:0;line-height:24px;font-size:500px;overflow:hidden;cursor:default;} #status{margin-top:20px;} .disabled{background-color:#333;color:#fff;} .disclaimer td{border-right:0;border-bottom:0;border-left:0;font-size:11px;text-align:right;color:#333;width:auto;} .disclaimer td em{font-weight:normal;font-style:italic;} </style> </head> <body> <table> <thead> <tr> <th> </th> <th>bits</th> <th>Bytes</th> </tr> </thead> <tbody> <tr id="action_row"> <td><div id="link_box"><a href="javascript:ajax_bandwidth_test();" id="trigger">Start Test</a><span id="link_mask"> </span></div></td> <td> </td> <td> </td> </tr> <tr class="disclaimer"> <td colspan="3">[ <em>speeds are only relative to your connection speed with this website</em> ]</td> </tr> </tbody> </table> <p id="status"></p> </body> </html> <?php } ?>