Menu

Tuesday, August 11, 2020

[Android - Espresso] การกดปุ่ม Allow บนหน้าต่างขอ Permission โดยไม่จำเป็นต้องรู้ชื่อของ Permission
[Android - Espresso] How to Click Allow Permissions with No Need to Know Permission Name

การทำ UI test automation ด้วย Espresso บางครั้งเราต้องเปิดใช้งานกล้องถ่ายรูป ถ้าหากเปิดใช้งานจาก application ของเราเป็นครั้งแรก สิ่งหนึ่งที่เราต้องเจอแน่นอน คือ modal สำหรับขอ permission ให้ application ของเราสามารถใช้งานกล้องดังภาพข้างล่างนี้


ด้วยข้อจำกัดของ Espresso ที่ไม่สามารถทำ action กับ element ที่อยู่ภายนอก application ได้ เราจึงต้องใช้ UI automator ช่วยในการกดปุ่ม Allow แทน โค้ดข้างล่างนี้จะกดปุ่ม Allow ให้เราโดยอัตโนมัติ ถ้าหากปุ่มดังกล่าวปรากฏอยู่
private val device: UiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

fun allowPermissionsIfNeeded() {
    if (Build.VERSION.SDK_INT >= 23) {
        val allowPermissions = device.findObject(UiSelector().text("Allow"))
        if (allowPermissions.exists()) {
            try {
                allowPermissions.click()
            } catch (e: UiObjectNotFoundException) {

            }
        }
    }
}
เนื่องจากเป็นการกดปุ่ม Allow โดยไม่สนใจว่า เป็นการขอ permission ใด จึงสามารถนำไปใช้กับการขอ permission อื่นๆได้ เช่น การเลือกรูปจาก gallery, การใช้งาน location เป็นต้น

สำหรับข้อมูลเพิ่มเติม สามารถอ่านได้ที่ https://stackoverflow.com/questions/33929937/android-marshmallow-test-permissions-with-espresso

Thursday, August 6, 2020

[Android - Espresso] การติดตั้ง Java เพื่อรัน uiautomatorviewer
[Android - Espresso] How to Install Java to Run uiautomatorviewer

uiautomatorviewer ใช้ในการหารายละเอียดของ element ที่ปรากฎบนหน้าจอ

โดยปกติแล้ว uiautomatorviewer จะอยู่ที่ {android_sdk_path}\tools\bin 
โดยที่ {android_sdk_path} บน Windows จะอยู่ที่ C:\Users\{username}\AppData\Local\Android\Sdk

ถ้าหากรัน uiautomatorviewer แล้วได้ error ตามด้านล่างนี้
-Djava.ext.dirs=/Users/<Username>/Library/Android/sdk/tools/lib/x86_64:/Users/<Username>/Library/Android/sdk/tools/lib is not supported.  Use -classpath instead.
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
สาเหตุที่ทำให้เกิด error เนื่องจาก version ของ Java ที่ติดตั้งอยู่ในเครื่องไม่เข้ากับ version ที่ uiautomatorviewer ใช้รัน

วิธีแก้ error คือ เปลี่ยนไป Java version 8 โดยดาวน์โหลดได้จาก https://www.java.com/en/download/

หมายเหตุ ถ้าดาวน์โหลด Java จาก https://www.oracle.com/java/technologies/javase-downloads.html จะเกิด error ข้างต้น

Wednesday, August 5, 2020

[Javascript] จุดสามจุดใน Javascript หมายถึงอะไร
[Javascript] What is Three Dot in Javascript

หลังจากรีวิวโค้ด Typescript แล้ว พบโค้ดตามข้างล่างนี้

ทำให้เกิความสงสัยว่า ... (จุดสามจุด) หน้าชื่อตัวแปรนั้นมีความหมายอย่างไร

เมื่อหาข้อมูลเพิ่มเติม จุดสามจุดหน้าชื่อตัวแปรนั้นมีใช้อยู่ 2 แบบ ดังนี้

Rest Parameters

ใช้รับค่าแทน parameter ที่เหลืออยู่ นอกเหนือจาก parameter อื่นๆที่มีการกำหนดตัวแปรมารับ โดยตัวแปรนี้จะเป็น array ของ parameter

ตัวอย่าง เช่น
function test(...params){
    console.log(params)
}
function test2(a, b, ...params){
    console.log(params)
}
test(1, 2, 3, 4)  // [1, 2, 3, 4]
test2(1, 2, 3, 4)  // [3, 4]

Spread Operators

ใช้กระจาย item ใน array ออกมา

ตัวอย่าง เช่น
var input = [1, 2, 3, 4]
[...input, 5, 6]  // [1, 2, 3, 4, 5, 6]

อ้างอิงจาก https://dev.to/sagar/three-dots---in-javascript-26ci

Monday, August 3, 2020

[Android - Espresso] การจัดการ System Animation ของ Emulator
[Android - Espresso] Managing Emulator System Animations

การรัน Espresso โดยเปิด system animation เอาไว้ จะทำให้เกิด exception ดังนี้
androidx.test.espresso.PerformException: Error performing 'single click' on view 'Animations or transitions are enabled on the target device.
วิธีแก้ไข exception นี้ คือ ต้องปิด system animation ก่อนรัน Espresso Test

วิธีที่ง่ายที่สุดสำหรับการปิด system animation คือ รันคำสั่งต่อไปนี้ใน Terminal (Powershell สำหรับ Windows)
adb shell settings put global window_animation_scale 0.0
adb shell settings put global transition_animation_scale 0.0
adb shell settings put global animator_duration_scale 0.0
นอกจากการปิด system animation แล้ว ยังมีการตั้งค่าอื่นสำหรับ UI test automation อีก สามารถอ่านเพิ่มเติมได้ที่ https://testyour.app/blog/emulator

หมายเหตุ กรณีที่ทดสอบใน device จริง สามารถใช้คำสั่งข้างต้นเพื่อปิด system animation ได้เช่นกัน แต่ต้องเชื่อมต่อ device เข้ากับเครื่องที่รัน Espresso เสียก่อน

[Android - Espresso] สิ่งที่เราสามารถทำกับ View ได้
[Android - Espresso] View Action

View หมายถึง UI component ที่แสดงอยู่บน Application ใน Android

เราสามารถใช้ Espresso ในการเขียนจำลอง action ที่เราจะทำกับ view ที่ต้องการได้ ดังนี้
onView({component_selector}).perform({action})
ในกรณีที่ต้องการทำ action หลายอย่างต่อเนื่องกัน เราสามารถใช้คำสั่งดังนี้
onView({component_selector}).perform({action1}, {action2}, ..., {actionN})
โดยที่
  • {component_selector} เป็นคำสั่งสำหรับเลือก component ที่เราจะทำ action ด้วย
  • {action} เป็น action ที่เราจะทำกับ component ที่เราเลือก 

Friday, July 31, 2020

[Android - Espresso] ความแตกต่างระหว่าง Espresso และ UI Automator Testing Framework
[Android - Espresso] What is Different between Espresso and UI Automator Testing Framework

Espresso และ UI Automator ทั้ง 2 ตัวเป็น Testing framework สำหรับ Android เพื่อใช้ทดสอบ User Interface (UI) เหมือนกัน

สิ่งที่แตกต่างกัน คือ ความสามารถในการทดสอบ Application

  • Espresso มีความสามารถในการทำ action ได้เหมือนกับที่เราทำกับ application ของเรา รวมถึงการตรวจสอบค่าของ component ต่างๆ  จึงเหมาะสำหรับการทดสอบ UI ของ application ที่เราเขียนขึ้นมาเอง แต่มีข้อจำกัด คือ ไม่สามารถจำลองการกระทำบน Application อื่นหรือ system ได้ 
  • UI Automator มีความสามารถในการทำ action ได้เหมือนกับที่เราทำกับ device ของเรา จึงเหมาะสำหรับการทดสอบ UI ที่มีการใช้งานข้ามไปมาระหว่าง system และ application อื่น แต่มีข้อจำกัดคือ ไม่เหมาะกับการตรวจสอบค่าของ component 
