Laravel 5.1におけるdownloadアクションの日本語ファイル名対応

More than 3 years have passed since last update.


日本語ファイルがダウンロードできない

Laravelには便利なアクションがあって、以下のようなコードで簡単にファイルをダウンロードさせられるのだが


何かのコントローラの何かのアクション

public function test(Request $request)

{
$filePath = '/var/www/hogehoge.zip';

return response()->download($filePath);
}


以下だとThe filename fallback must only contain ASCII charactersと怒られてしまう。


何かのコントローラの何かのアクション

public function test(Request $request)

{
$filePath = '/var/www/ほげほげ.zip';

return response()->download($filePath);
// InvalidArgumentException
}


これは内部で利用しているSymfonyのコンポーネントが引数をASCIIで受け取ることを前提としているせい。


どうすればいいのか

ちょっと前のLaravelであれば、訂正版:Laravelのエラー「The filename fallback must only contain ASCII characters」の対処法のようにして対応することができる。

しかし、Laravel 5.1ではマクロ周りの仕様が変わっており、このまま対応することはできない。

というわけで、5.1の仕様に則した方法をメモ。

まず、app\Providersあたりに"ResponseMacroServiceProvider"としてサービスプロバイダを作成。(別にプロバイダの名前はなんでもいい)

あとはおもむろに以下のように書く。


ResponseMacroServiceProvider.php

namespace App\Providers; // 名前空間を変更しているなら適宜直しましょう

use Illuminate\Support\Str;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Routing\ResponseFactory;
use Symfony\Component\HttpFoundation\BinaryFileResponse;

class ResponseMacroServiceProvider extends ServiceProvider
{

public function boot(ResponseFactory $factory)
{
// ここではdownloadExとして登録していますが、何でも良いです
$factory->macro('downloadEx', function($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));
});
}

// registerは今回特に必要ないです
/**
* Register the service provider.
*
* @return void
*/

public function register()
{
// TODO: Implement register() method.
}
}


あとはconfig\app.phpにサービスプロバイダとして

ResponseMacroServiceProviderを追加。


app.php

return [

// ~省略~
'providers' => [
// ~省略~
App\Providers\ResponseMacroServiceProvider::class,
];
// ~省略 ~
];

これで完了。あとは最初のコードをこんな感じにするだけ。


何かのコントローラの何かのアクション

public function test(Request $request)

{
$filePath = '/var/www/ほげほげ.zip';

return response()->downloadEx($filePath);
// OK!
}


簡単で今までよりも見通しがよくなりました。バンザイ!


参考

Laravel 5.1 サービスプロバイダー

訂正版:Laravelのエラー「The filename fallback must only contain ASCII characters」の対処法