AdSense 新加坡稅務資訊相關申請與設定教學

最近 Google AdSense 開始要台灣的 AdSense 使用者提交新加坡稅務資訊了。這是因為台灣的 AdSense 是透過 Google Asia 付款,而他們的地點設在新加坡。目前新加坡似乎還尚未開始扣稅,但如果之後法律要求預扣稅款,支付的款項可能會扣除較高的扣繳稅額。

先說一下,雖然不是很複雜,但整個過程其實需要點時間,主要是因為需要跟國稅局申請「稅務居住地證明」這個文件,且每年需要重新申請並去Adsense更新。以下就是整個申請與設定流程:

先到財政部稅務入口網,填寫申請表格。可以選要用自然人憑證登入或是以健保卡登入。

閱讀全文 AdSense 新加坡稅務資訊相關申請與設定教學

判斷上傳的圖片格式

當我們想要限制上傳檔案的格式時,最簡單的方式是檢查副檔名或Mime types,不過如果該檔案被更改過副檔名的話,這個檢查就沒意義了。好在我們可以透過各種檔案格式的「魔術數字」來檢查該檔案的內容是否真的符合副檔名所對應的格式。

所謂的「魔術數字」指的是各種不同的檔案開頭的幾個固定字節。比如說 .jpg 或 .jpeg 的檔案,開頭都固定是“ffd8ffe0”,.png 的檔案,開頭都固定是 “89504e47”。我們可以在檔案上傳後存檔前,檢查檔案是否有符合這個規則,若符合再將檔案儲存。

以下是 node.js 檢查上傳圖片格式的程式碼範例:

import express from 'express'
// express middleware for multipart/form parsing
import multer from 'multer'
import fs from 'fs'
import path from 'path'

const app = express()
const port = 5438

// 因為這個範例中,想先檢查副檔名是否符合檔案格式再儲存
// 因此我們使用 multer 的 memoryStorage,這樣我們就可以在 file 物件中使用 buffer 來檢查
// 不過使用 memoryStorage 時,最好限制一下檔案大小,否則上傳大檔時,會很消耗主機記憶體
const storage = multer.memoryStorage()
const upload = multer({
  storage,
  fileFilter (req, file, cb) {
    const ext = path.extname(file.originalname)

    const acceptFormats = ['.webp', '.jpg', '.jpeg', '.png', '.gif', '.svg']
    if (!acceptFormats.includes(ext)) {
      return cb(new Error('Only images are allowed'))
    }

    cb(null, true)
  },
  limits: {
    // 限制上傳檔案大小 (bytes)
    fileSize: 1000000
  }
})

app.post('/upload', upload.array('files'), (req, res, next) => {
  if (req.files && req.files.length) {
    req.files.forEach(file => {
      const filename = new Date().getTime() + '_' + Math.floor(Math.random() * 1E+12)
      file.newfilename = filename
      const ext = path.extname(file.originalname)
      const newpath = 'uploads/' + filename + ext

      // 在這邊檢查圖片格式符不符合副檔名
      const needsCheckFormats = ['.webp', '.jpg', '.jpeg', '.png', '.gif']
      const magicMatch = {
        '.jpg': 'ffd8ffe0',
        '.jpeg': 'ffd8ffe0',
        '.png': '89504e47',
        '.gif': '47494638',
        '.webp': '52494646'
      }

      // 檔案是否需要檢查
      if (needsCheckFormats.includes(ext)) {
        const magic = file.buffer.toString('hex', 0, 4)

        if (magic && magic === magicMatch[ext]) {
          // 檢查完畢,符合格式,存起來
          fs.appendFileSync(newpath, file.buffer)
        } else {
          // 檢查完畢,不符合格式,在 file 物件中做紀錄
          file.err = 'File format does not match file ext'
        }
      } else {
        // 不需檢查的svg直接存
        fs.appendFileSync(newpath, file.buffer)
      }
    })
  }

  console.log(req.files)
  res.send('OK')
})

app.listen(port, () => {
  console.log(`Server for testing image upload is listening on port ${port}`)
})

