Word Pressに「Wake On LAN」機能を埋め込み

前ページ                               デモ画面

ーーーーーーー2ページーーーーーーー

ファイル保存・アクセス制限

ファイルは全てWord Pressのフォルダーに保存。 
以下は「\wordpress\wp-content\wol」に保存した例
wp-contentフォルダー及びwolフォルダーにはアクセス制限をしておく。

wp-contentフォルダーに配置の「.htaccess」

指定のファイル拡張子のファイルは指定の経由アクセス元(自サイト)「リファラー(Referrer)」のみアクセス許可する。
アクセス制限はwp-contentフォルダー以下に適用

Apache 2.2以前 (Apache 2.4以降でも可)

<Files ~ "\.(gif|png|jpg|jpeg|php|html)$">
  SetEnvIf Referer "https://domaim\.com/" allow_ref
  order deny,allow
  deny from all
  allow from env=allow_ref
</Files>

Apache 2.4以降
  2.4は基本アクセス禁止なので許可のみ定義

<Files ~ "\.(gif|png|jpg|jpeg|php|html)$">
  SetEnvIf Referer "https://domaim\.com/" allow_ref
  Require env allow_ref
</Files>

設置フォルダー以下の全ファイルに適用の場合

SetEnvIf Referer "https://domaim\.com/" allow_ref
Require env allow_ref

wolフォルダーに配置の「.htaccess」

ベーシック認証用

# BASIC認証
 AuthType Basic
 AuthName "Please enter your ID and password"
 AuthUserFile d:/www/private_html/wol/.htpasswd
 AuthGroupFile /dev/null
 require valid-user

 

ソース説明

wol_monitor.js

メインの処理コードを記載しており,ヤマハのオリジナルからの変更点は下記のとおり
 1.ルーター起動からサーバーへ変更したことにより,データ保存場所もサーバーに変更
 2.ルーターコマンドをサーバーのコマンド処理に変更のためPHPでのコマンド処理追加
 3.PoE監視からWOL(起動)監視に変更により,WOLコマンド処理追加
 4.PHPでのソート機能追加(IPアドレス昇順)

// wol_monitor.js
var tlist;           // 監視対象一覧のテーブルのオブジェクト
var clist;           // Ping失敗数カウント用テーブルのオブジェクト
var logfd;           // ログ表示用フィールドのオブジェクト
var intobj;          // Ping定期実行用インターバルのオブジェクト

// 以下パラメーター定義
var authuser = "user";         // ベーシック認証 ユーザーid
var authpass = "pass";         // ベーシック認証 パスワード
var authstr = 'Basic ' + window.btoa(authuser + ':' + authpass);  // Authorizationヘッダー埋込認証用
var maxEntryNum = 16;               // 登録可能最大数
var pingWaitInterval = 1;          // Pingの待ち時間(s)
var pingExecInterval = 3000;       // Pingの一斉実行間隔(ms)
var pingErrorCount = 3;            // 何回Pingに失敗したらダウンと判断するか

function getResource(url, callback) {
    $.ajax({
        type: "get",
        url: url,
        contentType: "charset=shift_jis",
        cache: false,
         headers: {
          "Authorization": "Basic " + btoa(authuser + ":" + authpass)
         },
        success: function(data) {
            callback(data);
        }
    });
}

function cmdExecute(cmd, callback, arg1, arg2, arg3) {
    $.ajax({
        type: "post",
        url: "execute.php",
        cache: false,
        dataType : 'json',
        data: {post_cmd:cmd},
         headers: {
          "Authorization": "Basic " + btoa(authuser + ":" + authpass)
         },
        success: function(result){
        var data = result;
            if (callback != undefined)
                callback(data, arg1, arg2, arg3);
        }
    });
}

//
// 引数がIPアドレスとして正しいものか調べる
//
function isValidIPaddress(target, on) {
    var i;
    var confirm = document.getElementById('confirm');
    var factor;

    if (target.indexOf(".0") != -1) {
        if (on)
            confirm.innerHTML = "<font color=\"red\">入力値に誤りがあります</font>";
        return 1;
    }
    factor = target.split('.');
    if (factor.length != 4) {
        if (on)
            confirm.innerHTML = "<font color=\"red\">入力値に誤りがあります</font>";
        return 1;
    }
    for (i = 0; i < 4; i++) {
        if (factor[i].match(/[^0-9]+/)) {
            if (on)
                confirm.innerHTML = "<font color=\"red\">入力値に誤りがあります</font>";
            return 1;
        }
    }
    for (i = 0; i < target.length; i++) {
        if (encodeURI(target.charAt(i)).length >= 4) {
            if (on)
                confirm.innerHTML = "<font color=\"red\">入力値に誤りがあります</font>";
            return 1;
        }
    }
    for (i = 0; i < 4; i++) {
        var num = Number(factor[i]);
        if (num == NaN || factor[i] < 0 || factor[i] > 255) {
            if (on)
                confirm.innerHTML = "<font color=\"red\">入力値に誤りがあります</font>";
            return 1;
        } 
    }

    confirm.innerHTML = " ";
    return 0;
}

