20210213のPHPに関する記事は11件です。

MediaWikiの<head>に任意の内容を挿入するHeadScriptエクステンションを指定したページのみに適用する方法

MediaWiki において <head> 要素に <script> などを仕込むためには HeadScript エクステンションを利用するとよいのですが、LocalSettings.php にそのまま指定すると、すべてのページの <head> に書き込まれます。

しかし自分は任意のページだけに仕込みたいスクリプトがあったので、設定仕分ける方法をまとめておきます。

参考にしたのは MediaWiki の Support desk にあったこの Topic "How can I add the code into the <head>" です。

環境

  • MediaWiki 1.35.1
  • HeadScript 1.1.1

方法

LocalSettings.php の中に wfLoadExtension( 'HeadScript' ); の後、以下のような形で書き込む。

LocalSettings.php
if (
    ($_SERVER['REQUEST_URI'] == '/wiki/'.rawurlencode('メインページ')) ||
    ($_SERVER['REQUEST_URI'] == '/wiki/'.rawurlencode('yourWiki').':'.rawurlencode('プライバシー・ポリシー')) ||
    ($_SERVER['REQUEST_URI'] == '/wiki/'.rawurlencode('サンプル記事')) ||
    false
)
{
    $wgHeadScriptCode = <<<'START_END_MARKER'
<!-- head に書きたい何かいい感じのこと -->
<script>XXXXXX</script>
START_END_MARKER;
} else {
    $wgHeadScriptCode = <<<'START_END_MARKER'
<!-- その他のページに head に書きたい何かいい感じのことがあれば -->
<script>XXXXXX</script>
START_END_MARKER;
}

シンプルに if を使って分けているだけです。

細かい説明

簡単に内容について説明をいれます。

条件式

($_SERVER['REQUEST_URI'] == '/wiki/'.rawurlencode('メインページ')) ||
false

_SERVER['REQUEST_URI'] からアクセス先の URI を取得できるので、それを文字列比較することで任意のページかどうかの判断をしています。

日本語タイトルの記事ページも多いので rawurlencode を使って URL エンコードを施し、 . 演算子を使って文字列結合しています。

私はアドレスを https://xxxxx_wiki.org/wiki/XXXXXX になるように設定しているのでこのような感じですが、何も設定していないと https://xxxxx_wiki.org/index.php?title=XXXXXX このようなアドレスのはずなので適宜書き換える必要があると思われます。

最後に || false しているのは私の趣味で、Vim を使って行ごとにコピペして編集することが多いので、|| が常に末尾にあってもいいように工夫しているだけです。

$wgHeadScriptCode の書き分け

HeadScript エクステンション の説明にあるように <head> に設定したい内容は START_END_MARKER の間に書き込みます。

私の場合は基本的には全てのページに Google Analytics のコードを載せたいのですが、一部の充実した記事にのみ Google Analytics に加えて Google Adsense のコードも加えたかったので、それぞれ書き換えています。

{
    $wgHeadScriptCode = <<<'START_END_MARKER'
<!-- Google Adsense のコード -->
<!-- Google Analytics のコード -->
START_END_MARKER;
} else {
    $wgHeadScriptCode = <<<'START_END_MARKER'
<!-- Google Analytics のコード -->
START_END_MARKER;
}

参考資料

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

[PHP]半角英数のみのファイルの文字コードを変換しようとしてハマったので備忘録

文字コードを変換するコードを書いていて、表題の通り、ハマりましたので、備忘録として書いておきます。

環境

  • OS: Amazon Linux2
  • PHP: 7.4.14

詳細

UTF-8のファイルをもとに、SJISでファイル出力するコードを書きました(確認用のコードも含めてます)。

convertEncoding.php
$data_org = file_get_contents('./files/utf8_sample.csv');
echo "変換前の文字コード:".mb_detect_encoding($data_org,"UTF-8, ASCII, SJIS")."\n";
file_put_contents('./files/sjis_sample.csv',  mb_convert_encoding($data_org, "SJIS"), FILE_APPEND | LOCK_EX);
$data_conv = file_get_contents('./files/sjis_sample.csv');
echo "変換後の文字コード:".mb_detect_encoding($data_conv,"UTF-8, ASCII, SJIS")."\n";

半角英数のみのファイルを用いた場合

変換前のファイルの内容は以下の通り。文字コードはUTF-8です。

utf8_sample.csv
id,sex,age,amount,category
00000003,m,31,00002001,food
00000003,m,31,00007569,clothes
00000012,f,24,00001482,clothes
00000013,m,41,00012349,other
00000016,f,53,00001297,book
00000016,f,53,00005264,food

で、変換前のファイルを所定の場所に置き、PHPファイルを実行すると、以下のような結果に。

コンソール出力結果
$ php fileEncoding.php
変換前の文字コード:UTF-8
変換後の文字コード:UTF-8

ん? 変換されてない?

調べていくうちに、半角英数の場合は、どの文字コードでも(今回の比較対象:JIS, SJIS, EUC, UTF-8, UTF-16)、同じ文字数字の組み合わせになることが判明(当たり前っちゃ当たり前な気もしますが)。

Unicode対応 文字コード表

辺りを見ると、一目瞭然!

文字エンコーディングを検出する関数mb_detect_encodingでは、第2引数に指定した文字エンコーディングをリストを先頭から順番に一致するものがないか検索するようなので、試しに、convertEncoding.phpのmb_detect_encodingの第2引数の順序を変えてみるとコンソール出力結果は、以下のようになりました。

ASCIIを先頭にした場合
$ php fileEncoding.php
変換前の文字コード:ASCII
変換後の文字コード:ASCII
SJISを先頭にした場合
$ php fileEncoding.php
変換前の文字コード:SJIS
変換後の文字コード:SJIS

変換対象が半角英数の場合は、どの文字エンコーディングでも、表現が共通しているから、第2引数の先頭に指定したものに合致すると見なされるわけですね。

ちなみに、nkfコマンドで文字コードの確認をすると以下の通りに。

nkfコマンドの実行結果
# 変換前のファイル
$ nkf --guess ./files/utf8_sample.csv
ASCII (CRLF)
# 変換後のファイル
$ nkf --guess ./files/utf8_sample.csv
ASCII (CRLF)

UTF-8も、SJISもASCIIの拡張だからかな・・?

日本語入りのファイルを用いた場合

原因が分かったところで、変換前のファイルの一部を日本語にしてみます。今回も、文字コードはUTF-8です。

utf8_sample.csv
id,sex,age,amount,category
00000003,m,31,00002001,食品
00000003,m,31,00007569,衣類
00000012,f,24,00001482,衣類
00000013,m,41,00012349,その他
00000016,f,53,00001297,
00000016,f,53,00005264,食品

再度、convertEncoding.phpを実行!

コンソール出力結果
$ php fileEncoding.php
変換前の文字コード:UTF-8
変換後の文字コード:SJIS

今度はうまくいきました!

nkfコマンドでも確認してみると・・・

