參考:https://www.nodebeginner.org/index-zh-tw.html
1. 開啟PowerShell並安裝
npm install express <- 框架
npm install ws <- websocket
2. service.js
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8080 });
server.on('open', function open() {
console.log('connected');
});
server.on('close', function close() {
console.log('disconnected');
});
server.on('connection', function connection(ws, req) {
const ip = req.connection.remoteAddress;
const port = req.connection.remotePort;
const clientName = ip + port;
console.log('%s is connected', clientName)
ws.send("Welcome " + clientName);
ws.on('message', function incoming(message) {
console.log('received: %s from %s', message, clientName);
server.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send( clientName + " -> " + message);
}
});
});
});
3. client.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket Chat</title>
</head>
<body>
<script type="text/javascript">
var socket;
if (!window.WebSocket) {
window.WebSocket = window.MozWebSocket;
}
if (window.WebSocket) {
socket = new WebSocket("ws://localhost:8080/ws");
socket.onmessage = function (event) {
var ta = document.getElementById('responseText');
ta.value = ta.value + '\n' + event.data
};
socket.onopen = function (event) {
var ta = document.getElementById('responseText');
ta.value = "connection!";
};
socket.onclose = function (event) {
var ta = document.getElementById('responseText');
ta.value = ta.value + "connection close";
};
} else {
alert("你的浏览器不支持 WebSocket!");
}
function send(message) {
if (!window.WebSocket) {
return;
}
if (socket.readyState == WebSocket.OPEN) {
socket.send(message);
} else {
alert("connection fail.");
}
}
</script>
<form onsubmit="return false;">
<h3>WebSocket Chat room:</h3>
<textarea id="responseText" style="width: 500px; height: 300px;"></textarea>
<br>
<input type="text" name="message" style="width: 300px" value="Welcome">
<input type="button" value="Send" onclick="send(this.form.message.value)">
<input type="button" onclick="javascript:document.getElementById('responseText').value=''"
value="Clean">
</form>
<br>
</body>
</html>
4. 伺服器端啟動service.js
客戶端透過瀏覽器開啟client.html即可對話
sudo kill $(ps aux | grep 'app.js' | awk '{print $2}')
sudo node service.js &
2019年12月3日 星期二
2019年10月31日 星期四
DotNet Core API sample by GitHub
久不用就會忘記,透過Visual Studio 的WEBAPI範例來搭配GitHub配合看版當個小型的敏捷開發的範本。
1. 下載Git by windows
進入官網 http://git-scm.com/
進入官網 http://git-scm.com/
2. 建立看版做派工追蹤
3. 使用 Git Bash 建立專案
cd c:\git\
git init
git add -f --all
git commit
git push
DotNet:
1. 連結Git
2. 取得DotNet Core 3.0
使用Vistual Studio Install 的更新取得。
3. 建立API專案 Code Sample
4. 透過team Explorer 做 commit & push
2019年10月2日 星期三
試算表的日期轉文字
在試算表的儲存格常常會依照所貼入的文字去轉換格式,但使用公式來處理時日期就會變轉成無意義的數字,這部分可以使用TEXT函數來轉換。
=TEXT(儲存格, "yyyy/mm/dd HH:MM:ss")
很容易忘掉,所以做個MEMO。
=TEXT(儲存格, "yyyy/mm/dd HH:MM:ss")
很容易忘掉,所以做個MEMO。
2019年9月17日 星期二
AWS EFS+EC2(AutoScaling+LoadBalance) 備忘
如標題其實在AWS使用Elastic Beanstalk就含有這些,而且還有其他不可忽視的優點,不過作為一位All in One的工程師,這些優點反而就有些礙手礙腳,尤其是處在那些天馬行空的需求上,真能專注在Code內且功能單純的專案,難啊...其實這些應該給專業的MIS去處理而不是找工程師去代理!!
EFS可擴展的共用檔案儲存服務,建立服務要注意的地方是:
1. 可用區域,選擇EC2會使用的區網網段
2. 安全群組,選擇相關的安全群組(最好是EC2使用的),另外ALL TCP Port須開放相關"可用區域"的區網網段,以便NFS協定運行。
3. DNS名稱是拿來連線用的,不同的檔案系統AWS會配給不同的DNS名稱。
sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 DNS名稱:/ /掛載使用的資料夾
LoadBalance創建服務注意地方,唯一有卡關的在於ssl的CA憑證及PK密鑰的套用,這部分貼對位置就沒問題;另外可用區域的區網選擇也需搭配相關EC2使用的。
Auto Scaling根據設定自動對其進行擴展和縮減,建立服務要注意的地方是:
1. 創建使用的AMI檔,應已包含掛載EFS以便程式檔案更新時使用。當然AWS推薦的是CodeDeploy去處理;若干部落格推薦AMI手動更新,這些也是能考慮的...不在此篇討論。
※User Data記得加上...實測若沒有加上mount指令,則新的VM不會自動掛載~即便是原製作AMI的環境已掛載好的情況下。
#!/bin/bash
sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 DNS名稱:/ /掛載使用的資料夾
※User Data記得加上...實測若沒有加上mount指令,則新的VM不會自動掛載~即便是原製作AMI的環境已掛載好的情況下。
#!/bin/bash
sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 DNS名稱:/ /掛載使用的資料夾
2. 安全群組不要新建使用EFS相同的即可。
3. 增減條件與數量這部分依照實際需要去調整,目前使用的是CPU使用率超過60% 300秒就增加一台,最高增加到3台。
4. 另外要搭配LoadBalance分散風險,所以建立兩個AutoScaling Group關連到同一個LoadBalance。
後記: 就不截圖了AWS的文件還蠻多的且更新頻率高,有搭配相關超連結到時候需要再點選進去看即可。
2019年9月11日 星期三
網頁浮動式固定選單_CSS+JS
RWD風行,所以網站的前端要考慮的層面就多了很多,前端目前缺乏所以得自己來,浮動式固定選單挺常用到,備忘囉!!
CSS
<style>
.navFixed {
z-index: 10;
position: fixed;
top: 0;
left: 0;
margin-top: 0;
min-width: 100%;
opacity: 0.94;
transition: opacity .5s ease-out;
}
</style>
JS
<script type="text/javascript">
$(function() {
$(window).scroll(function() {
if ($(this).scrollTop() > 495) { /* 要滑動到選單的距離 */
$('.dropdowns').addClass('navFixed'); /* 幫選單加上固定效果 */
} else {
$('.dropdowns').removeClass('navFixed'); /* 移除選單固定效果 */
}
});
});
</script>
HTML
<div class="navFixed" ></div>
參考來源: https://edwardzou.blogspot.com/2017/09/fixMenu.html
CSS
<style>
.navFixed {
z-index: 10;
position: fixed;
top: 0;
left: 0;
margin-top: 0;
min-width: 100%;
opacity: 0.94;
transition: opacity .5s ease-out;
}
</style>
JS
<script type="text/javascript">
$(function() {
$(window).scroll(function() {
if ($(this).scrollTop() > 495) { /* 要滑動到選單的距離 */
$('.dropdowns').addClass('navFixed'); /* 幫選單加上固定效果 */
} else {
$('.dropdowns').removeClass('navFixed'); /* 移除選單固定效果 */
}
});
});
</script>
HTML
<div class="navFixed" ></div>
參考來源: https://edwardzou.blogspot.com/2017/09/fixMenu.html
透過gsutil進行 GCP Storage 至 AWS S3 操作
參考步驟:http://proanalyst.net/migrate-files-gcs-into-amazon-s3/
1. 建立一個VM並啟用SSH
2. 透過SSH連限制這個VM Instace
3. 寫入.boto
echo [Credentials] >> ~/.boto
echo aws_access_key_id = XXX >> ~/.boto
echo aws_secret_access_key = OOOOO >> ~/.boto
4. gsutil 指令
資料夾搬移
gsutil cp -r gs://BucketName/FolderName/ s3://BucketName/FolderName/
特定檔案類型搬移
gsutil cp *.jpg gs://BucketName/FolderName/ s3://BucketName/FolderName/
1. 建立一個VM並啟用SSH
2. 透過SSH連限制這個VM Instace
3. 寫入.boto
echo [Credentials] >> ~/.boto
echo aws_access_key_id = XXX >> ~/.boto
echo aws_secret_access_key = OOOOO >> ~/.boto
4. gsutil 指令
資料夾搬移
gsutil cp -r gs://BucketName/FolderName/ s3://BucketName/FolderName/
特定檔案類型搬移
gsutil cp *.jpg gs://BucketName/FolderName/ s3://BucketName/FolderName/
2019年8月23日 星期五
PHP import reCAPTCHA v3
早上得到反映Google reCAPTCHA循環出現輸入錯誤無法通過的消息,檢查中發現已經更新到 v3,他跟前代最大的差別就是不用再要求使用者與頁面互動,貌似會依照行為來計算分數判斷是否為機器人所為!!
套用步驟如下。
1. 申請KEY,進入此網站點選右上角進入Admin Console,依照步驟取得網站金鑰跟密鑰
2. 登入頁(HTML)
HEAD:
<script src="https://www.google.com/recaptcha/api.js?render=網站金錀"> </script>
<script>
grecaptcha.ready(function() {
grecaptcha.execute('網站金錀', {action: 'homepage'}).then(function(token) {
var recaptchaResponse = document.getElementById('recaptchaResponse');
recaptchaResponse.value = token;
});
});
</script>
FORM:
<input type="hidden" value="" name="recaptcha_response" id="recaptchaResponse">
3. 驗證頁(PHP)
if ( !$_POST ) exit;
$recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
$recaptcha_secret = '密鑰';
$recaptcha_response = $_POST['recaptcha_response'];
//Make and decode POST request:
$recaptcha = file_get_contents($recaptcha_url . '?secret=' . $recaptcha_secret . '&response=' . $recaptcha_response);
$recaptcha = json_decode($recaptcha);
if($recaptcha->success==true){
if($recaptcha->score >= 0.5) {
//PASS
} else {
//BOT
}
} else {
//FAIL
}
4. 檢查~套用v3的頁面右下角會出現Google reCAPTCHA圖示,若無則表示有缺漏得檢查。
套用步驟如下。
1. 申請KEY,進入此網站點選右上角進入Admin Console,依照步驟取得網站金鑰跟密鑰
2. 登入頁(HTML)
HEAD:
<script src="https://www.google.com/recaptcha/api.js?render=網站金錀"> </script>
<script>
grecaptcha.ready(function() {
grecaptcha.execute('網站金錀', {action: 'homepage'}).then(function(token) {
var recaptchaResponse = document.getElementById('recaptchaResponse');
recaptchaResponse.value = token;
});
});
</script>
FORM:
<input type="hidden" value="" name="recaptcha_response" id="recaptchaResponse">
3. 驗證頁(PHP)
if ( !$_POST ) exit;
$recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
$recaptcha_secret = '密鑰';
$recaptcha_response = $_POST['recaptcha_response'];
//Make and decode POST request:
$recaptcha = file_get_contents($recaptcha_url . '?secret=' . $recaptcha_secret . '&response=' . $recaptcha_response);
$recaptcha = json_decode($recaptcha);
if($recaptcha->success==true){
if($recaptcha->score >= 0.5) {
//PASS
} else {
//BOT
}
} else {
//FAIL
}
4. 檢查~套用v3的頁面右下角會出現Google reCAPTCHA圖示,若無則表示有缺漏得檢查。
2019年8月2日 星期五
大量Time_wait的改善紀錄
因為AP架構設計的緣故,做了個Agent處理在Listen伺服器上檢查是否有需要處理的作業,頻繁的連線>檢查>關閉的作業,在客戶端Agent多的狀況下在伺服器端就會發現有許多Time_wait紀錄,這樣會造成WEB服務上的效能變差。
編輯 vim /etc/sysctl.conf
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
然後執行 /sbin/sysctl -p 套用
編輯 vim /etc/sysctl.conf
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
然後執行 /sbin/sysctl -p 套用
- net.ipv4.tcp_syncookies = 1 表示開啟SYN Cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防範少量SYN攻擊,默認為0,表示關閉;
- net.ipv4.tcp_tw_reuse = 1 表示開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連接,默認為0,表示關閉;
- net.ipv4.tcp_tw_recycle = 1 表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉。
- net.ipv4.tcp_fin_timeout 修改系統默認的 TIMEOUT 時間
若是卡點在對資料庫的連線,那麼寫個shell script來kill process才能改善,單純結束連線解決不了問題。
define('MAX_SLEEP_TIME', 120);
$hostname = "xxx";
$username = "xxx";
$password = "xxx";
$err_level = error_reporting(0);
$connect = mysql_connect($hostname,$username,$password);
error_reporting($err_level);
$result = mysql_query("SHOW PROCESSLIST", $connect);
while ($proc = mysql_fetch_assoc($result)) {
if ($proc["Command"] == "Sleep" && $proc["Time"] > MAX_SLEEP_TIME) {
@mysql_query("KILL " . $proc["Id"], $connect);
}
}
mysql_close($connect);
2019年8月1日 星期四
aliyun push to android 8 up 備忘
相關資源:
https://github.com/aliyun/alicloud-ams-demo/tree/master/OpenApi2.0/push-openapi-php-demo
這陣子在處理阿里推送上在Android 8裝置會收不到的狀態卡了許久,使用PushNoticeToAndroidRequest.php來進行推送都很迅速地在Android 8以下裝置收到,若是透過阿里後台的推送則全裝置都能順利收到,這就不會是APP設計的問題。
這部分問題要爬文建議透過百度搜尋來查找,比Google來的更豐富且針對些,應該是阿里雲屬於內地的產品吧! 即便在那斯達克上市也不能免俗。
總之關鍵點在於...以下參考~
//XXX必須與APP設定的一致
$request_android->setAndroidNotificationChannel("XXX");
ExtParameters設定:
//這是透過 PushNoticeToAndroidRequest.php 使用的設定
$request->setAndroidExtParameters("{\"key1\":\"value1\",\"api_name\":\"PushNoticeToAndroidRequest\"}");
//這是透過 PushRequest.php 使用的設定
$request->setAndroidExtParameters("{\"k1\":\"android\",\"k2\":\"v2\"}");
//若設定成ALL則IOS相關設定需帶入
$request->setDeviceType("ANDROID");
//這設定貌似也要加~不過數字上沒甚麼感覺
$request->setAndroidNotificationBarType(1); //通知栏自定义样式0-100
$request->setAndroidNotificationBarPriority(1); //通知栏自定义样式0-100
小結: 許多阿里後台端的問題都需有內地帳號才能發問(這個在台灣手機認證上就掛了),所以即便是呼叫OPENAPI順利得到MessageID對於"沒收到"這檔是也是無濟於事,打轉許久只能透過Try & Error排除。
另外曾考慮透過Dot NET來呼叫OPENAPI,不過在帶入appkey那行總是編譯失敗,nullable long<n> 未定義,改用建議的DLL會造成更多的變數定義錯誤,這是就神奇了~~目前無解。
補充:使用PushNoticeToAndroidRequest設定NotificationChannel沒意義,追蹤相關的code看來沒支援/強制寫入固定值在回傳的陣列裡也是靜悄悄,所以用PushRequest.php來推送即可。
https://github.com/aliyun/alicloud-ams-demo/tree/master/OpenApi2.0/push-openapi-php-demo
這陣子在處理阿里推送上在Android 8裝置會收不到的狀態卡了許久,使用PushNoticeToAndroidRequest.php來進行推送都很迅速地在Android 8以下裝置收到,若是透過阿里後台的推送則全裝置都能順利收到,這就不會是APP設計的問題。
這部分問題要爬文建議透過百度搜尋來查找,比Google來的更豐富且針對些,應該是阿里雲屬於內地的產品吧! 即便在那斯達克上市也不能免俗。
總之關鍵點在於...以下參考~
//XXX必須與APP設定的一致
$request_android->setAndroidNotificationChannel("XXX");
ExtParameters設定:
//這是透過 PushNoticeToAndroidRequest.php 使用的設定
$request->setAndroidExtParameters("{\"key1\":\"value1\",\"api_name\":\"PushNoticeToAndroidRequest\"}");
//這是透過 PushRequest.php 使用的設定
$request->setAndroidExtParameters("{\"k1\":\"android\",\"k2\":\"v2\"}");
//若設定成ALL則IOS相關設定需帶入
$request->setDeviceType("ANDROID");
//這設定貌似也要加~不過數字上沒甚麼感覺
$request->setAndroidNotificationBarType(1); //通知栏自定义样式0-100
$request->setAndroidNotificationBarPriority(1); //通知栏自定义样式0-100
小結: 許多阿里後台端的問題都需有內地帳號才能發問(這個在台灣手機認證上就掛了),所以即便是呼叫OPENAPI順利得到MessageID對於"沒收到"這檔是也是無濟於事,打轉許久只能透過Try & Error排除。
另外曾考慮透過Dot NET來呼叫OPENAPI,不過在帶入appkey那行總是編譯失敗,nullable long<n> 未定義,改用建議的DLL會造成更多的變數定義錯誤,這是就神奇了~~目前無解。
補充:使用PushNoticeToAndroidRequest設定NotificationChannel沒意義,追蹤相關的code看來沒支援/強制寫入固定值在回傳的陣列裡也是靜悄悄,所以用PushRequest.php來推送即可。
2019年5月24日 星期五
aws s3 + CloudFront備忘
看中文頁面對照AWS官方英文說明剛開始會有些對不上,就寫個備忘文...留存
IAM USER設定:
新增一個使用者,取得程式使用的ID及KEY。
S3設定:
1. 建立S3服務,並設定儲存貯體名稱
2. 於屬性啟用靜態網站託管,取得靜態網站託管的終端節點
3. 設定儲存貯體政策{
"Version": "YYXX-MM-DD",
"Statement": [
{
"Sid": "PublicReadForGetBucketObjects",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::儲存貯體名稱/*"
}
]
}
CloudFront設定:
源網域名稱:選擇剛建立s3的 靜態網站託管的終端節點源ID : 輸入儲存貯體名稱
可開啟SSL服務與HTTP導向HTTPS
PHP
下載資源
composer require aws/aws-sdk-php
引用
require '/path/to/vendor/autoload.php';
補充:
1. 如果要使用自訂的網域名,可透過DNS的CNAME設定來轉,並加入CloudFront的網域清單。
2. 如果持續顯示存取拒絕,可開放S3權限的"everyone"的讀取設定。
IAM USER設定:
新增一個使用者,取得程式使用的ID及KEY。
S3設定:
1. 建立S3服務,並設定儲存貯體名稱
2. 於屬性啟用靜態網站託管,取得靜態網站託管的終端節點
3. 設定儲存貯體政策{
"Version": "YYXX-MM-DD",
"Statement": [
{
"Sid": "PublicReadForGetBucketObjects",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::儲存貯體名稱/*"
}
]
}
CloudFront設定:
源網域名稱:選擇剛建立s3的 靜態網站託管的終端節點源ID : 輸入儲存貯體名稱
可開啟SSL服務與HTTP導向HTTPS
PHP
下載資源
composer require aws/aws-sdk-php
引用
require '/path/to/vendor/autoload.php';
補充:
1. 如果要使用自訂的網域名,可透過DNS的CNAME設定來轉,並加入CloudFront的網域清單。
2. 如果持續顯示存取拒絕,可開放S3權限的"everyone"的讀取設定。
2019年3月28日 星期四
Cefsharp3 run at windows embedded standard
Cefsharp 是個可應用於Windows的chrome core的瀏覽器套件,近來搭配它做了一個WIN Form AP不過在發行時異常(尚未解),先用inno setup封裝頂著不過在更新上就沒有Visual Studio的方便。
佈署到客戶端在win 7 ~ X都順利運行,不過遺憾的是在客戶端有若干機器所使用的系統為 windows embedded standard,執行後直接跳出App Crash的訊息,自事件檢知器中看到的資訊貌似載入CefSharp.BrowserSubprocess.exe時出現的,研判應該跟multi thread設計有關吧,這部分只是猜測也無濟於事。
經GitHub更新到最近的73.X.X.X版本後直接編譯(use .NET Framework 4.6.2)的執行檔也是出現相同的狀況,後來在更新 Microsoft Visual C++ Redistributable至2015出現Setup Fails因此進行排除,順利安裝成功後再執行就順利啟動了(此期間安裝2012, 2013, 2017都順利,但無法啟動)。
處理這類線索有限的Debug過程是枯燥的,神隊友找到線索並順利排除真好。當下自己是直接在系統中安裝visual studio打算直接在windows embedded standard進行編譯,這好像也行但現在也只能先忙其他的,在緩緩囉。
佈署到客戶端在win 7 ~ X都順利運行,不過遺憾的是在客戶端有若干機器所使用的系統為 windows embedded standard,執行後直接跳出App Crash的訊息,自事件檢知器中看到的資訊貌似載入CefSharp.BrowserSubprocess.exe時出現的,研判應該跟multi thread設計有關吧,這部分只是猜測也無濟於事。
經GitHub更新到最近的73.X.X.X版本後直接編譯(use .NET Framework 4.6.2)的執行檔也是出現相同的狀況,後來在更新 Microsoft Visual C++ Redistributable至2015出現Setup Fails因此進行排除,順利安裝成功後再執行就順利啟動了(此期間安裝2012, 2013, 2017都順利,但無法啟動)。
處理這類線索有限的Debug過程是枯燥的,神隊友找到線索並順利排除真好。當下自己是直接在系統中安裝visual studio打算直接在windows embedded standard進行編譯,這好像也行但現在也只能先忙其他的,在緩緩囉。
2019年3月12日 星期二
CI cookies, session, cache memo
在CodeIgniter中頻繁使用Model在資料量大使用量高的EC網站是不好的選擇,可是EC網站的資料也不適合用靜態頁來處理,畢竟有許多互動的設計若是使用靜態頁那麼就失去意義了,某些(聯絡我們, 用戶條款)之類的到是很適合。
Ex. $this->output->cache($n);
delete_cookie('cookname');
Ex. $this->output->cache($n);
放置在Controler的 $this->load->view($action, $data); 前。
首先在config/autoload.php裡面需要加入相關的help
$autoload['helper'] = array('cookie');
寫入
set_cookie('cookname', $cookdata, 3600);
取得
get_cookie('cookname')
刪除delete_cookie('cookname');
於多網站共用Code的使用案例上,可是當使用prefix前綴來避免衝突/讀取錯誤的情事。
※全域設定可在 application/config/config.php 檔案中所設置的前綴 $config[‘cookie_prefix’]
※容量(size)大概4K使用,所以資料量大的話會無法儲存,存放於用戶端的瀏覽器內所以瀏覽器有限制存取時會無法使用。
取得
$this->session->userdata('sessionname')
$this->load->driver('cache'));
寫入$this->cache->save('cachename', $cookdata, 300); //300=5min
取得
$this->cache->get('cachename')
刪除
$this->cache->delete('cachename');
首先在config/autoload.php裡面需要加入相關的help
$autoload['libraries'] = array('session');
寫入
$this->session->set_userdata('sessionname', $cookdata);取得
$this->session->userdata('sessionname')
刪除
$this->session->unset_userdata('sessionname');
$this->session->unset_userdata('sessionname');
※ 容量(size)大概較Cookies大些但若是無法儲存則表示資料量超過容量限制,另外資料存放在記憶體內,伺服器記憶體管理務必注意。
cache:$this->load->driver('cache'));
寫入$this->cache->save('cachename', $cookdata, 300); //300=5min
取得
$this->cache->get('cachename')
刪除
$this->cache->delete('cachename');
※ 使用檔案儲存所以資料量不用擔心,不過因為是FILE所以I/O讀取的效率就偏低。
2019年3月7日 星期四
HTML中的特殊符號對照表(備忘)
在寫入資料庫與檔案(靜態檔,資源檔)常因特殊字元造成載入/顯示上的異常,這個網頁列出相當多的對應可以提供需要時的查詢,PHP最常碰到的大概是單/雙引號造成的字串判斷異常,可以用以下sample code來排除。
$Value= str_replace("'", "'", $Value);
$Value= str_replace("'", "'", $Value);
2019年2月21日 星期四
CefSharp3 Multi Thread Add listen AddressChanged Event
原來使用的套件 Awesomium.NET 因為太久沒更新對於BootStrap4的支援已經跟不上了,所以選擇的替代方案是CefSharp3這個Open Source Core。
不意外的CefSharp3也是Chrome Base的可是導入在WIN AP上有完整的範例,版控更新上於GitHub也能看出他的活躍,總之這是要補紀錄在multi Thread增加EVENT的備忘,免得過段時間又忘記怎麼做。
首先增加要listen的FUNC
/// <summary>
/// 設定新分頁的url address變更的監聽
/// </summary>
private void setNewTab_addressCheangeEvent() {
var control = GetCurrentTabControl();
if (control != null)
{
control.Browser.AddressChanged += new EventHandler<AddressChangedEventArgs>(web_Auto_AddressChanged);
}
}
//這個是把網址寫到指定的區域內
private void web_Auto_AddressChanged(object sender, AddressChangedEventArgs e){
SetTxt_Url(e.Address);
}
private delegate void str_Delegate(string str);
private void SetTxt_Url(string str) {
if (InvokeRequired) {
Invoke(new str_Delegate(SetTxt_Url), str);
return;
}
TSL_url.Text = str;
}
接著於browserTabControl.TabPages.Add(tabPage); 之後加上 setNewTab_addressCheangeEvent();就會在每次新增的Tab都會去加入這EVENT的Listen。
這是以AddressChanged 觸發時的範例,其他的以此類推即可。
補充: 有趣的文章
JS處理修改URL但不跳轉的方法,在WEB POS接地氣上面來說對我幫助很大,節錄ing
補充: 有趣的文章
JS處理修改URL但不跳轉的方法,在WEB POS接地氣上面來說對我幫助很大,節錄ing
var stateObj = { foo: "bar" };
history.pushState(stateObj, "", "controler/function/variable");
2019年2月12日 星期二
Redmine SETUP Memo
Redmine是一套Open Source的專案管理系統,之前安裝的是2.6近期再檢視已經發行到4.0.1版了,進行升級的參考此頁面的步驟,無痛(補充1?)的升級完成。
後來發現升級4.0.1其實也不是那麼需要,主因是同事發現此樣板覺得與GitHub敏捷管理類似,需要套用~套用完畢之後發現沒有出現就覺得是新版的有,其實都是誤會...因為即便是升級完畢依舊是沒有,它是以plugin方式加入的,說明如下:
Agile plugin 有 Lite版本是免費的,其餘進階版本都是要另外收年費,填寫完email之後會收到下載與安裝教學的連結,很直觀不過安裝時會檢查是否安裝crm套件,這部分就得先安裝CRM套件後才能順利安裝Agile plugin。
補充1: 2.6 to 4.0.1 唯一出的問題是ruby的版本需 > 2,原先安裝的版本是 1.9.1,變更ruby的步驟參考此頁面處理,用RVM管理Ruby版本真是方便!! 至於安裝ruby會依照不同的環境有不同的方式,就不留存了。
補充2: 啟用Redmine方式依舊沒變在VM環境下小小不方便(logout就關掉了),所以很開心script方式還是可以使用,這部分方式就持續使用start_redmine.sh來啟用/關閉/重啟。
補充3: Tags plugin 也是不錯用的套件,建議加裝。
後來發現升級4.0.1其實也不是那麼需要,主因是同事發現此樣板覺得與GitHub敏捷管理類似,需要套用~套用完畢之後發現沒有出現就覺得是新版的有,其實都是誤會...因為即便是升級完畢依舊是沒有,它是以plugin方式加入的,說明如下:
Agile plugin 有 Lite版本是免費的,其餘進階版本都是要另外收年費,填寫完email之後會收到下載與安裝教學的連結,很直觀不過安裝時會檢查是否安裝crm套件,這部分就得先安裝CRM套件後才能順利安裝Agile plugin。
補充1: 2.6 to 4.0.1 唯一出的問題是ruby的版本需 > 2,原先安裝的版本是 1.9.1,變更ruby的步驟參考此頁面處理,用RVM管理Ruby版本真是方便!! 至於安裝ruby會依照不同的環境有不同的方式,就不留存了。
補充2: 啟用Redmine方式依舊沒變在VM環境下小小不方便(logout就關掉了),所以很開心script方式還是可以使用,這部分方式就持續使用start_redmine.sh來啟用/關閉/重啟。
補充3: Tags plugin 也是不錯用的套件,建議加裝。
2019年2月1日 星期五
LinePay oneTimeKey 備忘
導入LinePay在門市端會使用到oneTimeKey,就官方文件上的說明雖然給了範例碼但就少了個醍醐味,估狗上的資料一堆看到了這篇實作後打通任督二脈,總算把掛在頭上個把月的需求單給結了。
話說...怎麼是日文的呢? 可能是Line本來就是從日韓那邊來的吧,相對的英文論壇討論的資料就少得可憐,當然內地簡體字的文章挺多的,可在oneTimeKey討論上應該是應用的少也沒爬到關鍵文章。
總之...
amount很直覺的金額,不用.00也不用x100。
oneTimeKey真的只能用一次,即便沒付費成功在丟會回錯誤訊息。
ConfirmUrl可以設但實測用不到(埋Log)沒有官方觸發的紀錄。
另外要注意的地方是呼叫payment後取得transactionId再進行refund才會真正扣款付款完成。
話說...怎麼是日文的呢? 可能是Line本來就是從日韓那邊來的吧,相對的英文論壇討論的資料就少得可憐,當然內地簡體字的文章挺多的,可在oneTimeKey討論上應該是應用的少也沒爬到關鍵文章。
總之...
amount很直覺的金額,不用.00也不用x100。
oneTimeKey真的只能用一次,即便沒付費成功在丟會回錯誤訊息。
ConfirmUrl可以設但實測用不到(埋Log)沒有官方觸發的紀錄。
另外要注意的地方是呼叫payment後取得transactionId再進行refund才會真正扣款付款完成。
2019年1月30日 星期三
htmlspecialchars vs strip_tags
CKEditor 是個好用的第三方元件,不過使用後就會有若干的缺點被放大出來,無論是安全上的問題或是資料儲放量爆炸等等...都是煩人的~不過其優點可以讓無止盡的客戶端需(要)求得以滿足(或應付)也是不得不的選擇。
在使用上有很多時候是被要求不要出現HTML TAG的,這時候這兩個 htmlspecialchars() 及 strip_tags()函式就被提出來囉!! 都是在做 HTML 輸出消毒但這兩者還是有所不同,參考說明節錄如下:
strip_tags() 是用來防君子,所有正規合法的 html 或 php 標籤,都將被濾除。
htmlspecialchars() 則是用來防小人,所有想借機偷渡的語法,也會被抓出來,例如onmouseover='...'。
所以如果是可控的資料來源(後台)那麼strip_tags會有效率些(快點),不可控的資料來源(前端)就嚴謹些準沒錯!!
所以如果是可控的資料來源(後台)那麼strip_tags會有效率些(快點),不可控的資料來源(前端)就嚴謹些準沒錯!!
2019年1月21日 星期一
=.= 每個軟體開發者都絕對一定要會的Unicode及字元集必備知識(佳文收錄)
每個軟體開發者都絕對一定要會的Unicode及字元集必備知識(沒有藉口!)
最近處理電子發票QRCode中文顯示亂碼的問題,爬文看到這篇文章...秒懂ㄚ,那個範例Code誤人不淺...總之~怕以後忘記所以收錄下來,宅友們共賞嚕。
2019年1月10日 星期四
刷新作業系統的DNS紀錄...備忘
清除本機DNS Cache的方法
一、Windows
- 打開你的Windows,開起搜尋框,打下cmd(或從附屬應用程式中找到命令提示字元)。當命令提示字元的黑底白字畫面跑出>的時候輸入ipconfig /flushdns,然後按下enter鍵。
二、Mac OS X
- 打開你的Mac OS,點擊畫面右上角的放大鏡圖示的Spotlight,輸入terminal(或終端機)。當終端機的白底黑字跑出$的時候,如果你是10.5以上版本請輸入:sudo dscacheutil -flushcache,不到10.5版本請輸入:lookupd -flushcache,如出現詢問密碼,請輸入您的系統密碼(同安裝程式時所輸入的密碼),輸入密碼時畫面並不會出現任何文字或*,請照打,打完按下Enter鍵。
三、Linux(Ubuntu)
- 開起你的terminal輸入/etc/rc.d/init.d/nscd restart,或者sudo /etc/init.d/nscd restart。
如果執行上述指令卻出現command not found,代表您的系統尚未安裝nscd,請先執行sudo aptitude install nscd,安裝nscd,安裝完成後請重新執行第一點之指令 /etc/rc.d/init.d/rstatd,或者sudo /etc/init.d/nscd restart。 - 完成後DNS Cache應該已經清空囉。
2019年1月9日 星期三
微信支付 By API 異常排除
近期在套用微信支付API碰到"數位簽章校驗不通過"的回覆困擾許久,程式碼檢查再檢查與文件對應都看不出所以然來,在檢視機台終端交易密鑰的更新Log發現相同程式碼下不同的終端編號會有不同的結果,若干編號就是回校驗不通過。
經查API文件僅敘述簽名檔做好SHA256運算後再以base64編碼置入sign中,此一現象在此網誌所述雷同,於是在base64編碼後在加上urlencode()後傳出,問題就排除了。
$hashValue= hash('sha256', $string, TRUE);
$sign=urlencode(base64_encode($hashValue));
小記:系統整合尤其是透過API交換資料的情況下,這類問題往往很難從單一方面去排除,尤其在另一方(內地? 代理的銀行端? 有聽沒有懂的客戶? )已讀不回或不讀不回下僅能以trial and error方式來排除,恩恩...期間所遭遇個管理層級與客戶層級的質問心酸,只能共勉之...
經查API文件僅敘述簽名檔做好SHA256運算後再以base64編碼置入sign中,此一現象在此網誌所述雷同,於是在base64編碼後在加上urlencode()後傳出,問題就排除了。
$hashValue= hash('sha256', $string, TRUE);
$sign=urlencode(base64_encode($hashValue));
小記:系統整合尤其是透過API交換資料的情況下,這類問題往往很難從單一方面去排除,尤其在另一方(內地? 代理的銀行端? 有聽沒有懂的客戶? )已讀不回或不讀不回下僅能以trial and error方式來排除,恩恩...期間所遭遇個管理層級與客戶層級的質問心酸,只能共勉之...
2019年1月4日 星期五
處理 curl call error(77) error(60) 備忘!
這陣子發生呼叫API無回應但API也沒有LOG(所以是沒有呼叫到API),後來在WEB端的Log檔看到crul回傳 err 77的記錄。
這個狀況因為只出現在特定機器上,所以看來非佈署問題與程式碼bug,新客戶網站後來新增SSL,但只用service nginx reload讓他生效並未執行service php-fpm restart,檢視SERVER運行時間已經百餘日也沒重啟過,所已將php-fpm重啟後就不會再發生相同的錯誤回報。
補充: 頁面使用JQuery(非同步)機制雖然能減少與伺服器端的資料交換量,可若啟用CSRF機制時若timeout時間設定太短而頁面太久沒有reload,會造成瀏覽者有頁面沒反應的情況,這部分在設計時需要檢查回傳值若為token過期狀態,則須強制頁面reload更新token已利正確運行。
使用curl增加設定:
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0)
使用file_get_contents增加設定:
$arrContextOptions=array(
"ssl"=>array(
"verify_peer"=>false,
"verify_peer_name"=>false,
),
);
file_get_contents($target,false,stream_context_create($arrContextOptions));
訂閱:
文章 (Atom)