Storageを使って画像アップロード、表示、削除をしてみました。また、Storageに保存したファイルを直接外部から参照できるのか検証しました。
下が完成品ですが、記事内で紹介してるコード以外に追加して投稿時以外も画像が表示するようにしています。
完成品 Firestore+Vuetifyで作った掲示板(認証機能+画像投稿付き)
前回まで作ったものに追加していきます。以下の続きです。
Template追加部分
ファイルの選択機能はVuetifyのv-file-inputだけで完成します。実際の操作は📎(クリップマーク)をクリックするとエクスプローラーが立ち上がりパソコンにあるファイルを選択して「開く」をクリックするとupload関数が起動されるので、そのイベントオブジェクトからfileを取り出しStorageに書き込みます。v-model=”image”のimageにもファイルの本体が入っているのですが取り出し方がわからなかったのでイベントオブジェクトを使いました。なのでimageは、ファイル名の表示/非表示の変数としか使っていません。
表示ボタンをクリックすると
v-imgで変数imageSrcに入っているurlの画像を表示させます。
削除ボタンで今、表示したファイルをStorageから削除します。
<template>に追加したのは以下
<v-sheet height="150" color="orange lighten-2" class="mt-2 mx-auto" max-width="400">
<v-file-input v-model="image" @change="upload" label="← クリックしてファイルを選択" ></v-file-input>
<v-btn color="success" dark v-on:click="downLoad" class="ma-5">表示</v-btn>
<v-btn color="success" dark v-on:click="deleteImg" class="ma-5">削除</v-btn>
</v-sheet>
<v-img v-if="imageSrc" v-bind:src="imageSrc" max-height="200" class="mt-4"></v-img>
Storageにアップロード、表示、削除
初期設定
Firebaseのコンソールで左のStorageをクリック→始める→テストモード→完了でStorageが使えるようになります。
ウェブで Cloud Storage を使ってみるの「バケット URL をアプリに追加する」がStorageを使うための初期設定です。
前回までCloud Firestore(データベース)Hosting(アプリ公開)Authentication(認証)を使用するのにfirebaseConfigに何を追加すればいいか実験してきました。その結果apiKey:projectId:authDomain:があれば動きました。今回Cloud Storageを使うにはstorageBucket:が必要なので追加しました。値は、プロジェクトの概要→プロジェクトの設定で下のほうにあります。
const firebaseConfig = {
apiKey: "***",
projectId: "***",
authDomain: "***",
storageBucket: "***",
};
あとは以下2行の追加でStorageが使えるようになります。
import { getStorage } from "firebase/storage";
const storage = getStorage(app);
今回使用するStorageの関数もimportします。
import { ref ,uploadBytes, getDownloadURL , deleteObject } from "firebase/storage";
データに以下追加
data() {
return{
imageSrc:null,
now_image:null,
image:null,
upload関数(アップロード)
ウェブで Cloud Storage を使用してファイルをアップロードするを参考にやっていきます。
使用するfirebaseの関数をimport
import { getStorage , ref ,uploadBytes} from "firebase/storage";
Blob または File からアップロードするの以下の2つだけでアップロードできます。
// Create a root reference
const storage = getStorage();
// Create a reference to 'mountains.jpg'
const mountainsRef = ref(storage, 'mountains.jpg');
具体的な処理は
async upload(e) {
console.log('eは',e);
console.log('e.target.files[0].nameは',e.target.files[0].name);
const file=e.target.files[0];
this.now_image=file.name;
// Create a reference to 'mountains.jpg'
const storageRef = ref(storage, 'images/'+file.name);
// 'file' comes from the Blob or File API
await uploadBytes(storageRef, file).then((snapshot) => {
console.log('Uploaded a blob or file!');
});
},
解説:ファイルを開くをクリックしたら発生するイベントオブジェクトeを受け取り、そこからファイル本体を取得して変数fileへ。コンソールでe(event)を表示しているので、targetの下のfiles(配列)の0番目にファイルがあるのが確認できます。
ファイル名(file.name)を抽出してthis.now_imageに代入。storageRefには保存先のパスが作られます。uploadBytes(storageRef, file)でstorageRefへファイルの実体をアップロードします。
目次へ
ダウンロード
ウェブで Cloud Storage を使用してファイルをダウンロードするの「URL 経由でデータをダウンロードする」を使います。サンプルに2つの方法が解説されています。2つ目の方法をVuetifyように改造します。以下サンプルをコメントアウトして解説を加えました。
async downLoad(){
console.log('ダウンロードimageは',this.now_image)
await getDownloadURL(ref(storage, 'images/'+this.now_image))
.then((url) => {
// `url` is the download URL for 'images/stars.jpg'
//①httpリクエストをurlに対して投げレスポンスをBlobに入れてるが、cordsの対策しないとエラーになる。
// This can be downloaded directly:
// const xhr = new XMLHttpRequest();
// xhr.responseType = 'blob';
// xhr.onload = (event) => {
// const blob = xhr.response;
// };
// xhr.open('GET', url);
// xhr.send();
//②imgタグのsrc属性にurlを代入している。今回、こちらをimgタグではなくVuetifyのv-imgタグで実装した。
// Or inserted into an <img> element
// const img = document.getElementById('myimg');
// img.setAttribute('src', url);
this.imageSrc=url;
})
.catch((error) => {
// Handle any errors
});
},
解説:getDownloadURL(ref(storage, ‘images/’+this.now_image))によりストレージに保存されている対応するファイ名のurlが取得できます。v-imgタグでv-bind:src=”imageSrc”としているのでimageSrcにurlを代入すれば、そのurlの画像が表示されます。
目次へ
削除
ウェブで Cloud Storage を使用してファイルを削除するに使い方が載っています。
async deleteImg(){
// Create a reference to the file to deleteref
const desertRef = ref(storage, 'images/'+this.now_image);
// Delete the file
await deleteObject(desertRef).then(() => {
// console.log('削除しました。',this.now_image);
// File deleted successfully
}).catch((error) => {
// Uh-oh, an error occurred!
});
this.now_image='';
this.imageSrc=null;
this.image=null;
}
解説:ref(storage, ‘images/’+this.now_image)によりストレージに保存されている対応するファイ名のurlが取得できます。それをdeleteObjectに渡すことで削除できます。
目次へ
Storageのリンクを直接使ってはいけないのか
urlの違い
プログラムで読み出して作った画像ファイルのリンクとStorageにある画像ファイルのリンクで違いがあるか確認してみました。
プログラムで読み出して作った画像ファイルのリンク
https://firebasestorage.googleapis.com/v0/b/vue-auth-40465.appspot.com/o/images%2Fkomakusa.jpg?alt=media&token=37d5ad69-de82-41ff-af35-c4dc4eee86dd
Storageにある画像ファイルのリンク
https://firebasestorage.googleapis.com/v0/b/vue-auth-40465.appspot.com/o/images%2Fkomakusa.jpg?alt=media&token=37d5ad69-de82-41ff-af35-c4dc4eee86dd&_gl=1*1q5g777*_ga*MTk5NDUzMDc2Ny4AbcDGNzc0*_ga_CW55HF8NVT*MTY4NjY0NTA1NC43Ny4xLjE689Y2NDU51DYuMC4wLjA.
Storageにあるファイルのリンクは赤色のurlパラメータが余分についていてます。なので直接このurlを使う場合、最後のurlパラメータ(&以降は削除したほうがいいかも)
プロジェクトにAuthenticationをいれないでStorageだけ入れてStorageにある画像ファイルのリンクを確認すると、&_gl=はない。なので&_gl=の部分はAuthenticationで使われるパラメータみたいです。
目次へ
ルールで何を制限しているのか
Storageに対する読み書きの許可をテストモードのデフォルトからreadのみ不可にしました。
参照Firebase Cloud Storage セキュリティ ルールで条件を使用する(Firestoreの説明のほうがわかりやすい。→データをセキュリティで保護する)
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
//allow read, write: if request.time < timestamp.date(2023, 7, 11);
allow write: if request.time < timestamp.date(2023, 7, 11);
allow read: if false;
}
}
}
今回、作ったプログラムで確認するとアップロード(write)はできます。しかし表示を押しても画像は表示されません。開発者ツールのネットワークタブでみると
以下へアクセスしています。
https://firebasestorage.googleapis.com/v0/b/vue-auth-40465.appspot.com/o/images%2Fusuyuki.jpg
これのレスポンスは
"error": {
"code": 403,
"message": "Permission denied."
}
}
getDownloadURL(ref(storage, 'images/'+this.now_image))が返すurlが上のurlでStorageにアクセスできないエラーを返すurlになっています。
しかしコンソール→Storage→該当ファイルをクリックして名前のリンクをクリックすると画像が見れます。
つまり、このルールはプログラムで動かすときだけ上記のようなエラーが発生するurlに誘導するだけでStorageの読み出しを制御しているわけではないということです。
FirebaseのStorageだけを使おうと思ったので、こういうことを調べました。分かったことは。ルールでは読み書き制限できない。後ろのurlパラメータ(Storageだけならつかない。)は消したほうがいいかもということです。
あとがき
プログラムからStorageを操作するのは簡単にできることがわかりました。
イチゲをOFUSEで応援する(御質問でもOKです)Vプリカでのお支払いがおすすめです。
MENTAやってます(ichige)
目次へ
コメント