nkfコマンドの実行結果
$ nkf --guess ./files/utf8_sample.csv
UTF-8 (CRLF)
# 変換後のファイル
$ nkf --guess ./files/utf8_sample.csv
Shift_JIS (CRLF)

こちらも想定通り!!

結論

  • 文字コードを正しく理解する!
  • 文字コード変換するなら、対象の言語を用いる!

につきますね。

参考

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

[Laravel]Gitを使わずアプリケーションを簡単にバックアップする

はじめに

パッケージlaravel-backupを使用すれば、ソースファイルやDBのバックアップが可能になるという記事を見て面白そうだと思い、バックアップするまでの一連の流れを記事にしました。デフォルトでは、バックアップの保存先はローカルに設定されていますが任意の場所に保存も可能なため、おまけとしてS3での保存方法も記載しています。

環境

  • PHP 7.3
  • Laravel 8.27

※PHPやLaravelのバージョンによって使用するlaravel-backupのバージョンが異なってきます。
詳しくはこちらを参照してください。

インストールとセットアップ

ここではlaravel-backupをインストールした後に、バックアップの設定を行います。

インストール

laravel-backupをインストールします。

$ composer require spatie/laravel-backup

設定ファイル作成

設定ファイルconfig/backup.phpを作成するために、下記コマンドを実行してください。

$ php artisan vendor:publish --provider="Spatie\Backup\BackupServiceProvider"
Copied File [/vendor/spatie/laravel-backup/config/backup.php] To [/config/backup.php]
Copied Directory [/vendor/spatie/laravel-backup/resources/lang] To [/resources/lang/vendor/backup]
Publishing complete.

実行結果として
config/backup.phpresources/lang/vendor/backupが生成されます。
ちなみにresources/lang/vendor/backup配下にはバックアップ失敗などで通知メッセージを送る際の言語ファイルが用意されています。言語ファイルは20カ国以上あり、日本語翻訳バージョンも用意されています。

バックアップ保存先の変更

バックアップの保存先はconfig/backup.phpdisksで設定されています。
今回はデフォルトのlocalで進めます。

config/backup.php
<?php
return [
    'backup' => [
        (省略)
        'destination' => [
            (省略)
            /*
             * The disk names on which the backups will be stored.
             */
            'disks' => [
                'local', //ここで設定
            ],
        ],
        (省略)
    ],
];

disksに設定のlocalはconfig/filesystems.phpのdisksと対応しています。

config/filesystems.php
<?php
return [
    (省略)
    'disks' => [
        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
        ],
        'public' => [
            'driver' => 'local',
            'root' => storage_path('app/public'),
            'url' => env('APP_URL').'/storage',
            'visibility' => 'public',
        ],
        's3' => [
            'driver' => 's3',
            'key' => env('AWS_ACCESS_KEY_ID'),
            'secret' => env('AWS_SECRET_ACCESS_KEY'),
            'region' => env('AWS_DEFAULT_REGION'),
            'bucket' => env('AWS_BUCKET'),
            'url' => env('AWS_URL'),
            'endpoint' => env('AWS_ENDPOINT'),
        ],
        (省略)
    ],
];

通知先の設定

バックアップ実行時に通知あり/なしを指定できます(コマンドにて)。通知を指定した際に送信元、通知先が未設定だとエラーが発生しますので必ず設定する必要があります。設定ファイルはconfig/backup.phpになります。

