20190607のPHPに関する記事は19件です。

php-master-changes 2019-06-06

この日はテストの修正、run-tests.php の修正、__toString() からの例外送出時の処理の最適化、ドキュメントの更新、get_object_vars() で false を返す可能性があったのを空配列を返すようにする修正、eval から sodium_*() を呼ぶと SEGV が起きていた問題の修正、php_zip_pcre() の処理の修正、不要コードの削減、 Windows でのビルド修正、ファイルを探すコードが 7.3.6 と比べて 7.4-dev で 100 倍遅くなっていた問題の修正があった!

2019-06-06

krakjoe: this test is flaky on azure, and can't see why from current output

krakjoe: junit testcase classname is used as filename on azure

krakjoe: Revert "this test is flaky on azure, and can't see why from current output"

krakjoe: fix test

dstogov: Fixed reference-counting

dstogov: Cheaper checks for exceptions thrown from __toString()

sgolemon: Update release-process.md

nikic: Remove possible false return value from get_object_vars()

cmb69: Fix #78114: segfault when calling sodium_* functions from eval

nikic: Fix accidentially dropped type

nikic: php_zip_pcre: Match pattern before stating for directories

  • https://github.com/php/php-src/commit/3372f2cf2cd90e899c3b412ec38f2eebc7e106b3
  • [7.4~]
  • ext/zip で、php_zip_pcre() の処理を修正
  • stat() かます前に正規表現の照合処理を入れるよう処理の順序を変えた
  • stat() より正規表現の方が安いだろというのと、処理と同時にディレクトリ内容が変わるようなケースを考慮して、ということらしい

dstogov: Reduce over-specialization for quite seldom instructions

dstogov: Support for exceptions thrown during "Array to string conversion" error processing

dstogov: Use ZEND_ASSUME() to perform the following check only on "slow" path.

nikic: Try to fix Windows build

cmb69: Fix test regarding Unix Domain Sockets on Windows

cmb69: Fix bug #78094: File Search Problem Excessive Time

cmb69: Use zero port in socket_(export|import)_stream-4-win.phpt

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

【LINE Messanging API】プレビュー画像がキャッシュのせいでうまく表示されないときの解決方法

はじめに

LINEbot開発をしている際にハマったことと解決策のメモ。

【環境】

  • PHP(7.3.2)
    • ImageMagick(7.0.7-11)
  • Heroku
  • LINE Messaging API

課題

ユーザのメッセージに応じてサーバに動的に保存した画像をリプライするbotを作っている際に、リプライのプレビュー画像が前回のキャッシュのせいで正しい画像が表示されなかった。

before.php
$client->replyMessage(array(
    'replyToken' => $event['replyToken'],
    'messages' => array(
        array(
            'type' => 'image',
            'originalContentUrl' => 'https://' . $_SERVER["HTTP_HOST"] . '/images/' . $userid . 'out.png',
            'previewImageUrl' => 'https://' . $_SERVER["HTTP_HOST"] . '/images/' . $userid . 'out.png',
        ),
    ),
));

解決方法

.uniqid()を画像指定の時につけたらキャッシュが表示されずに、新たに生成された画像が表示された。

after.php
$client->replyMessage(array(
    'replyToken' => $event['replyToken'],
    'messages' => array(
        array(
            'type' => 'image',
            'originalContentUrl' => 'https://' . $_SERVER["HTTP_HOST"] . '/images/' . $userid . 'out.png?=' . uniqid(),
            'previewImageUrl' => 'https://' . $_SERVER["HTTP_HOST"] . '/images/' . $userid . 'out.png?=' . uniqid(),
        ),
    ),
));
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

YYPHP「PhpStorm有効活用術」「自社サービス開発と受託開発の違いとは?」「ポートフォリオにどんな内容が必要?」「PHPのストリーム」

これは2019年6月7日に開催したPHPerイベントYYPHP#87のイベントレポートです。

YYPHPは一言で「PHPerの部室」です。PHPについて、雑に、ゆるく、ワイワイ話し合う集いです。毎回お題を決めずに雑談を出発点にいろいろなことを突発的にやります。集まった人でコードリーディングをすることもあれば、一緒に開発ツールを触ってみたり、フレームワークについての情報交換をすることもあります。開催はほぼ毎週、高田馬場にて。

今回の配信動画

過去回の配信動画

https://www.youtube.com/playlist?list=PLpOeTEye3Bg6PodrLHHC72jWMJYZz8VbG

雑談

PhpStormを有効活用する方法

テスト周り、実行や、xdebug活用できてないとかで活用できてないと感じる。
docCommentの活用法。

  • PhpStorm使ってる人?: 4/7
  • PhpStormをテストで使っている人?: 1/7
    • PhpStormにPHPUnitと統合する機能がついている
    • PhpStormのボタンクリック1発でテストができる!
    • phpunit.xml をルー
  • xdebug使っている人?: 1/7
    • わりと設定が面倒だった気がする
    • VS CodeでDockerでxdebug
      • xdebugがクライアントになって、ホストOS側に通信できるように設定しないといけないから
      • XAMPPや仮想マシンの方がやりやすい
    • xdebugのメリット
      • ステップ実行ができる
      • 変数が途中で書き換わっているときはステップ実行が便利
      • var_dumpの消し忘れがない
    • 昔はコンテナ内からホストにつなげるのめんどくさかったですけど1年かそこら前からhost.docker.internalという名前でホストにつながるアドレスひけるようになったので、xdebug.remote_host=host.docker.internal と書けば良くなってます
  • メソッドに飛ぶのが便利
  • 知らないと「PhpStormのライセンス料をドブに捨ててる」も同然のショートカットキーを教えてください - Qiita
  • 英語で使ってます?
    • 英語 3名
    • 会社では日本語
  • PHPerなら絶対に入れておきたいプラグイン
  • コーディングスタイル
  • リファクタ機能が便利

自社サービス開発しかやったことなかったけど、他社のシステム開発を受注した件について

他社のシステム開発するにあたって気をつけておくべきことは?

  • 設計が一番大事
    • ビジネス設計
    • 複雑になってるとシステムに落とし込んだときに技術的負債がたくさんできてしまうので気をつけたい
    • 要件定義とか上流工程で決まったことが覆りにくい
    • システムが良く分かってない人が考えると、いい計画にならない
  • 契約
    • 委任 → 完成義務がない
    • 請負 → 完成義務が発生
  • 工期・金額を見積もらないとあとで泣いちゃう
  • 仕事はどういう単位で振られる?
  • 要求の段階で不明確のものはもっとヒアリングする
    • 相手「ざっくりと」
    • 自分「ちゃんといえ」
  • 自社サービスと受託は学べる事は全くといっていいくらい違うかも
  • コミュニケーションが大事
    • 共通認識がずれていないことがすごく気になる
  • クライアントにとっての当たり前が前提になっていることも
    • 業務知識があること前提
    • だれがどういうふうに使うのかというのをちゃんと把握しておかないと死ぬ
  • なんでもやりたいって言われたとき
    • プロジェクトの目標が定まっているか?
    • 優先順位をつけるときにプロジェクトの目標が定まっていないと決められない。
  • 100%安全にやる方法はない
    • 意思疎通を大切にしてカバー
  • 受託のイメージはいいイメージがない
    • 言われたままに作ったものって、あとでポートフォリオとして見せたいと思わない
    • もっとキャリアを先に進めたいと思ったときに、自己PRできるものを作りたい

自社サービスと受託開発で学べることに違いってある?

  • 自社サービスと受託は学べる事は全くといっていいくらい違うかも
  • 自社サービス
    • マネタイズを意識したり、顧客のニーズを考えたり
    • エンジニアリングを超えて、浅く広く知れるようになる
    • 自分のこだわりを出せる
      • 受託: 勝手に変えたら怒られる
    • 自分で技術選定できる
      • Laravelでやるとか
    • 運用に必要な機能も見えてくる
    • モダンな技術が取り入れやすいので、新しい技術を学びやすい
      • チャレンジングな技術など
    • スタートアップだと動くものを早く作るのが大事になるので、スキルが上がるかというと疑問
      • 受託でも納期近いと急かされる
  • 受託開発
    • 作るプロダクトの全体像が見えないことも

※あくまで個人の所感

自社サービス

  • 良い点-> 上流から含めて自社内で完結可能な為、サービス全体の把握や融通が利きやすい。サービスの成長を体感できる。
  • 嫌な点 -> 同じプロダクトにかかわる時間が長くなるためとにかく飽きる。サービスで取り入れてる技術以外の学びが少ない

受託

  • 良い点 -> 設計開発を自分達の方向性に合ったものを選べば学びと仕事になる。様々な業務知識が得られる。上流からは入れてれば技術選定の自由がある
  • 悪い点 -> サービスの成長と自社の利益は全くシンクロしない

受託系でお客さんに振り回されないコツ

ポートフォリオはどんな内容があったら良いのか

