2019年2月11日 星期一

Node.js 執行 Linux 指令

使用 Node.js 建立網頁,網頁可透過 Node.js 執行 Linux 上的指令。
網頁的部分,使用 Express 網頁框架。使用 9000 PORT


建立 Node.js 專案,防火牆開放網頁預計使用的 9000 PORT
npm init
npm install express --save
#防火牆
firewall-cmd --state
firewall-cmd --list-all --zone=public
firewall-cmd --permanent --zone=public --add-port=9000/tcp
firewall-cmd --reload


Node.js 程式內容
let express = require('express');
let app = express();
let router = express.Router();
let exec = require('child_process').exec;
let port = 9000;
//app.use(express.static(__dirname + '/public'));
//app.use('/img', express.static(__dirname + '/public/img'));

let header = '<!DOCTYPE html><html><head><title>ctrl PHP</title>'
        + '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'
        + '<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">'
        + '</head><body><pre>';
let footer = "</pre></body></html>";

router.get('/', function (req, res, next) {
    //預設頁面
    console.log('index');
    res.sendfile('index.html', {root: __dirname + "/public"});
});
router.get('/ls', function (req, res, next) {
    //執行 ls -al 指令
    exec('ls -al', function (err, stdout, stderr) {
        console.log('ls');
        res.send(header + stdout + footer);
    });
});

app.use('/', router);
app.listen(port);



參考:
express nodejs execute ubuntu shell terminal command, ls, cat
Express.js 4.0 的路由(Router)功能用法教學 - G. T. Wang
node.js - simplest way to have Express serve a default page? - Stack Overflow
在 Express 中提供靜態檔案


2018年10月24日 星期三

找回 Nodepad++ 當掉崩潰不見的檔案內容

Nodepad++ 版本:7.5.7 (32bit)

情況:使用 Nodepad++ 編輯文字檔儲存時,突然當掉崩潰,重開 Nodepad++ 後,原來編輯的檔案內容全被清空不見。

解決方式:
查看「設定」->「使用者自訂」裡的「備份」,查看「檔案群組快照和定期備份」中的「備份路徑」位置。
到「備份路徑」位置,幸運的話,可找到「檔案名稱@時間」的備份檔案。
將檔名後面的「@時間」去掉,就是一般的文字檔。這可以找回之前某一時間點的備份內容,雖然還是會遺失後來編輯的內容,但至少可救回之前的內容。



另外自訂備份:
如果對上面的自動備份設定不放心,該設定下面還有一個「備份」的設定。
我測試的效果是,

「簡易備份」:每次儲存時將未編輯前的檔案,複製一份「原檔名」的檔案到「自訂備份資料夾」,該資料夾只會有一份該檔名的備份檔。

「詳細備份」:每次儲存時將未編輯前的檔案,複製一份「原檔名@時間」到「自訂備份資料夾」,該資料夾會有多份該檔名的不同時間點的備份檔。

最後我選用「詳細備份」,因為可避免檔案路徑不同,但檔名相同的檔案,備份檔案一定會互相覆蓋的情況。




參考:
Notepad ++ Crashed? Lost Notepad ++ Files? Restore Right Now! – EaseUS
file - Lost code lines when Notepad++ crashed - Stack Overflow


2018年9月6日 星期四

PHP strtotime 月份加減

PHP 的 strtotime 可以進行月份的加減。
但 PHP 進行時,會保留原來的「日」,再判斷是否需進行時間的偏移,所以可能導致最終的日期跟預想的不一樣。
例如:
$cur_date = "2016-03-31";
var_dump(date("Y-m-d", strtotime("-1 month", strtotime($cur_date))));//2016-03-02
var_dump(date("Y-m-d", strtotime("+1 month", strtotime($cur_date))));//2016-05-01
2016-03-31 減一個月變成 2016-02-31,但2016年2月只到29號,所以 2016-02-31 => 2016-03-02
2016-03-31 加一個月變成 2016-04-31,但4月只到30號,所以 2016-04-31 => 2016-05-01

這結果,可能跟預想的不太一樣。
但如果只是要取月份加減後的月初、月底,或只著重在結果的月分準確即可,
那可使用「first day of」(取月初)、「last day of」(取月底)來處理。
加減過程中,沒了原本的「日」,也就沒最後因為「日」而導致月份的偏移了。
$cur_date = "2016-03-31";
var_dump(date("Y-m-d", strtotime("first day of -1 month", strtotime($cur_date))));//2016-02-01
var_dump(date("Y-m-d", strtotime("last day of -1 month", strtotime($cur_date))));//2016-02-29
var_dump(date("Y-m-d", strtotime("first day of +1 month", strtotime($cur_date))));//2016-04-01
var_dump(date("Y-m-d", strtotime("last day of +1 month", strtotime($cur_date))));//2016-04-30


