LoginSignup
4
5

More than 3 years have passed since last update.

【PHP】メッセージ機能実装

Last updated at Posted at 2020-12-05

学習内容を備忘録としてまとめます。
メッセージ機能を実装しましたので、作成方法を記載します。
message.gif

ユーザー同士でメッセージ機能を用いてやり取りすることができます。

実装方法

実装方法について記載していきます。

テーブル構成

image.png
messaegeテーブルmessage_relationテーブルの2つを作成します。
各カラムは下記のような役割を担っています。

カラム名 役割
id メッセージID
text メッセージ内容
image メッセージに添付される画像
user_id メッセージをしたユーザーID
destination_user_id メッセージ送信先のユーザーID
created_id メッセージをした時刻

メッセージ画面

実際にメッセージのやり取りが行われる、メッセージ画面について実装していきます。

message.php
<?php
$current_user = get_user($_SESSION['user_id']);
$destination_user = get_user($_GET['user_id']);
$messages = get_messages($current_user['id'], $destination_user['id']);
?>

<body>
 <div class="message">
    <h2 class="center"><?= $destination_user['name'] ?></h2>
    <?php foreach ($messages as $message) :?>
        <div class="my_message">
        <?php if ($message['user_id'] == $current_user['id']) : ?>
            <div class="mycomment right">
            <span class="message_created_at"><?=  convert_to_fuzzy_time($message['created_at']) ?></span><p><?= $message['text'] ?></p><img src="../user/image/<?= $current_user['image'] ?>" class="message_user_img">
            </div>
        <?php else : ?>
            <div class="left"><img src="../user/image/<?= $destination_user['image'] ?>" class="message_user_img">
            <div class="says"><?= $message['text'] ?></div><span class="message_created_at"><?=  convert_to_fuzzy_time($message['created_at']) ?></span>
            <?php endif; ?>
            </div>
    <?php endforeach ?>

    <div class="message_process">
     <h2 class="message_title">メッセージ</h2>
     <form method="post" action="../message/message_add.php" enctype="multipart/form-data">
        <textarea class="textarea form-control" placeholder="メッセージを入力ください" name="text"></textarea>
        <input type="hidden" name="destination_user_id" value="<?= $destination_user['id'] ?>">
        <div class="message_btn">
            <div class="message_image">
                <input type="file" name="image" class="my_image" accept="image/*" multiple>
            </div>
            <button class="btn btn-outline-primary" type="submit" name="post" value="post" id="post">投稿</button>
        </div>
     </form>
    </div>
 </div>
</body>

23行目の<?php endforeach ?>までが、メッセージのやり取りが表示されている箇所で、
それ以降はメッセージを入力するフォーム等が記載されています。

<?php
$current_user = get_user($_SESSION['user_id']);
$destination_user = get_user($_GET['user_id']);
$messages = get_messages($current_user['id'], $destination_user['id']);
?>

こちらはメッセージをやり取りする上で必要な情報を取得しています。
それぞれ下記のような役割を担っています。

変数名 役割
$current_user 現在ログインしているユーザー情報
$destination_user メッセージ送信先のユーザー情報
$messages やり取りされるメッセージ情報

get_userget_messages関数で情報を取得しています。

function get_user($user_id){
  try {
    $dsn='mysql:dbname=db;host=localhost;charset=utf8';
    $user='root';
    $password='';
    $dbh=new PDO($dsn,$user,$password);
    $sql = "SELECT id,name,password,profile,image
            FROM user
            WHERE id = :id AND delete_flg = 0 ";
    $stmt = $dbh->prepare($sql);
    $stmt->execute(array(':id' => $user_id));
    return $stmt->fetch();
  } catch (\Exception $e) {
    error_log('エラー発生:' . $e->getMessage());
    set_flash('error',ERR_MSG1);
  }
}

function get_messages($user_id,$destination_user_id){
  try {
    $dsn='mysql:dbname=db;host=localhost;charset=utf8';
    $user='root';
    $password='';
    $dbh=new PDO($dsn,$user,$password);
    $sql = "SELECT *
            FROM message
            WHERE (user_id = :id and destination_user_id = :destination_user_id) or (user_id = :destination_user_id and destination_user_id = :id)
            ORDER BY created_at ASC";
    $stmt = $dbh->prepare($sql);
    $stmt->execute(array(':id' => $user_id,
                         ':destination_user_id' => $destination_user_id));
    return $stmt->fetchAll();
  } catch (\Exception $e) {
    error_log('エラー発生:' . $e->getMessage());
    set_flash('error',ERR_MSG1);
  }
}