プロジェクト管理ツールを作ってはいるが、、
どういう内容があったら採用者に響くか、良いエンジニアと判断されるか

  • ポートフォリオを持っている人は少ないと思う
    • ポートフォリオもいいけど、アウトプットがないと面談などで話しづらい
      • QiitaとかGitHubにアウトプットがあると話やすい
      • 採用担当も判断しやすい
    • Twitterでもいい
  • 「モデルとビューとコントローラーの数」
  • なんでそれを作ったのか、その背景を聞かれた

PHPのストリーム

単語とか調べたけどいまいちしっくりこなかった

  • ストリームって何?
    • PHPのストリームと一般的なアルゴリズム的なストリームは違う
  • PHPのストリーム
    • 入出力(I/O)を扱う
  • stream
    • ストリームは川
    • 川には水が流れている
    • ソフトウェアでは流れてる水がデータ
    • 川からちょっとずつデータを取り出して処理するのがPHPのストリーム
  • PHPではfileの読み込みがストリーム処理
  • PHPに限らずJavaとかでもストリームはあるけど、無限の配列とか、違いがある
  • PHP: ストリーム - Manual
  • ストリームフィルター
  • ストリームコンテキスト
  • ストリームラッパー

YYPHPは毎週やってます

PHPについてワイワイ話したい方は、YYPHPのイベント情報をチェックしてみて下さい。

以上、YYPHPのレポートでした。次回もワイワイやっていきたいと思います! では、また来週!

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

YYPHP#87「PhpStorm有効活用術」「自社サービス開発と受託開発の違いとは?」「ポートフォリオにどんな内容が必要?」「PHPのストリーム」

これは2019年6月7日に開催したPHPerイベントYYPHP#87のイベントレポートです。

YYPHPは一言で「PHPerの部室」です。PHPについて、雑に、ゆるく、ワイワイ話し合う集いです。毎回お題を決めずに雑談を出発点にいろいろなことを突発的にやります。集まった人でコードリーディングをすることもあれば、一緒に開発ツールを触ってみたり、フレームワークについての情報交換をすることもあります。開催はほぼ毎週、高田馬場にて。

今回の配信動画

過去回の配信動画

https://www.youtube.com/playlist?list=PLpOeTEye3Bg6PodrLHHC72jWMJYZz8VbG

雑談

PhpStormを有効活用する方法

テスト周り、実行や、xdebug活用できてないとかで活用できてないと感じる。
docCommentの活用法。

  • PhpStorm使ってる人?: 4/7
  • PhpStormをテストで使っている人?: 1/7
    • PhpStormにPHPUnitと統合する機能がついている
    • PhpStormのボタンクリック1発でテストができる!
    • phpunit.xml をルー
  • xdebug使っている人?: 1/7
    • わりと設定が面倒だった気がする
    • VS CodeでDockerでxdebug
      • xdebugがクライアントになって、ホストOS側に通信できるように設定しないといけないから
      • XAMPPや仮想マシンの方がやりやすい
    • xdebugのメリット
      • ステップ実行ができる
      • 変数が途中で書き換わっているときはステップ実行が便利
      • var_dumpの消し忘れがない
    • 昔はコンテナ内からホストにつなげるのめんどくさかったですけど1年かそこら前からhost.docker.internalという名前でホストにつながるアドレスひけるようになったので、xdebug.remote_host=host.docker.internal と書けば良くなってます
  • メソッドに飛ぶのが便利
  • 知らないと「PhpStormのライセンス料をドブに捨ててる」も同然のショートカットキーを教えてください - Qiita
  • 英語で使ってます?
    • 英語 3名
    • 会社では日本語
  • PHPerなら絶対に入れておきたいプラグイン
  • コーディングスタイル
  • リファクタ機能が便利

自社サービス開発しかやったことなかったけど、他社のシステム開発を受注した件について

他社のシステム開発するにあたって気をつけておくべきことは?

  • 設計が一番大事
    • ビジネス設計
    • 複雑になってるとシステムに落とし込んだときに技術的負債がたくさんできてしまうので気をつけたい
    • 要件定義とか上流工程で決まったことが覆りにくい
    • システムが良く分かってない人が考えると、いい計画にならない
  • 契約
    • 委任 → 完成義務がない
    • 請負 → 完成義務が発生
  • 工期・金額を見積もらないとあとで泣いちゃう
  • 仕事はどういう単位で振られる?
  • 要求の段階で不明確のものはもっとヒアリングする
    • 相手「ざっくりと」
    • 自分「ちゃんといえ」
  • 自社サービスと受託は学べる事は全くといっていいくらい違うかも
  • コミュニケーションが大事
    • 共通認識がずれていないことがすごく気になる
  • クライアントにとっての当たり前が前提になっていることも
    • 業務知識があること前提
    • だれがどういうふうに使うのかというのをちゃんと把握しておかないと死ぬ
  • なんでもやりたいって言われたとき
    • プロジェクトの目標が定まっているか?
    • 優先順位をつけるときにプロジェクトの目標が定まっていないと決められない。
  • 100%安全にやる方法はない
    • 意思疎通を大切にしてカバー
  • 受託のイメージはいいイメージがない
    • 言われたままに作ったものって、あとでポートフォリオとして見せたいと思わない
    • もっとキャリアを先に進めたいと思ったときに、自己PRできるものを作りたい

自社サービスと受託開発で学べることに違いってある?

  • 自社サービスと受託は学べる事は全くといっていいくらい違うかも
  • 自社サービス
    • マネタイズを意識したり、顧客のニーズを考えたり
    • エンジニアリングを超えて、浅く広く知れるようになる
    • 自分のこだわりを出せる
      • 受託: 勝手に変えたら怒られる
    • 自分で技術選定できる
      • Laravelでやるとか
    • 運用に必要な機能も見えてくる
    • モダンな技術が取り入れやすいので、新しい技術を学びやすい
      • チャレンジングな技術など
    • スタートアップだと動くものを早く作るのが大事になるので、スキルが上がるかというと疑問
      • 受託でも納期近いと急かされる
  • 受託開発
    • 作るプロダクトの全体像が見えないことも

※あくまで個人の所感

自社サービス

  • 良い点-> 上流から含めて自社内で完結可能な為、サービス全体の把握や融通が利きやすい。サービスの成長を体感できる。
  • 嫌な点 -> 同じプロダクトにかかわる時間が長くなるためとにかく飽きる。サービスで取り入れてる技術以外の学びが少ない

受託

  • 良い点 -> 設計開発を自分達の方向性に合ったものを選べば学びと仕事になる。様々な業務知識が得られる。上流からは入れてれば技術選定の自由がある
  • 悪い点 -> サービスの成長と自社の利益は全くシンクロしない

受託系でお客さんに振り回されないコツ

ポートフォリオはどんな内容があったら良いのか

プロジェクト管理ツールを作ってはいるが、、
どういう内容があったら採用者に響くか、良いエンジニアと判断されるか

  • ポートフォリオを持っている人は少ないと思う
    • ポートフォリオもいいけど、アウトプットがないと面談などで話しづらい
      • QiitaとかGitHubにアウトプットがあると話やすい
      • 採用担当も判断しやすい
    • Twitterでもいい
  • 「モデルとビューとコントローラーの数」
  • なんでそれを作ったのか、その背景を聞かれた

PHPのストリーム

単語とか調べたけどいまいちしっくりこなかった

  • ストリームって何?
    • PHPのストリームと一般的なアルゴリズム的なストリームは違う
  • PHPのストリーム
    • 入出力(I/O)を扱う
  • stream
    • ストリームは川
    • 川には水が流れている
    • ソフトウェアでは流れてる水がデータ
    • 川からちょっとずつデータを取り出して処理するのがPHPのストリーム
  • PHPではfileの読み込みがストリーム処理
  • PHPに限らずJavaとかでもストリームはあるけど、無限の配列とか、違いがある
  • PHP: ストリーム - Manual
  • ストリームフィルター
  • ストリームコンテキスト
  • ストリームラッパー

YYPHPは毎週やってます

PHPについてワイワイ話したい方は、YYPHPのイベント情報をチェックしてみて下さい。

以上、YYPHPのレポートでした。次回もワイワイやっていきたいと思います! では、また来週!

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

【WordPress】猿にでもできるWordPress脆弱性チェック

WPScanとかよく分からないという人でも、流石にこれならできる筈。1


迷惑です

WordPress は、非常に攻撃対象になりやすい CMS ですので、セキュリティ意識の低い人は、今すぐ使うのを止めてサイトを閉鎖して欲しいなと思います。

もし身の回りに「WordPress のセキュリティ?何それ美味いの?」という人がいたら、自分が被害に遭うだけではなく、他人にまで迷惑をかける事も多々あるという事を、よ~く教えてあげてください。


