PHPプログラミング

最終更新日:
公開日:

ワークショップ

お問い合わせフォームを作る(9)

アップロードしたファイルをメールに添付する

ワークショップ「お問い合わせフォームを作成する」の第9回目は、フォームからサーバーへアップロードされたファイルを自動送信メールに添付する機能を実装します。

この記事のポイント

  • メールにファイルを添付する方法を解説
  • メールをテキストデータ + 添付ファイルデータの形で送信するように実装する

目次

自動送信メールにファイルを添付する

前回の「フォームにファイルアップロード機能をつける」では、フォームに画像やPDFなどのファイルをサーバー上のディレクトリへ保存する機能を実装しました。
今回はそのファイルを、自動送信されるメールへ添付する機能を実装します。

今回使用しているコードは、前回までに作成したものを使うことを前提としています。
前回のページ:vol.8 フォームにファイルアップロード機能をつける
前回作成したコードはこちら:vol.8のサンプルコード – GitHub

メールにファイルを添付する方法

実装を進めている前に、メールにファイルを添付する方法について解説します。
まずはmb_send_mail関数のパラメータを改めて確認しておきましょう。

mb_send_mail( $to, $subject, $body, $header);

$toには宛先、$subjectにはメールの件名、$bodyにはメッセージ(本文)、$headerはヘッダー情報がそれぞれ入ります。
以下のようなイメージです。

メールの構造
メールの構造

今までは本文に「この度は、お問い合わせ頂き誠にありがとうございます。」などのテキストデータだけを入れて送信してきました。

テキストデータのみのメール

メールの本文にテキストデータだけを入れたイメージ
メールの本文にテキストデータだけを入れたイメージ

実は、本文にはテキストデータ以外にもファイルなどを入れて送信することができます。

ファイルデータも入ったメール

本文にテキストデータとファイルデータの両方を入れたイメージ
本文にテキストデータとファイルデータの両方を入れたイメージ

このようにファイルデータが含まれたメールが、いわゆる「添付ファイル付きのメール」となります。
もちろん複数のファイルを添付することも可能です。

今回はこれまで「本文」のみだったメールにファイルデータも追加するように実装して、添付ファイル付きのメールを送信できるようにしていきます。

ファイルを添付したメール送信を実装する

早速コードを書いていきましょう。
今回はメール送信に関連した実装となるため、「送信」ボタンが押された後の自動返信メールに関する場所にコードを追加、及び修正を加えていきます。

Note

赤い箇所は追加するコードを、オレンジの箇所は修正しているコードを示します。

index.php

<?php

define( "FILE_DIR", "images/test/");