以上是最常用的圖片上傳的判斷,其他還有很多魔術數字,下面列出一些常用的。其他可以參考 https://gist.github.com/leommoore/f9e57ba2aa4bf197ebc5 或 https://asecuritysite.com/forensics/magic

副檔名魔術數字
.gif47 49 46 38
.jpg / .jpegff d8 ff e0
.png89 50 4e 47
.tif / .tiff4d 4d 00 2a / 49 49 2a 00
.zip50 4b 03 04
.pdf25 50 44 46
.mp400 00 00 18 66 74 79 70 6D 70 34 32
.mp349 44 33
.docD0 CF 11 E0 A1 B1 1A E1
.xlsD0 CF 11 E0 A1 B1 1A E1
.psd38 42 50 53

用 color-mix() 處理CSS原生變數的顏色透明度

以往如果我們要在 css 中,對一個顏色變數做透明度處理,第一個想到的應該是透過 sass 的 color module 來處理。但如果我們是要在 runtime 處理一個 css 的原生變數呢?可能會有人想到把 rgb 拆成三個變數,再透過 rgba(var(–r), var(–g), var(–b), 0.5) 這種形式來改變透明度,相同的原理也能套用到 hsla 等等的 css 色彩函式中。

拆開變數的這個做法雖然可行,且在應用上可以很靈活,但同時也增加了變數的數量、造成閱讀與維護時的難度。

這時候不妨試試看 color-mix 函數來對顏色做透明度處理,且除了透明度以外,color-mix 其實本來是用來混合兩個顏色用的。且目前看起來各瀏覽器已經都普遍支援了(除了IE,但現在還有誰管它),請放心使用。

目前已經普遍支援各瀏覽器
閱讀全文 用 color-mix() 處理CSS原生變數的顏色透明度

用 View Transitions API 快速做出有趣的換頁動態吧

如果有在做 Native-like 的 Web Application 的人,應該都曾為了要做到像是 Native 的頁面轉換動態而絞盡腦汁。現在 View Transitions API 提供一種輕鬆創建不同 DOM 狀態之間的動畫轉換的機制。該 API 目前只能用於單一頁面中的 DOM 狀態轉換,但正在計劃支援於同 Domain 的不同頁面間的轉換。目前(2023/09)雖然僅有 Chrome, Edge, Opera 三個瀏覽器支援,但相信未來勢必會成為做動態時很重要的一環。

目前僅Chrome, Edge, Opera 三個瀏覽器支援
閱讀全文 用 View Transitions API 快速做出有趣的換頁動態吧

自動更新 Linode Object Storage SSL/TLS憑證

前一篇文章,我們了解了如何自訂Linode Object Storage的網域,但因Object Storage需要自己手動上傳SSL憑證,且Let’s Encrypt的憑證90天會到期,因此每到即將過期的時間,勢必就得再手動更新一次。因此,這篇就要繼續來了解,如何自動更新憑證。

閱讀全文 自動更新 Linode Object Storage SSL/TLS憑證

Linode Object Storage 自訂網域設定與大阪region Cyberduck設定

Custom Domain 步驟

開好 Linode 的 Object Storage 之後,常常覺得網址有夠長,查了一下自訂網域的方式。跟 AWS 比起來麻煩多了,還要自己用 Certbot 手動建立 ssl 憑證,而這也意味著會遇到無法自動更新憑證的問題。之後會再介紹用 API 更新憑證的方法,這篇的重點就先放在整個設定的步驟。

閱讀全文 Linode Object Storage 自訂網域設定與大阪region Cyberduck設定

[歌詞翻訳] Workin‘ Hard – 藤井風

掻っ攫った(かっさらう 「さらう」の乱暴な言い方) 圧巻(あっかん)でらした あらら 世は実に易し
信じ切った 安心し切った あたた 深き喜び
戦うは なぎ倒すは か弱い己自身さ
やり切って胸はって 綺麗に散るのさ~