同様の攻撃が急増中

  1. 息抜きに Web サーバのエラーログを何となく眺める

  2. 相変わらず WordPress への攻撃を試みるリクエストがたくさんあるなぁ…

  3. あれ?この攻撃元の IP は…たぶん○○の VPS だ… うちもお世話になってるところなのに、けしからんなぁ… 誰がやってるんだ…

  4. あぁこれ、WordPress が改ざんされて踏み台にされてるよ… WordPress のバージョン丸見え… って 4.4.1!(驚愕)

  5. 同じサーバーで運営してる別のドメインも、改ざんされてるよ…それなりにお金かかっただろうに…

  6. abuse 宛に報告(いつもなら放置)している内に、他の海外 IP からの攻撃もパターンが同じだと気付く

私が管理しているサーバーだけかもしれませんが、ここ最近、この事例と同様の、脆弱性のある WordPress を踏み台にした攻撃が急増しているようです。以下はホンの一例ですが…

wp-admin/admin-ajax.phpwp-admin/admin-post.php をターゲットにした分かりやすい攻撃ですので、Qiita を読むような方であれば、既に対策はバッチリ!…ですよね?


  1. データベースの更新頻度がかなり低いようですし、とてもオススメだとは言い難いですが、やらないよりは遥かにマシかと…。残念ながら、情報商材などに騙されて、訳も分からず WordPress を運用している人に、小難しい話をしても無駄だと思います。 

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

【WordPress】猿にでもできる脆弱性チェック

WPScanとかよく分からないという人でも、流石にこれならできる筈。1


迷惑です

WordPress は、非常に攻撃対象になりやすい CMS ですので、セキュリティ意識の低い人は、今すぐ使うのを止めてサイトを閉鎖して欲しいなと思います。

Qiita をご覧になるような方は大丈夫だと思いますが、もし身の回りに「WordPress のセキュリティ?何それ美味いの?」という人がいたら、自分が被害に遭うだけではなく、他人にまで迷惑をかける事も多々あるという事を、よ~く教えてあげてください。


経緯

  1. 息抜きに Web サーバのエラーログを何となく眺める

  2. 相変わらず WordPress への攻撃を試みるリクエストがたくさんあるなぁ…

  3. あれ?この攻撃元の IP は…たぶん○○の VPS だ… うちもお世話になってるところなのに、けしからんなぁ… 誰がやってるんだ…

  4. あぁこれ、WordPress が改ざんされて踏み台にされてるよ… WordPress のバージョン丸見え… って 4.4.1!(驚愕)

  5. 同じサーバーで運営してる別のドメインも改ざんされてるよ… こっちは 4.5.3 …(呆れ)

  6. 知識があまり無い人・セキュリティ意識の低い人でも、簡単に使えるサービスはないかと探してみる(今ココ)


同様の攻撃が急増中

私が管理しているサーバーだけかもしれませんが、ここ最近、上記と同様の攻撃が急増しています。以下はホンの一例ですが…

改ざん被害を受けた WordPress を経由して…

  • wp-admin/admin-ajax.php?Action=EWD_UFAQ_UpdateOptions
  • wp-admin/admin-ajax.php?action=update_zb_fbc_code

…のような、脆弱性のあるプラグインかテーマファイルを狙っているっぽいリクエストが送られてきます。

以下のような資料にもある通り、admin-ajax.php はその性質上、攻撃対象になりやすいファイルですので、ご注意ください。


  1. データベースの更新頻度がかなり低いようですし、オススメのサービスとは言い難いですが、やらないよりは遥かにマシかと…。残念ながら、情報商材などに騙されて、訳も分からず WordPress を運用している人に、小難しい話をしても無駄だと思います。 

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

【WordPress】猿にでもできる脆弱性チェック

WPScanとかよく分からないという人でも、流石にこれならできる筈。1


迷惑です

WordPress は、非常に攻撃対象になりやすい CMS ですので、セキュリティ意識の低い人は、今すぐ使うのを止めてサイトを閉鎖して欲しいなと思います。

自分が被害に遭うだけではなく、他人にまで迷惑をかける事も多々あるという事を、よ~く知っておいて下さい。


経緯

  1. 息抜きに Web サーバのエラーログを何となく眺める

  2. 相変わらず WordPress への攻撃を試みるリクエストがたくさんあるなぁ。WordPress なんて使ってないのに…

  3. あれ?この攻撃元の IP は…たぶん○○の VPS だ… うちもお世話になってるところなのに、けしからんなぁ… 誰がやってるんだ…

  4. あぁこれ、WordPress が改ざんされて踏み台にされてるよ… WordPress のバージョン丸見え… って 4.4.1!(驚愕)

  5. 同じサーバーで運営してる別のドメインも、違う方法で改ざんされてるよ…それなりにお金かかっただろうに…

  6. abuse 宛に片っ端から報告(いつもなら放置)

私が管理しているサーバーだけかもしれませんが、2019 年 6 月に入ってから、この事例と同じように、脆弱性のある WordPress を踏み台にした攻撃が急増しているようですので、ご注意ください。

それにしても、こういうところが、なぜ自前のサーバーで運営しようとするのでしょうか。

WordPress は、チューニングしなければくっそ重いですので、このレベルなら、WordPress に特化したレンタルサービスを使った方が、色んな意味で「マシ」だと思います。


  1. データベースの更新頻度がかなり低いようですし、とてもオススメだとは言い難いですが、やらないよりは遥かにマシかと…。残念ながら、情報商材などに騙されて、訳も分からず WordPress を運用している人に、小難しい話をしても無駄だと思います。 

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

【PHP】Google検索結果URLをサクっと生成する

コード

$queryAry = [
    'q' => 'サンプル',      // 検索ワード
    'ie' => 'utf-8',       // 検索ワードの文字コード(念の為指定)
    'newwindow' => '1',    // 検索結果へ飛ぶ際に新しいウインドウを開く
    'tbs' => 'qdr:y2',     // 期間指定(とりあえず2年)
];

echo 'https://www.google.co.jp/search?', http_build_query($queryAry, '', '&');

実行結果


Qiita 等に Google の検索結果 URL を載せる際、少しでも面倒だなと思ったら、数十秒でスッキリ書けるのが PHP の良いところ。

技術系の検索結果を載せる時は、newwindowtbs を指定した方が良いか…と今更反省。でも、newwindow は強制せずに、その人の設定に任せた方が良いのかな。

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

【PHP】FizzBuzz問題を解いてみた。【具体的解説付き】

・動作環境 PHP7

プログラミングの世界で最低限の実力を持っているかどうかを測る指標のような存在であるFizzBuzz問題を解いてみました。
以下に解くまでの過程と考え方も併せて解説致します。

なお「最低1回forとif文でコードを記述した事のある人向け」の解説となっています。
どうしてFizzBuzzがそのソースコードで成立するのか理解する助けになればと思います。

PHPにおけるFizzBuzz問題の答え

fileName.php
<?php

echo "FizzBuzz問題";
echo PHP_EOL;

for($i = 1; $i <=100; $i++){
    if($i % 15 === 0){
        echo "FizzBuzz";
        echo PHP_EOL;
    }elseif($i % 5 === 0){
        echo "Buzz";
        echo PHP_EOL;
    }elseif($i % 3 === 0){
        echo "Fizz";
        echo PHP_EOL;
    }else{
        echo $i;
        echo PHP_EOL;
    }
}

?>

以下解説。

その1 : For文

fileName.php
<?php
for($i = 1 ; $i <= 30 ; $i++){
  条件式
}
?>

Forはループを作り出すのに用います。
なお上記のforに続く()の中身を訳しますと、

1、「$i = 1」最初は$iに1を入れる。そしてまずはそれを出力。
2、「$i <= 30」以降の繰り返し処理で$iの中身が30を超えない限り出力を繰り返す。
3、「$i++」なお1回繰り返す毎に1を足していく。

という処理内容です。
なので上記の場合1~30までの数字が出力されます。

forは「n番目まで続く連続した数列を作る」とか、「n回同じ処理を必要とする」場合に用いられる訳です。

その2 : if文

一番上の答えの中でif文は以下の部分にある事が解ります。

for($i = 1; $i <=100; $i++){
 「この部分がif文」
}

ここからはその部分の解説をします。

filename.php
    if($i % 15 === 0){
        echo "FizzBuzz";
        echo PHP_EOL;
    }elseif($i % 5 === 0){
        echo "Buzz";
        echo PHP_EOL;
    }elseif($i % 3 === 0){
        echo "Fizz";
        echo PHP_EOL;
    }else{
        echo $i;
        echo PHP_EOL;
    }

なおそもそもの挙動としてif文は以下のように、順番に処理をしている事になります。

1、(今回の場合)最初のfor文で出てきた数字を受け取る。
2、if文の中身のソースコードを上から順番に処理し、該当部分が出たらその処理内容を出力する。
3、出力処理がされたらそこで計算は一旦終了。1に戻りfor文の記述に従い、次の数字を受け取る。

つまり今回のソースコードの場合は、「1をifで処理し、2をifで処理し、3をetc…」 という処理をしていた事になります。

ifでの処理の順番

次に処理の順番です。
結論から言うと、

1、if文で15の倍数を検知して”FizzBuzz”を出力。
2、3の倍数を検知して"Fizz"を出力。
3、5の倍数を検知して"Buzz"を出力。
4、上記に該当しなかった場合そのまま数字を出力。

