文件存储

未匹配的标注

File Storage

简介

Laravel 提供了一个强大的文件系统抽象概念,这得益于 Frank de Jonge 强大的 Flysystem 扩展包。Laravel 文件系统集成为使用本地文件系统、Amazon S3 和 Rackspace 云存储提供了简单易用的驱动程序。更棒的是,由于每个系统的 API 保持不变,所以在这些存储选项之间切换是非常简单的。

配置

文件系统的配置文件位于config/filesystems.php。在这个文件中你可以配置所有「磁盘」。每个磁盘代表特定的存储驱动及存储位置。每种支持的驱动程序的示例配置都包含在配置文件中。因此,只需要修改配置即可反映你的存储偏好和凭据。
当然,你可以根据需要配置多个磁盘,甚至你还可以使多个磁盘共用同一个驱动。

公共磁盘

public 磁盘适用于要公开访问的文件。默认情况下, public 磁盘使用 local 驱动,并且将这些文件存储在 storage/app/public 目录下。为了使它们能通过网络访问,你需要创建从 public/storagestorage/app/public 的符号链接。这种方式能把可公开访问文件都保留在同一个目录下,以便在使用零停机时间部署系统如 Envoyer 的时候,就可以轻松地在不同的部署之间共享这些文件。

你可以使用 Artisan 命令 storage:link 来创建符号链接:

php artisan storage:link

一旦一个文件被存储并且已经创建了符号链接,你就可以使用辅助函数 asset 来创建文件的 URL:

echo asset('storage/file.txt');

您可以在您的 filesystems 配置文件中配置额外的符号链接。 每一个配置的链接创建时,将运行 storage:link 命令:

'links' => [
    public_path('storage') => storage_path('app/public'),
    public_path('images') => storage_path('app/images'),
],

本地驱动

使用 local 驱动时,所有文件操作都与 filesystems 配置文件中定义的 root 目录相关。 默认情况下,此值设置为 storage/app 目录。 因此,以下方法会把文件存储在 storage/app/file.txt 中:

Storage::disk('local')->put('file.txt', 'Contents');

权限

public 可见性 转换为目录的 0755 和文件的 0644。 你可以修改 filesystems 配置文件中的权限映射:

'local' => [
    'driver' => 'local',
    'root' => storage_path('app'),
    'permissions' => [
        'file' => [
            'public' => 0664,
            'private' => 0600,
        ],
        'dir' => [
            'public' => 0775,
            'private' => 0700,
        ],
    ],
],

驱动程序先决条件

Composer 包

在使用 SFTP、S3 驱动之前,你需要通过 Composer 安装相应的软件包:

  • SFTP: league/flysystem-sftp ~1.0
  • Amazon S3: league/flysystem-aws-s3-v3 ~1.0

使用缓存适配器是提高性能的一个绝对必要条件。你需要一个额外的包:

  • CachedAdapter: league/flysystem-cached-adapter ~1.0

S3 驱动配置

S3 驱动配置信息位于你的 config/filesystems.php 配置文件中。该文件包含 S3 驱动程序的示例配置数组。 你可以自由使用你自己的 S3 配置和凭证修改此配置数组。 为方便起见,这些环境变量与 AWS CLI 使用的命名约定相匹配。

FTP 驱动配置

Laravel 的文件系统集成能很好的适配 FTP,不过 FTP 的配置示例并没有被包含在框架默认的 filesystems.php 文件中。如果你需要配置 FTP 文件系统,则需要使用如下配置内容:

'ftp' => [
    'driver' => 'ftp',
    'host' => 'ftp.example.com',
    'username' => 'your-username',
    'password' => 'your-password',

    // Optional FTP Settings...
    // 'port' => 21,
    // 'root' => '',
    // 'passive' => true,
    // 'ssl' => true,
    // 'timeout' => 30,
],

SFTP 驱动器的配置

Laravel 的 Flysystem 集成包可以很好的适配 SFTP;只不过在该框架的默认配置文件 filesystems.php 中并没有包含示例。如果你需要配置 SFTP 文件系统,则需要使用如下配置内容:

'sftp' => [
    'driver' => 'sftp',
    'host' => 'example.com',
    'username' => 'your-username',
    'password' => 'your-password',

    // Settings for SSH key based authentication...
    // 'privateKey' => '/path/to/privateKey',
    // 'password' => 'encryption-password',

    // Optional SFTP Settings...
    // 'port' => 22,
    // 'root' => '',
    // 'timeout' => 30,
],