---- 省略 ----

} elseif( !empty($clean['btn_submit']) ) {

	$page_flag = 2;

	// 変数とタイムゾーンを初期化
	$header = null;
	$body = null;
	$auto_reply_subject = null;
	$auto_reply_text = null;
	$admin_reply_subject = null;
	$admin_reply_text = null;
	date_default_timezone_set('Asia/Tokyo');
	
	//日本語の使用宣言
	mb_language("ja");
	mb_internal_encoding("UTF-8");

	$header = "MIME-Version: 1.0\n";
	$header = "Content-Type: multipart/mixed;boundary=\"__BOUNDARY__\"\n";
	$header .= "From: GRAYCODE <noreply@gray-code.com>\n";
	$header .= "Reply-To: GRAYCODE <noreply@gray-code.com>\n";

	// 件名を設定
	$auto_reply_subject = 'お問い合わせありがとうございます。';

	// 本文を設定
	$auto_reply_text = "この度は、お問い合わせ頂き誠にありがとうございます。
下記の内容でお問い合わせを受け付けました。\n\n";
	$auto_reply_text .= "お問い合わせ日時:" . date("Y-m-d H:i") . "\n";
	$auto_reply_text .= "氏名:" . $clean['your_name'] . "\n";
	$auto_reply_text .= "メールアドレス:" . $clean['email'] . "\n";

	if( $clean['gender'] === "male" ) {
		$auto_reply_text .= "性別:男性\n";
	} else {
		$auto_reply_text .= "性別:女性\n";
	}
	
	if( $clean['age'] === "1" ){
		$auto_reply_text .= "年齢:〜19歳\n";
	} elseif ( $clean['age'] === "2" ){
		$auto_reply_text .= "年齢:20歳〜29歳\n";
	} elseif ( $clean['age'] === "3" ){
		$auto_reply_text .= "年齢:30歳〜39歳\n";
	} elseif ( $clean['age'] === "4" ){
		$auto_reply_text .= "年齢:40歳〜49歳\n";
	} elseif( $clean['age'] === "5" ){
		$auto_reply_text .= "年齢:50歳〜59歳\n";
	} elseif( $clean['age'] === "6" ){
		$auto_reply_text .= "年齢:60歳〜\n";
	}

	$auto_reply_text .= "お問い合わせ内容:" . nl2br($clean['contact']) . "\n\n";
	$auto_reply_text .= "GRAYCODE 事務局";

	// テキストメッセージをセット
	$body = "--__BOUNDARY__\n";
	$body .= "Content-Type: text/plain; charset=\"ISO-2022-JP\"\n\n";
	$body .= $auto_reply_text . "\n";
	$body .= "--__BOUNDARY__\n";

	// ファイルを添付
	if( !empty($clean['attachment_file']) ) {
		$body .= "Content-Type: application/octet-stream; name=\"{$clean['attachment_file']}\"\n";
		$body .= "Content-Disposition: attachment; filename=\"{$clean['attachment_file']}\"\n";
		$body .= "Content-Transfer-Encoding: base64\n";
		$body .= "\n";
		$body .= chunk_split(base64_encode(file_get_contents(FILE_DIR.$clean['attachment_file'])));
		$body .= "--__BOUNDARY__\n";
	}

	// 自動返信メール送信
	mb_send_mail( $clean['email'], $auto_reply_subject, $body, $header);

	// 運営側へ送るメールの件名
	$admin_reply_subject = "お問い合わせを受け付けました";

	// 本文を設定
	$admin_reply_text = "下記の内容でお問い合わせがありました。\n\n";
	$admin_reply_text .= "お問い合わせ日時:" . date("Y-m-d H:i") . "\n";
	$admin_reply_text .= "氏名:" . $clean['your_name'] . "\n";
	$admin_reply_text .= "メールアドレス:" . $clean['email'] . "\n";

	if( $clean['gender'] === "male" ) {
		$admin_reply_text .= "性別:男性\n";
	} else {
		$admin_reply_text .= "性別:女性\n";
	}

	if( $clean['age'] === "1" ){
		$admin_reply_text .= "年齢:〜19歳\n";
	} elseif ( $clean['age'] === "2" ){
		$admin_reply_text .= "年齢:20歳〜29歳\n";
	} elseif ( $clean['age'] === "3" ){
		$admin_reply_text .= "年齢:30歳〜39歳\n";
	} elseif ( $clean['age'] === "4" ){
		$admin_reply_text .= "年齢:40歳〜49歳\n";
	} elseif( $clean['age'] === "5" ){
		$admin_reply_text .= "年齢:50歳〜59歳\n";
	} elseif( $clean['age'] === "6" ){
		$admin_reply_text .= "年齢:60歳〜\n";
	}

	$admin_reply_text .= "お問い合わせ内容:" . nl2br($clean['contact']) . "\n\n";
	
	// テキストメッセージをセット
	$body = "--__BOUNDARY__\n";
	$body .= "Content-Type: text/plain; charset=\"ISO-2022-JP\"\n\n";
	$body .= $admin_reply_text . "\n";
	$body .= "--__BOUNDARY__\n";

	// ファイルを添付
	if( !empty($clean['attachment_file']) ) {
		$body .= "Content-Type: application/octet-stream; name=\"{$clean['attachment_file']}\"\n";
		$body .= "Content-Disposition: attachment; filename=\"{$clean['attachment_file']}\"\n";
		$body .= "Content-Transfer-Encoding: base64\n";
		$body .= "\n";
		$body .= chunk_split(base64_encode(file_get_contents(FILE_DIR.$clean['attachment_file'])));
		$body .= "--__BOUNDARY__\n";
	}

	// 管理者へメール送信
	mb_send_mail( 'webmaster@gray-code.com', $admin_reply_subject, $body, $header);
}

---- 省略 ----

ここまでの変更を保存してフォームでお問い合わせを送信すると、以下のようにテキストメッセージに加え、ファイル添付のあるメールが届きます。

メーラーでの表示例
メーラーでの表示例

追加したコードを順に解説していきます。
まず、次の2行では使用する言語、文字コードを指定しています。

//日本語の使用宣言
mb_language("ja");
mb_internal_encoding("UTF-8");

ヘッダー部に追加した1行は、ファイルデータを扱うに当たって必要なコンテンツタイプの指定を行なっています。

$header = "MIME-Version: 1.0\n";
$header = "Content-Type: multipart/mixed;boundary=\"__BOUNDARY__\"\n";
$header .= "From: GRAYCODE <noreply@gray-code.com>\n";
$header .= "Reply-To: GRAYCODE <noreply@gray-code.com>\n";