//
// 入力されたIPアドレスからMACアドレスを調べる
//
function getMacAddress() {
    var cmd = "arp -a";
    cmdExecute(cmd, showMacAddress);
}

$(document).ready(function() {

    tlist = document.getElementById('target_list');
    clist = document.getElementById('target_list_cnt');
    logfd = document.getElementById('log');

    // コマンドの実行で管理者へ
   updateStatusMain();

    // データベースを開く
    getResource("database.txt", function(data) {
        var i, j, str, rows, line, num, cnt, rec;
        if (data != undefined) {
            str = data.split("\n");
            // 端末の登録
            for (i = 0; i < str.length; i++) {
                line = str[i].split(",");
                if (line.length != 4)
                    continue;
                rows = tlist.insertRow(-1);
                rows.style.height = "40";
                num = tlist.rows.length;
                for (j = 0; j < 8; j++) {
                    rows.insertCell(-1);
                }
                rows.cells[0].innerHTML = String(i + 1);
                rows.cells[1].innerHTML = line[0];
                rows.cells[2].innerHTML = line[1];
                rows.cells[3].innerHTML = "";
                rows.cells[4].innerHTML = line[2];
                rows.cells[5].innerHTML = "確認中";
                if (line[3].indexOf("auto") != -1) {
                    rows.cells[6].innerHTML = "自動起動";
                } else {
                    rows.cells[6].innerHTML = "手動起動  <input type=\"button\" value=\"実行\" onclick=\"offPortUse(\'" + line[0] + "\', 1);\">";
                }
                rows.cells[7].innerHTML = "<input type=\"button\" value=\"削除\" onclick=\"deleteTarget(\'" + line[0] + "\');\">";
                rows.style.textAlign = "center";

                // 端末毎のPing欠落回数の設定
                rows = clist.insertRow(-1);
                num = clist.rows.length;
                cnt = "cnt_" + line[0];
                rec = "rec_" + line[0];
                rows.insertCell(-1);
                rows.insertCell(-1);
                rows.cells[0].innerHTML = "<input type=\"hidden\" id=\"" + cnt + "\">";
                rows.cells[1].innerHTML = "<input type=\"hidden\" id=\"" + rec + "\">";
                document.getElementById(cnt).value = 0;
                document.getElementById(rec).value = 0;
            }
            // MACアドレスと経路情報の取得と表示
            setTimeout(getMacAddress, 1000);
        }
        updateStatus();
    })

    // ログファイルを開く
    getResource("logfile.txt", function(data) {
        if (data != undefined) {
            var log = document.getElementById('log');
            str = data.split("\r\n");
            for (i = 0; i < str.length; i++) {
                if (i == 0) {
                    log.innerHTML = str[i];
                } else {
                    log.innerHTML = log.innerHTML + "<br>" + str[i];
                }
            }
        }
    })
});

function updateStatusMain() {
    updateStatus();
    setInterval(updateStatus, pingExecInterval);
}

//
// Pingによる疎通確認を行う
//
function updateStatus() {
    // 対象が無ければ何もしない
    if (tlist.rows.length > 1) {
        var i;
        for (i = 1; i < tlist.rows.length; i++){
            updateStatusEach(i)
        }
        intobj = setTimeout(function() {checkPing();}, 2000);
    }
}

//
// テーブルのNoを指定してPingによる疎通確認を行う
//
function updateStatusEach(id) {
    var target;
    var cmd = "nwolc -p ";

    if (tlist.rows.length == id)
        return;

    target = tlist.rows[id].cells[1].innerHTML;
    if (isValidIPaddress(target, 0))
        return;
    cmd = cmd + target + " -t " + pingWaitInterval;
    cmdExecute(cmd, checkLuaStatus);

}

//
// Pingの結果を確認するため、show status luaを実行する DUMMY
//
function checkPing() {
//
}

