Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cakephp response cannot read UTF-8 file name

I want to download the file after login check so wrote a function in my controller like

// 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'));
    }
} 

Now, everything works fine as required.

PROBLEM : when the file name is in UTF-8 eg. テスト.pdf (its Test.pdf in japanese) cakephp throws error like this.

enter image description here

For English filename it works perfectly fine but my client wants the filename should be the same as uploaded, so I can't change the filename to English.

like image 506
Umar Sid Avatar asked Jun 21 '26 04:06

Umar Sid


1 Answers

If you want to know character encoding, you can use mb_detect_encoding() function if input text has enough length to detect encoding. But I am guessing your client would upload SJIS file. Because most Japanese people are using SJIS, as Windows has adopted SJIS for Japanese language.

I confirmed your code in my local environment. As cake's File class seems to be not able to handle SJIS correctly, you cannot use Response::file(). So I wrote alternative code.

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'));
    }
} 

However, I recommend you to convert SJIS to UTF8 before save it into your database and your disk. It is difficult to handle SJIS characters without enough knowledge about it. Because SJIS characters may contain ascii characters in the second byte. Especially backslash (\) is most dangerous. For example, 表 (955C) contains a backslash (5C = backslash). Note that I am not talking about rare cases. 表 means table or appearance in Japanese. 十 also contains a backslash and it means 10 in Japanese. 能 also contains a backslash and it means skill.

Unlike UTF-8 byte sequence, if you handle SJIS characters, almost all string functions don't work correctly. explode() would break SJIS byte sequence. strpos() would return wrong result. Does your client connect to your server by using FTP or SCP directly? If not, it would be better to convert SJIS to UTF-8 before save, and re-convert UTF-8 to SJIS before return to your client.

like image 110
Kurita Takashi Avatar answered Jun 22 '26 16:06

Kurita Takashi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!