20201112のPHPに関する記事は14件です。

朝活ラインボットを作成しました!

10.jpg

記事の概要

作成した朝活ラインボットについて、以下の項目に沿って説明します。

開発の背景

ラインボットの開発に至った経緯について説明します。

朝活ラインボットの機能

このラインボットの機能について説明します。

今後のアップデート項目

このラインボットも加えていきたい機能について説明します。

開発環境

開発環境を簡単に説明します。

開発の背景

朝活をやりたいメンバーでライングループを作り、朝活に励んでいました。
そこでは毎朝6時台に起きて、「おはよう」とメッセージを送り、各々朝活をしています。
寝坊した場合は罰ゲームとして、飲みに行ったときに「寝坊した回数×1杯」を他のメンバーに奢るというルールがありました。
実際に何度か寝坊するメンバーがいて、「寝坊しました」と自己申告してはいましたが、回数を集計するのがとても面倒でした。
そのとき、「集計するシステムを作っちゃえばいいじゃん!」ということで、このラインボットを作成することにしました。
何かを始めるときはノリと勢いが大事ですね!

朝活ラインボットの機能

朝活への参加登録

「朝活に参加する」とメッセージを送信すると、参加登録をしてくれます。
処理としては、メッセージを送信した人のプロフィールを取得し、データベースに登録します。
自分の意志で朝活をやるんだという思いを持ってほしいので、この機能を実装しました。

寝坊回数を集計する

このラインボットの機能の根幹となる部分です。
6時台にメッセージがなかった人は寝坊したとカウントします。
処理としては、6時台のメッセージをデータベースに保存し、7時になったら寝坊判定の処理を実行します。

寝坊回数の表示

「寝坊回数を教えて」とメッセージを送信すると、参加者全員の寝坊回数を教えてくれます。

今後のアップデート項目

朝活開始時間の選択

現在は6時台に設定されていますが、ティム・クックさんみたいに4時に起きて朝活をしたい人もいると思います。
お好みに合わせて設定できるようにする予定です。

プッシュメッセージ送信機能

午前7時に実行する集計処理の結果と、起きれなかった人の名前を通知する機能を実装したいと思います。

寝坊回数リセット機能

罰ゲームを終えたあとは寝坊回数をリセットする必要があります。全員一括でリセットするのか、個人ごとにリセットするのか、仕様を検討します。

朝活をする曜日の選択

毎日朝活をやりたい人や、土日くらいはゆっくり寝たいという人もいると思うので、選択できる機能を追加する予定です。

開発環境

言語:PHP7.4
フレームワーク:Laravel5.5
データベース管理システム:MySQL8.0
サーバー:ConoHa VPS

最後に

ラインボット完成までに、webhookURLがエラーとなったり、DBへデータをインサートできなかったりと他にも様々なエラーに遭遇し、何回か心が折れそうになりました。それでも完成までこぎつけることができたのは、周りの方の支えがあったからです。助けていただいた方々、ありがとうございました!おかげで素晴らしいものができました。今後こういったシステムを作っていって、困っている人の助けになれるように頑張ります!

以上で朝活ラインボットの説明を終わります。最後までお読みいただきありがとうございました!

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

XAMPPで複数バージョンのPHPを切り替えてApache + MySQL を使う方法 on Windows

目標

XAMPPでPHP7.4.xとPHP5.6.xを切り替えてApacheとMySQL、phpMyAdminを使えるようにする

前提

PHPのバージョンが新しい方、もしくは古い方のどちらかでApacheMySQLを稼働できていること

作業

バージョンの異なるXAMPPファイルの入手

ここから欲しいバージョンのPHPが含まれているXAMPPzipファイルをダウンロードする。
PHP単体でなく、XAMPP全体をダウンロードするのはApachephpMyAdminがそれぞれのPHPバージョンに対応した設定になっているから。
今回の方法ではPHPのバージョンを切り替えた際、ApachephpMyAdminのファイルや設定もそれに対応したものにする。
特定のファイルを変更するわけじゃないため作業自体や変更自体は少ないが、少し容量に余裕が必要なことに注意。

名前の変更

新しいバージョン、または古いバージョンが含まれたXAMPPzipファイルをダウンロードできたら、解凍し、以下の3つのフォルダをデスクトップなどにコピー。

  • apache
  • phpMyAdmin
  • php

そして名前を(ファイル名) (phpのメジャーバージョン).(phpのマイナーバージョン)に変更する。
もし、PHP5.6.xをダウンロードした場合、コピーしたフォルダは次の名前になる。

  • apache5.6
  • phpMyAdmin5.6
  • php5.6

名前を変更したら、それらをコピーし、現在のxamppフォルダに貼り付ける。

その後、xampp内のapache,phpMyAdmin,phpを貼り付けたのファイル達と同じ方法で名前を変更する。
既存のPHPバージョンが7.4.xだったら次のようになる。

  • apache7.4
  • phpMyAdmin7.4
  • php7.4

config.inc.phpの移動

今まで使っていたバージョンのphpMyAdminフォルダからconfig.inc.phpを新しく用意したバージョンのphpMyAdminにコピーして貼り付ける。
そうすることで、PHPのバージョンが違っても今までと同じようにphpMyAdminが使えるようになる。
新しく用意したバージョンのphpMyAdminconfig.inc.phpconfig.origin.inc.phpなどに名前を変えて残しておくと良いかもしれない。

シンボリックリンクの作成

シンボリックリンクとはショートカットのようなもの。
php7.4からphpというシンボリックリンクを作成したら、システムや他のファイルはphpというシンボリックリンクを参照して、それに指定されたphp7.4がその中身となる。
正直、使うたびにphp7.4phpに変更するような作業をすればいいが、手間なのでシンボリックリンクを作成する。

今回はPHPのバージョンが5.6のシンボリックリンクを作成する。
シンボリックリンクはコマンドプロントを開いて、それぞれ次のコマンドで実行できる。

$ mklink /D c:\xampp\apache C:\xampp\apache5.6
$ mklink /D c:\xampp\phpMyAdmin C:\xampp\phpMyAdmin5.6
$ mklink /D c:\xampp\php C:\xampp\php5.6

バッチファイル(スクリプト)の作成

「コマンドを毎回入力するよりも名前を毎回変えた方が楽じゃん」
それは否定しないが、コマンドの紹介をしたのは上記のコマンドを含めたバッチファイル(スクリプト)を作成すれば、もっと楽にできる。

ということで、下記のようなバッチファイル(スクリプト)を作成し、xampp下などの使いやすいところに置く。
使い方はエクスプローラーから直接実行するか、コマンドプロントからchange_php.batを置いたところまで移動し、change_php.batを実行する。

change_php.bat
@echo off

echo.
echo 使いたいPHPのバージョンを選択してください。
echo.
echo 現在のPHPバージョン:
echo.
php -v
echo.
echo 1: PHP 5.6
echo 2: PHP 7.4
echo C: Cancel
echo.

choice /c 12C /M "使いたいPHPのバージョン."
if %errorlevel% equ 1 goto PHP5_6
if %errorlevel% equ 2 goto PHP7_4
goto OnExit

:PHP5_6
rmdir C:\xampp\apache
mklink /D C:\xampp\apache C:\xampp\apache-5.6
rmdir C:\xampp\phpMyAdmin
mklink /D C:\xampp\phpMyAdmin C:\xampp\phpMyAdmin-5.6
rmdir C:\xampp\php
mklink /D C:\xampp\php C:\xampp\php-5.6
goto OnExit

:PHP7_4
rmdir C:\xampp\apache
mklink /D C:\xampp\apache C:\xampp\apache-7.4
rmdir C:\xampp\phpMyAdmin
mklink /D C:\xampp\phpMyAdmin C:\xampp\phpMyAdmin-7.4
rmdir C:\xampp\php
mklink /D C:\xampp\php C:\xampp\php-7.4
goto OnExit

:OnExit

コマンドプロントの文字コードがANSIなので、名前を付けて保存する際にANSIを指定しないと動作できなくなるので注意。
実際に動かすとこのようになる。

image.png

動作確認

xamppフォルダのxampp-control.exeを開き、ApacheMySQLAdminボタンをクリックし、新しく用意したバージョンのPHPInfoで用意したバージョンのPHPになっているのとphpMyAdminに接続できればOK。

参考資料

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

PHPで非公開のプロパティを外部から参照・設定する方法

getterを経由する

class App
{
    private $hoge = 'ほげほげ';
    public function getHoge()
    {
        return $this->hoge;
    }
    public function setHoge($hoge)
    {
        $this->hoge = $hoge;
    }
}

$a = new App();
$value = $a->getHoge();
var_dump($value);
//# string(12) "ほげほげ"

通常は上記のようにgetter/setterを経由して非公開のプロパティを取得/設定します。
訳あってgetterを利用せずに外部から非公開のプロパティを参照したい場面があり、詰まってしまったので解決した方法を紹介します。

リフレクションクラスを利用する

https://www.php.net/manual/ja/class.reflectionclass.php

function getValue($object, $propetyName)
{
    $ref = new ReflectionClass(get_class($object));
    $p = $ref->getProperty($propetyName);
    $p->setAccessible(true);

    return $p->getValue($object);
}

$a = new App();
$value = getValue($a, 'hoge');
var_dump($value);
//# string(12) "ほげほげ"

PHPにはReflectionClassが用意されています。
$p->setAccessible(true)とすることでアクセサの制約を無視して外部からプロパティ値の取得や設定が可能になります。
もちろん外部に公開したくない理由があってprivateやprotectedに設計しているので多くの場面で推奨できない方法です。

その他

serialize()を利用すればもっと黒魔術ができるのかも知れない。
https://www.php.net/manual/ja/function.serialize.php
https://stackoverflow.com/questions/2226103/how-to-cast-objects-in-php

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

【Laravel】超基礎☆簡単タスク管理アプリのチュートリアル

