20191012のMySQLに関する記事は7件です。

AWS EC2 LAMP環境構築

作成環境

 - AmazonLinux
 - Apache
 - MySQL
 - PHP

前提条件

  • AWSアカウントを持っている
  • EC2インスタンス起動済み
  • Macならターミナル 、WindowsならTeraTermからアクセスしている

  ※EC2インスタンスを立ち上げた時点でLinux環境は完了

インストール

[ec2-user@ip-・・・・・・・・・・・~]$ sudo yum update -y

これから頻繁に使う「yum」コマンドのアップデート
  ※「-y」のオプションは実行の確認全てに「YES」と答える設定

[ec2-user@ip-・・・・・・・・・・・~]$ sudo yum install -y httpd24 php70 mysql-server php70-mysqlnd php70-mbstring

httpd24:Apache本体
php70:PHP本体
mysql-server:MySQL(DB)本体
php70-mysqlnd:MySQLドライバ phpMyAdminなどでMySQLに接続する為に必要

上記をインストール

確認

インストールができているか確認

Apache

[ec2-user@ip-・・・・・・・・・・・~]$ httpd -v
Server version: Apache/2.4.33 (Amazon)
Server built:   May 23 2018 19:02:39

PHP

[ec2-user@ip-・・・・・・・・・・・~]$ php -v
PHP 7.0.30 (cli) (built: May 10 2018 17:39:13) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies

MySQL

[ec2-user@ip-・・・・・・・・・・・~]$ mysql --version
mysql  Ver 14.14 Distrib 5.5.60, for Linux (x86_64) using readline 5.1

起動

Apache

[ec2-user@ip-・・・・・・・・・・・~]$sudo service httpd start
                                              [  OK  ]

WebブラウザからEC2のIPアドレスにアクセスして、Apacheのテストページが表示されていればOK

PHP

[ec2-user@ip-・・・・・・・・・・・~]$sudo vi /var/www/html/phpinfo.php

viコマンドでphpファイルを作成及び、編集

<?php
   echo phpinfo();
?>

phpinfo.phpに上記を記載
AWSコンソールでセキュリティグループの設定し

Webブラウザにて、EC2のIPアドレス/phpinfo.phpにアクセス
phpinfoの表示を確認する

PHPの設定をしたい場合はこちら

MySQL

[ec2-user@ip-・・・・・・・・・・・~]$sudo service mysqld start
Starting mysqld:                                [  OK  ]

MySQLを起動

[ec2-user@ip-・・・・・・・・・・・~]$mysql -u root -p



 mysql >

MySQLにログイン
左側がmysqlになっていれば、ログイン状態

 mysql >exit
Bye

MySQLよりログアウト
左側が[ec2-user@ip-・・・・・・・・・・・~]になっていればOK


以上でLAMP環境の構築は完了
ここにあるのは最低限の設定でのインストールと起動確認だけ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker 環境構築(php+nginx+mysql+memcached)

ディレクトリ構成

---docker
|--docker-compose.yml
|--docker
|  |--nginx
|  |    |--Dockerfile
|  |    |--nginx.conf
|  |    |--conf.d
|  |         |--default.conf
|  |
|  |--phpfpm
|  |    |--Dockerfile
|  |    |--php.ini
|  |
|  |--mysql
|  |    |--Dockerfile
|  |    |--my.cnf
|  |
|  |--memcached
|       |--Dockerfile
|
|--volumes
   |--db
   |  |--data
   |
   |--logs
   |--nginx
   |--www
      |--html
      |--webcore

docker-compose.ym

FROM php:7.3-fpm-alpine

RUN apk update \
&& apk add \
    autoconf \
    vim \
    git \
    zip \
    gcc \
    g++ \
    make \
    libmemcached-dev \
    zlib-dev \
    freetype-dev \
    libjpeg-turbo-dev \
    libpng-dev \
    libmcrypt-dev \
    postgresql-dev \