奪得獎杯了 壓軸的驚人之舉 哎呀 這世界就是這麼簡單
徹底相信 徹底鬆了口氣 溫暖又深刻的喜悅
戰爭要打倒的是軟弱的自己
抬頭挺胸戰到最後 然後美麗地殞落

閱讀全文 [歌詞翻訳] Workin‘ Hard – 藤井風

[筆記] Critical Render Path 與 Reflow, Repaint

Critical Render Path

讀取 html => 產生 DOM Tree => 產生 CSSOM Tree => 產生 Render Tree => Layout => Paint => Compositing

Layout做的事情

依照樣式表與元素的可視與否,計算每個元素的尺寸、位置

Paint做的事情

繪製每個Layout的文字、顏色、圖片、透明度、transform。也就是把Layout轉為實際視覺上的結果。

Compositing做的事情

將所有的Layout組合起來

閱讀全文 [筆記] Critical Render Path 與 Reflow, Repaint

Nuxt Hydration Fails – SSR與CSR的比對錯誤

在 Nuxt 中,當我們 refresh 頁面時,寫在 data 或 computed 中的程式碼,在 server 端與 client 端都會各執行一次,並且在前端會進行html tag的比對,若兩者不相符會噴錯,甚至沒有辦法進行接下來的操作。

因此,當我們用了 new Date().getTime(), Math.random() 這類的程式碼在data中,是一定會造成錯誤的。甚至 new Date().getDay() 也是有可能,因為 server time 有很大的可能性,跟 client 端的時區不同。最後我們再來看看如何解決,我們先來看看相同的程式碼,在 Nuxt2 與 Nuxt3 分別會導出怎樣的結果。

閱讀全文 Nuxt Hydration Fails – SSR與CSR的比對錯誤

PM2 watch 造成的無限迴圈

pm2 的 watch 是用於監聽檔案變動,自動重啟服務的一個功能。我們可以透過在 pm2.config.js 檔案中設定 watch: true 來開啟此功能。這樣一旦進了新 code 就會自動重啟,不用手動 pm2 restart {id} 非常方便。

但也就是因為這麼方便,所以常常會忘了他的存在。

前陣子做了一個透過排程,自動到某處去下載json檔案回來存放,再提供一隻API來吐出篩選過的資料的小工具。在開發環境完成後,一樣就很順手的在正式環境用PM2跑起來。

閱讀全文 PM2 watch 造成的無限迴圈

在dockerfiles中使用aws ecr image

這篇文章主要是筆記如何在本機使用AWS ECR上已存在的image,以及所需要的驗證方式。

首先到AWS ECR選擇你的repo,進入映像列表後選擇一個映像,在內頁複製他的URI,像是:735675645655.dkr.ecr.ap-northeast-1.amazonaws.com/my_project:23f4b2a。打開你的Dockerfile,將FROM後面的映像名稱改成這個URI

閱讀全文 在dockerfiles中使用aws ecr image

虎蘭市的貓咪祭典:一場別具風味的活動

每年的11月,在日本埼玉縣的虎蘭市,都會舉行一個別具風味的祭典「にゃんにゃん祭り」(喵喵祭)主題也就是貓咪。這個祭典吸引了大量的遊客和當地居民,讓他們能夠欣賞到一場獨特而令人興奮的活動。這個祭典集結了山車遊行、攤販市集和寵物認養活動,讓人們能夠在這一天與貓咪們共度美好時光。

造型可愛、尺寸壯觀的赤面貓花車

一到了祭典的那一天,整個虎蘭市都被貓咪的氛圍所包圍。大街小巷裡,隨處可見以貓咪造型為主題的山車或花車,有些以傳統山車的形式呈現,但都以貓咪為靈感,栩栩如生。山車會以貓奔跑的速度高速在街上來回奔馳,給人一種刺激又有點小小的危險的感覺。也因此,拉山車的工作人員在活動開始前,都要先上虎蘭山上祈求貓神保佑,以確保活動的順利舉行。

閱讀全文 虎蘭市的貓咪祭典:一場別具風味的活動