John
John

Reputation: 337

laravel 4 The filename fallback must only contain ASCII characters

My file has UTF-8 (greek) characters and i am unable to download it. I am using laravel 4. Here is my code:

//download

Route::get('file/download', function()
{
$file = 'uploads/πτυχιακή.odt';
return Response::download($file);
});

I get the following error(invalidArgumentException) message :the filename fallback must only contain ASCII characters

Any ideas of how to fix that issue..?

Upvotes: 2

Views: 11638

Answers (3)

Pawan Verma
Pawan Verma

Reputation: 1269

You can't use / in the filename. If your file name contains / first remove it.

$file_name = str_replace(array("/", "\\", ":", "*", "?", "«", "<", ">", "|"), "-", $data->title);
$tempVideo = tempnam(sys_get_temp_dir(), $file_name);
copy($data->file, $tempVideo);            
return response()->download($tempVideo, $file_name);

Upvotes: 0

joseca
joseca

Reputation: 306

It's a bug in the Response::download function. Change it to:

// File: vendor/laravel/framework/src/Illuminate/Support/Facades/Response.php

public static function download($file, $name = null, array $headers = array(), $disposition = 'attachment')
{
    $response = new BinaryFileResponse($file, 200, $headers, true);

    if (is_null($name))
    {
        $name = basename($file);
    }

   return $response->setContentDisposition($disposition, $name, Str::ascii($name));
}

https://github.com/laravel/framework/pull/4296

Laravel 5

In Laravel 5, you can extend the \Illuminate\Routing\ResponseFactory class and override the download() method. Then, in a ServiceProvider, register your custom ResponseFactory as the default one:

// We extends \Illuminate\Routing\ResponseFactory class, that implements Illuminate\Contracts\Routing\ResponseFactory

$this->app->singleton('Illuminate\Contracts\Routing\ResponseFactory', function ($app) {
    return new MyCustomResponseFactoryExtendedFromResponseFactory($app['Illuminate\Contracts\View\Factory'], $app['redirect']);
});

Doing this, you can use the default methods (Response::json(), respose()->view(), etc) and your custom methods in the same way: Response::download(), _response()->download

Upvotes: 9

Philippe
Philippe

Reputation: 51

As it is stated in http://laravel.com/docs/responses#special-responses:

Note: Symfony HttpFoundation, which manages file downloads, requires the file being downloaded to have an ASCII file name.

If I understand this correctly, ideally the filename should be stored with an ascii filename during the upload process and then returned with:

return Response::download(<ascii_filename>);

This is fine if it is acceptable that the filename is not the same as when it was uploaded.

However, if the filename must not change then the download of the file should triggered with:

return Response::download(<ascii_filename>, <original_file_name>);

This means that it is necessary to keep track of the original filename after storing the file during the upload process. This can be achieved either by simplifying the filename and storing the original filename in a database or by storing the filename with a name encoded in such a way that it can be converted back to its original name.

Keeping track of the original filename in a database makes it possible to simplify the filenames so that they are very recognisable (e.g. 'hallå där.txt' -> 'halla dar.txt').

However, using a database is not always an option. There are different ways of converting UTF-8 or ISO-8859-1 strings to ASCII in a way that they can be converted back (e.g. base64_encode / base64_decode, mb_convert_encoding and others), each with pros and cons (for example, depending on if you want to be able to store the file with a recognizable name).

Upvotes: 2

Related Questions