2018/03/14

Let's Encrypt 開始支援 wildcard certification

在 Let's Encrypt 的 Tiwtter 看到「ACME v2 and Wildcard Certificate Support is Live」,已經開放大家申請 wildcard 的憑證:
We’re pleased to announce that ACMEv2 and wildcard certificate support is live! With today’s new features we’re continuing to break down barriers for HTTPS adoption across the Web by making it even easier for every website to get and manage certificates.

另外自己在更新 certification 的 dehydrated 已經開始支援,先來看一下怎麼玩,如果要用的話就來裝 gslin 打包的 PPA

2018/03/09

PHP 中 「...」(three dots) 也可以用在 argument provider

看了 PHPUnit 的 source code,發現有個很有趣的寫法
function assertSame($expected, $actual, string $message = ''): void
{
    Assert::assertSame(...\func_get_args());
}

最初以為「...」只能用在定義 variable-length function argument/param,重新看了文件才發現之前文件沒有看完,也可以拿來把陣列分別當作 argument/param 傳入:
function add($a, $b) {
    return $a + $b;
}

add(...[1, 2]);  // $a = 1, $b = 2

// or ...

$args = [1, 2];
add(...$args);

2018/03/08

PHPUnit 中「backupGlobals」的作用

複習 PHPUnit 順手寫了小程式做實驗。

PHPUnit 為了讓各個不同的 test case 不會因為 super globals 變數而互相影響,設計了 「backupGlobals」這個功能。先來看範例程式:
class MyTest extends TestCase
{
    public function testOne()
    {
        $GLOBALS['test'] = 123;

        $this->assertArrayHasKey('test', $GLOBALS);
    }

    public function testTwo()
    {
        $this->assertArrayHasKey('test', $GLOBALS);
    }
}

範例中 testOne() 修改了 $GLOBALS 變數的內容,如果在不使用「backupGlobals」的情況下,在 testTwo() 中的 $GLOBALS 也會保留 testOne() 修改過的內容,使 testTow() 抓得到「test」這個 key:
$ phpunit MyTest.php 
PHPUnit 7.0.2 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 40 ms, Memory: 4.00MB

OK (2 tests, 2 assertions)

也就表示 testOne() 影響到了 testTwo() 的測試結果,這在測試時是不樂見的,各個測試應該有獨立的測試環境,不應該互相影響。

使用「backupGlobals」功能,PHPUnit 會在 test case 執行之前,使用 serialize() 對 super globals 做備份,並在測試結束以後 unserialize() 復原,所以 testOne() 中做的修改就不會影響到 testTwo() 了:
$ phpunit --globals-backup MyTest.php 
PHPUnit 7.0.2 by Sebastian Bergmann and contributors.

.F                                                                  2 / 2 (100%)

Time: 52 ms, Memory: 4.00MB

There was 1 failure:

1) MyTest::testTwo
Failed asserting that an array has the key 'test'.

/home/johnroyer/tmp/MyTest.php:16

FAILURES!
Tests: 2, Assertions: 2, Failures: 1.

重點來了,因為是使用 serialize() 和 unserialize(),所以只能針對 primitive type 進行備份和還原,如果使用了 object 或是 singleton 時,「backupGlobals」就派不上用場了。這個時候要使用殺手鐧「runTestsInSeparateProcesses」:
/**
 * @runTestsInSeparateProcesses
 */
class MyTest extends TestCase
{
    ....
}

使用這個 annotation 會讓 PHPUnit 為每個 test case 分別 fork 出新的 proccess 進行測試,因此不同 test case 就可以在完全獨立的環境下執行不受影響:
$ phpunit MyTest.php 
PHPUnit 7.0.2 by Sebastian Bergmann and contributors.

.F                                                                  2 / 2 (100%)

Time: 303 ms, Memory: 4.00MB

There was 1 failure:

1) MyTest::testTwo
Failed asserting that an array has the key 'test'.

/home/johnroyer/tmp/MyTest.php:19

FAILURES!
Tests: 2, Assertions: 2, Failures: 1.

但使用這個殺手鐧也是要付出一點代價:時間。最前二次執行 PHPUnit 時,跑完二個 test case 只花費了 50ms 左右,而開 proccess 來進行測試則花了 300ms。

2018/03/02

PHP 7.x 與 HHVM 的效能比較

前幾天看到國外有人使用 PHP 7.x 和 HHVM 做了效能測試「The Definitive PHP 5.6, 7.0, 7.1, 7.2 & HHVM Benchmarks (2018)」,可以從比較上看到 PHP 7 以後速度有大幅的躍進,到了 7.1 與 7.2 已經和 HHVM 不相上下了。

