Post view

在macOS 10.12、10.13 Server版,PHP呼叫系統的sips指令把RAW照片轉成JPEG會產生全黑圖檔與錯誤訊息

insoler社群網站目前的伺服器主機是規格、配備完全相同的3台Mac mini。因為在新的macOS 10.12、10.13會有2個非常嚴重的大問題,所以這3台Mac mini目前全部都是使用比較舊的OS X EI Capitan 10.11.6版。

這2個非常嚴重的大問題分別是:

1. MySQL Server資料庫的8.0新版本無法在新的macOS 10.12、10.13上執行!

What's New in MySQL 8.0.11? Up to 2x Faster, Default to utf8mb

我在macOS 10.13上安裝當時的最新版本MySQL 8.0.11,竟然完全無法啟動MySQL!我有懷疑過,可能是舊版MySQL 5.6.37的my.cnf與大改版的MySQL 8.0.11不相容,所以有刪除my.cnf,但還是無法啟動MySQL Server!

由於MySQL 5.6.38以後的版本只能安裝在macOS 10.12以上的系統版本,所以insoler目前仍然是使用MySQL 5.6.37版,而不是MySQL 5.6.38或是更新的版本。因為MySQL 8.0.11、MySQL 8.0.12無法在macOS 10.13上執行,而舊的MySQL 5.6.37版卻可以在OS X EI Capitan 10.11.6上穩定執行,所以MySQL Server並沒有急於升級的必要性。

2. 從PHP呼叫系統的sips指令,把RAW照片轉成JPEG檔,竟然會產生全黑圖檔與Apache錯誤訊息!

這個問題會造成非常大的災難!insoler目前支援「直接上傳RAW照片檔案」其實是透過macOS系統內建的sips終端機指令(這個命令列程式的視窗介面操作版本,其實就是很常用的Preview預覽程式),透過php呼叫系統的sips指令把使用者上傳的RAW照片檔案,轉換成可以在Web網頁上顯示的JPEG圖檔。

這個功能在舊的OS X EI Capitan 10.11.6版本上可以正常執行,但如果把系統升級到新的macOS 10.12、10.13,就無法從RAW轉成JPEG!但是如果先手動把RAW另存為PNG圖檔,再透過php呼叫sips指令,卻可以轉成JPEG圖檔。也就是說,只有無法從RAW轉JPEG,但是其他圖檔格式卻可以正常轉換!

因為以上的2個重大問題,insoler網站的伺服器主機目前仍舊是使用舊版的OS X EI Capitan 10.11.6。可是網站伺服器主機不能一直停留在舊版,不升級到新的系統版本,因為不升級到macOS 10.12的話,系統內建的Digital camera RAW會不支援Canon EOS 5D Mark IV等新相機的RAW檔。也就是說,想要支援Canon EOS 5D Mark IV等更新相機的RAW檔,只能把系統升級到macOS 10.12、macOS 10.13以上的版本!

目前我利用其中一台Mac mini,把系統升級到macOS Sierra 10.12.5:

由於是規格、配備完全相同的3台Mac mini,所以我就只列出其中一台Mac mini的規格。你可以看到這是搭載2.6 GHz Intel Core i7的4核心處理器、最高的16GB 1600MB DDR3記憶體。

Mac mini只有內建標準的Intel HD Graphics 4000圖形處理晶片,並沒有搭載雙GPU的設計。所以沒有更好的AMD或是NVIDIA的GPU處理器。由於Mac mini伺服器主機平時都沒有連接支援HDMI的電腦螢幕,而且Mac mini負責擔任的Web Server與MySQL Server伺服器,也完全不需要性能強大的GPU處理器來加速資料處理速度。

事實上,就算把Mac mini升級到目前最新的macOS High Sierra 10.13.6,仍然無法解決sips指令,把RAW照片轉成JPEG檔,會產生全黑圖檔與Apache錯誤訊息的問題!