&& pecl install memcached \
&& docker-php-ext-install \
    mbstring \
    json \
    exif \
    mysqli \
    pdo_mysql \
    gd \
    pgsql \
    pdo_pgsql \
    hash

nginx

:latestと:alpineの違い
:latest → bash/shが使用可能
:alpine → shのみ使用可能

Dockerfile

FROM nginx:alpine

conf.d/default.conf

mysql

Dockerfile

#イメージ指定
FROM mysql:5.7

my.cnf

[mysql]
default-character-set=utf8mb4

[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
explicit_defaults_for_timestamp=1
default-time-zone=Asia/Tokyo
max_allowed_packet=32M
skip-symbolic-links=1

[client]
default-character-set=utf8mb4

phpfpm

Dockerfile

FROM php:7.3-fpm-alpine

RUN apk update \
&& apk add \
    autoconf \
    vim \
    git \
    zip \
    gcc \
    g++ \
    make \
    libmemcached-dev \
    zlib-dev \
    freetype-dev \
    libjpeg-turbo-dev \
    libpng-dev \
    libmcrypt-dev \
    postgresql-dev \
&& pecl install memcached \
&& docker-php-ext-install \
    mbstring \
    json \
    exif \
    mysqli \
    pdo_mysql \
    gd \
    pgsql \
    pdo_pgsql \
    hash

php.ini

[Date]
date.timezone = "Asia/Tokyo"

[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

[extension]
enabled_dl = On

[memcached]
extension=memcached.so

php-fpm.conf

memcached

Dockerfile

FROM memcached:latest
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel ide-helperでMySQLのJSON型カラムが認識できないエラーの対処法

課題

Laravel IDE helperでモデルクラスにアノテーションを追加しようとしたらMySQLのJSON型が認識できないとエラーになった。

Exception: Unknown database type json requested, Doctrine\DBAL\Platforms\MySQL57Platform may not support it.

解決策

config/ide-helper.php ファイルを下記内容で作成するだけで解決!

<?php
return [
    'custom_db_types' => [
        'mysql'=> [
            'json'=>'json_array',
        ]
    ],
];

参考

https://github.com/barryvdh/laravel-ide-helper/issues/295#issuecomment-268280789

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MacでRailsにgem mysql2をインストールする時のトラブルシューティング

はじめに

2019年10月現在MacでRailsアプリ開発時にDBにMySQLを選択する場合、デフォルトではmysql2というgemをインストールします。
その時にいくつかエラーに出会ったので、まとめておきます。

実行環境

  • macOS Mojave v10.14.6
  • ruby v2.6.4
  • Rails v6.0.0

MySQLのクライアントが必要

MacにMySQLクライアントをインストールしていない場合、以下のようなエラーが表示されます。

Fetching mysql2 0.5.2
Installing mysql2 0.5.2 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /Users/hogehoge/sample-app/vendor/bundle/gems/mysql2-0.5.2/ext/mysql2
/Users/hogehoge/.rbenv/versions/2.6.4/bin/ruby -I /Users/hogehoge/.rbenv/versions/2.6.4/lib/ruby/2.6.0 -r
./siteconf20191012-40688-181m253.rb extconf.rb
checking for rb_absint_size()... yes
checking for rb_absint_singlebit_p()... yes
checking for rb_wait_for_single_fd()... yes
checking for -lmysqlclient... no
-----
mysql client is missing. You may need to 'brew install mysql' or 'port install mysql', and try again.

Homebrewなどでインストールしておきましょう。
なお、2019年10月現在gemが対応しているバージョンは以下のようですので、採用バージョンに応じたものをインストールしましょう。

This gem is tested with the following MySQL and MariaDB versions:
MySQL 5.5, 5.6, 5.7, 8.0
MySQL Connector/C 6.0 and 6.1 (primarily on Windows)
MariaDB 5.5, 10.0, 10.1, 10.2, 10.3

(https://github.com/brianmario/mysql2 READMEより引用)

# MySQL最新バージョン(8.0)
$ brew install mysql

# 5.xの場合
$ brew install mysql@5.x

5.x系の場合はmysqlコマンドを使えるよう以下のようにPATHを通しておきましょう。

$ export PATH="/usr/local/opt/mysql@5.7/bin:$PATH"

bundle install時のlinkerエラー

無事MySQLクライアントをインストールできていても、以下のようなエラーが起こる場合があります。

Fetching mysql2 0.5.2
Installing mysql2 0.5.2 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /Users/hogehoge/sample-app/vendor/bundle/gems/mysql2-0.5.2/ext/mysql2
/Users/hogehoge/.rbenv/versions/2.6.4/bin/ruby -I /Users/hogehoge/.rbenv/versions/2.6.4/lib/ruby/2.6.0 -r
./siteconf20191012-62886-155hohe.rb extconf.rb
checking for rb_absint_size()... yes
checking for rb_absint_singlebit_p()... yes
checking for rb_wait_for_single_fd()... yes
-----
Using mysql_config at /usr/local/bin/mysql_config
-----
checking for mysql.h... yes
checking for errmsg.h... yes
checking for SSL_MODE_DISABLED in mysql.h... yes
checking for SSL_MODE_PREFERRED in mysql.h... yes
checking for SSL_MODE_REQUIRED in mysql.h... yes
checking for SSL_MODE_VERIFY_CA in mysql.h... yes
checking for SSL_MODE_VERIFY_IDENTITY in mysql.h... yes
checking for MYSQL.net.vio in mysql.h... yes
checking for MYSQL.net.pvio in mysql.h... no
checking for MYSQL_ENABLE_CLEARTEXT_PLUGIN in mysql.h... yes
checking for SERVER_QUERY_NO_GOOD_INDEX_USED in mysql.h... yes
checking for SERVER_QUERY_NO_INDEX_USED in mysql.h... yes
checking for SERVER_QUERY_WAS_SLOW in mysql.h... yes
checking for MYSQL_OPTION_MULTI_STATEMENTS_ON in mysql.h... yes
checking for MYSQL_OPTION_MULTI_STATEMENTS_OFF in mysql.h... yes
checking for my_bool in mysql.h... no
-----
Dont know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load
-----
-----
Setting libpath to /usr/local/Cellar/mysql/8.0.17_1/lib
-----
creating Makefile

current directory: /Users/hogehoge/sample-app/vendor/bundle/gems/mysql2-0.5.2/ext/mysql2
make "DESTDIR=" clean

current directory: /Users/hogehoge/sample-app/vendor/bundle/gems/mysql2-0.5.2/ext/mysql2
make "DESTDIR="
compiling client.c
compiling infile.c
compiling mysql2_ext.c
compiling result.c
compiling statement.c
linking shared-object mysql2/mysql2.bundle
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1

make failed, exit code 2

以下がこのエラーの原因で、ざっくり言うとgemのビルド時に、必要なopensslライブラリを見つけられないために発生しています。

ld: library not found for -lssl

詳細な原因は以下記事が大変参考になります。
https://qiita.com/HrsUed/items/ca2e0aee6a2402571cf6

解決策としては、bundle install時に以下オプションでpathを指定する必要があります。

  • --with-cppflags
  • --with-ldflags

brew infoでインストールされているopensslを確認すると、自分の環境のLDFLAGSとCPPFLAGSのpathが確認できます。

$ brew info openssl@1.1

openssl@1.1: stable 1.1.1d (bottled) [keg-only]
...
For compilers to find openssl@1.1 you may need to set:
  export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib"
  export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include"
...

こちらのpathをbundle configで設定してからインストールしましょう。

$ bundle config --local build.mysql2 "--with-cppflags=-I/usr/local/opt/openssl@1.1/include"
$ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl@1.1/lib"
$ bundle install

以上、自分が遭遇したエラー内容でした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

mysql.connector.errors.DatabaseError: 1366 (HY000): Incorrect string valueが出る

様々な事をしてきましたが、「mysql.connector.errors.DatabaseError: 1366 (HY000): Incorrect string value: '\xE7\xA6\x8F\xE5\xB2\xA1...' for column 'title' at row 1」とエラーが出て、直りませんでした。でも、めちゃくちゃ単純なことで直りました(笑)

結論から言うと、データベースを新しく作り直したらエラーが出なくなりました。原因としては、utf-8に変更してからテーブルしか作り直してませんでした。なのでデータベースに反映されてなかったのかと。

やったこと

エラーが出てからやっていった事を簡単に書きます。

まずは文字コードの変更

mysql> show variables like "chara%";
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

utf8mb4にもしましたが、エラーは変わらず。
設定が反映されてないのかと思い、もう一度mysqlの再起動、そしてサーバーの再起動するも変わらず。
pythonのコードで「charset='utf-8'」指定するも変わらず。

connect = mysql.connector.connect(
        host='localhost',
        port='3306',
        user='root',
        password='パスワード',
        database='DB名',
        charset='utf-8'
    )

mysql-connector-pythonを使っていたので、pythonのコードがおかしいのかと思い、ネットで使い方を紹介されている方のをやってみるとエラーがでなくなりました。なので私のプログラムをもう一度見直すもおかしいところはありませんでした。まあ、その方のを試すとき新しくデータベース作ってやっているので、エラーが出なくなって当然ですよねwww(今思うと)
でもその時は深夜まで何時間も粘って原因を探していたので、頭には何でエラーがなくったのかはてなマークでいっぱいでした。その日の解決は諦め、一度寝ました。朝起きてから、データベースから作り直すかと思い、やってみるとエラーがでなくなり解決。

まとめ

今思うとなんでデータベースから作り直さなかったと思いましたが、あの時はまったく頭になかったですね(笑)計6時間くらいは悩んでたと思います。まあmysql触り始めたばかりなので、様々なこと調べたりしていい勉強になりました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【図解付き】Docker Data Volumeのバックアップ・リストア方法

バックアップ方法

$ docker run --rm --volumes-from [データボリュームのマウント先コンテナ名] -v `pwd`:/backup busybox tar cvf /backup/backup.tar [データボリュームのマウント先ディレクトリ]

もしくは

$ docker run --rm -v [データボリューム名]:[データボリュームのマウント先ディレクトリ] -v `pwd`:/backup busybox tar cvf /backup/backup.tar [データボリュームのマウント先ディレクトリ]

具体例

MySQLのデータベース情報が保存されているデータボリュームをバックアップしたい場合は以下のようになります。
データボリュームがマウントされているDBコンテナをwp_db_conとします。

$ docker run --rm --volumes-from wp_db_con -v `pwd`:/backup busybox tar cvf /backup/backup.tar /var/lib/mysql

図で表現すると以下のようになります。

volume-backup-from-con-880-1.png

もしくは以下のようになります。
データボリューム名をmy_wordpress_mysql_dataとします。

$ docker run --rm -v my_wordpress_mysql_data:/var/lib/mysql -v `pwd`:/backup busybox tar cvf /backup/backup.tar /var/lib/mysql

図で表現すると以下のようになります。

volume-backup-from-volume-880-1.png

リストア方法

$ docker run --rm --volumes-from [データボリュームのマウント先コンテナ名] -v `pwd`:/backup busybox tar xvf /backup/backup.tar

もしくは

$ docker run --rm -v [データボリューム名]:[データボリュームのマウント先ディレクトリ] -v `pwd`:/backup busybox tar xvf /backup/backup.tar

具体例

MySQLのデータベース情報が保存されているデータボリュームをリストアしたい場合は以下のようになります。

$ docker run --rm --volumes-from wp_db_con -v `pwd`:/backup busybox tar xvf /backup/backup.tar

もしくは以下のようになります。

$ docker run --rm -v my_wordpress_mysql_data:/var/lib/mysql -v `pwd`:/backup busybox tar xvf /backup/backup.tar

さいごに

データボリュームのバックアップ・リストア方法の詳細については【Docker】具体例で理解するデータボリュームのバックアップ・リストア方法でも紹介していますのでもし興味のある方はご覧になっていただければと思います。

ツイッター(@nishina555)やってます。フォローしてもらえるとうれしいです!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPで【いいねボタン】を実装してみた

最初に

現在通っているプログラミングスクールのPHPカリキュラムの中で教材(市販の入門書)に沿って簡易掲示板を作成。
その簡易掲示板を元に自分で考えて【いいねボタン】機能を追加してみました。

学習後のアウトプットを目的としており、教材の入門書一冊分の知識だけです。
フレームワークは使っていません。
元となる書籍の内容には触れていませんので、同じ書籍を見ていない人には分かりづらいと思います。
きっと…いや、間違いなくもっと綺麗なコードがあるはずですが、同じ初学者の方の参考になれば幸いです。

※教材はこちらです→よくわかるPHPの教科書 【PHP7対応版】

完成イメージ

今回はいいねボタンを簡単なハート文字にしました。
image.png

image.png

DB

既存のテーブルはこちら

membersテーブル
image.png

postsテーブル
image.png

【いいねボタン】機能のために追加したテーブル

likesテーブル
image.png

1. いいねボタンをクリックした時にDBにデータを挿入or削除する

1-1. いいねボタン(仮)を用意する

index.php
<a class="heart" href="index.php?like=<?php echo h($post['id']); ?>">&#9825;</a>

表示部分です。
URLパラメータのlikeに$post['id']を使います。
$post['id']はpostsテーブルのidを取得した値になっています。

いいねボタンをクリックすると$_REQUEST['LIKE']$post['id']の値が入ります。

1-2. いいねを押したメッセージの投稿者を調べる

index.php
if (isset($_REQUEST['like'])) {

  //いいねを押したメッセージの投稿者を調べる
  $contributor = $db->prepare('SELECT member_id FROM posts WHERE id=?');
  $contributor->execute(array($_REQUEST['like']));
  $pressed_message = $contributor->fetch();

isset()で①の$_REQUEST['LIKE']に値が入ったか確認しtrueであれば、いいねを押したメッセージの投稿者を調べます。

1-3. いいねを押した人とメッセージ投稿者が同一人物でないか確認

index.php
//いいねを押した人とメッセージ投稿者が同一人物でないか確認
  if ($_SESSION['id'] != $pressed_message['member_id']) {

$_SESSION['id']はログインした人のmembersテーブルidの値が入っています。

ここでログインしている人が自分の投稿にはいいねを押せないようにします。

1-4. 過去にいいね済みであるか確認

index.php
    //過去にいいね済みであるか確認
    $pressed = $db->prepare('SELECT COUNT(*) AS cnt FROM likes WHERE post_id=? AND member_id=?');
    $pressed->execute(array(
      $_REQUEST['like'],
      $_SESSION['id']
    ));
    $my_like_cnt = $pressed->fetch();

likeテーブルにログイン者が同じメッセージにいいねしてあるかCOUNTで確認。

1-5. いいねのデータを挿入or削除

index.php
//いいねのデータを挿入or削除
    if ($my_like_cnt['cnt'] < 1) {
      $press = $db->prepare('INSERT INTO likes SET post_id=?, member_id=?, created=NOW()');
      $press->execute(array(
        $_REQUEST['like'],
        $_SESSION['id']
      ));
      header("Location: index.php");
      exit();
    } else {
      $cancel = $db->prepare('DELETE FROM likes WHERE post_id=? AND member_id=?');
      $cancel->execute(array(
        $_REQUEST['like'],
        $_SESSION['id']
      ));
      header("Location: index.php");
      exit();
    }

④で調べた$my_like_cnt['cnt']の値で分岐させて、挿入か削除をする。

これでいいねボタンを1回クリックするとlikeテーブルにデータが挿入され、もう一度クリックすると今度は削除されます。(DBで確認しましょう)

2. いいねボタンのハートの表示を変化させる

2-1. ログインしている人がいいねしたメッセージをすべて取得

index.php
//ログインしている人がいいねしたメッセージをすべて取得
$like = $db->prepare('SELECT post_id FROM likes WHERE member_id=?');
$like->execute(array($_SESSION['id']));
while ($like_record = $like->fetch()) {
  $my_like[] = $like_record;
}

ここは取り出すレコードが複数になることがあるので、while文で一つずつ値を取り出します。
取り出した値はもともと配列になっているので、さらに配列(二次元配列)として変数$my_like[]に代入します。

//$my_likeの中身(例)

     Array(
      [0] => Array(
            [post_id] => 17
            [0] => 17
            )
      [1] => Array(
            [post_id] => 19
            [0] => 19
            )

2-2. それぞれの投稿されたメッセージが、ログインしている人がいいねしたメッセージに当てはまるかを調べる

index.php
      $my_like_cnt = 0;
       if (!empty($my_like)) {
        foreach ($my_like as $like_post) {
         foreach ($like_post as $like_post_id) {
          if ($like_post_id == $post['id']) {
           $my_like_cnt = 1;
          }
         }
        }

テキストではもともとforeach文でメッセージ全てを表示させていますが($postがその変数)、その中で上記のコードを入れます。
まず、繰り返されるごとに$my_like_cntの値を初期化するために0を代入します。
$my_likeは二次元配列なので、foreachをネストして値を取り出します。
$like_post_id(いいねしたことのあるメッセージ)と$post['id'](表示しているメッセージ)が同一であれば、$my_like_cntに1を代入します。

$my_like_cntに代入している数字自体に特に意味はありません。

2-3. いいねボタンのハート表示を切り替える

index.php
<?php if ($my_like_cnt < 1) : ?>
<a class="heart" href="index.php?like=<?php echo h($post['id']); ?>">&#9825;</a>
<?php else : ?>
<a class="heart red" href="index.php?like=<?php echo h($post['id']); ?>">&#9829;</a>
<?php endif; ?>

2-2の結果をif文で分岐させていいねボタンの表示を切り替えます。

※ここではCSSは省略しますので、お好きにどうぞ。

これでいいねボタンの表示を変化させることが出来ました。

3. メッセージごとにいいねされた件数を表示する

3-1. メッセージ別のいいねされた件数をDBから取り出す

index.php
$posts = $db->prepare('SELECT m.name, m.picture, p.*, COUNT(l.post_id) AS like_cnt FROM members m, posts p LEFT JOIN likes l ON p.id=l.post_id WHERE m.id=p.member_id GROUP BY l.post_id ORDER BY p.created DESC LIMIT ?, 5');
$posts->bindParam(1, $start, PDO::PARAM_INT);
$posts->execute();

元の投稿内容を取得するところで、一緒にlikeテーブルからも取得するように書き換えます。
ここで追加で取得したいのは、メッセージ別のいいねされた件数です。それがCOUNT(l.post_id) AS like_cntになります。LEFT JOIN likes l ON p.id=l.post_idとしてリレーションを張って、GROUP BY l.post_idとすることでOKです。

3-2. いいねボタンの横に表示させる

index.php
<span><?php echo h($post['like_cnt']); ?></span>

これでメッセージごとにいいねされた件数を表示することが出来ました。

4. いいねボタンをクリックするたびに1ページ目に戻らないようにする

index.php
<?php if ($my_like_cnt < 1) : ?>
<a class="heart" href="index.php?like=<?php echo h($post['id']); ?>&page=<?php echo h($page); ?>">&#9825;</a>
<?php else : ?>
<a class="heart red" href="index.php?like=<?php echo h($post['id']); ?>&page=<?php echo h($page); ?>">&#9829;</a>
<?php endif; ?>

2-3の部分に&page=<?php echo h($page); ?>を追加して上記のように修正する。
そうするとURLパラメータに現在のページ$pageを渡すので、1-5のheaderファンクションの部分を下記のように書き直します。

index.php
header("Location: index.php?page={$page}");

これでいいねボタンをクリックしたあとも元のページが表示されます。

まとめ

index.php
//3-1. メッセージ別のいいねされた件数をDBから取り出す
$posts = $db->prepare('SELECT m.name, m.picture, p.*, COUNT(l.post_id) AS like_cnt FROM members m, posts p LEFT JOIN likes l ON p.id=l.post_id WHERE m.id=p.member_id GROUP BY l.post_id ORDER BY p.created DESC LIMIT ?, 5');
$posts->bindParam(1, $start, PDO::PARAM_INT);
$posts->execute();

//1-2. いいねボタン
if (isset($_REQUEST['like'])) {

  //いいねを押したメッセージの投稿者を調べる
  $contributor = $db->prepare('SELECT member_id FROM posts WHERE id=?');
  $contributor->execute(array($_REQUEST['like']));
  $pressed_message = $contributor->fetch();

  //1-3. いいねを押した人とメッセージ投稿者が同一人物でないか確認
  if ($_SESSION['id'] != $pressed_message['member_id']) {

    //1-4. 過去にいいね済みであるか確認
    $pressed = $db->prepare('SELECT COUNT(*) AS cnt FROM likes WHERE post_id=? AND member_id=?');
    $pressed->execute(array(
      $_REQUEST['like'],
      $_SESSION['id']
    ));
    $my_like_cnt = $pressed->fetch();

    //1-5. いいねのデータを挿入or削除
    if ($my_like_cnt['cnt'] < 1) {
      $press = $db->prepare('INSERT INTO likes SET post_id=?, member_id=?, created=NOW()');
      $press->execute(array(
        $_REQUEST['like'],
        $_SESSION['id']
      ));
      header("Location: index.php?page={$page}");
      exit();
    } else {
      $cancel = $db->prepare('DELETE FROM likes WHERE post_id=? AND member_id=?');
      $cancel->execute(array(
        $_REQUEST['like'],
        $login_user
      ));
      header("Location: index.php?page={$page}");
      exit();
    }
  }
}

//2-1. ログインしている人がいいねしたメッセージをすべて取得
$like = $db->prepare('SELECT post_id FROM likes WHERE member_id=?');
$like->execute(array($_SESSION['id']));
while ($like_record = $like->fetch()) {
  $my_like[] = $like_record;
}
index.php
<?php
  $my_like_cnt = 0;
  if (!empty($my_like)) {
    foreach ($my_like as $like_post) {
      foreach ($like_post as $like_post_id) {
        if ($like_post_id == $post['id']) {
          $my_like_cnt = 1;
        }
      }
    }
  }
  ?>
<?php if ($my_like_cnt < 1) : ?>
  <a class="heart" href="index.php?like=<?php echo h($post['id']); ?>&page=<?php echo h($page); ?>">&#9825;</a>
<?php else : ?>
  <a class="heart red" href="index.php?like=<?php echo h($post['id']); ?>&page=<?php echo h($page); ?>">&#9829;</a>
<?php endif; ?>
<span><?php echo h($post['like_cnt']); ?></span>

完成した表示

image.png

ハートをクリックすると赤くなってカウンターが増えます。

image.png

もう一度クリックすると色が戻ってカウンターが減ります。
image.png

振り返り

今回の実装にあたり個人的に苦戦したのは、
①DB設計
新たなテーブルにどんなカラムを用意すれば良いのか、テーブル間のリレーションはどうなるのか。
②SQL文
3-1では3つのテーブルでリレーションを張ってというような感じで、少し複雑になると思うようにデータを取り出すことが出来ず、解決まで時間がかかった。
③二次元配列
2-1、2-2では二次元配列の扱い方について理解が不十分だった為、時間がかかった。

きっと実務では、Ajaxで非同期処理をしたり、それぞれの処理をクラスで分けたり、色々あると思いますが、少しずつレベルアップして行きたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む