20201014のPHPに関する記事は18件です。

DockerでWordPressの開発環境をサクッと構築する

TL;DR

https://github.com/qpSHiNqp/docker-wordpress-dev

これcloneして docker-compose up すると、一瞬でWordPress環境立ち上がるよ

目次

  1. dockerでWordPress環境を構築するまで
  2. テーマ作るときに、コンテンツ部分に適用されるスタイルをよしなにいい感じにする(ついでに書いてるだけ)

dockerでWordPress環境を構築するまで

経緯

たまたまちょいとWordPressいじる必要が生じた。開発環境を整えるために今までは、ローカルにMySQLサーバ立てて、DB作って、ユーザーと権限周り作って整えて、PHP環境作って、Webサーバ環境作って、繋いで、動作確認して... っていういわゆるMAMP的なのを頑張ってやってたんですが、今どきそんなこと普通しないだろ、ということでdockerで環境構築すべく、ちょっと調べた。

構築方法

調べたところ、wordpress っていうdocker imageもあるし、当然のことながら mysql もdocker imageあるので、 docker-compose.yml いい感じに作ればいじゃんという話になり、作った。

作り方についても、 wordpress のDocker HubのDescriptionに丁寧に書いてあったので、参考情報として記載しておく。
ページ中頃の、「... via docker stack deploy or docker-compose」というセクションほぼそのまんま。

今回はテーマとかプラグインを作りたかったので、wp-content/themeswp-content/pluginsをマウントするようにdocker-compose.ymlを作成。
※最新のものはGitHubを参照してください。

version: '3.1'

services:

  wordpress:
    image: wordpress
    restart: always
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - wordpress:/var/www/html
      - ./wp-content/themes:/var/www/html/wp-content/themes
      - ./wp-content/plugins:/var/www/html/wp-content/plugins

  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - db:/var/lib/mysql

volumes:
  wordpress:
  db:

これで、 docker-compose up して http://localhost:8080 開くともうすぐに WordPressのセットアップ画面が開くので、そのまま進めば管理画面にいける。

テーマ作るときに、コンテンツ部分に適用されるスタイルをよしなにいい感じにする(ついでに書いてるだけ)

ここから先、本当についでに書いただけなので、自分の備忘録程度にしか使えないと思います。

自作テーマ作るときに、レイアウトとか、見た目とかをstyle.cssで制御すると思うんだけど、WordPressってWYSIWYGエディタを備えたCMSなので、コンテンツ部分のレイアウトはWordPress備え付けのものを生かしてあげる必要がある。

備え付けのstyleは、CSS « WordPress Codexの「WordPress Generated Classes」セクションに書いてあるもの。これを自作テーマの最下部にコピペしてあげることで、WYSIWYGで編集時に指定したレイアウトを実際の表示に反映することができた。

当初、自作style.cssで定義したスタイルがコンテンツ部分の要素にまで適用されていたことでWYSIWYGと見た目がずれてしまうという問題が発生してしまっていたが、おそらく下記のようにマークアップの責任分界をするとだいたい上手くいくような気がする。

  • テンプレ/テーマ側では、コンテンツをwrapするブロック要素のレイアウトだけHTML+CSSで制御してあげて、 <?php the_content(); ?> とかで埋め込むコンテンツ本体のレイアウトに影響しないようなstyle.cssにしてあげる
  • <h1>(か、若しくは<h2>)が投稿タイトルの表示を担当するなら、これはテンプレ側で表示を制御してあげたほうがいい
  • 文字色とかフォントとか、レイアウト以外の見た目に関するスタイルは style.css で定義して、コンテンツにも適用させるようにつくる(厳密に言うとフォントが違うとレイアウトも違ってくるとも言えるけど)

要は、WordPressのWYSIWYGが吐くHTMLなんて予想不可能なので、コンテンツ本文のブロックレイアウティングを自作cssで制御するのはたぶん無理。むしろテーマ作る側は、コンテンツ本文のブロックレイアウティングを制御せず放任してあげるようなクラス/セレクタ設計が必要な気がします。

カラーパレット機能とかサポートするように作っても良かったが、今回はそんなにWordPressの機能をフルサポートするような汎用的なテーマを作る必要がなかったので、最小限の機能サポートだけで実装した。

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

Laravel:componentの設定

【概要】

1.componentフォルダの作成

2.該当のblade.phpで呼び出し

3.開発環境

1.componentフォルダの作成

そもそもコンポーネントとは、レイアウトを最初から記述するために省き冗長にならないように部品のように使える仕組みです。ヘッター、フッターはどこのページにいっても同じデザインで使いたい場合に各レイアウトを統一する時に使用することが多いです。

viewsフォルダにcomponentsフォルダを作成します。さらにcomponentsフォルダの中に、適当なblade.phpファイルを作成します。

resorces/components/message.blade.php
  <div class="message">
    <p class="msg_title">{{$msg_title}}</p>
    <p class="msg_content">{{$msg_content}}</p>
  </div> 


2.該当のblade.phpで呼び出し

resorces/views/hoge/index.blade.php
<html>
<head>
  @component('components.message') #---❶
   @slot('msg_title') #---❷
    こちらにメッセージを入力してください
   @endslot #---❷

   @slot('msg_content')
    メッセージの内容
   @endslot
  @endcomponent #---❶
</html>
</head>