config/backup.php
'notifications' => [

    // 省略

    'mail' => [
        // 通知先のメールアドレス
        'to' => 'your@example.com',

        // 送信元
        'from' => [
            'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
            'name' => env('MAIL_FROM_NAME', 'Example'),
        ],
    ],

通知設定についてはこちらの記事が参考になると思います。
参考:Laravelメール送信機能の実装でmailtrapやGmailのSMTPサーバーを使ってみる

バックアップ実行

バックアップのコマンドを確認したあとに、実行したいと思います。

バックアップのコマンドの確認

$ php artisan list

backup
  backup:clean         Remove all backups older than specified number of days in config.
  backup:list          Display a list of all backups.
  backup:monitor       Monitor the health of all backups.
  backup:run           Run the backup.

バックアップ(全て)

$ php artisan backup:run

Starting backup...
Dumping database LaravelBackup...
Determining files to backup...
Zipping 228 files and directories...
Created zip containing 228 files and directories. Size is 618.99 KB
Copying zip to disk named local...
Successfully copied zip to disk named local.
Backup completed!

成功していれば、storage/app/〇〇にzipファイルが作成されています。(〇〇は.envファイルのAPP_NAMEが入るはず)

バックアップ(DBのみ)

$ php artisan backup:run --only-db

バックアップ(ファイルのみ)

$ php artisan backup:run --only-files

バックアップ(通知無効)

$ php artisan backup:run --disable-notifications

バックアップ(DBのみ通知無効)

$ php artisan backup:run --only-db --disable-notifications

バックアップ(ファイルのみ通知無効)

$ php artisan backup:run --only-files --disable-notifications

おまけ

ローカル(storage/app/)に長期で保存すると容量の問題等から、別の場所に保存する方が良いかもしれません。今回、新しい保存先としてAWSのS3で設定する方法も紹介します。

※AWS,S3バケットの準備方法は省略しています。
詳しく知りたい方はこちらを参照すると良いと思います。
参考:Laravelをバックアップ!定期的にDBやファイルをAWSへ保存する

AWS情報を設定ファイルに記載

AWSで取得した情報を.envファイルに下記を追加

.env
AWS_DEFAULT_REGION=****** // リージョンを記載
AWS_BUCKET=****** // バケット名を記載
AWS_ACCESS_KEY_ID=****** //アクセスキーを記載
AWS_SECRET_ACCESS_KEY=****** //シークレットアクセスキーを記載

ストレージパッケージをインストール

S3へアップロードできるようにパッケージをインストールします。

composer require league/flysystem-aws-s3-v3:"^1.0"

保存先の変更

localからs3に変更してあげます。

config/backup.php
'destination' => [
            (省略)
            /*
             * The disk names on which the backups will be stored.
             */
            'disks' => [
                // 'local',
                's3',
            ],
        ],

バックアップ実行

$ php artisan backup:run --only-files

Determining files to backup...
Zipping 231 files and directories...
Created zip containing 231 files and directories. Size is 2.29 MB
Copying zip to disk named s3...
Successfully copied zip to disk named s3.
Backup completed!

S3を確認すると・・・
スクリーンショット 2021-02-13 21.36.52.png
きちんとバックアップ取れていました!

参考先

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

【PHP】API実行ツールを作ってみよう(その2)

はじめに

PHPでツール作成の第四回目です。
前回のAPIツールの続きで、今回はPHPを使ってクライアント側を作成していきたいと思います。

PHPで作成することのメリットについて

前回紹介したChrome拡張のツールを使えばサーバと通信出来るのに、
わざわざクライアントを自作する意味があるのか?と疑問に思われる方も居るかもしれないので少しメリットについて記載します。

1.APIの連続実行
PHPを使うことで、APIを連続で実行することが可能になります。
それにより例えばサーバの負荷試験(1分間に60回以上通信する等)などが容易に試験可能になります。

2.複数APIの実行
1.と似ているのですが、データ削除を行うAPI、データ作成を行うAPIがそれぞれあったとして、
一回のスクリプト実行で「データ削除→データ作成」のAPIを連続で実行すれば楽にデータ作成を行った環境が構築可能になります。

個人的には連続実行出来るのが一番のメリットではないかなと思っています。

クライアント作成

では、クライアントを作成してみましょう。
作成場所は前回同様に「c:¥xampp¥htdocs¥api」フォルダになります。
api」フォルダ内に「client.php」ファイルを作成します。
中身は下記になります。

client.php
//------------------------------------------------------
// client.php   API送信クライアント
// 
// 実行コマンド
// cd C:\xampp\htdocs\api\
// php client.php テスト
//------------------------------------------------------

// 引数チェック
if( count($argv) < 2 ){
    echo "エラー:引数が足りません\n";
    echo "EX:\n";
    echo "php client.php テスト\n";
    exit;
}
$param = $argv[1];

$url = "http://localhost/api/server.php";       // 接続先URL

echo "-----[api start]-----\n";

$ret = sendApi( $url, $param );

echo "-----[api end]-----\n";

// API実行
function sendApi( $url, $param ) {

    // プロキシ情報
    $proxy_host = "proxy_ipaddress";
    $proxy_port = "port_no";
    $proxy_user = "username";
    $proxy_pass = "password";
    $proxy_auth = base64_encode("$proxy_user:$proxy_pass");

    // パラメータ設定
    $content = "name=".$param."";
    $content = mb_convert_encoding( $content, "UTF-8", "auto" );

    // ヘッダデータ作成
    $header = array(
        "Content-Type: application/x-www-form-urlencoded;",
        "Content-Length: ".strlen($content),
    //    "Proxy-Authorization: Basic ".$proxy_auth
    );

    $contextOptions = array(
        "http" => array(
            "protocol_version" => 1.1,
            "method"  => "POST",
            "header"  => implode( "\r\n", $header ),
            "ignore_errors" => true,
    //        "proxy" => "tcp://$proxy_host:$proxy_port",
            "request_fulluri" => true,
            "content" => $content
        )
    );
    $sslContext = stream_context_create( $contextOptions );

    // API実行
    $response = file_get_contents( $url, false, $sslContext );

    // リクエストパラメータ保存
    file_put_contents( "./request.txt", $content );  // ファイル出力

    // レスポンスパラメータ保存
    file_put_contents( "./response.txt", $response );  // ファイル出力

    return $response;
}

コード解説

  • 11~17行目・・実行時に引数が指定されているかチェックしています。
  • 28行目・・API実行を行うメソッドです。
  • 31~36行目・・外部接続時にプロキシ接続が必要な場合の設定です、もし必要であれば書き換えて下さい。
  • 46、55行目・・上記のプロキシ接続が必要な場合に限り、コメントアウトを解除して下さい。
  • 63行目・・APIを実行しています。
  • 65~69行目・・送信したリクエストパラメータと受信したレスポンスを、テキストファイルに保存しています。

クライアント動作確認

ではクライアントを実行してみましょう。
api」フォルダ上で、コマンドプロンプトを起動し、以下のように入力します。
php client.php PHPクライアントから送信!
qiita_01.png

API実行に成功した場合、以下のように表示されます。
qiita_02.png

サーバ動作確認

続いてサーバ側の確認を行います。
api」フォルダにアクセスし、以下の3ファイルが作成されていれば成功です。
qiita_03.png

[request.txt]
qiita_04.png

[response.txt]
qiita_05.png

[サーバ側で作成された実行日付のテキストファイル]
qiita_06.png

それぞれのファイルの中身が上記のようになっていればAPI実行が成功しています。

最後に

今回のツールを使えば簡単にAPI送受信のテストが実行出来るかと思います。
是非活用してみて下さい。

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

Attempt to read property on nullの解決

LaravelでAttempt to read property on nullが出た話

記事内容

本記事ではLaravelで自作の認証機能を実装していた際に、本題のエラーが出たので、その解決方法を書き下ろします。

開発環境

Laravel 8.22.1
PHP:8.0.1
MySQL:8.0.23
MacOS:11.1 ( Big Sur )

やろうとしていること

ビューで入力フォームと、データベースにcompaniesテーブルを作成し、
ユーザーから入力された値と、テーブルに格納されているデータ(カラム:company_id)と一致するものがあれば、ページを遷移させる。
一致するものがなければ、簡単なエラーメッセージを返すというもの。

テーブル

○○_create_companies_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCompaniesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('companies', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('company_id')->unique();
            $table->string('name');
            $table->timestamps();
        });
    }

今回の認証に利用したのはcompany_idカラムのみの簡単なもの。

Blade

login.blade.php(一部)
<div class="cpylogin-block">
  <form action="/company/login" method="post">
    <label for="company_id">会社/団体ID</label>
    <input type="text" name="company_id" value="{{ old('company_id') }}" placeholder="ID" required>
    <div class="btn-area">
      <button>ログイン</button>
    </div>
    {{ csrf_field() }}
  </form>

フォームの入力値も1つのみ。inputタグのname属性をcompany_idとする。
ちなみにloginブレードはコントローラの記述より、route/web.phpから呼び出しています。

Controller

LoginController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Models\Company;

class CpyLoginController extends Controller
{
    //
    public function index(Request $request)
    {
        return view('pages.cpylogin');
    }

    public function post(Request $request)
    {
        // Companyモデルからcompany_idで情報を検出→オブジェクト化
        $company = Company::where('company_id', $request->company_id)->first();
        $msg = ['msg' => '入力されたIDは存在しません'];

        if ($request->company_id === $company->company_id) {
            return redirect()->route('usrlogin');
        }
        else {
            return view('pages.cpylogin', $msg);
        }
    }
}

・LoginControllerのpostメソッドで認証機能が動くように記述。
Authを使っていない上に、よくあるuserモデルでのログイン機能ではないことをあらかじめ把握しておいてください。

・if文のところで、フォームのinputタグに入力された値がcompanyモデルのcompany_idカラムに保存されているデータと一致するものがあれば、usrloginビューを表示する。

実行

スクリーンショット 2021-02-13 19.04.55.png

Attempt to read property "company_id" on null とエラーになる。
日本語訳すると、「“company_id” プロパティをnullなのに読み込もうとしている。」の意味(少しズレてるかも)。

原因

エラーの原因はControllerの中の、companyモデルを呼び出す記述にありました。

LoginController.php
--- 省略 ---

    public function post(Request $request)
    {
        // Companyモデルからcompany_idで情報を検出→オブジェクト化
        $company = Company::where('company_id', $request->company_id)->first();

--- 省略 ---

    }

\$company変数の定義を間違えていました。
\$company変数を、\$request->company_idと、フォームで入力された値と紐付けるのではなく、
companyテーブルに存在する全てのデータをオブジェクト化したものにするべきでした。

解決策

ということで、\$company変数の定義を下記のように書き換えると解決しました。

