顯示具有 Other 標籤的文章。 顯示所有文章
顯示具有 Other 標籤的文章。 顯示所有文章

2022年5月17日 星期二

把JS ALERT變漂亮

 當系統開發運行趨於穩定後,使用者開始對UI/UX的需求就會趨向積極,恩恩...對單純的Programmer來說,美感永遠不是得優先強化的項目,當然嘔心瀝血做了好幾天更新上的版面,被吐槽到爆炸的評語帶來的挫折也不是一天兩天就能平復的,總之...依賴第三方套見是個不錯的選擇。

SWEETALERT2 可支援BootStrap是不錯的選擇,官網上的範例也很豐富大概常用的情境都有了,要更炫目的也有但使用者口味是會被養刁的,不要隨便做害人(舉某系統說他有位啥你沒有)害己(其他業管的系統為啥沒有)的決定。

取代alert();

Swal.fire("訊息","Hello world.","error");

取代comfirm();

Swal.fire({

  title: "警告",
  icon: "info", //warring(orange), primary(dark blue), info(blue), success(green), danger(red)
  html: "<font color='red'>查無OOOOO<br>請再次確認</font>",
  showCloseButton: false,
  showCancelButton: true,
  focusConfirm: false,
  confirmButtonText: "提交",
  cancelButtonText: "取消",
}).then((result) => {
  if (result.isConfirmed) {
  //Do something.;
  }

})

2021年9月30日 星期四

COBOL & DB2 中文字的處理

 古時候的DB2儲存中文字會在前後用0E跟0F框起來,但後人在改寫存取時沒處理好COBOL讀取時就會變成亂碼0E0F湊起來就佔了2 BYTES,也會讓欄位要塞好塞滿時得先扣掉2bytes才行,這部分要記好別踩坑。


直接更新下指令如果兩個TABLE長度不一樣,如TABLEA.CNNAME(14)而TABLEB.CNNAME2(20),就可以透過下列語法來塞值。

UPDATE TABLEA SET CNNAME=(SELECT CONCAT(LEFT(CNNAME2,13), X'''0F''') FROM TABLEB WHERE KEY=?) WHERE KEY2=?;

2021年4月9日 星期五

DB2 SP 中 LOOP Call SP Get Result

CREATE OR REPLACE PROCEDURE SCHEMANAME.SP_CALLER() DYNAMIC RESULT SETS 1

P1:BEGIN

DECLARE SQLSTATE CHAR(5) DEFAULT '00000';
DECLARE loc_cursor RESULT_SET_LOCATOR VARYING;
DECLARE CONTINUE HANDLER FOR SQLSTATE '23505' SET RET=SQLCODE;
SET PP = 1 ;
WHILE(PP < 5) DO
    CALL SCHEMANAME.SPNAME(PP);
    ASSOCIATE RESULT SET LOCATOR (loc_cursor) WITH PROCEDURE SCHEMANAME.SPNAME; 
    ALLOCATE cur CURSOR FOR RESULT SET loc_cursor;
    L1: LOOP 
        FETCH C1 INTO column1, column2, ...; 
        IF SQLSTATE<>'00000' THEN 
            LEAVE L1;  
         END IF; 
    END LOOP L1;
    CLOSE cur;

    SET PP = PP + 1 ;
END WHILE;

END P1
狀況:
DB2寫SP如果SP裡面又對另一個SP做多次呼叫,會一直抓到第一次呼叫SP的結果。
貌似因為DB2版本問題,所以原寫法建立到新的DB2就有問題,取值時須再LOOP即可!感謝辜狗大師。

2021年2月8日 星期一

WIN X BAT在工作排程器沒反應的調整

在批次作業要呼叫JAR時使用了相對路徑./xxx.jar方式呼叫,從Consloe執行OK可是設定上工作排程器就變成閃一下結束,參考了這網誌的說明就是卡在切換目錄上,實測加了後就可以跑了。

加了這個指令 CD /D "%~dp0" 就搞定了

/D 表示切換到執行的資料夾

"%~dp0" 表示當下的目錄


補充說明:本來也試過直接寫死絕對路徑不過考量到後續維護若干年後忘了或換位置會造成執行上的困擾,改成變數取得應該是比較好的做法。當然設定"開始位置"也是方法之一,但這個如果經手他人(MIS)如果對方忘了或疏忽掉也是隱患...

2020年12月16日 星期三

Datatable增加Export/Copy Button一併顯示筆數下拉的設定調整

JS Datatable dom設定成Bfrtip會顯示Button但是造成無法切換筆數,改成Blfrtip即可解決,至於排版可參考下列說網址說明

https://datatables.net/reference/option/dom

2020年12月4日 星期五