我測試過Canon EOS 5D、Nikon D90等多個相機的RAW檔案,無論是macOS Sierra 10.12.5還是macOS High Sierra 10.13.6,從php呼叫系統的sips指令,把RAW照片轉成JPEG檔的話,就會產生這樣的全黑圖檔!

簡單的PHP測試程式sips.php

我寫了一個非常簡單的PHP測試程式,並且把這個問題向Apple的Bug Report回報,但是很明顯Apple並沒有處理這個問題,甚至還關閉了問題回報!

<? php

$cmd = "/usr/bin/sips -s format jpeg --setProperty formatOptions low 'IMG_1000.CR2' --out 'IMG_1000.jpg'";
echo $cmd;
exec($cmd);

?>

把exec換成其他的 shell_exec($cmd); 或是 system($cmd); 都只會得到相同的結果,這不是 exec($cmd); 指令的問題。

當然,在Apache的error_log也會產生許多的錯誤訊息!

2018-09-17 11:09:20.621 sips[10023:94815] Metal library creation failed with error: Error Domain=MTLLibraryErrorDomain Code=3 "Compiler encountered an internal error" UserInfo={NSLocalizedDescription=Compiler encountered an internal error}
2018-09-17 11:09:20.621 sips[10023:94810] Metal pipeline state creation failed with error: Error Domain=MTLLibraryErrorDomain Code=3 "Compiler encountered an internal error" UserInfo={NSLocalizedDescription=Compiler encountered an internal error}
2018-09-17 11:09:20.622 sips[10023:94816] Metal library creation failed with error: Error Domain=MTLLibraryErrorDomain Code=3 "Compiler encountered an internal error" UserInfo={NSLocalizedDescription=Compiler encountered an internal error}

在Console,找到Apache的error_log就會看到許多相同的錯誤訊息!這些完全相同的錯誤訊息並不是許多次RAW轉成JPEG產生的,而是執行一次php呼叫sips指令,把RAW照片轉成JPEG檔,就會產生10幾個錯誤訊息!

關於OS X EI Capitan 10.11.6的Digital camera RAW

既然在macOS Sierra 10.12.5、macOS High Sierra 10.13.6系統上,從php呼叫sips指令,把RAW照片轉成JPEG檔,就會產生全黑的JPEG圖檔,還會產生許多錯誤訊息,那麼insoler網站就一直停留在舊的OS X EI Capitan 10.11.6版本不要升級,不就好了?非常可惜的是,事情並沒有那麼甜美!

不升級系統版本,仍然繼續執行OS X EI Capitan 10.11.6舊版的話,會因為macOS系統內建的Digital camera RAW不支援新的數位相機,例如把Canon EOS 5D Mark IV的RAW檔案拷貝到sips檔案夾,就會看到「IMG_1000.CR2」無法顯示照片的預覽縮圖!

如果用滑鼠按兩下「IMG_1000.CR2」想要打開這個Canon EOS 5D Mark IV的RAW圖檔,就會看到這樣的錯誤訊息畫面:

無法打開檔案「IMG_1000.CR2」。「預覽程式」目前不支援此原始檔案格式。

雖然不升級系統版本,繼續使用OS X EI Capitan 10.11.6舊版的話,sips可以正確的處理「RAW轉JPEG檔」的動作,但卻會導致不支援Canon EOS 5D Mark IV等新的數位相機的問題!

如果升級系統版本到macOS High Sierra 10.13.6最新版本的話,卻會導致sips在「RAW轉JPEG檔」只會產生全黑的JPEG圖檔!

雖然最新的macOS Mojave 10.14版本即將在2018年9月25日發表正式版,也就是後天的25日就能安裝macOS Mojave 10.14正式版,但我相信就算把macOS系統升級到macOS Mojave 10.14版,也無法解決sips在「RAW轉JPEG檔」只會產生全黑的JPEG圖檔的嚴重錯誤的問題!

如果萬一很幸運,或是很不幸的,就算升級到macOS Mojave 10.14版本,sips在「RAW轉JPEG檔」一樣會產生全黑的JPEG圖檔的話,那麼insoler就永遠都無法升級macOS系統版本?

