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. "です。";

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

複数選択ファイルを保存する

<?php
	  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;, "upload/img/".$_FILES&#91;"files"&#93;&#91;"name"&#93;&#91;$i&#93;)) {
          $message .= $_FILES&#91;"files"&#93;&#91;"name"&#93;&#91;$i&#93; . "を送信しました。<br>";
          $message .= "fileのパスは upload/img/".$_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;
  }

?>
<style>
.thumb {
  height: 100px;
  width: 100px;
  border: 1px solid #000;
  margin: 10px 5px 0 0;
}
h1 {
  margin:0px;
}
#caution {
  color:gray;
  font-size:small;
}
</style>
<h1>添付ファイルを送信</h1>
<div id="caution">
※送信できるファイルの拡張子は"gif","jpg","jpeg","png"の何れかです。<br>
※ファイル送信は最大2つまでです。3つ以上選択しても、3つ目以降は送れません。また、二つのファイルを送信する場合は、キーボードの"ctl"ボタンなどで二つ選択した状態で開いてください。</div><br>
<form action="#" method="post" enctype="multipart/form-data">
<input type="file" id="files" name="files&#91;&#93;" multiple />
<input type="submit" value="送信">
</form>
<?php echo $message; ?>
<output id="list"></output>
<script>
  function handleFileSelect(evt){
    var files = evt.target.files;
    if(files.length > 2){
      files = files.slice(0, 2);
    }    

    for (var i = 0, f; f = files[i]; i++) {
    // for (var i = 0, f; f = files[i]; i++) {

      if (!f.type.match('image.*')) {
            continue;
          }

      var reader = new FileReader();

      reader.onload = (function(theFile){
        return function(e){
              var span = document.createElement('span');
              span.innerHTML = ['<img class="thumb" src="', e.target.result,
                                '" title="', escape(theFile.name), '"/>'].join('');
              document.getElementById('list').insertBefore(span, null);
            };
          })(f);

      reader.readAsDataURL(f);
    }

    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
    // for (var i = 0, f; f = files[i]; i++) {

      output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
                  f.size, ' bytes, last modified: ',
                  f.lastModifiedDate.toLocaleDateString(), '</li>');
    }
    document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>

同じファイル名を送信すると、ファイルが上書きされてしまうので、保存するディレクトリを送信ごとにユニークにする必要がありますね。

選択ファイルのjavascript側の表示数をsliceで制御

適当に数時間試していたら上手くいきました。
変数のlengthをcountして条件分岐で欲しい数だけsliceしてます。

<script>
  function handleFileSelect(evt){
    var files = evt.target.files;
    if(files.length > 2){
      files = files.slice(0, 2);
    }    

    for (var i = 0, f; f = files[i]; i++) {
    // for (var i = 0, f; f = files[i]; i++) {

      if (!f.type.match('image.*')) {
            continue;
          }

      var reader = new FileReader();

      reader.onload = (function(theFile){
        return function(e){
              var span = document.createElement('span');
              span.innerHTML = ['<img class="thumb" src="', e.target.result,
                                '" title="', escape(theFile.name), '"/>'].join('');
              document.getElementById('list').insertBefore(span, null);
            };
          })(f);

      reader.readAsDataURL(f);
    }

    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
    // for (var i = 0, f; f = files[i]; i++) {

      output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
                  f.size, ' bytes, last modified: ',
                  f.lastModifiedDate.toLocaleDateString(), '</li>');
    }
    document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>

OK! Nice!

さて、問題は、送信ファイルをどうやって保存するかですね。
gmailやhotmailなどは、ファイル名は変わらずに送られてくるので、拡張子にバリデーションをかけて、ファイル名はそのままにしたいと思います。

php側のファイルのアップロードの数に制限をかける

for文の繰り返し処理をand $i < 2とすることで、3つ以上のファイルがpostされても、処理されるのは2つに制限できる。

	  for ($i = 0; $i < count($_FILES['files']['name']) and $i < 2; $i++) {
    $file_ext = pathinfo($_FILES["files"]["name"][$i], PATHINFO_EXTENSION);
    if (FileExtensionGetAllowUpload($file_ext) &&  is_uploaded_file($_FILES["files"]["tmp_name"][$i])) {
      if(move_uploaded_file($_FILES["files"]["tmp_name"][$i], "upload/img/".$_FILES["files"]["name"][$i])) {
          echo $_FILES["files"]["name"][$i] . "をアップロードしました。
“; } else { echo “ファイルをアップロードできません。
“; } } else { echo “ファイルが選択されていません。
“; } }