それぞれテーブルからユーザーID送信先ユーザーのIDを引数にして情報を取得しています。


$sql = "SELECT *
        FROM message
        WHERE (user_id = :id and destination_user_id = :destination_user_id) or (user_id = :destination_user_id and destination_user_id = :id)
        ORDER BY created_at ASC";

ユーザーによってはユーザー情報が互い違いになっているため、
WHERE条件でIDが取得できるようにしています。

$destination_user = get_user($_GET['user_id']);

送信先ユーザーについては、URLからIDを取得しています。

<a href='message.php?user_id=<?= $destination_user['id'] ?>'>

このようにURLから送信先ユーザーIDを取得しています。

続いてメッセージのやり取りを表示するブラウザ画面をみてきます。

        <?php foreach ($messages as $message) :?>
          <div class="my_message">
            <?php if ($message['user_id'] == $current_user['id']) : ?>
              <div class="mycomment right">
              <span class="message_created_at"><?=  convert_to_fuzzy_time($message['created_at']) ?></span><p><?= $message['text'] ?></p><img src="../user/image/<?= $current_user['image'] ?>" class="message_user_img">
              </div>
            <?php else : ?>
              <div class="left"><img src="../user/image/<?= $destination_user['image'] ?>" class="message_user_img">
                <div class="says"><?= $message['text'] ?></div><span class="message_created_at"><?=  convert_to_fuzzy_time($message['created_at']) ?></span>
              <?php endif; ?>
              </div>
        <?php endforeach ?>

自分のメッセージと送信先のメッセージが表示されるようになっています。

<?php foreach ($messages as $message) :?>

先ほどget_messages関数で取得したメッセージ情報をforeach文でループ処理します。


<?php if ($message['user_id'] == $current_user['id']) : ?>
  <div class="mycomment right">
  <span class="message_created_at"><?=  convert_to_fuzzy_time($message['created_at']) ?></span><p><?= $message['text'] ?></p><img src="../user/image/<?= $current_user['image'] ?>" class="message_user_img">
  </div>
<?php else : ?>
  <div class="left"><img src="../user/image/<?= $destination_user['image'] ?>" class="message_user_img">
  <div class="says"><?= $message['text'] ?></div><span class="message_created_at"><?=  convert_to_fuzzy_time($message['created_at']) ?></span>
<?php endif; ?>

メッセージ表示部分をみていきます。
自分と送信先のユーザーメッセージによって、左右に表示させるためにif文で分岐させています。
メッセージテーブルには送信したユーザーIDのカラムがあるので、そちらで判断しています。

messageの各カラムをブラウザに表示させています。
メッセージのレイアウトは下記を参照させていただきました。

CSSで作る!吹き出しデザインのサンプル19選

また、convert_to_fuzzy_time関数では取得した時刻情報から表示形式を渡しています。
詳細は下記の参照をお願いします。

投稿日時をTwitterのように「★分前」「★時間前」という文字列変換するユーザ定義PHP関数

メッセージ送信フォームについてみていきます。

<div class="message_process">
    <h2 class="message_title">メッセージ</h2>
    <form method="post" action="../message/message_add.php" enctype="multipart/form-data">
    <textarea class="textarea form-control" placeholder="メッセージを入力ください" name="text"></textarea>
    <input type="hidden" name="destination_user_id" value="<?= $destination_user['id'] ?>">
    <div class="message_btn">
    <div class="message_image">
        <input type="file" name="image" class="my_image" accept="image/*" multiple>
    </div>
        <button class="btn btn-outline-primary" type="submit" name="post" value="post" id="post">投稿</button>
    </div>
    </form>
</div>
 </div>

コメント内容の記載と画像を添付できるようになっており、
message_add.phpに遷移しコメントテーブルにINSERTをかけるような処理になっています。
※上記のコードは説明上不要な部分を省略しているので、トップの動作画面とは違いがあります。

<input type="hidden" name="destination_user_id" value="<?= $destination_user['id'] ?>">