因為只要升級macOS版本,就會無法使用「RAW轉JPEG」的sips功能,站長只好寫一個公告,公布本網站只支援舊的數位相機,不支援Canon EOS 5D Mark IV等新的相機?

我當然不能寫這種公告!這種無可奈何的公告,我也寫不出來!

所以,既然 shell_exec($cmd); 會導致全黑的JPEG圖檔,確定無法在10.12、10.13甚至是最新的10.14都不能執行這樣的sips指令,當然是山不轉路轉,只好想其他辦法,我想「生命會找到自己的出路(Life will find its way out.)」。

首先要找到的新方法,當然是要先測試確定,真的從php執行sips無法執行「RAW轉JPEG」?

因為經過實際的測試,確定從php執行sips可以執行「PNG轉JPEG」,所以看起來不像是Apple因為安全性漏洞的考量「禁止從php網頁執行sips指令」,也不像是因為php的World Wide Web Server的WWW帳號的權限問題,所以「禁止從php網頁執行sips指令」。

既然sips可以執行「PNG轉JPEG」的話,當然就完全沒有無法執行「RAW轉JPEG」的理由!

只能猜想,Apple為了某種安全性理由,可能是Web Server直接執行Metal library金屬函式庫(可能是macOS 10.12、10.13、10.14為了加速RAW圖檔的顯示速度,所以呼叫新的金屬函式庫),所以Metal library會禁止某些帳號執行!只有「RAW轉JPEG」會呼叫系統的Metal library,但是「PNG轉JPEG」不需要呼叫Metal library,所以才會產生這樣的差異。

從「安全性理由」來考量的話,如果從macOS系統來呼叫sips執行「RAW轉JPEG」的話?是不是就不會產生錯誤訊息,也不會產生全黑JPEG圖檔?

從crontab排程指令執行sips.php

因為從瀏覽器的網址列來執行sips.php的話,執行的帳號就會是World Wide Web Server的WWW帳號,所以我利用macOS系統內建的crontab的排程指令,設定每分鐘自動執行sips.php程式的話...

* * * * * cd /Library/Server/Web/Data/Sites/Default/sips; /usr/bin/php -q sips.php

這樣就可以在macOS High Sierra 10.13.6從「IMG_1000.CR2」產生正確的「IMG_1000.JPG」,就像是在OS X EI Capitan 10.11.6一樣!我的「推理」果然是正確的!很顯然Apple因為某種安全性的理由禁止Metal library金屬函式庫,被系統帳號以外的其他帳號執行。

雖然這樣就可以成功的解決問題,但卻不是最佳解決辦法!因為設定在crontab的最短執行時間是以「每分鐘」為單位,也就是說上傳照片以後,可能要等1分鐘,作業系統才會執行sips.php。有時候也可能運氣很好,上傳RAW完畢就會立即執行sips.php。

真正的問題是,什麼時候會執行sips.php並不是以「上傳RAW檔案完成」來決定,而是電腦每分鐘就會自動執行sips.php一次,不管有沒有上傳RAW檔案!每分鐘不斷執行sips.php不但沒有效率,而且在user上傳大量RAW檔案的時候,例如一次上傳100個RAW圖檔,反而會需要100分鐘才能處理完成全部的轉檔工作,顯然更是不切實際!

另外,Metal library金屬函式庫只能由最高權限的系統帳號執行的話... 這樣不就無解?因為網頁處理上傳的RAW轉JPEG,一定只能從瀏覽器的網址執行,這樣的話,呼叫sips.php的帳號身份就會是World Wide Web Server的WWW帳號!有沒有什麼其他辦法,不要直接執行sips.php或是從WWW帳號執行?

既然利用crontab來執行php指令,並傳給sips.php可以正確執行「RAW轉JPEG」的動作,那麼如果用同樣的方式來執行呢?很不幸的,結果還是只能得到一個全黑的JPEG圖檔!

