Gmail、hotmail、Yahoo!添付ファイル受信時の表示とURLの設計

gmail
-> 写真が表示されます。

hotmail
-> 写真を表示

yahoomail
-> 写真表示

ぬぬぬ、なるほど、基本は表示ですね。

ダウンロード時のURI
gmail:https://mail.google.com/mail/u/0/?ui=2&ik=10桁の英数字&view=att&th=16桁の英数字&attid=0.1&disp=safe&realattid=f_9桁の英数字&zw
hotmail:https://attachment.outlook.live.net/owa/hoge@hotmail.com/service.svc/s/GetAttachmentThumbnail?id=AQMkADAwATE2MjYxLTU3MmEtMGU4ZC0wMAItMDAKAEYAAAPamN5TZvIjQZibMQuFo… 以下略
yahoo: https://jp.mg5.mail.yahoo.co.jp/neo/launch?.rand=13桁の英数字#

なんじゃこりゃ?URIだけ見ると、yahooは比較的シンプルに見える。
hotmailは、subdomainがattachmentに変わって、id, x-owa-canary(意味不明?), tokenなどのパラメーターが色々ついています。※owaはoutlook web accessの略ですね。
これ、どういう設計になってるんでしょう???
もう、誰だよ、これつくってるの。

mysqlからデータを取り出して、form・textareaに挿入する

複数行のデータは、explode(“\n”, $hoge);で、1行ずつ配列に変換
inputはvalueに変数を代入、textareaはタグ内に挿入
textareaの改行は”&#13″を使う。

<?php
	$dsn = "mysql:dbname=mail;host=localhost";
	$user = "hoge";
	$password = "hogehoge";
	$id = 5;
	try {
	    $dbh = new PDO($dsn, $user, $password);
	} catch (PDOException $e){
	    print('connection failed:'.$e->getMessage());
	}
		$sql = "select * from sends where id = $id";
	$stmt = $dbh->query($sql);

	$result = $stmt->fetch(PDO::FETCH_ASSOC);
	$to = $result['username'];
	$subject = $result['subject'];
	$body = $result['body'];
	$body = explode("\n", $body);
	$sendtime = $result['sendtime'];
?>
<span id="fs-s">※必須</span><br>
<input type="text" name="to" size="90%" value="<?php echo $to ?>" required><br>
件名<br>
<input type="text" name="subject" value="><?php echo $subject; ?>" size="90%"><br>
本文
<span id="fs-s">※必須</span><br>
<textarea name="body" rows="12" cols="100%" required>
&#13;&#13;<?php
			echo ">".$sendtime ."&#13;"; 
		foreach($body as $value){
			echo ">" .$value;
		}
	?>
</textarea>
</p>
<input type="file" id="files" name="files&#91;&#93;" multiple />
<div id="caution">
※送信できるファイルの拡張子は"gif","jpg","jpeg","png"の何れかです。<br>
※ファイル送信は最大2つまでです。3つ以上選択しても、3つ目以降は送れません。また、二つのファイルを送信する場合は、キーボードの"ctl"ボタンなどで二つ選択した状態で開いてください。</div>
<output id="list"></output>
<p>
<input type="submit" value="送信">
</form>

返信っぽい表示になっていますね。

では、代入していきます。

メール詳細

返信押下

返信

送信済メール

割と簡単でしたね。

値がNULLのselect文

“columname is NULL”で選択できます。

select * from sends where destination = '".$username."' and deleted is NULL and junk is NULL order by sendtime desc

受信トレイ

メール本文

「削除」もしくは「ジャンク」がクリックされた場合は、pdoのupdateでテーブル側のステータスを変更します。

<div id="menu"> <a href="?path=todelete&inbox=<?php echo $id; ?>">削除</a> | <a href="?path=tojunk&inbox=<?php echo $id; ?>">ジャンク</a></div>

変更された対象のテーブルを読み込む。

$sql = "update sends set junk = :junk where id = ".$id.""

基本的なところは大分出来てきましたね♪

