🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
phpMyAdmin

phpMyAdminはオープンソースで、PHPで書かれたウェブベースのMySQL管理ツールのことです。

WordPress

WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

Q&A

解決済

8回答

1813閲覧

Q&A掲示板のテーブルは質問と回答で分けるべきでしょうか?

homepage-site

総合スコア49

phpMyAdmin

phpMyAdminはオープンソースで、PHPで書かれたウェブベースのMySQL管理ツールのことです。

WordPress

WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

0グッド

2クリップ

投稿2024/08/26 10:29

編集2024/08/26 14:33

実現したいこと

ファイルアップロード(画像、動画、PDF)が可能なログイン無しのQ&A掲示板を作成したいです。

発生している問題・分からないこと

現在質問画面と質問一覧表示画面を作り終えて回答画面を作成中です。
質問画面と質問一覧表示画面のテーブル構造は下記になります。

回答画面には追加でカラムに質問と回答を紐付けするための回答IDとその回答に対する返信のIDの2つを追加する予定なのですが、質問&回答の両用テーブルで使用するか回答専用テーブルを用意するどちらのほうが良いと思われますでしょうか?

両用にする場合はQ&A掲示板に投稿されたものが質問か回答かを識別するカラムを追加して、質問を「1」、回答を「2」のように意味付けて識別する形で考えております。

どちらもメリット、デメリットがあると思うのでそちらについてもお聞きしたいです。

※質問画面と質問一覧表示画面のテーブル構造
ID (質問番号)・・・・無限スクロールで表示しているため
TS (投稿日時)・・・・公開期間終了後に質問を cron で削除するため
question (質問内容)・・・・質問投稿文
title (質問タイトル)・・・・質問タイトル
namae (質問者名)・・・・任意なのでない場合は匿名で表示
stamp (リアクションスタンプ)・・・・用意された画像で気持ちを伝える
unique_id (質問UUID)・・・・アップロードされたファイル名の改名に使用
ip (IPアドレス)・・・・セキュリティ保護のために保存
attach1 (アップロードされたファイル)・・・・1、2、3で分けているのは1つ目の画像を一覧表示&1つ目の動画を横スクロールで表示するため
attach2 (IPアドレス)・・・・略
attach3 (IPアドレス)・・・・略
usericon (アイコン画像)・・・・アップロードされた画像を表示、アップロードがない場合は代替え画像を表示する

該当のソースコード

PHP