送信先のユーザーIDを渡しています。
これでメッセージテーブルの中に相手側の情報をもつことができます。

では、先ほど説明したmessage_add.phpについてみていきます。

メッセージ処理

message_add.php
<?php

try
{
$date = new DateTime();
$date->setTimeZone(new DateTimeZone('Asia/Tokyo'));

$message_text=$_POST['text'];
$message_image=$_FILES['image'];
$user_id=$_SESSION['user_id'];
$destination_user_id = $_POST['destination_user_id'];

if($message_text=='')
{
    set_flash('danger','メッセージ内容が未記入です');
    reload();
}

if($message_image['size']>0)
{
    if($message_image['size']>1000000)
    {
        set_flash('danger','画像が大きすぎます');
        reload();
    }
    else
    {
        move_uploaded_file($message_image['tmp_name'],'./image/'.$message_image['name']);

    }
}

$message_text=htmlspecialchars($message_text,ENT_QUOTES,'UTF-8');
$user_id=htmlspecialchars($user_id,ENT_QUOTES,'UTF-8');

$dsn = 'mysql:dbname=db;host=localhost;charset=utf8';
$user = 'root';
$password = '';
$dbh = new PDO($dsn,$user,$password);
$dbh -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = 'INSERT INTO message(text,image,user_id,destination_user_id,created_at) VALUES (?,?,?,?,?)';
$stmt = $dbh -> prepare($sql);
$data[] = $message_text;
$data[] = $message_image['name'];
$data[] = $user_id;
$data[] = $destination_user_id;
$data[] = $date->format('Y-m-d H:i:s');
$stmt -> execute($data);
$dbh = null;

if(!check_relation_message($user_id,$destination_user_id)){
insert_message($user_id,$destination_user_id);
}
set_flash('sucsess','メッセージを送信しました');
header('Location:../message/message.php?user_id='.$destination_user_id.'');

}   
catch (Exception $e)
{
print'ただいま障害により大変ご迷惑をお掛けしております。';
exit();
}

?>

<a href="post_index.php">戻る</a>

メッセージ内容と添付されている画像を確認して、メッセージテーブルにINSERTしています。

if(!check_relation_message($user_id,$destination_user_id)){
insert_message($user_id,$destination_user_id);
}

こちらではcheck_relation_message関数で、message_relationテーブルに自分のIDと送信先ユーザーのIDがあるかどうか確認しています。
今回は関数の前に!マークがついているので、あればfalseなければtureになります。

function check_relation_message($user_id,$destination_user_id){
  try {
    $dsn='mysql:dbname=db;host=localhost;charset=utf8';
    $user='root';
    $password='';
    $dbh=new PDO($dsn,$user,$password);
    $sql = "SELECT user_id,destination_user_id
            FROM message_relation
            WHERE (user_id = :user_id and destination_user_id = :destination_user_id)
                  or (user_id = :destination_user_id and destination_user_id = :user_id)";
    $stmt = $dbh->prepare($sql);
    $stmt->execute(array(':user_id' => $user_id,
                         ':destination_user_id' => $destination_user_id));
    return $stmt->fetch();
  } catch (\Exception $e) {
    error_log('エラー発生:' . $e->getMessage());
    set_flash('error',ERR_MSG1);
  }
}

このように引数の自分のユーザーID送信先ユーザーIDの組み合わせがmessage_relationテーブルにあるかどうか確認しています。

insert_message($user_id,$destination_user_id);

trueである場合には、insert_message関数で引数の自分のユーザーID送信先のユーザーIDを元にrelation_messageテーブルにINSERTしています。

後ほど説明しますが、message_relationテーブルとはメッセージ一覧画面で使用されるテーブルであり、
メッセージのやりとりがあったユーザーに関しては、このテーブルにIDが格納されます。

メッセージ一覧画面

message_list.gif
上記動作画面のように、メッセージでやりとりのあったユーザーを表示し一覧化する画面となっています。
テーブルについてはテーブル構成で説明したmessage_relationテーブルを使用します。

メッセージ一覧画面で使用されるmessage_top.phpをみていきます。