หมายเหตุ เราสามารถใช้ Espresso และ UI Automator ร่วมกันในการเขียนเทสได้ 

[Android - Espresso] โปรแกรมใน Android SDK ที่จำเป็นต้องใช้ในการเขียนเทสด้วย Espresso Framework
[Android - Espresso] Necessary Programs in Android SDK that Use to Write Test in Espresso Framework

โปรแกรมใน Android SDK ที่จำเป็นต้องใช้ในการเขียนเทส ประกอบด้วยโปรแกรมดังนี้
  • Android Debug Bridge (adb) เป็น command-line tool ที่ช่วยให้เราสามารถติดต่อสื่อสารกับอุปกรณ์ของเราได้ เช่น การรันคำสั่ง การติดตั้งแอพ เป็นต้น
    • Path ของ adb อยู่ที่ {android_sdk}/platform-tools/adb
    • คำสั่งที่ใช้บ่อยมีดังนี้
      • คำสั่งสำหรับแสดงรายการ devices ที่ connect อยู่กับเครื่องของเรา
        adb devices
      • คำสั่งสำหรับ map port จาก devices ที่ connect อยู่กับเครื่องของเรา
        adb reverse tcp:8081 tcp:8081
  • UI Automator viewer (uiautomatorviewer) เป็นเครื่องมือที่ช่วยสแกนและวิเคราะห์ UI component ที่แสดงอยู่บนหน้าจอ Device เราสามารถใช้เครื่องมือนี้ในการตรวจสอบ layout และ properties ของ component ที่เราต้องการได้
    • Path ของ uiautomatorviewer อยู่ที่ {android_sdk}/tools/bin/uiautomatorviewer
หมายเหตุ {android_sdk} บน Windows จะอยู่ที่ C:/Users/{username}/AppData/Local/Android/Sdk/
ตัวอย่างเช่น
C:\Users\puthipong\AppData\Local\Android\Sdk\platform-tools
C:\Users\puthipong\AppData\Local\Android\Sdk\tools\bin

Thursday, July 30, 2020

[Ubuntu] การสร้างพื้นที่ Virtual Memory บน Ubuntu
[Ubuntu] How to Create Virtual Memory on Ubuntu

Virtual memory เป็นหน่วยความจำบน Harddisk ที่ถูกใช้เสมือนว่าเป็น RAM โดยทำหน้าที่เก็บข้อมูลที่เป็น inactive page จาก RAM ในกรณีที่หน่วยความจำ RAM เต็ม

Swap เป็น Virtual memory บน Ubuntu

พื้นที่สำหรับ Swap นี้เป็นได้ทั้ง swap partition หรือ swap file โดยทั่วไปเมื่อรันบน Virtual machine จะไม่มี swap partition ให้ใช้งาน จึงเหลือเพียงทางเลือกเดียวคือ swap file

ขั้นตอนการสร้าง swap file เป็นดังนี้
  1. สร้างไฟล์พร้อมกำหนดขนาดพื้นที่ของไฟล์ตามขนาดที่ต้องการ
    sudo fallocate -l 1G /swapfile
    
  2. เปลี่ยน permission ของไฟล์ให้ root มีสิทธิ์ในการอ่านแและเขียนเท่านั้น
    sudo chmod 600 /swapfile
    
  3. กำหนดให้ใช้ไฟล์ข้างต้นเป็นพื้นที่สำหรับ Swap
    sudo mkswap /swapfile
    
  4. เปิดใช้งาน swap file
    sudo swapon /swapfile
    

Tuesday, July 7, 2020

[AWS - S3] การกำหนดนโยบาย เพื่อบล็อกการเข้าถึง S3 bucket ที่ไม่ได้มาจาก HTTP Referer ที่กำหนด
[AWS - S3] S3 Bucket Policy: Restricting Access to a Specific HTTP Referer

ในมุมกลับกันจากบทความเรื่อง [AWS - S3] การกำหนดนโยบาย เพื่ออนุญาตให้เข้าถึงไฟล์ใน S3 bucket ด้วย HTTP Referrer ที่กำหนด เราสามารถใช้ HTTP Referrer นี้ในบล็อกการเข้าถึงข้อมูลใน S3 ได้เช่นกัน