新版的 Druple 還不支援 PHP 7.2,但 7.1 的效能也很接近 HHVM 了


目前用過跑起來最慢的 project 應該是 GalleryDruple (古早的版本),由上圖可以看到 PHP 7.x 幾乎快了 5.x 一倍,另外在 7.1 的效能也逼近 HHVM 了。

相較於 HHVM 在佈署之前還要經過編譯步驟,我想應該很多人會回來使用 PHP 7.x 吧。

2018/02/22

docker aufs 把 inode 吃光的問題

前幾天在做 aptitude upgrade 時,系統噴儲存空間不夠的錯誤訊息,用 df 追了一下,發現是 inode 被吃光,網路上找了一下統計 inode 使用量的 script 來掃整個分割區:
find / -type d -print0 | xargs -0 -n1 count_files | sort -n

...
1794 ./var/lib/docker/aufs/diff/04d42c6fb6b72464ab397cc0cd67d8600f7bc0964ff7c9bb54392ec3eb53a13e/home/git/gitlab/app/assets/images/emoji
1794 ./var/lib/docker/aufs/diff/04d42c6fb6b72464ab397cc0cd67d8600f7bc0964ff7c9bb54392ec3eb53a13e/home/git/gitlab/public/assets/emoji
1794 ./var/lib/docker/aufs/diff/04d42c6fb6b72464ab397cc0cd67d8600f7bc0964ff7c9bb54392ec3eb53a13e/home/git/gitlab/vendor/bundle/ruby/2.3.0/gems/gemojione-3.0.1/assets/png
1794 ./var/lib/docker/aufs/diff/04d42c6fb6b72464ab397cc0cd67d8600f7bc0964ff7c9bb54392ec3eb53a13e/home/git/gitlab/vendor/bundle/ruby/2.3.0/gems/gemojione-3.0.1/assets/svg
1794 ./var/lib/docker/aufs/diff/bb44ab5db5ec7f5e3fe0bde806002e887cf11cf9aa598ce0453083f80fc10ff9/home/git/gitlab/app/assets/images/emoji
1794 ./var/lib/docker/aufs/diff/bb44ab5db5ec7f5e3fe0bde806002e887cf11cf9aa598ce0453083f80fc10ff9/home/git/gitlab/public/assets/emoji
1794 ./var/lib/docker/aufs/diff/bb44ab5db5ec7f5e3fe0bde806002e887cf11cf9aa598ce0453083f80fc10ff9/home/git/gitlab/vendor/bundle/ruby/2.3.0/gems/gemojione-3.0.1/assets/png
1794 ./var/lib/docker/aufs/diff/bb44ab5db5ec7f5e3fe0bde806002e887cf11cf9aa598ce0453083f80fc10ff9/home/git/gitlab/vendor/bundle/ruby/2.3.0/gems/gemojione-3.0.1/assets/svg
1794 ./var/lib/docker/aufs/diff/fcfbf2f22b171407b0a9d657131c0c4b55aadd50c49a26abfc40cd404ab02298/home/git/gitlab/app/assets/images/emoji
1794 ./var/lib/docker/aufs/diff/fcfbf2f22b171407b0a9d657131c0c4b55aadd50c49a26abfc40cd404ab02298/home/git/gitlab/public/assets/emoji
1794 ./var/lib/docker/aufs/diff/fcfbf2f22b171407b0a9d657131c0c4b55aadd50c49a26abfc40cd404ab02298/home/git/gitlab/vendor/bundle/ruby/2.3.0/gems/gemojione-3.0.1/assets/png
1794 ./var/lib/docker/aufs/diff/fcfbf2f22b171407b0a9d657131c0c4b55aadd50c49a26abfc40cd404ab02298/home/git/gitlab/vendor/bundle/ruby/2.3.0/gems/gemojione-3.0.1/assets/svg
1966 ./var/lib/docker/aufs/diff/04d42c6fb6b72464ab397cc0cd67d8600f7bc0964ff7c9bb54392ec3eb53a13e/home/git/gitlab/public/assets
1966 ./var/lib/docker/aufs/diff/bb44ab5db5ec7f5e3fe0bde806002e887cf11cf9aa598ce0453083f80fc10ff9/home/git/gitlab/public/assets
1971 ./var/lib/docker/aufs/diff/fcfbf2f22b171407b0a9d657131c0c4b55aadd50c49a26abfc40cd404ab02298/home/git/gitlab/public/assets
2271 ./var/lib/docker/image/aufs/distribution/diffid-by-digest/sha256
2271 ./var/lib/docker/image/aufs/distribution/v2metadata-by-diffid/sha256
3291 ./var/lib/dpkg/info
4025 ./var/lib/docker/aufs/diff/fcfbf2f22b171407b0a9d657131c0c4b55aadd50c49a26abfc40cd404ab02298/home/git/gitlab/tmp/cache/assets/sprockets/v3.0
4029 ./var/lib/docker/aufs/diff/04d42c6fb6b72464ab397cc0cd67d8600f7bc0964ff7c9bb54392ec3eb53a13e/home/git/gitlab/tmp/cache/assets/sprockets/v3.0
4029 ./var/lib/docker/aufs/diff/bb44ab5db5ec7f5e3fe0bde806002e887cf11cf9aa598ce0453083f80fc10ff9/home/git/gitlab/tmp/cache/assets/sprockets/v3.0