message_top.php
<?php
$current_user = get_user($_SESSION['user_id']);
$message_relations = get_message_relations($current_user['id']);
foreach ($message_relations as $message_relation) :
if($message_relation['destination_user_id']==$current_user['id']){
$destination_user=get_user($message_relation['user_id']);
}else{
$destination_user=get_user($message_relation['destination_user_id']);
}
$bottom_message=get_bottom_message($current_user['id'],$destination_user['id']);
?>

<body>
    <div class="row">
    <div class="col-8 offset-2">
<a href='message.php?user_id=<?= $destination_user['id'] ?>'>
    <div class="destination_user_list">
    <img src="../user/image/<?= $destination_user['image']?>" class="message_user_img">
<div class='destination_user_info'>
        <div class="destination_user_name"><?= $destination_user['name']?></div>
        <span class="destination_user_text"><?= $bottom_message['text'] ?></span>
        </div>
        <span class="bottom_message_time"><?= convert_to_fuzzy_time($bottom_message['created_at']); ?></span>
    </div>
    </a>
</div>
</div>
<?php endforeach ?>
</body>

message_relationテーブルからメッセージのやりとりがあるユーザー情報を取得して、一覧画面にユーザーの名前、アイコン画像等を表示しています。

$message_relations = get_message_relations($current_user['id']);

get_message_relations関数で引数の自分のユーザーIDからメッセージのやりとりがあるユーザー情報を取得しています。

function get_message_relations($user_id){
  try {
    $dsn='mysql:dbname=db;host=localhost;charset=utf8';
    $user='root';
    $password='';
    $dbh=new PDO($dsn,$user,$password);
    $sql = "SELECT *
            FROM message_relation
            WHERE user_id = :user_id";
    $stmt = $dbh->prepare($sql);
    $stmt->execute(array(':user_id' => $user_id));
    return $stmt->fetchAll();
  } catch (\Exception $e) {
    error_log('エラー発生:' . $e->getMessage());
    set_flash('error',ERR_MSG1);
  }
}

引数のユーザーIDから取り出します。

foreach ($message_relations as $message_relation) :
if($message_relation['destination_user_id']==$current_user['id']){
$destination_user=get_user($message_relation['user_id']);
}else{
$destination_user=get_user($message_relation['destination_user_id']);
}

送信先のユーザーIDを取得しています。
メッセージを送信するときにmessage_relationテーブルにINSERTされるので、
ユーザーによってはmessage_relationテーブルの自分のユーザーID送信先のユーザーIDが互い違いになっている可能性があるため、if文で条件分岐させています。

$bottom_message=get_bottom_message($current_user['id'],$destination_user['id']);

メッセージ一覧を表示する際に、やりとりの最後のメッセージを表示させるため、get_bottom_message関数でメッセージ情報を取得しています。

function get_bottom_message($user_id,$destination_user_id){
  try {
    $dsn='mysql:dbname=db;host=localhost;charset=utf8';
    $user='root';
    $password='';
    $dbh=new PDO($dsn,$user,$password);
    $sql = "SELECT *
            FROM message
            WHERE (user_id = :user_id and destination_user_id = :destination_user_id)
                  or (user_id = :destination_user_id and destination_user_id = :user_id)
            ORDER BY created_at DESC";
    $stmt = $dbh->prepare($sql);
    $stmt->execute(array(':user_id' => $user_id,
                         ':destination_user_id' => $destination_user_id));
    return $stmt->fetch();
  } catch (\Exception $e) {
    error_log('エラー発生:' . $e->getMessage());
    set_flash('error',ERR_MSG1);
  }
}

引数の自分のユーザーID送信先のユーザーIDから作成時間の一番古いメッセージを取得しています。

    <div class="row">
    <div class="col-8 offset-2">
<a href='message.php?user_id=<?= $destination_user['id'] ?>'>
    <div class="destination_user_list">
    <img src="../user/image/<?= $destination_user['image']?>" class="message_user_img">
<div class='destination_user_info'>
        <div class="destination_user_name"><?= $destination_user['name']?></div>
        <span class="destination_user_text"><?= $bottom_message['text'] ?></span>
        </div>
        <span class="bottom_message_time"><?= convert_to_fuzzy_time($bottom_message['created_at']); ?></span>
    </div>
    </a>
</div>
</div>

あとは、一覧画面に必要なメッセージ情報をブラウザに表示させています。

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5