การบล็อกไม่ให้เข้าถึงข้อมูล หากไม่ได้เรียกมาจาก Referrer ที่ระบุ เราสามารถกำหนด bucket policy ของ S3 ดังนี้
{
    "Version": "2012-10-17",
    "Id": "http referer policy example",
    "Statement": [
        {
            "Sid": "Block get requests originating from other than www.example.com and example.com.",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::examplebucket/*",
            "Condition": {
                "StringNotLike": {
                    "aws:Referer": [                        
                         "http://www.example.com/*",
                         "http://example.com/*"

                    ]
                }
            }
        }
    ]
}
หมายเหตุ เราสามารถกำหนด policy ข้างต้น ร่วมกับการใช้ Presigned URL เพื่อเพิ่มความปลอดภัยของข้อมูลใน S3 ได้

[AWS - S3] การกำหนดนโยบาย เพื่ออนุญาตให้เข้าถึงไฟล์ใน S3 bucket ด้วย HTTP Referrer ที่กำหนด
[AWS - S3] S3 Bucket Policy: Allowing Access to a Specific HTTP Referrer

โดยปกติแล้ว เราจะไม่อนุญาตให้เรียกข้อมูลใน S3 แบบ public ซึ่งใครจะเรียกก็ได้!!! เพื่อป้องกันการรั่วไหลของข้อมูล

อย่างไรก็ตาม การใช้งานบางอย่างจำเป็นต้องเรียกใช้ข้อมูลใน S3 แบบ public เนื่องจากไม่สามารถสร้าง Presigned URL ได้

วิธีเพิ่มความปลอดภัยของข้อมูลสำหรับกรณีนี้ คือ เพิ่มการตรวจสอบค่า HTTP Referrer ที่เรียกมายัง S3 เพื่อกำหนดสิทธิ์การเข้าถึงไฟล์ใน bucket

หมายเหตุ HTTP Referrer เป็นค่าอ้างอิงของ domain ที่ส่งคำร้องมายัง server

Saturday, May 23, 2020

[AWS - IAM] วิธีสร้าง IAM user
[AWS - IAM] How to Create IAM User

AWS Identity and Access Management (IAM) user เป็นสิ่งที่ถูกสร้างขึ้นแทนบุคคลหรือ application เพื่อใช้โต้ตอบกับ AWS

AWS แนะนำให้ใช้ IAM user ในการทำงานต่างๆแทนการใช้ AWS Account Root User และเก็บ Root user ไว้ใช้ในส่วนที่จำเป็นเท่านั้น

การสร้าง IAM user มีวิธีดังนี้
  1. login เข้า AWS console 
  2. เข้าไปที่ https://console.aws.amazon.com/iam/home#/users
  3. กดปุ่ม Add user
  4. กรอก User name (กรณีที่ต้องการสร้างมากกว่า 1 user ให้กดที่ Add another user)
  5. เลือก AWS access type ดังนี้ (สามารถเลือกได้มากกว่า 1 อันตามความต้องการใช้งาน)
    • ถ้าต้องการใช้ access key ID และ secret access key ของ user นี้กับ AWS API, CLI, SDK, และเครื่องมืออื่นๆ ให้เลือก Programmatic access 
    • ถ้าต้องการให้ user นี้สามารถ login เข้า AWS Management Console ได้ ให้เลือก AWS Management Console access
  6. กดปุ่ม Next: Permissions
  7. กดปุ่ม Next: Tags
  8. กดปุ่ม Next: Review
  9. กดปุ่ม Create user จะแสดงหน้า Add user ดังข้างล่าง
  10. ถ้าหากเลือก Programmatic access ในข้อ 5 ให้จดบันทึก Access key ID และ Secret accesss key ในหน้านี้เอาไว้ เนื่องจาก secret นี้จะแสดงเพียงครั้งเดียว
  11. กดปุ่ม Close

[AWS - IAM] การกำหนดสิทธิ์การเข้าใช้งาน โดยใช้ AWS IAM Policy เพื่อให้ใช้งาน S3 ได้เพียง bucket เดียว
[AWS - IAM] How To Grant Access To Only One S3 Bucket Using AWS IAM Policy

สมมติว่า เรามี IAM user ชื่อ my-user และ S3 bucket ชื่อ my-bucket

หากเราต้องการสร้าง policy ชื่อ My-S3-Policy เพื่อใช้กำหนดสิทธิ์ให้ my-user สามารถเข้าใช้ my-bucket ได้เพียงอันเดียว เรามีวิธีการดังนี้
  1. เข้าไปที่หน้า Policy ของ Identity and Access Management (IAM) ตามลิ้งค์นี้
    https://console.aws.amazon.com/iam/home?region=ap-southeast-1#/policies
  2. กดปุ่ม Create policy
  3. สร้าง Policy โดยมีรายละเอียดดังนี้
    • กรณีที่สร้าง Policy ในแท็บ Visual editor
      1. Service เลือกเป็น S3
      2. Action เลือกเป็น All S3 actions (s3:*)
      3. Resources ให้กำหนดค่าดังนี้
        • bucket 
          1. กดปุ่ม Add ARN
          2. กรอกข้อมูลช่อง Bucket name เป็น my-bucket
          3. กดปุ่ม Add
        • object
          1. กดปุ่ม Add ARN
          2. Bucket name กรอกข้อมูลเป็น my-bucket
          3. Object  name เลือกเป็น Any
          4. กดปุ่ม Add

Monday, April 27, 2020

[Bash Script] ระวังการสร้าง ฺBash Script บน Windows แล้วอาจจะไม่สามารถนำมารันบน Unix ได้
[Bash Script] Warning: Create Bash Script on Windows then Cannot Run on Unix

ในกรณีนี้เราเขียน Bash script ขึ้นมาบน Windows แล้วค่อยอัพโหลดขึ้นไปรันบนเซิร์ฟเวอร์ที่เป็น Ubuntu ผลการรันได้ข้อผิดพลาดตามด้านล่างนี้
/bin/bash^M: bad interpreter: No such file or directory
สาเหตุเกิดจากอักขระที่แทนการขึ้นบรรทัดใหม่บน Windows และ Unix นั้นต่างกันดังนี้
  • Windows จะเป็น \r\n
  • Unix จะเป็น \n
ทำให้ \r เป็นอักขระที่ไม่เกี่ยวข้องกับการขึ้นบรรทัดใหม่ จึงถูกมองว่าเป็นอักขระอีกตัวที่ตามหลัง /bin/bash จึงเกิดข้อผิดพลาดข้างต้น

วิธีแก้ไข คือ รันคำสั่งดังนี้
sed -i -e 's/\r$//' scriptname.sh
หรือเขียน bash script ใหม่บน Unix แทน

Wednesday, April 22, 2020

[Bash Script] วิธีการพิมพ์ข้อความที่มีการขึ้นบรรทัดใหม่หรือ Backslash Escape บน Bash
[Bash Script] How to Print New Line or Backslash Escape on Bash

เวลาเราจะพิมพ์ข้อความออกทาง standard output เราจะใช้คำสั่ง echo ดังนี้
echo "your_message"
นอกจากนั้น เรายังนำคำสั่งข้างต้นมาประยุกต์ใช้ เพื่อพิมพ์ข้อความลงไปในไฟล์ดังนี้
echo "your_message" >> [filename]
หากเราต้องการพิมพ์ข้อความที่มีการขึ้นบรรทัดใหม่หรือมี Backslash Escape แทรกอยู่ลงไปในไฟล์ ให้เราเลือกใช้คำสั่งใดคำสั่งหนึ่งต่อไปนี้
  • ใช้คำสั่ง printf แทน echo
    printf "your_message1\nyour_message2"
    
  • ใช้คำสั่ง echo ตามด้วย option -e เพื่ออนุญาตให้แปลง backslash escape
    echo -e "your_message1\nyour_message2"
    
  • ใช้คำสั่ง echo ตามด้วย $'your_message' เพื่อบอกว่า your_message เป็น ANSI-C Quoting
    echo $'your_message1\nyour_message2'
    

Monday, April 20, 2020

[Ubuntu] สรุปคำสั่งสำหรับบีบอัดและแตกไฟล์ผ่านทาง Command Line
[Ubuntu] The Commands to Zip and Unzip File and Folder via Command line

การบีบอัดไฟล์ผ่านทาง Command Line

ในกรณีที่ยังไม่เคยติดตั้ง zip ให้รันคำสั่งดังนี้
apt-get install zip
การบีบอัดแฟ้มข้อมูล ใช้คำสั่งดังนี้
zip -r [zip_name].zip [folder_name]
การบีบอัดไฟล์ ใช้คำสั่งดังนี้
zip [zip_name].zip [file_name]

การแตกไฟล์ผ่านทาง Command Line

ในกรณีที่ยังไม่เคยติดตั้ง unzip ให้รันคำสั่งดังนี้
apt-get install unzip
การแตกไฟล์ที่ถูกบีบอัด ใช้คำสั่งดังนี้
unzip [zip_name].zip

[PHP - Laravel] วิธีการตรวจสอบว่า Private key ที่ผู้ใช้งานใส่เข้ามาตรงกับ Public key ที่ตั้งค่าไว้หรือไม่
[PHP - Laravel] How to Verify Private Key with Existing Public Key

สืบเนื่องจากโพสต์ [Laravel - Model] การเข้ารหัสและถอดรหัสค่าของฟิลด์ใน Laravel Model โดยใช้ SSH Keys ที่ใช้ SSH keys ในการเข้ารหัสข้อมูล โดยที่เราตั้งค่า public key ไว้ในไฟล์ .env แต่เราให้ผู้ใช้งานเป็นผู้กรอก private key เอง แล้วเราจะรู้ได้อย่างไรว่า private key ที่ถูกกรอกเข้ามานั้น เป็นคู่ของ public key ที่เราตั้งค่าไว้จริงๆ

เรามีวิธีตรวจสอบ 2 วิธีดังนี้
  • การตรวจสอบด้วยการ sign และ verify signature
  • การตรวจสอบด้วยการ encrypt และ decrypt ข้อความ

การตรวจสอบด้วยการ sign และ verify signature

ขั้นตอนการตรวจสอบเป็นดังนี้
  1. เลือกข้อความมา 1 ข้อความ ข้อความอะไรก็ได้
  2. sign ข้อความนั้นด้วย private key ที่ผู้ใช้กรอกเข้ามา เพื่อสร้าง signature
  3. verify ข้อความนั้นกับ signature ที่เพิ่ง sign ด้วย public key ในระบบ
  4. ถ้า verify ไม่ผ่านจะเกิด exception ดังนี้

Wednesday, April 15, 2020

[MySQL] ระวังการใช้ mysqldump ในการ backup ฐานข้อมูลขนาดใหญ่ จะเกิดข้อผิดพลาด "Packet Too Large"
[MySQL] Warning: Using mysqldump to Backup Large Database May Cause "Packet Too Large" Error

หลังจากที่รัน mysqldump เพื่อ backup ฐานข้อมูลของโปรเจคนึง ก็เกิดข้อผิดพลาดดังนี้
mysqldump: Error 2020: Got packet bigger than 'max_allowed_packet' bytes when dumping table `failed_jobs` at row: 79
ข้อผิดพลาดข้างต้นเป็นข้อผิดพลาด Packet Too Large ที่มีระบุอยู่ใน MySQL Reference Manual ซึ่งสามารถเข้าไปอ่านเพิ่มเติมได้ที่ https://dev.mysql.com/doc/refman/5.7/en/packet-too-large.html

วิธีแก้ไขข้อผิดพลาดดังกล่าวมี 2 วิธีดังนี้
  1. เพิ่ม --max_allowed_packet=512M ตอนสั่งรัน mysqldump
  2. เพิ่ม max_allowed_packet=512M ไปในส่วนของ [mysqldump] ในไฟล์ my.cnf
หมายเหตุ 512M เป็นเพียงขนาดตัวอย่างเท่านั้น ขนาดใหญ่สุดที่เป็นไปได้ คือ 1024M

[GIT] การตั้งค่า Deploy Key ใน Gitlab
[GIT] How to Set Up Deploy Key in Gitlab

การตั้งค่า deploy key เป็นการตั้งค่า SSH key เฉพาะโปรเจคและใช้เป็น key สำหรับการ deploy เท่านั้น โดยปกติแล้ว key นี้จะอนุญาตให้ clone หรือ pull code จาก repository เท่านั้น ไม่อนุญาตให้ทำการ push code ที่แก้ไขขึ้นมายัง repository

สมมติว่า เราสร้าง SSH key ในเครื่อง server ของเราเรียบร้อยแล้ว (ข้อมูลเพิ่มเติม: การสร้าง SSH Key ใหม่)
  1. Login เข้า Gitlab
  2. เข้าไปที่โปรเจคของเรา
  3. เลือกเมนู Settings
  4. เลือกเมนู CI/CD
  5. เลื่อนลงไปยังส่วนของ Deploy Keys แล้วกดปุ่ม Expand
  6. กรอกข้อมูล Title เพื่อระบุว่า key นี้เป็นของเครื่องใด
  7. คัดลอกข้อมูลภายใน Public key ของ SSH แล้ววางลงในช่อง Key
  8. ไม่ต้องเลือกช่อง Write access allowed
  9. กดปุ่ม Add key
เพียงเท่านี้ เราก็สามารถใช้ Clone with SSH และ pull code จาก Gitlab ด้วย SSH key ของ server เราได้แล้ว โดยไม่จำเป็นต้องใส่ username และ password

Friday, April 10, 2020

[Laravel] การบันทึกไฟล์ JSON ใน Laravel Tinker
[Laravel] How to Save JSON File in Laravel Tinker

Tinker ช่วยให้เราสามารถตอบโต้กับ Laravel application ของเราทั้งหมดผ่านทาง command line ได้

เราสามารถเข้าใช้ Tinker ได้ โดยรันคำสั่งดังนี้
php artisan tinker
ส่วนใหญ่เราจะใช้ Tinker ช่วยในการตรวจสอบความถูกต้องของข้อมูลในฐานข้อมูล โดยเราจะใช้ Eloquent ในการ query ข้อมูลขึ้นมา และในบางครั้งเราต้องการส่งออกผลการ query ออกเป็นไฟล์ เพื่อนำไปตรวจสอบเพิ่มเติม

สมมติว่า เรา query ข้อมูลใน Tinker แล้วเก็บใส่ตัวแปรดังนี้
$users = User::all();
และเรามีการตั้งค่า disks ในไฟล์ config/filesystems.php ดังนี้
...
    'disks' => [
        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
        ],
...
การส่งออกผลการ query ข้างต้นออกเป็นไฟล์ JSON เราจะรันคำสั่งใน Tinker ดังนี้
Storage::disk('local')->put('users.json', json_encode((array) $users, JSON_PRETTY_PRINT));
ไฟล์ผลการ query ที่ถูกสร้างอยู่ที่ path storage/app/users.json

Wednesday, April 8, 2020

[Database - MySQL] วิธีการแก้ปัญหา Syntax Error เมื่อทำการสร้าง Procedure
[Database - MySQL] How to Fix Syntax Error when Creating a Procedure

สมมติว่า เราต้องการสร้าง procedure ด้วย SQL statement ข้างล่างนี้
CREATE PROCEDURE `my_procedure` (IN `_year` INT, IN `_month` INT)
    NO SQL
BEGIN
    SELECT * FROM my_table WHERE year = `_year`and month = `_month`;
END;
อย่างไรก็ตาม statement นี้ไม่สามารถรันได้ทุกฐานข้อมูล

บางฐานข้อมูลจะแสดงข้อผิดพลาดตามรูปข้างล่างนี้


[Laravel] ขั้นตอนการตั้งค่า XAMPP สำหรับรันโปรเจค Laravel
[Laravel] How to Set XAMPP to Run Laravel Project

สมมติว่า 
  • เรามี folder ชื่อ laravel ที่เป็น folder ของ project ที่เป็น Laravel
  • เราติดตั้ง XAMPP ไว้ที่ C:\xampp
  • เราต้องการเรียกหน้าเว็บของเราผ่าน domain ชื่อ laravel.dev
เราจะมีขั้นตอนดังต่อไปนี้

[Database - MySQL] การ Backup และ Restore ฐานข้อมูล MySQL ผ่านทาง Command Line
[Database - MySQL] How to Backup and Restore MySQL Databases via Command Line

การ Backup ฐานข้อมูล MySQL

การ backup ฐานข้อมูล เราจะใช้คำสั่ง mysqldump ซึ่งเป็นโปรแกรมที่ถูกลงมาพร้อมกับ MySQL software โดยเราจะใช้คำสั่งดังนี้
mysqldump -u [username] -p [database_name] > [filename].sql
โดย option ที่ใส่ได้มีดังนี้
  • -u [username] ใช้ระบุชื่อผู้ใช้งานที่ใช้ login เข้าฐานข้อมูล
  • -p[password] ใช้ระบุรหัสผ่านที่ใช้ login เข้าฐานข้อมูล
    (ถ้าไม่ระบุ [password] ระบบจะถามรหัสเมื่อสั่งรัน)
  • -h [host] ใช้ระบุ host ของฐานข้อมูล (ถ้าไม่ระบุ ค่าจะเป็นเครื่องที่รันคำสั่ง)
  • -P [port] ใช้ระบุ port ของฐานข้อมูล (ถ้าไม่ระบุ ค่าจะเป็น 3306)

การ Restore ฐานข้อมูล MySQL

การ restore ฐานข้อมูล เราจะใช้คำสั่ง mysql ร่วมกับไฟล์ SQL ที่ได้จากคำสั่ง backup ข้างต้น โดยเราจะใช้คำสั่งดังนี้
mysql -u [username] -p --default-character-set=[charset] [database_name] < [filename].sql
โดย option ที่ใส่ได้มีดังนี้
  • -u [username] ใช้ระบุชื่อผู้ใช้งานที่ใช้ login เข้าฐานข้อมูล
  • -p[password] ใช้ระบุรหัสผ่านที่ใช้ login เข้าฐานข้อมูล
    (ถ้าไม่ระบุ [password] ระบบจะถามรหัสเมื่อสั่งรัน)
  • ---default-character-set=[charset] ใช้ระบุ character set ของข้อมูลที่จะนำเข้าฐานข้อมูล

Thursday, April 2, 2020

[Blogger] วิธีการตั้งค่า Default Facebook Thumbnail สำหรับ Blogger
[Blogger] How to Set Default Facebook Thumbnail for Blogger

Default Facebook Thumbnail จะถูกใช้เมื่อเราแชร์โพสต์ของเราไปยัง Facebook แล้วโพสต์นั้นไม่มีรูปภาพประกอบ Facebook จะดึงข้อมูลภาพที่เราตั้งค่านี้มาแสดงในลิ้งค์แทน

วิธีการตั้งค่าภาพ Thumbnail ตั้งต้นเป็นดังนี้
  1. เข้าไปที่ Theme 
  2. เลือกเมนู Edit HTML 
  3. Copy script ด้านล่างไปใส่ไว้ในส่วนของ head ของ theme
    <b:if cond='data:blog.postImageUrl'>
    <meta expr:content='&quot;&quot; + data:blog.postImageUrl' property='og:image'/>
    <b:else/>
    <meta content= 'image_url' property='og:image'/>
    </b:if>
    
  4. แทนที่ image_url ใน script ข้างต้นด้วย URL ของรูปที่ต้องการ
  5. รอเวลาให้ Facebook อัพเดตข้อมูล ซึ่งใช้เวลาประมาณ 24 ชั่วโมง
หมายเหตุ สำหรับคนที่ไม่ต้องการรอ Facebook อัพเดตตามเวลา สามารถเข้าไปอ่านข้อมูลเพิ่มเติมได้ที่ [Facebook] วิธีการอัพเดตรูปภาพและรายละเอียดของ Link บน Facebook แบบ Manual

[Facebook] วิธีการอัพเดตรูปภาพและรายละเอียดของ Link บน Facebook แบบ Manual
[Facebook] How to Manually Updates The Thumbnail and Descriptions of Links on Facebook

เนื่องจาก Facebook จะอัพเดต thumbnail และรายละเอียดของ links ทุกๆ 24 ชั่วโมง ดังนั้นเมื่อเราแก้ข้อมูลภายใน links เราจำเป็นจะต้องรอการอัพเดต 24 ชั่วโมง

อย่างไรก็ตาม เราสามารถกดให้ Facebook อัพเดต links ของเราได้ด้วยตัวเราเอง เพื่อที่จะได้ไม่ต้องรอให้ครบ 24 ชั่วโมง ซึ่งมีวิธีการดังต่อไปนี้
  1. ไปที่ https://developers.facebook.com/tools/debug/

Wednesday, April 1, 2020

[Ubuntu] วิธีการตั้งค่า IP Address สำหรับ Host Name ที่ต้องการบน Ubuntu
[Ubuntu] How to Set IP Address for Specific Host Name on Ubuntu

ไฟล์ hosts เป็นไฟล์ที่ใช้สำหรับการระบุ IP address ของ host name ที่ต้องการ ซึ่งระบบปฏิบัติการจะเข้ามาหา IP address ของ host name ในนี้ก่อน ถ้าไม่พบจึงยิงไปขอข้อมูลจาก DNS server ต่อไป

สำหรับ Ubuntu ไฟล์ hosts ข้างต้นจะอยู่ที่ /etc/hosts

[Windows] วิธีการตั้งค่า IP Address สำหรับ Host Name ที่ต้องการบน Windows
[Windows] How to Set IP Address for Specific Host Name on Windows

ไฟล์ hosts เป็นไฟล์ที่ใช้สำหรับการระบุ IP address ของ host name ที่ต้องการ ซึ่งระบบปฏิบัติการจะเข้ามาหา IP address ของ host name ในนี้ก่อน ถ้าไม่พบจึงยิงไปขอข้อมูลจาก DNS server ต่อไป

สำหรับ Windows ไฟล์ hosts ข้างต้นจะอยู่ที่ C:\Windows\System32\drivers\etc\hosts

[PHP - Laravel] Closure คืออะไร
[PHP - Laravel] What is Closure?

Closure เป็น anonymous function ที่นิยมใช้เป็น callback method อีกทั้งยังสามารถใช้เป็น parameter ของ function ได้อีกด้วย

ตัวอย่างการใช้งาน

สมมติว่า เรามี function ชื่อ handle โดยที่ function นี้รับ parameter เป็น Closure ดังต่อไปนี้
function handle(Closure $closure) {
    $closure();
}
เวลาเราเรียกใช้งาน handle เราสามารถใส่ function ของเราเข้าไปเป็น parameter แบบนี้ได้เลย
handle(function(){
    echo __METHOD__;
});
นอกจากนั้น เราสามารถประกาศ function ของเราเก็บไว้ในตัวแปรก่อน แล้วค่อยส่งตัวแปรนั้นเป็น parameter แบบนี้ก็ได้
$myFunction = function(){
    echo __METHOD__;
});
handle($myFunction);

[Bash Script] วิธีการใช้วันที่และเวลาสำหรับชื่อไฟล์ในไฟล์ Bash
[Bash Script] How to Use Date and Time for Filename in Bash File

สำหรับค่าของวันที่และเวลาจะอยู่ในตัวแปรชื่อ date ซึ่งเราสามารถเรียกใช้ตามตัวอย่างดังนี้
echo `date`  # Wed Apr 1 06:22:11 UTC 2020
ในการจัดรูปแบบของวันที่และเวลา เราจะใช้คำสั่งในดังต่อไปนี้
echo `date +<format-option><format-option>...`
ยกตัวอย่างเช่น
echo `date +%Y%m%d`  # 20200401
กรณีที่เราต้องการตั้งชื่อไฟล์ โดยมีวันที่และเวลาในรูปแบบ yyyymmdd_hhmmss อยู่ในชื่อไฟล์ด้วย เราสามารถใช้คำสั่งดังนี้
filename=test_`date +%Y%m%d_%H%M%S`.zip
echo $filename
หมายเหตุ format-option สามารถอ่านเพิ่มเติมได้ที่ Bash Date – Format Options and Examples

Thursday, March 19, 2020

[PHP - Laravel] Trait คืออะไร?
[PHP - Laravel] What is Trait?

ปัญหานึงของการเขียนโปรแกรมด้วยภาษา PHP คือ class 1 class สามารถ inherit จาก class อื่นได้เพียง class เดียวเท่านั้น (single inheritance) ทำให้ไม่สามารถ inherit method ที่ต้องการใช้จาก class อื่นๆ เพื่อลดความซ้ำซ้อนของโค้ดได้

Traits เป็นกลไกสำหรับการใช้ code ซ้ำในภาษาที่เป็น single inheritance เช่น PHP

Traits มีความคล้ายคลึงกับ class ต่างกันที่ Traits เป็นเพียงกลุ่มของ method เท่านั้น จึงไม่สามารถเรียกใช้งานแบบ instance ได้ นอกจากนั้น มันยังมีความสามารถเพิ่มเติม คือ การเรียกใช้ class member ของ class ที่เรียกใช้มันได้ โดยไม่ต้อง inherit อีกด้วย

[Bash Script] รู้หรือไม่ว่า ส่วนหัวของ Bash Script ที่เป็นเครื่องหมาย #! มีไว้ใช้ทำอะไร
[Bash Script] What does the Head of a Script (#! Line) do?

เครื่องหมาย #! (she-bang) ในส่วนของหัว script ใช้เพื่อระบุว่า กลุ่มของคำสั่งในไฟล์นี้ต้องใช้  command interpreter ตัวใด

ส่วนข้อความหลังเครื่องหมาย #! คือ path ของโปรแกรมที่ใช้ประมวลผลคำสั่งใน script ซึ่งอาจะเป็น shell, programming language หรือโปรแกรมอื่นๆ

command interpreter นี้จะเริ่มประมวลผลคำสั่งใน script เริ่มต้นจากบรรทัดใต้เครื่องหมาย #! เป็นต้นไปและข้ามบรรทัดที่เป็น comment

ตัวอย่างของบรรทัดที่เป็น she-bang เป็นดังนี้

#!/bin/sh
#!/bin/bash
#!/usr/bin/perl
#!/usr/bin/tcl
#!/bin/sed -f
#!/bin/awk -f

หมายเหตุ โดยปกติแล้ว จะใช้ #!/bin/sh และ #!/bin/bash เป็นหลัก

Tuesday, March 10, 2020

[Docker - MySQL] การใช้ Docker Image MySQL โดยไม่ระบุเลขเวอร์ชั่นของ Patch ใน Tag อาจทำให้ได้ Docker Image เวอร์ชั่นที่เราไม่ได้คาดการณ์ไว้
[Docker - MySQL] Using Docker Image MySQL without Patch Version Number in Tag May Cause Using Unpredictable Docker Image Version

หลังจากที่ใช้ Docker Image สำหรับ MySQL 5.7 มาหลายโปรเจค 

วันนึงมีโปรเจคที่ต้องรัน SQL เพื่อ insert ข้อมูลภาษาไทยลงฐานข้อมูล ปรากฏว่า SQL ดังกล่าวสามารถรันบน environment ที่เป็น  UAT ได้ แต่ไม่สามารถรันบน Production ได้ ทั้งที่โค้ดและเลข Tag ของ Docker Image ก็เป็นเวอร์ชั่นเดียวกัน

หลังจากหาสาเหตุอยู่นาน พบว่า ถึงแม้จะใช้เลข Docker Tag เดียวกัน คือ 5.7 แต่เวอร์ชั่นของ MySQL ภายในแต่ละ Docker Image แตกต่างกัน ดังรูปข้างล่าง

Image mysql:5.7 ที่ถูกสร้างวันที่ 12/12/2017 จะใช้ MySQL version 5.7.20

[Security] วิธีการแก้ไขข้อผิดพลาด "Couldn't load this key (OpenSSH-SSH-2 private key (old PEM format))" ใน TortoiseGit สำหรับ Windows
[Security] How to Fix Error "Couldn't load this key (OpenSSH-SSH-2 private key (old PEM format))" in TortoiseGit for Windows

เมื่อสร้าง SSH2 RSA key ด้วย ssh-keygen เราจะได้ไฟล์ id_rsa และ id_rsa.pub

หลังจากที่เราเอา id_rsa.pub ไปตั้งค่าบน Git Repository แล้ว เราต้องใช้ไฟล์ id_rsa ใน TortoiseGit สำหรับ Windows เพื่อ clone code จาก Git Repository ลงมายังเครื่อง ดังรูปข้างล่างนี้

[Docker - MySQL] วิธีการหลีกเลี่ยงกรณีที่ไม่สามารถรัน mysql:5.7 container ได้ เนื่องจากมีข้อผิดพลาด "Operating system error number 22 in a file operation"
[Docker - MySQL] Workaround for mysql:5.7 Container Cannot Start Due to "Operating system error number 22 in a file operation"

เนื่องจากมีหลายโปรเจคที่ใช้ฐานข้อมูลเป็น MySQL ผมจึงรัน MySQL Docker ผ่านทาง Docker Compose (บน Docker Toolbox ของ Windows) เพื่อใช้เป็นฐานข้อมูล ซึ่งจะมีการตั้งค่าในส่วน mysql service ใน docker-compose.yml ตามด้านล่างนี้
mysql:
    container_name: mysqlserver
    image: mysql:5.7
    ports:
        - 3306:3306
    volumes:
        - ./mysql:/var/lib/mysql
อย่างไรก็ตาม ปัญหานึงที่ผมเจอ คือ Container ของ MySQL จะหยุดการทำงาน เมื่อรันไปสักพัก เมื่อตรวจสอบ Log ของ Container จะเจอ error ดังนี้
2020-03-06T08:39:40.454013Z 0 [ERROR] InnoDB: Operating system error number 22 in a file operation.
2020-03-06T08:39:40.454196Z 0 [ERROR] InnoDB: Error number 22 means 'Invalid argument'
2020-03-06T08:39:40.454258Z 0 [ERROR] InnoDB: File ./ib_logfile101: 'aio write' returned OS error 122. Cannot continue operation
2020-03-06T08:39:40.454584Z 0 [ERROR] InnoDB: Cannot continue operation.
จากการตรวจสอบเบื้องต้นยังไม่สามารถหาวิธีแก้ไขได้ แต่มีวิธีการหลีกเลี่ยง error ข้างต้นไม่ให้เกิดขึ้น  โดยแก้ไขการตั้งค่าในส่วน mysql service ใน docker-compose.yml ดังนี้
mysql:
    container_name: mysqlserver
    image: mysql:5.7
    ports:
        - 3306:3306
    # volumes:
    #     - ./mysql:/var/lib/mysql

Thursday, February 27, 2020

[Blogger][แก้ไขเพิ่มเติม] การทำ Code Snippet สำหรับ Blogger ที่เป็น HTTPS
[Blogger][Updated] How to Make Code Snippet for Blogger (HTTPS version)

จากโพสต์ [Blogger] การทำ code snippet สำหรับ Blogger ที่เป็น HTTPS ที่เรียกใช้ resource จาก https://agorbatchev.typepad.com ปรากฏว่า เมื่อเวลาผ่านไป มีบาง resource ที่ไม่สามารถเรียกใช้ได้ เช่น shThemeDefault.css เป็นต้น

เราจึงนำไฟล์ resource ทั้งหมดที่จำเป็นต้องใช้ไปไว้ที่ GitHub แล้วทำการเปิด GitHub Pages สำหรับ repository นี้

หลังจากนั้นแก้ไขการเรียกใช้ resource จาก GitHub แทนดังนี้
  1. เข้าไปที่ Theme 
  2. กดปุ่ม Edit HTML ภายใต้ Live on Blog
  3. Copy script ด้านล่างไปใส่ไว้ในส่วนของ head ของ theme
  4. <link href='https://arzeroid.github.io/syntaxhighlighter_css_js/css/shCore.css' rel='stylesheet' type='text/css'/>
    <link href='https://arzeroid.github.io/syntaxhighlighter_css_js/css/shThemeDefault.css' rel='stylesheet' type='text/css'/>
     
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shCore.js' type='text/javascript'/>
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shBrushBash.js' type='text/javascript'/>
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shBrushCpp.js' type='text/javascript'/>
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shBrushCSharp.js' type='text/javascript'/>
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shBrushCss.js' type='text/javascript'/>
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shBrushJava.js' type='text/javascript'/>
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shBrushJScript.js' type='text/javascript'/>
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shBrushPlain.js' type='text/javascript'/>
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shBrushPhp.js' type='text/javascript'/>
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shBrushPython.js' type='text/javascript'/>
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shBrushRuby.js' type='text/javascript'/>
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shBrushSql.js' type='text/javascript'/>
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shBrushVb.js' type='text/javascript'/>
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shBrushXml.js' type='text/javascript'/>
    <script src='https://arzeroid.github.io/syntaxhighlighter_css_js/js/shBrushPerl.js' type='text/javascript'/>
    <script language='javascript'>
        SyntaxHighlighter.config.bloggerMode = true;    
        SyntaxHighlighter.all();
    </script>
    
  5. กดปุ่ม Save theme
  6. ใส่ code ตามด้านล่างในส่วนของ HTML ของ Post
  7. <pre class="brush: html">
        <link href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' rel='stylesheet' type='text/css'/>
        <link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/>
    </pre>
    
หมายเหตุ: เราไม่จำเป็นต้องใส่ brush ทุกอันในข้อ 3 สามารถเลือกเฉพาะอันที่ใช้เท่านั้นได้ สำหรับ brush เพิ่มเติม สามารถดูได้จาก http://alexgorbatchev.com/SyntaxHighlighter/manual/brushes/

[GitHub] การสร้างเว็บไซต์จาก Repository บน GitHub
[GitHub] How to Create Website from Repository on GitHub

  1. สร้าง Repository บน GitHub
  2. เพิ่มไฟล์สำหรับหน้าเว็บ เช่น index.html, ไฟล์ CSS, ไฟล์ JS เป็นต้น ใน repository นั้น
  3. เข้าไปที่แท็บ Settings ของ repository นั้น
  4. เลื่อนลงไปยังส่วนของ GitHub Pages
  5. เลือก Source เป็น branch ที่เราเพิ่มไฟล์เข้าไปตามข้อ 2
  6. เรียกหน้าเว็บผ่าน URL ในรูปแบบดังนี้
  7. https://<username>.github.io/<repository_name>/<file_path>
    
    เช่น
    https://arzeroid.github.io/syntaxhighlighter_css_js/css/shThemeDefault.css

Wednesday, February 26, 2020

[Laravel - Package] การเข้ารหัสและถอดรหัสข้อความโดยใช้ SSH keys
[Laravel - Package] String Encryption and Decryption by Using SSH Keys

การเข้ารหัสและถอดรหัสข้อความโดยใช้ SSH keys ใน Laravel เราจะใช้ package ชื่อ phpseclib

สำหรับตัวอย่างการเข้ารหัสและถอดรหัสเป็นดังนี้
use phpseclib\Crypt\RSA;
...

$publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCEa1ivzN/iW1wBTyT1T6uPcDKzi3HlCBCp3ro61ZxA1byilNH/TP7HW3iFAh0A0Lyk7dZ7d6Ot4jdsXc783T+Ic0n2Blfh0kCm0ci7q2qXqOLpCa6N30LQyiDofSmaLRzQlD49kjVY8GJYrdqo7lEQvBupenJzjS71LgkIqq+BeQIDAQAB';

$privateKey = 'MIICXQIBAAKBgQCEa1ivzN/iW1wBTyT1T6uPcDKzi3HlCBCp3ro61ZxA1byilNH/TP7HW3iFAh0A0Lyk7dZ7d6Ot4jdsXc783T+Ic0n2Blfh0kCm0ci7q2qXqOLpCa6N30LQyiDofSmaLRzQlD49kjVY8GJYrdqo7lEQvBupenJzjS71LgkIqq+BeQIDAQABAoGAVfYZrIYjEJ6eK3tlUppVlNgREd0EItoJdzzPSEJDHROjUSeq60DgZCpNIossqMrYq3h6M8yGxOqFcCO1qxE1nDhwMRxNYALnM8yBfVTe/RfASD7A+XLBB4HKOPPAs7HjPj6rdJpTSLxSNFXW7lMmw+AUTuI1B5TTqINWR83rewECQQDrYAXjdB9/Xg2x+tW6kBh3Dcdm12d3bTIXklfVeds4/3tvJyZkWi/FnNAkZLG40+R39xzP2s+XbN4Ul14aok4VAkEAkAXNBC++X+91esEIwTf4RTMxn7Q/m5F9j7G827bTWUJ+oPCoCnmdLth+9QfMyVboo4D7P8w+trm665+emV7i1QJBALdBZrRFh/RxdPY6VkdPw0yGFNb0JKFuCg8iKHKT0mPZPfA3qgN92C3iPofnQhumFf51DiCiuvepkmqzw1e3QFUCQEDznMYqkfzKDX1S2RPqnfj3YYXY0Gbkcm//hGDCTwaOSnVikyZGOnEKChePcPfMThaO8MCQ6CeYE4h38BrTBBECQQDDp8w+aItksMhcLGIyPRZZmlLew6ic+Pv+8fES9apzy/13MbBpxm/oPVavftLQi+6N29eTtqbE7lL1hRcdsUqn';

$plaintext = 'test';

$rsa = new RSA();

$rsa->loadKey($publicKey);
$ciphertext = $rsa->encrypt($plaintext);

$rsa->loadKey($privateKey);
echo $rsa->decrypt($ciphertext);
สำหรับตัวอย่างการ Verify key เป็นดังนี้
$plaintext = 'ThisIsTest';

$rsa = new RSA();
$rsa->loadKey($privateKey);
$signature = $rsa->sign($plaintext);

$rsa->loadKey($publicKey);
$rsa->verify($plaintext, $signature); // Throw exception if verification is failed

Tuesday, February 25, 2020

[Laravel - Model] การเข้ารหัสและถอดรหัสค่าของฟิลด์ใน Laravel Model โดยใช้ SSH Keys
[Laravel - Model] Field Values Encryption and Decryption in Laravel Model by Using SSH Key

สืบเนื่องจากโพสต์ [Laravel - Model] การเข้ารหัสและถอดรหัสค่าของฟิลด์ใน Laravel Model ที่เราเข้ารหัสข้อมูลก่อนเก็บลงฐานข้อมูล โดยใช้การเข้ารหัสและถอดรหัสของ Laravel ซึ่งใช้ APP_KEY ใน .env เป็น key ทำให้คนที่เข้าถึง application สามารถถอดรหัสข้อมูลได้

เพื่อเพิ่มความปลอดภัยขึ้นไปอีกขั้น เราจะเปลี่ยนจากการใช้ APP_KEY ใน .env เป็น SSH Keys ซึ่งแยกเป็น Public key และ Private key แทน โดยเราจะได้เพียง Public key มาใช้ในการเข้ารหัส แต่คนมีสิทธิ์ดูข้อมูลเท่านั้นที่จะมี Private key เพื่อใช้ถอดรหัสข้อมูล

Thursday, February 20, 2020

[Bash Script] การสร้าง Link ระหว่าง File หรือ Folder
[Bash Script] How to Create Link between File or Folder

การสร้าง link file หรือ folder จะช่วยเพิ่มความสะดวกในการใช้งาน

สมมติว่า เราต้องเข้าไปที่ folder /usr/share/nginx/myweb ทุกครั้ง เพื่อแก้ไขหน้าเว็บ

เราสามารถสร้าง link /usr/share/nginx/myweb มาที่ folder /app

หลังจากนั้น หากเราต้องการแก้ไขหน้าเว็บ สามารถเข้าไปที่ /app/myweb ได้เลย

คำสั่งสำหรับสร้าง link file เป็นดังนี้
ln source_file destination_folder
เช่น
ln /usr/share/nginx/myscript.sh ~/app/

Thursday, February 6, 2020

[GIT] การตั้งค่า SSH Key ใน Github
[GIT] How to Set Up SSH Key in Github


สมมติว่า เราสร้าง SSH key ในเครื่องของเราเรียบร้อยแล้ว
  1. Login เข้า Github 
  2. เข้าไปที่ https://github.com/settings/keys
  3. กดปุ่ม New SSH key
  4. กรอกข้อมูล Title เพื่อระบุว่า key นี้เป็นของเครื่องใด
  5. คัดลอกข้อมูลภายใน Public key ของ SSH แล้ววางลงในช่อง Key
  6. กดปุ่ม Add SSH key
เพียงเท่านี้ เราก็สามารถใช้ Clone with SSH จาก Github ด้วย SSH key ของเราได้แล้ว โดยไม่จำเป็นต้องใส่ username และ password ทุกครั้ง รวมถึงการทำ Git operation อื่นๆ เช่น การ push, การ pull เป็นต้น

[GIT] การตั้งค่า SSH Key ใน Gitlab
[GIT] How to Set Up SSH Key in Gitlab

สมมติว่า เราสร้าง SSH key ในเครื่องของเราเรียบร้อยแล้ว
  1. Login เข้า Gitlab
  2. เข้าไปที่ https://gitlab.com/profile/keys
  3. กรอกข้อมูล Title เพื่อระบุว่า key นี้เป็นของเครื่องใด
  4. คัดลอกข้อมูลภายใน Public key ของ SSH แล้ววางลงในช่อง Key
  5. กดปุ่ม Add key
เพียงเท่านี้ เราก็สามารถใช้ Clone with SSH จาก Gitlab ด้วย SSH key ของเราได้แล้ว โดยไม่จำเป็นต้องใส่ username และ password ทุกครั้ง รวมถึงการทำ Git operation อื่นๆ เช่น การ push, การ pull เป็นต้น

Wednesday, February 5, 2020

[Docker] วิธีการเปลี่ยน Shell ตั้งต้นใน Image และระหว่าง Build
[Docker] How to Change Default Shell in Your Image and During Build

Shell ในระบบปฏิบัติการส่วนใหญ่มีมากกว่า 1 แบบ เช่น ใน Windows จะมี cmd และ PowerShell หรือใน Ubuntu จะมี /bin/sh และ /bin/bash

ถ้าหากเราต้องการเปลี่ยน Shell ตั้งต้นใน Image และช่วงระหว่าง Build เราสามารถใช้คำสั่ง SHELL ของ Dockerfile ดังนี้
SHELL ["/bin/bash", "-c"]

Friday, January 17, 2020

[System] การตั้งค่า Crontab เพื่อรันภายใต้ผู้ใช้งานที่ระบุ
[System] How to Run Crontab with Specific User

ในบางครั้งเราต้องการรัน cron ภายใต้ผู้ใช้งานที่เราระบุ ยกตัวอย่าง เช่น การรัน schedule ของ Laravel การไม่ระบุผู้ใช้งาน อาจจะทำให้เกิดปัญหาขึ้นได้ (อ่านเพิ่มได้ที่ [Laravel - Scheduler] ระวัง!!! การไม่กำหนด username ใน Cron Entry สามารถทำให้เกิด "Permission Denied" ได้)

การระบุผู้ใช้งานที่รัน cron สามารถระบุได้ 2 แบบดังนี้
  1. การตั้งค่า cron ในไฟล์ /etc/crontab หรือไฟล์ใน /etc/cron.d/ สามารถเพิ่ม cron entry ที่มี username ได้เลย ดังนี้
  2. * * * * * username /path/to/your/script.sh
    
  3. การตั้งค่า cron ภายใต้ user ที่ต้องการ สามารถรันคำสั่งดังนี้ 
  4. sudo crontab -u username -e
    
    หลังจากนั้น เพิ่ม cron entry ดังนี้
    * * * * * /path/to/your/script.sh
    
หมายเหตุ ไม่สามารถใช้ crontab entry แบบที่ 1 เพิ่มลงในการตั้งค่า cron แบบที่ 2 เนื่องจาก /path/to/your/script.sh จะไม่ถูกรัน

Wednesday, January 15, 2020

[Security] วิธีการดูข้อมูลใน ไฟล์ PFX บน Windows
[Security] How to View Content of PFX File on Windows

ไฟล์ PFX เป็นไฟล์ที่ใช้เก็บ certificates ทั้งหมดรวมถึง private key ที่เกี่ยวข้องด้วย ซึ่งไฟล์นี้จะมีการป้องกันด้วยรหัสผ่าน ในกรณีนี้เราใช้ไฟล์นี้ในการทำ Digital Signature

สำหรับวิธีดูข้อมูลในไฟล์ PFX สามารถรันคำสั่งใดคำสั่งหนึ่งข้างล่างนี้

  1. รันคำสั่งนี้ใน command prompt
  2. certutil -dump <path_to_cert>
    

  3. รันคำสั่งนี้ใน Windows PowerShell
  4. Get-PfxCertificate -FilePath <path_to_cert>
    

Monday, January 6, 2020

[Security] วิธีการบีบอัดไฟล์ ZIP พร้อมเข้ารหัสและถอดรหัสด้วย Public และ Private Keys
[Security] How to Create ZIP Files with Encryption and Decryption using Public and Private Key


สมมติว่า
  1. เราสร้าง Private key ชื่อ key.pem และ Public key ชื่อ pub.pem ด้วย OpenSSL แล้ว
  2. เราต้องการสร้าง ไฟล์ ZIP ชื่อ archive.7z 

วิธีการบีบอัดและเข้ารหัสไฟล์ ZIP

  1. สร้างรหัสผ่านด้วยการสุ่ม
  2. เข้ารหัสรหัสผ่านด้วย pub.pem แล้วบันทึกลงไฟล์ข้อความ archivePassword.ssl
  3. บีบอัดไฟล์ข้อความดังกล่าว archivePassword.ssl เข้าไปใน archive.7z โดยไม่กำหนดรหัสผ่าน
  4. บีบอัดแฟ้มหรือไฟล์ที่ต้องการเข้าไปเพิ่มใน archive.7z ด้วยรหัสผ่านตามข้อ 1

วิธีการถอดรหัสและแตกไฟล์ไฟล์ ZIP

  1. แตกไฟล์ข้อความ archivePassword.ssl จาก archive.7z
  2. ถอดรหัสข้อความภายใน archivePassword.ssl  ด้วย key.pem เพื่อให้ได้รหัสผ่านสำหรับแตกไฟล์
  3. แตก archive.7z ส่วนที่เหลือด้วยรหัสผ่านที่จากข้อ 2 เพื่อให้ได้แฟ้มหรือไฟล์ที่ต้องการ
สำหรับคนที่ต้องการใช้งานสคริปต์สำเร็จรูป สามารถดูได้ที่ https://github.com/arzeroid/e7z

หมายเหตุ สาเหตุที่ไม่เข้ารหัสไฟล์ ZIP ทั้งไฟล์ เพราะจะใช้เวลานานทั้งตอนเข้ารหัสและถอดรหัส จึงเข้ารหัสและถอดรหัสแค่รหัสผ่านเท่านั้น

[Laravel - Scheduler] ระวัง!!! การไม่กำหนด username ใน Cron Entry สามารถทำให้เกิด "Permission Denied" ได้
[Laravel - Scheduler] Warning!!! Adding Cron Entry without Specify Username May Cause "Permission Denied"

จากตัวอย่างใน Starting The Scheduler จะกำหนดให้ใส่ cron entry ดังนี้
 
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
ถ้าหากเราตั้งค่าข้างต้นใน crontab ของ root จะมีผลทำให้ folder ที่ถูกสร้างโดย Laravel command ที่ถูกรัน เป็นสิทธิ์ root ทันที

ผลกระทบ คือ เมื่อ controller พยายามเขียนไฟล์หรือสร้าง folder ภายใน folder ดังกล่าว จะเกิด Permission Denied ขึ้น ซึ่งอาจจะทำให้หน้าเว็บไม่สามารถใช้งานได้เลย

วิธีการป้องกัน คือ ให้ใส่ cron entry โดยกำหนด username ที่รันเป็น user ที่ใช้รัน web server ดังนี้
 
* * * * * username cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
โดยปกติแล้ว username ที่รัน PHPFPM จะเป็น www-data ดังนั้น cron entry จะเป็นดังนี้
 
* * * * * www-data cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

หมายเหตุ กรณีที่สร้าง folder ด้วยสิทธิ์ root ไปแล้ว ให้แก้ไขโดยใช้คำสั่งดังนี้
 
chown username folder_name
เช่น
 
chown www-data storages