PHP-WoL (Wake on LAN)

Do you have a home NAS (QNAP, Synology etc.) capable of running PHP?  Do you want to be able to “Wake Up” your PC remotely?

Having very little experience of PHP I began to Google for some code that someone else had written.  That’s when I discovered others had tried the same but had issues with running the “ping” command from within PHP due to permissions.  After a little “out of the box” thinking I came across a small script that would attempt to open a socket connection to a specified port!  The script worked perfectly, and in many ways provided me with better solution!  The RDP service that I use to connect to my PC is one of the last to load, therefore replies from pings are often received long before the service has started.  In the case of this script I know that when I get a “SUCCESFULL!” message my PC is ready and waiting for a connection….

I decided that I wanted a single file solution, which worked in the majority of browsers including those on mobile devices.  The first version of this code worked, but took a long time to load the initial page and refreshed ALL content until the browser was closed.  The delay in loading was caused by PHP waiting for the socket connection to timeout.  In addition the WoL packet was sent with each refresh.  I thought I can do better than this!

The script attached to this post when loaded will create a 2 page frame set using a single PHP page. The top frame sends the WoL packet and does NOT refresh, the bottom frame performs the port check and is refreshed until either a successful connection is made or the maximum tries is reached.

<?php
##################################################
##     php WoL with port check - PRThomasUK.    ##
##              www.pete-thomas.me.uk           ##
##################################################
//
// ################## user variables... ##################
// Friendly name for device, example "My Computer".
$device     = "My Computer";
// IP address of device, example "x.x.x.x".
$deviceip   = "10.0.0.23";
// TCP Port on device to check, example "3389" = RDP, "80" = WebServer.
$deviceport = "3389";
// MAC address of NIC1 on device, example "00:00:00:00:00:00" or "00-00-00-00-00-00".
$devicemac1 = "00-11-22-33-44-55";
// MAC address of NIC2 on device, example "00:00:00:00:00:00" or "00-00-00-00-00-00". - Optional set to "" if NIC2 not required.
$devicemac2 = "aa:bb:cc:dd:ee:ff";
// Number of times to attempt to connect to port on device after magic packet sent, example "10"
$maxtries   = "10";
// Broadcast address of network, example ""x.x.x.x". ("255.255.255.255" works in most cases.)
$broadcast  = "255.255.255.255";
// ICMP port number, default "7".
$udport     = "7";
// Timeout value for re-tries (in seconds), default "10".
$timeout    = "10";
// #######################################################
//
// ##### Read in variables from url #####
//
// $frame - used to determine which content to display when executed.
$frame      = $_GET[ "frame" ];
// $tries - used to determine number of attempts at checking port beetween reloads, compared with maxtries.
$tries      = $_GET[ "tries" ];
// $pageurl - obtain URL used to access file, used when creating frameset & setting reloads.
$pageurl    = pageurl();
// Process variables used in frame2, increments tries & sets status to Success(1) or Failed(2)
if ( $frame == 2 ) {
                processurl();
}
// ###### Functions ######
//
// function pageurl( ) - Returns URL of page via PHP variables.
function pageurl( )
{
                $pageurl = "HTTP";
                if ( $_SERVER[ "HTTPS" ] == "on" ) {
                                $pageurl .= "S";
                }
                $pageurl .= "://";
                if ( $_SERVER[ "SERVER_PORT" ] != "80" ) {
                                $pageurl .= $_SERVER[ "SERVER_NAME" ] . ":" . $_SERVER[ "SERVER_PORT" ] . $_SERVER[ "REQUEST_URI" ];
                } else {
                                $pageurl .= $_SERVER[ "SERVER_NAME" ] . $_SERVER[ "REQUEST_URI" ];
                }
                $urlarts = explode( "?", $pageurl );
                $pageurl = $urlarts[ "0" ];
                return $pageurl;
}
//  function processurl( ) - Processes variables used in frame2, increments tries & sets status to Success(1) or Failed(2)
function processurl( )
{
                global $status, $tries, $maxtries;
                if ( $status == 0 && $tries < $maxtries - 1 ) {
                                $tries = $tries + 1;
                } else {
                                $status = 2;
                }
                if ( portcheck() == 0 ) {
                                $status = 1;
                }
}
//  function wakeonlan() - Attempts to send WoL packet and returns outcome.
function wakeonlan( $device, $mac )
{
                global $broadcast, $udport;
                $mac            = ereg_replace( "[^A-Za-z0-9]", ":", $mac );
                $broadcast_byte = explode( ':', $mac );
                $hw_addr        = '';
                for ( $a = 0; $a < 6; $a++ )
                                $hw_addr .= chr( hexdec( $broadcast_byte[ $a ] ) );
                $msg = chr( 255 ) . chr( 255 ) . chr( 255 ) . chr( 255 ) . chr( 255 ) . chr( 255 );
                for ( $a = 1; $a <= 16; $a++ )
                                $msg .= $hw_addr;
                $s = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP );
                if ( $s == false ) {
                                $content = "Error creating socket!\n";
                } else {
                                // setting a broadcast option to socket:
                                $opt_ret = socket_set_option( $s, 1, 6, true );
                                if ( $opt_ret < 0 ) {
                                                $content = "setsockopt() failed, error: " . strerror( $opt_ret ) . "\n";
                                }
                                if ( socket_sendto( $s, $msg, strlen( $msg ), 0, $broadcast, $udport ) ) {
                                                $content = "WoL packet sent to mac address " . $mac . "...\n";
                                                socket_close( $s );
                                } else {
                                                $content = "Failed to send WoL packet!";
                                }
                }
                return $content;
}
//  function portcheck( ) - Attempts to connect to TCP port on the device via a Socket, returns $errno.
function portcheck( )
{
                global $deviceip, $deviceport;
                $file = fsockopen( $deviceip, $deviceport, $errno, $errstr, 50 );
                if ( $errno == 0 ) {
                                fclose( $file );
                }
                return $errno;
}
// function htmlheader( ) - Returns HTML Header for TITLE and if Frame2 REFRESH set.
function htmlheader( )
{
                global $device, $frame, $tries, $maxtries, $status, $pageurl, $timeout;
                // global "custom" header settings
                $content = "<TITLE>PHP WoL ($device) - by PRThomasUK </TITLE>\n";
                //generate refresh header for frame2.
                if ( $frame == 2 && $status == 0 ) {
                                $content .= "<META HTTP-EQUIV=\"refresh\" CONTENT=\"$timeout;url=$pageurl?frame=$frame&tries=$tries\">\n";
                }
                return $content;
}
// function htmlheader( ) - Returns HTML content for mainpage, frame1 & frame2 based on value of $frame.
function htmlcontent( )
{
                global $pageurl, $device, $deviceip, $deviceport, $devicemac1, $devicemac2, $frame, $tries, $maxtries, $status;
                if ( $frame == 2 ) {
                                if ( $status == 0 ) {
                                                $content = "<H3>$tries/$maxtries attempts to connect to $deviceip:$deviceport completed.</H3>\n";
                                } elseif ( $status == 1 ) {
                                                $content = "<FONT COLOR=\"green\">\n";
                                                $content .= "<H1>SUCCESS!!!</H1>\n";
                                                $content .= "</FONT>\n";
                                                $content .= "<H3>Connection made to $device ($deviceip:$deviceport).</H3>\n";
                                } else {
                                                $content = "<FONT COLOR=\"red\">\n";
                                                $content .= "<H1>FAILED...</H1>\n";
                                                $content .= "</FONT>\n";
                                                $content .= "<H3>Unable to connect to $device ($deviceip:$deviceport).</H3>\n";
                                }
                } elseif ( $frame == 1 ) {
                                $content = "<FONT COLOR=\"navy\">\n";
                                $content .= "<H1>PHP WoL ($device)</H1>\n";
                                $content .= "</FONT>\n";
                                $content .= wakeonlan( $device, $devicemac1 );
                                if ( $devicemac2 ) {
                                                $content .= "<BR>\n";
                                                $content .= wakeonlan( $device, $devicemac2 );
                                }
                } else {
                                $content = "<FRAMESET rows=\"130,*\" frameborder=0 border=0 framespacing=5>\n";
                                $content .= "<FRAME SRC=\"$pageurl?frame=1\">\n";
                                $content .= "<FRAME SRC=\"$pageurl?frame=2\">\n";
                                $content .= "<NOFRAMES>\n";
                                $content .= "<FONT COLOR=\"navy\">\n";
                                $content .= "<H1>PHP WoL ($device)</H1>\n";
                                $content .= "</FONT>\n";
                                $content .= wakeonlan( $device, $devicemac1 );
                                if ( $devicemac2 ) {
                                                $content .= "<BR>\n";
                                                $content .= wakeonlan( $device, $devicemac2 );
                                }
                                $content .= "<BR>\n";
                                $content .= "<BR>\n";
                                $content .= "<FONT COLOR=\"red\">\n";
                                $content .= "<H2>Your browser does not support frames...</H2>\n";
                                $content .= "</FONT>\n";
                                $content .= "<H3>Status of $device will not be monitored!</H3>\n";
                                $content .= "</NOFRAMES>\n";
                                $content .= "</FRAMESET>\n";
                }
                return $content;
}
?> 
<!doctype html public "-//w3c//dtd html 4.01 transitional//en" "http://www.w3.org/tr/html4/loose.dtd"> 
<HTML> 
<HEAD> 
<?php
echo htmlheader();
?> 
<META NAME="author" CONTENT="PRThomasUK"> 
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=utf-8"> 
<META HTTP-EQUIV="cache-control" CONTENT="no-cache"> 
<META HTTP-EQUIV="pragma" CONTENT="no-cache"> 
<META NAME="robots" CONTENT="none"> 
<META NAME="rating" CONTENT="safe for kids"> 
</HEAD> 
<?php
echo htmlcontent();
?> 
</HTML>

Click here to download the script…

Share this page:

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.