文件儲存


#檔案儲存

#簡介

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 來建立符號連結:

你可以使用Artisan 指令storage:link 來建立符號連結:

php artisan storage:link

當然,一旦一個檔案被儲存並且已經創建了符號鏈接,你就可以使用輔助函數asset 來創建文件的URL:

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

本機驅動程式

使用local 驅動程式時,所有檔案操作都與你在設定檔中定義的root 目錄相關。該目錄的預設值是 storage/app 。因此,以下方法會將檔案儲存在storage/app/file.txt 中:

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

##驅動程式先決條件

Composer 套件

在使用SFTP、S3 或Rackspace 等驅動程式之前,你需要透過Composer 安裝對應的軟體包:

    SFTP:
  • league/flysystem-sftp ~1.0
  • Amazon S3:
  • league/flysystem-aws-s3-v3 ~1.0
  • # Rackspace:
  • league/flysystem-rackspace ~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' => [
    'driver'   => 'ftp',    
    'host'     => 'ftp.example.com',    
    'username' => 'your-username',    
    'password' => 'your-password',    
    // 可选的 FTP 配置项...    
    // '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',    
    // 基于 SSH 密钥的身份验证设置...    
    // 'privateKey' => '/path/to/privateKey',    
    // 'password' => 'encryption-password',    
    // 可选的 SFTP 配置...    
    // 'port' => 22,    
    // 'root' => '',    
    // 'timeout' => 30,
   ],

Rackspace 磁碟機設定

Laravel 的Flysystem 整合套件與Rackspace 協同得非常好;不過,在此框架的預設設定檔filesystems.php 中並沒有包含示範配置。如果要配置Rackspace 檔案系統,可以使用下列範例配置:

'rackspace' => [
    'driver'    => 'rackspace',    
    'username'  => 'your-username',    
    'key'       => 'your-key',    
    'container' => 'your-container',    
    'endpoint'  => 'https://identity.api.rackspacecloud.com/v2.0/',    
    'region'    => 'IAD',    
    'url_type'  => 'publicURL',
  ],

#快取

#為指定磁碟開啟快取功能,需要在該磁碟的設定項中直接新增cachecache 選項應該是快取配置的數組,由快取驅動名稱store(譯者註:文件原始描述文字disk 與範例程式碼中的store 不一致,驗證程式碼後的確應該是store ,故作此修改。)、單位為秒的過期時間expire ,以及快取前綴prefix 組成:

's3' => [
    'driver' => 's3',    
   // 驱动器其他配置...    
    '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');

下載檔案

#download 方法可用來產生一個回應,強制使用者的瀏覽器在給定路徑下載檔案。 download 方法接受一個檔案名稱作為該方法的第二個參數,它將決定使用者下載檔案時看到的檔案名稱。最後,你可以傳遞一個 HTTP 陣列頭作為該方法的第三個參數:

return response()->download('file.jpg');
return response()->download('file.jpg', $name, $headers);

檔案 URLs

你可以使用 url 方法來取得給定檔案的 URL。如果你使用的時 local 驅動,一般只是在給定的路徑上加上 /storage 並返回一個相對的 URL 到那個文件。如果使用的是s3 或是rackspace 驅動,會傳回完整的遠端URL:

use Illuminate\Support\Facades\Storage;
$url = Storage::url('file.jpg');

{note} 切記,如果使用的是local 驅動,則所有想公開存取的檔案都應該放在storage/app/public 目錄下。另外你應該在 public/storage 建立一個符號連結 來指向 storage/app/public 目錄。

臨時URLs

當使用s3rackspace 驅動程式來儲存文件,可以使用 temporaryUrl 方法建立給定檔案的暫存URL。這個方法會接收路徑和DateTime 實例來指定URL 何時過期:

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

自訂本機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);
#

自動串流

如果你想Laravel 自動將給定檔案串流到你的儲存位置,你可以使用putFileputFileAs 方法。這個方法接收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 Illuminate\Http\Request;
    use App\Http\Controllers\Controller;
    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 facade 上的putFile 方法達到和上例同樣的效果:

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

#指定檔案名稱

如果你不想將檔案名稱自動指派給儲存的文件,可以使用storeAs 方法,該方法接受路徑,檔案名稱和(可選) 磁碟作為其參數:

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

你可以使用Storage facade 上的putFileAs 方法達到和上例同樣的檔案操作:

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

指定磁碟

預設情況下, store 方法使用預設磁碟。如果你需要指定其他的磁碟,可以傳入磁碟名稱作為store 方法的第二個參數:

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

檔案可見性

在Laravel 整合的檔案系統中,「可見性」是對多個平台的檔案權限的抽象。檔案可以宣告為 publicprivate。如果一個檔案被宣告為 public,表示其他人可以存取。例如,使用 S3 驅動程式時,就可以擷取宣告為 public 的檔案。

你可以透過put 方法來設定檔案的可見性:

use Illuminate\Support\Facades\Storage;
Storage::put('file.jpg', $contents, 'public');

getVisibilitysetVisibility 方法可以對現存文件的可見性進行查詢和設定:

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

#刪除檔案

##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 的檔案系統提供了一些開箱即用的驅動,但它不僅限於這些,還提供了其他檔案系統的適配器。透過這些適配器,可以在 Lavarel 應用程式中建立自訂驅動器。

為了設定自訂檔案系統,你需要一個 Flysystem 適配器。現在讓我們把社群維護的 Dropbox 適配器加入專案:

composer require spatie/flysystem-dropbox

接下來,你需要建立一個名為 DropboxServiceProvider 的 服務提供者 。在它的boot 方法中,使用Storage facade 的extend 方法自訂驅動程式:

<?php
    namespace App\Providers;
    use Storage;use League\Flysystem\Filesystem;
    use Illuminate\Support\ServiceProvider;
    use Spatie\Dropbox\Client as DropboxClient;
    use Spatie\FlysystemDropbox\DropboxAdapter;
    class DropboxServiceProvider extends ServiceProvider{  
      /**
     * 执行注册后引导驱动.
     *
     * @return void
     */   
   public function boot()   
    {       
      Storage::extend('dropbox', function ($app, $config) {       
           $client = new DropboxClient(             
              $config['authorization_token']       
            );         
      return new Filesystem(new DropboxAdapter($client));    
          });   
       }   
    /**
     * 在容器中注册绑定.
     *
     * @return void
     */   
     public function register() 
        {     
           //   
         }
   }

extend 方法的第一個參數是驅動的名稱,第二個參數是閉包,接受$app$config 變數。這個閉包必須傳回 League\Flysystem\Filesystem 的實例。 $config 變數包含了磁碟在 config/filesystems.php 中的位置。

接下來,在config/app.php 設定檔中註冊服務提供者:

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

當你建立並註冊好服務提供者後,就可以透過在config/filesystems.php 設定檔中新增 dropbox 驅動程式並使用它了。

本篇首刊在 LearnKu.com 網站上。