目次
デモページ
https://internet.mints.ne.jp/contact-mt/index.php
作成手順
1)ローカルDocker環境でプロジェクトディレクトリ作成
project-dir
├ Dockerfile
└ docker-compose.yml
project-dir\Dockerfile
FROM php:7.4-apache
RUN apt-get update && apt-get install -y \
libzip-dev \
zip \
&& docker-php-ext-install zip
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN docker-php-ext-install mysqli pdo pdo_mysql
# SMTPサポートを有効化
RUN apt-get install -y msmtp msmtp-mta && \
echo 'sendmail_path = "/usr/bin/msmtp -t"' > /usr/local/etc/php/conf.d/mail.ini
COPY . /var/www/html/
RUN composer install
project-dir\docker-compose.yml
version: '3'
services:
web:
build: .
ports:
- "8080:80"
volumes:
- .:/var/www/html
Dockerサービスの起動
docker-compose up -d
2)PHPMailerのインストール:
Composerを使用してPHPMailerをインストールします。プロジェクトのルートディレクトリで以下のコマンドを実行します
composer require phpmailer/phpmailer
project-dir
├ Dockerfile
├ docker-compose.yml
├ vendor
├ composer.json
└ composer.lock
3)設定ファイルの作成
config.php
.envファイルで環境変数の管理する方法もありますが、小規模なプロジェクトでシンプルな構成になるconfig.phpを使用した手順で行います
SMTPについての設定情報を定義
<?php
// 環境の判別
$is_local = ($_SERVER['SERVER_NAME'] == 'localhost' || $_SERVER['SERVER_ADDR'] == '127.0.0.1');
// デバッグモードの設定
define('DEBUG_MODE', $is_local); // ローカルではデバッグモードON、本番では OFF
// 本番環境で一時的にデバッグモードを有効化する場合
// define('DEBUG_MODE', true); // コメントを外して使用
if ($is_local) {
// ローカル環境(Docker)の設定
define('SMTP_HOST', 'smtp.example.com');
define('SMTP_USER', 'your_email@example.com');
define('SMTP_PASS', 'your_password');
define('SMTP_PORT', 587);
define('SMTP_SECURE', 'tls');
} else {
// さくらインターネット環境の設定
define('SMTP_HOST', 'your_sakura_smtp_host');
define('SMTP_USER', 'your_sakura_smtp_user');
define('SMTP_PASS', 'your_sakura_smtp_password');
define('SMTP_PORT', 587);
define('SMTP_SECURE', 'tls');
}
.gitignore
ファイルに secret_config.php
を追加して、Git の管理対象から除外します。
.gitignore
config.php
→別途 FTP でサーバーにアップロード
project-dir
├ Dockerfile
├ docker-compose.yml
├ vendor
├ composer.json
├ composer.lock
├ .gitignore
└ config.php ※本番環境ではウェブルート外で、直接アクセスされない階層に配置します
4)表示ファイル作成
project-dir
├ Dockerfile
├ docker-compose.yml
├ vendor
├ composer.json
├ composer.lock
├ .gitignore
├ config.php
├ index.php
├ confirm.php
├ thanks.html
└ contact.css
index.php
<?php
session_start();
$error = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// フォームの入力値を取得
// $post 配列は $_POST 配列とほぼ同じ構造を持ちます。
// キーは同じで、値がフィルタリングされたものになります。
$post = filter_input_array(INPUT_POST, $_POST);
// フォームの送信時エラーチェック
if ($post['name'] === '') {
$error['name'] = 'blank';
}
if ($post['email'] === '') {
$error['email'] = 'blank';
} elseif (!filter_var($post['email'], FILTER_VALIDATE_EMAIL)) {
$error['email'] = 'email';
}
if ($post['contact'] === '') {
$error['contact'] = 'blank';
}
if (count($error) === 0) {
// エラーがない場合、確認画面へリダイレクト
$_SESSION['form'] = $post;
header('Location: confirm.php');
exit();
}
} else {
if (isset($_SESSION['form'])) {
// 戻るボタンから戻ってきた場合、セッションに保存された値をフォームに表示
$post = $_SESSION['form'];
}
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>お問合せフォーム</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="contact.css">
</head>
<body>
<!-- お問合せフォーム画面 -->
<div class="container">
<!-- エラー時を考えると、formデータ送信後の遷移先は
自身のファイルに再度遷移するほうが
通常シンプルな作りになります -->
<form action="" method="POST" novalidate>
<p>お問い合わせ</p>
<div class="form-group">
<div class="row">
<div class="col-md-4">
<label for="inputName">お名前 <span class="require_item">必須</span></label>
</div>
<div class="col-md-8">
<input type="text" name="name" id="inputName" class="form-control" required autofocus
value="<?php echo htmlspecialchars($post['name']); ?>">
<?php if ($error['name'] === 'blank') : ?>
<p class="error_msg">※お名前をご記入下さい</p>
<?php endif; ?>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-4">
<label for="inputEmail">メールアドレス <span class="require_item">必須</span></label>
</div>
<div class="col-md-8">
<input type="email" name="email" id="inputEmail" class="form-control" required
value="<?php echo htmlspecialchars($post['email']); ?>">
<?php if ($error['email'] === 'blank') : ?>
<p class="error_msg">※メールアドレスをご記入ください</p>
<?php endif; ?>
<?php if ($error['email'] === 'email') : ?>
<p class="error_msg">※メールアドレスを正しくご記入ください</p>
<?php endif; ?>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-4">
<label for="inputContent">お問い合わせ内容 <span class="require_item">必須</span></label>
</div>
<div class="col-md-8">
<textarea name="contact" id="inputContent" rows="10" class="form-control" required><?php echo htmlspecialchars($post['contact']); ?></textarea>
<?php if ($error['contact'] === 'blank') : ?>
<p class="error_msg">※お問い合わせ内容をご記入ください</p>
<?php endif; ?>
</div>
</div>
</div>
<div class="row mt-5">
<div class="col-8 offset-4">
<a href="javascript:history.back();" class="btn btn-secondary mr-2">戻る</a>
<button type="submit" class="btn btn-primary">確認画面へ</button>
</div>
</div>
</form>
</div>
</body>
</html>
confirm.php
<?php
ob_start(); // 出力バッファリングを開始
session_start();
// 設定ファイルの読み込み
if (strpos(__DIR__, '/home/siennahare23') !== false) {
// さくらインターネット環境
require_once '/home/siennahare23/config/config.php';
} else {
// ローカル環境
require_once __DIR__ . '/config.php';
}
error_log('Current working directory: ' . getcwd());
// PHPMailer の読み込み
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'vendor/autoload.php';
if (!isset($_SESSION['form'])) {
header('Location: index.php');
exit();
} else {
$post = $_SESSION['form'];
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$mail = new PHPMailer(true);
try {
// デバッグ設定(問題解決後に削除してください)
$mail->SMTPDebug = 3;
$mail->Debugoutput = 'error_log';
$mail->CharSet = 'UTF-8';
$mail->Encoding = 'base64';
// メールサーバの設定
$mail->isSMTP();
$mail->Host = SMTP_HOST;
$mail->SMTPAuth = true;
$mail->Username = SMTP_USER;
$mail->Password = SMTP_PASS;
$mail->SMTPSecure = SMTP_SECURE;
$mail->Port = SMTP_PORT;
// ↓お問い合わせフォームの内容をメールで送信する処理↓
// 送信元(システムのメールアドレス)
$mail->setFrom(SMTP_USER, 'お問い合わせフォーム自動返信メール');
// 送信元のメールアドレス
// フォームに入力されたメールアドレスを送信元として
// 使用することが原因でメールが拒否される可能性があるため
// $toEmail = $is_local ? SMTP_USER : (defined('TO_EMAIL') ? TO_EMAIL : SMTP_USER);
$toEmail = $post['email'];
if (filter_var($toEmail, FILTER_VALIDATE_EMAIL)) {
$mail->addAddress($toEmail);
} else {
throw new Exception('Invalid TO_EMAIL address: ' . $toEmail);
}
// 管理者へのコピー送信(オプション)
$adminEmail = SMTP_USER;
if (filter_var($adminEmail, FILTER_VALIDATE_EMAIL) && $adminEmail !== $toEmail) {
$mail->addCC($adminEmail, '管理者');
}
$mail->isHTML(false);
$mail->Subject = 'お問い合わせがありがとうございます';
$mail->Body = <<<EOT
{$post['name']} 様
お問い合わせありがとうございます。
以下の内容で承りました。
お名前:{$post['name']}
メールアドレス:{$post['email']}
お問い合わせ内容:
{$post['contact']}
後ほど、担当者より回答させていただきます。
EOT;
$mail->send();
// セッションを破棄
unset($_SESSION['form']);
header('Location: thanks.html');
exit();
} catch (Exception $e) {
ob_end_clean();
error_log("メール送信エラー: " . $e->getMessage());
error_log("PHPMailer エラー: " . $mail->ErrorInfo);
echo "メッセージを送信できませんでした。エラー: " . $e->getMessage() . "<br>";
echo "PHPMailer エラー: " . $mail->ErrorInfo;
}
}
ob_end_flush(); // バッファの内容を出力
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>お問合せフォーム</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="contact.css">
</head>
<body>
<!-- お問合せフォーム画面 -->
<div class="container">
<form action="" method="POST">
<p>お問い合わせ</p>
<div class="form-group">
<div class="row">
<div class="col-3">
<label for="inputName">お名前</label>
</div>
<div class="col-9">
<p class="display_item"><?php echo htmlspecialchars($post['name']); ?></p>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-3">
<label for="inputEmail">メールアドレス</label>
</div>
<div class="col-9">
<p class="display_item"><?php echo htmlspecialchars($post['email']); ?></p>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-3">
<label for="inputContent">お問い合わせ内容</label>
</div>
<div class="col-9">
<p class="display_item">
<?php echo nl2br(htmlspecialchars($post['contact'])); ?>
</p>
</div>
</div>
</div>
<div class="row">
<div class="col-9 offset-3">
<a href="/index.php" class="btn btn-secondary mr-2">戻る</a>
<button type="submit" class="btn btn-primary">送信する</button>
</div>
</div>
</form>
</div>
</body>
</html>
thanks.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>お問合せフォーム</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="contact.css">
</head>
<body>
<div class="container">
<p>お問い合わせ</p>
<div class="thanks_msg">
<p>
お問い合わせありがとうございました。<br>
後ほど、担当者よりご連絡をさせていただきます。<br>
</p>
<img src="./img/thanksimg.png" alt="Thank you" class="img-fluid mb-4" style="max-width: 40%;">
<div>
<a href="index.php" class="btn btn-primary">トップページに戻る</a>
</div>
</div>
</div>
</body>
</html>
conatact.css
/* 共通 */
.container {
padding: 1.5% 8%;
}
form > p, .container > p {
text-align: center;
font-size: 24px;
padding-bottom: 20px;
}
label {
padding-top: 7px;
}
.form-group {
margin-bottom: 0;
}
/* contact.html */
.form-group label {
display: flex;
align-items: center;
}
.require_item {
display: inline-block;
background-color: #dc3545;
color: #fff;
font-size: 0.75rem;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
margin-left: 0.5rem;
vertical-align: middle;
}
.error_msg {
font-size: 14px;
color: #ff0000;
height: 14px;
}
/* confirm.html */
.display_item {
padding: 7px 0;
margin-bottom: 30px;
}
a {
color: #000;
border: solid 0.5px rgb(173, 173, 173);
background-color: #f7f7f7;
padding: 3.5px 20px;
}
a:hover {
text-decoration: none;
color: #000;
}
/* thanks.html */
.thanks_msg {
text-align: center;
background-color: #c8fbff;
padding:20px 0 50px;
}