LoginController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Models\Company;

class CpyLoginController extends Controller
{
    //
    public function index(Request $request)
    {
        return view('pages.cpylogin');
    }

    public function post(Request $request)
    {
        $validate_rule = $request->validate([
            'company_id' => ['required']
        ]);

        // Companyモデルからcompany_idで情報を検出→オブジェクト化
        $company = Company::all()->first();
        $msg = ['msg' => '入力されたIDは存在しません'];

        if ($request->company_id === $company->company_id) {
            return redirect()->route('usrlogin');
        }
        else {
            return view('pages.cpylogin', $msg);
        }
    }
}

\$company変数をCompanyモデルから全て取り出しオブジェクト化したデータと定義することで、うまくいきました。

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

【?初心者】Laravelで問題解決を試みたポートフォリオ

logo.png

概要

車両を保有している人と保有していない人を結ぶアプリケーション。大手カーシェアリングサービスのように車両を会社からドライバーに貸し出す(BtoB)のでなく、個人間で気軽に貸し借りができるサービス(CtoC)をコンセプトとした。
[→アプリケーション リンク]
スクリーンショット 2021-02-13 15.35.44.png

制作背景

交通インフラの整備や若者の車離れの影響を受け、自動車の国内需要は1990年ごろをピークとして年々減少している。これに伴い、大手のBtoBカーシェアリングサービス(タイムズ)の会員数は過去5年間で約4倍以上伸びている。対して、今後伸びてくると予想されていたCtoCのカーシェアリング業界は伸び悩んでいるというギャップが生じている。この現象に疑問を持ったため、原因をトヨタの問題解決の手法を用いて考え、このギャップを解決するサービスの開発を行った。
[→制作背景詳細 リンク]

システム概要

このサービスのユーザーは3パターンに分けられる。
A. ドライバー (車を借りたい人)
B. オーナー (車を貸したい人)
C. 管理者 (Car.マッチング株式会社:自動車保険会社)
systemflow.png

操作説明

各ユーザーの操作方法について下記に示す。
[→操作詳細説明 リンク]

A. ドライバーの基本操作

①ログイン
②希望の条件(日時や乗車人数)で検索
③該当したオーナーとチャットでの交流
④車両を借りることへの不安がなくなれば、契約を結んでもらえるようオーナーへ依頼
driver.gif


B. オーナーの基本操作

①ログイン
②車両を貸し出せる日程を登録
③ドライバーから依頼があればチャットにて交流
④オーナーとドライバーが契約条件に合意した場合、契約フォームに入力
⑤確認メール送信


C. 管理者(Car.マッチング株式会社:自動車保険会社)の基本操作

①ドライバーとオーナー間で契約が結ばれた後、DBへ内容が保存されるため、それらを表示
②この登録情報を見て自動車の保険の加入手続き・料金の支払い手続きに移行
admin.png

こだわり

私はCtoCのカーシェアリング業界が伸びていない原因は主に下記の3点に起因すると考える。
①初期登録操作のハードルが高い
②条件に合う車両を探す作業が煩わしい
③全く交流がない他人から車両を借りることへの不安がある

これらを解決するために下記にこだわって開発した。

A. 初期登録の簡略化
初期の登録はなるべくシンプルにしておき、ドライバーとオーナーの交渉が成立してから、更に必要な情報を入力させる。ナンバープレート情報や料金の設定など初期登録の際に煩わしさを感じるものは契約時に入力させる。

B. 操作がシンプル
マルチログイン機能を実装してドライバーとオーナーの操作を分け、余分な機能は付けず、直感的に分かりやすい構成を心がける。
* ドライバーの操作: 初期登録 → 検索 → チャットによるオーナーとの交渉
* オーナーの操作 : 初期登録→ 貸出日程登録 → チャット → 契約詳細入力

C. LINEのような手軽さで個人間でチャットが可能(非同期通信)
アプリ内のチャット機能を、スマートフォンユーザーのおよそ80%が利用しているLINEの操作に合わせることで、誰でも容易にチャット機能を使って交流できる。また、非同期通信を行うことによって画面の遷移無しで、相手のメッセージを受け取ることができる。

上記とは色合いが異なるが、その他にもユーザーと管理者を思いやった機能も追加した。

D. 契約内容のエビデンスとしてメールの自動送信
オーナーが契約内容を入力後、確認メールが自動でドライバー・オーナー・Carマッチング(自動車保険会社)へと送付される。これにより、ドライバーとオーナーとの間で契約した内容を失念しても、再度確認することができる。また、料金や内容の相違でトラブルが起きた際に、エビデンスとして示すこともできる。

E. 管理者用の契約内容閲覧機能
ドライバーとオーナー間で契約が結ばれた後、DBへその内容が保存されるため、その内容を表示する機能。その内容を見て自動車の保険の加入手続き・料金の支払い手続きに移行する。

使用技術

バックエンド
PHP 7.2.34 / Laravel 6.20.5

フロントエンド
HTML / CSS / javascript / jQuery 3.2.1 / Vue.js(現在学習中のため今後組み込む)

インフラ
mysql 8.0.22 / AWS(EC2,S3)

その他の使用技術
Pusher / git(gitHub) / Visual Studio Code / draw.io / Gmail

AWS構成図

aws.png

DB設計

・ ER図

finaltable.png

・ 各種テーブル

テーブル名 定義
owners
(オーナー)
オーナーの登録情報
drivers
(ドライバー)
ドライバーの登録情報
owner_schedules
(オーナースケジュール)
ドライバーの車両貸出可能な日程
chats
(チャット)
会話の内容
contracts
(コントラクト)
契約確定後、契約内容を格納

苦労したところ

①DB設計

ER図を添付していますが、実際のアプリケーションとテーブル名やカラム名に相違があります。テーブルの命名規則の理解が曖昧ままDB設計をしており、キャメルケースを用いた記述をしてしまいました。開発終盤に気付きましたが、影響範囲が広すぎて修正が困難になりました。この失敗を二度と繰り返さないよう再度学習を行い、Qiitaにまとめています。初期設計の重要性を身に染みて学びました。[→Qiita記事 リンク]

②Laravelのマルチログイン機能

ドライバーとオーナーで初期の登録方法やログインした後の挙動が変わるため、マルチログイン機能を実装する必要がありました。Laravelでは基本のログイン機能がついていますが、これを応用して2通りのログイン機能を作りました。変更が必要なファイルが多く、それぞれの関連性が分かっていなかったため、苦労しました。ここで3日以上も悩んだことで認証やミドルウェア・ルーティングについての知識を身に着けることができました。[→Qiita記事 リンク]

③AWSでのデプロイ

web系企業ではクラウドはAWSが主流になっていますのでAWSを用いて本番環境を構築しました。初めてのVimコマンドの操作に慣れていないことや、ディレクトリの階層も頭に入っていなかったことで、configファイルや.envファイルを探したり編集するだけでかなり難航しました。VPCの生成から数えると30〜40時間以上かけてなんとかデプロイしました。多く悩んだ分、仮想サーバーやIPアドレスの知識・コマンドの操作などを身に着けることができました。

