Help us understand the problem. What is going on with this article?

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」の対処法

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away