❶:コンポーネントを使用するためにどのフォルダのどのファイルを使用するかを決めています。"components"ファイルの、"message.blade.php"なので、('components.message')とコーディングしています。範囲の終わりには@endcomponentで括れます。

❷:massage.blade.phpの{{$msg_title}}、{{$msg_content}}の変数を使用するために記述しています。cssが反映された状態でindex.blade.phpにそのまま使用できます。@slot(名前)でそのまま使用できます。 @endslotで括れます。


3.開発環境

PHP 7.4.10
Laravel 8.9.0
Apache 2.4.41

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

Laravel アウトプット

controller editアクションメソッドを追加

LaravelではArticleモデルのインスタンスのDI(依存性の注入)が行われます。
DIが行われることで、editアクションメソッド内の$articleにはArticleモデルのインスタンスが代入された状態となっています。
スクリーンショット 2020-10-14 18.10.13.png

ログイン

ログインしているIDと記事の投稿したIDが同じであれば表示する。
スクリーンショット 2020-10-14 18.32.36.png

Null合体演算子(??)

$article->title ?? old('title')となっているコードの??はNull合体演算子と呼ばれるものです。
null合体演算子は、式1 ?? 式2という形式で記述し、以下の結果となります。

式1がnullでない場合は、式1が結果となる
式1がnullである場合は、式2が結果となる
スクリーンショット 2020-10-14 18.53.22.png

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

PHPセキュリティ入門【これだけはやろう】

セキュリティについて、
"安全なWebアプリケーションの作り方 第二版(徳丸浩著)"を読みましたので
アウトプットとして、
細かいところは置いといて
最低限の守るべきところをまとめました!

1. POSTの値を使うときはfilter_inputをかける

2. 外部からコードやファイル名を取り込むのは避け、どうしても使うときはエスケープする

3. バリデーションはアプリケーション要件に沿って行うだけでも効果あり

4. eval関数は使わない

5. APIを呼ぶときはMIMEタイプを正しく指定する

6. hiddenパラメータ、クッキーは書き換え可能という前提を持つ

7. htmlspecialchars関数の文字コード指定は必須

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

javascriptのLocalStorage を使ってお気に入り機能を自作してみた ①準備編

どうも7noteです。プラグインより多機能なお気に入り機能を作成。まずは準備編。

wordpressの投稿にお気に入り機能を実装するため、プラグインの導入を検討したのですが欲しい機能がついているプラグインがなく、

「プラグインがないならもう自作で実装してしまえ!」

と思って、javascript開発経験が浅い頃に3日かけて作成したお気に入り機能です。
書き方など至らぬ所多々あるかもしれませんが、優しく見守ってください。

この記事を読む前に

できるだけド素人でもわかりやすく説明していく予定です。
ですが、本当に1から始めると日が暮れてしまうので、最低限WEBに関する事をある程度理解をされている以下のような方向けの記事になっています。

・HTML・CSS・javascriptの初歩的な書き方を知っている人
・WordPressがなんとなくどういうものか知っている人(wordpressに応用しなければ別にOK)
・ゴリゴリのプロじゃない人

よく出てくる用語集

単語・用語 説明
Wordpress 代表的なCMSの1つ。サイトのページ管理や記事の投稿などができる。データベースの知識がない人でも簡単に使うことができる。
LocalStorage 今回の主役。webブラウザ(ローカル環境)にデータを保管できる仕組み。ここにお気に入りしたデータなどを保存する。
JSON JavaScript Object Notationの略で、データ形式の種類の事。文字列しか扱えない場合に仕様される事が多い(と思う。)人が見ても分かりやすいフォーマットのため、様々なシーンでよく使われる。

LocalStorageとは

LocalStorage

別称でwebstoroageなんて呼ばれ方もします。
ホームぺージを表示するには、ホームぺージのデータが格納されているサーバーと、それを表示するためのブラウザが必要になります。主にホームぺージに関わるデータのほとんどははこの2箇所で扱われます。その中で、ブラウザの中にデータを保管しておくことができる仕組みのことをLocalStorageと言います。

似たようなもの

LocalStorageと似ているものでクッキーセッションと呼ばれるものがあります。
詳しい違いは検索していただければ多くの情報が見つかるので詳しくは説明しませんが、Local Storageは消さない限り半永久的にデータが保存されるということと、個人情報は取扱わない事だけ覚えておきましょう。

※詳しく知りたい方は違いを書かれた記事がありましたので、こちらをどうぞ。
https://qiita.com/pipiox/items/95554673ba3b078ac112

特徴

  • データはブラウザに保管される。
  • 消さない限り半永久的にデータが保存される。
  • 永久保存されるので、個人情報に関するようなデータは取扱わない方が良い。
  • 形式は文字列のみ。
  • {キー:値}の形で保存できる。
  • 複数の値を保持するには、JSON形式に変換する必要がある。

開発に必要なもの

特に特別な何かをインストールしたりせずに扱うことができます。
コマンドプロンプトを立ち上げてなんやかんやをインストールするなどの手順は必要ありません!
ただ、javascriptの記述にjQueryを使用していますので、ご注意ください。

jQueryって何?という方はこちら

「Wordpressで使いたいよ!」という方は、自由にカスタマイズできるWordpressの開発環境を整えてください。
Wordpressを使用する場合少しだけphpの記述も必要になるので、基礎的なphpの書き方を理解しておくことをオススメします。