④websocket通信を用いたチャットの非同期通信

外部API(pusher)を用いたリアルタイムチャットの実装に挑戦しました。実装に必要な作業をなるべく最小単位に分割して進めていきました。非同期でのメッセージの受信はできるようになったものの、ドライバー側からのメッセージなのかオーナー側からのメッセージなのかを分岐させることができません。少し手詰まり状態にありますが、今も諦めずにトライしています。

⑤LaravelのCollection型の条件分岐(ユーザーからのフィードバック)

知人にアプリケーションの操作トライを依頼した際に、「検索後、該当するものが無かった時にコメントが出ないので分からない」とアドバイスを受けました。これを受け、検索する前・検索して成功した時・検索して失敗した時と3つの条件で表示を分岐させました。この時にLaravelのCollection型の扱いについて理解が少なく、空値判定がうまくいかず長時間悩んでしまいましたので、学習してQiitaにまとめました。[→Qiita記事 リンク]

最後に

転職活動のポートフォリオとして製作しています。実務未経験者が独学で作ったため、内容に誤っている点があるかと思います。お手柔らかにお願いいたします。今後実務を経験して、過去の実力を振り返られるように記録として執筆しました。LGTMで応援いただけると励みになります。

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

【ポートフォリオ】初心者?がLaravelで問題解決を試みた

logo.png

概要

車両を保有している人と保有していない人を結ぶアプリケーション。大手カーシェアリングサービスのように車両を会社からドライバーに貸し出す(BtoB)のでなく、個人間で気軽に貸し借りができるサービス(CtoC)をコンセプトとした。
※悪意のあるイタズラが多発したため、アプリリンクは貼っていません。
スクリーンショット 2021-02-13 15.35.44.png

制作背景

交通インフラの整備や若者の車離れの影響を受け、自動車の国内需要は1990年ごろをピークとして年々減少している。これに伴い、大手のBtoBカーシェアリングサービス(タイムズ)の会員数は過去5年間で約4倍以上伸びている。対して、今後伸びてくると予想されていたCtoCのカーシェアリング業界は伸び悩んでいるというギャップが生じている。この現象に疑問を持ったため、原因をトヨタの問題解決の手法を用いて考え、このギャップを解決するサービスの開発を行った。
[→制作背景詳細 リンク]

システム概要

このサービスのユーザーは3パターンに分けられる。
A. ドライバー (車を借りたい人)
B. オーナー (車を貸したい人)
C. 管理者 (Car.マッチング株式会社:自動車保険会社)
systemflow.png

操作説明

各ユーザーの操作方法について下記に示す。

A. ドライバーの基本操作

①ログイン
②希望の条件(日時や乗車人数)で検索
③該当したオーナーとチャットでの交流
④車両を借りることへの不安がなくなれば、契約を結んでもらえるようオーナーへ依頼
driver.gif


B. オーナーの基本操作

①ログイン
②車両を貸し出せる日程を登録
③ドライバーから依頼があればチャットにて交流
④オーナーとドライバーが契約条件に合意した場合、契約フォームに入力
⑤確認メール送信
ownerQiita2.gif


C. 管理者(Car.マッチング株式会社:自動車保険会社)の基本操作

①ドライバーとオーナー間で契約が結ばれた後、DBへ内容が保存されるため、それらを表示
②この登録情報を見て自動車の保険の加入手続き・料金の支払い手続きに移行
admin.png

こだわり

私はCtoCのカーシェアリング業界が伸びていない原因は主に下記の3点に起因すると考える。
①初期登録操作のハードルが高い
②条件に合う車両を探す作業が煩わしい
③全く交流がない他人から車両を借りることへの不安がある

これらを解決するために下記にこだわって開発した。

A. 初期登録の簡略化
初期の登録はなるべくシンプルにしておき、ドライバーとオーナーの交渉が成立してから、更に必要な情報を入力させる。ナンバープレート情報や料金の設定など初期登録の際に煩わしさを感じるものは契約時に入力させる。

B. 操作がシンプル
マルチログイン機能を実装してドライバーとオーナーの操作を分け、余分な機能は付けず、直感的に分かりやすい構成を心がける。
* ドライバーの操作: 初期登録 → 検索 → チャットによるオーナーとの交渉
* オーナーの操作 : 初期登録→ 貸出日程登録 → チャット → 契約詳細入力

C. LINEのような手軽さで個人間でチャットが可能(非同期通信)
アプリ内のチャット機能を、スマートフォンユーザーのおよそ80%が利用しているLINEの操作に合わせることで、誰でも容易にチャット機能を使って交流できる。また、非同期通信を行うことによって画面の遷移無しで、相手のメッセージを受け取ることができる。

上記とは色合いが異なるが、その他にもユーザーと管理者を思いやった機能も追加した。

D. 契約内容のエビデンスとしてメールの自動送信
オーナーが契約内容を入力後、確認メールが自動でドライバー・オーナー・Carマッチング(自動車保険会社)へと送付される。これにより、ドライバーとオーナーとの間で契約した内容を失念しても、再度確認することができる。また、料金や内容の相違でトラブルが起きた際に、エビデンスとして示すこともできる。

E. 管理者用の契約内容閲覧機能
ドライバーとオーナー間で契約が結ばれた後、DBへその内容が保存されるため、その内容を表示する機能。その内容を見て自動車の保険の加入手続き・料金の支払い手続きに移行する。

使用技術

バックエンド
PHP 7.2.34 / Laravel 6.20.5

フロントエンド
HTML / CSS / javascript / jQuery 3.2.1 / Vue.js(現在学習中のため今後組み込む)

インフラ
mysql 8.0.22 / AWS(EC2,S3)

その他の使用技術
Pusher / git(gitHub) / Visual Studio Code / draw.io / Gmail

AWS構成図

aws.png

DB設計

・ ER図

finaltable.png

・ 各種テーブル

テーブル名 定義
owners
(オーナー)
オーナーの登録情報
drivers
(ドライバー)
ドライバーの登録情報
owner_schedules
(オーナースケジュール)
ドライバーの車両貸出可能な日程
chats
(チャット)
会話の内容
contracts
(コントラクト)
契約確定後、契約内容を格納

苦労したところ

①DB設計

ER図を添付していますが、実際のアプリケーションとテーブル名やカラム名に相違があります。テーブルの命名規則の理解が曖昧ままDB設計をしており、キャメルケースを用いた記述をしてしまいました。開発終盤に気付きましたが、影響範囲が広すぎて修正が困難になりました。この失敗を二度と繰り返さないよう再度学習を行い、Qiitaにまとめています。初期設計の重要性を身に染みて学びました。[→Qiita記事 リンク]

②Laravelのマルチログイン機能

ドライバーとオーナーで初期の登録方法やログインした後の挙動が変わるため、マルチログイン機能を実装する必要がありました。Laravelでは基本のログイン機能がついていますが、これを応用して2通りのログイン機能を作りました。変更が必要なファイルが多く、それぞれの関連性が分かっていなかったため、苦労しました。ここで3日以上も悩んだことで認証やミドルウェア・ルーティングについての知識を身に着けることができました。[→Qiita記事 リンク]