//
// Pingの結果を表示に反映させる
// ダウン時の自動起動を実行する
//
function checkLuaStatus(data) {
    var i, j, id;
    var str = String(data[0]).split(' ');
    var str1 = data;
    var str2;
    var target;
    var cel2,cel3, cel5, cel6;
    var cnt, rect, cnt_ele, rec_ele, cnt_num, rec_num;

    for (i = 1; i < tlist.rows.length; i++) {
        target = tlist.rows[i].cells[1].innerHTML;
        cel2 = tlist.rows[i].cells[2];
        cel3 = tlist.rows[i].cells[3];
        cel5 = tlist.rows[i].cells[5];
        cel6 = tlist.rows[i].cells[6];
        cnt = "cnt_" + target;
        rec = "rec_" + target;
        cnt_ele = document.getElementById(cnt);
        rec_ele = document.getElementById(rec);
        cnt_num = Number(cnt_ele.value);
        rec_num = Number(rec_ele.value);

            if (str[0] == target) {
                if (str1[1] == 0) {
                    if (cel5.innerHTML == "OFF" || cel5.innerHTML.indexOf("確認中") != -1 || cel5.innerHTML.indexOf("WOL起動中") != -1 ) {
                        makeStateLog(target, 1);
                    }
                    cel3.innerHTML = cnt_num;
                    cel5.innerHTML = "ON";
                    cel5.style.backgroundColor = "#7bdf2e";
                    cnt_ele.value = 0;
                    rec_ele.value = 0;
                    // MACアドレスの更新
                    if (cel2.innerHTML == "") {
                        getMacAddress();
                    }
                } else {
                    if (cnt_num < pingErrorCount) {
                        cnt_num += 1;
                    }
                    cnt_ele.value = cnt_num;
                    if (rec_num > 0) {
                        break;
                    }
                    if (cnt_num >= pingErrorCount) {
                      if (cel5.innerHTML.indexOf("WOL起動中") == -1) {
                        if (cel5.innerHTML == "ON" || cel5.innerHTML.indexOf("確認中") != -1) {
                            makeStateLog(target, 0);
                        }
                        cel3.innerHTML = cnt_num;
                        cel5.innerHTML = "OFF";
                        cel5.style.backgroundColor = "#F83131";
                        if (cel6.innerHTML == "自動起動") {
                            // 自動起動
                            offPortUse(target, 0);
                        }
                      }
                    }
                }
                break;
            }
    }
}

//
// マジックバケットを送信する
//
function offPortUse(target, manual) {
    var i;
    var rec = "rec_" + target;
    var rec_ele = document.getElementById(rec);
    var macaddr;

    for (i = 1; i < tlist.rows.length; i++) {
        if (tlist.rows[i].cells[1].innerHTML == target) {
            macaddr = tlist.rows[i].cells[2].innerHTML;
            break;
        }
    }

    if (macaddr == "") {
        return;
    }
    var mac = macaddr.replace(/:/g, '' );
    cmd0 = "nwolc -m " + mac;
    cmdExecute(cmd0);

    rec_ele.value = 1;
    tlist.rows[i].cells[5].innerHTML = "WOL起動中";
    tlist.rows[i].cells[5].style.backgroundColor = "#FF9900";
    makePoeLog(manual, target, 0);

    // Pingの監視をリスタート
    clearTimeout(intobj);
    setTimeout(updateStatus, 3000);
}

//
// 給電設定変更のログを作る
//
function makePoeLog(manual, target, on) {
    var dateinfo = new Date();
    var year = dateinfo.getFullYear();
    var month = dateinfo.getMonth() + 1;
    var day = dateinfo.getDate();
    var hour = dateinfo.getHours();
    var minute = dateinfo.getMinutes();
    var second = dateinfo.getSeconds();
    var time;
    var method = (manual == 1) ? "[手動起動]" : "[自動起動]";
    var proc = (on == 1) ? "の給電を再開しました" : "へマジックパケットを送信しました";
    var str;

    month = doubleNumber(month);
    day = doubleNumber(day);
    hour = doubleNumber(hour);
    minute = doubleNumber(minute);
    second = doubleNumber(second);
    time = year + "/" + month + "/" + day + " " + hour + ":" + minute + ":" + second;
    str = time + " " + method + target + proc;
    logfd.innerHTML = str + "<br>" + logfd.innerHTML;
    LogSave(str);
}

