最近我花了許多時間,終於把insoler社群網站從舊版的Dolphin 7.1.6,升級系統版本到目前最新的Dolphin 7.3版本。當然,在Dolphin 7.1.6經過大幅度修改,可以支援RAW上傳的Photos相簿模組,也因應Dolphin 7.3放棄Flash,改用HTML 5,所以也花了超過1個月以上的時間,在熱心網友ayaka的協助下,完成了支援HTML 5的全新相片模組。
在改寫Photos模組,開發上傳RAW程式碼、進行測試的時候,雖然有遇到過一些問題,但是並沒有遇到【只能上傳 .CR2,卻無法上傳 .NEF】的問題!原本以為可以正常運作的相簿模組,卻突然出問題,居然只能上傳Canon相機拍攝的RAW檔案,卻無法上傳Nikon相機拍攝的RAW檔案!
我追查了PHP程式碼之後,猜想這個問題應該是與Apple最近在2016/3/21釋出的安全性更新版本有關!
下載 - 安全性更新 2016-002 Yosemite
建議所有使用者安裝「安全性更新 2016-002」,它改進了 OS X 的安全性。
如需此更新項目安全性內容的相關資訊,請參訪 http://support.apple.com/kb/HT1222?viewlocale=zh_TW 網站。
投稿日: 2016/3/21
最大的問題是出在php的getimagesize這個可以同時取得圖檔大小、圖檔格式的函式!在舊版Dolphin 7.1.6的時候,是寫成這樣:
@chmod($sTempFileName, 0644);
if(file_exists($sTempFileName) && filesize($sTempFileName)>0) {
$aSize = getimagesize($sTempFileName);
if (!$aSize) {
@unlink($sTempFileName);
if ($iRAW) @unlink($sTmpFileRAW); //BNW
return false;
}
switch($aSize[2]) {
case IMAGETYPE_JPEG: $sExtension = '.jpg'; break;
case IMAGETYPE_GIF: $sExtension = '.gif'; break;
case IMAGETYPE_PNG: $sExtension = '.png'; break;
default:
@unlink($sTempFileName);
if ($iRAW) @unlink($sTmpFileRAW); //BNW
return false;
}
$sStatus = 'processing';
$iImgWidth = (int)$aSize[0];
$iImgHeight = (int)$aSize[1];
if (!(($iImgWidth >= 1280 && $iImgHeight >= 600) || ($iImgWidth >= 600 && $iImgHeight >= 1280))) { //BNW Photo least 1280x1280
@unlink($sTempFileName);
if ($iRAW) @unlink($sTmpFileRAW); //BNW
return false;
}
熱心網友ayaka幫我改寫成這樣:
$aSize = getimagesize($sTempFileName);
if (!$aSize) {
@unlink($sTempFileName);
return false;
}
switch($aSize[2]) {
case IMAGETYPE_JPEG: $sExtension = '.jpg'; break;
case IMAGETYPE_GIF: $sExtension = '.gif'; break;
case IMAGETYPE_PNG: $sExtension = '.png'; break;
default:
@unlink($sTempFileName);
return false;
}
$sStatus = 'processing';
$iImgWidth = (int)$aSize[0];
$iImgHeight = (int)$aSize[1];
$sDimension = $iImgWidth.'x'.$iImgHeight;
//BNW check the image size
if (!(($iImgWidth >= 1280 && $iImgHeight >= 600) ||
($iImgWidth >= 600 && $iImgHeight >= 1280)))
{
@unlink($sTempFileName);
if ($this->sTempFileExts) {
@unlink($sTempRAWFileName);
}
return false;
}
基本上這兩段PHP程式碼並沒有什麼太大的問題,如果有的話,在Dolphin 7.1.6就會出問題,導致無法上傳Nikon相機拍攝的 .NEF 照片!雖然getimagesize其實並不支援RAW,以前讀取的 .NEF 檔案的照片大小,以Nikon D90來說,讀取到的RAW照片大小竟然只有2144x1424!事實上這個錯誤,從一開始就一直記錄在MySQL裡面。我並沒有修正。因為連原版Dolphin在瀏覽照片(無論是只有上傳JPEG或是RAW)的時候,BOONEX他們自己也不使用bx_photos_main的Size這個資料,只是一直把Size儲存在MySQL裡面而已。
查Nikon原廠網站,就會看到Nikon D90正確的照片大小應該是4288×2848才對。但是getimagesize以前只能讀到1/2一半大小的2144x1424!
事實上,Canon也一樣只能讀取到1944x1296只有一半大小的圖檔大小!只能猜想getimagesize不支援RAW所以會判斷錯誤。但無論如何,讀取到的圖檔size都不算太小,以前並沒有什麼太大問題。
但是在我安裝「安全性更新 2016-002,它改進了 OS X 的安全性」之後,getimagesize讀取到的 .NEF 的圖檔大小,竟然只剩160x120的縮圖大小!所以才會導致上傳 .NEF 照片檔案會失敗出錯!
Array
(
[0] => 160
[1] => 120
[2] => 8
[3] => width="160" height="120"
[mime] => image/tiff
)
因為160x120的照片太小,不符合我限定的最小必須是1280 x 600(或是600x1280)以上的照片大小,所以才會導致只有Nikon相機拍攝的 .NEF上傳照片失敗!
那麼,如果上傳Canon相機的 .CR2呢?結果也與以前的1944x1296不同!為什麼會這樣?我也不知道!只能確定PHP內建函式getimagesize不能在RAW上面了!雖然用來讀取JPEG照片大小還算是正確。
Array
(
[0] => 1936
[1] => 1288
[2] => 7
[3] => width="1936" height="1288"
[mime] => image/tiff
)
getimagesize不能用的話,解決辦法?
原本在正常的情況下,getimagesize應該要可以讀取JPEG、RAW照片的常、寬size才對,但因為不支援RAW,所以會讀出錯誤的大小,這個函式不能用的話,第二個選擇當然是改用PHP內建的exif_read_data函式,從EXIF裡面應該也能讀到照片大小才對!但更不幸的是,exif_read_data竟然連最基本的【照片大小】都讀不出來!可說是100%不支援RAW!竟然比getimagesize還要更差!
在PHP內建的exif_read_data、getimagesize都不能用的情況下,只好求助於ExifTool這個免費的工具程式。只要是上傳RAW的時候,就只能放棄getimagesize,改用ExifTool來讀取照片大小。雖然從PHP呼叫外部程式會花費更多時間,但是相較於上傳RAW照片本身就需要更多時間,在上傳照片完成之後,再多花一點時間呼叫ExifTool來讀出EXIF,取出照片大小,用來判別照片大小,儲存在MySQL的bx_photos_main裡面,雖然會略慢一點點,但因為上傳照片的會員不多,應該不會有什麼太大的感覺。
修正Bug之後(雖然這個Bug不是我造成的),新的程式碼改寫成這樣:
if ($RAW != '') {
$pSize = $this->getPhotoSize($sTempFileName); // 讀取RAW照片大小
if (!$pSize) return false;
$iImgWidth = (int)$pSize[0];
$iImgHeight = (int)$pSize[1];
}
else {
$iImgWidth = (int)$aSize[0];
$iImgHeight = (int)$aSize[1];
}
if (!(($iImgWidth >= 1280 && $iImgHeight >= 600) || ($iImgWidth >= 600 && $iImgHeight >= 1280))) { //BNW 照片大小必須是1280x1280以上
@unlink($sTempFileName);
return false;
}
這段PHP程式碼會先判別上傳的是不是RAW,如果不是,就還是用原本的getimagesize來讀取照片大小(同時還會讀出圖檔類型是JPEG、GIF、PNG),但如果上傳的是RAW照片的話,就會執行getPhotoSize副程式,再由getPhotoSize去呼叫外部的ExifTool,再讀出照片大小。
由於熱心網友ayaka提出【非同步處理】的寶貴意見,所以在這裡的ExifTool只會讀出照片大小,用來記錄在bx_photos_main的Size這個資料欄位。等到【非同步處理RAW或是JPEG】的時候,還需要再執行一次ExifTool讀出EXIF資訊,並且呼叫我寫的class BnwPhotoEXIF,來分析處理EXIF,把EXIF判別的結果記錄在bnw_photo_exif裡面。