この順番で処理します。

また、FizzBuzz問題を解く際は、「集合」を気にしてみるのが良いと感じました。
高校数学Aでやったあの集合です。

四角形の中に〇が2つ描かれていて、その丸同士が重なっている図を1度は見た事があると思います。

その図の丸が重なった部分から処理し、次に丸単体を処理し、最後に丸に該当しない数字を順番に書き出せばよいのです。
そうすれば重なった部分を重複処理する事を避ける事ができます。

図で集合を解説

FizzBuzz.jpg

上記の図は、
・forの四角い枠が全ての数字。
・3nの円が3の倍数。
・5nの円が5の倍数。
・そして3と5が重なる部分が15の倍数
という事になります。

今回はこの図を使って解説します。

計算部の考え方

ところでFizzBuzz問題は3の倍数や5の倍数や15の倍数の時に表現をFizzやらBuzzにすり変えよという問題です。
この場合、複数条件が重なった部分を出力し、次に単体で条件に重なるものを順番に出力して、最後にどの条件にも合致していない数字を出力すればよいのです。

従って、
1、計算部の重なっている部分の15n(3の倍数かつ5の倍数である15nの部分)をまず出力
2、3nの部分を出力
3、5nの部分を出力
4、3倍でも5倍でもない数字を出力
※2と3は重なり合った部分ではないので順番が逆でもOK!

という順番に処理を行えば、FizzBuzzが完成するという訳です。

FizzBuzz.jpg

if文の仕様

「え?15の倍数を処理できても、それらは3の倍数とか5の倍数でもあるのだから"FizzBuzzFizz"みたいな出力にならないか?」
と考えたかもしれませんが、ご安心を。

if文は、1度処理に成功したら以降の処理をしないという仕様です。

処理時に数字が15の倍数であると解ればFizzBuzzを出力して、以降にある3の倍数・5の倍数の処理層にはそもそも計算が行かないのです。
それを考慮しながら下記のif文をもう一度ご覧ください。

filename.php
    if($i % 15 === 0){
        echo "FizzBuzz";
        echo PHP_EOL;
    }elseif($i % 5 === 0){
        echo "Buzz";
        echo PHP_EOL;
    }elseif($i % 3 === 0){
        echo "Fizz";
        echo PHP_EOL;
    }else{
        echo $i;
        echo PHP_EOL;
    }

if文は、例えるのなら”フィルター”に近いです。

・最初が15の倍数というフィルターで該当したらそこで処理。
・次が、3と5の倍数というフィルターで該当したらそこで処理。
・そして最後の"}else{"以降で、どのフィルターにも当てはまらない数字を処理。

となります。

最後までフィルター(15の倍数/5の倍数/3の倍数)にかからなかった数字が最後の処理層に届く訳です。

間違い等ありましたらお気軽にコメント欄へお申し付けください。

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

【PHP】FizzBuzz問題を解いてみた。

・動作環境 PHP7

プログラミングの世界で最低限の実力を持っているかどうかを測る指標のような存在であるFizzBuzz問題を解いてみました。
以下に解くまでの過程と考え方も併せて解説致します。

なお「最低1回forとif文でコードを記述した事のある人向け」の解説となっています。
どうしてFizzBuzzがそのソースコードで成立するのか理解する助けになればと思います。

PHPにおけるFizzBuzz問題の答え

fileName.php
<?php

echo "FizzBuzz問題";
echo PHP_EOL;

for($i = 1; $i <=100; $i++){
    if($i % 15 === 0){
        echo "FizzBuzz";
        echo PHP_EOL;
    }elseif($i % 5 === 0){
        echo "Buzz";
        echo PHP_EOL;
    }elseif($i % 3 === 0){
        echo "Fizz";
        echo PHP_EOL;
    }else{
        echo $i;
        echo PHP_EOL;
    }
}

?>

以下解説。

先頭のFor文

fileName.php
<?php
for($i = 1 ; $i <= 30 ; $i++){
  条件式
}
?>

Forはループを作り出すのに用います。
なお上記のforに続く()の中身を訳しますと、

1、「$i = 1」最初は$iに1を入れる。そしてまずはそれを出力。
2、「$i <= 30」以降の繰り返し処理で$iの中身が30を超えない限り出力を繰り返す。
3、「$i++」なお1回繰り返す毎に1を足していく。

という処理内容です。
なので上記の場合1~30までの数字が出力されます。

forは「n番目まで続く連続した数列を作る」とか、「n回同じ処理を必要とする」場合に用いられる訳です。

if文

一番上の答えから見ますとif文は以下の部分にある事が解ります。

for($i = 1; $i <=100; $i++){
 「この部分がif文」
}

ここからはその部分の解説をします。

filename.php
    if($i % 15 === 0){
        echo "FizzBuzz";
        echo PHP_EOL;
    }elseif($i % 5 === 0){
        echo "Buzz";
        echo PHP_EOL;
    }elseif($i % 3 === 0){
        echo "Fizz";
        echo PHP_EOL;
    }else{
        echo $i;
        echo PHP_EOL;
    }

なおそもそもの挙動としてif文は以下のように処理をしています。

1、(今回の場合)最初のfor文で出てきた数字を受け取る。
2、if文の中身のソースコードを上から順番に処理し、該当部分が出たらその処理内容を出力する。
3、出力処理がされたらそこで計算は一旦終了。1に戻りfor文の記述に従い、次の数字を受け取る。

つまり今回のソースコードの場合は、「1をifで処理し、2をifで処理し、3をetc…」 という処理をしていた事になります。

ifでの処理の順番

次に処理の順番です。
結論から言うと、

1、if文で15の倍数を検知して”FizzBuzz”を出力。
2、3の倍数を検知して"Fizz"を出力。
3、5の倍数を検知して"Buzz"を出力。
4、上記に該当しなかった場合そのまま数字を出力。

この順番で処理します。

また、FizzBuzz問題を解く際は、「集合」を気にしてみるのが良いと感じました。
高校数学Aでやったあの集合です。

四角形の中に〇が2つ描かれていて、その丸同士が重なっている図を1度は見た事があると思います。
その図の丸が重なった部分から処理し、次に丸単体を処理し、最後に丸に該当しない数字を順番に書き出せばよいのです。

図で集合を解説

FizzBuzz.jpg

上記の図は、
・forの四角い枠が全ての数字。
・3nの円が3の倍数。
・5nの円が5の倍数。
・そして3と5が重なる部分が15の倍数
という事になります。

今回はこの図を使って解説します。

計算部の考え方

ところでFizzBuzz問題は3の倍数や5の倍数や15の倍数の時に表現をFizzやらBuzzにすり変えよという問題です。
この場合、複数条件が重なった部分を出力し、次に単体で条件に重なるものを順番に出力して、最後にどの条件にも合致していない数字を出力すればよいのです。

従って、
1、計算部の重なっている部分の15n(3の倍数かつ5の倍数である15nの部分)をまず出力
2、3nの部分を出力
3、5nの部分を出力
4、3倍でも5倍でもない数字を出力
※2と3は重なり合った部分ではないので順番が逆でもOK!

という順番に処理を行えば、FizzBuzzが完成するという訳です。

FizzBuzz.jpg

if文の仕様

「え?15の倍数を処理できても、それらは3の倍数とか5の倍数でもあるのだから"FizzBuzzFizz"みたいな出力にならないか?」
と考えたかもしれませんが、ご安心を。

if文は、1度処理に成功したら以降の処理をしないという仕様です。

処理時に数字が15の倍数であると解ればFizzBuzzを出力して、以降にある3の倍数・5の倍数の処理層にはそもそも計算が行かないのです。
それを考慮しながら下記のif文をもう一度ご覧ください。

filename.php
    if($i % 15 === 0){
        echo "FizzBuzz";
        echo PHP_EOL;
    }elseif($i % 5 === 0){
        echo "Buzz";
        echo PHP_EOL;
    }elseif($i % 3 === 0){
        echo "Fizz";
        echo PHP_EOL;
    }else{
        echo $i;
        echo PHP_EOL;
    }

if文は、例えるのなら”フィルター”に近いです。

・最初が15の倍数というフィルターで該当したらそこで処理。
・次が、3と5の倍数というフィルターで該当したらそこで処理。
・そして最後の"}else{"以降で、どのフィルターにも当てはまらない数字を処理。

となります。

間違い等ありましたらお気軽にコメント欄へお申し付けください。

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

Laravel の Listener, Subscriber, Observer それぞれの使い分けについてざっくり

この記事について

Laravel にはイベントを捕捉する仕組みがいくつかあるんですが、まとめて違いや使い方を説明してるページがないな、と思ったので、本当にざっくりですが、書いてみました。

Listener

単体のイベントを捕捉する

Providers/EventServiceProvider.php

protected $listen = [
    Event::class => [
        Listener::class,
    ],
];

呼び方

event(new Event($something));

Subscriber

複数のイベントを捕捉する - 何らかの共通の処理を挟んだりするときに有用