これで準備は整いました。次からは実際にソースを書いていきます。

【続き】 javascriptのLocalStorage を使ってお気に入り機能を自作してみた ②実装編-基盤作り-

おそまつ!

~ Qiitaで毎日投稿中!! ~
【初心者向け】HTML・CSSのちょいテク詰め合わせ

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

Contact Form 7の特定の項目のエラーメッセージの位置を変更する

色々迷子したので残しておきます。

参考にした文献
Contact Form 7で特定の入力項目のエラーメッセージの位置を変更する
Contact Form 7のエラーメッセージの表示位置を変更する
wordpress:ContactForm7でvar_dumpしたい

開発環境
WordPress 5.4.2
Contact Form 7 5.2.1

とりあえず前置きいいから、上記環境で動くコードは下記通り。

function wpcf7_custom_item_error_position( $items, $result ) {
    $class = 'wpcf7-custom-item-error';
    $names = array( 'sample' );

    if ( isset( $items['invalid_fields'] ) ) {
        foreach ( $items['invalid_fields'] as $k => $v ) {
            $orig = $v['into'];
            $name = substr( $orig, strrpos($orig, ".") + 1 );
            if ( in_array( $name, $names ) ) {
                $items['invalid_fields'][$k]['into'] = ".{$class}.{$name}";
            }
        }
    }
    return $items;
}
add_filter( 'wpcf7_ajax_json_echo', 'wpcf7_custom_item_error_position', 10, 2 );

Contact Form 7のエラーメッセージの表示位置を変更する で書かれている通り、
Contact Form のバージョンによって設定情報が変更になる。
その都度変更情報を確認して、該当箇所を変更する必要がある。

変更箇所の確認方法は、
wordpress:ContactForm7でvar_dumpしたい
で記載のある通り、
chromeのデベロッパーツールならNetwork→XHR→Response
で確認することができる。

FireFoxだと
ネッワーク→XHR→応答
で確認できた。

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

Monolog使ってバッチのログをDBに出力する

あらすじ

業務でLaravel使っていたある日のこと。
元々ログはMonologを使って、ログ用のテーブルに出力していました。

バッチで出したログもそのテーブルに出す予定だったのですが、バッチログ用のテーブルを新たに作ってそっちに出力したいとのこと。

というわけで、調査のまとめとして投稿することにしました。

環境

  • Laravel7
  • MariaDB

新規作成・編集するもの

Monologはインストール済みとして考えます。
なかったらComposer使って入れてください。

マイグレーションファイル

Artisanコマンドを使ってサクっと作ります。
カラムは一先ず次のようにしていますが、各自の好きに設定して下さい。

  • batch_name
    • 動いたバッチの名前
  • level
    • ログレベル。成功なら200, エラーなら400が入る(その他の番号は分かんないです)
  • level_name
    • DEBUG, INFO, ERRORと言ったログレベルの区分
  • start_time
    • バッチ処理が始まった時間
  • end_time
    • バッチ処理が終わった時間
  • message
    • ログメッセージ
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateBatchLogsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('batch_logs', function (Blueprint $table) {
            $table->id();
            $table->string('batch_name');
            $table->string('level');
            $table->string('level_name');
            $table->datetime('start_time');
            $table->datetime('end_time');
            $table->string('message');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('batch_logs');
    }
}

.env

DB_BATCH_LOG_TABLE 以外は最初からある項目です。環境に合わせて記述します。

# いつものDB設定
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=hogeeeeee
DB_USERNAME=root
DB_PASSWORD=1234

# バッチログの出力先テーブル
DB_BATCH_LOG_TABLE=batch_logs

config/logging.php

configファイルにバッチログ用の設定を追加
handler の部分のクラスはこれから新しく作ります。

また、下記の参考記事のように env()の記述はconfig以外に書かないようするため、handler_withにenvの情報を書きます。
handler_withで書かれた情報は、handlerで指定したクラスのコンストラクタで受け取ることができます。

Laravel では env() を config 系ファイル以外の場所に書いてはいけない

        'batch' => [
            'driver' => 'monolog',
            'handler' => BatchMonologHandler::class,  # ← これから新しく作成します
            'handler_with' => [    # ← 'handler'で指定したクラスのコンストラクラで受け取り可
                'table' => env('DB_BATCH_LOG_TABLE', 'batch_logs'),
                'connection' => env('DB_LOG_CONNECTION', env('DB_CONNECTION', 'mysql')),
                'ratio' => env('DB_LOG_FLUSH_RATIO', 100),
                'limit' => env('DB_LOG_PRESERVE_DAYS', 30)
            ],
        ],

Loggers/BatchMonologHandler

下記の記事を参考にしました。
Laravel5.6でログをデータベースに記録する

namespace App\Loggers;


use Illuminate\Support\Facades\DB;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Logger;

class BatchMonologHandler extends AbstractProcessingHandler
{
    protected $table;
    protected $connection;
    protected $ratio;
    protected $limit;

    public function __construct(string $table, string $connection, string $ratio, int $limit, $level = Logger::DEBUG, $bubble = true)
    {
        $this->table = $table;
        $this->connection = $connection;
        $this->ratio = $ratio;
        $this->limit = $limit;
        parent::__construct($level, $bubble);
    }