multipart/mixed;boundary=\"__BOUNDARY__\"」という指定は、メッセージ本文のデータを「__BOUNDARY__」で区切って複数の形式のデータを扱うという内容です。

実際にそれを行なっているのが次の行です。

// テキストメッセージをセット
$body = "--__BOUNDARY__\n";
$body .= "Content-Type: text/plain; charset=\"ISO-2022-JP\"\n\n";
$body .= $auto_reply_text . "\n";
$body .= "--__BOUNDARY__\n";

// ファイルを添付
if( !empty($clean['attachment_file']) ) {
	$body .= "Content-Type: application/octet-stream; name=\"{$clean['attachment_file']}\"\n";
	$body .= "Content-Disposition: attachment; filename=\"{$clean['attachment_file']}\"\n";
	$body .= "Content-Transfer-Encoding: base64\n";
	$body .= "\n";
	$body .= chunk_split(base64_encode(file_get_contents(FILE_DIR.$clean['attachment_file'])));
	$body .= "--__BOUNDARY__\n";
}

今までと同じ方法で作成したテキストデータ「$auto_reply_text」と、添付したいファイルの2つを「__BOUNDARY__」で区切って1つのメッセージを生成します。

データの種類によって、それぞれにコンテンツタイプを指定している点にも注目してください。
テキストデータは「text/plain」と文字コードの「ISO-2022-JP」を、添付ファイルについては様々なファイル形式に対応した「application/octet-stream」を指定しています。
もし添付するファイル形式が限られていたら「image/jpeg」などと指定することも可能です。

添付ファイルについてはコンテンツタイプ以外にも「Content-Disposition」と「Content-Transfer-Encoding」を記述しています。

Content-Disposition

「Content-Disposition」はコンテンツの表示方法をします。
初期値は「inline」で、そのまま表示する指定となっています。

しかし今回はファイルの添付なので、「attachment」を指定し、「このデータはダウンロード形式にする」という指定です。

Content-Transfer-Encoding

「Content-Transfer-Encoding」はデータのエンコード形式を指定します。
ただのテキスト形式のデータであればこの指定は不要ですが、画像やPDFのような独自の形式をもつデータの場合は、メールで送信するための形式にエンコード(変換)しなければなりません。

ここで指定している「base64」というものは、メールのデータを送信する規格である「MIME(Multipurpose Internet Mail Extensions)」で使われているエンコード方式です。
一般的に使われているメールでは、通常のテキストを除き、基本的にこの「base64」という形式にエンコード・デコードして送受信を行います。

実際にこのbase64形式へエンコード処理をしているのが、次の1行です。

$body .= chunk_split(base64_encode(file_get_contents(FILE_DIR.$clean['attachment_file'])));

3つの関数が入れ子になっており少々見づらいですが、内側から順に確認していきます。

まず、file_get_contents関数でサーバーに保存されているファイルを取得し、続いてbase64_encode関数でbase64の形式へエンコードしています。
最後に、chunk_split関数でエンコードしたデータに改行を加えます。

最後の改行を加える処理は必要か疑問に思われるかもしれませんが、メールの送信形式に合わせた形にデータ形式を整えるための重要な処理です。

以上で送信する本文データの準備が整いました。
本文データが入った$bodymb_send_mail関数に渡して実行すれば添付ファイル付きのメール送信完了です。
以上と同じ処理を、管理者宛のメールにも反映しましょう。

// テキストメッセージをセット
$body = "--__BOUNDARY__\n";
$body .= "Content-Type: text/plain; charset=\"ISO-2022-JP\"\n\n";
$body .= $admin_reply_text . "\n";
$body .= "--__BOUNDARY__\n";

// ファイルを添付
if( !empty($clean['attachment_file']) ) {
	$body .= "Content-Type: application/octet-stream; name=\"{$clean['attachment_file']}\"\n";
	$body .= "Content-Disposition: attachment; filename=\"{$clean['attachment_file']}\"\n";
	$body .= "Content-Transfer-Encoding: base64\n";
	$body .= "\n";
	$body .= chunk_split(base64_encode(file_get_contents(FILE_DIR.$clean['attachment_file'])));
	$body .= "--__BOUNDARY__\n";
}

// 管理者へメール送信
mb_send_mail( 'webmaster@gray-code.com', $admin_reply_subject, $body, $header);

以上で添付ファイル付きのメールを送信する機能が実装できました。
次回は、セッションを使ったフォームの2重送信を防ぐ機能を実装します。

今回作成したコードはこちら:vol.9のサンプルコード – GitHub

こちらの記事は役に立ちましたか?

ありがとうございます。
もしよろしければ、あわせてフィードバックや要望などをご入力ください。

コメントありがとうございます!
運営の参考にさせていただきます。