Providers/EventServiceProvider.php

protected $subscribe = [
    Subscriber::class,
];

Subscriber.php

public function subscribe($events): void
{
    $events->listen(FooEvent::class, 'App\Listeners\Subscriber@handleFoo');
    $events->listen(BarEvent::class, 'App\Listeners\Subscriber@handleBar');
}

呼び方

event(new FooEvent($something));

Observer

特定のモデルのイベントを捕捉する - モデルの変化にシームレスに追従して何らかの処理を行いたいときに有用

AppServiceProvider.php

SomeModel::observe(SomeModelObserver::class);

明示的にイベントを発火する必要はなく、それぞれのイベントがしかるべきタイミングで勝手に呼ばれます。

デフォルトで捕捉してくれるイベントは下記の13個

HasEvents.php

    public function getObservableEvents()
    {
        return array_merge(
            [
                'retrieved', 'creating', 'created', 'updating', 'updated',
                'saving', 'saved', 'restoring', 'restored', 'replicating',
                'deleting', 'deleted', 'forceDeleted',
            ],
            $this->observables
        );
    }

setObservableEvents, addObservableEvents, removeObservableEvents あたりをつかって増やしたり減らしたりできます。 getObservableEvents() が呼ばれる前に使ってください。

おまけ: ワイルドカード Listener

イベント名のプレフィックスを使ってマッチしたイベントを捕捉する

Event::listen('message.*', function ($event, $payload) {
  // handle event with prefix 'message.'
});

通常は、

event(new MessageSent());

のようにオブジェクトを渡しますが、ワイルドカードを使う場合は、

event('message.sent', ['message' => 'hi']);

のように、イベント名を表す文字列で発火させるようにします。

まとめ

  • Listener: 単独のイベント
  • Subscriber: 複数の関連したイベント
  • Observer: モデルのイベント
  • ワイルドカード Listener: 共通で処理したいイベント
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP-fpmの環境設定するにあたって理解出来るように仕組みについて調べてみた!

どうもUT(@ut_1029)です。
PHP-fpmでプログラミングしているとあまり気にしていなかったんですが、PHP-fpm環境構築設定などするにあたり、何も知らないなぁっと自分で感じたので、基本的なことを調べることにしました。

これまでは、PHPの設定とかは
ただググってとりあえず動けばOK
って感じでした。

でも、
細かなチューニング正しい設定となるとお手上げでした。。。

それで
少しでも理解できればと思い本記事を書きました。

今回、以下の事を中心に調べてみました。

  • PHP-fpmってなに?
  • CGIとかFastCGIってなに?
  • PHP-fpmはPHPと何が違うの?
  • NginxとPHP-fpmの連携ってどうなってるの?

などなど。

では、
PHP-fpmで知っておくべき知識について
まずはこちらから紹介します。

ちなみに
この内容は自分のブログからの転載です。
UTの日常 - PHP-fpmの環境設定するにあたって理解出来るように仕組みについて調べてみた!

PHPとは

PHP : Hypertext Preprocessor
Webシステムの作成によく使われるプログラム言語のひとつ。

ポイントは

pointプログラミング言語だよ
pointスクリプト言語だよ
pointWeb系のプログラムを作るときによく使われるよ

「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

広く使われているオープンソースの汎用スクリプト言語です。
PHP は、特に Web 開発に適しており、HTML に埋め込むことができます。
PHP: PHPとはなんでしょう?

あと、
PHPの詳しい動作について書かれている記事がありましたので、紹介しておきます。

知っていますか?あなたの書いたPHPのコードが実行される4つのプロセス

ちなみに
PHPは、インタープリタ言語コンパイラ言語どちらでしょうか?

正解は、
インタープリタ言語
です。

コンパイラ言語

コンパイラ言語は、プログラム作成後にコンパイルを行う必要があります。

インタープリタ言語

インタープリタ言語は、プログラムを実行する度の機械語へ変換されます。
なので、コンパイルを行うこと必要がありません。

また
PHPには、モジュール版CGI版の二種類があります。

これが、
PHP-fpmPHPの違いの第1歩です。

PHPのモジュール版とCGI版の違い

CGI版

Webサーバとは別のプロセスで実行される。

Webサーバとは別プロセスで動作ということは、実行する度にメモリのロードが必要となります。
その為、動作速度がモジュール版に比べて遅くなります。

モジュール版

WebサーバのプロセスのなかでPHPを実行する方法。
CGIに比べて動作速度が高速になります。

CGIとは

Common Gateway Interface の略。

すごくかみ砕くと
ホームページでプログラムを動かすための仕組み
だそうです。

つまりは

  • 掲示板サイト
  • ショッピングサイト

など
は、CGIの仕組みでプログラムを動かしているWebサイトになります。

ポイントは、

  • pointWebサーバ上でプログラムを動かすための仕組みだよ
  • pointWebサーバ上で(クライアントからの要求に応じて)動くプログラムを指していることもあるよ
  • point動的にページを生成して返すよ

「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

FastCGIとは

CGIの改良版で
Webサーバのプログラムを一度起動させたら、しばらくメモリ上へ保持し待機させる仕組み
だそうです。

一度起動させたプログラムを待機させることで
プログラムの起動や終了の処理を軽減させ、Webサーバの負荷軽減が期待できます。

一定期間待機しているプログラムはメモリ上に展開されます。

この用語のポイント

  • pointCGIの改良版だよ
  • point一度動き出したプログラムは、しばらくメモリ上に待機させるよ
  • point起動/終了処理が減る分、CGIと比較して、処理の高速化と負荷の軽減が見込めるよ

「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

PHP-FPMとは

FastCGI Process Managerの略。
つまり
PHPFastCGIで動作させることが出来るものになります。

PHP の FastCGI 実装のひとつで、
主に高負荷のサイトで有用な追加機能を用意しています。

以下のような機能があります。

  • 緩やかな (graceful) 停止/起動 機能を含む高度なプロセス管理
  • 異なる uid/gid/chroot/environment でのワーカーの開始、 異なるポートでのリスン、異なる php.ini の使用 (safe_mode の代替)
  • 標準出力および標準エラー出力へのログ出力
  • opcode キャッシュが壊れた場合の緊急再起動
  • 高速なアップロードのサポート
  • “slowlog” – 実行時間が非常に長いスクリプトの記録 (スクリプト名だけでなく、PHP バックトレースも記録します。バックトレースを取得するために、 ptrace やそれと同等の仕組みを使ってリモートプロセスの execute_data を読みます)
  • fastcgi_finish_request() – 何か時間のかかる処理 (動画の変換や統計情報の処理など) を継続しながら リクエストを終了させてすべてのデータを出力させるための特殊な関数
  • 動的/静的 な子プロセスの起動
  • 基本的な SAPI の動作状況 (Apache の mod_status と同等)
  • php.ini ベースの設定ファイル

PHP: FastCGI Process Manager(FPM)

Nginxとは

PHP-fpmといえば
Nginxで動作させるのが一般的っぽいので、Nginxについても少し触れておきます。

Nginxは、通常FastCGIを使っているみたいです。

そして
Nginxは、PHPプロセスとは別で動作するため、PHPの処理が高負荷になっても影響は、Apacheに比べて軽減されます。

ちなみに
初期設定では9000番ポートで起動するが、UNIXドメインソケットに変更することも可能みたいです。

PHP-fpmとNginxを連携させる(通信)にあたって

どういった設定を行っているのか具体的に理解していなかったので、改めて整理してみました。

ちなみに
TCPとかUNIXドメインソケットとかはまた詳しく調べようと思います。。。

TCP

  • ネットワーク上でマシンを越えてのプロセス間通信
  • 特定方法
    • IPアドレス+ポート番号
  • 通信箇所
    • 他マシンと通信可

調べなきゃ寝れない!と調べたら余計に寝れなくなったソケットの話

NginxPHP-fpmのサーバが物理的に別の場合は、
TCPを利用する理由が分かった気がします。

PHP-fpmとNginxの設定例

※設定して実際に動かしてないのであくまで参考程度にしてください。

# $ sudo vi /etc/php-fpm.d/www.conf
; The address on which to accept FastCGI requests.
; Valid syntaxes are:
; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on
; a specific port;
; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
; a specific port;
; 'port' - to listen on a TCP socket to all addresses
; (IPv6 and IPv4-mapped) on a specific port;
; '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
; PHP-FPMが待ち受けを行うポートの設定
; listen = /var/run/php-fpm/www.sock
listen = 127.0.0.1:9000
# $ sudo vi /etc/nginx/nginx.conf
location ~ \.php$ {
root /var/www/html;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include fastcgi_params;
}
$ sudo /etc/rc.d/init.d/php-fpm restart
$ sudo /etc/rc.d/init.d/nginx restart
$ netstat -a --tcp
tcp 0 0 localhost:9000 *:* LISTEN