//
// 監視状態変更のログを作る
//
function makeStateLog(target, on) {
    var dateinfo = new Date();
    var year = dateinfo.getFullYear();
    var month = dateinfo.getMonth() + 1;
    var day = dateinfo.getDate();
    var hour = dateinfo.getHours();
    var minute = dateinfo.getMinutes();
    var second = dateinfo.getSeconds();
    var time;
    var proc = (on == 1) ? "の状態が [<b><font color=\"green\">ON</font></b>] になりました" : "の状態が [<b><font color=\"red\">OFF</font></b>] になりました";
    var str;

    month = doubleNumber(month);
    day = doubleNumber(day);
    hour = doubleNumber(hour);
    minute = doubleNumber(minute);
    second = doubleNumber(second);
    time = year + "/" + month + "/" + day + " " + hour + ":" + minute + ":" + second;
    str = time + " " + target + proc;
    logfd.innerHTML = str + "<br>" + logfd.innerHTML;
    LogSave(str);
}

//
// 1桁の数字を2桁にする(1->01)
//
function doubleNumber(num) {
    num += "";
    if (num.length === 1) {
        num = "0" + num;
    }
    return num;
}

//
// 端末の登録を行う
//
function registDevice1() {
    var i, num, ret;
    var target = document.forms.id_target_form.elements.target.value;
    var comment = document.forms.id_target_form.elements.comment.value;
    var confirm = document.getElementById('confirm');
    var cmd;

    // IPアドレス入力チェック
    if (isValidIPaddress(target, 1))
        return;

    // コメント入力チェック
    if (comment.indexOf(',') != -1) {
        confirm.innerHTML = "<font color=\"red\">コメントに , は使用できません</font>";
        return;
    }

    // 設定数上限の確認
    if (tlist.rows.length == maxEntryNum + 1) {
        confirm.innerHTML = "<font color=\"red\">これ以上登録できません</font>";
        return;
    }

    // 管理者への昇格およびARPテーブルの更新
    cmd = "nwolc -p " + target;
    cmdExecute(cmd);
    setTimeout(registDevice2, 1000);
}

function registDevice2() {
    var i, num;
    var ret = 0;
    var target = document.forms.id_target_form.elements.target.value;
    var comment = document.forms.id_target_form.elements.comment.value;
    var recover = document.forms.id_target_form.id_recover1.checked;
    var rows, cnt, rec, cmd;

    // 登録情報の上書き
    for (i = 1; i < tlist.rows.length; i++) {
        rows = tlist.rows[i];
        if (rows.cells[1].innerHTML == target) {
            rows.cells[4].innerHTML = comment;
            rows.cells[5].innerHTML = "確認中";
            if (recover == true)
                rows.cells[6].innerHTML = "自動起動";
            else
                rows.cells[6].innerHTML = "手動起動  <input type=\"button\" value=\"実行\" onclick=\"offPortUse(\'" + target + "\', 1);\">";
            return;
        }
    }

    // 端末の登録
    rows = tlist.insertRow(-1);
    rows.style.height = "40";
    num = tlist.rows.length;
    for (i = 0; i < 8; i++) {
        rows.insertCell(-1);
    }
    rows.cells[0].innerHTML = String(num - 1);
    rows.cells[1].innerHTML = target;
    rows.cells[2].innerHTML = "";
    rows.cells[3].innerHTML = "";
    rows.cells[4].innerHTML = comment;
    rows.cells[5].innerHTML = "確認中";
    if (recover == true)
        rows.cells[6].innerHTML = "自動起動";
    else
        rows.cells[6].innerHTML = "手動起動  <input type=\"button\" value=\"実行\" onclick=\"offPortUse(\'" + target + "\', 1);\">";
    rows.cells[7].innerHTML = "<input type=\"button\" value=\"削除\" onclick=\"deleteTarget(\'" + target + "\');\">";
    rows.style.textAlign = "center";


    // 端末毎のPing欠落回数の設定
    rows = clist.insertRow(-1);
    num = clist.rows.length;
    cnt = "cnt_" + target;
    rec = "rec_" + target;
    rows.insertCell(-1);
    rows.insertCell(-1);
    rows.cells[0].innerHTML = "<input type=\"hidden\" id=\"" + cnt + "\">";
    rows.cells[1].innerHTML = "<input type=\"hidden\" id=\"" + rec + "\">";
    document.getElementById(cnt).value = 0;
    document.getElementById(rec).value = 0;

    // MACアドレスと経路情報の取得と表示
    setTimeout(getMacAddress, 1000);

    return;
}

