ファイルをアップロード

ファイルのmax sizeを指定します。

<form method="post" action="#" enctype="multipart/form-data">
		ファイル:<input type="file" name="up_file"><br>
		<input type="submit" value="upload">
		<input type="hidden" name="MAX_FILE_SIZE" value="4194304" />
</form>

fileが一時保存の領域に保存されているか確認

<?php
	if(is_uploaded_file($_FILES&#91;'up_file'&#93;&#91;'tmp_name'&#93;)){
		if(move_uploaded_file($_FILES&#91;'up_file'&#93;&#91;'tmp_name'&#93;,"./".$_FILES&#91;'up_file'&#93;&#91;'name'&#93;)){
			echo "uploaded";
		} else {
			echo "error while saving.";
		}
	} else {
		echo "file not uploaded.";
	}

?>
<form method="post" action="#" enctype="multipart/form-data">
		ファイル:<input type="file" name="up_file"><br>
		<input type="submit" value="upload">
		<input type="hidden" name="MAX_FILE_SIZE" value="4194304" />
</form>

保存場所を/upload/img/test.gif と指定します。

if(is_uploaded_file($_FILES['up_file']['tmp_name'])){
		if(move_uploaded_file($_FILES['up_file']['tmp_name'],"./upload/img/test.gif")){
			echo "uploaded";
		} else {
			echo "error while saving.";
		}
	} else {
		echo "file not uploaded.";
	}

保存されています。

phpでメールボックスをつくろう3 DBと接続

メール送信後のテーブルを作成します。file送信の機能は後から追加の予定。

create table mail.sends(
	id int unsigned auto_increment primary key,
	username varchar(41),
	destination varchar(41),
	subject varchar(255),
	body varchar(255),
	file1 varchar(255),
	file2 varchar(255),
	sendtime datetime default null
);

DBへの接続 ”to”がpostされたら、DBに入れます。

session_start();
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 = "hogehoge";
	 
	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, sendtime) VALUES(:username, :destination, :subject, :body, :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(':sendtime', $date, PDO::PARAM_STR);
    $stmt->execute();
}

メールを新規作成します。

ブラウザ上の挙動

mysql側
select * from sends

mysql> select * from sends;
+----+----------+-------------+----------------------------------------------------------+--------------------------------------------------------------------------------------------+-------+-------+---------------------+
| id | username | destination | subject                                                  | body                                                                                       | file1 | file2 | sendtime            |
+----+----------+-------------+----------------------------------------------------------+--------------------------------------------------------------------------------------------+-------+-------+---------------------+
|  1 | sample   | tanaka      | 2,000円分の割引クーポンが発行されました                  | 対象ショップ
-31 Sons de mode
-CANAL JEAN
-ORiental TRaffic
-GRACE CONTINENTAL
       | NULL  | NULL  | 2018-03-26 10:23:00 |
+----+----------+-------------+----------------------------------------------------------+--------------------------------------------------------------------------------------------+-------+-------+---------------------+
1 row in set (0.00 sec)

入ってますね。
時間は $date = date(“Y-m-d h:i”); ではなく、$date = date(“Y-m-d H:i”); ですね。

次は、
1.添付ファイルを送りたい。
2.メールの宛先がusernamesの中になければ、宛先なしで送信エラーとしたい。
3.send itemをクリックすると、sendテーブルから送信メールを呼び出したい。

あれ、まてよ、
受け取るtestは、receiveテーブルから読み込む想定なので、receiveテーブルにもinsertしないといけない?

phpでメールボックスをつくろう2 新規作成

<div class="flex-2">
   <?php if($_GET&#91;"compose"&#93; == 'new'): ?>
		<form action="" method="post">
			宛先:<br>
			<span id="fs-s">※送り先のユーザ名を入力してください</span>
			<input type="text" name="to" size="90%"><br>
			件名:<br>
			<input type="text" name="subject" size="90%"><br>
			本文:<br>
			<textarea name="body" rows="12" cols="100%"></textarea>
			</p>
			<p>
			<input type="submit" value="送信">
			</form>
   <?php endif; ?>
</div>

宛先と本文を必須(required)にする

<?php if($_GET&#91;"compose"&#93; == 'new'): ?>
		<form action="" method="post">
			宛先
			<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>
			<p>
			<input type="submit" value="送信">
			</form>
   <?php endif; ?>

DBに入れるため、postの内容を受け取り、変数に格納する

session_start();
if(isset($_POST["to"])){
	$to = $_POST["to"];
	$subject = $_POST["subject"];
	$body = $_POST["body"];
}

送信後はパラメータを”?compose=done”に変更する

<?php if($_GET&#91;"compose"&#93; == 'new'): ?>
		<form action="?compose=done" method="post">
			宛先
			<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>
			<p>
			<input type="submit" value="送信">
			</form>
   <?php elseif($_GET&#91;"compose"&#93; == 'done'): ?>
   			<p>メール送信が完了しました</p>
   <?php endif; ?>

おお、なんか凄い疲れた。

phpでメールボックスをつくろう1

まず初期状態

<?php
session_start();
?>
<style>
h1 {
	display:inline;
}
#out {
/*	display: inline;*/
	float:right;
}
.flex-container {
  display: flex;
}
.flex-1{
  flex:2;
  height:400px;
  background-color:#f5f5f5;
}
.flex-2{
  flex:7;
}
</style>
<?php if(isset($_SESSION&#91;"username"&#93;)): ?>
<h1><?php echo $_SESSION&#91;"username"&#93;; ?>さんのメールボックス</h1>
<div id="out"><a href="logout.php">ログアウト</a></div>
<hr>
<div class="flex-container">
<div class="flex-1">
</div>
<div class="flex-2">
</div>
</div>
<?php else: header('Location: login.php'); ?>
<?php endif; ?>

sampleというユーザ名でログインした状態です。

メニューを作ります。
gmailやhotmailではメール新規作成などはgetパラメーターを使っているので、ここでは”?compose=new”とします。

<div class="flex-1">
<a href="?compose=new" class="square_btn">新規作成</a>
<ul>
		<li><a href="">Inbox</a></li>
		<li><a href="">Junk Email</a></li>
		<li><a href="">Sent Items</a></li>
		<li><a href="">Deleted Email</a></li>
</ul>
</div>

getパラメータでcomoseがnewの場合、フォームを表示させたいので、

<div class="flex-2">
   <?php if($_GET&#91;"compose"&#93; == 'new'): ?>
		<p>メール新規作成</p>
   <?php endif; ?>
</div>

うまく動いているようです。

ログインからログアウトまでの挙動

loginとregisterにそれぞれリンクをつけて、logoutはjavascriptのsettimeoutで1秒後に、loginにリダイレクト。

register.php

<h1>新規登録</h1>
<?php if($status == "ok"):?>
	<p>登録完了</p><br>
	<a href="login.php">ログインページ</a>
<?php elseif($status == "failed"): ?>
	<p>エラー:既に存在するユーザ名です。<br>
	ユーザ名(英数字3~32文字)、推測されにくいパスワード(英数字8~32文字)を入力してください。</p>
	<form method="POST" action="">
	ユーザ名:<input type="text" name="username">
	パスワード:<input type="password" name="password">
	<input type="submit" value="登録">
	</form>
	<a href="login.php">ログイン</a>
<?php elseif($status == "none"): ?>
	<p>ユーザ名(英数字3~32文字)、推測されにくいパスワード(英数字8~32文字)を入力してください。</p>
	<form method="POST" action="">
	ユーザ名:<input type="text" name="username">
	パスワード:<input type="password" name="password">
	<input type="submit" value="登録">
	</form>
	<a href="login.php">ログイン</a>

<h1>ログイン</h1>
    <?php if($status == "logged_in"):  header('Location: hoge.php');?>
    <?php elseif($status == "ok"): header('Location: hoge.php'); ?>
    <?php elseif($status == "failed"): ?>
      <p>ログイン失敗</p>
      <form method="POST" action="login.php">
        ユーザ名:<input type="text" name="username" />
        パスワード:<input type="password" name="password" />
        <input type="submit" value="ログイン" />
      </form>
      <a href="register.php">新規登録</a>
    <?php else: ?>
      <form method="POST" action="login.php">
        ユーザ名:<input type="text" name="username" />
        パスワード:<input type="password" name="password" />
        <input type="submit" value="ログイン" />
      </form>
      <a href="register.php">新規登録</a>
 	<?php endif; ?>

hoge.php

<?php
session_start();
?>
<?php if(isset($_SESSION&#91;"username"&#93;)): ?>
<p>コンテンツコンテンツコンテンツ</p>
<a href="logout.php">ログアウト</a>
<?php else: header('Location: login.php'); ?>
<?php endif; ?>

logout.php

<h1>ログアウト</h1>
<p>ログアウト完了しました<p>
<script>
setTimeout(function(){
	window.location.href = "login.php";
}, 1000);
</script>

以下のようにも書けますね。

<?php
session_start();
?>
<?php if(isset($_SESSION&#91;"username"&#93;)): ?>
<p><?php echo $_SESSION&#91;"username"&#93;; ?>さんの会員ページ</p>
<a href="logout.php">ログアウト</a>
<?php else: header('Location: login.php'); ?>
<?php endif; ?>

classでログイン機能

auth.php

<?php 

class Auth{
	const HOST_NAME = "localhost";
	const USER_NAME = "hoge";
	const PASSWORD ="hogehoge";
	const DATABASE_NAME = "mail";

	private $mysqli = null;

	function __construct(){
		$this->mysqli = new mysqli(
			self::HOST_NAME,
			self::USER_NAME,
			self::PASSWORD,
			self::DATABASE_NAME
		);
		session_start();
	}

	public function register($username, $password){
		$password = password_hash($_POST["password"], PASSWORD_DEFAULT);
		$stmt = $this->mysqli->prepare("INSERT INTO users VALUES(?, ?)");
		$stmt->bind_param('ss', $_POST["username"], $password);
		return $stmt->execute();
	}

	public function login($username, $password){
		$stmt = $this->mysqli->prepare(
			"SELECT password FROM users WHERE username = ?");
		$stmt->bind_param('s', $_POST["username"]);
		$stmt->execute();

		$stmt->store_result();
		if($stmt->num_rows == 1){
			$stmt->bind_result($hash);
			while ($stmt->fetch()){
				if(password_verify($_POST['password'], $hash)){
					$_SESSION["username"] = $_POST["username"];
					return true;
				}
			}
		}
		return false;
	}

	public function getUser(){
		if(isset($_SESSION["username"]))
			return $_SESSIOn["username"];
		return null;
	}

	public function logout(){
		$_SESSION = array();
		session_destroy();
	}
}

register.php

<?php

require_once("auth.php");
$auth = new Auth();

$status = "none";

if(!empty($_POST&#91;"username"&#93;) && !empty($_POST&#91;"password"&#93;)){

	if(!preg_match('/^&#91;0-9a-zA-Z&#93;{3,32}$/', $_POST&#91;"username"&#93;))
    		$status = "error_username";
  	else if(!preg_match('/^&#91;0-9a-zA-Z&#93;{8,32}$/', $_POST&#91;"password"&#93;))
    		$status = "error_password";
	elseif($auth->register($_POST["username"], $_POST["password"]))
			$status = "ok";
	else
			$status = "failed";	
	
}
?>
<head>
<script src="http://code.jquery.com/jquery-2.0.0.min.js"></script>
<script src="register_check.js"></script>
</head>
<h1>Jmail新規登録</h1>
<?php if($status == "ok"):?>
	<p>登録完了</p>
<?php elseif($status == "failed"): ?>
	<p>エラー:既に存在するユーザ名です。</p>
<?php elseif($status == "none"): ?>
	<p>ユーザ名(英数字3~32文字)、推測されにくいパスワード(英数字8~32文字)を入力してください。</p>
	<form method="POST" action="">
	ユーザ名:<input type="text" name="username">
	パスワード:<input type="password" name="password">
	<input type="submit" value="登録">
	</form>
<?php else: ?>
	<p>hogehoge</p>
<?php endif; ?>

login.php

<?php 

require_once("auth.php");
$auth = new Auth();

$status = "none";

if($auth->getUser())
	$status = "logged_in";
else if(!empty($_POST["username"]) && !empty($_POST["password"])){
	 if($auth->login($_POST["username"], $_POST["password"]))
        $status = "ok";
     else
        $status = "failed";
}
?>
<h1>ログイン</h1>
    <?php if($status == "logged_in"): ?>
      <p>ログイン済み</p>
    <?php elseif($status == "ok"): ?>
      <p>ログイン成功</p>
    <?php elseif($status == "failed"): ?>
      <p>ログイン失敗</p>
    <?php else: ?>
      <form method="POST" action="login.php">
        ユーザ名:<input type="text" name="username" />
        パスワード:<input type="password" name="password" />
        <input type="submit" value="ログイン" />
      </form>
 	<?php endif; ?>

logout.php

<?php 

require("auth.php");
$auth = new Auth();
$auth->logout();

?>

<h1>ログアウト</h1>
<p>完了<p>

すげー!

ログイン中のページ表示

セッションに値がある場合は、コンテンツを表示させ、それ以外は、ログインページにリダイレクトさせる。

session_start();

if(isset($_SESSION["username"])){
	echo "ログイン中です。";
} else {
	header('Location: login.php');
}

ふむふむ

session destroy もしくは nullの場合はログインページにリダイレクト

ログイン・サインインの基本機能はできたかな?

sign inに英数字のバリデーションを付与

id 英数字3~32文字、パスワード英数字8~32文字のバリデーション

<?php

require_once("auth.php");
$mysqli = connect_mysql();

$status = "none";

if(!empty($_POST&#91;"username"&#93;) && !empty($_POST&#91;"password"&#93;)){

	if(!preg_match('/^&#91;0-9a-zA-Z&#93;{3,32}$/', $_POST&#91;"username"&#93;))
    $status = "error_username";
  //パスワードのチェック
  else if(!preg_match('/^&#91;0-9a-zA-Z&#93;{8,32}$/', $_POST&#91;"password"&#93;))
    $status = "error_password";
	else{
		$password = password_hash($_POST&#91;"password"&#93;, PASSWORD_DEFAULT);
		$stmt = $mysqli->prepare("INSERT INTO users VALUES (?, ?)");
		$stmt->bind_param('ss', $_POST["username"], $password);

		if($stmt->execute())
			$status = "ok";
		else
			$status = "failed";	
		}
	}
?>
<head>
<script src="http://code.jquery.com/jquery-2.0.0.min.js"></script>
<script src="register_check.js"></script>
</head>
<h1>Jmail新規登録</h1>
<?php if($status == "ok"):?>
	<p>登録完了</p>
<?php elseif($status == "failed"): ?>
	<p>エラー:既に存在するユーザ名です。</p>
<?php elseif($status == "none"): ?>
	<p>ユーザ名(英数字3~32文字)、推測されにくいパスワード(英数字8~32文字)を入力してください。</p>
	<form method="POST" action="">
	ユーザ名:<input type="text" name="username">
	パスワード:<input type="password" name="password">
	<input type="submit" value="登録">
	</form>
<?php else: ?>
	<p>hogehoge</p>
<?php endif; ?>

register_check.js

$(function(){
  $("form").submit(function(){
    if(!$("input[name=username]").val().match(/^[0-9a-zA-Z]{3,32}$/)
    || !$("input[name=password]").val().match(/^[0-9a-zA-Z]{8,32}$/)){
      alert("入力エラー");
      return false;
    }
    return true;
  });
});

logout

<?php 

session_start();
$_SESSION = array();
session_destroy();

?>

<h1>ログアウト</h1>
<p>完了<p>

password_verifyが上手くいかないとき

ログイン機能をつくっていた際に、何故かpassword_verifyが上手くいかなかったが、

create tableする際に、passwordの桁数が少なかったのが原因。
passwordを255にして

create table mail.users(
	username varchar(41) unique,
	password varchar(255)
)

再度password_hashしたら、上手く機能しました。

<?php 

session_start();

$mysqli = new mysqli('localhost', 'hoge', 'hogehoge', 'mail');

$status = "none";

if(isset($_SESSION&#91;"username"&#93;))
	$status = "logged_in";
else if(!empty($_POST&#91;"username"&#93;) && !empty($_POST&#91;"password"&#93;)){
	 $stmt = $mysqli->prepare("SELECT password FROM users WHERE username = ?");
  $stmt->bind_param('s', $_POST["username"]);
  $stmt->execute();

$stmt->store_result();

  if($stmt->num_rows == 1){
    $stmt->bind_result($pass);
    while ($stmt->fetch()) {
      if(password_verify($_POST["password"], $pass)){
        $status = "ok";
        $_SESSION["username"] = $_POST["username"];
        break;
      }else{
        $status = "failed";
        break;
      }
    }
  }else
  	$status = "failed";
}
?>
<h1>ログイン</h1>
    <?php if($status == "logged_in"): ?>
      <p>ログイン済み</p>
    <?php elseif($status == "ok"): ?>
      <p>ログイン成功</p>
    <?php elseif($status == "failed"): ?>
      <p>ログイン失敗</p>
    <?php else: ?>
      <form method="POST" action="login.php">
        ユーザ名:<input type="text" name="username" />
        パスワード:<input type="password" name="password" />
        <input type="submit" value="ログイン" />
      </form>
    <?php endif; ?>