UNIXドメインソケット

  • 同じマシン上で動いているプロセスが通信を行うためのソケット。
  • アドレス・名前空間としてファイルシステムを使用している。
  • ファイルシステム内のinodeとしてプロセスから参照される。
  • 特定方法
    • ファイル名で一致
  • 通信箇所
    • 自マシンのみ
  • TCPソケット(INETドメインソケット)よりも遥かにスループットが優れてるらしい。

調べなきゃ寝れない!と調べたら余計に寝れなくなったソケットの話

PHP-fpmとNginxの設定例

※設定して実際に動かしてないのであくまで参考程度にしてください。

# $ sudo vi /etc/php-fpm.d/www.conf
; The address on which to accept FastCGI requests.
; Valid syntaxes are:
; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on
; a specific port;
; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
; a specific port;
; 'port' - to listen on a TCP socket to all addresses
; (IPv6 and IPv4-mapped) on a specific port;
; '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
; PHP-FPMが待ち受けを行うポートの設定
listen = /var/run/php-fpm/www.sock
; listen = 127.0.0.1:9000
# $ sudo vi /etc/nginx/nginx.conf
location ~ \.php$ {
root /var/www/html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}
$ sudo /etc/rc.d/init.d/php-fpm restart
$ sudo /etc/rc.d/init.d/nginx restart
$ netstat -a --unix
unix 2 [ ACC ] STREAM LISTENING 20655 /var/run/php5-fpm.sock

おわりに

今回PHP-fpmについてまとめることで、ちょっとPHP-fpmについて分かった気がしました。

ただ
まだまだ分からないことは、たくさんあるのでもう少し深掘りして行こうかなぁっと思います。

いつになるか分からないですが、その時はまたブログへ投稿します♪

この記事の内容でおかしな点があればご指摘をお願いしますm(_ _)m

最後になりますが、
こちらの内容は以下の自分のブログへも投稿しています。
もし、気が向いたらブログも読んで見てください♪

ロゴ_100.jpeg

UTの日常

参考サイト

記事作成でメインに参考にさせてもらった記事です。
他にも色々参考にしたサイトもありますが、紹介しておきます。

ググるとこの記事がすぐに出るぐらいよく読まれている記事のようです。
今回の記事作成でメインで参考にさせてもらいました。

nginx と PHP-FPM の仕組みをちゃんと理解しながら PHP の実行環境を構築する

UNIXドメインソケット(ソケット通信)について
簡単にまとめてくれている記事。

調べなきゃ寝れない!と調べたら余計に寝れなくなったソケットの話

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

PHP foreachで回した配列を更新する

PHP foreachで回した配列を更新する

基礎の基礎という感じですが、初投稿も兼ねてforeachで回した配列の要素を更新する方法についてメモします。

例)数値型を持つ配列$arrayの各要素をforeachで取り出し、各要素に+1する

以下はNGケースです。

$array = [1, 2, 3];

foreach($array as $value){
    $value += 1;
}

print_r($array);

/* 実行結果 → 各要素に+1されない
Array
(
[0] => 1
[1] => 2
[2] => 3
)
*/

上記のコードでは配列を更新できません。foreachの仕様として、配列要素のコピーがforeach内の変数に格納されるため、更新ができないのです。

foreachの変数を利用して配列要素を更新するためには、参照渡しをする必要があります。
手順は以下2点です。
・更新したいforeach変数の頭に&を付与 (参照渡し)
・更新処理の後にunset(変数名)を記述 (参照渡しの解除)

以下はOKケースです。

$array = [1, 2, 3];

foreach($array as &$value){       //(参照渡し)
    $value += 1;
}
unset($value);                   //(参照渡しの解除)

print_r($array);

/* 実行結果
Array
(
[0] => 2
[1] => 3
[2] => 4
)
*/

まとめ

foreach変数に参照渡しをすることで、配列要素とforeach変数がリンクするので、配列要素の更新が可能になります。
この点は少し注意が必要ですが、foreachを抜けた後も参照渡しをした変数には配列の最後の要素が入ったままなので、unset()で参照渡しの解除をしています。

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

PHP で GET, POST のどちらからでもパラメーターを受け取る

GET, POST のどちらでパラメーター渡されても楽に受け取りたい

方法

function fetch_param($param)
{
    return $_SERVER['REQUEST_METHOD'] === 'GET'
        ? filter_input(INPUT_GET, $param)
        : filter_input(INPUT_POST, $param);
}

やってること

PHP のスーパーグローバル変数である $_REQUEST['REQUEST_METHOD'] を用いると、いまアクセスされている httpメソッドがGET なのか POST なのか確認できるので、それに応じて filter_input() の第一引数を変更する。

もうちょっとスマートな方法がありそうな気はしますね。

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

""で囲まれた文字列にあるスペースを*に変換する

ポイント:preg_replace_callbackを利用する

変換前文字列:"aaa bbb" ccc ddd "eee"
変換後文字列:"aaa*bbb" ccc ddd "eee"

php > print(preg_replace_callback('/".+?"/', function ($matches) {return str_replace(' ', '', $matches[0]);}, '"aaa bbb" ccc ddd "eee"'));
"aaa
bbb" ccc ddd "eee"

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

Laravel-adminで1対多を色々な形で表示してみる

概要

Laravel-adminの1対多で結びついているデータを色々な形で表示してみました.

環境

Laravel 5.3 , Laravel-admin 1.6.9

モデル

Author.php
class Author extends Model
{
    public function books() {
        return $this->hasMany(Book::class,'author_id')->orderBy('id','asc');
    }
}
Book.php
class Book extends Model
{
    protected $fillable=['title','author_id','page','subtitle','price'];

    public function author() {
        return $this->belongTo(Author::class,'author_id');
    }
}

通常の使用

公式ドキュメントなどにあるように実装するとこのような画面が出来上がります.
子のテーブルのカラムが少ない場合はこれで十分使えると思います.

ノーマルモード.PNG

AuthorController.php
protected function form()
{
    $form = new Form(new Author);

    $form->tab('氏名',function($form) {
        $form->hidden('id');
        $form->text('first_name', '名');
        $form->text('last_name', '氏');
    })->tab('本',function($form) {
        $form->hasMany('books','BOOK',function(Form\NestedForm $nestedForm) {
            $nestedForm->hidden('id');
            $nestedForm->text('title','タイトル');
            $nestedForm->text('subtitle','サブタイトル');
            $nestedForm->number('page','ページ数');
            $nestedForm->currency('price','価格');
        });
    });

    return $form;
}

タブモード

ノーマルモードのフォーム1つ1つをタブに入れて表示しています.子のカラムが増えても1ページに1つのレコードが表示されるため,ノーマルモードに比べて下に伸びにくくなっています.
一方で,親が子を多く持つとタブの数が増加するため,このようなときには使いづらくなります.また,目的のレコードが探しづらいという短点もあります.

タブモード.PNG

AuthorController.php
protected function form()
{
    $form = new Form(new Author);

    $form->tab('氏名',function($form) {
        $form->hidden('id');
        $form->text('first_name', '名');
        $form->text('last_name', '氏');
    })->tab('本',function($form) {
        $form->hasMany('books','BOOK',function(Form\NestedForm $nestedForm) {
            $nestedForm->hidden('id');
            $nestedForm->text('title','タイトル');
            $nestedForm->text('subtitle','サブタイトル');
            $nestedForm->number('page','ページ数');
            $nestedForm->currency('price','価格');
        })->useTab();
    });

    return $form;
}

デーブルモード

laravel-admin 1.6.10にて追加された機能.上記の2つに比べてスッキリとしたデザインで使いやすいと思います.
しかし,子のカラムが増えると横幅が足りなくなり,入力フォームが非常に小さくなることがあります.

テーブルモード.PNG

AuthorController.php
protected function form()
{
    $form = new Form(new Author);

    $form->tab('氏名',function($form) {
        $form->hidden('id');
        $form->text('first_name', '名');
        $form->text('last_name', '氏');
    })->tab('本',function($form) {
        $form->hasMany('books','BOOK',function(Form\NestedForm $nestedForm) {
            $nestedForm->hidden('id');
            $nestedForm->text('title','タイトル');
            $nestedForm->text('subtitle','サブタイトル');
            $nestedForm->number('page','ページ数');
            $nestedForm->currency('price','価格');
        })->useTable();
    });

    return $form;
}

index画面の埋めこみ

index画面にあるgridをそのままフォームに埋め込んだものとなっています.
index画面を埋め込んでいるため動作はindex画面に準じたもので,他のフォームとは独立した編集画面として動作します.
例えばindex画面と同様に編集を行うと,送信ボタンを押さずともデータベースが更新され,新規ボタンを押すとBookControllerのcreateメソッドに飛びます.
あくまで表示だけにとどめて,新規・編集機能は上記の3つのどれかで実装するのが良いと思われます.

grid埋めこみ.PNG