    protected function write(array $record): void
    {
        $data = [
            'batch_name' => $record['context']['batch_name'],
            'start_time' => $record['context']['start_time']->format('Y-m-d H:i:s'),
            'end_time' => $record['context']['end_time']->format('Y-m-d H:i:s'),
            'message' => $record['message'],
            'level' => $record['level'],
            'level_name' => $record['level_name'],
        ];
        DB::connection($this->connection)->table($this->table)->insert($data);

        $ratio = $this->ratio;
        if (rand(0, $ratio - 1) == 0) {
            $this->deleteOld();
        }

    }

    protected function deleteOld()
    {
        $limit = $this->limit;
        $date = date('Y-m-d H:i:s', strtotime("-$limit days"));
        DB::connection($this->connection)->table($this->table)->where('created_at', '<', $date)->delete();
    }
}

BatchTest

バッチ処理を書くクラスです。Artisanコマンドで作成します。

Logファサードを使ってログを書いていますが、普通に書いてしまうと.envのLOG_CHANNELで設定されているものが適用されてしまいます。
そのためLog::channel('batch');で新しく記述した設定を使うようにしています。

また、ログを残すコードの第1引数はmessageです。他の情報は第2引数の配列で追加しています。

namespace App\Console\Commands;

use App\Models\Logs;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;

class BatchTest extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'batch:test';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'batch log test command';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        // config/logging.phpで設定したものを使用する
        $batch_log = Log::channel('batch');

        $start_time = Carbon::now();
        sleep(5);
        $end_time = Carbon::now();

        // 第1引数はmessage。他は第2引数の配列にする
        $batch_log->info('test batch start', [
            'batch_name' => 'test_batch',
            'start_time' => $start_time,
            'end_time' => $end_time,
        ]);

        return 0;
    }
}

結果

batch_logsテーブルには画像のようなレコードが追加されていました。

log.PNG

悩んだとこ

Log::info('hoge') のようなログ出力はよくやりますが、第2引数に配列を指定をするのはやったことなかったです。
なので、BatchMonologHandlerクラスのwtiteメソッドで「batch_nameなんてねーよ」って怒られた時は悩みました。配列で指定した内容をどこから取得するのは分かってなかったんです。

print_r($record)で中身を見るとcontextキーの中に含まれていたので解決できました。

まとめ

Monologを使って、バッチのログを指定したテーブルに出力することができました。
テーブルカラムや、BatchMonologHandlerクラスのwtiteメソッドをいじればいろんな形で出力できそうですね。
バッチファイルが増えてきたら、ログ出力する前のLog::channel('batch');を書くのが忘れそうっていうのが気になりますね。何かいい方法ないかな?

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

使おうぜ php 画像加工 Intervention\Image\Facades\Image;

とりあえず、表題の通り、phpを使って画像を加工したい。
しかし、できることが多すぎるので、よく使う機能だけをピックアップしていく。

下準備

インストール方法は、省く

HogeController.php
use Intervention\Image\Facades\Image;

背景に画像を重ねる

コロまるアイコンを背景画像に重ねる。
背景画像は whitebg.png (600x381) として保存しておく。

HogeController.php
//コロまる アイコン
$icon = 'https://pbs.twimg.com/profile_images/378800000552767745/fb8f309e621d078cfe46250d73d38047_normal.png';

//600 x 381 pixels
//https://twi.ski/img/whitebg.png
$bg = Image::make(public_path('/img/whitebg.png'));
$icon = Image::make($icon);

//bg に 対し真ん中に 重ねる
$bg->insert($icon,'center');

//nakayoshi.png として保存
$bg
->save(public_path('/tmp/nakayoshi.png'));

echo '<img src="/tmp/nakayoshi.png?'.time().'">';

nakayoshi.png

うーん♪キュート。

丸く切り抜き (マスク)

HogeContoller.php
$bg = Image::make(public_path('/img/blackbg.png'));

//コロまる アイコン 200 x 200 のサイズ
$icon = 'https://pbs.twimg.com/profile_images/378800000552767745/fb8f309e621d078cfe46250d73d38047_200x200.png';
$icon = Image::make($icon);
//背景は透過、真っ黒の円を 200 x 200 で作成
$mask = Image::make(public_path('img/mask200.png'));
$icon->mask($mask,true);
$bg->insert($icon, 'center');
//       nakayoshi.png として保存
$bg
->save(public_path('/tmp/nakayoshi.png'));

echo '<img src="/tmp/nakayoshi.png?'.time().'">';


nakayoshi (1).png

うーん!セクシー!

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

【PHP勉強中です!】クラスについて

はじめに

PHPの勉強をし始めた初心者ですが、勉強していることのメモとして投稿します。
(ちなみに初投稿です・・・)
同じようにPHP初心者の方に読んでいただけたら嬉しいです。

この記事では、PHPのクラスについてまとめています。

クラスとは

クラスとは変数と関数の集まりのことです。
クラス内では、変数のことをプロパティ、関数のことをメソッドと呼びます。

アクセス修飾子

アクセス修飾子を使うと、そのクラスがどこからアクセスできるのか指定することができます。
アクセス修飾子は以下の3種類です。

  • public→どこからでもアクセス可能
  • private→クラス内のみからアクセス可能
  • protected→クラス内とそのクラスの継承した子クラスからアクセスが可能

