* @license GPL * @copyright (c) 2009-2019 Andreas Schamanek * */ $version = 'netstat.php ' . 'by Andreas Schamanek ' . '~ v0.16 ~ 2019-01-28 ~ ' . 'GPL licensed'; // below we set up some silly defaults; it is recommended to save your // own settings in $configfile; if readable it will override our defaults; // for a list of configuration variables see the readme. $configfile = 'netstat.conf.php'; // title (as in HTML) and headline of the page $title = "Our Network Status"; $headline = $title; // including $configfile if available if (file_exists($configfile) && is_readable($configfile)) include($configfile); // all configuration variables are set only if not already set function defaults(&$var, $value) { isset($var) || $var = $value; } // Report no PHP errors (to be safe we include this very early) defaults($error_reporting, 0); error_reporting($error_reporting); // if $alertfile exists the contents will be included()/shown (use HTML!) defaults($alertfile, 'netstat.txt'); // checks (use pipes (|) with care ;) // syntax: host or IP to check | port | description // if $port = 'ping' an ICMP ping will be executed // if $port = 'headline' $host is printed as a headline defaults($checks, array( 'Examples testing localhost |headline', 'localhost | ping| ICMP ping (ping)', 'localhost | 80 | WWW server (port 80)', '127.0.0.2 | 443 | WWW server (SSL, port 443)', '127.0.0.1 | 22 | SSH server (port 22)', '[::1] | 22 | SSH server IPv6 (port 22)', '127.0.0.3 | 21 | FTP server (port 21)', '-------------------------------------------------', 'Some more examples with errors or not :)|headline', 'www.unknown.example.com| 80|www.unknown.example.com', 'example.com| 23|example.com:23 (telnet is dead)', 'Empty and negative ports are ignored||', 'So are lines without pipe delimiter', 'www.google.com | 80 | WWW server @ google.com', 'localhost |-ping| Disabled ping', 'www.example.com | -80 | WWW server @ www.example.com', )); // exec commands for ping: -l3 (preload) is recommended but //defaults($ping_command, 'ping -l3 -c3 -w1 -q'); // might not work everywhere defaults($ping_command, 'ping -c3 -w1 -q'); defaults($ping6_command, 'ping6 -c3 -w1 -q'); // fsockopen timeout; might need adjustment depending on network defaults($timeout, 4); // show a very simple progress indicator (requires Javascript) // may be disabled also by adding '?noprogress' to the script's URL defaults($progressindicator, true); // diagnostics and errors are added by default as title attributes // they are shown by browsers in tooltips upon mouse over // with ?showdiagnostics, ?diags or $showdiagnostics=true diagnostics // will be shown in their own table rows defaults($showdiagnostics, false); // output buffering can be a PITA (see below), in some cases it can help // to send "garbage" to get browsers to display the first parts of a page // (like the title + progress indicator) while the rest is still loading. // consider $bufferfill="\n"; defaults($bufferfill,''); // strings for online and offline (by default these are used for CSS, too) defaults($online, 'Online'); defaults($offline, 'Offline'); // print date and/or time (leave empty to show no timestamp) defaults($datetime, 'l, F j, Y, H:i:s T'); // RSS alert feed defaults($rssfeed, true); // enable/disable RSS feed // URL of RSS feed defaults($rssfeedurl, '//'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?rss'); // RSS feed title defaults($rsstitle, "RSS alert feed of $title"); // RSS header e.g. to include in $htmlheader; set to '' to offer no RSS defaults($rssheader, '"); // RSS alert link (might point e.g. to your network status homepage) defaults($rsslink, '//'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?noprogress'); // RSS date and/or time format (here we use a ISO 8601 format) defaults($rssdatetime, 'o-m-d H:i:s T'); // HTML/page header (_tmp variable just used for readability) $htmlheader_tmp = << $title $rssheader
EOH; // end of $htmlheader_tmp defaults($htmlheader, $htmlheader_tmp); // HTML/page footer defaults($htmlfooter, "
\n\n"); // ------------------------------------------------- main part of script // if RSS feed is requested send $alertfile and quit if ((isset($_REQUEST['rss']) && ($rssfeed)) || (isset($argv[1]) && $argv[1] == 'rss')) { header("Content-Type: application/rss+xml"); echo "\n"; echo "\n\n"; echo "$rsstitle\n$rsslink\n"; echo "$rsstitle\n"; echo "en\n"; if (file_exists($alertfile) && is_readable($alertfile)) { echo "\nAlert ".date($rssdatetime, filemtime($alertfile)) . " for $rsstitle\n"; echo ''.date("r", filemtime($alertfile))."\n"; echo "$rsslink\n"; echo '#'.date("Ymd\THi", filemtime($alertfile))."\n"; echo '\n\n"; } echo "\n\n"; exit; } else if (isset($_REQUEST['rss'])) { // if RSS was requested even though it was disabled exit; } // output HTML/page header echo $htmlheader; // headline, date and time and start of table echo "

$headline

\n"; if ($datetime) echo '

as of ' . date($datetime) . "

\n"; // show the contents of $alertfile if it is readable and larger than 7 bytes if (file_exists($alertfile)) { clearstatcache(true, $alertfile); if ((is_readable($alertfile) && (filesize($alertfile) > 7))) { echo "
\n"; @include($alertfile); echo "
\n"; } } // show a simple progress indicator if (isset($_REQUEST['noprogress']) || (isset($argv[1]) && $argv[1] == 'noprogress')) { $progressindicator = false; } if ($progressindicator) { echo '\n"; } // flush output buffers (if any)/send content to browser // note that this won't work if output is buffered by filters, proxies // etc. of is gzip'ed; cf. https://stackoverflow.com/q/4191385/196133 // + https://stackoverflow.com/q/3445222/196133 // + https://stackoverflow.com/q/4481235/196133 echo $bufferfill; @ob_flush(); @flush(); // $showdiagnostics is true w/ ?diags, and false with ?diags=off if (isset($_GET['showdiagnostics']) || isset($_GET['diags'])) { if ($_GET['showdiagnostics'] == 'off' || $_GET['diags'] == 'off') { $showdiagnostics = false; } else { $showdiagnostics = true; } } echo "\n"; // main loop of checks foreach ($checks as $check) { $status = $offline; // default state $diagnostics = ''; // mouse-over for tooltips $output = true; // print a line or print no line list($host,$port,$description) = explode('|',"$check||"); // the 2 extra '|'s are to avoid notices about undefined offsets $host = trim($host); $port = trim($port); switch ($port) { case '': // ignore lines with empty or no "ports", and ignore ... case (substr($port,0,1)=='-'): // negative ports, '-ping', and // any "port" starting with '-' is considered a disabled check $output = false; break; case 'headline': // print a headline within the status table // we enclose it with invisible
== == for nicer text output echo '\n"; $output = false; break; case 'ping': // do an ICMP ping $ping=exec("$ping_command $host",$pingoutput,$pingreturn); // Continues on into ping6 as they share all but the command. case 'ping6': // do an ICMP IPv6 ping if (!isset($ping)) { $ping=exec("$ping6_command $host",$pingoutput,$pingreturn); } if(strlen($ping)>10) { // strlen($ping)>10 works around a bug in Debian ping (", pipe 3") // https://bugs.debian.org/456192 $status = $online; $diagnostics = "$ping :: $pingreturn"; } else $diagnostics = "$ping :: $pingreturn"; // uncomment this if you want the full output as HTML comment //echo "\n\n"; //unset($pingoutput); // *nix ping command's return value meanings: // 0: all OK; 1: an error occured; 2: host unknown unset($ping); break; default: // look if a TCP connection to port can be opened $time_start = microtime(true); $fp = @fsockopen($host, $port, $errno, $errstr, $timeout); $time_end = microtime(true); $time = number_format(($time_end - $time_start)*1000,1); if ($fp) { // fsockopen worked, service is online $status = $online; $diagnostics = "$time ms"; fclose($fp); } else if ($errno<0) { $diagnostics = "errno=$errno; Host unknown?"; } else { $diagnostics = $errstr; } } // output results if ($output) { $diagnostics = htmlspecialchars($diagnostics); if ($showdiagnostics && $diagnostics) { if ($status == $online && ($port != 'ping' && $port != 'ping6')) { echo "\n"; } else { echo "\n"; echo "\n"; } } else { echo "\n"; } } // flush output buffers (if any)/send content to browser @ob_flush(); @flush(); } echo "
' . '' . $host . '' . "
$description$status ($diagnostics)
$description$status
∵ $diagnostics
$description$status
\n"; // make progress indicator disappear by means of Javascript if ($progressindicator) { echo << progressindicator = document.getElementById("progress"); progressindicator.innerHTML = "Checks finished"; progressindicator.style.visibility = 'hidden'; EOT; } // output $version and HTML/page footer if (!empty($version)) echo "

$version

\n"; echo "$htmlfooter\n"; /* * License * * This script is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This script is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this script; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA * History * * 0.09 * 2009-10-26 first buggy "punish me" alpha release candidate * 0.10 * 2009-11-07 added stopwatch (time diagnostics) for online services * 0.11 * 2009-11-09 added RSS feed option for alerts * 0.12 * 2009-11-12 cleaned up and simplified settings mechanism * 0.13 * 2009-11-18 $alertfile is only included if larger than 2 bytes * 0.14 * 2009-12-05 default CSS code change to improve font size scaling * 0.15 * 2012-08-04 added ping6 (suggested by Todd Johnson; thanks!) * 0.15 * 2012-08-05 converted to HTML5, improved progress indicator, ... * 0.16 * 2012-08-13 removed @ from include($configfile) * 0.16 * 2014-04-25 charset UTF-8; viewport; added RSS guid+atom links * 0.16 * 2015-12-07 updated copyright date + URLs * 0.16 * 2019-01-22 buffering workarounds, responsive CSS, various tweaks * 0.16 * 2019-01-28 added $showdiagnostics to print errors in extra rows * */