AuthorController.php
protected function form($id = null)
{
    if($id) {
        //Bookのgird画面のHTMLレンダリングを先に行う
        $html = '';

        //Book用のgridを作成する
        $grid = new Grid(new Book);
        $grid->setName('BOOK')
            ->setTitle('本')
            ->setRelation(Author::find($id)->books())
            ->resource('/admin/books');

        $grid->title('タイトル')->editable();
        $grid->subtitle('サブタイトル')->editable();
        $grid->page('ページ数')->editable();
        $grid->price('価格')->editable();

        //ボタンを無効
        $grid->disableExport();
        $grid->disableFilter();
        $grid->disablePagination();
        $grid->disableRowSelector();
        $grid->tools(function ($tools) {
            $tools->disableRefreshButton();
        });

        //操作を無効化
        $grid->actions(function ($actions) {
            $actions->disableView();
            $actions->disableEdit();
            });

        $html = $grid->render();
    }

    $form = new Form(new Author);

    $form->tab('氏名',function($form) {
        $form->hidden('id');
        $form->text('first_name', '名');
        $form->text('last_name', '氏');
    })->tab('本',function($form) use ($html) {
        $form->html(function() use ($html) {
            return $html;
        })->setWidth(12, 0);
    });

    return $form;
}

まとめ

4つの表示方法を紹介しましたが,いずれも一長一短で状況に応じて使い分けるのが良いと思います.
また,index画面の埋めこみはかなりトリッキーな実装をしているので,ここまでするなら素直にbladeを書いたほうが良い気もします.

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

PHP5.6からPHP7.3へバージョンアップしたのでeregi関数をpreg_match関数へ置き換え

PHPを5.6から7.3へバージョンアップした際に、7系から削除されたerigi関数をpreg_match関数で置き換えた備忘録。

置き換え

置き換え前
eregi($hoge, $fuga)
置き換え後
preg_match('{'.$hoge.'}', $fuga)

はじめは、'/'.$hoge.'/'で置き換えたらWarningが出てしまいダメだったので、下記サイトを参考に上記置き換え後のコードにしたら無事に動作してくれました。

参考サイト

PHPでpreg_match関数、URLの比較してUnknown modifier ‘/’ inエラーが出てしまう時の原因と対処法 – 1ft-seabass.jp.MEMO

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

Virtual Box+Vagrantを使ってローカル環境で既存のCakePHPアプリを動かす

はじめに

転職先でリリース済みサービスの開発に途中から参加することになり、テスト環境としてローカル環境を作ってアプリを動すために構築した手順を備忘録として残したいと思い投稿しました。

目次

  1. VirtualBox,Vagrantのインストール
  2. Vagrantfileの作成、各種編集
  3. vagrant upの実行
  4. 既存アプリのクローン
  5. Apacheのhttpd.confの編集
  6. MySQLの設定、アプリとの接続
  7. 本番環境DBのダンプ→ローカルDBへリストア
  8. ブラウザで接続確認

手順

1. VirtualBox,Vagrantのインストール

それぞれのHPからOSにあったものをダウンロードします。

Virtual Box↓
https://www.virtualbox.org/
Vagrant↓
https://www.vagrantup.com/

2. Vagrantfileの作成,各種編集

①Vagrantfileの作成

vagrantfileを設置するディレクトリを作成し「vagrant init」で初期化、vagrantfileを作成します。
自分はデスクトップ上でディレクトリを確認したかったので ~/desktop/work/vagrant内にvagrantfileを作成します。(※1)
また、vagrantディレクトリと同じ階層に仮想マシンとホストマシンと共有するための共有ディレクトリ(src)を作成します。(※2)
(※1)work:仮想マシンを複数立ち上げる場合、仮想マシンの数ぶんのディレクトリを作成するので、その大元のディレクトリになります。
(※2)共有ディレクトリ:実際のアプリは仮想マシン内にクローンしますが、共有ディレクトリを設定しておくことでホストマシンにも仮想マシンでクローンしたアプリが共有され、ホストマシンで使い慣れたエディタでアプリのソースをいじることができるようになります。

#workディレクトリ、vagrantディレクトリの作成
~$       cd desktop
desktop$ mkdir work

#workディレクトリに移動しvagrantとsrcディレクトリを作成
desktop$ cd work
work$    mkdir vagrant (Vagrantfileを作成するディレクトリ)
work$    mkdir src   (仮想マシンとの共有ディレクトリ)
work$    ls            (vagrantとsrcが作成されているか確認)
src vagrant ←が表示されればOK!

#Vagrantfileの作成
work$    cd vagrant
vagrant$ vagrant init "bento/centos-7.4"

↑"bento/centos-7.4"はvagrant boxと呼ばれる仮想マシンのテンプレート,雛形のようなものです。
1からOSをインストールして行くのは大変ですが vagrant init box名 で環境を構築することができます。

②Vagrantfileの編集

・vimの起動

vagrant$ vim Vagrantfile

(1)ネットワーク設定

# config.vm.network "private_network", ip: "192.168.33.10"

上記のコメントアウトを外して・・・

config.vm.network "private_network", ip: "192.168.33.10"

このようにします。
こちらで設定したIPアドレスにブラウザでアクセスしてアプリの動作を確認します。

(2).共有ディレクトリ、パーミッションの設定
「# config.vm.synced_folder」のコメントアウトを外して下記のように編集します。

config.vm.synced_folder "../src", "/vagrant", mount_options:['dmode=777','fmode=777']

「config.vm.synced_folder "ホストマシンのパス", "仮想マシンのパス"」 で共有ディレクトリを設定します。
「mount_options:['dmode=777','fmode=777']」は「config.vm.synced_folder」のオプションで、dmodeはディレクトリの権限、fmodeはファイルの権限を設定します。

(3)プロビジョニング(vagrant up時に行うプロセスを設定)
「# config.vm.provision」の記述を編集(コマンドアウトされていたら外してください)

config.vm.provision "shell", :path => "provision.sh"

↑これで「vagrant up」時に「provision.sh」が実行されるように設定されました。
「provision.sh」内に各種インストールの記述をしておけば「vatrant up」時に自動的にインストールを行ってくれます。

(4)「provision.sh」の作成,編集
先ほどVagrantfileに設定した「provision.sh」はまだ作成していないのでVagrantfileがある階層で「provision.sh」を作成し編集を行います。

#Vagrantfileがあるvagrantディレクトリ内にprovision.shを作成
vagrant$ touch provision.sh

自分の環境に合わせて「provision.sh」に以下の記述を修正しペースト

# Apache,unzip,gitのインストール
yum -y install httpd unzip git

# MySQLのインストール
yum -y install http://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm
yum -y install mysql-community-server

# PHPのインストール
yum -y install epel-release
yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
※remi-release-7の数字部分は仮想マシンのCentOSのバージョンに合わせる
yum -y install --enablerepo=remi,remi-php56 php php-devel php-mbstring php-intl php-mysql php-xml
※remi-php56の数字部分はインストールしたいPHPのバージョンに合わせる(今回は既存アプリの環境がPHP5.6)

# ApacheがVagrant up時に起動する設定
systemctl enable httpd.service
systemctl start httpd.service

# MySQLがVagrant up時に起動する設定
systemctl enable mysqld.service
systemctl start mysqld.service

# Vagrantの共有フォルダにパスを設定
rm -rf /var/www/html
ln -fs /vagrant /var/www/html
3.vagrant upの実行

Vagrantfileがあるvagrantディレクトリに移動し「vagrant up」を実行します。

vagrant$ vagrant up

各種設定やインストールを自動的に行うので時間がかかるかもしれないです。しばらく待ちましょう。

「vagrant up」が終わったら

vagrant$ vagrant ssh

↑を実行し

[vagrant@localhost ~]$

$マークの前が↑のように切り替わっていればログイン成功です!
ログインが成功したら「provision.sh」に記述したインストールが成功しているか確認してみます。

# Apacheバージョン確認
[vagrant@localhost ~]$ httpd -version

# MySQLバージョン確認
[vagrant@localhost ~]$ mysql --version

#PHPバージョン確認
[vagrant@localhost ~]$ php -v

それぞれのコマンド実行後にバージョン情報が返ってくればインストール成功です。
仮想マシンの環境構築は完了です。

4.既存アプリのクローン

GitHubやGitLabのリモートリポジトリから共有ディレクトリ内にアプリのディレクトリをクローンしてきます。

#共有ディレクトリに移動
[vagrant@localhost ~]$ cd /var/www/html

#共有ディレクトリ内でgitのクローンコマンドを実行
[vagrant@localhost html]$ git clone "クローン用のURL"

クローンが完了したら

[vagrant@localhost html]$ ls

↑で共有ディレクトリ内の中身を確認しアプリ名のディレクトリがあればクローン成功です!
クローンが成功するとホストマシンの共有ディレクトリからもアプリを確認できると思います。
(今回はデスクトップ上から確認できます。)

5.Apacheのhttpd.confの編集

Apacheのconfigファイルの記述を編集します。

#viの起動
[vagrant@localhost ~]$ sudo vi /etc/httpd/conf/httpd.conf

#ドキュメントルートの変更
DocumentRoot "/var/www/html"
↑上記のデフォルト設定から
DocumentRoot "/var/www/html/アプリのディレクトリ名"
に変更