(※ この記事は、Laravel8が出るより結構前に書いて、他のブログに載せていました。それを転載したものなので、Laravel7で解説しています。ご了承くださいませ。。(m´・ω・`)m ゴメン…)

環境:XAMPP

初めてLaravelで何かアプリを作ってみようと思って、公式ドキュメントにも載っている簡単なタスク管理アプリを作ることにしました!
自分への備忘録も兼ねて、チュートリアル的な感じで解説していこうと思います。同じく初Laravel製アプリを作ろうとしている方や、Laravel勉強中の初学者の方に参考になれば幸いです!

完成品は以下のような感じです。↓↓

pic_1

新規追加でタスクを入力すると、タスク一覧に表示されて、削除ボタンを押すと削除されます。↓↓

pic_2

それでは早速スタート!

1: プロジェクトの作成

XAMPPのインストール後、C:\xampp\htdocs に移動して、composerでプロジェクトを作成します。プロジェクト名は『basic-task』にします。

composer create-project --prefer-dist laravel/laravel basic-task

※ 因みに、現在は上記のコマンドだと最新の8系がインストールされるので、7系にする場合は、以下コマンドのようにバージョン指定が必要です。

composer create-project --prefer-dist laravel/laravel basic-task "7.*"

プロジェクトを作成したら、cd コマンドでプロジェクト内(C:\xampp\htdocs\basic-task)に移動します。因みに今回のLaravelのバージョンを確認したら下記のようになりました。

php artisan --version //Laravelバージョン確認用コマンド
Laravel Framework 7.11.0

2: データベースの作成

XAMPPでデータベースを作成します。(XAMPPでのデータベースの作り方がわからない人は、検索してみてください。) データベース名は『basic_task』にします。
データベースを作ったら、C:\xampp\htdocs\basic-task\.env ファイルに移動して、 DB_DATABASE を『basic_task』に変更します。DB_USERNAME と DB_PASSWORD はそのままにします。(XAMPP側でデータベース ユーザーを設定した人は、こちらも変更してください。)

basic-task\.env
DB_DATABASE=basic_task // ←ここ変更。
DB_USERNAME=root
DB_PASSWORD=

3: ロケールの設定

C:\xampp\htdocs\basic-task\config\app.php ファイルへ移動します。
'timezone' と 'locale' を以下のように変更します。

basic-task\config\app.php
'timezone' => 'Asia/Tokyo',
'locale' => 'ja',

4: マイグレーションファイルの作成

マイグレーションファイル (データベーステーブル)を作成します。テーブル名は『tasks』にします。 --create=tasks オプションをつけると、作成したマイグレーションファイルに対応したテーブルを作ってくれます。(XAMPP側でいちいちテーブルを作らなくてもOK!)

php artisan make:migration create_tasks_table --create=tasks

5: マイグレーションファイルの更新

作成したマイグレーションファイルを更新します。
C:\xampp\htdocs\basic-task\database\migrations\2020_05_19_021913_create_tasks_table.php ファイルへ移動します。(2020_05_19_021913 の部分は、作成した日付ですので、作成日によって変わります。)今回は極シンプルなアプリということもあり、nameカラムの追加のみです。18行目あたりに $table->string('name'); だけを追記します。

basic-task\database\migrations\2020_05_19_021913_create_tasks_table.php
    public function up()
   {
       Schema::create('tasks', function (Blueprint $table) {
           $table->id();
           $table->string('name'); //ここを追記。
           $table->timestamps();
       });
   }

追記したらマイグレーションします。

php artisan migrate

tasksテーブルに、nameカラムが入っていることを確認します。

image.png

6: モデルの作成

マイグレーションファイルに対応するモデルを作ります。
モデル名は『Task』にします。

php artisan make:model Task

C:\xampp\htdocs\basic-task\app\Task.php ファイルにモデルが作成されます。

7: ルートの設定

お次はルートの設定をします。C:\xampp\htdocs\basic-task\routes\web.php ファイルへと移動します。以下3つのルートを設定します。

①トップページへアクセスしたときに表示されるページ。(getリクエスト)
②新規追加フォームで追加ボタンを押した(=submitした)時にデータを飛ばすページ(postリクエスト)
※ フォームから飛んでくるデータはRequest型で渡ってきます。その為、コールバック関数の引数には、Implicit Bindingを利用して、(Request $request) とします。この辺りがよくわからない方は、『Laravel フォーム Request Implicit Binding』等で検索してみてください。
③削除ボタンを押した時にデータを飛ばすページ(deleteリクエスト)
以上の3つです。

basic-task\routes\web.php
Route::get('/', function () {
   //
});
Route::post('/task', function (Request $request) {
   //
});
Route::delete('/task/{task}', function () {
   //
});

8: BootstrapとFont Awesomeのインストール

viewページ作成の前に、BootstrapとFont Awesomeのインストールをしておきます。まずはBootstrapのインストールから。

composerを使って、laravel/ui パッケージをインストールします。

composer require laravel/ui

Artisanコマンドを利用して、Bootstrapのスカフォールドをインストールします。

php artisan ui bootstrap

package.json の "devDependencies"箇所に、以下のようにBootstrapが追加されます。

package.json
    "devDependencies": {
       "axios": "^0.19",
       "bootstrap": "^4.0.0", //Bootstrapが追加されています。
       "cross-env": "^7.0",
       "jquery": "^3.2",
       "laravel-mix": "^5.0.1",
       "lodash": "^4.17.13",
       "popper.js": "^1.12",
       "resolve-url-loader": "^3.1.0",
       "sass": "^1.15.2",
       "sass-loader": "^8.0.0",
       "vue-template-compiler": "^2.6.11"
   },

npmでインストールします。

npm install && npm run dev

これで、C:\xampp\htdocs\basic-task\public\css\app.css ファイルにコンパイルされてBootstrapが使えるようになります!

次はFont Awesomeをインストールします。まずはnpmでインストールします。

npm install --save @fortawesome/fontawesome-free

package.json の "dependencies" の箇所に、以下のようにFont Awesomeが追加されます。

package.json
    "dependencies": {
       "@fortawesome/fontawesome-free": "^5.13.0"
   }

C:\xampp\htdocs\basic-task\resources\sass\app.scss ファイルに移動して、以下の通りに追記してインポートします。

basic-task\resources\sass\app.scss
// Font Awesome
@import '~@fortawesome/fontawesome-free/scss/fontawesome';
@import '~@fortawesome/fontawesome-free/scss/regular';
@import '~@fortawesome/fontawesome-free/scss/solid';
@import '~@fortawesome/fontawesome-free/scss/brands';

npmで実行します。

npm run production

C:\xampp\htdocs\basic-task\public\css\app.css ファイルにコンパイルされてFont Awesomeが使えるようになります!

9:viewの作成

C:\xampp\htdocs\basic-task\resources\views フォルダ内に、
『tasks.blade.php』という名前で、手動で新規ファイルを作ります。今回、極シンプルなアプリなので、viewはトップページの1ページのみです。
ひとまず、新規追加フォーム箇所を作成して表示させてみます。
コードは以下の通りです。

basic-task\resources\views\tasks.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Basic Tasks</title>
 <link type="text/css" rel="stylesheet" href="{{ mix('css/app.css') }}">
</head>
<body>
 <div class="container">
   <h3 class="my-3">タスク管理ツール</h3>
   <div class="card mb-3">
     <div class="card-header">タスク新規追加</div>
     <div class="card-body">
       <form method="POST" action="{{ url('/task') }}">
         @csrf
         <div class="form-group">
           <input type="text" name="name" class="form-control">
           @if ($errors->has('name'))
           <p class="text-danger">{{ $errors->first('name') }}</p>
           @endif
           <button type="submit" class="btn btn-outline-info mt-2"><i class="fas fa-plus fa-lg mr-2"></i>追加</button>
         </div>
       </form>
     </div>
   </div>
 </div>
</body>
</html>

ルートファイル(C:\xampp\htdocs\basic-task\routes\web.php)のgetリクエスト部分を、tasks.blade.php ファイルが表示されるように、以下の通り更新します。

basic-task\routes\web.php
Route::get('/', function () {
   return view('tasks');
});

ブラウザを更新すると、以下のように表示されるはずです。

pic_4

tasks.blade.php ファイルのコードに関して何点か説明します。(HTMLの書き方や、Bootstrapの書き方等は説明致しませんので、分からない方はご自身で調べてみてください。)
10行目辺りの以下コードは、コンパイルしたBootstrapとFont Awesomeを読み込みます。

<link type="text/css" rel="stylesheet" href="{{ mix('css/app.css') }}">

上記はmix関数を使っていますが、以下のような書き方で、asset関数を使った書き方もできます。

<link type="text/css" rel="stylesheet" href="{{ asset('css/app.css') }}">

フォーム部分について説明します。Laravelでフォームを作成する場合は、必ずformタグの下に『@csrf』をつけてください。CSRF対策の為です。これを書かないと、419|Page Expired エラー等が起きる可能性があります。

<form method="POST" action="{{ url('/task') }}">
@csrf

以下の部分はエラー変数を使っています。Laravelでは、エラーが出ると直前のページへとリダイレクトされます。その為、その時に(今回の場合だと、submitしたら '/task' に飛ばすので、その直前のページ、つまりトップページです。)定義済みエラー変数を設定することができます。

@if ($errors->has('name'))
<p class="text-danger">{{ $errors->first('name') }}</p>
@endif

<p>タグ部分を、@if ($errors->has('name')) ~ @endif で囲わずに、『<p class="text-danger">{{ $errors->first('name') }}</p>』の部分だけでも動作します。しかし、このエラー変数はどこでも使用可能な為、ifで囲わないとブラウザからソースを表示したときに、<p>タグが表示されます。(以下画像の赤枠部分です。)そこで、エラーが出た時だけ表示させるようにするには、ifで囲みます。

image.png

10:ルートの更新

まずはpostリクエストのルート設定を更新します。コードは以下の通りです。

Route::post('/task', function (Request $request) {
   request()->validate(
       [
           'name' => 'required|unique:tasks|min:3|max:255'
       ],
       [
           'name.required' => 'タスク内容を入力してください。',
           'name.unique' => 'そのタスクは既に追加されています。',
           'name.min' => '3文字以上で入力してください。',
           'name.max' => '255文字以内で入力してください。'
       ]
   );
   $task = new Task();
   $task->name = request('name');
   $task->save();
   return redirect('/');
});

request()->validate( ) の箇所は、バリデートをかけている(入力項目をチェックする)部分です。今回は、『入力必須で、ユニークであること、3文字以上であること、255文字以内であること』を設定しています。また、続けて上記のように配列を追加すると、エラーメッセージを好きなようにカスタマイズすることができます。デフォルトのメッセージは、C:\xampp\htdocs\basic-task\resources\lang\ja\validation.php ファイル内に書かれている英語表記のものです。

image.png

バリデーションの後は、コードの通りですが、以下の通りになります。
① Taskモデルのインスタンス化
\$task = new Task();
② request()ヘルパー関数を利用して、viewファイルのinputタグの名前がnameというデータを格納
\$task->name = request('name');
③ 最後に保存して、トップページにリダイレクト
\$task->save();
return redirect('/');

次は、getリクエストのルート設定も更新します。コードは以下の通りです。

Route::get('/', function () {
   return view('tasks', [
       'tasks' => App\Task::latest()->get()
   ]);
});

『トップページにアクセスしたら、'tasks'ページを表示して、'tasks'という変数を最新のものから降順にして、viewに渡しますよ』という意味です。因みに、ここでは'tasks'という変数は、viewファイルの方では『\$tasks』という表記で$マーク付きになりますので、混同しないようにしましょう。私も最初は混乱しました!ww

11: viewを完成させる

getリクエストとpostリクエストのルート設定が終わったら、viewファイルを完成させてしまいます。タスク一覧と、削除ボタンを表示する箇所です。コードは以下の通りです。(全ソースコードはこの後に載せていますので、全体像はそちらでご確認ください。)

    <div class="card">
     <div class="card-header">タスク一覧</div>
     <div class="card-body">
       @if (count($tasks) > 0)
       <table class="table table-striped">
         <tbody>
           @foreach ($tasks as $task)
           <tr>
             <td>{{ $task->name }}</td>
             <td>
               <form method="POST" action="{{ url('/task/' . $task->id) }}">
                 @csrf
                 @method('DELETE')
                 <button type="submit" class="btn btn-outline-danger" style="width: 100px;"><i class="far fa-trash-alt"></i> 削除</button>
               </form>
             </td>
           </tr>
           @endforeach
         </tbody>
       </table>
       @endif
     </div>
   </div>

上記のコードについて何点か説明します。まず@if (count(\$tasks) > 0) の箇所は、このように書くことで、タスクがあれば表示するというようにしております。@foreach (\$tasks as \$task) 箇所では、ルートで設定したように、最新のものを降順で、且つ@foreachを使うことによって、一つずつ表示するように設定しています。

12:ルートを完成させる

最後に、削除ボタンを押したときのルート設定をします。コードは以下の通りです。

Route::delete('/task/{task}', function (Task $task) {
   $task->delete();
   return redirect('/');
});

delete('/task/{task}' の、{task}にはTaskインスタンスのidが入ってきます。また、Taskインスタンスが渡ってくるので、Implicit Bindingでコールバック関数の引数には (Task \$task) を渡してあげます。この際、delete('/task/{task}' の{task} と、(Task \$task) の \$task は同じ名前にしないといけません。

以上で全行程が終了です!お疲れさまでした!
最後に、viewファイル、ルートファイル、マイグレーションファイルのソースコードを以下に載せておりますので、全体像のチェック等、参考にしてください!
それではまた第2回でお会いしましょうヽ(´ー`)ノ マタネ~。

basic-task\resources\views\tasks.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Basic Tasks</title>
 <!-- <link type="text/css" rel="stylesheet" href="{{ asset('css/app.css') }}"> -->
 <link type="text/css" rel="stylesheet" href="{{ mix('css/app.css') }}">
</head>
<body>
 <div class="container">
   <h3 class="my-3">タスク管理ツール</h3>
   <div class="card mb-3">
     <div class="card-header">タスク新規追加</div>
     <div class="card-body">
       <form method="POST" action="{{ url('/task') }}">
         @csrf
         <div class="form-group">
           <input type="text" name="name" class="form-control">
           @if ($errors->has('name'))
           <p class="text-danger">{{ $errors->first('name') }}</p>
           @endif
           <button type="submit" class="btn btn-outline-info mt-2"><i class="fas fa-plus fa-lg mr-2"></i>追加</button>
         </div>
       </form>
     </div>
   </div>
   <div class="card">
     <div class="card-header">タスク一覧</div>
     <div class="card-body">
       @if (count($tasks) > 0)
       <table class="table table-striped">
         <tbody>
           @foreach ($tasks as $task)
           <tr>
             <td>{{ $task->name }}</td>
             <td>
               <form method="POST" action="{{ url('/task/' . $task->id) }}">
                 @csrf
                 @method('DELETE')
                 <button type="submit" class="btn btn-outline-danger" style="width: 100px;"><i class="far fa-trash-alt"></i> 削除</button>
               </form>
             </td>
           </tr>
           @endforeach
         </tbody>
       </table>
       @endif
     </div>
   </div>
 </div>
</body>
</html>
basic-task\routes\web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Task;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
   return view('tasks', [
       'tasks' => App\Task::latest()->get()
   ]);
});