//
// 導出したMACアドレスを表示する
//
function showMacAddress(data) {
    var i, j;
    var str1 = JSON.stringify(data).split(',');
    var str2;
    var target_ip;
    var macaddr;

    for (i = 1; i < tlist.rows.length; i++) {
        target_ip = tlist.rows[i].cells[1].innerHTML;
        for (j = 0; j < str1.length; j++) {
            str1[j] = str1[j].replace(/{"|"}/g, '');
            str1[j] = str1[j].replace(/":"/g, ' ');
            str2 = str1[j].replace(/"/g, '');
            str2 = str2.split(' ');
            if (str2[0] == target_ip) {          // ip
                macaddr = str2[1].replace( /-/g , ':' );
                tlist.rows[i].cells[2].innerHTML = macaddr;
            }
        }
    }
}

//
// 現状の監視対象のリストを保存する
//
async function saveTargetList() {
   var i, str;
var rows, line = "";
   await DataClear();
   for (i = 1; i < tlist.rows.length; i++) {
//  async内のawaitから呼び出した関数(_sleep)からPromiseが返されるまで待機
       await _sleep(300);
       rows = tlist.rows[i];
       if (isValidIPaddress(rows.cells[1].innerHTML, 0))
           continue;
       rows.cells[0].style.backgroundColor = "#F83131";
       line = rows.cells[1].innerHTML + "," + rows.cells[2].innerHTML + "," + rows.cells[4].innerHTML + ",";
       str = rows.cells[6].innerHTML.split(" ");
       if (str[0] == "自動起動")
           line = line + "auto ";
       else
           line = line + "manual ";
       await DataSave(line);
       await _sleep(300);
       rows.cells[0].style.backgroundColor = "#7bdf2e";
   }
}

//
// sleep処理
//
function _sleep(ms) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve();
    }, ms);
  });
}

//
// データベースを保存する
//
function DataSave(data) {
dataurl = "database.php"

  $(function(){
    //ajax送信
    $.ajax({
        url : dataurl,
        type : "POST",
        dataType : 'json',
        data : {post_data:data},
        headers: {
         "Authorization": "Basic " + btoa(authuser + ":" + authpass)
        },
        xhrFields: {
          withCredentials: true
        }
    });
  });
}

//
// 現状の監視対象のリストをIPアドレスで並び替えする
//
function datasort() {
dataurl = "datasort.php"

  $(function(){
    //ajax送信
    $.ajax({
        url : dataurl,
        type : "POST",
        dataType : 'json',
        headers: {
         "Authorization": "Basic " + btoa(authuser + ":" + authpass)
        }
    }).always(
        function() {
           location.reload(true);
        }
      );
  });
}

//
// データベースを消去する
//
function DataClear() {
  datacurl = "dataclear.php"
  var xhr = new XMLHttpRequest();
  xhr.open('POST', datacurl);
  xhr.setRequestHeader("Authorization" , authstr);
  xhr.withCredentials = true;
  xhr.send();
}

//
// 監視対象一覧から1行削除する
//
function deleteTarget(target) {
    var i, rows;

    // tlistから削除
    for (i = 1; i < tlist.rows.length; i++) {
        if (tlist.rows[i].cells[1].innerHTML == target) {
            tlist.deleteRow(i);
            break;
        }
    }
    for (i = 1; i < tlist.rows.length; i++) {
        tlist.rows[i].cells[0].innerHTML = i;
    }

    // clistから削除
    for (i = 0; i < clist.rows.length; i++) {
        if (clist.rows[i].cells[0].innerHTML.indexOf("id=\"cnt_" + target + "\"") != -1) {
            clist.deleteRow(i);
            break;
        }
    }
}

//
// ログファイルを保存する
//
function LogSave(log) {
logurl = "logfile.php"

  $(function(){
    //ajax送信
    $.ajax({
        url : logurl,
        type : 'POST',
        dataType : 'json',
        data : {post_log:log},
        headers: {
         'Authorization': 'Basic ' + btoa(authuser + ':' + authpass)
        },
        xhrFields: {
          withCredentials: true
        }
    });
  });
}

//
//
// ログファイルを消去する
//
function LogClear() {
  logcurl = "logclear.php"
  var xhr = new XMLHttpRequest();
  xhr.open('POST', logcurl);
  xhr.setRequestHeader("Authorization" , authstr);
  xhr.withCredentials = true;
  xhr.send();
}

//
// ログファイルの削除とログフィールドのクリア
//
function clearLog() {
    logfd.innerHTML = "";
    LogClear();
}

wol.html

1.並び替えボタン追加
  ボタン押下でサーバー保存のデータを並び替えして再読み込みする。表示データは上書きされるので,並び替え前にデータ保存する。
  連続ボタン操作でサーバーIO処理能力によってはデータ抜けの可能性あり。  
2.接続ポート欄をPINGエラー回数に変更

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- wol.html -->
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=shift_jis">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
    <script type="text/javascript" src="wol_monitor.js"></script>
    <link href="custom.css" rel="stylesheet" type="text/css"/>