アクセス修飾子を指定しないとpublicになります。

クラスを定義する構文

class クラス名 {
    $変数名

    function 関数名(引数) {
    }

}

クラスを使うメリット

クラスを定義することで、簡単に変数や関数をまとめたものを使い回すことができます。
クラスを使いまわせる状態にすることをインスタンス化と呼びます。
そして、クラスをインスタンス化して使いまわせる状態にしたものをインスタンスと呼びます。

例えると、

  • クラス→車の設計図
  • インスタンス→車
  • インスタンス化→車を作成

というような感じです。
車の設計図(クラス)があればいくつも車(インスタンス)を作ることができます。

クラスからインスタンスを作成する構文

$変数名 = new クラス名(引数)

    function 関数名(引数) {
    }

}

作成したインスタンスは変数に代入します。
インスタンスは基本的に変数に代入して使うそうです。

インスタンスのプロパティやメソッドにアクセスする方法

アロー演算子というものを使います。

$インスタンスを代入した変数名 -> 呼び出したいインスタンスのプロパティ・メソッド名

クラスのプロパティとメソッドについて

先ほどは、インスタンスのプロパティとメソッドについて紹介しましたが、
実は、クラスのプロパティとメソッドというものもあります。

"static"という修飾子をつけることでクラスのプロパティ・メソッドになります。

アクセス修飾子 static $プロパティ名
アクセス修飾子 static function メソッド名 (引数) {
 //処理
}

staticについて

static宣言した場合、クラスに属したプロパティまたはメソッドになります。
そして、staticがあるプロパティとメソッドをそれぞれ、静的プロパティ静的メソッドと呼びます。

一方、staticを宣言しなかった場合、インスタンスに属したプロパティまたはメソッドになります。
staticがないとプロパティとメソッドは、インスタンスプロパティインスタンスメソッドとなります。

コンストラクタとは

コンストラクタとは、new演算子でインスタンス化するときに実行される特別なメソッドのことです。
メソッド名に __construct() と記述することで定義できます。

class クラス名 {
 function __construct (引数) {
  //処理
 }
}

コンストラクタはプロパティを初期化するときなどに使います。

$thisとは

$thisとは、インスタンス自身を指す特別な変数です。
インスタンス自身を指すので、インスタンスメソッドないでしか使うことができません。
また、静的メソッドの中でも使うことはできません。

クラスの継承について

クラスの継承とは基となるクラスの変数や関数を引き継いだ新しいクラスを定義することです。
基となるクラスを親クラス(スーパークラス)、継承したクラスを子クラス(サブクラス)と呼びます。

クラスを継承する構文

class クラス名 extends 親クラス{
}

継承における親子関係

PHPでは、親クラスを複数指定する継承する多重継承はできず、
ひとつの親クラスから継承する単一継承ができます。

子クラスは親クラスの変数や関数を引き継いでいますが、
反対に親クラスは小クラスの変数や関数を引き継ぐことはありません。

オブジェクトについて

オブジェクトは人によって、定義が異なりますが、

  • クラスとインスタンス
  • クラスのみ
  • インスタンスのみ

の3パターンを指していることが多いです。
オブジェクトと言われたときに何を指しているのかを考えて、適切なもの置き換えることが大切です。

最後に

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

この記事は、以下の記事を参考にさせていただきました。

【PHP超入門】クラス~例外処理~PDOの基礎

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

PHP8 に文字列判定を改善する関数が導入されます!

こんにちは。やまゆです。

PHP8 の RC 版がリリースされ、そろそろ触っても良い感じになってきました。

色々楽しく触ってみていますが、今回は 「文字列関連の新規関数」 を紹介したいと思います。

str_contains

RFC はこちら

Laravel などで既に実装されているこの str_contains ですが、コア関数として実装されることになりました。

str_contains(string $haystack, string $needle): bool

$haystack $needle の引数名はほかの str_ 関連関数でも使われますね。

false !== strpos($haystack, $needle)

という直感的でないやり方で現在の関数でも実現出来ますが、より簡単に文字列が中に含まれているかどうかを判定できるようになりました。

if (str_contains($request->getHeaderLine('Content-Type'), 'json')) {
  $request = $request->withParsedBody(json_decode((string)$request->getBody(), true));
}

雑実装ですがこういうロジックが分かりやすくなります。

<?php

// 実装例
var_dump(str_contains('Hello', 'He')); // bool(true)
var_dump(str_contains('Hello', '')); // bool(true)
var_dump(str_contains('➡⇦', '➡')); // bool(true)

※空文字は「全ての文字列にヒットする」という判定が一般的なため、 $needle が空文字列の場合は常に true が返ります。

str_starts_with, str_ends_with

RFC はこちら

str_contains より厳しい判定として、指定された $needle から始まった文字列かどうかを判定する str_starts_with と、指定された $needle で終わる文字列かどうかを判定する str_ends_with も追加されました。

<?php

// 実装例
var_dump(str_starts_with('Hello', 'He')); // bool(true)
var_dump(str_ends_with('Hello', '')); // bool(true)
var_dump(str_starts_with('➡⇦', '➡')); // bool(true)

文字列チェックが直感的に出来るようになりましたね。

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

インスタンスを使い捨てない。WebアプリのBule/Green風デプロイ(for PHP)