看起來兇手是 docker,而且吃掉的量還不小。

查了一下資料,其實是自己在刪除 images 和 volumes 時有漏參數,導致有檔案沒有被清乾淨,inode 被吃光沒有回收回來。參考這篇「Docker、AUFS、inode耗尽和一个小工具」整理,可以透過以下 script 把無用的檔案清空:
docker images -qf dangling=true | xargs docker rmi

docker volume ls -qf dangling=true |xargs docker volume rm

這二個 script 跑完以後,我的 inode usage 從 99% 瞬間降到 17%,看來以後真的要小心。


其他參考資料:

2018/01/31

類流感中獎心得

好像每次放假回家都會遇到頭大的事情,以前是回家就下大雨,這次回家就中流感。

這次沒有做流感快篩,醫師說快篩的正確率大約只有 60%,由症狀來看或許會比較準確。我這次的病症有:
  • 喉嚨痛
  • 疑似全身酸痛 (因為感冒前有做運動,所以沒辦法確定是哪邊引起的酸痛)
  • 發燒
  • 有痰、咳嗽
  • 流鼻涕
由以上病症猜測是 B 型流感。

流感的傳染能力很強,所以在家做了一些措施:
  • 醒著就帶口罩,因為主要是靠飛沫傳染
  • 餐具分開、獨自用餐 (因為吃飯不能帶口罩)
  • 室內開窗通風,空間中的病毒密度會較低
  • 多喝溫水,在加上一些運動飲料
  • 吃維他命 B 和 C 補充體力
流感沒有治療方法,所以多久能康復就看個人免疫系統狀況了,希望這次不要向以前一樣拖到幾個月,會很想死 ... Orz

2018/01/26

2018 年開發人員的技能整理

Hacker News 看到一篇文章「2018 Developer Skills Report」,裡面列出一些程式設計師的特質,還蠻有趣的,這裡大概列出幾個有趣的點:

  • 有超過四分之一的人在 16 歲左右就開始接觸程式設計,但有 36% 的人在 26 歲才開始學習程式設計,而且現在是資深工程師。所以學寫程式不嫌晚、也不嫌早。
  • 幾乎左有的開發者都求知若渴,大多都學了 3 種或以上的程式語言
  • 自修的人比在學校上課的比例還稍微多了一些
  • 年輕人傾向從網路媒體取技術知識 (像是 StackOverflow、YouTube)
  • 幾乎所有人都把問題解決能力擺在最前面
  • 在工作與生活間取得平衡的方法:彈性的工時、遠端作業、注重產出而非工時 (這些台灣公司好像很少有聽過)

2018/01/18

Nginx 最大接收檔案大小

因為最近網路攻擊蠻多的,索性用 reverse proxy 把 NAS 藏在 Nginx 後面,順便讓 Nginx 處理掉 SSL 那段工作:
   location / {
      proxy_pass http://192.168.0.xxx:80;
      proxy_set_header Host $host;       
      proxy_set_header X-Real-IP $remote_addr;
      proxy_buffers 32 32k;
      proxy_buffer_size 32k;
      error_page 404  404.html;
      error_page 500 502 503 504  500.html;
   }

不過後來友人說上傳檔案一直失敗,在某個大小以上的檔案通通出錯。

觀察一下網路流量才發現 Nginx 並不是直接把流量即時 proxy 到 NAS 端,而是整個 HTTP request 完成以後才一次送到 NAS 那邊去,所以上傳檔案時自然會遇到 upload size 問題。

