📝
LaravelのファイルストレージにS3を使用したときにurlメソッドでファイルのURLが取得できない原因と対策
概要
LaravelのファイルストレージでS3ドライバを使用しているとき、下記のようなコードで指定したファイルのURLを取得できるはずが相対パスが返ってきた場合の原因と解決法をメモ。
// Laravelのファイルストレージのページから引用
use Illuminate\Support\Facades\Storage;
$url = Storage::url('file.jpg');
バージョン
- Laravel Framework 8.10.0
原因
s3ドライバーを使用している場合は、完全修飾リモートURLが返されます。
Laravelのドキュメントにこのように記載してあるのでどんな実装になっているのかurl
メソッドを調査。/Illuminate/Filesystem/FilesystemAdapter.php
にurl
メソッドがあるので読んでみる。
/**
* Get the URL for the file at the given path.
*
* @param string $path
* @return string
*
* @throws \RuntimeException
*/
public function url($path)
{
$adapter = $this->driver->getAdapter();
if ($adapter instanceof CachedAdapter) {
$adapter = $adapter->getAdapter();
}
if (method_exists($adapter, 'getUrl')) {
return $adapter->getUrl($path);
} elseif (method_exists($this->driver, 'getUrl')) {
return $this->driver->getUrl($path);
} elseif ($adapter instanceof AwsS3Adapter) {
return $this->getAwsUrl($adapter, $path);
} elseif ($adapter instanceof Ftp || $adapter instanceof Sftp) {
return $this->getFtpUrl($path);
} elseif ($adapter instanceof LocalAdapter) {
return $this->getLocalUrl($path);
} else {
throw new RuntimeException('This driver does not support retrieving URLs.');
}
}
S3ドライバの時はgetAwsUrl
メソッドが呼ばれるので追ってみる。
/**
* Get the URL for the file at the given path.
*
* @param \League\Flysystem\AwsS3v3\AwsS3Adapter $adapter
* @param string $path
* @return string
*/
protected function getAwsUrl($adapter, $path)
{
// If an explicit base URL has been set on the disk configuration then we will use
// it as the base URL instead of the default path. This allows the developer to
// have full control over the base path for this filesystem's generated URLs.
if (! is_null($url = $this->driver->getConfig()->get('url'))) {
return $this->concatPathToUrl($url, $adapter->getPathPrefix().$path);
}
return $adapter->getClient()->getObjectUrl(
$adapter->getBucket(), $adapter->getPathPrefix().$path
);
}
下記のコードからS3ドライバの設定でurlを指定しているとバケットにあるオブジェクトのURLが返ってこないことが判明。
// getAwsUrlメソッドから抜粋
if (! is_null($url = $this->driver->getConfig()->get('url'))) {
return $this->concatPathToUrl($url, $adapter->getPathPrefix().$path);
}
解決策
Laravelのconfig/filesystems.php
でS3ドライバのデフォルトは下記のようになっているので
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
],
'url' => null,
と変更。
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => null,
'endpoint' => env('AWS_ENDPOINT'),
],
おわりに
設定項目があるからと適当にAWS_URLという環境変数と値を設定してしまったのが原因なのできちんと必要なものだけ設定せねばなと。
Discussion