<title>ネットワーク機器監視システム</title>
</head>

<body>

<!--監視対象の登録-->
<div id="register_field">
<img class="register_title_icon" src="register_icon.png" alt=""><h1 class="register_title">監視対象の登録</h1>
<form name="target_form" id="id_target_form" action="">
    <table border="1">
        <tbody>
            <tr>
                <td class="td">監視対象IPアドレス</td>
                <td><input type="text" name="target" id="id_target" maxlength="15"></td>
            </tr>
            <tr>
            <td class="td">機器名・コメント</td>
               <td><input type="text" name="comment" id="id_comment" maxlength="30"></td>
            </tr>
                <tr>
                <td class="td">WOL起動方法</td>
                <td><input type="radio" name="recover" id="id_recover1" value="auto">自動起動<br>
                   <input type="radio" name="recover" id="id_recover2" value="manual" checked="">手動起動</td>
           </tr>
      </tbody>
   </table>
   <div id="confirm"> </div>
   <div align="right"><input type="button" class="normal_button" value="登  録" onclick="registDevice1();"></div>
</form>
</div>

<hr>


<!--起動状況ログ-->
<div id="log_field">
    <img class="log_title_icon" src="log.png" alt=""><h1 class="log_title">起動状況ログ</h1>
    <div id="log" class="log"></div>
    <div> </div>
    <div align="right"><input type="button" class="normal_button" value="ログのクリア" onclick="clearLog();"></div>
</div>

<hr>

<!--監視対象一覧-->
<div id="list_field">
<div id="list_field_title">
    <img class="list_title_icon" src="camera.png" alt=""><h1 class="list_title">監視対象一覧</h1>
</div>
<div class="target_poe" id="target_poe"></div>
<table align="right">
<tr align="right" style="padding-bottom: 10px; margin-top: -20px;">
   <td> <input type="button" class="blink_button" value="監視対象情報を保存" onclick="saveTargetList();"/>
   <td> <input type="button" class="blink_button" value="並び替え" onclick="datasort();"/>
</tr>
</table>
<table border="1" id="target_list" width="100%"><tbody>
    <tr class="tr">
        <th width="6">№</th>
        <th width="130">IPアドレス</th>
        <th width="130">MACアドレス</th>
        <th width="8">ERR</th>
        <th>機器名・<br>コメント</th>
        <th width="100">状態</th>
        <th width="200">起動方法</th>
        <th width="100">削除</th>
   </tr>
</tbody></table>

<table border="0" id="target_list_cnt"><tbody>
</tbody></table>
</div>

</body>
</html>

custom.css

1.並び替えボタン追加に伴う若干の変更
2.ログ表示欄を移動

@charset "utf-8";
/* CSS Document   custom.css */

body{
	font-family:"Hiragino Kaku Gothic Pro",Meiryo, "MS PGothic", sans-serif
}

td{
	padding:5 15 5 15;
	border-color:#9e9e9e;
}

.td{
	background-color: #90caf9;
	min-width: 150px;
}

.td2{
	width: 50px;
}

.tr{
	background-color: #90caf9;
	height: 40px;
}

th{
	border-color: #9e9e9e;
}

table{
	max-width:100%;
	font-size:12px;
	margin-bottom:0px;
	border-collapse:collapse;
	border:#9e9e9e;
}

.normal_button{
	display:inline-block;
	padding: 9px 10px;
	font-size: 16px;
	//border: 1px solid #90caf9;
	border: solid 2px;
	border-color: #2196f3;
	color: #000;
	background-color: #ffffff;
	box-shadow: 4px 4px #9e9d9d;
	border-radius: 5px;
	-webkit-border-radius: 5px;
	-moz-border-radius: 5px;
	margin: 0 5px;
	min-width: 130px;
	text-align: center;
}

.normal_button:hover {
	background: #c4e5f7;
}

.normal_button:active {
	background: #2196f3;
}

.blink_button {
	display:inline-block;
	padding: 9px 10px;
	font-size: 16px;
	//border: 1px solid #90caf9;
	border: solid 2px;
	border-color: #2196f3;
	color: #000;
	background-color: #ffffff;
	box-shadow: 4px 4px #9e9d9d;
	border-radius: 5px;
	-webkit-border-radius: 5px;
	-moz-border-radius: 5px;
	margin: 0 5px;
	min-width: 130px;
	text-align: center;
}

.blink_button:hover {
	background: #c4e5f7;
}

.blink_button:active {
	background: #2196f3;
}