最後測試一下跨年是否有影響。
結果:跨年度的話,似乎「年」能先準確的計算出來。至於最後會不會自動偏移,一樣是看該「年-月」是否有該日期決定。
$cur_date = "2017-03-29";
var_dump(date("Y-m-d", strtotime("-13 month", strtotime($cur_date))));//2017-02-29

$cur_date = "2017-03-30";
var_dump(date("Y-m-d", strtotime("-13 month", strtotime($cur_date))));//2016-03-01
var_dump(date("Y-m-d", strtotime("first day of -13 month", strtotime($cur_date))));//2016-02-01
var_dump(date("Y-m-d", strtotime("last day of -13 month", strtotime($cur_date))));//2016-02-29


參考:
令人困惑的strtotime | 风雪之隅


2018年8月19日 星期日

JavaScript RegExp 的 lastIndex 屬性

JavaScript 正規表示式 RegExp 物件,當有使用「g」global match 參數時,
會有一個 lastIndex  屬性,記錄上一次批配到的字串,後面的位置(預設值為0)。

RegExp.lastIndex  屬性:
  1. RegExp.exec()、RegExp.test(),都是以 lastIndex 當作匹配比對起點
  2. 當匹配比對失敗,lastIndex 會重設為 0
  3. RegExp.lastIndex 值可手動設定

範例:
var str = 'abcde';
var RegExpObj = new RegExp('b', 'g');
RegExpObj.lastIndex; //0  預設值為 0

//第一次比對,比對成功,lastIndex 變為 2
RegExpObj.test(str); // true
RegExpObj.lastIndex; //2

//第二次比對,從字串位置 2 開始比對,比對失敗,lastIndex 自動重置為 0
RegExpObj.test(str); // false
RegExpObj.lastIndex; //0

//第三次比對,又從字串位置 0 開始比對,比對成功,lastIndex 變為 2
RegExpObj.test(str); // true
RegExpObj.lastIndex; //2

//手動將 lastIndex 設為 1,再次比對,可成功比對到字串位置 1 的 「b」
RegExpObj.lastIndex=1; 
RegExpObj.lastIndex; //1
RegExpObj.test(str); // true


參考:
JavaScript lastIndex 属性
regexp.lastIndex - JavaScript | MDN
regex - Bug with RegExp in JavaScript when do global search - Stack Overflow

PHP 判斷是否為搜尋引擎爬蟲訪問網頁

要判斷是否為搜尋引擎爬蟲訪問網頁,可以從 $_SERVER["HTTP_USER_AGENT"] 字串判斷。
一般有以下兩種判斷方法。
方法1:找出「搜尋引擎爬蟲」可能的 User-Agent,符合的即為「搜尋引擎爬蟲」。
方法2:找出「瀏覽器」可能的 User-Agent,不符合的即是「網路爬蟲」,這邊當做都是「搜尋引擎爬蟲」。當然,如果是要較精準的分辨出「搜尋引擎爬蟲」和其他網路爬蟲,還是要使用方法1。

一般情況,大都只是要分辨出所有網路爬蟲(搜尋引擎、其他爬蟲),所以這邊選用方法2,因為常用的瀏覽器 User-Agent,比較容易知道、也可自己測試取得,
而且一般使用者使用瀏覽器時,應該都會傳送正常的 User-Agent。
所以應該可以放心將不符合的當作是網路爬蟲(搜尋引擎爬蟲)。
檢查方法:
/**
 * 判斷是否為網路爬蟲
 * @return boolean
 */
function webCrawlerDetect() {
    $pattern = '/firefox|chrome|msie|opera|safari|edge|yabrowser|maxthon|konqueror|netscape|lynx|links/i';//瀏覽器
    return !(isset($_SERVER['HTTP_USER_AGENT']) && preg_match($pattern, $_SERVER['HTTP_USER_AGENT']));
}
其他:
可能會在瀏覽器的 User-Agent 發現其他瀏覽器的關鍵字,
例如 Chrome、Edge 的 User-Agent 可能發現 Mozilla、Safari。
這是因為有的網站會針對不同瀏覽器特有功能,做適當的回應。
所以當新的瀏覽器,也相容其他瀏覽器特有功能時,瀏覽器便用此方式,讓網站也能如期顯示。
參考 WebAIM: History of the browser user-agent string