Cách backup dữ liệu lên Google Drive
Xin chào các bạn, mình đã quay trở lại rồi đây. Hôm nay sẽ không phải là một bài chia sẻ về bể cá thông minh mà sẽ là một bài viết liên quan đến dữ liệu. Các bạn nếu quan tâm đến series bể cá thông minh của mình thì có thể theo dõi tại đây. Mình sẽ viết bài cuối của series này nhanh thôi. Show Xin hỏi các bạn trong một trang web thì thứ gì quan trọng nhất? Chắc chắn 96.69% các bạn trả lời là dữ liệu phải không. Đúng vậy dữ liệu rất là quan trọng. Mình lập ra trang web là để thu thập và lưu dữ liệu mà Để thực hiện việc này chúng ta cần phải chuẩn bị 2 thứ:
Và chương trình sẽ phải thực hiện theo 2 bước:
Nội dung cần chuẩn bịĐể tạo file backup cơ sở dữ liệu ta có một lệnh rất đơn giản dùng mysqldump như sau: mysqldump database_name --password=your_pass --user=user_name --single-transaction | gzip >file_path_to_write_to.sql.gzVà lệnh để khôi phục lại cơ sở dữ liệu đã backup là: gunzip < file_path_to_write_to.sql.gz | mysql --user=user_name --password=your_pass database_nameBật Google Drive APIMuốn sử dụng được API Drive thì ta cần phải bật nó lên. Các bước thực hiện như sau:
Các bạn ấn nút Continue để tạo một project. Nếu bạn đã có project rồi thì chọn project đó rồi ấn Continue. Chờ một chút nó sẽ hiện ra trang như sau.
Tiếp theo chọn tab OAuth consent screen và điền các thông tin cần thiết vào đây. Chỉ cần chọn email và điền Product name shown to users là được. Sau đó ấn Save để lưu lại. Chuyển sang tab Credentials ấn nút Create credentials. Nó sẽ sổ ra một danh sách chọn. Chọn OAuth client ID. Tiếp đến chọn Other và nhập tên OAuth client cần tạo. Rồi ấn Create. Màn hình sẽ hiện client ID và client secret. Ấn OK để tắt nó đi.
Đổi tên file json đó thành drive-secret.json cho dễ nhớ. Rồi chép file đó vào thư mục /storage/drive của project. Cài đặt thư viện cần thiếtĐể có thể thao tác với Google Api dễ dàng. Ta cài thư viện google/apiclient vào project laravel. Lập trìnhVới mục tiêu đề ra là tạo file database backup sau đó upload lên google driver chúng ta sẽ cần phải tạo 2 command:
Như vậy mục tiêu đã rõ ràng, công việc đã minh bạch cùng code thôi. Tạo command export database fileTạo command bằng lệnh artisan: php artisan make:command ExportDatabaseThêm config path lưu file export ra ở file config/filesystems.php: 'path' => [ 'backup_database' => 'backup/database', ],Nhập tên command: protected $signature = 'db:export';Ta sẽ sử dụng Process của Symfony để gọi shell command tạo file export database. Nói qua về Process một chút. Process là một thư viện hỗ trợ việc thao tác với shell command. Nó sẽ giống với hàm exec, passthru, shell_exec, system trong PHP vậy. Khi sử dụng Process thì ta sẽ dễ dàng viết test cho command của bạn. Và chính Laravel cũng đang sử dụng Process nên ta hoàn toàn tin tưởng và tất nhiên sẽ không phải cài thêm thư viện rồi vì nó đã có sẵn trong project laravel. Bây giờ ta use thư viện và triển thôi use Symfony\Component\Process\Process; use Symfony\Component\Process\Exception\ProcessFailedException;Hàm handle: public function handle() { $dateTime = Carbon::now(); $dateTimeString = $dateTime->format('Y_m_d_H_i_s'); $fileName = 'database_' . $dateTimeString . '.sql.gz'; $filePath = storage_path(config('filesystems.path.backup_database')); $database = env('DB_DATABASE'); $userName = env('DB_USERNAME'); $password = env('DB_PASSWORD'); $shellCommand = 'mysqldump ' . $database . ' --password=' . $password . ' --user=' . $userName . ' --single-transaction | gzip' . ' >' . $filePath . '/' . $fileName; $process = new Process($shellCommand); $process->run(); $this->info('Export database ' . $database . ' to file ' . $fileName . ' success!'); }Mình đã chú thích các đoạn code rồi nên sẽ không giải thích gì thêm nữa nhé. Bạn đừng quên đăng kí command class vào file app/Console/Kernel.php nhé. Chú ý: Đối với phiên bản laravel 5.5 trở lên thì trong hàm commands() của file app/Console/Kernel.php đã được tự động load các class trong thư mục Commands rồi nên các bạn không cần thực hiện đăng kí command bằng tay nữa. Chạy thử lệnh: php artisan db:exportKết quả tạo được file database trong thư mục storage Tạo chức năng upload lên driveConfigThêm các biến config tại file config/services.php 'google_drive' => [ 'secret' => storage_path('drive/drive-secret.json'), 'access_token' => storage_path('drive/access-token.json'), ],Thêm một disk database vào mảng disks trong file config/filesystems.php để có thể truy cập được thư mục 'backup-database'dễ dàng hơn. 'disks' => [ 'database' => [ 'driver' => 'local', 'root' => storage_path('backup/database'), ], ],Tạo Google Drive serviceLuồng hoạt động của google driver service như sau:
Bây giờ chúng ta sẽ tạo file app/Services/GoogleDriveService.php thực hiện các công việc trên: namespace App\Services; use Google_Service_Drive; use Google_Service_Drive_DriveFile; use Google_Client; use Storage; use Exception; class GoogleDriveService { protected $driveService; protected $scopes = [ Google_Service_Drive::DRIVE_FILE, ]; protected $accessType = 'offline'; public function __construct() { $client = $this->getClient(); $this->driveService = new Google_Service_Drive($client); } public function listFiles() { $optParams = [ 'pageSize' => 10, 'fields' => 'nextPageToken, files(id, name)' ]; $results = $this->driveService->files->listFiles($optParams); if (count($results->getFiles()) == 0) { print "No files found.\n"; } else { print "Files:\n"; foreach ($results->getFiles() as $file) { printf("%s (%s)\n", $file->getName(), $file->getId()); } } } protected function getClient() { $client = new Google_Client(); $client->setApplicationName(config('app.name')); $client->setScopes(implode(' ', $this->scopes)); $client->setAuthConfig(config('services.google_drive.secret')); $client->setAccessType($this->accessType); $client->setAccessToken($this->getAccessToken($client)); if ($client->isAccessTokenExpired()) { $this->refreshToken($client); } return $client; } protected function getAccessToken($client) { $credentialsPath = config('services.google_drive.access_token'); if (file_exists($credentialsPath)) { $accessToken = json_decode(file_get_contents($credentialsPath), true); } else { $accessToken = $this->requestAccessToken($client, $credentialsPath); } return $accessToken; } protected function refreshToken($client) { $credentialsPath = config('services.google_drive.access_token'); $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken()); file_put_contents($credentialsPath, json_encode($client->getAccessToken())); } protected function requestAccessToken($client, $credentialsPath) { if (php_sapi_name() != 'cli') { throw new Exception('Please run this application on the command line.'); } $authUrl = $client->createAuthUrl(); printf("Open the following link in your browser:\n%s\n", $authUrl); print 'Enter verification code: '; $authCode = trim(fgets(STDIN)); $accessToken = $client->fetchAccessTokenWithAuthCode($authCode); if(!file_exists(dirname($credentialsPath))) { mkdir(dirname($credentialsPath), 0700, true); } file_put_contents($credentialsPath, json_encode($accessToken)); printf("Credentials saved to %s\n", $credentialsPath); return $accessToken; } public function uploadLatest() { $files = Storage::disk('database')->files(); $file = array_pop($files); if ($file == '.gitignore') { throw new Exception('Database file not exist', 1); } $fileMetadata = new Google_Service_Drive_DriveFile([ 'name' => $file, ]); $content = Storage::disk('database')->get($file); $this->driveService->files->create($fileMetadata, [ 'data' => $content, 'mimeType' => 'application/gzip', 'uploadType' => 'multipart', 'fields' => 'id', ]); return $file; } }Tạo commandTạo command bằng lệnh artisan: php artisan make:command BackupDatabaseHàm handle tạo backup và upload lên Drive public function handle() { $this->call('db:export'); $this->driveService = new GoogleDriveService; $file = $this->driveService->uploadLatest(); if ($file) { $this->info('Upload file ' . $file . ' successful!'); } }Kết luậnNhư vậy mình đã giới thiệu xong cách backup dữ liệu lên Drive rồi. Bây giờ chúng ta có thể yên tâm là dữ liệu của mình sẽ không bao giờ bị mất một cách oan ức nữa. Tài liệu tham khảo: |