PHP For Beginnersチュートリアル　その7　基本的なコンタクトフォームの実装

##このシリーズの目的

体系的なwebコーディングの訓練ができるようになるために、PHPの初学のきっかけかつ、PHPでログインフォームやフォームを実装することができるようになるために

[PHP For Beginners](https://www.youtube.com/playlist?list=PLgt-G5tEOlKX4LKrBCYfjcyrp7wmnRdAL)

上記のチュートリアルを進めているのでその備忘録。

[前回](https://qiita.com/shitikakei/items/51df3898292acf5b1fbe)

##内容

**今回のチュートリアル**

[PHP Tutorial: Create Contact Form & Send an Email With Attachment Using PHPMailer](https://youtu.be/Mw_ORXPoogY?list=PLgt-G5tEOlKX4LKrBCYfjcyrp7wmnRdAL)

**このチュートリアルでやること**

・簡単なコンタクトフォームの作り方を覚える
・フォームに書かれた内容と添付ファイルをPHPを使ってEメールで送信する

**成果物**

```php:index.php
<?php

		$msg = "";

	use PHPMailer\PHPMailer\PHPMailer;
    use PHPMailer\PHPMailer\Exception;
	
	
	
	if (isset($_POST['submit'])) {

	mb_language("japanese");
	mb_internal_encoding("UTF-8");
    require 'vendor/autoload.php';
    require 'Mairtrap-config.php';

    // メール送信を行うための関数
    function sendemail($to,$from,$fromName,$body,$attachment) {

    	$mail = new PHPMailer();

    	// Server

    	$mail->SMTPDebug = 0; //本番では0とかにする。
        $mail->isSMTP();
        $mail->SMTPAuth = true;
        $mail->Host = MAIL_HOST;
        $mail->Username = MAIL_USERNAME;
        $mail->Password = MAIL_PASSWORD;
        $mail->SMTPSecure = MAIL_ENCRPT;
        $mail->Port = SMTP_PORT;

        // Recipients
    	$mail->setFrom($from,$fromName);
    	$mail->addAddress($to);
    	$mail->addAttachment($attachment);

    	// Content
    	
    	$mail->FromName = mb_encode_mimeheader("$fromName", "ISO-2022-JP", "UTF-8");
    	$mail->Subject = mb_encode_mimeheader("Contact Form test", "ISO-2022-JP", "UTF-8");
    	$mail->Body = mb_convert_encoding("$body","JIS","UTF-8");
    	$mail->CharSet = 'ISO-2022-JP';
    	$mail->Encoding = "7bit";

    	// Select HTML or NOT
    
    	$mail->isHTML(false);

    	return $mail->send();
    }
    
    //ここまで


    $name= $_POST['username'];
    $email= $_POST['email'];
    $body = $_POST['body'];

    $file = "attachment/". basename($_FILES['attachment']['name']);

    //デバック用のコード、本番時はオフ
    // echo "<pre>";
    // print_r($_FILES);
    
    if (move_uploaded_file($_FILES['attachment']['tmp_name'],$file)) {
    	if(sendemail("test@to.example.com",$email,$name,$body,$file))
    		$msg = "Email sent";

    	else

    		$msg = "Error";
    } else
    	$msg = "Please check your attachment!";
	}

 ?>


<!DOCTYPE html>
<html>
<head>
	<title>PHP contactform tutorial</title>
	<link rel="stylesheet" href="css/sample1.css">
</head>
<body>
<div class="form">
	<img src="img/icon.png" alt="アイコン">
<form action="index.php" method="post" enctype="multipart/form-data">
	<input type="text" name="username" placeholder="Name" required><br>
	<input type="text" name="email" placeholder="Email" required><br>
	<textarea name="body" placeholder="what`s up?" required></textarea><br>
	<input type="file" name="attachment" required><br>
	<input type="submit" name="submit" value="Send Email"><br>
</form>
</div>
<br><br>
<?php 	echo $msg; ?>
</body>
</html>

```

```css:sample1.css

input,textarea {
	width:250px;
	height:27px;
	margin-bottom:10px;
}

textarea {
	height: 100px;
	resize:vertical;

}

body {
	text-align: center;
	margin-top: 150px;
}

img{
	height: 100px;
	width:200px;
}


```

## 添付ファイルを送れるようなフォームを作る手順

1.formタグにおいてmethod属性をPOSTにする

2.enctype属性を追加し内容をmutipart/form-dataにする。

3.type属性がfileのinputタグを書く

2,3が肝。

## 今回のコードの注釈


```php:$_FILESについて

$file = "attachment/". basename($_FILES['attachment']['name']);


/*$_FILESはHTTPのPOSTメソッドでアップロードされたファイルの値を取得するファイルアップロード変数。平たく言うと、クライアントからサーバーへファイルをアップロードするために必要な変数であり、送信されてきたデータのうち、type属性がfileであるinputタグの部分のデータが連想配列でこの変数に格納されることになる。
格納されるデータは以下の通りであり、必ず最初にinputタグで指定したname属性の値を引数に設定していることがわかる。

$_FILES['inputで指定したname']['name']	ファイル名
$_FILES['inputで指定したname']['type']	ファイルのMIMEタイプ
$_FILES['inputで指定したname']['tmp_name']	サーバー上で一時的に保存されるテンポラリファイル名
$_FILES['inputで指定したname']['error']	アップロード時のエラーコード
$_FILES['inputで指定したname']['size']	ファイルサイズ（バイト単位）

よって今回の場合、<input type="file" name="attachment" required>と指定しているので、例えばbg.jpgというファイルをアップロードすると各データとキーと値は以下のようになる。

Array
(
    [attachment] => Array
        (
            [name] => bg.png
            [type] => image/png
            [tmp_name] => C:\xampp\tmp\phpEE16.tmp
            [error] => 0
            [size] => 20918
        )

)

また、basenameはファイルあるいはディレクトリへのパスを含む文字列を受け取って、最後にある名前の部分を返す関数で要はファイル名やディレクト名を取得するための関数である。
つまり、$file = "attachment/". basename($_FILES['attachment']['name']);というのはattachmentフォルダにある$_FILESでアップロードされてきたファイルの名前ということになり、次で触れるmove_upload_file関数を使うために必要なパスを書いていると思えばいい。*/
?>
```

```php:move_upload_fileについて

if (move_uploaded_file($_FILES['attachment']['tmp_name'],$file)) {
        if(sendemail("test@to.example.com",$email,$name,$body,$file))
            $msg = "Email sent";

        else

            $msg = "Error";
    } else
        $msg = "Please check your attachment!";
    }

/*move_upload_fileはクライアントからのリクエストでアップロードされたファイルの保存場所を変更する際に使用する関数である。
そもそもファイルアップロードの仕組みから説明すると、アップロードされたファイルは任意の一時フォルダに保存される。先に出したキーと値でいうと

 [tmp_name] => C:\xampp\tmp\phpEE16.tmp

この部分を見ればいい、tmpというフォルダに仮に保存されているのがわかる。
仮に保存されているということは、一定時間で消えるということなのでそうならないために。これを別の専用のフォルダに移すための関数がmove_upload_file関数ということである。

内容は簡単、第1引数に移動前のパス、第2引数に移動後のパスを指定してやればいい。
今回の場合は$_FILESにおいてサーバーに一時的に保存されるファイル名の引数の設定の仕方は上に書いてあるように、$_FILES['inputで指定したname']['tmp_name']であるからそれを第1引数に設定し、第2引数には先程設定した$fileを指定する。
つまり、先程の$fileはアップロードされたファイルの保存場所を指定したということが逆説的にわかる。
あとは簡単な話で、functionでメール送信の為の一連の処理はまとめてあるので、関数作成の際に設定した引数を入れてif文で条件分岐してエラーメッセージ等を適宜出すようにすればいい。
ちなみに今回指定した引数は左から順に
送り先のアドレス、inputタグのname属性がemail箇所から送信されてきた値(フォームに入力されたメールアドレス、通常の場合は補足の項目にあるように送り主のアドレス）、inputタグのname属性がusernameの箇所から送信されてきた値（フォームに入力された名前、通常の場合は送り主の名前)、メール本文、添付ファイル（ない場合は書かなくていい）となっている。

*/


```

## 補足　

1.複数のメールアドレスにメールを送信するためには？


成果物の下記の部分においてsendemailで別のアドレスと引数を指定してやればいい。


```php:

if (move_uploaded_file($_FILES['attachment']['tmp_name'],$file)) {
        if(sendemail("test@to.example.com",$email,$name,$body,$file))
            $msg = "Email sent";
//中略

//これを例えば以下のようにする

if (move_uploaded_file($_FILES['attachment']['tmp_name'],$file)) {
        if(sendemail("test@to.example.com",$email,$name,$body,$file))
            $msg = "Email sent";
        sendemail("test@example.com","post@mail.com","website","hey!");

//中略

```

こうすると、"test@to.example.com"と"test@example.com"へ送られるメールの内容を変えつつ同時に送信することができる。
今回のようなメールフォームには必要ないが覚えておこう。

2.日本語の部分が文字化けする（件名、送信者名、本文等）

成果物のように以下のコードを必ず記載する。
チュートリアルは英語の教材でかつ、英語圏の人たちを対象に想定して作られているので特に言及されていないが、チュートリアルのまま日本語を本文等に使うと必ず文字化けするので忘れないこと。

```php:設定するコード

mb_language("japanese");
mb_internal_encoding("UTF-8");
$mail->FromName = mb_encode_mimeheader("$fromName", "ISO-2022-JP", "UTF-8");
$mail->Subject = mb_encode_mimeheader("Contact Form test", "ISO-2022-JP", "UTF-8");
    	
$mail->Body = mb_convert_encoding("$body","JIS","UTF-8");    	
$mail->CharSet = 'ISO-2022-JP';
$mail->Encoding = "7bit";

```


## 参考

[PHPでmove_uploaded_file関数を使う方法【初心者向け】](https://techacademy.jp/magazine/18804)
[PHPでファイル名や拡張子,ディレクトリ名を取得する方法]
(https://www.flatflag.nir87.com/basename-844#i)
[PHP $_FILES(ファイル変数)のすべて！【初心者向け基本】](https://wepicks.net/phpref-files/)
[PHPで日本語メールを送信する]
(https://qiita.com/kidatti/items/16b9fa22399d6db7bcff)