我想在登录检查后下载文件,所以在我的控制器中写了一个函数
// Function to check login and download News PDF file
public function download(){
if($this->Auth->user()){
// Get the news file path from newsId
$pNewsObj = ClassRegistry::init('PublicNews');
$news = $pNewsObj->findById($newsId);
$filePath = ROOT.DS.APP_DIR.DS.'webroot/upload_news'.DS.$news['PublicNews']['reference'];
// Check if file exists
if(!file_exists($filePath)){
return $this->redirect('/404/index.php');
}
$this->response->charset('UTF-8');
//$this->response->type('pdf');
$this->response->file('webroot/upload_news'.DS.$news['PublicNews']['reference'], array('download' => true, 'name' => $news['PublicNews']['reference']));
//$this->response->download($news['PublicNews']['reference']);
return $this->response;
}else{
return $this->redirect(array('controller'=> 'users', 'action' => 'login'));
}
}
现在,一切都按要求进行。
问题:当文件名是utf-8时,例如__.pdf(它的test.pdf是日语)cakephp会抛出这样的错误。
对于英文文件名,它工作得很好,但我的客户希望文件名应该与上传的文件名相同,所以我无法将文件名更改为英文。
最佳答案
如果您想知道字符编码,如果输入文本有足够的长度来检测编码,则可以使用mb_detect_encoding()
函数。
但我猜你的客户会上传sjis文件。因为大多数日本人都在使用sjis,因为windows已经将sjis用于日语。
我在本地环境中确认了你的代码。由于cake的File
类似乎无法正确处理sjis,因此不能使用Response::file()
。所以我写了另一个代码。
public function download(){
if($this->Auth->user()){
// Get the news file path from newsId
$pNewsObj = ClassRegistry::init('PublicNews');
$news = $pNewsObj->findById($newsId);
if (!$news) {
throw new NotFoundException();
}
$fileName = mb_convert_encoding($news['PublicNews']['reference'], 'SJIS-win', 'UTF8');
// Directory traversal protection
if (strpos($fileName, '..') !== false) {
throw new ForbiddenException();
}
$filePath = WWW_ROOT . 'upload_news' . DS . $fileName;
if (!is_readable($filePath)) {
throw new NotFoundException();
}
if (function_exists('mime_content_type')) {
$type = mime_content_type($filePath);
$this->response->type( $type );
} else {
// TODO: If Finfo extension is not loaded, you need to detect content type here;
}
$this->response->download( $fileName );
$this->response->body( file_get_contents($filePath) );
return $this->response;
}else{
return $this->redirect(array('controller'=> 'users', 'action' => 'login'));
}
}
但是,我建议您在将sjis保存到数据库和磁盘之前将其转换为utf8。没有足够的知识很难处理sjis字符。因为sjis字符可能在第二个字节中包含ascii字符。尤其是反斜杠(\)最危险。例如,表(955c)包含反斜杠(5c=反斜杠)。注意,我不是在说罕见的病例。表在日语中是指桌子或外观。十还包含一个反斜杠,在日语中是10。还有一个反斜杠,意思是技巧。
与utf-8字节序列不同,如果处理sjis字符,几乎所有字符串函数都不能正常工作。
explode()
会破坏sjis字节序列。strpos()
将返回错误的结果。您的客户机是否直接使用ftp或scp连接到服务器?否则,最好在保存之前将sjis转换为utf-8,并在返回到客户端之前将utf-8重新转换为sjis。