③AWSでのデプロイ

web系企業ではクラウドはAWSが主流になっていますのでAWSを用いて本番環境を構築しました。初めてのVimコマンドの操作に慣れていないことや、ディレクトリの階層も頭に入っていなかったことで、configファイルや.envファイルを探したり編集するだけでかなり難航しました。VPCの生成から数えると30〜40時間以上かけてなんとかデプロイしました。多く悩んだ分、仮想サーバーやIPアドレスの知識・コマンドの操作などを身に着けることができました。

④websocket通信を用いたチャットの非同期通信

外部API(pusher)を用いたリアルタイムチャットの実装に挑戦しました。実装に必要な作業をなるべく最小単位に分割して進めていきました。非同期でのメッセージの受信はできるようになったものの、ドライバー側からのメッセージなのかオーナー側からのメッセージなのかを分岐させることができません。少し手詰まり状態にありますが、今も諦めずにトライしています。

⑤LaravelのCollection型の条件分岐(ユーザーからのフィードバック)

知人にアプリケーションの操作トライを依頼した際に、「検索後、該当するものが無かった時にコメントが出ないので分からない」とアドバイスを受けました。これを受け、検索する前・検索して成功した時・検索して失敗した時と3つの条件で表示を分岐させました。この時にLaravelのCollection型の扱いについて理解が少なく、空値判定がうまくいかず長時間悩んでしまいましたので、学習してQiitaにまとめました。[→Qiita記事 リンク]

最後に

転職活動のポートフォリオとして製作しています。実務未経験者が独学で作ったため、内容に誤っている点があるかと思います。お手柔らかにお願いいたします。今後実務を経験して、過去の実力を振り返られるように記録として執筆しました。LGTMで応援いただけると励みになります。

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

【ポートフォリオ】初心者?がLaravelでカーシェアアプリ開発

logo.png

概要

車両を保有している人と保有していない人を結ぶアプリケーション。大手カーシェアリングサービスのように車両を会社からドライバーに貸し出す(BtoB)のでなく、個人間で気軽に貸し借りができるサービス(CtoC)をコンセプトとした。
※悪意のあるイタズラが多発したため、アプリリンクは貼っていません。
スクリーンショット 2021-02-13 15.35.44.png

制作背景

交通インフラの整備や若者の車離れの影響を受け、自動車の国内需要は1990年ごろをピークとして年々減少している。これに伴い、大手のBtoBカーシェアリングサービス(タイムズ)の会員数は過去5年間で約4倍以上伸びている。対して、今後伸びてくると予想されていたCtoCのカーシェアリング業界は伸び悩んでいるというギャップが生じている。この現象に疑問を持ったため、原因をトヨタの問題解決の手法を用いて考え、このギャップを解決するサービスの開発を行った。
[→制作背景詳細 リンク]

システム概要

このサービスのユーザーは3パターンに分けられる。
A. ドライバー (車を借りたい人)
B. オーナー (車を貸したい人)
C. 管理者 (Car.マッチング株式会社:自動車保険会社)
systemflow.png

操作説明

各ユーザーの操作方法について下記に示す。

A. ドライバーの基本操作

①ログイン
②希望の条件(日時や乗車人数)で検索
③該当したオーナーとチャットでの交流
④車両を借りることへの不安がなくなれば、契約を結んでもらえるようオーナーへ依頼
driver.gif


B. オーナーの基本操作

①ログイン
②車両を貸し出せる日程を登録
③ドライバーから依頼があればチャットにて交流
④オーナーとドライバーが契約条件に合意した場合、契約フォームに入力
⑤確認メール送信
ownerQiita2.gif


C. 管理者(Car.マッチング株式会社:自動車保険会社)の基本操作

①ドライバーとオーナー間で契約が結ばれた後、DBへ内容が保存されるため、それらを表示
②この登録情報を見て自動車の保険の加入手続き・料金の支払い手続きに移行
admin.png

こだわり

私はCtoCのカーシェアリング業界が伸びていない原因は主に下記の3点に起因すると考える。
①初期登録操作のハードルが高い
②条件に合う車両を探す作業が煩わしい
③全く交流がない他人から車両を借りることへの不安がある

これらを解決するために下記にこだわって開発した。

A. 初期登録の簡略化
初期の登録はなるべくシンプルにしておき、ドライバーとオーナーの交渉が成立してから、更に必要な情報を入力させる。ナンバープレート情報や料金の設定など初期登録の際に煩わしさを感じるものは契約時に入力させる。

B. 操作がシンプル
マルチログイン機能を実装してドライバーとオーナーの操作を分け、余分な機能は付けず、直感的に分かりやすい構成を心がける。
* ドライバーの操作: 初期登録 → 検索 → チャットによるオーナーとの交渉
* オーナーの操作 : 初期登録→ 貸出日程登録 → チャット → 契約詳細入力

C. LINEのような手軽さで個人間でチャットが可能(非同期通信)
アプリ内のチャット機能を、スマートフォンユーザーのおよそ80%が利用しているLINEの操作に合わせることで、誰でも容易にチャット機能を使って交流できる。また、非同期通信を行うことによって画面の遷移無しで、相手のメッセージを受け取ることができる。

上記とは色合いが異なるが、その他にもユーザーと管理者を思いやった機能も追加した。

D. 契約内容のエビデンスとしてメールの自動送信
オーナーが契約内容を入力後、確認メールが自動でドライバー・オーナー・Carマッチング(自動車保険会社)へと送付される。これにより、ドライバーとオーナーとの間で契約した内容を失念しても、再度確認することができる。また、料金や内容の相違でトラブルが起きた際に、エビデンスとして示すこともできる。

E. 管理者用の契約内容閲覧機能
ドライバーとオーナー間で契約が結ばれた後、DBへその内容が保存されるため、その内容を表示する機能。その内容を見て自動車の保険の加入手続き・料金の支払い手続きに移行する。

使用技術

バックエンド
PHP 7.2.34 / Laravel 6.20.5

フロントエンド
HTML / CSS / javascript / jQuery 3.2.1 / Vue.js(現在学習中のため今後組み込む)

インフラ
mysql 8.0.22 / AWS(EC2,S3)

その他の使用技術
Pusher / git(gitHub) / Visual Studio Code / draw.io / Gmail

AWS構成図

aws.png

DB設計

・ ER図

finaltable.png

・ 各種テーブル

テーブル名 定義
owners
(オーナー)
オーナーの登録情報
drivers
(ドライバー)
ドライバーの登録情報
owner_schedules
(オーナースケジュール)
ドライバーの車両貸出可能な日程
chats
(チャット)
会話の内容
contracts
(コントラクト)
契約確定後、契約内容を格納

苦労したところ

①DB設計

ER図を添付していますが、実際のアプリケーションとテーブル名やカラム名に相違があります。テーブルの命名規則の理解が曖昧ままDB設計をしており、キャメルケースを用いた記述をしてしまいました。開発終盤に気付きましたが、影響範囲が広すぎて修正が困難になりました。この失敗を二度と繰り返さないよう再度学習を行い、Qiitaにまとめています。初期設計の重要性を身に染みて学びました。[→Qiita記事 リンク]