Route::post('/task', function (Request $request) {
   request()->validate(
       [
           'name' => 'required|unique:tasks|min:3|max:255'
       ],
       [
           'name.required' => 'タスク内容を入力してください。',
           'name.unique' => 'そのタスクは既に追加されています。',
           'name.min' => '3文字以上で入力してください。',
           'name.max' => '255文字以内で入力してください。'
       ]
   );
   $task = new Task();
   $task->name = request('name');
   $task->save();
   return redirect('/');
});

Route::delete('/task/{task}', function (Task $task) {
   $task->delete();
   return redirect('/');
});
basic-task\database\migrations\2020_05_19_021913_create_tasks_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTasksTable extends Migration
{
   /**
    * Run the migrations.
    *
    * @return void
    */
   public function up()
   {
       Schema::create('tasks', function (Blueprint $table) {
           $table->id();
           $table->string('name');
           $table->timestamps();
       });
   }
   /**
    * Reverse the migrations.
    *
    * @return void
    */
   public function down()
   {
       Schema::dropIfExists('tasks');
   }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Laravel]超基礎☆簡単タスク管理アプリのチュートリアル

(※ この記事は、Laravel8が出るより結構前に書いて、他のブログに載せていました。それを転載したものなので、Laravel7で解説しています。ご了承くださいませ。。(m´・ω・`)m ゴメン…)

環境:XAMPP

初めてLaravelで何かアプリを作ってみようと思って、公式ドキュメントにも載っている簡単なタスク管理アプリを作ることにしました!
自分への備忘録も兼ねて、チュートリアル的な感じで解説していこうと思います。同じく初Laravel製アプリを作ろうとしている方や、Laravel勉強中の初学者の方に参考になれば幸いです!

完成品は以下のような感じです。↓↓

pic_1

新規追加でタスクを入力すると、タスク一覧に表示されて、削除ボタンを押すと削除されます。↓↓

pic_2

それでは早速スタート!

1: プロジェクトの作成

XAMPPのインストール後、C:\xampp\htdocs に移動して、composerでプロジェクトを作成します。プロジェクト名は『basic-task』にします。

composer create-project --prefer-dist laravel/laravel basic-task

※ 因みに、現在は上記のコマンドだと最新の8系がインストールされるので、7系にする場合は、以下コマンドのようにバージョン指定が必要です。

composer create-project --prefer-dist laravel/laravel basic-task "7.*"

プロジェクトを作成したら、cd コマンドでプロジェクト内(C:\xampp\htdocs\basic-task)に移動します。因みに今回のLaravelのバージョンを確認したら下記のようになりました。

php artisan --version //Laravelバージョン確認用コマンド
Laravel Framework 7.11.0

2: データベースの作成

XAMPPでデータベースを作成します。(XAMPPでのデータベースの作り方がわからない人は、検索してみてください。) データベース名は『basic_task』にします。
データベースを作ったら、C:\xampp\htdocs\basic-task\.env ファイルに移動して、 DB_DATABASE を『basic_task』に変更します。DB_USERNAME と DB_PASSWORD はそのままにします。(XAMPP側でデータベース ユーザーを設定した人は、こちらも変更してください。)

basic-task\.env
DB_DATABASE=basic_task // ←ここ変更。
DB_USERNAME=root
DB_PASSWORD=

3: ロケールの設定

C:\xampp\htdocs\basic-task\config\app.php ファイルへ移動します。
'timezone' と 'locale' を以下のように変更します。

basic-task\config\app.php
'timezone' => 'Asia/Tokyo',
'locale' => 'ja',

4: マイグレーションファイルの作成

マイグレーションファイル (データベーステーブル)を作成します。テーブル名は『tasks』にします。 --create=tasks オプションをつけると、作成したマイグレーションファイルに対応したテーブルを作ってくれます。(XAMPP側でいちいちテーブルを作らなくてもOK!)

php artisan make:migration create_tasks_table --create=tasks

5: マイグレーションファイルの更新

作成したマイグレーションファイルを更新します。
C:\xampp\htdocs\basic-task\database\migrations\2020_05_19_021913_create_tasks_table.php ファイルへ移動します。(2020_05_19_021913 の部分は、作成した日付ですので、作成日によって変わります。)今回は極シンプルなアプリということもあり、nameカラムの追加のみです。18行目あたりに $table->string('name'); だけを追記します。

basic-task\database\migrations\2020_05_19_021913_create_tasks_table.php
    public function up()
   {
       Schema::create('tasks', function (Blueprint $table) {
           $table->id();
           $table->string('name'); //ここを追記。
           $table->timestamps();
       });
   }

追記したらマイグレーションします。

php artisan migrate

tasksテーブルに、nameカラムが入っていることを確認します。

image.png

6: モデルの作成

マイグレーションファイルに対応するモデルを作ります。
モデル名は『Task』にします。

php artisan make:model Task

C:\xampp\htdocs\basic-task\app\Task.php ファイルにモデルが作成されます。

7: ルートの設定

お次はルートの設定をします。C:\xampp\htdocs\basic-task\routes\web.php ファイルへと移動します。以下3つのルートを設定します。

①トップページへアクセスしたときに表示されるページ。(getリクエスト)
②新規追加フォームで追加ボタンを押した(=submitした)時にデータを飛ばすページ(postリクエスト)
※ フォームから飛んでくるデータはRequest型で渡ってきます。その為、コールバック関数の引数には、Implicit Bindingを利用して、(Request $request) とします。この辺りがよくわからない方は、『Laravel フォーム Request Implicit Binding』等で検索してみてください。
③削除ボタンを押した時にデータを飛ばすページ(deleteリクエスト)
以上の3つです。

basic-task\routes\web.php
Route::get('/', function () {
   //
});
Route::post('/task', function (Request $request) {
   //
});
Route::delete('/task/{task}', function () {
   //
});

8: BootstrapとFont Awesomeのインストール

viewページ作成の前に、BootstrapとFont Awesomeのインストールをしておきます。まずはBootstrapのインストールから。

composerを使って、laravel/ui パッケージをインストールします。

composer require laravel/ui

Artisanコマンドを利用して、Bootstrapのスカフォールドをインストールします。

php artisan ui bootstrap

package.json の "devDependencies"箇所に、以下のようにBootstrapが追加されます。

package.json
    "devDependencies": {
       "axios": "^0.19",
       "bootstrap": "^4.0.0", //Bootstrapが追加されています。
       "cross-env": "^7.0",
       "jquery": "^3.2",
       "laravel-mix": "^5.0.1",
       "lodash": "^4.17.13",
       "popper.js": "^1.12",
       "resolve-url-loader": "^3.1.0",
       "sass": "^1.15.2",
       "sass-loader": "^8.0.0",
       "vue-template-compiler": "^2.6.11"
   },

npmでインストールします。

npm install && npm run dev

これで、C:\xampp\htdocs\basic-task\public\css\app.css ファイルにコンパイルされてBootstrapが使えるようになります!

次はFont Awesomeをインストールします。まずはnpmでインストールします。

npm install --save @fortawesome/fontawesome-free

package.json の "dependencies" の箇所に、以下のようにFont Awesomeが追加されます。

package.json
    "dependencies": {
       "@fortawesome/fontawesome-free": "^5.13.0"
   }

C:\xampp\htdocs\basic-task\resources\sass\app.scss ファイルに移動して、以下の通りに追記してインポートします。

basic-task\resources\sass\app.scss
// Font Awesome
@import '~@fortawesome/fontawesome-free/scss/fontawesome';
@import '~@fortawesome/fontawesome-free/scss/regular';
@import '~@fortawesome/fontawesome-free/scss/solid';
@import '~@fortawesome/fontawesome-free/scss/brands';

npmで実行します。

npm run production

C:\xampp\htdocs\basic-task\public\css\app.css ファイルにコンパイルされてFont Awesomeが使えるようになります!

9:viewの作成

C:\xampp\htdocs\basic-task\resources\views フォルダ内に、
『tasks.blade.php』という名前で、手動で新規ファイルを作ります。今回、極シンプルなアプリなので、viewはトップページの1ページのみです。
ひとまず、新規追加フォーム箇所を作成して表示させてみます。
コードは以下の通りです。

basic-task\resources\views\tasks.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Basic Tasks</title>
 <link type="text/css" rel="stylesheet" href="{{ mix('css/app.css') }}">
</head>
<body>
 <div class="container">
   <h3 class="my-3">タスク管理ツール</h3>
   <div class="card mb-3">
     <div class="card-header">タスク新規追加</div>
     <div class="card-body">
       <form method="POST" action="{{ url('/task') }}">
         @csrf
         <div class="form-group">
           <input type="text" name="name" class="form-control">
           @if ($errors->has('name'))
           <p class="text-danger">{{ $errors->first('name') }}</p>
           @endif
           <button type="submit" class="btn btn-outline-info mt-2"><i class="fas fa-plus fa-lg mr-2"></i>追加</button>
         </div>
       </form>
     </div>
   </div>
 </div>
</body>
</html>

ルートファイル(C:\xampp\htdocs\basic-task\routes\web.php)のgetリクエスト部分を、tasks.blade.php ファイルが表示されるように、以下の通り更新します。

basic-task\routes\web.php
Route::get('/', function () {
   return view('tasks');
});

ブラウザを更新すると、以下のように表示されるはずです。

pic_4

tasks.blade.php ファイルのコードに関して何点か説明します。(HTMLの書き方や、Bootstrapの書き方等は説明致しませんので、分からない方はご自身で調べてみてください。)
10行目辺りの以下コードは、コンパイルしたBootstrapとFont Awesomeを読み込みます。

<link type="text/css" rel="stylesheet" href="{{ mix('css/app.css') }}">

上記はmix関数を使っていますが、以下のような書き方で、asset関数を使った書き方もできます。

<link type="text/css" rel="stylesheet" href="{{ asset('css/app.css') }}">

フォーム部分について説明します。Laravelでフォームを作成する場合は、必ずformタグの下に『@csrf』をつけてください。CSRF対策の為です。これを書かないと、419|Page Expired エラー等が起きる可能性があります。

<form method="POST" action="{{ url('/task') }}">
@csrf

以下の部分はエラー変数を使っています。Laravelでは、エラーが出ると直前のページへとリダイレクトされます。その為、その時に(今回の場合だと、submitしたら '/task' に飛ばすので、その直前のページ、つまりトップページです。)定義済みエラー変数を設定することができます。

@if ($errors->has('name'))
<p class="text-danger">{{ $errors->first('name') }}</p>
@endif

<p>タグ部分を、@if ($errors->has('name')) ~ @endif で囲わずに、『<p class="text-danger">{{ $errors->first('name') }}</p>』の部分だけでも動作します。しかし、このエラー変数はどこでも使用可能な為、ifで囲わないとブラウザからソースを表示したときに、<p>タグが表示されます。(以下画像の赤枠部分です。)そこで、エラーが出た時だけ表示させるようにするには、ifで囲みます。

image.png

10:ルートの更新

まずはpostリクエストのルート設定を更新します。コードは以下の通りです。

Route::post('/task', function (Request $request) {
   request()->validate(
       [
           'name' => 'required|unique:tasks|min:3|max:255'
       ],
       [
           'name.required' => 'タスク内容を入力してください。',
           'name.unique' => 'そのタスクは既に追加されています。',
           'name.min' => '3文字以上で入力してください。',
           'name.max' => '255文字以内で入力してください。'
       ]
   );
   $task = new Task();
   $task->name = request('name');
   $task->save();
   return redirect('/');
});

request()->validate( ) の箇所は、バリデートをかけている(入力項目をチェックする)部分です。今回は、『入力必須で、ユニークであること、3文字以上であること、255文字以内であること』を設定しています。また、続けて上記のように配列を追加すると、エラーメッセージを好きなようにカスタマイズすることができます。デフォルトのメッセージは、C:\xampp\htdocs\basic-task\resources\lang\ja\validation.php ファイル内に書かれている英語表記のものです。

image.png

バリデーションの後は、コードの通りですが、以下の通りになります。
① Taskモデルのインスタンス化
\$task = new Task();
② request()ヘルパー関数を利用して、viewファイルのinputタグの名前がnameというデータを格納
\$task->name = request('name');
③ 最後に保存して、トップページにリダイレクト
\$task->save();
return redirect('/');

次は、getリクエストのルート設定も更新します。コードは以下の通りです。

Route::get('/', function () {
   return view('tasks', [
       'tasks' => App\Task::latest()->get()
   ]);
});

『トップページにアクセスしたら、'tasks'ページを表示して、'tasks'という変数を最新のものから降順にして、viewに渡しますよ』という意味です。因みに、ここでは'tasks'という変数は、viewファイルの方では『\$tasks』という表記で$マーク付きになりますので、混同しないようにしましょう。私も最初は混乱しました!ww

11: viewを完成させる

getリクエストとpostリクエストのルート設定が終わったら、viewファイルを完成させてしまいます。タスク一覧と、削除ボタンを表示する箇所です。コードは以下の通りです。(全ソースコードはこの後に載せていますので、全体像はそちらでご確認ください。)

    <div class="card">
     <div class="card-header">タスク一覧</div>
     <div class="card-body">
       @if (count($tasks) > 0)
       <table class="table table-striped">
         <tbody>
           @foreach ($tasks as $task)
           <tr>
             <td>{{ $task->name }}</td>
             <td>
               <form method="POST" action="{{ url('/task/' . $task->id) }}">
                 @csrf
                 @method('DELETE')
                 <button type="submit" class="btn btn-outline-danger" style="width: 100px;"><i class="far fa-trash-alt"></i> 削除</button>
               </form>
             </td>
           </tr>
           @endforeach
         </tbody>
       </table>
       @endif
     </div>
   </div>

上記のコードについて何点か説明します。まず@if (count(\$tasks) > 0) の箇所は、このように書くことで、タスクがあれば表示するというようにしております。@foreach (\$tasks as \$task) 箇所では、ルートで設定したように、最新のものを降順で、且つ@foreachを使うことによって、一つずつ表示するように設定しています。

12:ルートを完成させる

最後に、削除ボタンを押したときのルート設定をします。コードは以下の通りです。

Route::delete('/task/{task}', function (Task $task) {
   $task->delete();
   return redirect('/');
});

delete('/task/{task}' の、{task}にはTaskインスタンスのidが入ってきます。また、Taskインスタンスが渡ってくるので、Implicit Bindingでコールバック関数の引数には (Task \$task) を渡してあげます。この際、delete('/task/{task}' の{task} と、(Task \$task) の \$task は同じ名前にしないといけません。

以上で全行程が終了です!お疲れさまでした!
最後に、viewファイル、ルートファイル、マイグレーションファイルのソースコードを以下に載せておりますので、全体像のチェック等、参考にしてください!
それではまた第2回でお会いしましょうヽ(´ー`)ノ マタネ~。

basic-task\resources\views\tasks.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Basic Tasks</title>
 <!-- <link type="text/css" rel="stylesheet" href="{{ asset('css/app.css') }}"> -->
 <link type="text/css" rel="stylesheet" href="{{ mix('css/app.css') }}">
</head>
<body>
 <div class="container">
   <h3 class="my-3">タスク管理ツール</h3>
   <div class="card mb-3">
     <div class="card-header">タスク新規追加</div>
     <div class="card-body">
       <form method="POST" action="{{ url('/task') }}">
         @csrf
         <div class="form-group">
           <input type="text" name="name" class="form-control">
           @if ($errors->has('name'))
           <p class="text-danger">{{ $errors->first('name') }}</p>
           @endif
           <button type="submit" class="btn btn-outline-info mt-2"><i class="fas fa-plus fa-lg mr-2"></i>追加</button>
         </div>
       </form>
     </div>
   </div>
   <div class="card">
     <div class="card-header">タスク一覧</div>
     <div class="card-body">
       @if (count($tasks) > 0)
       <table class="table table-striped">
         <tbody>
           @foreach ($tasks as $task)
           <tr>
             <td>{{ $task->name }}</td>
             <td>
               <form method="POST" action="{{ url('/task/' . $task->id) }}">
                 @csrf
                 @method('DELETE')
                 <button type="submit" class="btn btn-outline-danger" style="width: 100px;"><i class="far fa-trash-alt"></i> 削除</button>
               </form>
             </td>
           </tr>
           @endforeach
         </tbody>
       </table>
       @endif
     </div>
   </div>
 </div>
</body>
</html>
basic-task\routes\web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Task;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
   return view('tasks', [
       'tasks' => App\Task::latest()->get()
   ]);
});