缓存

给指定磁盘开启缓存功能,需要在该磁盘的配置项中直接添加 cache 配置项。 cache 配置内容是以数组形式存在的,由缓存驱动名称 store (译者注:文档原始描述文字 disk 与示例代码中的 store 不一致,验证代码后的确应该是 store ,故作此修改。)、 缓存过期时间 expire(单位:秒) ,以及缓存前缀 prefix 组成:

's3' => [
    'driver' => 's3',

    // Other Disk Options...

    'cache' => [
        'store' => 'memcached',
        'expire' => 600,
        'prefix' => 'cache-prefix',
    ],
],

获取磁盘实例

Storage 门面适用于所有已配置的磁盘进行交互。例如,你可以使用门面中的 put 方法将头像存储到默认磁盘。如果你使用 Storage 门面时并没有使用 disk 方法,那么所有的方法调用将会自动传递给默认的磁盘:

use Illuminate\Support\Facades\Storage;

Storage::put('avatars/1', $fileContents);

如果应用程序要与多个磁盘进行互操作,可使用 Storage 门面中的 disk 方法对特定磁盘上的文件进行操作:

Storage::disk('s3')->put('avatars/1', $fileContents);

检索文件

get 方法可以用于检索文件的内容,此方法返回该文件的原始字符串内容。 切记,所有文件路径的指定都应该相对于为磁盘配置的「root」目录:

$contents = Storage::get('file.jpg');

exists 方法可以用来判断磁盘上是否存在指定的文件:

$exists = Storage::disk('s3')->exists('file.jpg');

missing 方法可以用来判断磁盘上是否缺少指定的文件:

$missing = Storage::disk('s3')->missing('file.jpg');

下载文件

download 方法可用于生成一个响应,强制用户的浏览器在给定路径下载文件。 download 方法接受一个文件名作为该方法的第二个参数,它将确定用户下载文件时看到的文件名。最后,你可以传递一个 HTTP 请求头的配置数组作为该方法的第三个参数:

return Storage::download('file.jpg');

return Storage::download('file.jpg', $name, $headers);

文件 URLs

你可以使用 url 方法来获取给定文件的 URL。如果你使用的是 local 驱动,通常会给指定的路径前加上 /storage 并返回文件的相对 URL 地址。如果使用的是 s3驱动,则返回完整的远程 URL:

use Illuminate\Support\Facades\Storage;

$url = Storage::url('file.jpg');

注意:切记,如果使用的是 local 驱动,所有想被公开访问的文件都应该放在 storage/app/public 目录下。此外,你需要在 public/storage创建符号链接storage/app/public 目录上。

临时 URLs

对于使用 s3 驱动来存储文件,可以使用 temporaryUrl 方法创建给定文件的临时 URL。这个方法会接收路径和 DateTime 实例来指定 URL 何时过期:

$url = Storage::temporaryUrl(
    'file.jpg', now()->addMinutes(5)
);

对于使用 s3 驱动来存储文件,可以使用 temporaryUrl 方法创建给定文件的临时 URL。这个方法会接收路径和 DateTime 实例来指定 URL 何时过期: S3 request parameters, 你可以传递一个数组作为 temporaryUrl 方法的第三个参数:

$url = Storage::temporaryUrl(
    'file.jpg',
    now()->addMinutes(5),
    ['ResponseContentType' => 'application/octet-stream']
);

自定义本地 URL 主机

如果要使用 local 驱动为存储在磁盘上的文件预定义主机,可以向磁盘配置数组添加一个 url 选项:

'public' => [
    'driver' => 'local',
    'root' => storage_path('app/public'),
    'url' => env('APP_URL').'/storage',
    'visibility' => 'public',
],

文件元数据

除了读写文件外,Laravel 还可以提供有关文件本身的信息,例如,size 方法可用来获取文件的大小(以字节为单位):

use Illuminate\Support\Facades\Storage;

$size = Storage::size('file.jpg');

lastModified 方法返回文件最后一次被修改的 UNIX 时间戳:

$time = Storage::lastModified('file.jpg');

保存文件

put 方法可用于将原始文件内容保存到磁盘上。你也可以传递 PHP 的 resourceput 方法,它将使用文件系统下的底层流支持。切记,所有的文件路径都是相对于磁盘配置中「根」的路径:

