画像添付 PHPメールフォーム ダウンロード
画像添付 PHP メールフォームのご紹介です。
機能性を増した物は下記をぜひためしてみてください。
メールフォームとは
メールフォームとは、Webサイトに設置されており、メールを介して申込みや投稿を行うためのものです。
広い意味では、Web上のテキスト投稿なども POST を通じた情報のやりとりと捉えることができます。
このやりとりは、Webサービスの信頼性や機能性を左右する重要な部分です。
フロントエンドは通常 HTML で構成され、バックエンドには PHP や Node.js+JavaScript フレームワークなどが使用されます。
なお、Node.js はサーバー自体を含むため、一般的なレンタルサーバーでは主に PHP が利用されています。
かつては .cgi 拡張子で Perl を使った CGI も多く見られました。
PHPメールフォームを作る
ここでは、PHP を用いたメールフォームを作成してみたいと思います。
構成は以下の3ファイルです:
- index.php(入力画面)
- confirmation.php(確認画面)
- send.php(送信処理)
よく検索で見かける「PHP工房」さんのように1ファイルで完結する例もありますが、ここではセキュリティ対策として「CSRF 対策」や「セッション管理による再送信防止」を考慮し、3ファイル構成としています。
まず、index.php
<form action="confirmation.php" method="post" enctype="multipart/form-data">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($token) ?>">
<div class="form-group">
<label for="name" class="required">名前(必須)</label>
<input type="text" name="name" id="name" required placeholder="例: 檸檬">
</div>
<div class="form-group">
<label for="kana">ふりがな</label>
<input type="text" name="kana" id="kana" placeholder="例: れもん">
</div>
<div class="form-group">
<label for="prefecture">住所(都道府県)</label>
<select name="prefecture" id="prefecture">
<option value="">選択してください</option>
<?php
$prefs = ['北海道','青森県','岩手県','宮城県','秋田県','山形県','福島県','茨城県','栃木県','群馬県','埼玉県','千葉県','東京都','神奈川県','新潟県','富山県','石川県','福井県','山梨県','長野県','岐阜県','静岡県','愛知県','三重県','滋賀県','京都府','大阪府','兵庫県','奈良県','和歌山県','鳥取県','島根県','岡山県','広島県','山口県','徳島県','香川県','愛媛県','高知県','福岡県','佐賀県','長崎県','熊本県','大分県','宮崎県','鹿児島県','沖縄県'];
foreach ($prefs as $p) {
echo '<option value="'.htmlspecialchars($p).'">'.htmlspecialchars($p).'</option>';
}
?>
</select>
</div>
<div class="form-group">
<label for="email" class="required">メールアドレス(必須)</label>
<input type="email" name="email" id="email" required placeholder="例: example@mail.com">
</div>
<div class="form-group">
<label for="file">画像添付①</label>
<input type="file" name="file" id="file" accept="image/*">
</div>
<div class="form-group">
<label for="file2">画像添付②</label>
<input type="file" name="file2" id="file2" accept="image/*">
</div>
<div class="form-group">
<label for="file3">画像添付③</label>
<input type="file" name="file3" id="file3" accept="image/*">
</div>
<div class="form-group submit-group">
<button type="submit" class="submit-button">確認画面へ進む</button>
</div>
</form>
このフォームのポイントは以下の2点です:
method="post" enctype="multipart/form-data"
method=”post” および enctype=”multipart/form-data” を指定することで、画像ファイルの送信が可能になります。
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($token) ?>">
csrf_token を hidden フィールドで送信し、外部からの不正なアクセスを防止します。
csrf_token を生成するため、ページ上部には以下の PHP を記述します
<?php session_start(); session_regenerate_id(true); $token = bin2hex(random_bytes(32)); $_SESSION['csrf_token'] = $token; ?> <!DOCTYPE html> <html lang="ja"> <head>
session_start() によりセッションを開始し、生成したトークンをセッションと hidden フィールドの両方に保存しています。
PHPメールフォーム 確認画面
confirmation.php
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Location: index.php');
exit;
}
// CSRFチェック
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== ($_SESSION['csrf_token'] ?? '')) {
exit('不正なアクセスです。');
}
// サニタイズ関数
function h($str) {
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
// ファイル処理用
$image_fields = ['file', 'file2', 'file3'];
$saved_images = [];
$image_previews = [];
$tmp_dir = __DIR__ . '/tmp/';
if (!is_dir($tmp_dir)) {
mkdir($tmp_dir, 0755, true);
}
foreach ($image_fields as $field) {
if (!isset($_FILES[$field]) || $_FILES[$field]['error'] === UPLOAD_ERR_NO_FILE) continue;
if ($_FILES[$field]['error'] !== UPLOAD_ERR_OK) continue;
$mime = mime_content_type($_FILES[$field]['tmp_name']);
$allowed = ['image/jpeg', 'image/png', 'image/gif'];
if (!in_array($mime, $allowed)) continue;
$ext = pathinfo($_FILES[$field]['name'], PATHINFO_EXTENSION);
$filename = uniqid($field . '_') . '.' . $ext;
$destination = $tmp_dir . $filename;
if (is_uploaded_file($_FILES[$field]['tmp_name'])) {
move_uploaded_file($_FILES[$field]['tmp_name'], $destination);
$saved_images[$field] = $filename;
$image_previews[] = './tmp/' . $filename;
}
}
// フォームデータ保持
$_SESSION['form_data'] = [
'name' => $_POST['name'] ?? '',
'kana' => $_POST['kana'] ?? '',
'prefecture' => $_POST['prefecture'] ?? '',
'email' => $_POST['email'] ?? '',
'images' => $saved_images
];
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>確認画面</title>
<style>
body { font-family: sans-serif; padding: 20px; }
.data-group { margin-bottom: 15px; }
.buttons { margin-top: 30px; }
img.preview { max-width: 200px; margin-top: 10px; margin-right: 10px; }
</style>
</head>
<body>
<h1>入力内容の確認</h1>
<div class="data-group"><strong>名前:</strong><?= h($_POST['name']) ?></div>
<div class="data-group"><strong>ふりがな:</strong><?= h($_POST['kana']) ?></div>
<div class="data-group"><strong>都道府県:</strong><?= h($_POST['prefecture']) ?></div>
<div class="data-group"><strong>メール:</strong><?= h($_POST['email']) ?></div>
<?php if (!empty($image_previews)): ?>
<div class="data-group">
<strong>添付画像:</strong><br>
<?php foreach ($image_previews as $url): ?>
<img src="<?= h($url) ?>" alt="画像" class="preview">
<?php endforeach; ?>
</div>
<?php endif; ?>
<form action="send.php" method="post">
<input type="hidden" name="csrf_token" value="<?= h($_POST['csrf_token']) ?>">
<input type="hidden" name="name" value="<?= h($_POST['name']) ?>">
<input type="hidden" name="kana" value="<?= h($_POST['kana']) ?>">
<input type="hidden" name="prefecture" value="<?= h($_POST['prefecture']) ?>">
<input type="hidden" name="email" value="<?= h($_POST['email']) ?>">
<?php foreach ($saved_images as $key => $filename): ?>
<input type="hidden" name="uploaded_images[<?= h($key) ?>]" value="<?= h($filename) ?>">
<?php endforeach; ?>
<div class="buttons">
<button type="submit">この内容で送信する</button>
</div>
</form>
<form action="index.php" method="get">
<div class="buttons">
<button type="submit">戻って修正する</button>
</div>
</form>
</body>
</html>
index.php から POST で送られてきた内容を受け取り、確認画面を表示します。
今回は画像添付フォームなので、この段階で画像がサーバーに一時保存され、確認画面でプレビュー表示されます。
確認後、「送信」ボタンを押すと send.php によって処理されます。
PHPメールフォーム 送信
send.php
<?php
session_start();
// CSRFチェック
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['csrf_token']) || $_POST['csrf_token'] !== ($_SESSION['csrf_token'] ?? '')) {
exit('不正な送信です。');
}
// 入力データ取得
$name = $_POST['name'] ?? '';
$kana = $_POST['kana'] ?? '';
$prefecture = $_POST['prefecture'] ?? '';
$email = $_POST['email'] ?? '';
$uploaded_images = $_POST['uploaded_images'] ?? [];
$tmp_dir = __DIR__ . '/tmp/';
// メール本文
$body = "以下の内容でお問い合わせがありました。\n\n";
$body .= "名前: {$name}\n";
$body .= "ふりがな: {$kana}\n";
$body .= "都道府県: {$prefecture}\n";
$body .= "メール: {$email}\n\n";
$body .= "送信元IP: {$_SERVER['REMOTE_ADDR']}\n";
$body .= "送信日時: " . date('Y-m-d H:i:s') . "\n";
// メールヘッダ
$to = ''; // 管理者宛先
$from = ''; // 自ドメイン
$subject = '【お問い合わせ】フォームからの送信';
$headers = "From: {$from}\r\n";
$headers .= "Reply-To: {$email}\r\n";
// 添付メール送信関数
function send_mail_with_attachments($to, $subject, $message, $headers, $files = []) {
$boundary = "==Multipart_" . md5(uniqid());
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed; boundary=\"{$boundary}\"\r\n";
$body = "--{$boundary}\r\n";
$body .= "Content-Type: text/plain; charset=\"UTF-8\"\r\n";
$body .= "Content-Transfer-Encoding: 7bit\r\n\r\n";
$body .= $message . "\r\n\r\n";
foreach ($files as $filepath) {
if (!file_exists($filepath)) continue;
$filename = basename($filepath);
$mime = mime_content_type($filepath);
$content = chunk_split(base64_encode(file_get_contents($filepath)));
$body .= "--{$boundary}\r\n";
$body .= "Content-Type: {$mime}; name=\"{$filename}\"\r\n";
$body .= "Content-Disposition: attachment; filename=\"{$filename}\"\r\n";
$body .= "Content-Transfer-Encoding: base64\r\n\r\n";
$body .= $content . "\r\n\r\n";
}
$body .= "--{$boundary}--";
return mail($to, $subject, $body, $headers);
}
// 添付ファイルのパス配列を作成
$files = [];
foreach ($uploaded_images as $img) {
$filepath = $tmp_dir . basename($img);
if (file_exists($filepath)) {
$files[] = $filepath;
}
}
// 送信
$sent = send_mail_with_attachments($to, $subject, $body, $headers, $files);
if (!empty($_SESSION['form_data']['images'])) {
$tmp_dir = __DIR__ . '/tmp/';
foreach ($_SESSION['form_data']['images'] as $filename) {
$path = $tmp_dir . basename($filename);
if (file_exists($path)) unlink($path);
}
unset($_SESSION['form_data']['images']);
}
// セッション破棄
unset($_SESSION['form_data']);
// 完了画面表示
if ($sent) {
echo '<p>送信が完了しました。ありがとうございました。</p>';
} else {
echo '<p>送信に失敗しました。</p>';
}
?>
<p><a href="index.php">戻る</a></p>
このファイルでは、確認画面で「送信」ボタンが押されたあと、最終的な送信処理を行います。
- CSRFトークンを検証し、不正アクセスを防止
- 入力された情報と画像ファイルを取得
- 管理者宛にメールを送信(画像は添付)
- 送信後、サーバーに一時保存された画像を削除
- セッションを破棄して再送信を防止
設定も同じファイルになっています。
送信先メールアドレスを設定し、サーバーにアップすれば動くはず。
送信した後、セッションで画像を識別しサーバーから削除します。
送信後セッションも破棄されるので、戻っても再送信はできません。
このメールフォームはサンプル
このサンプルフォームはシンプルな構造で設計されています。そのため
- 自動返信メール機能 は含まれていません
- フォームのフィールドを変更する際、POST処理側のコードも都度修正が必要です
- 入力バリデーションやスパム対策など、セキュリティ対策は最低限です
- WordPressなどのCMSと組み合わせると、セッション処理が競合して正しく動作しない可能性があります
またセキュリティ面もバリデーションチェックなども不十分です。
よりよい自分設置型 画像添付フォームをお探しの方へ
上記のような不便さや制限を解消するために開発されたのが lemonform です。
- JavaScript による入力補助機能
- 有料版では 動画ファイルの送信 にも対応
- 容量制限なども設定可能
- スマホ対応やスパム対策など、機能を搭載
ぜひお試しください。