問題はjavascript側なんだが、
var i = 0, f; f = files[i], i < 2; i++ と書いても、制御ができない。。。 しかも、画像とテキストで二つのfor文を回しているのだが、 二つ目のfor文が上手く動かない。困った。 [code] function handleFileSelect(evt){ var files = evt.target.files; for (var i = 0, f; f = files[i], i < 2; i++) { // for (var i = 0, f; f = files[i]; i++) { if (!f.type.match('image.*')) { continue; } var reader = new FileReader(); reader.onload = (function(theFile){ return function(e){ var span = document.createElement('span'); span.innerHTML = ['‘].join(”);
document.getElementById(‘list’).insertBefore(span, null);
};
})(f);

reader.readAsDataURL(f);
}

var output = [];
for (var i = 0, f; f = files[i]; i++) {
// for (var i = 0, f; f = files[i]; i++) {
output.push(‘

  • ‘, escape(f.name), ‘(‘, f.type || ‘n/a’, ‘) -‘,
    f1.size, ‘ bytes, last modified: ‘,
    f1.lastModifiedDate.toLocaleDateString(), ‘
  • ‘);
    }
    document.getElementById(‘list’).innerHTML = ‘

      ‘ + output.join(”) + ‘

    ‘;
    }
    [/code]

    ファイルアップロードの進捗(%)をjavascriptで表示

    コードでは一番下に来ていますが、addEventListenerで、getElementById(‘files’).addEventListener(‘change’, handleFileSelect, false)として、handleFileSelectの関数を実行します。
    handleFileSelectでは、new FileReader();とした後、errorHandlerとupdateProgressを実行します。
    %は、Math.round((evt.loaded / evt.total) * 100);

    <style>
    #progress_bar {
    	margin: 10px 0;
    	padding: 3px;
    	border: 1px solid #000;
    	font-size: 14px;
    	clear: both;
    	opacity: 0;
    	-moz-transition: opacity ls linear;
    	-o-transition: opacity ls linear;
    	-webkit-transition: opacity ls linear;
    }
    #progress_bar.loading {
    	opacity: 1.0;
    }
    #progress_bar .percent {
    	background-color: #99ccff;
    	height: auto;
    	width: 0;
    }
    </style>
    
    <input type="file" id="files" name="file" />
    <button onclick="abortRead();">Cancel read</button>
    <div id="progress_bar"><div class="percent">0%</div></div>
    
    <script>
    	var reader;
    	var progress = document.querySelector('.percent');
    
    	function abortRead(){
    		reader.abort();
    	}
    
    	function errorHandler(evt){
    		switch(evt.target.error.code){
    			case evt.target.error.NOT_FOUND_ERR:
    				alert('File Not Found!');
    				break;
    			case evt.target.error.NOT_READABLE_ERR:
    				alert('File is not readable');
    				break;
    			case evt.target.error.ABORT_ERR:
    				break;
    			default:
    				alert('An error occurred reading this file.');
    		};
    	}
    
    	function updateProgress(evt) {
        if (evt.lengthComputable) {
          var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
          if (percentLoaded < 100) {
            progress.style.width = percentLoaded + '%';
            progress.textContent = percentLoaded + '%';
          }
        }
      }
    
    
    		function handleFileSelect(evt) {
    	    progress.style.width = '0%';
    	    progress.textContent = '0%';
    
    	    reader = new FileReader();
    	    reader.onerror = errorHandler;
    	    reader.onprogress = updateProgress;
    	    reader.onabort = function(e) {
    	      alert('File read cancelled');
    	    };
    	    reader.onloadstart = function(e) {
    	      document.getElementById('progress_bar').className = 'loading';
    	    };
    	    reader.onload = function(e) {
    	      progress.style.width = '100%';
    	      progress.textContent = '100%';
    	      setTimeout("document.getElementById('progress_bar').className='';", 2000);
    	    }
    
    		reader.readAsBinaryString(evt.target.files&#91;0&#93;);
    	}
    	document.getElementById('files').addEventListener('change', handleFileSelect, false);
    </script>
    

    容量が小さいと、直ぐに100%となるので、最近downloadして重かったJavaの”spring-tool-suite-3.9.2.RELEASE-e4.7.2-win32-x86_64.zip”で試してみます。

    いや、参りました。って感じですかね。参ってばっかりですが。。