眾所周知,在 PHP 中 parse_url()
這個函式遲遲未支援 UTF-8,這導致一些英文、數字以外的 Host, Path, Query 及 Fragment 都會解析錯誤。
(psysh) >> parse_url('https://中文.台灣/你好嗎?我=很好&大家都很好#你呢?')
=> [
"scheme" => "https",
"host" => b"ä¸æ__.å_°ç_£",
"path" => b"/ä½ å¥½å__",
"query" => b"æ__=å¾_好&大家é_½å¾_好",
"fragment" => b"ä½ å_¢ï¼_",
]
這個問題直到 PHP 8.1 仍未見改善,這也是促使我寫下本文的動機。
PHP FFI
FFI 是 PHP 7.4 加入的新功能,作為一個 extension 的形式被加入 PHP 核心中。
它允許讓 PHP 直接使用現成的動態函式庫(Windows 上的 .dll
、macOS 上的 .dylib
及 Unix-like 上的 .so
),而不需要費心撰寫 PHP extension。
據官方文件所述:
- FFI 是危險的:它能夠以相對低階的方式執行邏輯,這也導致它可能會危害作業系統或造成不可預期的 Memory, IO Leak。
- FFI 是低效率的:FFI 在 存取資料結構時,可能花費比原本 PHP 存取陣列或物件 2 倍甚至以上的時間;只不過在某些情況下它可能會消耗較少的記憶體空間。
只不過,不可諱言地,FFI 提供了 PHP 與其它程式語言的另一種交互方式,而在很多現代的程式語言中都具備這樣的特性。
如何讓 libcurl 解析 URL
用 libcurl 解析 URL 主要會需要三個 API(不考慮 free
及 cleanup
):
CURLU *curl_url()
: https://curl.se/libcurl/c/curl_url.htmlCURLUcode curl_url_set(CURLU *url, CURLUPart part, const char *content, unsigned int flags)
: https://curl.se/libcurl/c/curl_url_set.htmlCURLUcode curl_url_get(CURLU *url, CURLUPart what, char **part, unsigned int flags)
: https://curl.se/libcurl/c/curl_url_get.html
libcurl 官方文件上的範例程式如下:
CURLU *url = curl_url();
CURLUcode rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
if (!rc) {
char *scheme;
rc = curl_url_get(url, CURLUPART_SCHEME, &scheme, 0);
if(!rc) {
printf("the scheme is %s\n", scheme);
curl_free(scheme);
}
curl_url_cleanup(url);
}