こんにちは。AWS歴3年生の人です。最近、アプリケーションのデプロイやAWSのCI/CDサービスについて勉強しています。その中でAWS CodeDeploy+EC2+PHPのインプレースデプロイをBule/Green風にしたのでご紹介します。(あくまで”風”です)

注意

  • 本記事は2020年8月28日時点でのバージョンで確認しました。

  • 記載のコードにつきましては参考となりますので、利用時の不具合について一切の責任を負いません。

デプロイタイプについて軽くおさらい

  • インプレース(In-place)デプロイ

    • 稼働中のインスタンス上に、新しいアプリケーションをインストールします。デプロイの前後で同じインスタンスが利用されます。
    • デプロイ中のサービス影響を回避するために、ロードバランサから切り離して1台ずつデプロイする構成をとることも可能です。
  • ブルーグリーン(Blue/Green)デプロイ

    • 稼動中とは別に新しくインスタンスを作成し、アプリケーションをインストールします。新旧インスタンスの切り替えはロードバランサでトラフィックをコントロールしサービス投入をします。
    • デプロイの前後で異なるインスタンスを利用します。旧インスタンスは破棄するか、障害時のロールバック用として待機、利用ができます。

アプリケーションデプロイの勉強はこちらの資料を参考にしました。説明図が分かりやすいです。

AWS Black Belt Online Seminar AWS Code Series Part 2

Blue/Greenではなく、In-placeで”Blue/Green風”にした経緯

Blue/Greenのメリットを知っている方は「なぜ、最初からBlue/Greenデプロイを選択しないの?」と、思うかもしれません。

Blue/Greenデプロイを実運用にのせるためには「インフラ(インスタンス)」と「アプリケーション」の2つを、適切なバージョンでリリースするので、インフラ運用チームとアプリ開発チームが一緒に運用設計を進めていくのがベターだと感じています。

しかし実際のプロジェクトでは、運用要件、性能要件、システムの難易度、体制と役割、コストなどさまざまな制約、条件があります。その中で、”必ずしも最新のアーキテクチャやテクノロジーがいつもベストな選択とはかぎらない” ということが、気づきになりその過程で、インプレースデプロイでBlue/Green風という手法を選択しました。

また、PHPのようなスクリプト言語でSSHを利用しないデプロイの事例紹介や記事があまりなく苦労したので、どなたかの参考になれば幸いです。

どこがBule/Green風なのか

 1. サービス稼働用とデプロイ用、2つのアプリケーションバージョンを持つ

インスタンスの代わりにアプリケーションの実体を格納するディレクトリをblueとgreenの2つ用意します。サービス用パスはシンボリックリンクにしてblue(もしくはgreen)の実体に向けておきます。デプロイ用パスもシンボリックリンクにしてgreen(もしくはblue)の実体に向けておきます。

 2. 旧から新へきりかえる

稼働中のシンボリック先をblueとしたとき、新しいアプリケーションはgreenにデプロイされます。その後、シンボリックリンクを切り替えることで、新しいアプリケーションを瞬時にリリースします。

 3. 一つ前のバージョンに戻すことも可能

新しいバージョンで問題が発生したときは、再度シンボリックリンクを切りかえることでロールバックができます

(注:緊急避難的に手動でシンボリックリンクを切りかえてロールバックもできますが、デプロイツールを使っている場合はその後のデプロイ整合性を合わせるために、手動ではなくデプロイツールを使ってロールバックすることをおすすめします)

image1.png

AWS CodeDeploy+インプレースの課題も併せて回避できる

SSHを使わずに済むので、デプロイツールはAWS CodeDeployのインプレースデプロイを選択したのですが、以下のような課題がでてきました。

  • アプリケーションリビジョンの展開中、ファイル参照ができない時間が発生する(AWS CodeDeployの仕様)

    • 特にアプリケーションリビジョンのサイズが大きすぎる場合はその時間が長くなります
    • 1台しかインスタンスが無い場合、その間はアプリケーションの実行はできません
  • ロードバランサでサービスから切り離してデプロイもできるが、一時的に縮退構成になる

    • リリースの時間帯やタイミングの考慮が必要
    • 毎回深夜帯の更新運用は避けたい

Bule/Green風にすることで、AWS CodeDeploy+インプレースの持つこれらの課題も回避することができます。

  • インスタンス1台でもデプロイ時の切り替えによる影響は、ほぼ一瞬
  • サービス中のインスタンスを切り離す必要がない
    • 全台ほぼ同時にデプロイができるので、時間も短くなります

試したAWS構成例

AWS CodeDeployとEC2で確認をしました。台数は1台から可能です。

image2.png

AWS CodeDeployの設定

押さえておく設定だけ挙げておきます。

設定名 補足
デプロイタイプ インプレース
デプロイ設定 AllAtOnce 全インスタンス同時にデプロイします
Load balancer OFF ロードバランシングは無効にしておきます
ロールバック 無効にする AWS CodeDeployのロールバックはデプロイ中にエラーが発生したときに一つ前のリビジョンに自動で戻してくれる便利な機能ですが無効にしておきます。今回のBlue/Green風ではサービス投入(切り替え)のコントロールはスクリプトで行います。

AppSpecの設定

ポイント

  • filesセクションのdestinationの値をデプロイ用のパスにしておきます
  • フックセクション(hooks)で実行するスクリプトを指定します