解決方法就是把 Nginx 的 client_max_body_size 調大:
server {
    ....

    client_max_body_size 1g;

    ....
}


Ref:

7XX Range of HTTP Status codes

7xx 系列看起來是惡搞的 HTTP status code,包含開發常見的問題和笑話:RFC for the 7XX Range of HTTP Status codes - Developer Errors

這邊看到幾個比較機車的 status code:
704 - Goto Fail
707 - Can't quit vi
724 - This line should be unreachable
725 - It works on my machine
726 - It's a feature, not a bug
730 - Fucking Bower
767 - Drunk
775 - Out of cash
789 - Not my department
799 - End of the world

2018/01/15

Silex EOL in Jine 2018

Symfony 團隊認為新版的 Symfony 4 的修改,已經能讓使用者有和 Silex 相同的使用者體驗,於是決定不再繼續維護 Silex

http://symfony.com/blog/the-end-of-silex

目前 Silex 將在 6 月結束維護 (EOL, End Of Life):
So, we've decided to not support Symfony 4 in Silex, or at least not add the new features added in 3.4. The current stable version of Silex is still maintained for bugs and security issues. But its end of life is set to June 2018.

2018/01/14

紫羅蘭永恆花園不負責觀後感

這次會被掉坑,除了一堆人推薦以外,也是聽說它是京都動畫大獎近期唯一的大賞獎得主,且還得到了 Netflix 的贊助,所以想看一下所謂「預算無上限」京阿尼的功力可以做到哪裡。

在 Netflix 上了第一集,注意到以下幾點:

  • 畫面很細緻,很注重光影細節
  • 畫面禎數高,不是只有主角動動嘴而已
  • 背影音樂,後面說明

前二項我不專業,交給其他人說明。但音樂製作我到是有沾到邊。

這部作品很不一樣的是背景音樂很意外的使用交響樂團做配樂,不是以前一般的小團,而是連平常較少出現的雙簧管都有的配樂,這應該花了蠻大的一筆經費在作曲和演奏上。

劇情對我來說有點沈重,但以目前的品質我想我應該會看下去。

PHP 7.2 下使用 xdebug

我目前使用的 PHP APT 是「http://ppa.launchpad.net/ondrej/php/ubuntu」,不過看起來在 PHP 7.2 還沒有 xdebug 可以使用。

如果硬要使用 aptitude 安裝,只能裝到 PHP 7.1 的版本。

所以後來用 phpbrew 在硬幹,發現不能安裝是有原因的:目前 xdebug stable 版本只支援到 PHP 7.1,若要在 PHP 7.2 使用 xdebug,只能先安裝 dev 版本

所以開發機可能考慮先降版本回到 7.1 吧。

2018/01/12

寒流來襲,讓電腦為你取暖

國外有人用 bitcoin 礦機當暖爐取暖,但其實就算你沒在挖礦也可以開電腦取暖,甚至做更有意義的事情。


BOINC 是個用來做學術研究的開放平台,只要個人願意擔任志工,便能透過個人電腦閒置的時候,借用處理器或顯示卡進行運算,協助研究。研究項目從生物、醫學、數學、自然科學、地球科學,甚至還有尋找外星人的專案,選擇一個自己有興趣的專案參與,並讓你的電腦協助專案研究。

我主要是跑醫學、藥學研究,使用到 7 core CPU 與 1 GPU,從下圖就可以看到協助研究時會用到大量的運算資源,讓整台電腦熱起來。



與開暖氣相同,參與研究專案讓電腦進行運算,需要付出額外的電費,但可以保證的是這些電費不單只讓房間變溫暖,研究成果也會讓世界變得更溫暖。

2018/01/07

2017 年部落格的 review

下雨天哪裡都不能去,只好發個廢文。

開始工作,下班後其實沒剩下多少體力和精神可以整理文章和經驗,部落格文章也相對少了很多,因此今天才有辦法幫去年整年的紀錄做個簡單的回顧。

去年 page view (PV) 最多的是「部落格的圖床」。看來大家都很想找到一個操作簡單又可以免費使用的圖床,之前試過幾個方案:
比較可惜的是 Flickr 主機在國外,且網路頻寬看起來不大,回應速度實在有夠慢的,賣給 Yahoo 以後越改越不好用。Imgur 若沒有註冊成會員,則圖片好像在沒有人檢閱一段時間後便會自動刪除。

