
ファイルのアップロード機能を作成していて、アップロードする場所にカメラの画像を配置しているのですが、ファイルをアップロードするとカメラ画像の下に画像や動画やpdfが表示されてしまうため、
カメラ画像の上にアップロードファイルを表示したいと考えております。
画像、動画、PDFで分岐するコードを書きたい場合、どのように書けばよいのでしょうか?
<style>
/* 通常時 */
form > div { display: flex; }
.contents-selector-button {
position: relative;
margin: .3em;
}
.contents-selector-button label img {/*カメラ画像に対してのcss*/
width: 200px; height: 100px;
}
.contents-selector-button input { display: none; }
/* 画像、動画、PDF表示時のレイアウト */
.contents-selector-button.contents-on label { visibility: hidden; }
.contents-selector-button.contents-on .viewer {
position: absolute;
top:0; left: 0;
width: 100%; height: 100px;
overflow: hidden;
}
</style>
</head>
<body>
<form method="post">
<div>
<div class="contents-selector-button">
<label>
<div><img src="img/camera.jpg"></div>
<input type="file" accept=".png, .jpg, .jpeg, .pdf, .mp4">
</label>
<input type="hidden">
<button type="button">clear</button>
<div class="viewer"></div>
</div>
</div>
</form>
<script>
(()=>{
const
fileTypes = ['image/jpeg','image/png','video/mp4','application/pdf'],
wrap = document.querySelector('form > div'),
P = e => e.closest('.contents-selector-button'),
V = e => P(e).querySelector('.viewer'),
C = (e, s) => P(e).classList[s]('contents-on');
for(let i = 0; i<3; i++)
wrap.appendChild(wrap.firstElementChild.cloneNode(1));
/* クリアボタン */
wrap.addEventListener('click', (e, t = e.target) => {
if(t.nodeName != 'BUTTON' || t.type != 'button') return;
V(t).innerHTML = '';
C(t, 'remove');
});
/* 画像、動画、PDF登録 */
wrap.addEventListener('change', (e, t = e.target) => {
if(t.nodeName != 'INPUT' || t.type != 'file') return;
if(t.files.length == 0 || !fileTypes.includes(t.files[0].type)) return;
/* ここから分岐させたい */
/* 画像の場合 */
wrap.addEventListener('change', (e, t = e.target) => {
if(t.nodeName != 'INPUT' || t.type != 'file') return;
if(t.files.length == 0 || !fileTypes.includes(t.files[0].type)) return;
const img = document.createElement('img');
img.src = URL.createObjectURL(t.files[0]);
img.style.height = '100px';
V(t).appendChild(img);
C(t, 'add');
});
})();
/* 動画の場合 */
wrap.addEventListener('change', (e, t = e.target) => {
if(t.nodeName != 'INPUT' || t.type != 'file') return;
if(t.files.length == 0 || !fileTypes.includes(t.files[0].type)) return;
const img = document.createElement('video');
video.src = URL.createObjectURL(t.files[0]);
video.style.height = '100px';
V(t).appendChild(video);
C(t, 'add');
});
})();
/* PDFの場合 */
wrap.addEventListener('change', (e, t = e.target) => {
if(t.nodeName != 'INPUT' || t.type != 'file') return;
if(t.files.length == 0 || !fileTypes.includes(t.files[0].type)) return;
const img = document.createElement('pdf');
video.src = URL.createObjectURL(t.files[0]);
video.style.height = '100px';
V(t).appendChild(pdf);
C(t, 'add');
});
})();
</script>
A 回答 (4件)
- 最新から表示
- 回答順に表示
No.4
- 回答日時:
No3です。
>修正いただいたコードに別途コードを追加すべきでしょうか?
>PHP側でチェックをファイルタイプのチェックは行っております。
全体像がよくわかりません。
どこにもそのような説明は無いので・・・
スクリプト側でのチェックは、あくまで簡易的なものと考えてください。
スクリプトでいろいろチェックしても、悪意のあるユーザがくぐり抜けることは可能ですので、サーバ側できちんと再チェックする必要があります。
(同じチェック内容であっても省略はできません)
とは言っても、No3のマークアップ例では、送信できるようにはなっていませんけれど・・
回答ありがとうございます、全体像についての説明が欠けておりました申し訳ありません。
アップロードファイルをbase64データ変換を行いPHPでバイナリーデータを確認しております。ファイル名はセキュリティ上信用できないためバイナリーデータから拡張子を判定して該当しない場合はファイルエラーになるようにしているのでPHP側ではチェックは問題ない気がします。
コードが長いためsample.phpにPHP側でチェックコードを載せさせていただきました。
※該当コード
https://wandbox.org/permlink/7jBbvXUm0QbRlXj5
No.3
- 回答日時:
No2です。
>~~にclass="hideItems"は必要でしょうか?
HTML文法上必要とされるnameやidは省略しない方が良いでしょう。
それ以外に関しては、作成者の好み的なところもあります。
主には、CSSやスクリプトから参照する都合で設定しているものが多いと思います。
(私は、メモ帳に手打ちなので可能なら省略しちゃいますけれど・・)
ご提示の、INPUT要素は常に非表示の要素なので、そのクラスの有無で何が違うのかよくわかりません。(CSSがどうなっているのかも不明ですし・・)
もしも、付与してもしなくても変わりがないのなら不要とも言えますし、それでも好みで設定したからと言って、別に問題は生じないと思います。
なお、No2にも記しましたが、.createObjectURL()で紐づけを行った場合は、revokeObjectURL() で解放してあげる必要があるようです。
とは言え、動画の場合は解放のタイミングがちょっと難しそうですね。
以下は、画像等の読み込み方法を変えてみた例です。ご参考までに。
<参考ページ>
https://developer.mozilla.org/ja/docs/Web/API/Fi …
※ 送信の必要はないようなので、formタグははずしてあります。
(他の不要そうなdivもはずしてありあます)
※ PDFのデフォルト表示がブラウザによって異なるようですが、特に対処はしていません。
<!DOCTYPE HTML>
<html lang="ja">
<head><title>Sample</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
/* 通常時のレイアウト */
#wrapper { display: flex; }
.image-selector-button {
position: relative;
margin: .3em;
}
.image-selector-button label img {
display: block;
width: 200px; height: 100px;
}
.image-selector-button input { display: none; }
/* 画像等表示時のレイアウト */
.image-selector-button.image-on .viewer {
position: absolute;
top:0; left: 0;
width: 100%; height: 100px;
background-color: white;
overflow: hidden;
}
</style>
</head>
<body>
<div id="wrapper">
<div class="image-selector-button">
<label>
<img src="./img/photo00.jpg">
<input type="file" accept=".png, .jpg, .jpeg, .pdf, .mp4">
</label>
<button type="button">clear</button>
<div class="viewer"></div>
</div>
</div>
<script>
(()=>{
const
fileTypes = [
{ type: 'image/png', tag: 'img' }, { type: 'image/jpeg', tag: 'img' },
{ type: 'video/mp4', tag: 'video' }, { type: 'application/pdf', tag: 'iframe' }
],
wrap = document.getElementById('wrapper'),
P = e => e.closest('.image-selector-button'),
V = e => P(e).querySelector('.viewer'),
C = (e, s) => P(e).classList[s]('image-on');
for(let i = 0; i<2; i++)
wrap.appendChild(wrap.firstElementChild.cloneNode(1));
/* クリアボタン */
wrap.addEventListener('click', (e, t = e.target) => {
if(t.nodeName != 'BUTTON' || t.type != 'button') return;
P(t).querySelector('input').value = '';
V(t).innerHTML = '';
C(t, 'remove');
});
/* 画像登録 */
wrap.addEventListener('change', (e, t = e.target) => {
if(t.nodeName != 'INPUT' || t.type != 'file' || t.files.length == 0) return;
const file = t.files[0], f = fileTypes.filter( e => e.type == file.type)[0];
if( !f ) return;
const obj = document.createElement( f.tag );
const rdr = new FileReader();
rdr.onload = e => { obj.src = e.target.result; };
rdr.readAsDataURL(file);
if( f.tag == 'video') obj.controls = true;
obj.style.height = '100px';
V(t).appendChild(obj);
C(t, 'add');
});
})();
</script>
</body>
</html>
Q.HTML文法上必要とされるnameやidは省略しない方が良いでしょう。
ご提示の、INPUT要素は常に非表示の要素なので、そのクラスの有無で何が違うのかよくわかりません。(CSSがどうなっているのかも不明ですし・・)
もしも、付与してもしなくても変わりがないのなら不要とも言えますし、それでも好みで設定したからと言って、別に問題は生じないと思います。
A.アドバイスありがとうございます、慣れてないうちは書くようにしてみます。
どうしてもお聞きしておきたいことがあるのですが、修正いただいたコードに別途コードを追加すべきでしょうか?
こちらの質問をする以前に別の方に、Javascriptでもセキュリティ対策コードを書いた方がよいとアドバイスを頂きました、
修正いただいたコードを参考に考えていきたいのですがウイルス対策が充分なのか心配です。MIME typeで分岐しているため該当しないファイルはキャンセルしているので問題ないと思うのですが…
PHP側でチェックをファイルタイプのチェックは行っております。
※アドバイスを頂いた文
Javascriptでファイルアップロードの際にアップロードされたファイルの拡張子や内容を厳密に検証し、信頼できるファイル形式のみを許可して、実行可能なファイルや危険なファイルを拒否してください。
PHPでアップロードされたファイルの拡張子を正規化し、意図しないファイルタイプのマイムタイプを避けるために、サーバーサイドで適切なファイルタイプのチェックを行ってください。
No.2
- 回答日時:
No1です。
>どうまとめればよいのか自分でも分からないのですが、~~
>につなげるにはどのように書けばよいのでしょうか?
No1の回答は「ちゃんと処理できるスクリプトがあるのなら、そちらを利用すれば良いのでは」ということです。
無理に混在させることを考える必要はありません。
(処理全体が異なるので、そちらの方が難しいです)
お手持ちのものが、ご希望の処理になっているのなら、全部を入れ替えてしまえばよいのではないでしょうか?
(回答のスクリプトは、File APIを良く知らないので、テスト用に簡易的に作成したものですので・・)
ただし、使用するスクリプトに合うように、HTMLの id やクラス名は設定しておく必要があります。
ちなみに、
>f(t.nodeName != 'INPUT' || t.type != 'file') return;
>if(t.files.length == 0 || !fileTypes.includes(t.files[0].type)) return;
では、.png、.jpegのチェックもまとめて記述してありますので、その後に記述しても画像以外は既にはじかれてしまっています。
if(t.nodeName != 'INPUT' || t.type != 'file' || t.files.length == 0) return;
とでもしておいて、その後でMIMEタイプをチェックすれば、分岐は可能になると思います。
アドバイスありがとうございます。回答者さまのコードを参考にコードは考えてみたのですが、changeImg[i].classList.add('hideItems');の部分が引っ掛かります。<input type="file" id="inputFile" class="hideItems" accept=".png, .jpg, .jpeg, .pdf, .mp4">にclass="hideItems"は必要でしょうか?
※最新コード
https://wandbox.org/permlink/JALzQaRCAjmXFa6y
No.1
- 回答日時:
こんにちは
前回回答者です。
https://oshiete.goo.ne.jp/qa/13495417.html
前回のご質問は、表示レイアウトに関するご質問だと認識しているのですが・・・
その際に説明や実物でも伝わらないようでしたので、動作する簡単なスクリプトを付けて回答したただけのものです。
ですので、スクリプトに関しては、もともとお使いのものが機能するのなら、そちらを利用なされば宜しいのではないでしょうか?
前回の説明にも書きましたように、レイアウトの変更は、クラス設定だけで可能な仕組みになっています。
>画像、動画、PDFで分岐するコードを書きたい場合、
>どのように書けばよいのでしょうか?
INPUT要素に入力された、input.file.typeを取得すると、MIMEタイプが返されますので、それで分岐すれば良いでしょう。
例えば、.pngであれば ”image/png” が返されます。(文字列で取得できます)
なお、前回は動作確認のためだけなので省略していますが、.createObjectURL()でオブジェクトURLを作成するとメモリが拘束されるので、revokeObjectURL() で解放してあげる必要があるようですのでご注意ください。
https://note.affi-sapo-sv.com/js-create-revoke-o …
回答ありがとうございます、どうまとめればよいのか自分でも分からないのですが、if(t.nodeName != 'INPUT' || t.type != 'file') return;
if(t.files.length == 0 || !fileTypes.includes(t.files[0].type)) return;
につなげるにはどのように書けばよいのでしょうか?
簡略して書くことに慣れていないためアドバイスを頂きたいです。よろしくお願い致します。
<script>
/* 画像、動画、PDF登録 */
wrap.addEventListener('change', (e, t = e.target) => {
const fileType = fileDate.type;//MIMEタイプで分岐
let newElement;// 新しい要素を取得
if (['image/jpeg', "image/png"].includes(fileType)) {
newElement = document.createElement('img');
} else if (fileType === 'video/mp4') {
newElement = document.createElement('video');
newElement.controls = true;
} else if (fileType === 'application/pdf') {
newElement = document.createElement("iframe");
} else {
return alert("対象外のファイルです");
}
</script>
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- JavaScript clear機能を失わずにファイルアップロード機能を作成したい 3 2023/06/10 16:12
- HTML・CSS CSSが効かずどのように指定すれば良いか分からないのでアドバイスお願い致します 2 2023/06/07 12:25
- JavaScript ①入力フォーム→②確認表示画面→③送信完了画面のコードを書いているのです、 入力フォームから受け取っ 2 2022/05/10 16:45
- JavaScript 入力フォームの javascript で メールアドレスの正規チェックをを行い、ボタンをクリックして 2 2022/04/27 16:06
- HTML・CSS ボタンをクリックした時に、入力フォームのすぐ下部に、「入力欄が空白です」というテキストメッセージが表 1 2022/04/27 16:25
- JavaScript プログラムがうまく動きませんレビューお願いします 1 2022/07/10 05:08
- JavaScript コードレビューをお願いします。 1 2022/07/16 05:38
- JavaScript jqueryを使ったスムーススクロールのコードを書いたのですが、HTMLコード内にある、a butt 2 2022/04/14 10:59
- JavaScript 画像の表示位置 3 2022/12/23 08:25
- PHP PHP MySql 画像を取得 1 2022/06/04 14:05
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
javascript ランダム表示
-
animateを使用したマウスオーバ...
-
ホームページ作成で画像スクロ...
-
jQueryでセレクタに複数のIDを...
-
jqueryを使用した画像スクロー...
-
時間差で画像を動作させたいjav...
-
これぞ、JavaScriptの究極の参...
-
Javascript(jQuery)のスライド...
-
cookie.jsを使ってクッキーを利...
-
lightboxのような効果
-
jqueryでHTMLを変える
-
JavaScriptが、Firefoxで動かな...
-
透過pngで作った画像がIE6で表...
-
ツリー型の目次作成
-
HTMLへ要素の挿入について
-
IMGタグごとにCSSを設定する方法
-
IE6でmax-width:100px; max-hei...
-
RSSフィードを取得して【NEW】...
-
jquery:animate中にイベントを付与
-
プルダウンメニューがうまくい...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
jQueryで同じクラス名のものを...
-
デフォルト非表示にしたい。【t...
-
スクリプト
-
jQueryで4枚の画像がフェードア...
-
交互に入れ替わる画像を複数配置
-
クリッカブルマップをロールオ...
-
bxsliderで最初に縦に複数表示...
-
複数bxsliderをタブで切り替え...
-
JavaScriptでの画像切り替えを...
-
「画像クリックで音声再生」を ...
-
画像切り替え
-
ボタンを押すたびに交互に切り...
-
jQuery 親要素の大きさに合わせ...
-
画像のフェードインについて・...
-
ボタンを画像に変更したい
-
画像のフェードイン・フェード...
-
アップロードファイルの種類に...
-
クリックでクリッカブルマップ...
-
Jquery cheeckbox(複数)とsli...
-
画像の切り替えについて
おすすめ情報