- 投稿日:2019-04-15T23:31:19+09:00
Docker php:7.3(7.2)-fpm-alpineベースでphp-ast extention導入
個人的にメンテしているdyoshikawa/laravelイメージでPhanを使えるようにしたかった。
php-ast導入が必要だったのでビルド方法の記録。OGProgrammer/php 7.2 with ast phan argon support
基本的には上記を参考にした。
DockerfileRUN git clone https://github.com/nikic/php-ast.git \ && cd php-ast \ && phpize \ && ./configure \ && make install \ && echo 'extension=ast.so' > /usr/local/etc/php/php.ini \ && cd .. && rm -rf php-astこんな記述をして
docker build
を走らせるとCannot find autoconf. Please check your autoconf installation and the $PHP_AUTOCONF environment variable. Then, rerun this script.エラー。
PECL::memcacheインストールしようとしたらphpizeでこけた(泣)
dockerでPHP7.3+Laravel環境を15分で作る~2019年版どうもautoconfが足りてないようだ。
Dockerfile+ RUN apk add autoconf RUN git clone https://github.com/nikic/php-ast.git \ && cd php-ast \ && phpize \ && ./configure \ && make install \ && echo 'extension=ast.so' > /usr/local/etc/php/php.ini \ && cd .. && rm -rf php-ast
こうすると今度は下記のエラー。
configure: error: no acceptable C compiler found in $PATHxdebug インストール時の error: no acceptable C compiler について
gccが足りていないということらしい。
Dockerfile- RUN apk add autoconf + RUN apk add autoconf gcc RUN git clone https://github.com/nikic/php-ast.git \ && cd php-ast \ && phpize \ && ./configure \ && make install \ && echo 'extension=ast.so' > /usr/local/etc/php/php.ini \ && cd .. && rm -rf php-ast今度は下記。
configure: error: C compiler cannot create executablesg++が足りない。
Dockerfile- RUN apk add autoconf gcc + RUN apk add autoconf gcc g++ RUN git clone https://github.com/nikic/php-ast.git \ && cd php-ast \ && phpize \ && ./configure \ && make install \ && echo 'extension=ast.so' > /usr/local/etc/php/php.ini \ && cd .. && rm -rf php-astそして下記。
make not foundmakeがないということだろう。
Dockerfile- RUN apk add autoconf gcc g++ + RUN apk add autoconf gcc g++ make RUN git clone https://github.com/nikic/php-ast.git \ && cd php-ast \ && phpize \ && ./configure \ && make install \ && echo 'extension=ast.so' > /usr/local/etc/php/php.ini \ && cd .. && rm -rf php-astこれは通った。
完成形
FROM node:10-alpine AS node FROM php:7.3-fpm-alpine MAINTAINER dyoshikawa # install packages RUN apk add -U --no-cache \ bash \ git \ curl-dev \ libxml2-dev \ postgresql-dev \ libpng-dev \ libjpeg-turbo-dev \ zip \ libzip-dev \ unzip \ gmp-dev # install PHP extensions RUN docker-php-source extract RUN cp /usr/src/php/ext/openssl/config0.m4 /usr/src/php/ext/openssl/config.m4 RUN docker-php-ext-configure gd --with-png-dir=/usr/include --with-jpeg-dir=/usr/include RUN docker-php-ext-install pdo\ pdo_mysql \ mysqli \ pdo_pgsql \ pgsql \ mbstring \ curl \ ctype \ xml \ json \ tokenizer \ openssl \ gd \ zip \ gmp \ bcmath # install php-ast RUN apk add --no-cache gcc g++ make autoconf RUN git clone https://github.com/nikic/php-ast.git \ && cd php-ast \ && phpize \ && ./configure \ && make install \ && echo 'extension=ast.so' > /usr/local/etc/php/php.ini \ && cd .. && rm -rf php-ast # install composer RUN curl -sS https://getcomposer.org/installer | php \ && mv composer.phar /usr/local/bin/composer # install composer plugin RUN composer global require laravel/installer ENV PATH=~/.composer/vendor/bin:$PATH RUN composer global require hirak/prestissimo # install dockerize ENV DOCKERIZE_VERSION v0.6.1 RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && tar -C /usr/local/bin -xzvf dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && rm dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz # add node.js npm COPY --from=node /usr/local /usr/local RUN apk add --no-cache python make g++ RUN rm /usr/local/bin/yarn /usr/local/bin/yarnpkg # add user RUN apk add sudo shadow RUN groupadd -g 1000 dyoshikawa RUN useradd -u 1000 -g 1000 dyoshikawa RUN sed -e 's/# %wheel ALL=(ALL) NOPASSWD: ALL/%wheel ALL=(ALL) NOPASSWD: ALL/g' \ -i /etc/sudoers RUN sed -e 's/^wheel:\(.*\)/wheel:\1,dyoshikawa/g' -i /etc/group RUN mkdir /home/dyoshikawa && chown 1000:1000 -R /home/dyoshikawa RUN mkdir /work && chown 1000:1000 -R /work WORKDIR /work USER dyoshikawa ENTRYPOINT [] CMD php artisan serve --host 0.0.0.0
- 投稿日:2019-04-15T22:09:23+09:00
素PHPでDIをやる(pimple)
素PHPでDIをやりたくなったのでpimpleで簡単にやってみました。
これがベストかは全くわかりません。対象読者
DIという単語を聞いたことがあるひと
Laravelでサービスコンテナという単語を聞いたことがあるひと用語の整理(諸説あります)
DI
外部から必要なインスタンスを注入することDIコンテナ
DIを便利に行う仕組み、箱。
設定を書いておくとよしなにやってくれるかんじ。余談ですが、Laravelでもこの仕組があり、それは「サービスコンテナ」と呼ぶらしい。
まず、DIでないパターン
<?php class Message { private $message; public function __construct() { $this->setMessage(); } private function setMessage (): void { $this->message = 'こんにちは世界'; } public function getMessage(): string { return $this->message; } } class Call { private $message; function __construct() { // 必要なインスタンスを得るためにクラスの内部でインスタンス化しています。 // 注入にはなっていません。 $this->message = new Message(); } function callMessage () { echo $this->message->getMessage(); } } $call = new Call(); $call->callMessage(); // こんにちは世界手動DI
class Call { private $message; function __construct(Message $message) { $this->message = $message; } function callMessage () { echo $this->message->getMessage(); } } // ここで手動でインスタンスを注入しています。 $message = new Message(); $call = new Call($message); $call->callMessage(); // こんにちは世界手動DIがたくさんになるとめんどいです。
class Call { private $message; function __construct( Message $message, Message2 $message2, Message3 $message3 ) { $this->message = $message; $this->message2 = $message2; $this->message3 = $message3; } function callMessage () { echo $this->message->getMessage(); echo $this->message2->getMessage2(); echo $this->message3->getMessage3(); } } $message = new Message(); $message2 = new Message2(); $message3 = new Message3(); $call = new Call($message, $message2, $message3); $call->callMessage(); // こんにちは世界こんにちは日本ハローアメリカpimpleを使ったコンストラクタインジェクションの例。コンストラクタ内で注入します。
// インストール $ ./composer.phar require pimple/pimple ~3.0
<?php require_once __DIR__.'/vendor/autoload.php'; use Pimple\Container; $container = new Container(); $container['Message'] = function ($c) { return new Message(); }; $container['Message2'] = function ($c) { return new Message2(); }; $container['Message3'] = function ($c) { return new Message3(); }; // ここでインスタンスをコンテナに入れている感じです。 $container['call'] = function ($c) { return new Call($c['Message'], $c['Message2'], $c['Message3']); }; class Call { private $message; function __construct( Message $message, Message2 $message2, Message3 $message3 ) { $this->message = $message; $this->message2 = $message2; $this->message3 = $message3; } function callMessage () { echo $this->message->getMessage(); echo $this->message2->getMessage2(); echo $this->message3->getMessage3(); } } // この部分を端折ることができます。 //$message = new Message(); //$message2 = new Message2(); //$message3 = new Message3(); // //$call = new Call($message, $message2, $message3); $container['call']->callMessage(); // こんにちは世界こんにちは日本ハローアメリカ設定の記述量が多くて、便利なのかという感じなのですが、別クラスに設定を書いておいて使いたいときに注入すればいいので便利だと思います。
副産物として、テストがしやすくなったり、インターフェイスをかませてインターフェイスを注入することでクラス同士を疎結合にして、保守性を上げるということができるようになるようです。
参考
PIMPLEA simple PHP
Dependency Injection Container
https://pimple.symfony.com/フレームワークを作りながらLaravelのアーキテクチャを学ぶ / Learn Laravel's architecture while creating a framework
https://speakerdeck.com/fendo181/learn-laravels-architecture-while-creating-a-framework?slide=109
- 投稿日:2019-04-15T22:09:23+09:00
PHPでDIをやる(pimple)
PHPでDIをやりたくなったのでpimpleで簡単にやってみました。
これがベストかは全くわかりません。対象読者
DIという単語を聞いたことがあるひと
Laravelでサービスコンテナという単語を聞いたことがあるひと用語の整理(諸説あります)
DI
外部から必要なインスタンスを注入することDIコンテナ
DIを便利に行う仕組み、箱。
設定を書いておくとよしなにやってくれるかんじ。余談ですが、Laravelでもこの仕組があり、それは「サービスコンテナ」と呼ぶらしい。
まず、DIでないパターン
<?php class Message { private $message; public function __construct() { $this->setMessage(); } private function setMessage (): void { $this->message = 'こんにちは世界'; } public function getMessage(): string { return $this->message; } } class Call { private $message; function __construct() { // 必要なインスタンスを得るためにクラスの内部でインスタンス化しています。 // 注入にはなっていません。 $this->message = new Message(); } function callMessage () { echo $this->message->getMessage(); } } $call = new Call(); $call->callMessage(); // こんにちは世界手動DI
class Call { private $message; function __construct(Message $message) { $this->message = $message; } function callMessage () { echo $this->message->getMessage(); } } // ここで手動でインスタンスを注入しています。 $message = new Message(); $call = new Call($message); $call->callMessage(); // こんにちは世界手動DIがたくさんになるとめんどいです。
class Call { private $message; function __construct( Message $message, Message2 $message2, Message3 $message3 ) { $this->message = $message; $this->message2 = $message2; $this->message3 = $message3; } function callMessage () { echo $this->message->getMessage(); echo $this->message2->getMessage2(); echo $this->message3->getMessage3(); } } $message = new Message(); $message2 = new Message2(); $message3 = new Message3(); $call = new Call($message, $message2, $message3); $call->callMessage(); // こんにちは世界こんにちは日本ハローアメリカpimpleを使ったコンストラクタインジェクションの例。コンストラクタ内で注入します。
// インストール $ ./composer.phar require pimple/pimple ~3.0
<?php require_once __DIR__.'/vendor/autoload.php'; use Pimple\Container; $container = new Container(); $container['Message'] = function ($c) { return new Message(); }; $container['Message2'] = function ($c) { return new Message2(); }; $container['Message3'] = function ($c) { return new Message3(); }; // ここでインスタンスをコンテナに入れている感じです。 $container['call'] = function ($c) { return new Call($c['Message'], $c['Message2'], $c['Message3']); }; class Call { private $message; function __construct( Message $message, Message2 $message2, Message3 $message3 ) { $this->message = $message; $this->message2 = $message2; $this->message3 = $message3; } function callMessage () { echo $this->message->getMessage(); echo $this->message2->getMessage2(); echo $this->message3->getMessage3(); } } // この部分を端折ることができます。 //$message = new Message(); //$message2 = new Message2(); //$message3 = new Message3(); // //$call = new Call($message, $message2, $message3); $container['call']->callMessage(); // こんにちは世界こんにちは日本ハローアメリカ設定の記述量が多くて、便利なのかという感じなのですが、別クラスに設定を書いておいて使いたいときに注入すればいいので便利だと思います。
副産物として、テストがしやすくなったり、インターフェイスをかませてインターフェイスを注入することでクラス同士を疎結合にして、保守性を上げるということができるようになるようです。
参考
PIMPLEA simple PHP
Dependency Injection Container
https://pimple.symfony.com/フレームワークを作りながらLaravelのアーキテクチャを学ぶ / Learn Laravel's architecture while creating a framework
https://speakerdeck.com/fendo181/learn-laravels-architecture-while-creating-a-framework?slide=109
- 投稿日:2019-04-15T20:02:41+09:00
Laravelでバリデーションにモックを仕掛ける
バリデーションにモックを仕掛ける
ファサードには下記のようにshouldReceiveメソッドが実装されていて楽にモックを仕掛けることができます。
私のケースではexistsでテーブルに値があるか確認していて、apiのテスト時にDBアクセスを避けたかったので利用しました。shouldReceiveメソッドを使用し、Cacheファサードへの呼び出しをモックできます。これはMockeryインスタンスを返します。ファサードはLaravelのサービスコンテナにより管理され、依存解決されていますので、典型的な静的クラスよりもかなり高いテスタビリティーを持っています。
makeメソッドだけではなく正常系チェック用のpassesメソッドも範囲にして、返り値を設定することです。
existsを使って無い時でも別途バリデーションのテストをしている等であれば使ってもよさそう。ExampleTest.phpValidator::shouldReceive('make->passes') ->once() ->andReturn(true); $response = $this->json('GET', /example, $param);(参考)
- 投稿日:2019-04-15T20:02:41+09:00
Laravel/Lumenでバリデーションにモックを仕掛ける
バリデーションにモックを仕掛ける
ファサードには下記の説明にあるように最初からモックをできるヘルパがあるので、楽にモックを仕掛けることができます。しかしバリデーションに仕掛けるケースの記事がなかったので備忘録として。
ファサードはLaravelのサービスコンテナにより管理され、依存解決されていますので、典型的な静的クラスよりもかなり高いテスタビリティーを持っています。
https://readouble.com/laravel/5.5/ja/mocking.html
実装
重要なのはバリデーションのmakeメソッドだけではなく、正常系確認用にあるpassesメソッドも対象にして、返り値を設定することでバリデーションが実行される心配がなくなります。
ExampleTest.phpValidator::shouldReceive('make->passes') ->once() ->andReturn(true); $response = $this->json('GET', /example, $param);まとめ
今回はバリデーションでexistsルールを使ってテーブルに値があるか確認していて、APIのテスト時にはDBアクセスを避けたかったのでモックを利用してます。他にも複雑なカスタムバリデーションなどを組んでいる時などにも良いのではないかと考えてます。
- 投稿日:2019-04-15T20:02:41+09:00
Laravel/LumenでValidatorにモックを仕掛ける
バリデーションにモックを仕掛ける
Laravel/LumenのValidatorクラスにはファサードが用意されています。ファサードには下記の説明にあるように最初からモックできるヘルパがあり、楽にモック化することができます。しかしValidatorに仕掛けるケースの記事がなかったので備忘録として。
Laravelにはイベント、ジョブ、ファサードを最初からモックできるヘルパが準備されています。これらのヘルパは主にMockery上で動作する便利なレイヤーを提供しているので、複雑なMockeryのメソッドコールを自分で作成する必要はありません。
https://readouble.com/laravel/5.5/ja/mocking.html
実装
重要なのはバリデーションのmakeメソッドだけではなく、正常系確認用にあるpassesメソッドもつないで、返り値を設定することでバリデーションが実行される心配がなくなります。
ExampleTest.phpValidator::shouldReceive('make->passes') ->once() ->andReturn(true); $response = $this->json('GET', /example, $param);まとめ
今回はバリデーションでexistsルールを使ってテーブルに値があるか確認していて、APIのテスト時にはDBアクセスを避けたかったのでモックを利用してますが、他にも複雑なカスタムバリデーションなどを組んでいる時などにも良いと考えてます。(もちろん別途テストは必要)
- 投稿日:2019-04-15T17:42:38+09:00
MAMPでローカル開発から、xserverのphpmyadminを使って、ローンチするまで。
phpの学習として、MAMP環境でWebサービスをローカルで開発したものの、
いざローンチするとなると、どうしていいかわからない。
そんな時のためのノートです。【想定状況】
・ MANPで、phpmyadminを使ってお理、すでにDBにデータが入っている
・ DBとの接続に、PDOオブジェクトを使用している
・ ブログやポートフォリオ等で、すでにxserverを使用しているxserver側でやること
ではまず、下準備。
MAMPはローカル環境用なので、外部サーバーのxserverでの準備です。xserverのサブドメインの申請
すでに、ドメインを持ってい人は、サブドメインを作成しましょう。
http://yahoo.co.jp
がメインドメインだとすると、サブドメインは
http://◯◯.yahoo.co.jp
となります。新しいドメインとは異なり、無料かつお手軽に作成することができます。
xserverの「サーバーパネル」から
サブドメインの設定追加を行って行きます。まずは
サーバーパネルから、ドメイン>サブドメイン設定ドメイン選択画面から、サブドメインを作成したいドメインを選択
実際に使用していくサブドメイン名(任意の文字列)を入力、
右下の確認画面で、サブドメインの申請は終了です!
(コメントは入力しなくても大丈夫です。)無事、サブドメインが認証されるまで1時間〜半日ぐらいかかります。
(深夜に行っても2時間くらいで反映されました。)xserverのphppmyadminの作成
次にローカル環境で使用していたDBを移行してくるためのDB設定を行います。
サーバーパネルの
データベース>MySQL設定へMySQL追加からDBの名前を入力します。
なんでもいいですが、今回「Egg」としました。そうするとMySQL一覧のところに
「_Egg」というデータベースができています。最初は、アクセス権未所有ユーザーのところに
自分のユーザーネームがあるので、アクセス権所有ユーザーに変更をしておいてください。また後々、
MySQL ホスト名というところを使っていきますので
メモ帳なんかにコピーしておきます。ローカル環境周りでやること
次にやるべきことはDBの移行です。
今までもphpMyAdminを使用していましたが、
xserverに、新しく作りましたのでそちらに移動させていきます。phpMyAdiminへの移行
もともと使用していたphpMayAdminから
移行させたいDBを選択し、エクスポートを行います。詳しいやり方は以下のサイトを参考にしました。
各項目にチェックをつけていき、
最終的に、sqlファイルとして保存し、
移行先であるxserverのphpmyadminにインポートすれば、
DBの移行は終了です。PDOオブジェクトの編集
サブアドレスも発行し、DBの移行も終わり、
あとは、xserver内にドキュメントを写すだけ....ではありません。重要なDB接続の
PDOを変更する必要があります。変更前までは$dsnのmyssql以下は
ローカルで開発していたため、
hostがlocalhostもしくは127.0.0.1でしたが先ほどxserveでの設定時に出てきたhost名を入力する必要があります。
またそれに合わせて、DBnameも変更する必要があります。変更前
function dbConnect(){ $dsn = 'mysql:dbname=egg; host=localhost; charset=utf8'; $user = 'root'; $password = 'root'; $options = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, ); $dbh = new PDO($dsn, $user, $password, $options); return $dbh; }変更後
function dbConnect(){ $dsn = 'mysql:dbname=▲▲_egg; host=◯◯.xserver.jp; charset=utf8'; $user = 'DBのユーザー名'; $password = 'DBのパスワード'; $options = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, ); $dbh = new PDO($dsn, $user, $password, $options); return $dbh; }変更後の
dsn文のdbnameとhostは
上で自分で決めたDB名とホスト名DBのユーザー名とパスワードは
xserverでphpmydminに入るときに使用するやつです。FTPソフトを使用した移行
あとは、FTPソフトを使用して移行していくだけです。
やり方は以下を参考にCyberDuckを使用していきました。
https://showtaki.com/30days-trial-3/
ファイルさえ移行しておけば
DBの接続を失敗していない限り、正常にサブドメインのアドレスで
Webページが表示されているはずです。【困った時】SQLのエラーの一覧
これを行う上で、SQLのエラーとだいぶにらめっこしたので
まとめておきます。ホスト名のエラー
SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: hostname nor servname provided, or not knownDB名のエラー
SQLSTATE[HY000] [1044] Access denied for user ‘example’@’%’ to databaseユーザー名のエラー
SQLSTATE[HY000] [1045] Access denied for user ‘◯◯’@’127.0.0.1’ (using password: YES)最後に
役に立ったら、
いいねください!
- 投稿日:2019-04-15T14:54:45+09:00
セッション機能(SESSION)
プログラミング初心者であるため、内容に誤りがあるかもしれません。
もし、誤りがあれば修正するのでどんどん指摘してください。私は、立命館大学ロボティクス学科4回生です。
現在、未来電子テクノロジーでインターンを行なっています。
日々のプログラミングで気になったことをブログに書いています。初めに
私は、データベース連携フォームを作っている際に、ファイル間のデータの受け渡しに困っていました。
そこで、今回は、一番引っかかったSESSION機能について簡単にお話しします。SESSION機能とは
SESSION機能は、webサイトにアクセスして作業を行う一連のことを言います。
これだとわからなかったため、簡単に解釈すると、ログインしてから、ログアウトするまでのようなことです。
つまり、ある状態に入ることなのです。SESSION機能を使う理由
Webで使われるHTTPプロトコルに、状態を維持する、管理する方法がないからです。
HTTPプロトコルとは、HTMLなどのコンテンツの送受信で用いられる通信プロトコルのことです。
また、Webページに、アクセエスした人、経緯、回数をHTTPプロトコルでは、保持できないのです。私が使ったSESSION機能のコード
session_start(); $number = htmlspecialchars( $_SESSION["number"], ENT_QUOTES ); $name = htmlspecialchars( $_SESSION["name"], ENT_QUOTES ); $grade = htmlspecialchars( $_SESSION["grade"], ENT_QUOTES ); $other = htmlspecialchars( $_SESSION["biko"], ENT_QUOTES ); session_destroy();まとめ
この記事だけでは、SESSION機能について、存在くらいしかわからないと思います。
ぜひ、興味がある方は、調べてみてはいかがでしょうか?
- 投稿日:2019-04-15T13:11:33+09:00
BaserCMSのカスタムフィールドプラグインを4系対応して機能追加してみた
BaserCMSにはPetitCustomFieldと言う結構高機能な3系用のカスタムフィールドプラグインがあるのですが、4系用の更新がされておらず止まったままなので使えるようにしてみました。それに合わせて幾つか機能を追加しています。
ファイルアップロード機能
とりあえず一番欲しいと思われるファイルアップロード機能を追加しました。
BaserCMS標準のアップロード機能を利用してアップロード出来るようにしているので、そこに追加された画像も含めて選択することが可能です。ファイル選択するとこのような感じになります。
カスタムフィールドの設置する位置を追加
カスタムフィールドの表示位置が上と下しかなく、ちょっと位置が中途半端だったので【エディターの下】を選択できるようにしました。
管理画面のUI文言などを調整
使ったことある人しかわからないかもですが登録画面が少し迷子になりやすい感じなので、少しわかりやすく名称などを変更しました。
- カスタムフィールド → フィールドグループ
- フィールド → フィールド項目
- ブログIDで表示 → ブログ名称で表示 など
登録したデータの表示
ヘルパー周りも自分もあまりよくわかっていないのですが、登録されたデータはアーカイブだと\$posts、単ページでは\$postとして紐づいているようです。
今回の修正したファイル
以下にforkして修正した内容を上げてあります。
https://github.com/BigFly3/PetitCustomFieldあんまりデバッグ出来てませんが良かったらお試しください。
- 投稿日:2019-04-15T13:06:53+09:00
【PHP】CarbonのaddMonth()を使ってハマった話(CarbonとDateTimeクラスの仕様を今一度確認してみる)
TL;DR
特に理由がなければCarbonを用いて月の計算をする場合は
addMonthsNoOverflow()
メソッドを使うようにしたほうがいいDateTimeクラスの仕様に度々ひっかかる
Carbonを用いて月の計算を行っていると、どうやら28~31日のデータを扱うときに挙動がおかしいことに気が付きました
前もこんなのあったなーと思いつつ再現させる
(前:【PHP】ある月の初日と末日を取得する方法(DateTimeクラス & Carbon編)#要注意引数は年月日を渡しましょう - Qiita )検証
例:契約日が15日未満の場合は翌月の27日、15日以降なら翌々月の27日が請求月になる
みたいな場合の処理
(ここでは契約日が2018-01-31
で考えます)
環境としてはLaravelのv5.5系に入っているCarbon(1.36)を使用して以下の例の処理を動かしますuse Carbon\Carbon; $array = []; $contractDate = new Carbon('2018-01-31'); // 5回払い for ($i = 0; $i < 5; $i++) { // 契約日が15日以降か if ((int)$contractDate->format('d') < 15) { $array['date'] = (new Carbon($contractDate))->addMonth($i + 1)->format("Y-m-27"); } else { $array['date'] = (new Carbon($contractDate))->addMonth($i + 2)->format("Y-m-27"); } $array['target_month'] = (new Carbon($array['date']))->format('Y-m'); var_dump($i); var_dump($array); }↓以下、tinker(laravel用REPL)で実行した結果
int(0) array(2) { ["date"]=> string(10) "2018-03-27" ["target_month"]=> string(7) "2018-03" } int(1) array(2) { ["date"]=> string(10) "2018-05-27" ["target_month"]=> string(7) "2018-05" } int(2) array(2) { ["date"]=> string(10) "2018-05-27" ["target_month"]=> string(7) "2018-05" } int(3) array(2) { ["date"]=> string(10) "2018-07-27" ["target_month"]=> string(7) "2018-07" } int(4) array(2) { ["date"]=> string(10) "2018-07-27" ["target_month"]=> string(7) "2018-07" } >>>なんだこれは・・・
Carbonの
addMonth()
について調べてみるCarbonはDateTimeクラスのラッパーなので、基本的にDateTimeクラスの仕様に依存してるみたいです。
んでaddMonth()
の処理がどうなっているかCarbonのソースコード(Carbon/Carbon.php at version-1.36)を見てみるとCarbon/Carbon.php/** * Add a month to the instance * * @param int $value * * @return static */ public function addMonth($value = 1) { return $this->addMonths($value); }
addMonths()
メソッドを呼び、Carbon/Carbon.php/** * Add months to the instance. Positive $value travels forward while * negative $value travels into the past. * * @param int $value * * @return static */ public function addMonths($value) { if (static::shouldOverflowMonths()) { return $this->addMonthsWithOverflow($value); } return $this->addMonthsNoOverflow($value); }
static::shouldOverflowMonths()
で呼ばれているmonthsOverflow
プロパティはデフォルトでtrue
になっているので、
オーバーフローで月を計算するメソッドaddMonthsWithOverflow()
を呼びます。Carbon/Carbon.php/** * Add months to the instance. Positive $value travels forward while * negative $value travels into the past. * * @param int $value * * @return static */ public function addMonthsWithOverflow($value) { return $this->modify((int) $value.' month'); }でその中身はDateTimeクラスの
modify()
メソッドでした。
ドキュメント(PHP: DateTime::modify - Manual)にも書いてある通り、月の加減算には注意ということで以下の処理例が載ってます。例2 月の加減算には注意
<?php $date = new DateTime('2000-12-31'); $date->modify('+1 month'); echo $date->format('Y-m-d') . "\n"; $date->modify('+1 month'); echo $date->format('Y-m-d') . "\n"; ?>上の例の出力は以下となります。
2001-01-31
2001-03-03要は月の計算(加算)時に存在しない日(2月が28日までで、31日がない)になった場合、あふれた日数(3日)を次の月(3月)に+して計算する(=3月3日)という仕様になってるんですね
確認するために
modify()
メソッドを使用して処理を書いてみましたdate_default_timezone_set('Asia/Tokyo'); for ($i = 0; $i < 10; $i++) { $date = new DateTime('2018-01-31'); $date->modify((int) ($i + 2).' month'); var_dump($date->format('Y-m-d H:i') ." → " . $date->format('Y-m-27')); echo PHP_EOL; }以下実行結果
string(35) "2018-03-31 00:00 → 2018-03-27" string(35) "2018-05-01 00:00 → 2018-05-27" string(35) "2018-05-31 00:00 → 2018-05-27" string(35) "2018-07-01 00:00 → 2018-07-27" string(35) "2018-07-31 00:00 → 2018-07-27" string(35) "2018-08-31 00:00 → 2018-08-27" string(35) "2018-10-01 00:00 → 2018-10-27" string(35) "2018-10-31 00:00 → 2018-10-27" string(35) "2018-12-01 00:00 → 2018-12-27" string(35) "2018-12-31 00:00 → 2018-12-27"案の定、最初に書いた処理と同じような結果になりました。
(※4月や6月は30日までしかないので、1日分、次の月に+されてしまってます)オーバーフローしないメソッド
addMonthsNoOverflow()
ならオーバーフローしない計算メソッドを使えばいいんではないか、ということで
CarbonのaddMonthsNoOverflow()
メソッドの処理を見てみます。Carbon/Carbon.php/** * Add months without overflowing to the instance. Positive $value * travels forward while negative $value travels into the past. * * @param int $value * * @return static */ public function addMonthsNoOverflow($value) { $day = $this->day; $this->modify((int) $value.' month'); if ($day !== $this->day) { $this->modify('last day of previous month'); } return $this; }結局は
modify()
メソッドを使用してるみたいですが、'last day of previous month'
(前の月の最後の日)と書かれてるので、オーバーフローした際は前月の最終日を返すようになっているようです。正しい処理になるように修正
ということで、Carbonの
addMonthsNoOverflow()
メソッドを用いて計算するように先ほどの処理を修正してみます。use Carbon\Carbon; $array = []; $contractDate = new Carbon('2018-01-31'); // 5回払い for ($i = 0; $i < 5; $i++) { if ((int)$contractDate->format('d') < 15) { // $array['date'] = (new Carbon($contractDate))->addMonth($i + 1)->format("Y-m-27"); $array['date'] = (new Carbon($contractDate))->addMonthsNoOverflow($i + 1)->format("Y-m-27"); } else { // $array['date'] = (new Carbon($contractDate))->addMonth($i + 2)->format("Y-m-27"); $array['date'] = (new Carbon($contractDate))->addMonthsNoOverflow($i + 2)->format("Y-m-27"); } $array['target_month'] = (new Carbon($array['date']))->format('Y-m'); var_dump($i); var_dump($array); }以下、tinker(laravel用REPL)で実行した結果
int(0) array(2) { ["date"]=> string(10) "2018-03-27" ["target_month"]=> string(7) "2018-03" } int(1) array(2) { ["date"]=> string(10) "2018-04-27" ["target_month"]=> string(7) "2018-04" } int(2) array(2) { ["date"]=> string(10) "2018-05-27" ["target_month"]=> string(7) "2018-05" } int(3) array(2) { ["date"]=> string(10) "2018-06-27" ["target_month"]=> string(7) "2018-06" } int(4) array(2) { ["date"]=> string(10) "2018-07-27" ["target_month"]=> string(7) "2018-07" } >>>期待通りの処理になりました。
ということで特に理由がなければCarbonを用いて月の計算をする場合は
addMonthsNoOverflow()
メソッドを使うようにしたほうがいいかなというお話でした。おわり
- DateTimeクラスの仕様には度々振り回されます・・・
- というかドキュメントちゃんと読みましょう>自分
参考URL
- 投稿日:2019-04-15T12:44:06+09:00
Composer: どのパッケージが依存しているか調べる方法
Composerで、あるパッケージが、どのパッケージから依存されているかを調べる方法です。
composer why --tree パッケージ名例えば、
symfony/yaml
がどのパッケージで使われているか調べるには、次のようにします。composer why --tree symfony/yaml
- 投稿日:2019-04-15T11:45:19+09:00
AWSを使ってLAMP環境を構築する手順
自己学習のメモとして。
AWS上にLAMP環境を作成する手順を書いておきます。Linux仮想マシン(EC2)を起動
1、AWSのマネジメントコンソールからEC2を選択。
※この段階でリージョンを日本にしておく2、インスタンスの作成を選択
・AMAZON Lunux AMIを選択
・無料利用枠のt2.microを選択
→インスタンスを作成キーペアが生成できるのでダウンロードしておく。
パブリックIPアドレスを設定
パブリックIPアドレスが毎回変化してしまうので固定する。
・左のメニューからElastic IPを選択
・新しいアドレスの割り当てをクリック
・出来上がったアドレスを選択し、アクション→アドレスの関連付け
・インスタンスをクリックし、先ほど設定したLinuxのIDが出るので選択して紐づけ
・インスタンスからセキュリティグループをクリッ
アクション→インバウンドルールの編集を選択
・ルールの追加→http→保存リモートアクセス
・ターミナル(コマンドプロンプト)を起動
・.sshフォルダがあるか確認する。(無ければmkdirでユーザーディレクトリの中に作っておく)
・.sshの中に先ほどのKey.pemファイルを移動しておく
・以下のsshコマンドでAWSにアクセスssh -i ~/.ssh/xxx.pem ec2-user@xx.xxx.xxx.xxx※デフォルトで名前はec2-userになっている
初回はyesを選択して接続今後接続するときは毎回このコマンドを打つので覚えておきたい
exitで接続を終了できる
Apacheを導入
・Linuxをアプデしておく
sudo yum -y update※-yをつけると確認画面なしにできる
・Apacheをインストールする
sudo yum -y install httpd・Apacheを起動する
sudo service httpd start・今後自動で立ち上がるように設定する
sudo chkconfig httpd on※ブラウザに切り替えてIPアドレスからapacheが見られるか確認するとよい
おまけ1
htmlファイルを作って試しに見てみる方法
htmlを作成
sudo vi /var/www/html/index.html1、編集画面になったら「i」を打って適当にhtmlファイルを作成する
2、「esc」を押してから「:wq」で上書き保存しenter※:q!で保存せず終了できる
ファイルの確認方法
ls /var/www/htmlブラウザにIPアドレスを打ち込んで確認できる
おまけ2
scpコマンドで、ローカルで作成したhtmlファイルを転送する
※scpはPC間で安全に転送するコマンドおまけ1でAWSに作ったhtmlファイルをローカルにダウンロードする(デスクトップの場合)
scp -i ~/.ssh/xxx.pem ec2-user@xx.xxx.xxx.xxx:/var/www/html/index.html ~/Desktop適当にhtmlファイルを編集し、AWSに転送する
scp -i ~/.ssh/xxx.pem ~/Desktop/index.html ec2-user@xx.xxx.xxx.xxx:成功したかどうかsshコマンドで接続して確認
(pwd、lsで見られる。)現状htmlファイルはec2-userの中にあるので正しい保存先に移動させる
sudo mv ~/index.html /var/www/htmlこれでブラウザで見ることができるようになる
この流れは面倒なのでもう少し簡略化できるよう設定する
EC2にリモートアクセスしている状態でwwwというグループを作成する
sudo groupadd wwwこのグループに自分のユーザー名を追加する
sudo usermod -a -G www ec2-userいったんexitでログアウトし、もう一度ログイン→グループの権限が有効になっているはず
groupsで確認すると
ec2-user wheel wwwとなっているはず
htmlを保存するディレクトリのグループ所有権を変更する
sudo chown -R root:www /var/www/var/www以下のディレクトリに書き込み許可を設定する
sudo chmod 2775 /var/www将来のサブディレクトリにグループIDを設定
find /var/www -type d -exec sudo chmod 2775 {} \;/var/www及びサブディレクトリのファイル許可を繰り返し、グループの書き込み許可を与える
find /var/www -type f -exec sudo chmod 0664 {} \;今後は転送先に直接/var/www/htmlを指定できる
scp -i ~/.ssh/xxx.pem ~/Desktop/index.html ec2-user@xx.xxx.xxx.xxx:/var/www/htmlPHPをインストール
※お決まりのコマンドでリモートログインしておく
管理者権限に切り替えておく
sudo suユーザー名の部分に#がつけばOK。
切り替えておけばsudoコマンドを打つ必要が無くなる。時間の設定
dateロンドンの時間になっていたりすると、掲示板などのサービスを作った際におかしくなるので日本時間に修正
ln -sf /usr/share/zoneinfo/Japan /etc/localtimedateコマンドで確認して問題なければOK
・PHPをインストールする
yum install -y php動作確認
・PHPの設定をしておく
※バックアップを取っておくと良いcp /etc/php.ini /etc/php.bakもしバックアップの必要が出た場合は
cp /etc/php.bak /etc/php.iniviでphp.iniの設定をいじる
vi /etc/php.ini行番号を表示させると見やすくなるのでescキーを押して
:set number520行目あたりを編集したいので
:520iモードにして
error_reporting = E_ALL &E_DEPRECATEDに追記をすれば、phpの余分なエラーメッセージを表示させずに済む
error_reporting = E_ALL &E_DEPRECATED & ~E_NOTICE次に537行目を編集。
ディスプレイエラーをOnにしておく
これでphpのエラーがブラウザに表示されるようになるdisplay_errors = Onターミナルに戻り、apacheを再起動
service httpd restartviでindex.phpを作って動作確認をすると良い
ブラウザでxx.xxx.xxx.xxx/index.php、(または番号のみで閲覧できる?)で確認できる。MySQLのインストール
※sshでリモートアクセスし、sudo suで管理者にしておく。
yumでmysqlをインストールする
yum install -y mysql-serverphpからmysqlをコントロールするため追加プログラムを入れる
yum install -y php-mysqlndmysqlを起動してみる
service mysqld start・mysqlの設定
mysql_secure_installationパスワードを聞かれるが無いのでそのままenter
すると新しくパスワードを設定するかを聞かれるのでyを押し、パスワードを設定する
※パスワードは忘れないように
確認のためにもう一度打ち込む
そしてRemove anonyemous users?(ゲストユーザーを消しますか?)と尋ねられるのでyを押す。
そのあとはすべてyでOK。・mysqlの文字コードをviで設定
vi /etc/my.cnf11行目あたりにある[mysqld_safe]の前に
character-set-server = utf8を追加。:wqで保存
再起動して確認service mysqld restartOKと表示されているればOK。
phpMyAdminを導入
phpMyAdminをインストールするためにyumコマンドの設定を変更する
yum-config-manager --enable epelこれで準備ができたので、phpmyadminをインストールする
yum install -y phpmyadmin・自分のローカルPCのみでphpmyadminにログインできるよう設定する
自分のPCのグローバルIPアドレスを確認する
→確認くん確認できたらviで設定をいじる
vi /etc/httpd/conf.d/phpMyAdmin.conf※大文字に注意
127.0.0.1の部分をグローバルIPアドレスに書き換えればOK
せっかくなので置換機能を使ってみる
:%s/127.0.0.1/xxx.xx.xx.xx/g全4か所が修正されていればOK
設定を反映させるために再起動するservice httpd restart確認のためxx.xx.xx.xx/phpmyadminをブラウザで確認する
ユーザー名はroot、パスワードはmysqlで設定したものを入力。これにてLAMP環境が完成!
今後はLaravel環境を作る方法を書けるようになれればと思っています!
ありがとうございました。
- 投稿日:2019-04-15T10:25:29+09:00
WordPressのテーマに登録されている有効なショートコード一覧の取得
- 投稿日:2019-04-15T08:52:27+09:00
php-master-changes 2019-04-14
今日は不要な条件コンパイルを削除する修正があった!
2019-04-14
carusogabriel: Remove HAVE_* for always available extensions
- https://github.com/php/php-src/commit/656db96eb931671ecdc789c047f620de2f9fec05
- [7.4~]
- 常時ある拡張について HAVE_* の条件コンパイルを削除