use Illuminate\Support\Facades\Storage;

Storage::put('file.jpg', $contents);

Storage::put('file.jpg', $resource);

自动流式传输

您可以使用 putFileputFileAs 方法来让 Laravel 自动将给定的文件流式传输到您的存储位置。该方法接收一个 Illuminate\Http\FileIlluminate\Http\UploadedFile 实例并自动将文件流式传输到您想要的位置:

use Illuminate\Http\File;
use Illuminate\Support\Facades\Storage;

// 自动为文件名生成唯一 ID ……
Storage::putFile('photos', new File('/path/to/photo'));

// 手动指定文件名……
Storage::putFileAs('photos', new File('/path/to/photo'), 'photo.jpg');

关于 putFile 方法,有一些重点需要注意。请注意我们仅仅指定了目录名。默认情况下, putFile 方法将生成唯一的 ID 并将其作为文件名。文件的扩展名则是根据文件的 MIME 类型来进行判断。putFile 方法会返回文件的路径,您可以将其和生成的文件名存储到数据库中。

putFileputFileAs 方法接收一个参数用来指定存储文件的「可见性」。当您将文件存储到诸如 S3 的云盘上,并且想让其能够公开访问,此时,此举(指定存储文件的可见性)就很有帮助:

Storage::putFile('photos', new File('/path/to/photo'), 'public');

文件数据写入

prependappend 方法允许您在文件的开头和末尾写入数据:

Storage::prepend('file.log', 'Prepended Text');

Storage::append('file.log', 'Appended Text');

复制和移动文件

您可以使用 copy 方法来复制一个已经存在的文件到磁盘上的一个新位置,而 move 方法则可以重命名或移动一个已经存在的文件到新位置:

Storage::copy('old/file.jpg', 'new/file.jpg');

Storage::move('old/file.jpg', 'new/file.jpg');

文件上传

在 Web 应用中,最常见的文件存储用例便是上传用户头像、照片和文档。Laravel 上传文件的 store 方法可以轻松处理上传文件的存储。您只需要调用 store 方法,并将您预期的文件存储位置作为参数传递给它:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class UserAvatarController extends Controller
{
    /**
     * 上传用户头像。
     *
     * @param  Request  $request
     * @return Response
     */
    public function update(Request $request)
    {
        $path = $request->file('avatar')->store('avatars');

        return $path;
    }
}

在这个例子中,有一些重点需要注意。我们仅仅指定了目录名,并没有指定文件名。默认情况下,store 方法将会自动生成一个唯一的 ID 并将其作为文件的名称。而文件的扩展名则是根据文件的 MIME 类型来进行判断的。store 方法将会返回文件的路径,您可将其与生成的文件名一起存到数据库中。

您亦可调用 Storage 门面的 putFile 方法达到与上述例子中相同的效果:

$path = Storage::putFile('avatars', $request->file('avatar'));

指定一个文件名

如果您不想让应用在存储文件过程中自动生成文件名,您可以使用 storeAs 来实现之。该方法接受路径,文件名以及磁盘(可选)作为其参数:

$path = $request->file('avatar')->storeAs(
    'avatars', $request->user()->id
);

您亦可使用 Storage 门面的 putFileAs 方法来实现与上述例子中相同的效果:

$path = Storage::putFileAs(
    'avatars', $request->file('avatar'), $request->user()->id
);

注意:文件路径中的非打印字符和无效的 unicode 字符将会被自动移除。因此,您可能希望在将路径传递给 Laravel 的文件存储方法前对其进行清理,您可以使用 League\Flysystem\Util::normalizePath 方法对其进行规范。

指定一个磁盘

默认情况下,store 方法将使用默认的磁盘。如果您希望指定另一块磁盘,请将磁盘名称作为 store 方法的第二个参数传递给它:

$path = $request->file('avatar')->store(
    'avatars/'.$request->user()->id, 's3'
);

如果您使用 storeAs 方法,您可以将磁盘名称作为该方法的第三个参数:

$path = $request->file('avatar')->storeAs(
    'avatars',
    $request->user()->id,
    's3'
);

其他文件信息

您可以使用 getClientOriginalName 方法来获取上传文件的原始名称:

$name = $request->file('avatar')->getClientOriginalName();