div.body{
	margin-top:0px;
	margin-left:0px;
}

div.log{
	overflow: scroll;
	width: auto;
	height: 150px;
}

div.target_poe{
	display:inline;
	margin-left: 0px;
}

div.h3{
	border: solid 2px #ffe082;
	width: auto;
	height: 130px;
	margin: 20px 30px;
	padding: 0px;
}

h1{
	margin-bottom: 0px;
	display:inline;
}

h3{
	padding:10 20 10 20;
	margin: 10px;
	background-color: #ffe082;
	position: relative;
}

.register_title{
	position: relative;
	left: 30px;
}

.register_title_icon{
	position: relative;
	left: 15px;
}

.log_title{
	position: relative;
	left: 30px;
}

.log_title_icon{
	position: relative;
	left: 15px;
}

.list_title{
	position: relative;
	left: 30px;
}
.list_title_icon{
	position: relative;
	left: 15px;
}

#register_field {
        margin-left: 50px;
        padding-right: 100px;
}

#log_field {
        width: auto;
        margin-left: 0px;
        margin-bottom: 15px;
}

#list_field {
        width: auto;
        margin-left: 0px;
        margin-bottom: 15px;
}

database.php

1.監視対象データを受け取って保存処理する。
2.1レコード毎に受け取って連続追加保存するので,サーバー負荷等の状況によりレコード抜けが発生するのでスリープを入れて保存遅延させている。
3.以下の4ファイルは,(ヤマハルーターのPoE監視デモ改造時)のものをそのまま使用

<?php
  /* database.php */
  usleep(1000);
  $fileName='database.txt';
  $data=$_POST['post_data'] . "\r\n";
  file_put_contents($fileName, $data, LOCK_EX | FILE_APPEND);
?>

dataclear.php

<?php
  /* dataclear.php */
  $fileName='database.txt';
  file_put_contents($fileName,"");
?>

logfile.php

<?php
  /* logfile.php */
  usleep(2000);
  $fileName='logfile.txt';
  $logdata=$_POST['post_log'] . "\r\n" . file_get_contents($fileName);
  file_put_contents($fileName, $logdata, LOCK_EX); 
?>

logclear.php

<?php
  /* logclear.php */
  $fileName='logfile.txt';
  file_put_contents($fileName,"");
?>

execute.php

1.サーバーコマンド実行用
2.’arp -a’コマンドは結果取得後,データ処理して戻り値として返す。
3.その他コマンドはnWOLc.exe(nwolc-p,nwolc -m)を処理する。
4.Windowsコマンドの’arp -a’を入力するので,パスを通す(Path:C:\Windows\System32)
5.「nWOLc.exe」はこのファイルと同じフォルダーに保存する。
5.「nWOLc.exe」はphpのルートフォルダーに保存する。( 例:D:\Program Files\php)

<?php
  /* execute.php */
$cmd = $_POST['post_cmd'];
$table = array();
$result;

exec($cmd, $opt , $return_ver);

if ($cmd == 'arp -a'){
  foreach ($opt as $line) {
      if (preg_match('/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}).*([0-9a-f]{2}[\-:][0-9a-f]{2}[\-:][0-9a-f]{2}[\-:][0-9a-f]{2}[\-:][0-9a-f]{2}[\-:][0-9a-f]{2})/i', $line, $matches)) {
          $ip = $matches[1];
          $mac = strtoupper(str_replace(array('-', '.'), ':', $matches[2]));
          $table[$ip] = $mac;
      }
  }
/* arp -aの実行結果を配列で返す */
  $result = $table;

}else {
/*  実行結果と戻り値を配列で返す */
  $result=array(
 	  0 => $opt,
 	  1 => $return_ver
 	);
};
echo json_encode( $result ) ;
return;
?>

datasort.php

1.ソート機能をwindowsのsortコマンドで処理している。
2.IPアドレスのセパレーターを削除したものをキーとして追加し,ソート用ファイルに保存・ソート後,追加したキーを削除してデータベースに保存し直している。
3.Windowsのsortコマンド前後にタイミング遅延のためスリープを入れている。

<?php
  /* datasort.php */
//  $sleeptime = '20000';  // マイクロ秒 1,000,000=1秒
  $fileName='database.txt';
  $sortfile='sortfile.txt';
  $spos = array();
  $epos = array();
  $ipadr = array();

/* ソートファイルクリア */
 file_put_contents($sortfile, "");