Route::post('/task', function (Request $request) {
   request()->validate(
       [
           'name' => 'required|unique:tasks|min:3|max:255'
       ],
       [
           'name.required' => 'タスク内容を入力してください。',
           'name.unique' => 'そのタスクは既に追加されています。',
           'name.min' => '3文字以上で入力してください。',
           'name.max' => '255文字以内で入力してください。'
       ]
   );
   $task = new Task();
   $task->name = request('name');
   $task->save();
   return redirect('/');
});

Route::delete('/task/{task}', function (Task $task) {
   $task->delete();
   return redirect('/');
});
basic-task\database\migrations\2020_05_19_021913_create_tasks_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTasksTable extends Migration
{
   /**
    * Run the migrations.
    *
    * @return void
    */
   public function up()
   {
       Schema::create('tasks', function (Blueprint $table) {
           $table->id();
           $table->string('name');
           $table->timestamps();
       });
   }
   /**
    * Reverse the migrations.
    *
    * @return void
    */
   public function down()
   {
       Schema::dropIfExists('tasks');
   }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP 基本文法まとめ 後編

後編は、if文while文for文foreach文の紹介をします。

if文

if (条件式) {
   // 条件がfalseの場合に実行される。
} else {
  // 条件式がtrueの場合に実行される。
}

if (条件式) {
   // 条件がfalseの場合に実行される。
} elseif (条件式) {
   // 条件がfalseの場合に実行される。
}else {
   // 条件式がtrueの場合に実行される。
}

$name = '佐藤';  // 変数に佐藤を代入。
if ($name === '加藤') {  // $nameに加藤が入ってる場合、「加藤です。」を表示する。

    echo '加藤です';

} elseif ($name === '成田') {

    echo '成田です';

} elseif ($name === '佐藤') {

    echo '佐藤です';

} else {

    echo '名前がありません。';

}

if文 = 制御を行う構文の一つで、条件式が真(false)の時・偽の時(true)で、
    条件を書くことでプログラムを制御することができる。

while文

while (条件式) {
  // 条件式がfalseである場合ずっとwhile文内の処理が繰り返し実行される。
}


$number = 0; // 変数に0を代入。
while ($number <= 100) {  // $numberが100になるまで処理を続ける。
   echo $number;     // 現在$numeberに入っている数字を表示。
   $number++;      // $numberに1を足す。
} 

↓

0
1
・
・
100 //0から100まで表示される。

while文 = 制御構文の一つで、条件式が偽(true)になるまで{ } 内に書かれた処理を繰り返し実行する

$number = 1;
while($number <= 100) {

   // $numberが9の時ループから抜ける。
     if ($number === 9) { 
         break;
     }

   // $numberが3で割り切れる時$numberに1を足してスキップする。
     if ($number % 3 === 0) { 
         $number++;
         continue;
     }

     // $numberが100になるまで、$numberを表示して、$numberに1を足す。
     echo $number . "\n";
     $count++;
}

whileと一緒によく使われる構文で、breakcontinueがあります。
break = ループ処理から抜ける、強制的に終了する
continue = 条件判定が真(false)の時に処理をスキップする

for文

for (初期化式; 条件式; 反復式) {
    // 処理内容
}

$name = array(
   '佐藤', '加藤', '鈴木', '成田', '渡辺'
);

// $iが5になるまで$nameを表示。(5人分の名前が表示される。)
for ($i = 0; $i < 5; $i++) {
     echo $name[$i];
}

for = 反復処理を行うのに便利な構文で、初期化式・条件式・反復式がある。
①初期化式を実行。
②条件式が真(false)であれば処理を実行
     偽(true)であれば処理を実行せず、forの動作は終了です。
③中の処理を実行し、反復式を実行します。
④②からを繰り返す。

foreach文

foreach (配列 or オブジェクト as 要素) {
   // 処理内容
}

$name = array(
    '佐藤', '加藤', '鈴木', '成田', '渡辺'
);

foreach ($name as $row) { // $nameの中身を順番に$rowに入れて表示。
     echo $row; // 5人の名前が表示される。
}

foreach = 配列やオブジェクトを反復処理するのに便利な構文。
       for文とは違い、反復回数は制限せずに、配列の中身全てに処理を実行する

参考元はこちら
https://creive.me/archives/8719/#PHP)

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

composerという依存性管理パッケージツールのありがたみ

はじめに

最近、チームで開発することになりPHPのフレームワークのLaravelを使用しているのですが、その時に使用するcomposerが改めて便利だなと思った話。

  1. composerとは
  2. composerを使用してみよう
  3. まとめ

composerとは

composerは依存管理パッケージツールと呼ばれています。どういう意味かというと

Aというライブラリを使用しようとすると、他にBが必要でBを使用するとCが必要でと、どんどん必要なものが増えていきます。

そんな、面倒なことを一気に解決してくれるのがcomposerです。

composerの利点

composer.lockがあるのでチームでの開発が楽になる。composer.lockにはcomposer.jsonに書かれたライブラリを取得するために、どのようなファイルを落としてきたかだまとめられているファイルです。なのでチームで開発する時に、composer installというコマンドを入力すると他のチームと同じ開発の環境にしてくれます。

オートロード機能がある。例えば、ライブラリを使用したいとしてこのファイルとこのファイルを読み込みといったことをしなくてよく。/vendor/autoload.phpを読み込んであげるとそんなめんどくさいことをしなくよくなります。

このように利点がいくつかあります。

composerを使用してみよう

それでは、実際に使用してみましょう。始める方法は沢山あるのですがそのうちの一つを今回はやります。
(composerはあらかじめ自分の環境で使用できる状態にして下さい)

最初に、自分が作業するフォルダに移動しcomposer.jsonというファイルを作成します。

{
   "require": {
      "phpmailer/phpmailer": "*"
   }
}

そして、上記の内容を記述して下さい。
まず、composer.jsonには自分が取得するライブラリの名前をrequireに記述します。ベンダー名/プロジェクト名:バージョンになります。バージョンには今回はワイルドカードを設定します。
次にコマンドでcomposer installを入力します。するとフォルダ内にvendorとcomposer.lockが作成されました。
composer installは、composer.jsonに記載されている内容もしくはcomposer.lockに記載されている内容に従って、パッケージをインストールします。
composer lockはcomposer.jsonにあるライブラリを取得するために、どのようなファイルを落としてきたかが書かれています。
後は、自分が作業しているファイルにライブライを読み込んであげることで使用することが出来ます。

まとめ

このように、composerがあるおかげてチームで開発するのも楽になります。また、依存関係を気にせずに自分の環境にライブラリを落とすことができます。

参考文献

https://getcomposer.org/

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

composer様という依存性管理パッケージツールのありがたみ

はじめに

最近、チームで開発することになりPHPのフレームワークのLaravelを使用しているのですが、その時に使用するcomposerが改めて便利だなと思った話。

  1. composerとは
  2. composerを使用してみよう
  3. まとめ

composerとは

composerは依存管理パッケージツールと呼ばれています。どういう意味かというと

Aというライブラリを使用しようとすると、他にBが必要でBを使用するとCが必要でと、どんどん必要なものが増えていきます。

そんな、面倒なことを一気に解決してくれるのがcomposerです。

composerの利点

composer.lockがあるのでチームでの開発が楽になる。composer.lockにはcomposer.jsonに書かれたライブラリを取得するために、どのようなファイルを落としてきたかだまとめられているファイルです。なのでチームで開発する時に、composer installというコマンドを入力すると他のチームと同じ開発の環境にしてくれます。

オートロード機能がある。例えば、ライブラリを使用したいとしてこのファイルとこのファイルを読み込みといったことをしなくてよく。/vendor/autoload.phpを読み込んであげるとそんなめんどくさいことをしなくよくなります。

このように利点がいくつかあります。

composerを使用してみよう

それでは、実際に使用してみましょう。始める方法は沢山あるのですがそのうちの一つを今回はやります。
(composerはあらかじめ自分の環境で使用できる状態にして下さい)

最初に、自分が作業するフォルダに移動しcomposer.jsonというファイルを作成します。

{
   "require": {
      "phpmailer/phpmailer": "*"
   }
}

そして、上記の内容を記述して下さい。

composer.json

まず、composer.jsonには自分が取得するライブラリの名前をrequireに記述します。ベンダー名/プロジェクト名:バージョンになります。バージョンには今回はワイルドカードを設定します。
次にコマンドでcomposer installを入力します。するとフォルダ内にvendorとcomposer.lockが作成されました。

composer install

composer installは、composer.jsonに記載されている内容もしくはcomposer.lockに記載されている内容に従って、パッケージをインストールします。

composer.lock

composer.lockはcomposer.jsonにあるライブラリを取得するために、どのようなファイルを落としてきたかが書かれています。
vendorにはインストールしたライブライが入っています。

後は、自分が作業しているファイルにライブライを読み込んであげることで使用することが出来ます。

<?php

require '/vendor/autoload.php';

#自分が使用したいライブライを使用

?>

まとめ

このように、composerがあるおかげてチームで開発するのも楽になります。また、依存関係を気にせずに自分の環境にライブラリを落とすことができます。

参考文献

https://getcomposer.org/

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

PHP+MySQL

PHP+MySQLを使用した基礎知識についてのまとめです。

PDO - MySQLに接続する

try catchを使って記述します。

フォルダの中に以下のファイルを用意。

index.php
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<pre>
<?php
//以下の記述でPHPからDBに接続できる。MAMPの場合、パスワードはrootになる。
try{
  //new PDO(DBを扱う)でオブジェクトのインスタンスを作っている。
  $db = new PDO ('mysql:dbname=mydb;host=127.0.0.1;port=8889;charset=utf8', 'root', 'root');
  //接続できなければ$eという形で受け取り、それを画面に出力する。
}catch(PDOException $e){
  echo 'DB接続エラー:' . $e->getMessage();
}
?>
</pre>
</main>
</body>    
</html>

exec - SQLを実行する

PHPからDBにSQLを発行する。
以下の記述でDBにデータを追加できる。

index.php
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<pre>
<?php
try{
  $db = new PDO ('mysql:dbname=mydb;host=127.0.0.1;port=8889;charset=utf8', 'root', 'root');
}catch(PDOException $e){
  echo 'DB接続エラー:' . $e->getMessage();
}

//以下の記述でmy_itemテーブルにデータを追加。
$count = $db->exec('INSERT INTO my_item SET maker_id=1,item_name="桃",price=210,keyword="缶詰,ピンク,甘い"');
//$countでデータの数を返す。
echo $count . '件のデータを挿入しました';
?>
</pre>
</main>
</body>    
</html>

query - SELECT SQLを実行する

<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<pre>
<?php
//以下の記述でPHPからDBに接続できる。MAMPの場合、パスワードはrootになる。
try{
  //new PDO(DBを扱う)でオブジェクトのインスタンスを作っている。
  $db = new PDO ('mysql:dbname=mydb;host=127.0.0.1;port=8889;charset=utf8', 'root', 'root');
  //接続できなければ$eという形で受け取り、それを画面に出力する。
}catch(PDOException $e){
  echo 'DB接続エラー:' . $e->getMessage();
}
//以下の記述でrecordsという変数の中にdbの内容が入っている。
$records=$db->query('SELECT * FROM my_item');
//while構文を使って取り出していく。1行ずつ取り出してそれを$recordに入れている。
while($record=$records->fetch()){
  print($record['item_name']."\n");
}
?>
</pre>
</main>
</body>    
</html>

これにより、DBの情報が表示される。
スクリーンショット 2020-11-11 18.21.01.png

フォームからの情報を取得する

以下のように記載。

<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<pre>
   <?php
   try{
     //PDOのはデータベースの種類や接続文字列などを入力する。
   $db=new  PDO('mysql:dbname=mydb;host=127.0.0.1;port=8889;charset=utf8', 'root', 'root');
   $db->exec('INSERT INTO memos SET memo="'.$_POST['memo'].'",created_at=NOW()');
   }catch(PDOException $e){
     echo 'DB接続エラー:'.$e->getMessage();
   }
   ?>
</pre>
</main>

</body>    
</html>

①input.htmlにアクセスしてメモに文字を入力。
スクリーンショット 2020-11-11 21.04.45.png
②input_do.phpにアクセスして何も表示されなければデータは登録されている。
③文字接続エラーが出ればPDOの中身の記載が間違っている。

しかし、上記のプログラムはまだ危険な状態なので安全に設定する必要がある。

//postの値がそのまま指定されているため、SQLが意図的に壊されてDBの中身を盗まれてします恐れがある。
$db->exec('INSERT INTO memos SET memo="'.$_POST['memo'].'",created_at=NOW()')

それを解決するためにprepareメソッドを使う。

<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<pre>
   <?php
   try{
     //PDOのはデータベースの種類や接続文字列などを入力する。
   $db=new  PDO('mysql:dbname=mydb;host=127.0.0.1;port=8889;charset=utf8', 'root', 'root');
   //?をいれる。prepareでセキュリティ対策
   $statement=$db->prepare('INSERT INTO memos SET memo=?,created_at=NOW()');
   $statement->execute(array($_POST['memo']));
   echo 'メッセージが登録されました';
   }catch(PDOException $e){
     echo 'DB接続エラー:'.$e->getMessage();
   }
   ?>
</pre>
</main>

</body>    
</html>

input.html
スクリーンショット 2020-11-11 21.20.23.png

input_do.php
スクリーンショット 2020-11-11 21.20.57.png

データの一覧・詳細画面を作る

phpmyadiminを使わずに画面で見れるようにする。
ファイル名をmemo.phpとする。

memo.php
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="../css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<?php
//以下の記述でPHPからDBに接続できる。MAMPの場合、パスワードはrootになる。
try{
  //new PDO(DBを扱う)でオブジェクトのインスタンスを作っている。
  $db = new PDO ('mysql:dbname=mydb;host=127.0.0.1;port=8889;charset=utf8', 'root', 'root');
  //接続できなければ$eという形で受け取り、それを画面に出力する。
}catch(PDOException $e){
  echo 'DB接続エラー:' . $e->getMessage();
}
//以下の記述でmemosという変数の中idが1のdbの内容が入っている。
$memos = $db->query('SELECT * FROM memos WHERE id=1');
$memo = $memos->fetch();
?>
<article>
  <pre><?php print($memo['memo']);?></pre>
  <a href="index.php">戻る</a>
</article>
</main>
</body>    
</html>

memo.php/1にアクセスすると1番目の詳細がみれる。
スクリーンショット 2020-11-11 22.01.24.png

一覧画面と詳細画面の連携

IDの部分を自由にしたい場合

<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<?php
//以下の記述でPHPからDBに接続できる。MAMPの場合、パスワードはrootになる。
try{
  //new PDO(DBを扱う)でオブジェクトのインスタンスを作っている。
  $db = new PDO ('mysql:dbname=mydb;host=127.0.0.1;port=8889;charset=utf8', 'root', 'root');
  //接続できなければ$eという形で受け取り、それを画面に出力する。
}catch(PDOException $e){
  echo 'DB接続エラー:' . $e->getMessage();
}
//以下の記述でrecordsという変数の中にdbの内容が入っている。
$memos = $db->query('SELECT * FROM memos ORDER BY id DESC');
?>
<article>
   <?php while ($memo = $memos->fetch()): ?>
    <!-- 以下の記載で表示する文字数を0~50字に設定。aタグに詳細ページのリンクを設定 -->
      <p><a href="memo.php?id=<?php print($memo['id']);?>"><?php print(mb_substr($memo['memo'],0,50)); ?></a></p>
      <time><?php print($memo['created_at']); ?></time>
      <hr>
   <?php endwhile; ?>
</article>
</main>
</body>    
</html>

しかし、今のままだとURLにID=何番 と表示されてしまうのでユーザーに自由に書き換えられてしまう。

以下の記述でマイナスなどの数字、数字以外の文字の場合はエラーが表示されるようにできる。

memo.php
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<?php
//以下の記述でPHPからDBに接続できる。MAMPの場合、パスワードはrootになる。
try{
  //new PDO(DBを扱う)でオブジェクトのインスタンスを作っている。
  $db = new PDO ('mysql:dbname=mydb;host=127.0.0.1;port=8889;charset=utf8', 'root', 'root');
  //接続できなければ$eという形で受け取り、それを画面に出力する。
}catch(PDOException $e){
  echo 'DB接続エラー:' . $e->getMessage();
}

//$idが数字以外が指定された時、if構文の内容が反映される。
$id=$_REQUEST['id'];
if(!is_numeric($id) || $id<=0){
print('1以上の数字で指定してください');
exit();
}

//prepareでセキュリティ対策
$memos = $db->prepare('SELECT * FROM memos WHERE id=?');
$memos->execute(array($_REQUEST['id']));
$memo = $memos->fetch();
?>
<article>
  <pre><?php print($memo['memo']);?></pre>
  <a href="index.php">戻る</a>
</article>
</main>
</body>    
</html>

接続プログラムを共通プログラムに

今のままなどデータが変わった後全部のファイルを書き換える必要性が出てくるのでそれをなくす。

requireを使って他のファイルを取り込む。

index.php
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<?php
//以下の記述でdbconnect.phpファイルを読み込む。
require('dbconnect.php');


//以下の記述でrecordsという変数の中にdbの内容が入っている。
$memos = $db->query('SELECT * FROM memos ORDER BY id DESC');
?>
<article>
   <?php while ($memo = $memos->fetch()): ?>
    <!-- 以下の記載で表示する文字数を0~50字に設定。aタグに詳細ページのリンクを設定 -->
      <p><a href="memo.php?id=<?php print($memo['id']);?>"><?php print(mb_substr($memo['memo'],0,50)); ?></a></p>
      <time><?php print($memo['created_at']); ?></time>
      <hr>
   <?php endwhile; ?>
</article>
</main>
</body>    
</html>
input_do.php
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<pre>
   <?php
   require('dbconnect.php');
   //?をいれる。prepareでセキュリティ対策
   $statement=$db->prepare('INSERT INTO memos SET memo=?,created_at=NOW()');
   $statement->execute(array($_POST['memo']));
   echo 'メッセージが登録されました';
   ?>
</pre>
</main>

</body>    
</html>
memo.php
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<?php
require('dbconnect.php');
//$idが数字以外が指定された時、if構文の内容が反映される。
$id=$_REQUEST['id'];
if(!is_numeric($id) || $id<=0){
print('1以上の数字で指定してください');
exit();
}

//prepareでセキュリティ対策
$memos = $db->prepare('SELECT * FROM memos WHERE id=?');
$memos->execute(array($_REQUEST['id']));
$memo = $memos->fetch();
?>
<article>
  <pre><?php print($memo['memo']);?></pre>
  <a href="index.php">戻る</a>
</article>
</main>
</body>    
</html>

ページネーション

以下の記述でページが指定されなかった場合も1ページ目が自動で表示される。

memo.php
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<?php
//以下の記述でdbconnect.phpファイルを読み込む。
require('dbconnect.php');

if(isset($_REQUEST['page']) && is_numeric($_REQUEST['page'])){
  $page=$_REQUEST['page'];
}else{
  $page=1;
}

$start=5*($page-1);

//LIMIT区を使って件数を表示できる。
$memos = $db->prepare('SELECT * FROM memos ORDER BY id DESC LIMIT ?,5');
//数字でパラメータを渡すことができるようになる。
$memos->bindParam(1,$start,PDO::PARAM_INT);
$memos->execute();
?>
<article>
   <?php while ($memo = $memos->fetch()): ?>
    <!-- 以下の記載で表示する文字数を0~50字に設定。aタグに詳細ページのリンクを設定 -->
      <p><a href="memo.php?id=<?php print($memo['id']);?>"><?php print(mb_substr($memo['memo'],0,50)); ?></a></p>
      <time><?php print($memo['created_at']); ?></time>
      <hr>
   <?php endwhile; ?>
</article>
</main>
</body>    
</html>

リンクで前のページや次のページに行けるようにする

<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<?php
//以下の記述でdbconnect.phpファイルを読み込む。
require('dbconnect.php');

if(isset($_REQUEST['page']) && is_numeric($_REQUEST['page'])){
  $page=$_REQUEST['page'];
}else{
  $page=1;
}

$start=5*($page-1);

//LIMIT区を使って件数を表示できる。
$memos = $db->prepare('SELECT * FROM memos ORDER BY id DESC LIMIT ?,5');
//数字でパラメータを渡すことができるようになる。
$memos->bindParam(1,$start,PDO::PARAM_INT);
$memos->execute();
?>
<article>
   <?php while ($memo = $memos->fetch()): ?>
    <!-- 以下の記載で表示する文字数を0~50字に設定。aタグに詳細ページのリンクを設定 -->
      <p><a href="memo.php?id=<?php print($memo['id']);?>"><?php print(mb_substr($memo['memo'],0,50)); ?></a></p>
      <time><?php print($memo['created_at']); ?></time>
      <hr>
   <?php endwhile; ?>

   <!-- 2ページ以上の時表示 -->
   <?php if($page>=2):?>
   <a href="index.php?page=<?php print($page-1);?>"><?php print($page-1);?>ページ目へ</a>
   <?php endif; ?>
   |
   <a href="index.php?page=<?php print($page+1);?>"><?php print($page+1);?>ページ目へ</a>
</article>
</main>
</body>    
</html>

件数の多いレコードをページを分ける

余分なページを表示しなくて済む

index.php
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<?php
//以下の記述でdbconnect.phpファイルを読み込む。
require('dbconnect.php');

if(isset($_REQUEST['page']) && is_numeric($_REQUEST['page'])){
  $page=$_REQUEST['page'];
}else{
  $page=1;
}

$start=5*($page-1);

//LIMIT区を使って件数を表示できる。
$memos = $db->prepare('SELECT * FROM memos ORDER BY id DESC LIMIT ?,5');
//数字でパラメータを渡すことができるようになる。
$memos->bindParam(1,$start,PDO::PARAM_INT);
$memos->execute();
?>
<article>
   <?php while ($memo = $memos->fetch()): ?>
    <!-- 以下の記載で表示する文字数を0~50字に設定。aタグに詳細ページのリンクを設定 -->
      <p><a href="memo.php?id=<?php print($memo['id']);?>"><?php print(mb_substr($memo['memo'],0,50)); ?></a></p>
      <time><?php print($memo['created_at']); ?></time>
      <hr>
   <?php endwhile; ?>

   <!-- 2ページ以上の時表示 -->
   <?php if($page>=2):?>
   <a href="index.php?page=<?php print($page-1);?>"><?php print($page-1);?>ページ目へ</a>
   <?php endif; ?>
   <?php 
   $counts=$db->query('SELECT count(*) as cnt FROM memos');
   $count=$counts->fetch();
   $max_page=ceil($count['cnt']/5);
   if($page < $max_page):
   ?>
   |
   <a href="index.php?page=<?php print($page+1);?>">
   <?php print($page+1);?>ページ目へ</a>
   <?php endif; ?>
</article>
</main>
</body>    
</html>

メモを編集、変更する

update.php
<?php require('dbconnect.php');?>
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<?php 
if(isset($_REQUEST['id'])&& is_numeric($_REQUEST['id'])){
  $id=$_REQUEST['id'];

  $memos=$db->prepare('SELECT * FROM memos WHERE id=?');
  $memos->execute(array($id));
  $memo=$memos->fetch();
}

?>
<form action="update_do.php" method="post">
  <!-- 以下の記述でデータを編集画面に渡す。 -->
  <input type="hidden" name="id" value="<?php print($id);?>">
  <textarea name="memo" cols="50" rows="10"><?php print($memo['memo']);?></textarea><br>
  <button type="submit">登録する</button>
</form>
</main>

</body>    
</html>
update_do.php
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<pre>
   <?php
   require('dbconnect.php');

   $statement=$db->prepare('UPDATE memos SET memo=? WHERE id=?');
   $statement->execute(array($_POST['memo'],$_POST['id']));
   ?>
</pre>
<p>メモの内容を変更しました</p>
<p><a href="index.php">戻る</a></p>
</main>

</body>    
</html>
memo.php
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<?php
require('dbconnect.php');
//$idが数字以外が指定された時、if構文の内容が反映される。
$id=$_REQUEST['id'];
if(!is_numeric($id) || $id<=0){
print('1以上の数字で指定してください');
exit();
}

//prepareでセキュリティ対策
$memos = $db->prepare('SELECT * FROM memos WHERE id=?');
$memos->execute(array($_REQUEST['id']));
$memo = $memos->fetch();
?>
<article>
  <pre><?php print($memo['memo']);?></pre>
  <a href="update.php?id=<?php print($memo['id']);?>">編集する</a>
  |
  <a href="index.php">戻る</a>
</article>
</main>
</body>    
</html>

削除機能

delete.phpを作成

delete.php
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<pre>
   <?php
   require('dbconnect.php');
   if(isset($_REQUEST['id']) && is_numeric($_REQUEST['id'])){
     $id=$_REQUEST['id'];
     $statement=$db->prepare('DELETE FROM memos WHERE id=?');
     $statement->execute(array($id));
   }

   ?>
</pre>
<p>メモを削除しました。</p>
<p><a href="index.php">戻る</a></p>
</main>

</body>    
</html>
memo.php
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">

<title>PHP</title>
</head>
<body>
<header>
<h1 class="font-weight-normal">PHP</h1>    
</header>

<main>
<h2>Practice</h2>
<?php
require('dbconnect.php');
//$idが数字以外が指定された時、if構文の内容が反映される。
$id=$_REQUEST['id'];
if(!is_numeric($id) || $id<=0){
print('1以上の数字で指定してください');
exit();
}

//prepareでセキュリティ対策
$memos = $db->prepare('SELECT * FROM memos WHERE id=?');
$memos->execute(array($_REQUEST['id']));
$memo = $memos->fetch();
?>
<article>
  <pre><?php print($memo['memo']);?></pre>
  <a href="update.php?id=<?php print($memo['id']);?>">編集する</a>
  |
  <a href="delete.php?id=<?php print($memo['id']);?>">削除する</a>
  |
  <a href="index.php">戻る</a>
</article>
</main>
</body>    
</html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

引数の概念がわからないので自分なりに噛み砕いてみた。

関数を作成するとき「引数」を使うがどうしても私はその概念が理解できない。

なので今回、引数の概念をしっかりと理解するようにしてみた。

引数とは

関数は入力をすると、出力(戻り値という)される。

引数とはその一連の流れの中で「入力」に相当するものである。

例)関数=人   引数=食べ物  戻り値=排泄
 人が食べ物を食べると排泄をする。