extension 可用于获取上传文件的扩展名:

$extension = $request->file('avatar')->extension();

文件的可见性

在 Laravel 继承的文件系统中,「可见性」是一个针对多平台的权限的抽象概念。文件可以定义为 publicprivate 。当文件被定义为 public 时,意味着其他人可以访问之。例如,当您使用 S3 驱动的时候,您可以检索声明为 public 的文件的 URL 。

在使用 put 方法的时候,您可以设置文件的可见性:

use Illuminate\Support\Facades\Storage;

Storage::put('file.jpg', $contents, 'public');

您可以使用 getVisibilitysetVisibility 方法对现有文件的可见性进行检索和设置:

$visibility = Storage::getVisibility('file.jpg');

Storage::setVisibility('file.jpg', 'public');

当和上传文件交互的时候,您可以使用 storePubliclystorePubliclyAs 方法来将文件的可见性设置为 public 并存储之:

$path = $request->file('avatar')->storePublicly('avatars', 's3');

$path = $request->file('avatar')->storePubliclyAs(
    'avatars',
    $request->user()->id,
    's3'
);

删除文件

delete 方法接收一个文件名或一个文件名数组来将其从磁盘中删除:

use Illuminate\Support\Facades\Storage;

Storage::delete('file.jpg');

Storage::delete(['file.jpg', 'file2.jpg']);

如果有必要,您可以指定删除的文件的磁盘:

use Illuminate\Support\Facades\Storage;

Storage::disk('s3')->delete('folder_path/file_name.jpg');

目录

获取目录下所有的文件

files 将以数组的形式返回给定目录下所有的文件。如果您想要检索给定目录的所有文件及其子目录的所有文件,您可以使用 allFiles 方法:

use Illuminate\Support\Facades\Storage;

$files = Storage::files($directory);

$files = Storage::allFiles($directory);

获取特定目录下的子目录

directories 方法以数组的形式返回给定目录中的所有目录。此外,您还可以使用 allDirectories 方法递归地获取给定目录中的所有目录及其子目录中的目录:

$directories = Storage::directories($directory);

// 递归……
$directories = Storage::allDirectories($directory);

创建一个目录

makeDirectory 方法可递归的创建指定的目录:

Storage::makeDirectory($directory);

删除一个目录

最后,deleteDirectory 方法可用于删除一个目录及其下所有的文件:

Storage::deleteDirectory($directory);

自定义文件系统

Laravel 内置的文件系统提供了一些开箱即用的驱动;当然,它不仅仅是这些,它还提供了与其他存储系统的适配器。通过这些适配器,您可以在您的 Laravel 应用中创建自定义驱动。

要安装自定义文件系统,您可能需要一个文件系统适配器。让我们将社区维护的 Dropbox 适配器添加到项目中:

composer require spatie/flysystem-dropbox

接下来,您可以创建一个诸如 DropboxServiceProvider 这样的 服务提供者 。在提供者的 boot 方法中,您可以使用 Storage 门面的 extend 方法来定义一个自定义驱动:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Storage;
use Illuminate\Support\ServiceProvider;
use League\Flysystem\Filesystem;
use Spatie\Dropbox\Client as DropboxClient;
use Spatie\FlysystemDropbox\DropboxAdapter;

class DropboxServiceProvider extends ServiceProvider
{
    /**
     * 注册应用服务。
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * 驱动应用服务。
     *
     * @return void
     */
    public function boot()
    {
        Storage::extend('dropbox', function ($app, $config) {
            $client = new DropboxClient(
                $config['authorization_token']
            );

            return new Filesystem(new DropboxAdapter($client));
        });
    }
}

extend 方法的第一个参数是驱动的名称,第二个参数是一个闭包函数,这个闭包函数接收 $app$config 变量。解析器的闭包函数必须返回一个 League\Flysystem\Filesystem 的实例。$config 变量包含了指定磁盘在 config/filesystems.php 文件中定义的值。

接下来,在您的 config/app.php 配置文件中注册服务提供者:

'providers' => [
    // ...
    App\Providers\DropboxServiceProvider::class,
];

当您成功注册了一个扩展的服务提供者后,您便可以在您的 config/filesystems.php 配置文件中使用 dropbox 驱动。

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
上一篇 下一篇
Summer
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
贡献者:3
讨论数量: 0
发起讨论 只看当前版本


暂无话题~