1<?php 2/* 3Template Name: input 4固定ページ: 入力画面 5*/ 6get_header(); 7?> 8<?php 9if (!$noindexaccess) { 10exit('不正アクセス'); 11} 12if (empty($_SESSION['token'])) {// 悪意のある攻撃者があらかじめ作成したコードが実行されてしまうのを防ぐ 13$_SESSION['token'] = bin2hex(random_bytes(16)); 14} 15$attach = []; 16if (!empty($_SESSION['attach'])) { 17foreach ($_SESSION['attach']['data'] as $i => $data) { 18if (!empty($data)) { 19$base64 = base64_encode($data); 20} 21$type = $_SESSION['attach']['type'][$i]; 22switch ($type) { 23case 'image/jpeg': 24case 'image/png': 25$attach[] = '<img style="height: 100px;" src="data:'.$type.';base64,'.$base64.'">'; 26break; 27case 'video/mp4': 28$attach[] = '<video style="height: 100px;" controls src="data:'.$type.';base64,'.$base64.'">'; 29break; 30case 'application/pdf': 31$attach[] = '<iframe style="height: 100px;" src="data:'.$type.';base64,'.$base64.'"></iframe>'; 32break; 33default: 34$attach[] = ''; 35break; 36} 37} 38} 39$stamp_checked = []; 40$stamp_checked[$stamp] = 'checked'; 41$upload_dir = wp_upload_dir(); 42$camera_url = $upload_dir['baseurl'].'/camera.png'; 43?> 44<h2>入力画面</h2> 45<?php 46foreach ($errors as $error) { 47echo "<p>{$error}</p>"; 48} 49?> 50<div class="board_form_partial" id="js_board_form_partial"> 51<form method="post" enctype="multipart/form-data"> 52<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>"> 53<div class="image-partial"> 54<h2>動画・画像をアップロード(Upload video・image)<span class="required">※ファイルサイズ15MB以内、JPG/GIF/PNG/MP4</span></h2> 55<div class="image-selector-button"> 56<label> 57<div class="image-camera-icon"> 58<img src="<?php echo $camera_url; ?>" class="changeImg" style="height: 100px;"> 59</div> 60<input type="file" class="attach" name="attach[]" accept=".png, .jpg, .jpeg, .pdf, .mp4" style="display: none;"> 61</label> 62<input type="hidden" class="attachdel" name="attachdel[]"> 63<div class="viewer"><?php echo $attach[0]; ?></div> 64<button type="button" class="attachclear">clear</button> 65</div> 66<div class="image-selector-button"> 67<label> 68<div class="image-camera-icon"> 69<img src="<?php echo $camera_url; ?>" class="changeImg" style="height: 100px;"> 70</div> 71<input type="file" class="attach" name="attach[]" accept=".png, .jpg, .jpeg, .pdf, .mp4" style="display: none;"> 72</label> 73<input type="hidden" class="attachdel" name="attachdel[]"> 74<div class="viewer"><?php echo $attach[1]; ?></div> 75<button type="button" class="attachclear">clear</button> 76</div> 77 78<div class="image-selector-button"> 79<label> 80<div class="image-camera-icon"> 81<img src="<?php echo $camera_url; ?>" class="changeImg" style="height: 100px;"> 82</div> 83<input type="file" class="attach" name="attach[]" accept=".png, .jpg, .jpeg, .pdf, .mp4" style="display: none;"> 84</label> 85<input type="hidden" class="attachdel" name="attachdel[]"> 86<div class="viewer"><?php echo $attach[2]; ?></div> 87<button type="button" class="attachclear">clear</button> 88</div> 89</div> 90<style> 91.hideItems { 92display: none; 93} 94</style> 95<div class="title-partial parts"> <!-- title-partial + parts --> 96<h2>名前(name)<span class="required">※必須</span></h2> 97<div class=parts> 98<input class=input type="text" name="namae" id="name" data-length="32" placeholder="未入力の場合は、匿名で表示されます" value="<?php echo $namae; ?>"> 99<div></div> 100</div> 101</div> 102 103<div class="body-partial parts"><!-- body-partial + parts --> 104<h2>コメント(comment)<span class="required">※必須</span></h2> 105<div class=parts> 106<textarea class=input name="message" id="message" data-length="40" placeholder="荒らし行為や誹謗中傷や著作権の侵害はご遠慮ください"><?php echo $message; ?></textarea> 107<div></div> 108</div> 109</div> 110 111<div class="stamp-partial"> 112<h2>スタンプを選ぶ(必須)</h2> 113<input type="radio" name="stamp" value="1" id="stamp_1" <?php echo $stamp_checked['1']; ?>><label for="stamp_1"></label> 114<input type="radio" name="stamp" value="2" id="stamp_2" <?php echo $stamp_checked['2']; ?>><label for="stamp_2"></label> 115<input type="radio" name="stamp" value="3" id="stamp_3" <?php echo $stamp_checked['3']; ?>><label for="stamp_3"></label> 116<input type="radio" name="stamp" value="4" id="stamp_4" <?php echo $stamp_checked['4']; ?>><label for="stamp_4"></label> 117<input type="radio" name="stamp" value="5" id="stamp_5" <?php echo $stamp_checked['5']; ?>><label for="stamp_5"></label> 118<input type="radio" name="stamp" value="6" id="stamp_6" <?php echo $stamp_checked['6']; ?>><label for="stamp_6"></label> 119<input type="radio" name="stamp" value="7" id="stamp_7" <?php echo $stamp_checked['7']; ?>><label for="stamp_7"></label> 120<input type="radio" name="stamp" value="8" id="stamp_8" <?php echo $stamp_checked['8']; ?>><label for="stamp_8"></label> 121</div> 122<div class="post-button"><!-- ボタンを押せなくする --> 123<button type="submit" id="submit_button" name="mode" value="confirm">表示画面へ進む</button> 124</div> 125<!-- type、name、id、valueの順番 --> 126</form> 127 128<script> 129function validation_submit(f) { 130const submit = document.getElementById("submit_button"); 131/* 判定は逆なので、逆に渡す */ 132submit.disabled = f ? false : true; 133}; 134function validation_text(parts) { 135/* このpartsグループの、inputを抽出 */ 136let text = parts.getElementsByClassName('input')[0]; 137/* 最小チェック */ 138if (text.value.length == 0) { 139return false; 140} 141/* 最大チェック */ 142if (text.value.length >= text.dataset.length) { 143return false; 144} 145return true; 146}; 147/* バリデーション条件判断部分 */ 148function validation() { 149let parts = document.getElementsByClassName('parts'); 150let submit = true; 151for (let i = 0; i < parts.length; i++) { 152if (validation_text(parts[i]) != true) { 153submit = false; 154} 155} 156validation_submit(submit); 157}; 158/* 例えばのチェック */ 159function init() { 160/* カメラ画像をファイルアップロード時に非表示にする */ 161/* 省略 */ 162/* カメラ画像をファイルアップロード時に非表示にする */ 163const attach = document.querySelectorAll('.attach'); 164const del = document.querySelectorAll('.attachdel'); 165const clear = document.querySelectorAll('.attachclear'); 166const viewer = document.querySelectorAll('.viewer'); 167const changeImg = document.querySelectorAll('.changeImg'); // 入力されたら消す画像 168for (let i = 0; i < attach.length; i++) { 169attach[i].addEventListener('change', () => { 170if (attach[i].files[0].size > 15 * 1024 * 1024) { 171alert('ファイルサイズが 15MBバイトを超えています'); 172return; 173} 174del[i].value = ""; 175viewer[i].innerHTML = ""; 176if (attach[i].files.length !== 0) { 177const reader = new FileReader(); 178reader.onload = () => { 179var child = null; 180if (reader.result.indexOf("data:image/jpeg;base64,") === 0 || 181reader.result.indexOf("data:image/png;base64,") === 0) { 182child = document.createElement("img"); 183} else if (reader.result.indexOf("data:video/mp4;base64,") === 0) { 184child = document.createElement("video"); 185child.setAttribute("controls", null); 186} else if (reader.result.indexOf("data:application/pdf;base64,") === 0) { 187child = document.createElement("iframe"); 188} else { 189alert("対象外のファイルです"); 190alert(reader.result); 191attach[i].value = ""; 192} 193if (child !== null) { 194child.style.height = "350px"; 195child.style.width = "528px"; 196child.src = reader.result; 197viewer[i].appendChild(child); 198changeImg[i].classList.add('hideItems'); // もともとの画像を消す 199} 200}; 201reader.readAsDataURL(attach[i].files[0]); 202} 203}); 204clear[i].addEventListener('click', () => { 205attach[i].value = ""; 206del[i].value = "1"; 207viewer[i].innerHTML = ""; 208changeImg[i].classList.remove('hideItems'); 209}); 210} 211/* 文字数表示 */ 212document.addEventListener('input', e => { 213if (!['name', 'message'].includes(e.target.id)) return; 214const 215t = e.target, 216m = t.nextElementSibling, 217n = t.value.length - (t.dataset.length | 0), 218c = document.createElement('span'); 219c.append(Math.abs(n)); 220m.style.color = n > 0 ? 'red' : 'black'; 221m.replaceChildren(n > 0 ? '' : '残り', c, 222`文字${n > 0 ? '超過してい' : '入力でき'}ます。`); 223/* 毎回判定によるボタン制御 */ 224validation(); 225}); 226/* 初回判定のボタン制御 */ 227validation(); 228}; 229document.addEventListener("DOMContentLoaded", init); 230</script>

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

検索してみたのですが Q&A掲示板についての記事がなく掲示板のコメント返信機能に必要な部分のみ参考にしております。

追記

データ通信量によるかと思いますが回答専用テーブルを用意して質問専用テーブルと分けたほうが良いのではないかと考えております。
7~10日で質問を cron で削除する前提であるものの同時刻に複数の掲示板が動作した場合負荷がかかり遅延に繋がるのではないかと思います。

質問&回答の両用テーブルの場合共通のコードなどはまとめることが可能だと思うのですがそれ以外のメリットがあまり無さそうです。

補足

※参考サイト
https://qiita.com/ryouya3948/items/6928c89607cf4eaa72a0

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TakaiY

2024/08/26 11:14

> どちらもメリット、デメリットがあると思う 質問者さんはどのように考えているのでしょうか。
homepage-site

2024/08/26 11:26

TakaiYさん回答ありがとうございます。 データ通信量によるかと思いますが回答専用テーブルを用意して質問専用テーブルと分けたほうが良いのではないかと考えております。 7~10日で質問を cron で削除する前提であるものの同時刻に複数の掲示板が動作した場合負荷がかかり遅延に繋がるのではないかと思います。 質問&回答の両用テーブルの場合共通のコードなどはまとめることが可能だと思うのですがそれ以外のメリットがあまり無さそうです。
TakaiY

2024/08/26 11:39

なるほど。 まず、ここは質問にたいするコメントを書くところですので上記の内容は質問を編集して追記しておいたほうがいいでしょう。 まとめたときと、別にしたときのテーブルの構造がどのようになるか検討してみたりしていますか?
tezcello

2024/08/26 12:05

もの凄く大雑把に言えば、「考え方次第なのでどの様に作っても良い(ただし、キチンと機能しなければ意味は無い)」です。 > どちらもメリット、デメリットがあると思う (やりたい事が全て出来る前提の上で)作成者 / 運用者 がデメリットと思わなければデメリットでは無い訳だし... > 質問か回答かを識別するカラムを追加して、質問を「1」、回答を「2」のように意味付けて識別 どの質問への回答かは頓着しないのですね。 > ID (質問番号)・・・・無限スクロールで表示しているため IDと無限スクロールとは直接関係は無いと思います。 > TS (投稿日時)・・・・7~10日で質問を cron で削除するため cronで削除するのにそんな幅のあるとやり難いと思うけど? __未定であるなら、公開期間終了後と書くと伝わり易いと思う 一般的にデータベースのデータを物理削除するのは悪手では? 利用者からすれば、表示されないデータは削除されたのと同じでしょう。 微妙にタイミングがずれるcronに依存するよりは、有効期間内であるかの判定をして表示・非表示するのを僕なら選びます。 __本当に削除が必要なら、別途管理者が管理メニュから実行する > namae (質問者名) 殆どのカラム名が英単語なのに、ローマ字表記をぶっこむと勘違いの元にしかならないと思います。 > question (質問内容)・・・・質問投稿文 「両用」にするなら、カラム名は変更した方が良いでしょうね。 > title (質問タイトル)・・・・質問タイトル 「回答」にタイトルが必要なのかなぁと思いました。 > attach1 (アップロードされたファイル) > attach2 (IPアドレス)・・・・略 > attach3 (IPアドレス)・・・・略 ホントにファイルを入れる気かは別にして、「IPアドレス」は単なるミスだよね? どうせ後で仕様が変わるのはほぼ間違いないから、3つ分のファイル関連カラムを用意するってのは避けると楽だと思います。 __個人的感覚なので、「その時はその時」と考えるなら無問題 今時のデータベースはリレーションが出来て当たり前なので、1行の中に全部を持っていなければいけない理由は無いと思います。 UUID-1、UUID-2、UUID-3なんてファイル名じゃなく、ファイル名をそれぞれ別のUUIDにした方が、「○○を推測される恐れ」は回避できます。 __投稿IDだけ推測されない様にするってのは、不統一感が... どの投稿とファイルが関連付いているかなんて、管理用のページでやれば良いだけなので、目視でのチェックを前提にするのは普通は無いでしょう。 > ログイン無しのQ&A掲示板 他の質問でも書いた通り、「ログイン必要」にするだけで(スパム的な)迷惑な書き込みや危険なリンク先や不適切な画像の貼り込みを「かなり」避けられます。 誰でも何回でも投稿できる仕組みは危険が一杯です。
homepage-site

2024/08/26 14:01

TakaiYさん回答ありがとうございます、追記いたしました。 別にしたときのテーブル構造は下記のように考えております。 ID (質問番号)・・・・無限スクロールで表示しているため TS (投稿日時)・・・・7~10日で質問を cron で削除するため question (質問内容)・・・・質問投稿文 namae (質問者名)・・・・任意なのでない場合は匿名で表示 unique_id (質問UUID)・・・・アップロードされたファイル名の改名に使用 ip (IPアドレス)・・・・セキュリティ保護のために保存 attach1 (アップロードされたファイル)・・・・1、2、3で分けているのは1つ目の画像を一覧表示&1つ目の動画を横スクロールで表示するため attach2 (アップロードされたファイル)・・・・略 attach3 (アップロードされたファイル)・・・・略 usericon (アイコン画像)・・・・アップロードされた画像を表示、アップロードがない場合は代替え画像を表示する + 返信ID (返信番号)・・・・回答に対する返信のID
homepage-site

2024/08/26 14:26

Q.質問か回答かを識別するカラムを追加して、質問を「1」、回答を「2」のように意味付けて識別 どの質問への回答かは頓着しないのですね。 A.tezcelloさん回答ありがとうございます。 確かにどの質問への回答か紐付けしたほうが良さそうですね。 Q.IDと無限スクロールとは直接関係は無いと思います。 A.回答ありがとうございます。前回の質問で uuid を使用することに変更したのでカラムは削除いたします。 Q.TS (投稿日時)・・・・7~10日で質問を cron で削除するため cronで削除するのにそんな幅のあるとやり難いと思うけど? __未定であるなら、公開期間終了後と書くと伝わり易いと思う A.回答ありがとうございます。公開期間終了後に修正いたしました。 Q.一般的にデータベースのデータを物理削除するのは悪手では? 利用者からすれば、表示されないデータは削除されたのと同じでしょう。 微妙にタイミングがずれるcronに依存するよりは、有効期間内であるかの判定をして表示・非表示するのを僕なら選びます。 __本当に削除が必要なら、別途管理者が管理メニュから実行する A.回答ありがとうございます。 非表示にする方法の方が適切そうですね変更も視野に入れてみます。 カラム名はそれぞれ下記のように変更いたします。 質問タイトルは悩みましたが、質問一覧表示画面で投稿者がタイトルを工夫して回答を集めるのも1つの方法だと考えあえて設定するようにしております。 name (質問者名) comment (コメント内容)・・・・コメント Q.ホントにファイルを入れる気かは別にして、「IPアドレス」は単なるミスだよね? UUID-1、UUID-2、UUID-3なんてファイル名じゃなく、ファイル名をそれぞれ別のUUIDにした方が、「○○を推測される恐れ」は回避できます。 __投稿IDだけ推測されない様にするってのは、不統一感が... どの投稿とファイルが関連付いているかなんて、管理用のページでやれば良いだけなので、目視でのチェックを前提にするのは普通は無いでしょう。 A.回答ありがとうございます、IPアドレスはアップロードされたファイルの間違いです申し訳ありません。 attach1 attach2 attach3 でループ処理にして1番目の画像を質問一覧表示画面のサムネイルとして、動画横スクロールで1番目の動画をランダムに5件だけトップページに表示させているのでコードをまとめるために設定していなかったのですが、 セキュリティを考えると別のUUIDにした方が良いでしょうか? Q.ログイン無しのQ&A掲示板 他の質問でも書いた通り、「ログイン必要」にするだけで(スパム的な)迷惑な書き込みや危険なリンク先や不適切な画像の貼り込みを「かなり」避けられます。 誰でも何回でも投稿できる仕組みは危険が一杯です。 A.回答ありがとうございます。 以前 tezcelloさんからアドバイス頂いたように投稿された質問を承認制にしてリスクの軽減を行うように変えてみます…
tezcello

2024/08/26 16:16

> セキュリティを考えると別のUUIDにした方が良いでしょうか? 「セキュリティーが~」を理由にして投稿IDではなくUUIDを使っているのに、アンバランスだと思っただけです。 __個人的には今回の場合、投稿IDが予測可能でもセキュリティーリスクが高いと思えないので __わざわざ投稿IDに代えてUUIDを使う必要もないと思っています __が、質問者さんのお好きな様に ファイル名に関しては、アップロードされたファイル名をそのまま使うのは危険なので何らかの処理が必要ですが、UUIDにしてしまうのは手っ取り早い方法だと思います。 > 1番目の動画を ファイルの順序に特別な意味があるのなら、それは別途記録するのが良いのでは? 僕だったら id INT UNSIGNED NOT NULL AUTO_INCREMENT commentId INT UNSIGNED NOT NULL sortOrder TINYINT UNSIGNED NOT NULL DEFAULT 0 displayName VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL filename VARCHAR(40) NOT NULL createdAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP 的なテーブルにして投稿のIDでリレーションを使って...と考えると思います。 __filenameカラムに保存時の実ファイル名(UUID等)をセットするつもりで書きました __UUIDがあるのにidをPKにしているのは、ブラウザ上でのファイル名は __idを基にしたその場限りのモノにして再利用等を防げないかなと思ったり... __具体的にどうやるかまでは考えていない... > 投稿された質問を承認制にして 正直管理者の負荷が大変なので、僕ならログイン制にします。
homepage-site

2024/08/27 14:50

Q.ファイル名に関しては、アップロードされたファイル名をそのまま使うのは危険なので何らかの処理が必要ですが、UUIDにしてしまうのは手っ取り早い方法だと思います。 A.tezcelloさん回答ありがとうございます。申し訳ありませんカラムの説明が間違っておりました。 ファイル名は現在 {質問UUID}_{ファイル番号}.{拡張子} という形に変更しているため、attach1、attach2、attach3 はファイル番号になります。 質問UUIDは unique_id になります。 Q.投稿のIDでリレーションを使って...と考えると思います。 __filenameカラムに保存時の実ファイル名(UUID等)をセットするつもりで書きました __UUIDがあるのにidをPKにしているのは、ブラウザ上でのファイル名は __idを基にしたその場限りのモノにして再利用等を防げないかなと思ったり... __具体的にどうやるかまでは考えていない... A.アドバイスありがとうございます。UUID-1、UUID-2、UUID-3 が推測されやすいという事ですが、元々の {質問ID}_{ファイル番号}.{拡張子} から変更していた場合もファイル番号を1、2、3で設定するのは避けたほうが良いでしょうか? Q.投稿された質問を承認制にして 正直管理者の負荷が大変なので、僕ならログイン制にします。 A.回答ありがとうございます。1点だけ気になることがあるのですがログイン制にした場合に避けられるのはロボットからの連投のみではないのでしょうか? 不適切不適切な画像(動画、PDF)の貼り込みな画像の貼り込みや詐欺や迷惑な広告、フィッシングも制御できるのか疑問です…
tezcello

2024/08/27 17:38

> 元々の {質問ID}_{ファイル番号}.{拡張子} から変更していた場合もファイル番号を1、2、3で設定するのは避けたほうが良いでしょうか? それぞれのファイル名を、個別のUUIDにしているって事? 質問UUID_1、質問UUID_2、、、の様に「質問UUID」の部分は同一で末尾だけ変えるって事? 後者だったら、質問IDが判ったら末尾を付加するだけでファイル名になるって事です。 「質問IDが連番だから推測され易いので危険だ」と考えるのに、推測どころか「確定的にファイル名が判明する」のはなぜ危険とは考えないのか腑に落ちません。 何度か同じ事を書いているけど、伝わらないみたいですね。 ファイル名のホントの名前は隠しておいて、ログイン後に質問を表示している状態じゃないとそのファイルを開けない様にするとかの再利用されない工夫も必要だと思うんですけどね。 UUIDもバージョンによってはセキュアではないみたい(ただし元々の発想が衝突の可能性を下げる事なのでセキュアを目指したわけではない)のは覚えておく必要があると思います。 > ログイン制にした場合に避けられるのはロボットからの連投のみではないのでしょうか? 最初に会員登録的な事をしないと投稿できない仕様だと、そのプロセスを理解できないと投稿まで進めないです。 __だからあまり簡単な登録では意味が無い __登録するとメールが返って、その内容に従ってアクセスしたり入力欄を埋めたり...が必要 「人が見て判断する」程には賢くない普通の自動投稿型のモノでは対処できないし、悪い事をしようとする連中は「面倒な」手続きを嫌う傾向にあるから、ある程度は防げると思います。 人がやる部分を残しておくと、危険性が減るってのは、CAPTCHAも似たような発想では? > も制御できるのか疑問です… 人が個別に入力しているモノは、内容が何であろうと基本的に入力時には防げません。 そこに至るまでを面倒だと思わせる位しか対処が無いと考えています。 ログイン不要の誰でも書き込める掲示板は、機械的なモノでも楽々書き込めますから、そんなモノよりは安全であろうという程度です。 __入力欄が複数あると全部に入力しようとする場合が多いので __空欄である事が必要と日本語で書いておくと、海外製のヤツには有効だったり... __ただしパラメータ名等でそういう事が判明しない様にする必要はアリ 以前に指摘した通り「短期で削除される様な掲示板は使いたくない」に賛同してくれる人は居るみたいですね。 > 古い質問が蓄積されていくよりも循環させたほうが良い 個人的な「お悩み相談所」になるのだと思いますが、どんな質問がどの様に解決されるのか実績が(消されてしまうので)解らないのでは、利用したいと思う人は少ないと思います。
homepage-site

2024/08/28 05:35 編集

Q.元々の {質問ID}_{ファイル番号}.{拡張子} から変更していた場合もファイル番号を1、2、3で設定するのは避けたほうが良いでしょうか? それぞれのファイル名を、個別のUUIDにしているって事? 質問UUID_1、質問UUID_2、、、の様に「質問UUID」の部分は同一で末尾だけ変えるって事? A.tezcelloさん回答ありがとうございます。{質問UUID}_{ファイル番号}.{拡張子} でファイル名を設定しており、個別のUUID_ファイルアップロード番号1、2、3.{拡張子}で表示しております。 Q.「人が見て判断する」程には賢くない普通の自動投稿型のモノでは対処できないし、悪い事をしようとする連中は「面倒な」手続きを嫌う傾向にあるから、ある程度は防げると思います。 人がやる部分を残しておくと、危険性が減るってのは、CAPTCHAも似たような発想では? 人が個別に入力しているモノは、内容が何であろうと基本的に入力時には防げません。 そこに至るまでを面倒だと思わせる位しか対処が無いと考えています。 A.解説ありがとうございます。掲示板に投稿するまでを複雑化することで危険性を減らすことが出来るという事なんですね理解出来ました。 お問い合わせフォームはメール送信とCAPTCHAを実装するようにしているのですが掲示板では考えておりませんでした。 Q.以前に指摘した通り「短期で削除される様な掲示板は使いたくない」に賛同してくれる人は居るみたいですね。 > 古い質問が蓄積されていくよりも循環させたほうが良い 個人的な「お悩み相談所」になるのだと思いますが、どんな質問がどの様に解決されるのか実績が(消されてしまうので)解らないのでは、利用したいと思う人は少ないと思います。 A.回答ありがとうございますデータが蓄積されていく掲示板だと競合に負けてしまうのではないかと考えて特徴を出す方法として選択したのですが適切ではなかったかもしれません…
tezcello

2024/08/28 12:22

> {質問UUID}_{ファイル番号}.{拡張子} でファイル名を設定 それは僕の書いた「後者」と同じですね。 > 後者だったら(略) と違和感についても書いています。 「固定の質問UUIDに末尾を付加する方法だと手動で質問と関連付けて削除するのが楽」にも無意味な関連付けである事は指摘済みです。 > 個別のUUID_ファイルアップロード番号1、2、3.{拡張子}で表示しております。 スクレイピングする連中はソースを読んでファイル名を取得するでしょうから、どんな表示をしているかは関係ないです。
tezcello

2024/08/30 07:27

> データ通信量によるかと思いますが回答専用テーブルを用意して質問専用テーブルと分けたほうが良いのではないかと考えて データの通信量が多い(あるいは少ない)と、なぜテーブルを分けた方が良いと考えたのでしょうか? それが間違った思い込みなどに因るものだとしたらそれを正しておかないとまたどこかで勘違いをする事になります。 > 7~10日で質問を cron で削除する前提であるものの同時刻に複数の掲示板が動作した場合負荷がかかり遅延に繋がるのではないか 一体どれ程の質問&回答があると想定されているのでしょうか? そしてどれ程の同時アクセスがあると想定されているのでしょうか? __個人で運営の短期で削除されてしまって過去の実勢や経緯が無くなってしまう __質問サイトがそれ程大人気になるとは考え難いと思うけど... かなり長文のSQLを書いたとしても、それが妥当な内容なら、データベース側での処理はそれ程の時間にはならないのでは? __(データベースの構造やインデックスを含めて)不適当なSQLなら __無駄に実行時間が掛かるでしょうが それよりもPHP側での処理が(データベースとの連携を含めて)キチンとなされているかの方が問題になると思います。
homepage-site

2024/08/31 13:24

Q.データの通信量が多い(あるいは少ない)と、なぜテーブルを分けた方が良いと考えたのでしょうか? A.tezcelloさん回答ありがとうございます、回答が増えた場合リアルタイムで複数のやり取りが行われ負荷が増える為、質問と切り離した方が良いのではないかと考えております。 Q.一体どれ程の質問&回答があると想定されているのでしょうか? そしてどれ程の同時アクセスがあると想定されているのでしょうか? A.回答ありがとうございます、1日で100件の投稿で1000件の回答&返信があると想像しております。 現在のイラスト掲示板を調べたところアクセス数は1日で5万から10万まで可能だと思われるので、日数を調整しないとレンタルサーバーが容量不足になるのではないかと考えております。
tezcello

2024/08/31 14:29

> 回答が増えた場合リアルタイムで複数のやり取りが行われ負荷が増える テーブルを分けた方がデータの取り扱いが楽になるかもとは考えるでしょうが、データの授受で極端な負荷が掛かるとは思えません。 アクセス頻度が高くなればデータベースへの負荷は当然大きくなりますが、もの凄く極端な状況で無い限り、許容できる程度の負荷でしょう。 何かデータ授受の負荷が増えて困る(システム全体の応答が遅くなる的な)裏付け(バックデータ)はありますか? > 1日で100件の投稿で1000件の回答&返信がある > 現在のイラスト掲示板を調べたところアクセス数は1日で5万から10万まで可能 > レンタルサーバーが容量不足になる 投稿が全部で1000件で、半数に800万画素(≒4MB)程度のイラストが添付されるとして約2GB 残り半数に60MB程度の動画であれば30GB、合計で32GB 画像、更には動画まで扱おうというにしては、余りに少ないのでは? __廉価なレンサバでも100GB程度はありそう 質問者さんはどの様な計算をしていますか?
homepage-site

2024/09/03 03:45

tezcelloさん回答ありがとうございます、データの授受で負荷が増えるという裏付けはありません… 1日で合計1000件で計算して7日で32GB×7=224GB  現在のレンタルサーバーの容量は SQL が 140GB なので 1つプランをあげて 350GB が目安になりそうです。 最大で10日程度は Q&A掲示板のデータを維持できると思われます。
tezcello

2024/09/03 08:12

> 1日で合計1000件 そんな大人気のサイトを想定しているのですか? > 現在のレンタルサーバーの容量は SQL が 140GB データベースにデータを突っ込むという話ではなかったはずです。
A21

2024/09/03 08:31

途中で割って入ってしまい申し訳ありませんがまずはどんな仕組みでもいいので作ってみては? すでにサイトを持っているとかそういうのでない限り一日1000個も投稿来ませんよ。 そういうのはそうなったら考えればいいんです まずは作ってみて、需要を実感したほうが良いと思います。
homepage-site

2024/09/09 10:18

tezcelloさん回答ありがとうございます、大型サイトとRSSで提携することを見越したサイトに掲示板を付け加えるような設計で考えているので、アクセス数に関しては伸びると見越しております。 データベースにファイルを直接保存する形ではなかったので、説明に間違えがありました申し訳ありません。
homepage-site

2024/09/09 10:19

A21さんありがとうございます。 まずは作成してみます。
tezcello

2024/09/09 10:59

> 大型サイトとRSSで提携することを見越したサイトに掲示板を付け加える 今時のVPSはスケールアップが簡単に出来ます。 『見越した』って始まってもいない事をアレコレ考えても無意味です。 仕組みを変えずとも簡単に対応出来るのだから、先ずは始める事を考える方が良いのでは? 個人のサイトなんて何時でも止められますから、何とでもなります。 > アクセス数に関しては伸びると見越して それは過大評価し過ぎでしょう...
guest

回答8

0

Q&Aは必ず関連しているから、両用という考えになるのかと思いますが、関係的に1:1とは限りませんから別テーブルにすべきだと思います。
また、関係を示す情報も別テーブルとする方が、拡張性は高いと思います。

投稿2024/08/27 01:15

sazi

総合スコア25313

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

homepage-site

2024/08/27 03:27

回答ありがとうございます。 別テーブルにするという方向でコードを考えてみます。
XiiTuzi

2024/08/27 05:46

関係を示す別テーブル(中間テーブル)は、この場合は不要ではないてしょうか? 基本的にN対Nで、例えば質問テーブルに回答IDがない場合があり、回答テーブルに質問IDがない場合がある。という設計であれば有効かと思いますが…… ※必要になるかもしれないからとりあえず作る、という設計には否定的な立場での意見です。
homepage-site

2024/08/27 14:55

XiiTuziさん回答ありがとうございます。 基本的に1つの質問に対して回答は複数くるのではないかと想定しているため両用テーブルにして質問か回答かを識別させた方が良いかもしれません。
XiiTuzi

2024/08/28 01:12 編集

質問テーブルと回答テーブルを分ける設計については全く異論ありません。 saziさんの回答にある最後の一行に対して、私の想定していない意図があればお聞きしたいと思った次第です。 (私の勘違いの可能性もありますし)
sazi

2024/09/02 01:03

@XiiTuziさん > ※必要になるかもしれないからとりあえず作る、という設計には否定的な立場での意見です。 要件が明確であれば提案はしませんが、Qに対して過去のAが参考になる(所謂FAQ)のような場合を想定していました。 私の回答スタンスは情報を提供し、取捨選択は質問者にしてもらうというものなので、こういった回答が多いです。
XiiTuzi

2024/11/08 02:38

かなり今更ですが、通知が来ないので見逃していました。 こちらから質問したにも関わらず、すみません。 FAQというのは私の想定範囲外で、理解しました。 回答の「スタンス」について異を唱えるつもりはありませんでしたが、私の発言を見直すとそのように取れますね。不快に感じたのであれば謝罪します。(日本語ネイティブではないので、言葉の表現がおかしいのはご容赦ください)
guest

0

質問と回答に保存する内容が極端に違うのであれば分けてもいいでしょうけど、たとえば回答に対してレスができる枝分岐していくような仕組みを模索するなら一緒の方が管理が楽だと思います

投稿2024/08/28 00:34

yambejp

総合スコア116644

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

homepage-site

2024/08/28 05:52

yambejpさんアドバイスありがとうございます。 質問と回答が結びついており回答に対してレスができる枝分岐していくような形なので両用テーブルで作成してみます。
guest

0

「X-Twitterのように質問・回答関係なくタイムラインとして時系列で並べたい」
「質問にも回答、どちらにも返信ができる仕様としたい」
「質問も回答も、基本的なデータ構造が同じ」
「質問・回答、どちらも対象に同じ条件で検索をさせたい」
という場合は、同じテーブルにして質問か回答かのフラグを付ける形が良いと思います。

質問と回答で持つカラムの内容が大きく異なる - 例えば、質問の方にはタグ、カテゴリ、閲覧PV数、いいね数、など回答には必要のないカラムが多数あるといった場合は、分けても良いと思います。

これは感想ですが、7-10日で質問を削除してしまうと、Q&Aがウェブ上に残らないのは少しもったいないような感じました。現にこの回答はご質問から8日後にしていますので、あと2日で消えてしまうと思うと…

投稿2024/09/02 23:28

findy

総合スコア43

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

homepage-site

2024/09/03 03:27

findyさんアドバイスありがとうございます。 カラムはスタンプとタイトルを除いて同じなので両用テーブルの方が良さそうですね。 もう少し期間を延ばせるように工夫してみたいと思います。
guest

0

分けた方がいいかなーとおもってはいます

投稿2024/08/28 02:06

yuske39

総合スコア2

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

homepage-site

2024/08/28 05:37

yuske39さん回答ありがとうございます。皆様のアドバイスからしっかり考えてみます。
guest

0

ベストアンサー

設計上、10日ほどで古いものを削除する運用であることから、データが増えた場合の性能低下を考慮する必要性が薄いです。そのため、作りやすい方で良いと思います。
動かないものよりは動いているものの方が大きな価値がありますし、とっかかりは実装が容易な方が良いです。
(セキュリティに問題があり、利用者に影響がでるなどの場合はその限りではないので、ここは慎重に検討する必要はあります。)

teratailのように、運営時間に応じてデータが増えていくサイトを目指すのであれば私であればテーブルを分けます。理由は主に下記です。

  • テーブルを分けなかった場合、一番アクセスの多いであろう質問一覧画面を表示するためにwhere句で item_type = 1 の絞り込みが必要になり、DBを効率的に扱えない
  • 感覚上テーブルを正規化して作りにくくなったことはあまりない
  • 分けることによって質問だけ、回答だけのデータ属性を拡張しやすくなる

投稿2024/08/27 16:24

Eggpan

総合スコア3203

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

homepage-site

2024/08/28 05:49

Eggpanさんアドバイスありがとうございます、データが蓄積される場合の性能低下を考慮する必要は無さそうですね。 分けることでカラムとコードが増えて難しくなるのであれば両用テーブルが良さそうです。 分けることによって質問だけ、回答だけのデータ属性を拡張しやすくなるということで覚えておきます。
guest

0

[香車]東上☆Aho☆海美「
『7~10日で質問が削除される掲示板』には、ワシは回答しないであろう。

投稿2024/08/27 10:37

umimi

総合スコア512

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

homepage-site

2024/08/27 14:58

umimiさん回答ありがとうございます。 期間は回答率などを見て調整する予定です。古い質問が蓄積されていくよりも循環させたほうが良いと思い一定期間での削除を考えました。
umimi

2024/08/29 11:16

似たような質問があった時、『過去レス #nnnn にあります』みたいな書込をしますが、質問が消される掲示板では、それが出来ません。 『循環』とは、具体的には、どのような行為を指しますか ?
homepage-site

2024/08/31 13:29

umimiさん回答ありがとうございます。 すべてのユーザーに平等な機会が与えられるべきだと考えました。過去レスが残ってしまうと掲示板開設初期から質問をしているユーザーに回答が集まることが予測されます。 雑談掲示板も別途作成予定であるため、そちらにも影響が出てしまうのではないかと考え、既存ユーザーと新規ユーザーで格差が出ない仕組みを考えております。
guest

0

ひとつのテーブルでいいと思います
質問にもあるようにコードをまとめられますから

投稿2024/08/27 04:14

utm.

総合スコア324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

utm.

2024/08/27 12:05 編集

関係的に1:1でないこととテーブルを分けることになんの関連性があるんだろうか? 例えばTwitterとかは、投稿1つに対して複数の返信がありえて、再帰的にこれが起きるけど、 返信テーブルが無限にあるという考えなのだろうか?(システムに制限があるのか、無限に返信出来るかどうかは知らんが) グッドボタンが5つも押されているので疑問を吐露
homepage-site

2024/08/27 15:02

utm.さん回答ありがとうございます。 投稿1つに対して複数の返信があるというシステムであると思います。 質問に対して回答がありその回答にも複数の返信があるという形を想定しているので、負荷を考えるとテーブルを分ける方が良いかもしれません…
utm.

2024/08/27 15:09

わかりました。 投稿者に任せますが、 テーブルを分けると、おそらく想定よりコードが煩雑になる気がします。 正直な話、 1. 多分想定しているよりは、検索等のクエリによる負荷(遅延)はかからないかと思います。 2. 同じテーブルに投稿をまとめた場合、リプレイスやリファクタリングでテーブルを分けるのは簡単ですが、その逆は困難です。 個人的に、ヌルなカラムが増えることより、コードで見た時のやりやすさを取りたい気持ちがあります。 あ、そういえば最初の回答で書き忘れましたが、 DB設計に正解はありませんから、正直なんでもいいとも思います。
utm.

2024/08/27 23:51

UIに使う列はどうせインデックス張るし、絞込みを行うとDBを効率的に扱えないってミスリードな気がするんですが。 (パフォーマンスについては測定しろ推測するなですが)
homepage-site

2024/08/28 05:44

utm.さんアドバイスありがとうございます。 テーブルを分けた場合も質問専用テーブルと結び付ける必要がありそうなのでカラムもコードも増えそうです。 クエリによる負荷(遅延)が想定よりかからないのであれば両用テーブルにしてみます。
utm.

2024/08/28 07:31

ひとつのテーブルにしても結びつけは必要ですけどね。。。
homepage-site

2024/08/31 13:30

utm.さんアドバイスありがとうございます。 結びつけるようにして考えてみます。
guest

0

タグにも本文にも登場していないですが、そもそもテーブルとは
DB(おそらくmysql辺り?)という前提で良いんでしょうか


仮にmysqlであればpaizaのオンライン実行環境みたいなところで
テーブル作成・仮データ投入・想定される用途でのデータ取得(質問の一覧取得, 特定の質問と紐づく回答の取得)
みたいなのを試してみると良いんじゃないでしょうか。

一般的な開発のやり方としては、実装を進める前の設計フェーズにて机上で検討してみるというのは当然やるべきで大切なことですが
なんとなく、質問者さんはDB設計のセオリーとか常識みたいなのを習得する前段階なのでは?と見受けられるので
まずは色々手を動かして試してみて、異なる設計方針でのメリットデメリットを体感してみるのも良いと思います。

今回の件では、「両用テーブル」方針と「専用テーブルに分割」方針で
ある一方は割と自然なデータ定義&素直なデータ取得クエリになり、
もう一方はかなり不自然なデータ定義&面倒なデータ取得クエリになる。
……と思うので、実際に分かり易く体感できるのでないかと。

投稿2024/08/27 04:10

pecmm

総合スコア664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

homepage-site

2024/08/27 15:06

pecmmさん回答ありがとうございます。 データベースの SQL になります。paiza で動かしてみるというのは想定しておりませんでした、以後使ってみようと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問