そのほかの値は参考となります。

version: 0.0
os: linux
files:
   - source: /
     destination: /var/www_deploy/
     overwrite: true
permissions:
  - object: /var/www_deploy
    owner: hoge
    group: fuga
    mode: 744
    type:
      - file
  - object: /var/www_deploy
    owner: hoge
    group: fuga
    mode: 755
    type:
      - directory
hooks:
   AfterInstall:
     - location: hooks/AfterInstall.sh
       timeout: 180
       owner: hoge
   ValidateService:
     - location: hooks/ValidateService.sh
       timeout: 180
       owner: hoge

AppSpecのフックセクション

フックセクションではデプロイの進行に応じてイベント実行するスクリプトを指定することができます。

セクション名 イベント説明 Blue/Green風のスクリプト内容
AfterInstall アプリケーションファイルの展開後、アプリケーションの設定やファイル権限の変更など使用します。 AfterInstall.shでは、サービスパスとデプロイパスのシンボリックリンクの入れ替え処理を行います。
ValidateService 最後にデプロイが正常に完了したことを確認するために使用されます。 ValidateService.shではチェック処理を行います。問題が発生した場合はシンボリックリンクを戻すなど必要な処理を実装することもできます。

使っているセクションだけ挙げています。その他の説明についてはこちらをご確認ください。

AWS > ドキュメント > AWS CodeDeploy >ユーザーガイド
AWS AppSpec 「フック」セクション

AfterInstall.sh(シンボリックリンクの切り替え)の例

最低限ですが、このようなスクリプトでリンク先のblueとgreenを切りかえることができます。

#!/bin/bash

SERVICE_PATH='/var/www'
SERVICE_DIR=`readlink ${SERVICE_PATH}`
DEPLOY_PATH='/var/www_deploy'
DEPLOY_DIR=`readlink ${DEPLOY_PATH}`

`ln -nfs ${DEPLOY_DIR} ${SERVICE_PATH}`
`ln -nfs ${SERVICE_DIR} ${DEPLOY_PATH}`

実際に試して感じたこと

  • 軽微なアプリケーションの更新作業などには向いています

    • 大規模改修や投入前検証で高い品質担保を毎回求められる場合は、メンテナンス計画や他の手法も検討したほうがよいかもしれません。
  • サービス切り替えやロールバックのスクリプト開発工数が増える

    • アプリケーションの配置はAWS CodeDeployがしてくれますが、その他の処理はhooksスクリプトで行います。そのため、実運用ではこれらのスクリプトの作りこみ、エラーハンドリングの実装など、品質を保持したデプロイを実現するための工数は多くなります。
  • 逆に、 柔軟な処理もスクリプトに実装できる(またそのスキルが必要)

    • AWS CodeBuildも同じく、ビルド環境はAWSが用意してくれますがビルドの設計と開発は自分たちで実装する必要があります。そのため、今後はデプロイやビルドを設計して実装するスキルが大事になってくるのかな、と思いました。
  • デプロイ全体の進行管理やログはAWSのサービスにお任せ

    • ログ状況やエラーはAWSコンソールで確認ができるので、運用者やデプロイのデバッグは楽になります。

以上です。最後まで読んでいただき、ありがとうございました。

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

php sessionマニュアル

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

php デフォルトセキュリティ

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

AWS-SDK PHPでS3バケット上のファイルをコピーするときにContent-Typeを変更する

S3に既に配置済みのファイルのContent-Typeを変更する際に苦戦したので、自分用のメモ

結論

copyObjectを使用する際に、オプションでContentType, MetadataDirectiveの2つを指定する。

$s3 = new S3Client([
    'version' => 'latest',
    'region'  => 'us-east-1'
]);

$s3->copyObject([
    'Bucket'     => $targetBucket,
    'Key'        => "{$sourceKeyname}-copy",
    'CopySource' => "{$sourceBucket}/{$sourceKeyname}",
    'ContentType' => 'binary/octet-stream', // ※
    'MetadataDirective' => 'REPLACE', // ※
]);

MetadataDirective:REPLACEを指定しないと、S3に配置されている元ファイルのContent-Typeを引き継ぐみたいなので注意

参考URL

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

()()

変数を省略

 $today = new Carbon();
 $today ->format('Y-m-d');

上記の式は下記一行で処理できる 

 (new Carbon())->format('Y-m-d');

分かりにくいけど、、

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

Laravel PHP 三項演算子の戻り値部分の記載で苦労した

目的

  • Laravelのbladeファイルの記載で三項演算子を用いて「文字列+DBのデータ」を表示分岐していたところ非常に苦労したのでメモとしてまとめる

実施環境

  • ハードウェア環境
項目 情報
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をインストールする

問題箇所

  • 下記のように記載し三項演算子の真の部分にデータを入れ込みたかった。

    @inject('ContentService', 'App\Services\ContentsService')
    <p>{{真偽判断の式 !== 0 ? 'コンテンツの数は{{$ContentService->getContent(Auth::id())}}件です' : 'コンテンツはありません'}}</p>
    
  • 簡単に解説すると「真偽判断の式」が真のときのみp要素で「コンテンツの数は〇〇件です」(〇〇はDBから認証中ユーザIDを引数に取得したデータ)のように表示したかった。

  • 中括弧が不足している旨のエラーが出て当該ページを表示する事ができなかった。