/* データファイルから呼び出してソートキー(先頭12桁)を追加してソートファイルに保存 */
/* ファイルポインタをオープンしファイルを1行ずつ出力 */
$file = fopen($fileName, "r");
if($file){
  while ($data = fgets($file)) {
    $data = mb_convert_encoding($data,"SJIS-win","utf-8");  // UTF-8からシフトJISに変換

/* ipアドレス取り出し */
    $wdata = $data;
    $posip = strpos($wdata, ',');
    $ipaddr = substr($wdata, 0, $posip);
    $ipadr[1] = $ipaddr;
    $spos[1] = 0;

/* セパレーター単位で個別取り出し */
    for ($i = 1; $i <= 4; $i++) {
      $wdata = $data;
      $bi = $i - 1;
      $ai = $i + 1;
      if ($i < 4){
         $epos[$i] = strpos($ipadr[$i], '.');
      }else{
         $epos[$i] = strpos($ipadr[$i], ',');
      };
      if ($epos[$i] == false){
          $epos[$i] = 3;
      };
      if ($i > 1){
      $spos[$i] = $epos[$bi] + 1;
      };
      $ipadr[$i] = substr($wdata, $spos[$i], $epos[$i]);
      $wdata = $data;
      $epos[$i] = $spos[$i] + $epos[$i];
      $ipadr[$ai] = substr($wdata, $epos[$i] + 1, 3);
    }
/* 3桁で0埋め ゼロパディング*/
    $ipaddr01 = str_pad($ipadr[1], 3, 0, STR_PAD_LEFT);
    $ipaddr02 = str_pad($ipadr[2], 3, 0, STR_PAD_LEFT);
    $ipaddr03 = str_pad($ipadr[3], 3, 0, STR_PAD_LEFT);
    $ipaddr04 = str_pad($ipadr[4], 3, 0, STR_PAD_LEFT);
/* データ結合 ソートキーを先頭12桁に追加   123.456.7.8 >>> 123456007008 */
    $ipaddr0 = $ipaddr01 . $ipaddr02 . $ipaddr03 . $ipaddr04;
    $sortdata = $ipaddr0 . $data;

/* ソートファイルに保存 */
    file_put_contents($sortfile, $sortdata, LOCK_EX | FILE_APPEND);
  }
}

usleep(2000);
/* ソート */
$cmd = "SORT " . $sortfile . " /O " . $sortfile;
exec($cmd);
usleep(10000);

/* データーファイルクリア */
  file_put_contents($fileName,"");

/* ソートファイルから1行ずつ呼び出してソートキー(先頭12桁)削除して保存 */
$file = fopen($sortfile, "r");
if($file){
  while ($sortline = fgets($file)) {
    $sortline = mb_convert_encoding($sortline,"utf-8","SJIS-win");  // シフトJISからUTF-8に変換
    file_put_contents($fileName,substr($sortline, 12), LOCK_EX | FILE_APPEND);
  }
}
?>

ダウンロードファイル一覧

ヤマハのホームページからダウンロードしたpoe_demo.zipを解凍
1 camera.png
custom.css      変更あり
3 database.txt    
4 deletelog.lua       不要
5 index.html         wol.htmlに名称変更
6 jquery-1.11.1.min.js    不要
7 kconv.lua         不要
8 kconv_utable.lua      不要
9 log.lua           不要

10 log.png
11 logo.png
12 logout.html         不要
13 logout.js          不要

14 monitor.js           wol_monitor.jsに名称変更
15 ping.lua           不要
16 register_icon.png
17 save.lua         不要
18 skeleton.png

流用(ヤマハルーターのPoE監視デモ改造時のものをそのまま使用)
database.php
dataclear.php
logfile.php
logclear.php

新規作成
execute.php  コマンド実行用
datasort.php ソート処理用

考察

元々完成されたコードがあったので,比較的簡単に作成できた。_(._.)_
外部からLAN内機器へPINGを送信できないので,WOL機能よりLAN内機器の稼働状況の確認用としての用途のほうが多いと思う。
ルーターへログオンが必要な従来システムでは外部からVPNを通してからでないと使用できないので,Word Pressに埋め込んでのほうが使い勝手がよい。ただしセキュリティ対策は必要。
javascriptのコードにベーシック認証用のユーザーidとパスワードを記載しており,ソースコードの閲覧で見られてしまうため,Word Pressに埋め込む際はページにパスワード設定するか,ベーシック認証が必要なページに埋め込む必要がある。wolフォルダーにベーシック認証を設定すれば,ページ表示時に認証要求されるので,認証が通らないと画面表示されない。

最終形2023/11/12

パソコンの起動・停止監視ツール – na-blog (na-3.com)



次ページ「デモ画面」