最後我找到比較折衷的方法是 AWS s3。剛好本站的流量極小 (廢文沒人看 XD),再加上主要以程式碼居多,所以圖片數量也少,使用 s3 當作圖床,一年平均下來一個月大約只要台幣 3 元左右就可以跑得很順 (我使用 Tokyo 的 bucket),目前只缺一個好用的圖片上傳工具。



而 PV 第二名的是「尾寮山路況」。很明顯的大家希望能在數小時的挑戰前,確認自己的身體狀況以及路況,以免有什麼萬一。

去年年初將尾寮山攻頂的狀況,拿來當作自己身體復健的進度參考。在一次颱風後留下路況紀錄,沒想到能幫上其他人的忙,小驚訝了一下。



第三名則是「為 Gitlab 加上 CI runner」,猜測應該是操作難度較高,所以讓大家把所有可以找到的資料都抓來看了一遍,也因此該筆記點閱率較高。

個人覺得 Gitlab 真的是一個功能蠻齊全的程式碼管理、協作平台,但是因為功能齊全也導致架設的成本偏高,不是花錢解決問題就真的只能花時間了。目前仍在 9.x to 10.x migration 奮鬥,希望前輩有什麼奇淫巧計也能和大家分享。



今年有什麼計畫嗎?沒,就船到橋頭自然直。

這個站從以前的作用就是一個個人的筆記,防止自己魚腦把花了數天搞定的解決方法忘記而開始撰寫的,如果能幫助到其他人,這些筆記當然會更有價值,但當初並沒有這個構想。

若你覺得這個站對你有幫助,歡迎使用 CC-by-name 方式轉貼,也歡迎留言互相交流。謝謝。

2018/01/05

PHP 近幾年生態圈一些可惜的地方


進幾年 Laravel framework 竄紅,大家也趨之若騖,相對其他的 framework 就被冷落了,實在有點可惜。

Laravel 有其特色,但個人用了幾個版號,覺得 Laravel 比較適合中大型專案、以及快速開發,在往後維護和升級難度都不低 (5.1 migrate 到 5.4 根本是地獄)。





而如雨後春筍般冒出來的 Laravel library 很多又只能供 Laravel 使用,很難在其他 framework 上使用。Laravel 開發出來的元件耦合度也不低,很難拉出來供其他人使用 (Symfony 的各個元件都是 library,可以透過 composer require 供需要者使用)。結果讓想要使用其他 framework 的人找不到資源可以使用,少了很多選擇。

個人比較想看到的是,各種 framework 都能有社群協助一起發展,PSR 把一些好的設計制定成開發規範,大家遵守便能讓一個 library 在多個平台使用,而不是讓 Laravel 獨大,讓 PHP 的生態系變得單調、沒有選擇。

最近因公司需要而翻了近十個 framework、以及 CRM,並從中截長補短撰寫適合公司使用的 framework,希望以後有時間可以整理成公版讓其他有類似需求的人也來用看看。(本來想再愚人節發布的,似乎來不及了 TAT)

2018/01/04

PHPStan 靜態分析工具

前陣子從 gslin 那邊看到 PHPStan 這個工具,剛好手上有需要測試的程式,就拿來掃一掃。常見的問題大多都可以抓到,甚至連 doc comment 有錯誤也會抓出來。

下面弄個個 demo code 讓大家稍微看一下實際狀況。

Hello.php:
<?php
namespace Zero;

class Hello
{
    /**
     * @param array $name
     */
    public function greeting(): void
    {
        $test = '123';
        echo "Hello $name\n";
    }
}

bootstrap.php:
<?php
require __DIR__ . '/../vendor/autoload.php';

$hello = new \Zero\Hello();
$hello->greeting(123);

然後執行 PHPStan 做 level 5 的分析:
 ------ ------------------------------------------------------ 
  Line   src/Hello.php                                         
 ------ ------------------------------------------------------ 
  10     PHPDoc tag @param references unknown parameter $name  
  14     Undefined variable: $name                             
 ------ ------------------------------------------------------ 

 ------ --------------------------------------------------------------------- 
  Line   src/bootstrap.php                                                    
 ------ --------------------------------------------------------------------- 
  7      Method Zero\Hello::greeting() invoked with 1 parameter, 0 required.  
 ------ ---------------------------------------------------------------------

PHPStan 給的錯誤訊息,就可以在執行 PHP 之前預防錯誤發生。

不過有一些比較可惜的地方:

  • PHPStan 一定要吃 autoload 規則,看起來是為了要解 PHP Refelction 問題,所以比較就的程式就 GG 了
  • Hello.php 裡面有個沒使用到的變數 $test 沒有被抓到,不然應該可以再把程式清的更乾淨