②Laravelのマルチログイン機能

ドライバーとオーナーで初期の登録方法やログインした後の挙動が変わるため、マルチログイン機能を実装する必要がありました。Laravelでは基本のログイン機能がついていますが、これを応用して2通りのログイン機能を作りました。変更が必要なファイルが多く、それぞれの関連性が分かっていなかったため、苦労しました。ここで3日以上も悩んだことで認証やミドルウェア・ルーティングについての知識を身に着けることができました。[→Qiita記事 リンク]

③AWSでのデプロイ

web系企業ではクラウドはAWSが主流になっていますのでAWSを用いて本番環境を構築しました。初めてのVimコマンドの操作に慣れていないことや、ディレクトリの階層も頭に入っていなかったことで、configファイルや.envファイルを探したり編集するだけでかなり難航しました。VPCの生成から数えると30〜40時間以上かけてなんとかデプロイしました。多く悩んだ分、仮想サーバーやIPアドレスの知識・コマンドの操作などを身に着けることができました。

④websocket通信を用いたチャットの非同期通信

外部API(pusher)を用いたリアルタイムチャットの実装に挑戦しました。実装に必要な作業をなるべく最小単位に分割して進めていきました。非同期でのメッセージの受信はできるようになったものの、ドライバー側からのメッセージなのかオーナー側からのメッセージなのかを分岐させることができません。少し手詰まり状態にありますが、今も諦めずにトライしています。

⑤LaravelのCollection型の条件分岐(ユーザーからのフィードバック)

知人にアプリケーションの操作トライを依頼した際に、「検索後、該当するものが無かった時にコメントが出ないので分からない」とアドバイスを受けました。これを受け、検索する前・検索して成功した時・検索して失敗した時と3つの条件で表示を分岐させました。この時にLaravelのCollection型の扱いについて理解が少なく、空値判定がうまくいかず長時間悩んでしまいましたので、学習してQiitaにまとめました。[→Qiita記事 リンク]

最後に

転職活動のポートフォリオとして製作しています。実務未経験者が独学で作ったため、内容に誤っている点があるかと思います。お手柔らかにお願いいたします。今後実務を経験して、過去の実力を振り返られるように記録として執筆しました。

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

LaravelでFullcalendarに登録した内容を更新する方法

はじめに

前回に続き、今回はFullcalendarで登録した情報を更新する方法についてご説明します。
LaravelでFullcalendarを実装する方法

また、今回はカレンダー上の登録したイベントをクリックするとモーダルが出てきて、そのモーダル上で更新ができるようにします。モーダルでは更新前の情報も確認できるようにしたいと思います。

-各バージョン
-Laravel 6.x
-PHP 7.4.9
-MySQL 5.7.30
-Fullcalendar v5

Fullcalendarはバージョンによって記述方法が異なるので注意してください。
v4の記事を参考にしてもうまくいかないことが多かったです。

なお、フォルダ名とうは登録時に作成したものをそのまま使用しておりますのでご了承ください。

更新用のモーダルを用意する

モーダルはJavaScriptのプアグインであるMicromodal.jsを使用しました。
モーダルに関しては自作のものではなく、プラグインを利用した方が利点が多いというツイートを見かけたので、今回は自作をせずにプラグインを使用しています。

Micoromodal.jsのダウンロードは以下から行えます。
(https://micromodal.now.sh/)

今回はCDNで読み込ませました。

event.blade.php
<!-- Micromodal.js -->
<script src="https://unpkg.com/micromodal/dist/micromodal.min.js"></script>

続いて、モーダル用のbladeを作成し、更新フォームを作っていきます。
こちらはこの後@includeでevent.blade.php内で読み込ませるので、直接event.blade.php内に書いても問題ないです。

また、headerに関してはMicromodal.jsの公式ドキュメントを参考にしています。
フォームはmainタグ内に書いていきます。

moda.blade.php
<div class="modal micromodal-slide" id="modal-1" aria-hidden="true">
    <div class="modal__overlay" tabindex="-1" data-micromodal-close>
        <div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="modal-1-title">
            <header class="modal__header">
                <h2>Editing my task list</h2>
                <button class="modal__close" aria-label="Close modal" data-micromodal-close></button>
            </header>
            <main>
         <form method="POST" action="{{ route('editEvent') }}">
                 @csrf
                 <input type="hidden" id="id" value="" name="id">
           <input type="text" id="edit_title" name="title" value="">
           <input type="date" id="edit_start" name="start" value="">
           <input type="color" id="edit_color" name="textColor" value="">
          </form> 
            </main>
        </div>
    </div>
</div>

通常だとvalueに更新前の情報を入れることで、フォームで確認できるのですが、今回はJSで指定するので空にしています。

続いて、カレンダー上のイベントをクリックした際に、モーダルが出てくるように設定していきます。
カレンダー上のイベントをクリックした時の挙動は、Fullcalendarの公式ドキュメントを確認すると、eventClickというプロパティが用意されているようなので、こちらを前回作成したJSに追加していきます。
eventClick

event.blade.php
<script>
  $(document).ready(function () {
    $('#calendar').fullCalendar({
      // はじめりの曜日を月曜日に変更 デフォルトは日曜日になっており、日=0,月=1になる
      firstDay: 1,
      headerToolbar: {
                     right: 'prev,next'
                     },
      events: '/home',

     // ここから追加
    eventClick: function(info){
        document.getElementById("id").value = info.id;
        document.getElementById("edit_title").value = info.title
        document.getElementById("edit_start").value = info.start._i
        document.getElementById("edit_color").value = info.textColor
        MicroModal.show('modal-1');
     }
    });
  });
</script>

infoの中には更新前の情報が入っているので、その情報をそれぞれ先ほど指定したフォーム内のid属性をgetElementByIdで取得し、value値に指定しています。
また、startに関しては、console.log(info.start)で見てみると、_isAMomentObject: true, _i: "2021-02-06", _f: "YYYY-MM-DD", _isUTC: true, _pf:となっており、_iの箇所に日付が格納されているのがわかると思います。
そのため、info.start._iとすることで日付を取得するようにしています。

これで、更新前の情報が表示されるようになりました。

また、event.blade.php内でmodal.blade.phpを忘れずに読み込んでください。
私は前回作成した新規登録用のフォームの真下に書きました。

event.blade.php
@include('modal')

コントローラー、ビューを追加する

先ほどaction="{{ route('editEvent') }}で指定したルートを設定します。

web.php
Route::post('/editEvent', 'EventController@editEvent');

続いてコントローラーです。

EventController.php
use App\Models\Event; //冒頭で宣言する

 public function editEvent(Request $request)
    {  
     // 送信されてきたidをEventテーブルに登録されているデータと紐付ける
        $event = Event::find($request->input('id'));
        $event->title = $request->input('title');
        $event->start = $request->input('start');
        $event->textColor = $request->input('textColor');

        $event->save();

        return redirect('/home');
    }

以上で更新用モーダルの完成です!

さいごに

今回は、前回作成したFullcalendarの更新処理を、モーダルを利用して作ってみました。
また次回以降は登録したデータの削除方法についても書いていきたいと思います!

最後まで読んでいただきありがとうございました!

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

DiscordPHP + 形態素解析


タグがPばかりで面白いですね
100年くらい前にやった人工無能作成の解説記事です

目次


  1. 形態素解析ってなに?

  2. DiscordPHPってなに?

  3. 形態素解析をして出力を確認する

  4. プラグインでbotを実装してみる

  5. まとめ

  6. 参考文献


1. 形態素解析ってなに?


文章にはいろんな名詞や動詞といった品詞が隠れています
文章中を一つ一つの小さな意味として品詞に分解したものを形態素と呼びます

形態素はそれ以上細分化すると意味を成しません
中学校で国語の勉強を怠けた人は何とか頑張りましょう


形態素解析は文章を形態素に分解する解析のことを指します
今回やるのは解析した形態素を組み合わせて一つの文章にするってことです

解析の方法として、ライブラリを使用して形態素解析をします
有名なもので 解析サイト にアクセスして結果をいただく実装をします


[備考]

  形態素の感情を分析する感情分析というのがあります
  簡単に例えると "ポジティブ" か "ネガティブ" な単語なのか分析します

  そういうことがphp-mlでできるらしいということで探していたのですが、
  リポジトリが消えていたので三日間は夜しか眠れませんでした 

2. DiscordPHPってなに?


Discordのbotをphpで動かしたい物好きな方のために
有志な勇者が作成してくださったライブラリです

今回はComposerを使って使用するのですが、Composerの説明は他の方に任せます


DiscordPHP は一つのスレッドを占領します
なのでbotがする処理以外のことを外部からはあまりできません

説明項目 #4. プラグインでbotを実装してみる では、PMMPを使用した環境を前提としてマルチスレッドでbotを動かし #3. 形態素解析をして出力を確認する を用いて文章を作成してレスポンスする実装をします

3. 形態素解析をして出力を確認する


以下、解析方法と出力結果。

Morph.php
<?php

$id = '取得したID';
$sentence = "今日のご飯はモンスターエナジーです。";

$data = ['app_id' => $id, 'sentence' => $sentence];
$curl = curl_init("https://labs.goo.ne.jp/api/morph");

curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_COOKIEFILE, 'tmp');
curl_setopt($curl, CURLOPT_COOKIEJAR, 'cookie');
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data));


