在Symfony框架開發的項目上,需要製作上傳檔案功能,很多時為了加快開發速度,都會使用第三方插件。
提供上傳檔案功能這一類的插件非常多,在這次項目上使用了OneupUploaderBundle這一個插件。
OneupUploaderBundle提供了一個命名上傳檔案的介面,預設情況下,上載的檔案會使用uniqid函數處理。
oneup/uploader-bundle/Oneup/UploaderBundle/Uploader/Naming/UniqidNamer.php
public function name(FileInterface $file)
{
return sprintf('%s.%s', uniqid(), $file->getExtension());
}
但這次需求上,上傳的檔案名稱需要和原檔名相同,所以自訂了一個namer介面。
public function name(FileInterface $file)
{
$suffix = '';
$name = $file->getClientOriginalName();
$name = substr($name,0, mb_strrpos($name, '.')); //取得檔案名稱
$number = 2; //如檔名已存在,則於檔名後加入一個數值
while(true) {
$filePath = sprintf('%s%s%s.%s',
$this->container->getParameter('oneup_fineuploader_directory'),
$name,
$suffix,
$file->getExtension()
);
if(file_exists($filePath)) {
$suffix = '(' . $number .')';
} else {
break;
}
$number++;
}
return sprintf('%s%s.%s',
$name,
$suffix,
$file->getExtension()
);
}
但測試時發現上傳的檔名開頭如果為中文時(除了英文和中文,其它語言沒有測試),上傳後在系統找回該檔案會沒有了中文的部份。追查後發現插件於命名函數裹使用了basename函數,因為basename函數依賴於區域設置,如果是多字節名稱返回為空,可以通過setlocale函數作如下設置。
oneup/uploader-bundle/Oneup/UploaderBundle/Uploader/Storage/FilesystemStorage.php
public function upload(FileInterface $file, $name, $path = null)
{
$path = is_null($path) ? $name : sprintf('%s/%s', $path, $name);
$path = sprintf('%s/%s', $this->directory, $path);
// now that we have the correct path, compute the correct name
// and target directory
$targetName = basename($path);
$targetDir = dirname($path);
$file = $file->move($targetDir, $targetName);
return $file;
}
所以最後我選擇在Symfony的入口加入這個設置,中文命名的檔案上傳亦沒有問題。
web/app.php
web/app_dev.php
setlocale(LC_ALL, 'zh_TW.UTF-8');
鏈結到這頁!