# AllowOverride NoneをAllに変更
<Directory "/var/www/html">
    ...
    AllowOverride None
</Directory>
↓下記に変更
<Directory "/var/www/html">
    ...
    AllowOverride All
</Directory>

編集後、Apadcheを再起動し変更を反映させます。

# Apcheの再起動
[vagrant@localhost ~]$ sudo systemctl restart httpd

これでApacheの設定は完了です。

6. MySQLの設定、アプリとの接続

①MySQLの設定
MySQLにログインし
・新規ユーザーの作成
・作成ユーザーへの権限付与
・アプリと接続するDBの作成
を行います。

#rootユーザーでMySQLに接続
[vagrant@localhost ~]$ mysql -u root

#ユーザーの作成
mysql> create user "ユーザー名"@localhost (identified by "パスワード");
↑パスワードが必要な場合は()内も記述

#mysqlというDBに移動
mysql> use mysql;

#作成したユーザーに全権限を付与
mysql> grant all on *.* to "ユーザー名"@localhost (identified by "パスワード");

ここまで行ったら一度mysqlからログアウトします。

mysql> exit

rootでログアウトしたら作成したユーザーで再度ログインし、アプリ用に使用するDBを作成します。

#作成したユーザーでログイン
[vagrant@localhost ~]$ mysql -u "ユーザー名"

#DBの作成
mysql> create database "DB名";

#DBの確認
mysql> show databases;
↑で作成したDBが表示されていればOK

②アプリとの接続
アプリ内のapp.phpを編集します。

#viを起動しapp.phpを編集
[vagrant@localhost html] /~/app.php

#Datasources内のusername,password,databaseを修正
'Datasources' => [
        'default' => [
            ...            
            'username' => 'mysqlで作成したユーザー名',                  
            'password' => 'mysqlユーザーのパスワード',                  
            'database' => '作成したDB名',                    
            ...

MySQLのユーザー作成時にパスワードを設定しなかった場合は「'password' => ''」とします。

7.本番環境DBのダンプ→ローカルDBへリストア

本番環境のDBをローカル環境に移行するためにMySQLのダンプ、リストアを行います。

#本番環境のMySQLからDBを指定しdumpを実行
[vagrant@localhost ~] mysqldump -u "ユーザー名" -h "ホスト名" -p --database "DB名" > "dumpファイル名"

#dumpしたファイルを指定しローカル環境のDBにリストア(ユーザー、DBは先ほどローカルのMySQLで作成したDB)
[vagrant@localhost ~] mysqldump -u "ユーザー名" -p "DB名" < "dumpファイル名"

#念の為MySQLに接続しリストアできてるか確認
[vagrant@localhost ~]$ mysql -u "ユーザー名"

#リストア先のDBを指定し中身を確認
mysql> use "DB名";
mysql> show tables;
本番環境のDBが反映されていればOK!
8.ブラウザで接続確認

Vagrantfileで設定したIPアドレスにブラウザでアクセスしTOPページが表示されれば成功です!!

最後に

最終的に上手くローカルで動かせるようになるまで様々なエラーが発生し苦しめられました、、、
しかしその度に、エラーの原因を把握し解消するために色々調べ物をするのでその分知識はついたかなと感じています。
スクール受講時にもvagrant環境を作りましたが、その時はテキストに書かれているがまま思考停止でコマンドを打っていたので何が起きているのか全く分からずじまいだったのでこのタイミングでじっくり勉強できたのはいい経験になったなと思います。
自分のような初学者はエラーが発生すると同じようなエラーが発生した記事を参考にコードをパパッとコピペしがちですが、エラーの原因を分からないままにしてしまうと何も身につかず何度も同じエラーで苦しめられる羽目になり時間とエネルギーを無駄にしてしまう恐れがあります、、、
なので「急がば回れ」理論でエラーに向き合い理解した上で1歩1歩進んでいくことが大事なのかなと感じました。

ここまでお読みいただきありがとうございました。

※記述や認識に誤りがあればご指摘いただけると大変助かります!

参考にさせていただいた記事

https://qiita.com/kenta0629/items/574251c140387779b681
https://qiita.com/tatsuo-iriyama/items/e9d63f2eaa901d1e9132
https://akamist.com/blog/archives/648

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

LaravelでRepository Patternを採用した時に手間が発生

なぜしたのか?

  • Repository Patternを実装する際InterfaceとRepositoryのfileを作成する手間が発生しめんどーだと思ったから。

何をしたのか?

  • Laravelでartisan コマンドを作成しInterfaceとRepositoryのfileをコマンドで作成できるようにしました
    • php artisan make:command CommandNameで作成し、実装後にapp/Console/Kernel.phpに追記して使用できるようにします。

備考

  • php artisan make:repository RepositoryNameというコマンドを作成しようと思います
    • 本来ならば実装した方がいいですが今回は、Service Classは書いておらず、またPHPUnitも書いてません
  • 今回は、InterfaceとRepositoryを同じディレクトリに作成します。
  • 参考にしたサイト(ほぼ使わせていただいてます)

完成イメージ

projectName > php artisan make:repository Hoge

new directory name. or use directory name:
> Hoge # 入力
  • 実行結果
app/Repositories/
└── Hoge
    ├── HogeInterface.php
    └── HogeRepository.php

作成したFile

  • 今回1fileで書いています。
<?php
declare(strict_types=1);

namespace App\Console\Commands;

use Illuminate\Console\Command;

/**
 * CreateRepositoryFileCommand class
 */
class CreateRepositoryCommand extends Command
{
    /**
     * @const string repository dir path
     */
    const REPOSITORIES_PATH = 'app/Repositories/';

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'make:repository {repositoryName : The name of repository}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Create repository files';

    /**
     * @var string
     */
    private $fileName;

    /**
     * @var string
     */
    private $dirName;

    /**
     * @var string
     */
    private $repositroyFileName;

    /**
     * @var string
     */
    private $interfaceFileName;

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

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $this->fileName = $this->argument('repositoryName');

        if (is_null($this->fileName)) {
            $this->error('Repository Name invalid');
        }
        $this->dirName = $this->ask('new directory name. or use directory name');

        if (is_null($this->dirName)) {
            $this->error('Directory required!');
        }

        if (!$this->isExistDirectory()) {
            $this->createDirectory();
        }

        $this->repositroyFileName = self::REPOSITORIES_PATH . $this->dirName . '/' . $this->fileName . 'Repository.php';
        $this->interfaceFileName = self::REPOSITORIES_PATH . $this->dirName . '/' . $this->fileName . 'Interface.php';
        if ($this->isExistFiles()) {
            $this->error('already exist');
            return;
        }

        $this->creatRepositoryFile();
        $this->createInterFaceFile();
        $this->info('create successfully');
    }

    /**
     * Repositoryのfileを作成する
     * @return void
     */
    private function creatRepositoryFile(): void
    {
        $content = "<?php\ndeclare(strict_types=1);\n\nnamespace App\\Repositories\\$this->dirName;\n\class $this->fileName" . "Repository implements $this->fileName" . "Interface\n{\n}\n";
        file_put_contents($this->repositroyFileName, $content);
    }

    /**
     * Interfaceのfileを作成する
     * @return void
     */
    private function createInterFaceFile(): void
    {
        $content = "<?php\ndeclare(strict_types=1);\n\nnamespace App\\Repositories\\$this->dirName;\n\ninterface $this->fileName" . "Interface\n{\n}\n";
        file_put_contents($this->interfaceFileName, $content);
    }

    /**
     * 同名fileの確認
     * @return bool
     */
    private function isExistFiles(): bool
    {
        return file_exists($this->repositroyFileName) && file_exists($this->interfaceFileName);
    }

    /**
     * directoryの存在確認
     * @return bool
     */
    private function isExistDirectory(): bool
    {
        return file_exists(self::REPOSITORIES_PATH . $this->dirName);
    }

    /**
     * 指定名でdirectoryの作成
     * @return void
     */
    private function createDirectory(): void
    {
        mkdir(self::REPOSITORIES_PATH . $this->dirName, 0755, true);
    }
}

作成されるfile

  • あとはおすきなように書いてください。
    • ちなみに自分は、RepositoryでEloquent Modelを継承したclassをDIして使用しています。
<?php
declare(strict_types=1);

namespace App\Repositories\Hoge;

interface HogeInterface
{
}

<?php
declare(strict_types=1);

namespace App\Repositories\Hoge;

class HogeRepository implements HogeInterface
{
}

まとめ

  • 自身が設計知識に精通しているわけではないので同じディレクトリで良いのだろうかなど色々悩みましたが、まぁーちゃんとした答えがあるとは、思っていないのでひとまずは、同じディレクトリでいいかなっておもい同じディレクトリにしました

    • 「いやいや待て待て」と思う方はぜひご指摘の方よろしくお願いいたします!
  • 久々にQiitaに投稿しましたがアウトプットは大切だなと思いました。

    • 自分のコードを見直してて1行しかないメソッドもどうかと思いますが。
  • 不備、間違い等ございましたらぜひご指摘いただけたらと思います。

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