一連の流れとしてはこのようなものになる。

実際のコードで引数を見てみる

public function test($people){
   return ($people);
}

echo test('鈴木くん');

とすると  出力結果は 鈴木くんが出るということになる。

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

PHPで文字列と数値を「足す」もしくは「連結」するとどうなる?の話

本題に入る前に

本題に入る前に前提知識として話しておきたいことがあります。

本記事作成時のPHPのバージョン

php -v

// => PHP 7.3.9 

PHPの文字列

phpで変数に文字列を代入して表示する際

<?php
$hoge = "Hello PHP";
echo $hoge;             // Hello PHP

このように書いていきますよね。

文字列の連結

文字列の連結は

<?php
$hoge1 = "Hello";
$hoge2 = "PHP";
$hoge3 = $hoge1 . $hoge2;
echo $hoge3;             // HelloPHP

このようにやっていきます。

PHPの数値

同じように数値も

<?php
$number = 1;
echo $number;             // 1

このように書いていきますよね。

数値の連結

数値の連結は以下のようにやります。

<?php
$number1 = 1;
$number2 = 4;
$number3 = $number1 . $number2;
echo $number3;             // 14

数値なので+を使うとどうなるか

<?php
$number1 = 1;
$number2 = 4;
$number3 = $number1 + $number2;
echo $number3;             // 5