あと大きなところとして、1.メールの返信機能、2.添付ファイルの表示
余力があれば、3.Post後にPHP側で宛先の有り無しをチェックして、表示の出し分け

メールの返信はどうすればいいんでしょう?
機能としては、新規作成メールのformに、対象のレコードを呼び出して、fromをtoにセットして、返信するメールのsendtime, subject, bodyを新規メールのbodyの下部に返信とわかるように追加、というところでしょうか。
結構ややこしいですね。

phpでメールボックスをつくろう7 送信したメールを表示

getパラメーターでメールのidを取得して、テーブルから呼び出します。

<?php elseif($_GET&#91;"path"&#93; == 'mailrp'): ?>
			<?php
			$id = empty($_GET&#91;"inbox"&#93;)? 'null' : $_GET&#91;"inbox"&#93;;

			$dsn = "mysql:dbname=mail;host=localhost";
			$user = "hoge";
			$password = "hogehoge";
			try {
			    $dbh = new PDO($dsn, $user, $password);
			} catch (PDOException $e){
			    print('connection failed:'.$e->getMessage());
			}
			$sql3 = "select * from sends where id = '".$id."'";
			$stmt3 = $dbh->query($sql3);

			$result3 = $stmt3->fetch(PDO::FETCH_ASSOC);
			$send_des = $result3['destination'];
			$send_sub = $result3['subject'];
			$send_body = $result3['body'];
			$sendtime = $result3['sendtime'];

			echo "<h3>".$send_sub."</h3>";
			echo "To: ".$send_des. "<br>";
			echo $sendtime. "<hr>";
			echo $send_body. "<br>";
			?>
   <?php endif; ?>

1.nakayamaさんにメールを書く

2.送信する

3.送信一覧

4.メール詳細を表示

送信一覧は、order byでソート順逆ですね。

$sql2 = "select * from sends where username = '".$username."' order by sendtime desc";

新着順にしました。

添付ファイルの表示設計は面倒なので後にして、受信ボックスを先に作りたいと思います。

受信ボックス

受信メール

phpでメールボックスをつくろう6 送信メールの宛先・タイトルを表示

テーブルからデータを引っ張てきます。

<?php elseif($_GET&#91;"path"&#93; == 'sentitems'): ?>
   			<h2>Sent Items</h2>
   			<?php 
   			$dsn = "mysql:dbname=mail;host=localhost";
			$user = "hoge";
			$password = "hogehoge";
			$username = $_SESSION&#91;"username"&#93;;
			try {
			    $dbh2 = new PDO($dsn, $user, $password);
			} catch (PDOException $e){
			    print('connection failed:'.$e->getMessage());
			}
   			$sql2 = "select * from sends where username = '".$username."'";
			$stmt2 = $dbh2->query($sql2);

			while($result = $stmt2->fetch(PDO::FETCH_ASSOC)){
				$id[] = $result['id'];
				$destination[] = $result['destination'];
				$subject[] = $result['subject'];
				$sendtime[] = $result['sendtime'];
			}
			$i= 0;
			echo "<table>";
			foreach($destination as $value){
				echo "<tr><td> <img src=\"icon.png\"> <a href=\"\">".$value ."</a></td><td><a href=\"\">". $subject[$i]."</a> </td><td>" .$sendtime[$i]. " </td></tr>";
				$i++;
			}
			echo "</table>";
			?>
   <?php endif; ?>

アイコンをつけてそれっぽくします。

idで、メール詳細に移動するようにします。

あああ、なるほど、gmailはメール詳細に飛ぶ際に、乱数字16桁のid使ってますね。
なるほどな~!

ALTER TABLEでデータベースのカラムを成形

alter tableでメール送信、受信用テーブルのカラム追加、削除を行っていきます。

ALTER TABLE sends ADD alreadyread int afetr junk;

mysql> desc sends;
+————-+——————+——+—–+———+—————-+
| Field | Type | Null | Key | Default | Extra |
+————-+——————+——+—–+———+—————-+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| username | varchar(41) | YES | | NULL | |
| destination | varchar(41) | YES | | NULL | |
| subject | varchar(255) | YES | | NULL | |
| body | varchar(255) | YES | | NULL | |
| file1 | varchar(255) | YES | | NULL | |
| file2 | varchar(255) | YES | | NULL | |
| alreadyread | int(11) | YES | | NULL | |
| junk | int(11) | YES | | NULL | |
| deleted | int(11) | YES | | NULL | |
| sendtime | datetime | YES | | NULL | |
+————-+——————+——+—–+———+—————-+
11 rows in set (0.07 sec)

メールボックスをつくろう5 複数添付ファイルの保存パスをDBに格納

php側
画像保存後は、unlinkで一時フォルダの画像を削除します。

session_start();

if(!empty($_FILES['files']['name'])){
      $rand = mt_rand(1,9);
      $date = date("ymdHis");
      $path = "upload/img/".$date.$rand;
      mkdir($path, 0777);
    }

    for ($i=0; $i<count($_FILES&#91;'files'&#93;&#91;'name'&#93;) and $i < 2; $i++) {
    $file_ext = pathinfo($_FILES&#91;"files"&#93;&#91;"name"&#93;&#91;$i&#93;, PATHINFO_EXTENSION);
    if (FileExtensionGetAllowUpload($file_ext) &&  is_uploaded_file($_FILES&#91;"files"&#93;&#91;"tmp_name"&#93;&#91;$i&#93;)) {
      if(move_uploaded_file($_FILES&#91;"files"&#93;&#91;"tmp_name"&#93;&#91;$i&#93;, $path."/".$_FILES&#91;"files"&#93;&#91;"name"&#93;&#91;$i&#93;)) {
          $message .= $_FILES&#91;"files"&#93;&#91;"name"&#93;&#91;$i&#93; . "を送信しました。<br>";
          if($i == 0){
            $file1 = $path."/".$_FILES["files"]["name"][$i];
            $message .= "file1のパスは ".$file1." です。<br>";
          } else {
            $file2 = $path."/".$_FILES["files"]["name"][$i];
            $message .= "file2のパスは ".$file2." です。<br>";
          }
      } else {
        $message = "ファイルをアップロードできません。<br>";
      }
    } else {
      $message = "ファイルが選択されていません。<br>";
    }
  }
  function FileExtensionGetAllowUpload($ext){
    $allow_ext = array("gif","jpg","jpeg","png");
    foreach($allow_ext as $v){
      if ($v === $ext){
        return 1;
      }
    }
    return 0;
  }
unlink($_FILES['files']['name']);

if(isset($_POST["to"])){
	$username = $_SESSION["username"];
	$destination = htmlspecialchars($_POST["to"]);
	$subject = htmlspecialchars($_POST["subject"]);
	$body = htmlspecialchars($_POST["body"]);
	$date =	date("Y-m-d H:i");

	$dsn = "mysql:dbname=mail;host=localhost";
	$user = "hoge";
	$password = "hogehogehoge";
	 
	try {
	    $dbh = new PDO($dsn, $user, $password);
	} catch (PDOException $e){
	    print('connection failed:'.$e->getMessage());
	}

	$stmt = $dbh -> prepare("INSERT INTO sends (username, destination, subject, body, file1, file2, sendtime) VALUES(:username, :destination, :subject, :body, :file1, :file2, :sendtime)");
    $stmt->bindParam(':username', $username, PDO::PARAM_STR);
    $stmt->bindParam(':destination', $destination, PDO::PARAM_STR);
    $stmt->bindParam(':subject', $subject, PDO::PARAM_STR);
    $stmt->bindParam(':body', $body, PDO::PARAM_STR);
    $stmt->bindParam(':file1', $file1, PDO::PARAM_STR);
    $stmt->bindParam(':file2', $file2, PDO::PARAM_STR);
    $stmt->bindParam(':sendtime', $date, PDO::PARAM_STR);
    $stmt->execute();
}

ブラウザ(画像添付時)

画像フォルダ

mysql sendsテーブル
おおお、入ってる! いいね♪

新規送信機能はほぼ出来たので、次はテーブル情報の呼び出しですね。
二重にDBに登録する理由はないので、メール受信者もsendsテーブルの呼び出しでつくってみたいと思います。

パラメータがsentitemsの時に表示

メールボックスをつくろう4 複数添付ファイルの機能を実装する

html側

<div class="flex-2">
   <?php if($_GET&#91;"compose"&#93; == 'new'): ?>
		<form action="?compose=done" method="post" enctype="multipart/form-data">
			宛先
			<span id="fs-s">※必須</span><br>
			<input type="text" name="to" size="90%" required><br>
			件名<br>
			<input type="text" name="subject" size="90%"><br>
			本文
			<span id="fs-s">※必須</span><br>
			<textarea name="body" rows="12" cols="100%" required></textarea>
			</p>
			<input type="file" id="files" name="files&#91;&#93;" multiple />
			<div id="caution">
			※送信できるファイルの拡張子は"gif","jpg","jpeg","png"の何れかです。<br>
			※ファイル送信は最大2つまでです。3つ以上選択しても、3つ目以降は送れません。また、二つのファイルを送信する場合は、キーボードの"ctl"ボタンなどで二つ選択した状態で開いてください。</div>
			<output id="list"></output>
			<p>
			<input type="submit" value="送信">
			</form>
   <?php elseif($_GET&#91;"compose"&#93; == 'done'): ?>
   			<p>メール送信が完了しました</p>
   <?php endif; ?>
</div>

ここまではOK

$_FILEがpostされたらフォルダを作って格納する

    if(!empty($_FILES['files']['name'])){
      $rand = mt_rand(1,9);
      $date = date("ymdHis");
      $path = "upload/img/".$date.$rand;
      mkdir($path, 0777);
    }

	  for ($i=0; $i<count($_FILES&#91;'files'&#93;&#91;'name'&#93;) and $i < 2; $i++) {
    $file_ext = pathinfo($_FILES&#91;"files"&#93;&#91;"name"&#93;&#91;$i&#93;, PATHINFO_EXTENSION);
    if (FileExtensionGetAllowUpload($file_ext) &&  is_uploaded_file($_FILES&#91;"files"&#93;&#91;"tmp_name"&#93;&#91;$i&#93;)) {
      if(move_uploaded_file($_FILES&#91;"files"&#93;&#91;"tmp_name"&#93;&#91;$i&#93;, $path."/".$_FILES&#91;"files"&#93;&#91;"name"&#93;&#91;$i&#93;)) {
          $message .= $_FILES&#91;"files"&#93;&#91;"name"&#93;&#91;$i&#93; . "を送信しました。<br>";
          $message .= "fileのパスは ".$path."/".$_FILES["files"]["name"][$i]." です。<br>";
      } else {
        $message = "ファイルをアップロードできません。<br>";
      }
    } else {
      $message = "ファイルが選択されていません。<br>";
    }
  }
  function FileExtensionGetAllowUpload($ext){
    $allow_ext = array("gif","jpg","jpeg","png");
    foreach($allow_ext as $v){
      if ($v === $ext){
        return 1;
      }
    }
    return 0;
  }

画像選択状態

送信後のブラウザ

送信後のディレクトリ

o oh, very nice!
file1、file2のパスも以下の様に取得できますね。

if($i == 0){
            $file1 = $path."/".$_FILES["files"]["name"][$i];
            $message .= "file1のパスは ".$file1." です。<br>";
          } else {
            $file2 = $path."/".$_FILES["files"]["name"][$i];
            $message .= "file2のパスは ".$file2." です。<br>";
          }

date(“ymdHis”);のフォルダをつくる

date(“ymdHis”)だけだと怖いので、mt_rand(1,9)も追加します。

$rand = mt_rand(1,9);
$date = date("ymdHis");
$path = "upload/img/".$date.$rand;
mkdir($path, 0777);
echo "finish!<br>";
echo "passは" .$path. "です。";

はい、ガンガンいきましょう。