PHP imagettftext() could not read font

Published on:

今天撞牆撞很大....由於手邊在碰的一個專案裡面需要產生類似驗證碼的圖片,他用了 imagecreate(), imagettftext(), imagesetpixel() 這些 PHP functions。聽說這支程式「曾經」是可以 work 的,不過在我手上就不 work,為了證明不是人品問題,一定要把這個 bug 修掉!

一開始我傻傻的在程式碼裡面翻找,但這樣實在太沒效率了,身為一個專業的....呃...雜工,一定要懂得善用工具!所以我用了..... command line php.....

    $ php image.php > /dev/null  
    對啦,只不過是測試環境從 apache 換到 command line 底下了,這樣是有比較強嗎?有喔~因為我的測試環境有裝 [xdebug][1],只要有 enable 就可以在 command line 底下看到 debugging messages,不用特別打開 stack trace。至於最後面把 standard output 導向 `/dev/null` 是為了不想看到他輸出的那張不完整的圖,那會干擾畫面。  

首先第一步,我忘記詳細的訊息了,大意是說 imagecreate() is undefined 等等,這時候當然要去找找這函式有沒有需要什麼相依的 library 啊!找了一下發現,這些函式是由 PHP 的 GD module 所提供的,所以我迅速的安裝了 GD 模組...

$ sudo apt-get install php5-gd

接著,才是重頭戲的開始....

[][2]裝好 GD 模組之後,那些 function 都可以使用了,但是我卻一直收到這個錯誤訊息....

PHP Warning: imagettftext(): Could not read font .....(後略)

當然這訊息也是伴隨著 stack trace 的,看看傳進去的字型參數,用的是相對路徑 include/font/font.ttf,當下懷疑是不是找不到檔案,用 realpath() 來幫忙看看...

echo realpath($font_path);

但是,咦,怎麼什麼都沒出現?大概花了 30 秒我才發現我做了蠢事....我已經把 standard output 丟掉了啊XD 上網找了一下「php stderr」立刻找到應該要這樣做

file_put_contents('php://stderr', realpath($font_path));

印出來之後,發現我給他的路徑是正確的,怎麼會這樣呢?苦惱許久,才想到要去查查 imagettftext() 的 manual,發現了驚人的事情!

原來,某些版本的 GD 會在你給他的路徑是相對路徑時,使用環境變數 GDFONTPATH 當作前綴,並且在最後補上 .ttf。另外,版本低於 2.0.18 的 GD 還不允許路徑裡面有空白字元。檢查了一下...嗯,路徑沒有空白字元,那會不會是路徑問題?參考官方 manual 提供的 sample code:

<?php

// Set the enviroment variable for GD

putenv('GDFONTPATH=' . realpath('.'));

    // Name the font to be used (note the lack of the .ttf extension)  
    $font = 'SomeFont';  
    ?>  
    我自己設定好了正確的 `GDFONTPATH` 也把後面的 `.ttf` 拿掉,依然不 work....到這裡我已經快崩潰了....即使我發瘋似的交叉測試拿掉或加上 `.ttf`、更改路徑、使用絕對路徑等等,都還是失敗。  

接著我又開始想,會不會是別的原因?來看看檔案權限好了....

$ ls -l include/font/font.ttf

很好,檔案權限是 644 (rw-r--r--),應該沒問題吧?算了,死馬當活馬醫,改成 777!!

$ chmod 777 include/font/font.ttf

可想而知,還是炸了.....

在網路上找來找去,碰到類似問題的人大多是這幾種狀況:

  • 路徑錯誤 (前面提到的相對路徑問題)
  • 檔案從 windows 傳到 un*x 上就無法 work 了 (因為 un*x 對檔名是 case-sensitive 的)
  • ttf 寫成 tff (這是他自己耍笨了...)

很多人問問題會列出自己的 GD 版本,那我也來看看有沒有什麼端倪

$ php -i

...

gd

    GD Support => enabled  
    GD Version => 2.0  
    FreeType Support => enabled  
    FreeType Linkage => with freetype  
    FreeType Version => 2.4.8  
    T1Lib Support => enabled  
    GIF Read Support => enabled  
    GIF Create Support => enabled  
    JPEG Support => enabled  
    libJPEG Version => unknown  
    PNG Support => enabled  
    libPNG Version => 1.2.46  
    WBMP Support => enabled  

    Directive => Local Value => Master Value  
    gd.jpeg_ignore_warning => 0 => 0  
    ...  
    就沒問題嘛 orz  

我已經確定我的路徑是完全正確的,而且也是絕對路徑,檔案權限也確定是可以讀取的,GD module 看起來沒有什麼錯,那到底是什麼問題?心灰意冷之際,我想說不然拿現有的其他字型來試試看好了。事實上該專案裡本來有好幾個字型檔,我早就試過幾個都不 work,結果沒想到改成用自己系統本來有的字型,就成功了!太崩潰了!!! 可是還是很高興,立馬回到本來的程式上,加上剛剛使用的字型的絕對路徑,一切都搞定了!(超開心)

所以總結而言,我一開始的環境沒辦法正確執行這個程式,只有兩個原因

  • 缺少 php-gd
  • 字型檔有某種錯誤

我對字型不太有研究,所以就無法深究該字型檔究竟有什麼問題,畢竟用 file 去看他還是個正常的 True Type font 啊....

$ file font.ttf

font.ttf: TrueType font data

會不會跟編碼有關係呢?可是我用的只是一個 "1" 耶.....

好吧,雖然還是帶著懷疑,不過主要的問題算是解決了,結案!!!

[2]:

Comments

comments powered by Disqus