シンプルに足し算しています。

本題

ではここからが本題です。

PHPで文字列と数値を足すとどうなると思いますか?


そんなのエラーになるに決まっているだろ!!

そう私は思っていました。

エラーが起きない!!


まさかのエラーは起きずでした??

試したパターン


足す
  • 文字列と数値を足す
  • 文字列の前に数字を入れてみる
  • 文字列の途中もしくは後ろに数値を入れてみる
連結
  • 文字列と数値を連結
  • 文字列の前に数字を入れてみる
  • 文字列の途中もしくは後ろに数値を入れてみる

文字列と数値の足し算

1. 文字列と数値を足す

まずは足し算からやってみましょう

<?php
$hoge1 = "Hello";
$number1 = 1;
$hoge2 = $hoge1 + $number1;
echo $hoge2;             

さて結果は??

1

となります?

2. 文字列の前に数字を入れてみる

次に文字列の前に数値を入れてみました。

<?php
$hoge1 = "3Hello";
$number1 = 1;
$hoge2 = $hoge1 + $number1;
echo $hoge2;            

結果は?

4

どうやら文字の方は0として扱われて3 + 1の計算になっているようです。

3. 文字列の途中もしくは後ろに数値を入れてみる

<?php
$hoge1 = "He3llo";
$number1 = 1;
$hoge2 = $hoge1 + $number1;
echo $hoge2;
<?php
$hoge1 = "Hello3";
$number1 = 1;
$hoge2 = $hoge1 + $number1;
echo $hoge2;     