<? php

$cmd = "cd /Library/Server/Web/Data/Sites/Default/sips; /usr/bin/php -q sips.php";

echo $cmd;
shell_exec($cmd);

?>

利用sips.sh的批次指令檔

如果不要直接在 shell_exec($cmd); 執行sips指令,而是執行sips.sh的批次指令檔,再利用sips.sh來進行RAW轉JPEG的動作?我在 /usr/local/bin 檔案夾底下新增一個sips.sh的批次檔案:

#!/bin/sh

sips -s format jpeg --setProperty formatOptions low '/Library/Server/Web/Data/Sites/Default/sips/IMG_2000.png' --out '/Library/Server/Web/Data/Sites/Default/sips/IMG_2000.jpg'
sips -s format jpeg --setProperty formatOptions low '/Library/Server/Web/Data/Sites/Default/sips/IMG_1000.CR2' --out '/Library/Server/Web/Data/Sites/Default/sips/IMG_1000.jpg'

exit 0

然後修改一下php程式碼

<? php

$cmd = "sips.sh";

echo $cmd;
shell_exec($cmd);

?>

這樣 shell_exec($cmd); 就不會直接執行sips指令,而是交給sips.sh來負責執行sips指令。這樣應該可以得到正確的IMG_1000.jpg圖檔?非常不幸的,還是只能得到一個全黑的JPEG檔案!

原因猜想大概是從php呼叫sips.sh批次檔,不管批次檔執行什麼指令,執行指令的身份仍就是WWW。

利用AppleScript批次程式檔來執行sips

在Mac OS X系統上還有一個比 .sh 批次檔案更好用的AppleScript批次程式檔案可以利用。比如寫一個hello.scpt程式,打開終端機,然後執行一個簡單的echo Hello指令:

tell application "Terminal"
    do script "echo Hello"
    activate
    delay 1
    quit
end tell

當然也可以把要執行的 "echo Hello" 指令改成這個sips指令:

sips -s format jpeg --setProperty formatOptions low '/Library/Server/Web/Data/Sites/Default/sips/IMG_1000.CR2' --out '/Library/Server/Web/Data/Sites/Default/sips/IMG_1000.jpg'

這樣就可以得到正確的IMG_1000.jpg圖檔?還是非常不幸的,只能得到一個全黑的JPEG檔案!

另外,由於hello.scpt的內容並不是純文字檔案,而是二進位編碼檔案,所以無法改變直接IMG_1000.CR2的檔名。

唯一的辦法只剩下從終端機Terminal執行sips指令

進行了各種實驗以後,目前唯一確定可以在macOS 10.13上成功執行轉檔的方法,就只有打開終端機,在終端機裡面執行上面的sips指令。想要從php執行這樣的動作難度就更高了!幾乎可說是「不可能的任務」!

如果很難理解的話,換一個方式來說明。在macOS、UNIX、Linux系統上的終端機Terminal,其實就類似Windows的MS-DOS模式。如果想要在Windows上,從php使用exec直接執行某些DOS指令,這並沒有什麼問題,但問題是無法直接執行DOS指令的時候,你就會想到其他辦法來測試看看,比方說透過BAT批次檔來執行某些DOS指令,例如:

exec("sips.bat");

但是這樣的執行身份因為是從php的exec呼叫,所以仍舊是WWW帳號的關係,想要執行的DOS指令,可能會因為WWW帳號而被Windows系統封鎖!比較好的辦法是執行MS-DOS模式,然後把sips.bat當作參數來執行。

exec("cmd.exe /c sips.bat");

在macOS 10.13的話,當然就必須想其他辦法,因為Windows的MS-DOS模式與macOS的終端機Terminal並不是一樣的程式,使用方式也完全不同。

蘇言霖 2018/09/23 0 1161
Comments
Order by: 
Per page:
 
  • There are no comments yet
Rate
0 votes
Post info
蘇言霖
「超級懶貓級」社群網站站長
2018/09/23 (2043 days ago)
Actions