原因

  • 単純明快な原因である。文字列連結がうまくできていないだけだった。
  • 本来PHPで文字列を連結するときは下記のように.を使用する。

    //「おはようございます」と出力される
    echo 'おはよう' . 'ございます'
    
  • エラーが出た箇所は下記の部分である。

    'コンテンツの数は{{$ContentService->getContent(Auth::id())}}件です'
    
  • 落ち着いて見るとエラーが出るのは当たり前である。文字列部分とデータ部分の連結部分似誤りがある。正しく記載すると下記のようになる。

    'コンテンツの数は' . $ContentService->getContent(Auth::id()) . '件です'
    
  • 上記の内容を踏まえてp要素部分を正しく記載する。

    @inject('ContentService', 'App\Services\ContentsService')
    <p>{{真偽判断の式 !== 0 ? 'コンテンツの数は' . $ContentService->getContent(Auth::id()) . '件です' : 'コンテンツはありません'}}</p>
    
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

文字列から、JSONオブジェクトを正規表現で抽出

こんにちは。

文字列からJSONオブジェクトを正規表現で抽出したくなった事ってありませんか?

例えばAPIから返ってきたレスポンスが、下のような文字列だったとします。

string(102) "[
  {
    "id": 230,
    "content": "ブレイクアウトルーム",
  },
  {
    "id": 100,
    "content": "zoom",
  }
]"

JSON形式の部分だけ抽出して配列に代入できたら、操作が楽ですよね。

やってみると意外と大変だったので、備忘録として書いておきます。

サンプルコード

$pattern = '/\{[\s\S]*?\}/';
preg_match_all($pattern, $response, $matches );

抽出結果

array(1) {
  [0]=>
  array(2) {
    [0]=>
    string(59) "{
    "word_id": 230,
    "surface_form": "ブレイクアウトルーム",
  }"
    [1]=>
    string(48) "{
    "word_id": 100,
    "content": "zoom",
  }"
  }
}

各配列の要素は、文字列ですがPHPでは、json_decode($matches[0][0], true)を使うと、連想配列に変換できます。

正規表現

ポイントは、正規表現の書き方です。

'/\{[\s\S]*?\}/'

説明

[\s\S]

改行とそれ以外の文字にマッチ。
- \s :空白、タブ、フォーム フィードなどの任意の空白文字
- \S:空白文字以外の任意の文字

*

直前の文字に0回以上マッチ。

?

  • 最短マッチ。デフォルトでは最長マッチなので、全てのオブジェクトが一つの要素として取れてしまう。

参考

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

Ubuntu20.04の新規VMへanyenvやnodenvやphpenvをセットアップした時のコマンド履歴

備忘のための記録なので解説などは無し。

###################################
## https://cloud-images.ubuntu.com/minimal/releases/focal/release/
## のような minimal版のUbuntuを使う場合はgitを先にインストールしておく
###################################
sudo apt update
sudo apt upgrade
sudo apt install git


###################################
##  anyenv のセットアップ
###################################
git clone https://github.com/riywo/anyenv ~/.anyenv
echo 'export PATH="~/.anyenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(anyenv init -)"' >> ~/.bashrc
~/.anyenv/bin/anyenv install --init
exec $SHELL -l
~/.anyenv/bin/anyenv init
mkdir -p ~/.anyenv/plugins
git clone https://github.com/znz/anyenv-update.git ~/.anyenv/plugins/anyenv-update
git clone https://github.com/znz/anyenv-git.git ~/.anyenv/plugins/anyenv-git
anyenv update

###################################
##  nodenv, node, yarn のセットアップ
###################################
anyenv install nodenv
echo 'export PATH="$HOME/.nodenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(nodenv init -)"' >> ~/.bashrc
exec $SHELL -l
mkdir -p "$(nodenv root)"/plugins
## 次行を実行した結果、「already exists and is not an empty directory.」とか言われるかも。そしたら node-build は既にセットアップ済みなので実行不要。
## git clone https://github.com/nodenv/node-build.git "$(nodenv root)"/plugins/node-build
git clone https://github.com/nodenv/nodenv-update.git "$(nodenv root)"/plugins/nodenv-update
nodenv update
touch $(nodenv root)/default-packages
nodenv install 14.13.1
nodenv rehash
nodenv versions      ### 確認
nodenv global 14.13.1
node -v
npm -v
npm install -g yarn
nodenv rehash
yarn -v

###################################
##  phpenv, php7.4系 のセットアップ
###################################
anyenv install phpenv
git clone git://github.com/phpenv/phpenv.git ~/.phpenv
echo 'export PATH="$HOME/.phpenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(phpenv init -)"' >> ~/.bashrc
exec $SHELL -l
phpenv --version
mkdir -p ~/.phpenv/plugins/php-build
git clone git://github.com/php-build/php-build.git ~/.phpenv/plugins/php-build
phpenv install --list
phpenv versions
sudo apt -y install build-essential
sudo apt -y install libxml2-dev libssl-dev libbz2-dev libcurl4-openssl-dev libjpeg-dev libpng-dev libmcrypt-dev libreadline-dev libtidy-dev libxslt-dev autoconf pkg-config libsqlite3-dev libonig-dev libzip-dev
phpenv install -i development 7.4.11
phpenv global 7.4.11
php -v


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