いずれも結果は

1

となります。


文字列と数値の連結

1. 文字列と数値を連結

まずは足し算からやってみましょう

<?php
$hoge1 = "Hello";
$number1 = 1;
$hoge2 = $hoge1 . $number1;
echo $hoge2;             

さて結果は??

Hello1

となります?

2. 文字列の前に数字を入れてみる

次に文字列の前に数値を入れてみました。

<?php
$hoge1 = "3Hello";
$number1 = 1;
$hoge2 = $hoge1 . $number1;
echo $hoge2;            

結果は?

3Hello1

となります。?

3. 文字列の途中もしくは後ろに数値を入れてみる

<?php
$hoge1 = "He3llo";
$number1 = 1;
$hoge2 = $hoge1 . $number1;
echo $hoge2;
<?php
$hoge1 = "Hello3";
$number1 = 1;
$hoge2 = $hoge1 + $number1;
echo $hoge2;     

いずれも結果は

He3llo1

となります。?

なぜ??

別の言語でもみてみる

JavaScript

      let a = 1;
      let b = 2;
      let c = a + b;
      console.log(c);

      let d = 1;
      let e = "アイウエオ";
      let f = d + e;
      console.log(f);

      let g = 1;
      let h = "22アイウエオ";
      let i = g.h;
      console.log(i);

コンソール結果は以下のようになりました。
スクリーンショット 2020-11-12 3.33.44.png

javaScriptでは+で文字列の連結を行い、.で足し算などを行うので定義されていないという文言が出ております。

結論

これはPHPの仕様によるものらしい。
いろいろ調べたところ、PHPでは厳密な型を指定していないので状況に応じて、型変換が処理時に行われるようです。

実戦で役にたたなさそうですが、プログラミングを楽しむ。PHPを楽しむ。より理解するという意味でこの記事を書かせていただきました。

長くなってしまいましたが、みていただきありがとうございます。

参考サイト

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

曜日を求めるツェラーの公式

曜日を求めるツェラーの公式

ツェラーの公式

<?php
$Zeller = function($y,$m,$d,$flg=false){
    $wd = array("日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日");
    $g = ($y+(int)($y/4)-(int)($y/100)+(int)($y/400)+(int)(((13 * $m) +8)/5)+$d)%7;
    return $flg?$wd[$g]:$g;
};

try {
    $y = 2020;
    $m = 9;//date("m");
    $d = 1;
    var_dump($Zeller($y,$m,$d));
    var_dump($Zeller($y,$m,$d,true));
} catch (\Throwable $th) {
    var_dump($th);
}

前処理を追加すると正しく曜日を求めることが出来る。

<?php
$Zeller = function($y,$m,$d,$flg=false){
    if($m <= 2) {
        $m += 12;
        $y -= 1;
    }   
    $wd = array("日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日");
    $g = ($y+(int)($y/4)-(int)($y/100)+(int)($y/400)+(int)(((13 * $m) +8)/5)+$d)%7;
    return $flg?$wd[$g]:$g;
};