Get method has XSS的處理

 弱點掃描反映有高風險問題,處理方法註記下

原寫法

<%
String TEST = "";
if ((request.getParameter("test")!=null)) TEST = request.getParameter("test");
%>

<input type="TEXT" id="TEST" name="TEST"  value="<%=TEST %> />

在這方式下就GG惹
http://localhost/home?test=%22onmouseover%3D%22alert%28140%29%22

改寫法搞定

<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<input type="TEXT" id="TEST" name="TEST"  value="${fn:escapeXml(param.test)}" />

轉跑道寫JSP 一些PHP跟C#處理的方式會有所不同,恩恩...記錄下

2020年6月15日 星期一

使用Enter鍵來移動焦點至下個輸入元素

用AJAX做功能習慣了,碰到習慣submit的使用者,對於封鎖在輸入框按Enter做提交的設計,給了許多的負評,沒辦法改變人那就改變寫法吧,把ENTER的封鎖改成切換焦點方式,當切到按鈕處在執行提交,那頁面功能就不會異常了,寫法如下~~

 var allInputSelector = ":input:visible:enabled"; 
 $("body").on("keydown", allInputSelector + ":not(textarea, :button)", function(event){
    //排除 focus 在 textarea 或 button 時觸發 
    if (event.keyCode == 13) { 
         $(allInputSelector + ":eq(" + ($(allInputSelector).index($(this)) + 1) + ")").focus();
         event.preventDefault(); 
     } 
 });


2020年3月26日 星期四

Jenkins curl 出現 unable to get local issuer certificate

平常在跑的排程因為SSL簽章過期更新後出現unable to get local issuer certificate這樣的錯誤訊息 參考這篇blog無法解決,不過也是個研究方向,應急不行。

這篇 curl 略過檢查自簽 SSL 憑證有效性 就不錯用了,加上-k 或 --insecure 去重跑排程就不會再報錯!! 當然一般寫code加上CURLOPT_SSL_VERIFYPEER去排除狀態,不過這是透過Shell Script來執行的初次碰到就註記下。


#!/bin/sh
system=('www1' 'www2' 'www3')
for i in "${system[@]}"
do
   curl -k --request GET 'https://'$i'.domain.net/method.php'
done


<?php
$url = "https://www1.domain.net/method.php/";
$post_data['var'] = "xxx";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
$result = curl_exec($ch);
curl_close($ch);
?>

2019年12月3日 星期二

node.js use websocket Chat Room sample

參考: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年10月2日 星期三

試算表的日期轉文字

在試算表的儲存格常常會依照所貼入的文字去轉換格式,但使用公式來處理時日期就會變轉成無意義的數字,這部分可以使用TEXT函數來轉換。

=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名稱:/ /掛載使用的資料夾

2. 安全群組不要新建使用EFS相同的即可。
3. 增減條件與數量這部分依照實際需要去調整,目前使用的是CPU使用率超過60% 300秒就增加一台,最高增加到3台。
4. 另外要搭配LoadBalance分散風險,所以建立兩個AutoScaling Group關連到同一個LoadBalance。


後記: 就不截圖了AWS的文件還蠻多的且更新頻率高,有搭配相關超連結到時候需要再點選進去看即可。

2019年9月11日 星期三

透過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/


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圖示,若無則表示有缺漏得檢查。

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來推送即可。

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"的讀取設定。

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進行編譯,這好像也行但現在也只能先忙其他的,在緩緩囉。


2019年3月7日 星期四

HTML中的特殊符號對照表(備忘)

在寫入資料庫與檔案(靜態檔,資源檔)常因特殊字元造成載入/顯示上的異常,這個網頁列出相當多的對應可以提供需要時的查詢,PHP最常碰到的大概是單/雙引號造成的字串判斷異常,可以用以下sample code來排除。

$Value= str_replace("'", "&apos;", $Value);

2019年2月1日 星期五

LinePay oneTimeKey 備忘

導入LinePay在門市端會使用到oneTimeKey,就官方文件上的說明雖然給了範例碼但就少了個醍醐味,估狗上的資料一堆看到了這篇實作後打通任督二脈,總算把掛在頭上個把月的需求單給結了。

話說...怎麼是日文的呢? 可能是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會有效率些(快點),不可控的資料來源(前端)就嚴謹些準沒錯!!

2019年1月21日 星期一

=.= 每個軟體開發者都絕對一定要會的Unicode及字元集必備知識(佳文收錄)

每個軟體開發者都絕對一定要會的Unicode及字元集必備知識(沒有藉口!)


最近處理電子發票QRCode中文顯示亂碼的問題,爬文看到這篇文章...秒懂ㄚ,那個範例Code誤人不淺...總之~怕以後忘記所以收錄下來,宅友們共賞嚕。