11

is there a wake on lan script using a web language preferably php that works? Also one that has some documentation on how to get it to work like what needs to be enabled on your server etc

Funk Forty Niner
  • 73,764
  • 15
  • 63
  • 131
Michael
  • 441
  • 3
  • 9
  • 16
  • What's a "wake on lan script" exactly? – deceze May 19 '11 at 07:46
  • About server configuration: beware of OS-level WoL blocking (Linux turning off Wake-on-LAN) - basically `ethtool -s eth0 wol g` will be your friend: http://ubuntuforums.org/showthread.php?t=234588 - so much about "server configuration" – Tomasz Gandor Nov 18 '13 at 14:18

5 Answers5

11
function wol($broadcast, $mac)
{
    $hwaddr = pack('H*', preg_replace('/[^0-9a-fA-F]/', '', $mac));

    // Create Magic Packet
    $packet = sprintf(
        '%s%s',
        str_repeat(chr(255), 6),
        str_repeat($hwaddr, 16)
    );

    $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);

    if ($sock !== false) {
        $options = socket_set_option($sock, SOL_SOCKET, SO_BROADCAST, true);

        if ($options !== false) {
            socket_sendto($sock, $packet, strlen($packet), 0, $broadcast, 7);
            socket_close($sock);
        }
    }
}

Should work - call it with a broadcast IP address, and a MAC address

Mez
  • 22,526
  • 14
  • 67
  • 91
  • When you say call it with those two things do you mean set those as variables? – Michael May 19 '11 at 10:06
  • I mean - pass them as arguments into the function – Mez Jun 21 '11 at 13:57
  • Sorry doesn't work anymore. Warning: socket_send() expects exactly 4 parameters, 6 given – Roger Far Jun 07 '12 at 15:03
  • It wouldn't hurt to do a: `$mac = str_replace("-", ":", $mac);` right at the beginning: to also accept windows' format of MAC. – Tomasz Gandor Nov 18 '13 at 14:19
  • 1
    One liner to get hwaddress which is compatible with *nix and winblows: `$hwaddr = pack('H*', preg_replace('/[^0-9a-zA-Z]/', '', $mac) );` This is instead of 1 call to split(), and writing a loop over an array which has 6 calls to hexdec() and 6 calls to chr(). Well, not much performance improvement for such a small routine, but just to show a little php hack. – David Strencsev Nov 18 '14 at 17:49
  • 1
    No longer works as of PHP 7.0: `PHP Fatal error: Uncaught Error: Call to undefined function split()` - swap out `split()` for `explode()` and you're good to go. – EionRobb Dec 29 '18 at 22:02
6

I know this is an old questions, but it's still the first Google result, so here's what I ended up doing after a bit of research:

Prerequisites:

  • Linux box on the same network
  • Install the wakeonlan package from your system's package manager
        (i.e. sudo apt-get install wakeonlan)

Now the script is as easy as this:

<?php
    # replace with your target MAC address
    $mac = 'aa:bb:cc:11:22:33';

    exec("wakeonlan $mac");
?>

 

Hope that helps someone.

Ryan Steffer
  • 373
  • 5
  • 10
  • 1
    This works as long as $mac never contains user input. Thanks! – Robert Talada May 23 '18 at 19:40
  • yup. be VERY careful with exec, and if possible, just dont use it – My1 Nov 20 '19 at 09:18
  • Given that this question assumed a simple, off-the-shelf solution, I believe that "linux box on the same network" prerequesit (especially one where you have to trigger exec command) doesn't seem to fit here. – Artanis Apr 25 '20 at 11:27
  • @Artanis exec() is totally fine if you control the entire command. And of course this solution only works for people with an existing server, but it's better to share info rather than hide it because it might not work for one specific person. – Ryan Steffer Apr 25 '20 at 16:28
2

HTML (test.htm)

<body>
<a href="test.php?mymac=XX:XX:XX:XX:XX:XX">Click to WOL XX:XX:XX:XX:XX:XX</a>
</body>

PHP (test.php)

<?php
$mymac = $_REQUEST['mymac'];
wol("255.255.255.255", $mymac);
echo 'WOL sent to '.$mymac;

function wol($broadcast, $mac){
$mac_array = preg_split('#:#', $mac); //print_r($mac_array);
$hwaddr = '';
    foreach($mac_array AS $octet){
    $hwaddr .= chr(hexdec($octet));
    }
    //Magic Packet
    $packet = '';
    for ($i = 1; $i <= 6; $i++){
    $packet .= chr(255);
    }
    for ($i = 1; $i <= 16; $i++){
    $packet .= $hwaddr;
    }
    //set up socket
    $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
    if ($sock){
    $options = socket_set_option($sock, 1, 6, true);
        if ($options >=0){    
        $e = socket_sendto($sock, $packet, strlen($packet), 0, $broadcast, 7);
        socket_close($sock);
        }    
    }
}  //end function wol
?>

Since the split() function was removed from PHP 7.0.0, this script uses preg_split() to be compatible with current and previous PHP versions.

Replace XX:XX:XX:XX:XX:XX in the HTML with your target MAC to test the script.

goks
  • 1,057
  • 2
  • 17
  • 32
Ken H
  • 91
  • 7
  • I don't think that is a very good idea at all. I can imagine a company retiring some old application servers and leaving them racked, then forgetting about them. Along comes a spider and bam! I start brodcasting WOL for every popular server NIC overnight and you come in the next morning to find tons of IP conflicts and garbage database connections... Not to mention the security vulnerabilities introduced by a bunch of old, unpatched servers suddenly appearing back on the network. – Robert Talada May 23 '18 at 19:38
  • 1
    Yes, thats a good security tip. You would not want this on a public web page. This is the kind of tool you use on your home, private network, to power on your pc's from a simple, private web page. – Ken H May 24 '18 at 15:36
0

Building upon the previous answers. Had to set udp port to 9 and repeat the MAC a couple more times before it worked for me:

function wol($mac)
{
    $hwaddr = pack('H*', preg_replace('/[^0-9a-fA-F]/', '', $mac));

    // Create Magic Packet
    $packet = sprintf(
        '%s%s',
        str_repeat(chr(255), 6),
        str_repeat($hwaddr, 20)
    );

    $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);

    if ($sock !== false) {
        $options = socket_set_option($sock, SOL_SOCKET, SO_BROADCAST, true);

        if ($options !== false) {
            socket_sendto($sock, $packet, strlen($packet), 0, "255.255.255.255", 9);
            socket_close($sock);
        }
    }
}
Allanrbo
  • 2,037
  • 1
  • 22
  • 26
  • May as well then make the port/repeats optional. However; I've had no luck getting any of these examples to work. For some reason when using "homebrew's" 'wakeonlan', I would see the packet appear in packetsender (set to receive UDP on port 9), but not when using the above script. I'm guessing it may be due to PHP running in docker though. – Paul Apr 07 '21 at 14:10
-1

Please read if you're running PHP in Docker, otherwise disregard this.

It seems that UDP broadcast from docker isn't being routed properly (possibly only broadcasted in the container itself, not on the host).

You may try setting (CLI) --network host or (compose) network_mode: host, but for PHP this was causing issues.

You can't send UDP WoL messages directly, as the device you're trying to control is 'offline' it doesn't show up in your router's ARP table and thus the direct message can't be delivered.

I ended up running @reboot root /usr/bin/php -S 0.0.0.0:8877 -t /home/user/php and putting the wol.php file there.

As a 'more proper' solution you may run an 'wol proxy' docker container that does exactly that (but then in a network host privileged docker container).

Paul
  • 503
  • 1
  • 4
  • 22