try {
    $y = 2020;
    $m = 9;//date("m");
    $d = 1;
    var_dump($Zeller($y,$m,$d));
    var_dump($Zeller($y,$m,$d,true));
} catch (\Throwable $th) {
    var_dump($th);
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP 基本文法まとめ 前編

PHP基本文法

PHPの基本文法を前編と後編に分けてご紹介します。

前半:変数定数関数演算子配列連想配列
後半:if文while文for文foreach文

変数

$変数名 = 整数;
$number = 10;
$name = '佐藤'; //文字列の場合は''(シングルクォーテーション)で囲む。

変数 = 箱のようなもので、$変数に整数を一時的に格納することができる。
$(ドルマーク)に続けて変数名を付ける。
・変数名は文字、または _(アンダースコア)で始める。
大文字と小文字は区別される

定数

 define('USER_NAME', 'user name');
 const USER_NAME = 'user name';

定数 = 変数とは違い、一度定義した定数の値を変更することができない
・定義方法は、define(‘定数名’,‘定数の値’)もしくは、const ‘定数名’=‘定数の値’
・定数名は大文字_の組み合わせのみ。

演算子

echo 1 + 1; // 足し算
echo 6 - 3; // 引き算
echo 3 * 4; // 掛け算
echo 8 / 2; // 割り算
echo 7 % 2; // 割り算の余り

//比較演算子
== 等しい
=== 等しい(厳密)
!=  異なる
!== 異なる(厳密)
<> 異なる(!= と同じ)
>  大きい
>=  以上
<  小さい
<= 以下

//論理演算子
&& ~ かつ ~ (AND)
|| ~ または ~ (OR)
!  ~でない

配列

$fruits = ['apple', 'orange', 'pineapple'];
$fruits = array('apple', 'orange', 'pineapple');

//添字は0からスタート
echo $変数名[添字];
echo $fruits[0]; // apple
echo $fruits[1]; // orange
echo $fruits[2]; // pineapple

配列 = 複数の値を管理するarray()で値を定義。

連想配列

$juice = array(
  'orange' => 'orange juice',
  'apple'  => 'apple juice',
  'grape'  => 'grape juice',
  'banana' => 'banana juice'
);

echo $変数名['キー名'];
echo $juice['orange']; //orange juiceを表示。
echo $juice['apple'];  //apple juiceを表示。
echo $juice['grape'];  //grape juiceを表示。
echo $juice['banana']; //banana juiceを表示。


//count($変数名)で配列の中身の数を表示させることもできる。
$fruits = array('apple', 'banana', 'lemon');
echo count($fruits); //countは要素の数を返す。この場合は3。

連想配列 = 添字の代わりに自分で要素に名前を付けてアクセスする。
要素の名前をkey(キー)という。

関数

function 関数名 () 
{
   //処理内容
}
関数名(); //関数を使う。


function myName() {
    $name = “佐藤”;
    echo “私の名前は” . $name . “です。<br>”;
}
function myName() // 「私の名前は佐藤です。」 が表示される。

↓ 引数を使った場合

function myName($name) {
    echo “私の名前は” . $name . “です。<br>”;
}
function myName("佐藤") // 「私の名前は佐藤です。」 が表示される。

関数 = 何らかに処理をまとめておくことで、好きな時に関数として呼び出せる
     同じようなコードを何度も書かないで済む
引数 = 関数を引き出すときに渡す値

参考元はこちら
(https://creive.me/archives/8719/#PHP)
(https://techacademy.jp/magazine/4925)

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

Laravel8 CRUD処理を使った投稿アプリを作成する その9 画像をアップロードできるようにする

目的

  • ヘッダーをベースレイアウトファイルに記載して反映する方法をまとめる

実施環境

  • 筆者の実施環境を記載する。
  • ハードウェア環境
項目 情報
OS macOS Catalina(10.15.5)
ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)
プロセッサ 2 GHz クアッドコアIntel Core i5
メモリ 32 GB 3733 MHz LPDDR4
グラフィックス Intel Iris Plus Graphics 1536 MB
  • ソフトウェア環境
項目 情報 備考
PHP バージョン 7.4.8 Homebrewを用いてこちらの方法で導入→Mac HomebrewでPHPをインストールする
Laravel バージョン 8.6.0 commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う
MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする

前提条件

前提情報

  • 作成するアプリ名は「laravel8_crud」とする。
  • 作成するMySQLのデータベース名は「laravel8_crud_DB」とする。
  • 下記に今回の作業のあとのソースコードのリモートリポジトリのリンクを記載する。

概要

  1. .envファイルの記載
  2. シンボリックリンクの作成
  3. マイグレーションファイルの記載とマイグレート
  4. コントローラファイルの修正
  5. ベースレイアウトファイルの作成
  6. ビューファイルの編集
  7. 確認

詳細

  1. .envファイルの記載

    1. laravel8_crudディレクトリで下記コマンドを実行して.envファイルを開く。

      $ vi .env
      
    2. 下記の内容を.envファイルに追記する。

      laravel8_crud/.env
      FILESYSTEM_DRIVER=public
      
  2. シンボリックリンクの作成

    1. laravel8_crudディレクトリで下記コマンドを実行してシンボリックリンクを作成する。

      $ php artisan storage:link
      
  3. マイグレーションファイルの記載とマイグレート

    1. laravel8_crudディレクトリで下記コマンドを実行してモデルファイルとマイグレーションファイルを作成する。

      $ php artisan make:model ContentImage -m
      
    2. laravel8_crudディレクトリで下記コマンドを実行して作成したマイグレーションファイルを開く。

      $ vi database/migrations/YYYY_MM_DD_HHMMSS_create_content_images_table.php
      
    3. up側に下記の内容を記載する。

      laravel8_crud/database/migrations/YYYY_MM_DD_HHMMSS_create_content_images_table.php
      $table->integer('content_id');
      $table->string('file_path');
      $table->string('file_name');
      
    4. 記載後の全内容を下記に記載する。

      laravel8_crud/database/migrations/YYYY_MM_DD_HHMMSS_create_content_images_table.php
      <?php
      
      use Illuminate\Database\Migrations\Migration;
      use Illuminate\Database\Schema\Blueprint;
      use Illuminate\Support\Facades\Schema;
      
      class CreateContentImagesTable extends Migration
      {
          /**
           * Run the migrations.
           *
           * @return void
           */
          public function up()
          {
              Schema::create('content_images', function (Blueprint $table) {
                  $table->id();
                  // 下記を追記する
                  $table->integer('content_id');
                  $table->string('file_path');
                  $table->string('file_name');
                  // 上記までを追記する
                  $table->timestamps();
              });
          }
      
          /**
           * Reverse the migrations.
           *
           * @return void
           */
          public function down()
          {
              Schema::dropIfExists('content_images');
          }
      }
      
    5. laravel8_crudディレクトリで下記コマンドを実行してマイグレーションを行う。

      $ php artisan migrate
      
  4. コントローラファイルの修正

    1. laravel8_crudディレクトリで下記コマンドを実行してコントローラファイルを開く。

      $ vi app/Http/Controllers/ContentController.php
      
    2. 下記のように修正する。

      laravel8_crud/app/Http/Controllers/ContentController.php
      <?php
      
      namespace App\Http\Controllers;
      
      use Illuminate\Http\Request;
      use App\Models\Content;
      // 下記を追記する
      use App\Models\ContentImage;
      use Illuminate\Support\Facades\Storage;
      // 上記までを追記する
      
      class ContentController extends Controller
      {
          public function input()
          {
              return view('contents.input');
          }
      
          public function save(Request $request)
          {
              $input_content = new Content();
              $input_content->content = $request['content'];
              $input_content->save();
      
              // 下記を追記する
              if ($request->file('file')) {
                  $this->validate($request, [
                      'file' => [
                          // 空でないこと
                          'required',
                          // アップロードされたファイルであること
                          'file',
                          // 画像ファイルであること
                          'image',
                          // MIMEタイプを指定
                          'mimes:jpeg,png',
                      ]
                  ]);
      
                  if ($request->file('file')->isValid([])) {
                      $file_name = $request->file('file')->getClientOriginalName();
                      $file_path = Storage::putFile('/images', $request->file('file'), 'public');
      
                      $image_info = new ContentImage();
                      $image_info->content_id = $input_content->id;
                      $image_info->file_name = $file_name;
                      $image_info->file_path = $file_path;
                      $image_info->save();
                  }
              }
              // 上記までを追記する
              return redirect(route('output'));
          }
      
          public function output()
          {
              $contents_get_query = Content::select('*');
              $items = $contents_get_query->get();
      
              // 下記を追記する
              foreach ($items as &$item) {
                  $file_path = ContentImage::select('file_path')
                  ->where('content_id', $item['id'])
                  ->first();
                  if (isset($file_path)) {
                      $item['file_path'] = $file_path['file_path'];
                  }
              }
              // 上記までを追記する
      
              return view('contents.output', [
                  'items' => $items,
              ]);
          }
      
          public function detail($content_id)
          {
              $content_get_query = Content::select('*');
              $item = $content_get_query->find($content_id);
      
              // 下記を追記する
              $file_path = ContentImage::select('file_path')
              ->where('content_id', $item['id'])
              ->first();
              if (isset($file_path)) {
                  $item['file_path'] = $file_path['file_path'];
              }
              // 上記までを追記する
      
              return view('contents.detail', [
                  'item' => $item,
              ]);
          }
      
          public function edit($content_id)
          {
              $content_get_query = Content::select('*');
              $item = $content_get_query->find($content_id);
      
              return view('contents.edit', [
                  'item' => $item,
              ]);
          }
      
          public function update(Request $request)
          {
              $content_get_query = Content::select('*');
              $content_info = $content_get_query->find($request['id']);
              $content_info->content = $request['content'];
              $content_info->save();
              return redirect(route('output'));
          }
      
          public function delete(Request $request)
          {
              $contents_delete_query = Content::select('*');
              $contents_delete_query->find($request['id']);
              $contents_delete_query->delete();
      
              // 下記を追記
              $content_images_delete_query = ContentImage::select('*');
              if ($content_images_delete_query->find($request['id'] !== '[]')) {
                  $content_images_delete_query->delete();
              }
              // 上記までを追記
      
              return redirect(route('output'));
          }
      }
      
  5. ビューファイルの編集

    1. laravel8_crudディレクトリで下記コマンドを実行してビューファイルを開く。

      $ vi resources/views/contents/input.blade.php
      
    2. 下記のように編集する。

      laravel8_crud/resources/views/contents/input.blade.php
      @extends('layouts.app')
      
      @section('content')
      
      <h1>input</h1>
      
      {{-- 下記を修正する --}}
      <form action="{{route('save')}}" method="post" enctype="multipart/form-data">
          @csrf
          <textarea name="content" cols="30" rows="10"></textarea>
          {{-- 下記を追記する --}}
          <br>
          @error('file')
              {{$message}}
              <br>
          @enderror
          <input type="file" name="file">
          {{-- 上記までを追記する --}}
          <input type="submit" value="送信">
      </form>
      
      @endsection
      
    3. laravel8_crudディレクトリで下記コマンドを実行してビューファイルを開く。

      $ vi resources/views/contents/output.blade.php
      
    4. 下記のように編集する。

      laravel8_crud/resources/views/contents/output.blade.php
      @extends('layouts.app')
      
      @section('content')
      
      <h1>output</h1>
      
      @foreach ($items as $item)
      <hr>
      {{-- 下記を追記する --}}
      @if (isset($item['file_path']))
      <img src="{{asset('storage/' . $item['file_path'])}}" alt="{{asset('storage/' . $item['file_path'])}}">
      @endif
      {{-- 上記までを追記する --}}
      <p>{{$item['content']}}</p>
      <a href="{{route('detail', ['content_id' => $item['id']])}}">詳細</a>
      <a href="{{route('edit', ['content_id' => $item['id']])}}">編集</a>
      @endforeach
      
      @endsection
      
    5. laravel8_crudディレクトリで下記コマンドを実行してビューファイルを開く。

      $ vi resources/views/contents/detail.blade.php
      
    6. 下記のように編集する。

      laravel8_crud/resources/views/contents/detail.blade.php
      @extends('layouts.app')
      
      @section('content')
      
      <h1>detail</h1>
      
      {{-- 下記を追記する --}}
      @if (isset($item['file_path']))
      <img src="{{asset('storage/' . $item['file_path'])}}" alt="{{asset('storage/' . $item['file_path'])}}">
      @endif
      {{-- 上記までを追記する --}}
      <p>投稿ID: {{$item['id']}}</p>
      <p>投稿内容: {{$item['content']}}</p>
      <p>投稿時間: {{$item['created_at']}}</p>
      <a href="{{route('edit', ['content_id' => $item['id']])}}">編集</a>
      <form action="{{route('delete')}}" method="post">
          @csrf
          <input type="hidden" name="id" value="{{$item['id']}}">
          <input type="submit" value="削除">
      </form>
      
      @endsection
      
  6. 確認

    1. laravel8_crudディレクトリで下記コマンドを実行してローカルサーバを起動する。

      $ php artisan serve
      
    2. ブラウザで下記にアクセスする。

    3. コメントを入力後に「ファイルを選択」をクリックしてjpegかpngファイルを選択して「送信」をクリックする。

      laravel8_crud-2.png

    4. 下記にアクセスする。

    5. 画像が表示されることを確認する。

    6. 詳細をクリックする。

      laravel8_crud-3.png

    7. 投稿内容の詳細とともに画像が表示されることを確認する。

      laravel8_crud-4.png

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