var_dump(json_decode(curl_exec($curl), true)["word_list"]);


result.txt
array(1) {
  [0]=>
  array(8) {
    [0]=>
    array(3) {
      [0]=>
      string(6) "今日"
      [1]=>
      string(6) "名詞"
      [2]=>
      string(9) "キョウ"
    }
    [1]=>
    array(3) {
      [0]=>
      string(3) "の"
      [1]=>
      string(9) "格助詞"
      [2]=>
      string(3) "ノ"
    }
    [2]=>
    array(3) {
      [0]=>
      string(6) "ご飯"
      [1]=>
      string(6) "名詞"
      [2]=>
      string(9) "ゴハン"
    }
    [3]=>
    array(3) {
      [0]=>
      string(3) "は"
      [1]=>
      string(12) "連用助詞"
      [2]=>
      string(3) "ハ"
    }
    [4]=>
    array(3) {
      [0]=>
      string(15) "モンスター"
      [1]=>
      string(6) "名詞"
      [2]=>
      string(15) "モンスター"
    }
    [5]=>
    array(3) {
      [0]=>
      string(12) "エナジー"
      [1]=>
      string(6) "名詞"
      [2]=>
      string(12) "エナジー"
    }
    [6]=>
    array(3) {
      [0]=>
      string(6) "です"
      [1]=>
      string(9) "判定詞"
      [2]=>
      string(6) "デス"
    }
    [7]=>
    array(3) {
      [0]=>
      string(3) "。"
      [1]=>
      string(6) "句点"
      [2]=>
      string(0) ""
    }
  }
}

4. プラグインでbotを実装してみる


基本的な実装の仕方
- DiscordPHPは神だった

プラグイン作ってみた
- ribnil/MorphBot


概要

プラグインが読み込まれたときにデータをThreadに渡してそれをもとに形態素解析してる
5分に一回集めたデータを解析してthreadが止まったらデータを保存してる


自分のギルドのIDだったり形態素解析させてくれるサイトで取得したIDだったり
もっと処理をいじりたかったら必要に応じて編集してください

DiscordThread.php
define('APP_ID', '');
define('BOT_TOKEN', '');

define('GUILD_ID', '');
define('MAIN_CHAT_CHANNEL_ID', '');

taken: botのトークン
logging: botの動作ログの表示
intents: 受け取るイベントの種類(?)

DiscordThread.php
$discord = new Discord([
    'token' => BOT_TOKEN,
    'logging' => false,
    'intents' => [Intents::GUILD_MESSAGES]
]);


まとめ

やっぱりphpってサイコーだな!(笑)

botの用意とかappidの用意とか面倒くさいけれど頑張ってください
動かなくても怒らないでください、怒りよりissueを投げてくれると安心します


いい感じの文章を作りたいと思っていても
あんなにひどい出力から品詞を分別するのがとても苦労すると思います

そこは開発者としての意地と根性を使って何とかしてほしいです
(出来たら僕にも送ってください)


PMMPプラグイン開発者グループ
- server.mcbe.jp : Discord



参考文献

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

Composerをダウングレードする手順メモ

はじめに

Composer 2.0がリリースされており、更新した方も多いと思います。

v1系はいずれEOLになるでしょうし、今後、開発ではv2を採用するでしょう。

今回は調査の過程でやむを得ず、ローカルに Composer 1.xが必要になり作業したので、メモしておきます。

アンインストール

多くの場合、以下のディレクトリにあると思いますので、削除します。

$ cd /usr/local/bin
$ rm -r composer

上記になければ、which で探して消しましょう。

$ which composer
/path/to/dir/composer

$ cd /path/to/dir
$ rm -r composer

v1系のインストール

公式サイトを確認します(https://getcomposer.org/download/ )。
インストール用のスクリプトは既にv2系統になっていますが、ページ中程に Manual Download の案内があります。

今回は、 Latest 1.x のリンク からダウンロードしました(2021/2/13 に確認)。

terminal でファイルをダウンロードした場所に移動し、ファイルを移動させます。
このとき、macに設定しているパスワードを入力します。

$ cd ~/Downloads
$ sudo mv composer.phar /usr/local/bin/composer
Password:

パーミッションを設定する

ファイルを移動しただけだと composer not found で怒られるかと思います。

実行可能なように権限を設定しましょう。

$ chmod a+x /usr/local/bin/composer

バージョンを確認します。

$ composer -v
   ______
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                    /_/
Composer version 1.10.20 2021-01-27 15:41:06

無事、v1系を使えるようになりました。

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