- 投稿日:2020-04-09T23:44:25+09:00
Docker で立てた WordPress を検証した後からブラウザで特定ポートへのアクセスができなくなる
問題
- ローカルで WordPress を Docker で構築した
- 使ったイメージは ここ のDocker Official
- ページに記載されている通り
-p 8080:80
のポート割り当てで起動- この時点で初回の検証をする場合は特に問題は起きなかった
- 改めて起動して
http://localhost:8080
にアクセスすると、http://localhost
にリダイレクトされてアクセスできない- WordPressコンテナを落として次の日、WordPress 以外のアプリケーション開発で
http://localhost:8080
にアクセスするとhttp://localhost
の表示となり、8080
にアクセスできていないように見える
- ただし、
/
以外 (http://localhost:8080/login
など ) にアクセスはできる- curl などでは普通に
http://localhost:8080
へはアクセスできるこの問題の原因を探る。
調査結果
- WordPress の
home
およびsiteurl
はコンテナ内部のポートに依存した初期設定が行われるので、http://localhost
で初期データが作成される
- どうも WordPress ではアクセスしてきたドメインと
wp_options.home
に登録されているドメインが違う場合、home
のドメインに 301リダイレクトが発生する……らしい。
- なんでこんな機能があるんだろう…、リバプロとかすごく挟みづらそう…
- そのため、この状態のWordPressが動作している状態で
http://localhost:8080
にアクセスすると、http://localhost
に 301 リダイレクトされる- そして ブラウザでは 301 リダイレクトもキャッシュする
- ので、キャッシュが残っている間は
http://localhost:8080
へのアクセスを行うと、一瞬でリダイレクトされるのでhttp://localhost:8080
に対してアクセスができないように見える解決策
- ブラウザのキャッシュをクリアする
- WordPressが利用するDataBase の
home
およびsiteurl
をhttp://localhost:8080
に書き換える
- ただし、WordPress 内部から home および siteurl を参照して自分自身にアクセスするような場合、
http://localhost:8080
はコンテナ内部で閉じているので動かない- サンプルには
-p 8080:80
と書いてあるが、もう複雑すぎるので-p 80:80
以外で動かさない方がいいんじゃないかな?- もしくは、そもそもローカルで構築せずにグローバルなFQDNを割り当ててそれで外中両方のアクセスを適切に解決できるようにすればよい
参考
というか同様のトラブルにハマった方の記事。
余談
WordPress、システムを管理する側から見るとものすごくハマりどころが多い印象でつらい。
- 投稿日:2020-04-09T22:33:30+09:00
PHP学習記 #4日目
sprintf関数
指定したフォーマットで文字列を生成する。
オブジェクト指向プログラミング
プロパティとは
クラスの中で定義された変数のことである。メンバ変数とも呼ばれる。プロパティとして変数を定義する場合、アクセス修飾子を頭につける必要がある。
コンストラクタ
インスタンス化のタイミングで実行される特別なメソッドである。何らかの戻り値を返す必要がない。
デストラクタとは
コンストラクタとは逆に、オブジェクトが破棄されるタイミングで実行される。何らかの戻り値を返す必要がない。
静的メソッド
静的メソッドとは、インスタンスを生成しなくてもクラスから直接に呼び出せることメソッドのことである。静的メソッドを呼び出すのには、「::」演算子を利用する。
クラス定数とは
classブロックの中で定義された定数のことである。
- 投稿日:2020-04-09T22:30:11+09:00
2020年版 VSCodeの良さげな拡張機能紹介
日々VSCodeをより気持ちよく使用するために拡張機能の探求は欠かせません。
今回は私の独断と偏見で良さげな拡張機能を紹介します。見た目編
Peacock
https://marketplace.visualstudio.com/items?itemName=johnpapa.vscode-peacock
VSCodeのウィンドウをおしゃれにできます。
私は複数の環境(プロジェクトやプログラミング言語)を使い分けるので、ウィンドウごと色を変えることで気持ちも一緒に切り替えています。Ubuntu VSCodeTheme
https://marketplace.visualstudio.com/items?itemName=ThiagoLcioBittencourt.ubuntuvscode
見た目をUbuntuっぽくできます。ただの気分です。
私はMacの壁紙をUbuntuにしています(Ubuntu使えというツッコミは受け付けません)Rainbow CSV
https://marketplace.visualstudio.com/items?itemName=mechatroner.rainbow-csv
CSVを開いたときに色分けしてくれて見やすくなります。
indent-rainbow
https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow
インデントがカラフルになってちょっと見易くなります。
共通機能系
Settings Sync
https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync
複数のPCでVSCodeを使用する場合、各PCでVSCodeの設定を行う必要がありますが、こちらの拡張機能を使えば設定を共有できます!
Vim
https://marketplace.visualstudio.com/items?itemName=vscodevim.vim
VSCodeをVimっぽく使いたい方におすすめ。ただし、コテッコテのVimmerは痒いところに手が届かない可能性あり。
私は普段VimとVSCodeのハイブリットなので重宝しています。GitLens
https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens
Git使うならまず入れた方が良いです。
Git操作をせずにいつ誰が該当のソースを修正したのかがパッと分かります。言語別
ここからは言語別の拡張機能紹介です。
デバッガーやLanguage Supportは書くまでも無いと思うので割愛します。PHP
PHP Intelephense
https://marketplace.visualstudio.com/items?itemName=bmewburn.vscode-intelephense-client
Language Supportは書かないって言ったくせに早速書きました。
PHPは他のLanguage Supportもあるのですが、こちらの拡張機能の方が頭が良い気がしたので紹介します。PHP DocBlocker
https://marketplace.visualstudio.com/items?itemName=neilbrayfield.php-docblocker
PHPDocを自動で作ってくれます。intって書いてもintegerと書かれるお茶目さがあります。
(多分自分で設定すれば修正できますが)PHP Namespace Resolver
https://marketplace.visualstudio.com/items?itemName=MehediDracula.php-namespace-resolver
Classのインポートを自動でやってくれます。(IDEから乗り換えた人はとりあえず入れて見てください。ストレスが減ります)
一括インポートもできるので結構良いです。Ruby
endwise
https://marketplace.visualstudio.com/items?itemName=kaiwood.endwise
自分で
end
って書くの面倒ですよね?
こちらの拡張機能は自動で付与してくれます。ruby-rubocop
https://marketplace.visualstudio.com/items?itemName=misogi.ruby-rubocop
別途Gemの追加が必要ですが、静的チェックとフォーマットをやってくれるので入れておきましょう。
自分の悪いところも容赦無く教えてくれたり、修正してくれるので勉強にもなります。ifじゃなくてunless使いな〜とか、ネスト減らせるよ〜とか、
eachじゃなくてmap使いなーとか言ってくれるのでレビュワーの負担も減ると思います。JavaScript
Prettier
https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode
JS触っている人なら当たり前だと思いますが、自動でコード整形してくれるので便利です。
ただ、保存時に整形する設定を入れると差分がめっちゃ出るリポジトリもあったりすると思うので程々に。Debugger for Chrome
https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome
デバッガーも書かないと言ったくせに書いてしまいました。
JSのデバッグをVSCode上で行えるので便利です。もうconsole.log
デバッグとはおさらば。その他
Remote-SSH
https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh
SSH先のPC上のソースを編集することができます。
私は自宅のUbuntuや、Vagrantに対してSSHして開発する際に使用しています。
ただソースを編集できるだけでなく、ポートフォワードも行えるのでリモート先の8080ポートをローカルの8080にすることもできたりします。
とても便利なのでSSHで開発する方はぜひ使ってみてください。Remote-Container
https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers
Dockerコンテナの中のソースをVSCodeから修正できちゃいます。
もちろんコンテナなのでVolumeマウントしないと修正内容が飛んでしまいますが、開発環境も含めてコンテナ化しちゃうような時は良さげ。昔別記事書いてます。
https://qiita.com/MasanoriIwakura/items/fe1bb1fade98c0aa65d2
https://qiita.com/MasanoriIwakura/items/e7a2045b2de28c76ccd9REST Client
https://marketplace.visualstudio.com/items?itemName=humao.rest-client
なんと、VSCode上からREST APIを試すことができます!
デバッグや外部APIの確認に便利。
まだまだ拡張機能は沢山あるので、気が向いたタイミングで更新していきます!
- 投稿日:2020-04-09T22:03:55+09:00
ブラウザでPHPの処理をすぐ確認したいとき
どういうときに使うか
ブラウザでPHPからの出力(HTMLなど)を確認したいとき
どのようにするか
- 以下をターミナルから打つことで簡易的なウェブサーバを立てることができる。
php -S localhost:8080
- このコマンドの後に出てくる"Listening on"以降がURLとなる。
- 何も指定しなければドキュメントルートはカレントディレクトリとなる。
- -tオプションを使えば明示的にドキュメントルートを指定できる。
php -S localhost:8080 -t /var/www/test参考
https://qiita.com/drafts/7c8d8fad5815f98fc143/edit
https://xn--web-oi9du9bc8tgu2a.com/php-web-server/
- 投稿日:2020-04-09T22:03:55+09:00
PHPのビルトインサーバ
どういうときに使うか
ブラウザでPHPからの出力(HTMLなど)を確認したいとき
どのようにするか
- 以下をターミナルから打つことで簡易的なウェブサーバを立てることができる。
php -S localhost:8080
- このコマンドの後に出てくる"Listening on"以降がURLとなる。
- 何も指定しなければドキュメントルートはカレントディレクトリとなる。
- -tオプションを使えば明示的にドキュメントルートを指定できる。
php -S localhost:8080 -t /var/www/test参考
https://qiita.com/drafts/7c8d8fad5815f98fc143/edit
https://xn--web-oi9du9bc8tgu2a.com/php-web-server/
- 投稿日:2020-04-09T16:08:31+09:00
不正アクセスを防ぐためのパーミッション設定 | EC-CUBEユーザーグループ合同勉強会
今回は文字が多いので Qiita スライドモードでお送りします
自己紹介
- 名前: 大河内健太郎(@nanasess) 年齢: 43才
- 出身: 愛知県西尾市一色町
- 在住: 大阪市(四天王寺の近く)
- 前職:寿司屋の板前
- 資格: 調理師・ふぐ処理師
- EC-CUBE コミッター・公式エバンジェリスト
- 最近のマイブーム: #おうち寿司
EC-CUBE セキュリティチェックリスト のパーミッション設定を、もう少し深堀りします
EC-CUBEにおける不正アクセスの原因の多く
- 見えちゃいけないファイルが見えていた
- 他の CMS や CGI の脆弱性攻撃
- OSコマンドインジェクション
- SQLインジェクション
当社調べ
見えちゃいけないファイルからの攻撃方法
- 見えちゃいけないファイルから、セッション奪取
- 管理画面からテンプレート改竄
- 購入確認画面に攻撃用 JavaScript を混入
- 偽の決済画面 からカード番号奪取
あくまでも推測です
他の CMS や フリーCGI の脆弱性攻撃
- 他の CMS や フリーCGIの脆弱性を利用して、 書き込み可能なディレクトリに 攻撃用ファイルを書き込む
- 攻撃用ファイルからテンプレート改竄
- 購入確認画面に攻撃用 JavaScript を混入
- 偽の決済画面 からカード番号奪取
あくまでも推測です
OSコマンドインジェクション
- OSコマンドインジェクションを利用して、 書き込み可能なディレクトリに 攻撃用ファイルを書き込む
- 攻撃用ファイルからテンプレート改竄
- 購入確認画面に攻撃用 JavaScript を混入
- 偽の決済画面 からカード番号奪取
あくまでも推測です
SQLインジェクション
- SQLインジェクションを利用して、データベースに保存されている情報を盗む
数年前から多く悪用されており、カスタマイズ時には注意が必要。判例あり
phpMyAdmin や phpPgAdmin を同居させないのも重要
ファイル改竄の直接原因
- Webサーバーのユーザー権限でファイルを書き込まれた
- テンプレートを改竄された
ファイル改竄を防ぐには
- Webサーバーのユーザー権限で、テンプレートを変更させないこと
- Webサーバーのユーザー権限で、書き込める範囲を最小限にすること
Webサーバーのユーザー権限で、テンプレートを変更させないために
- デザイン管理画面は閉じる
- テンプレートの変更は、 FTP/SSH ユーザー権限で行う
- テンプレートのパーミッションは 604(環境によって変わります)
多くの共有レンタルサーバーでは FTP/SSH ユーザー権限で Webサーバーが動作しているため、対策できない
Webサーバーのユーザー権限で、書き込める範囲を最小限にするには
Webサーバーの権限で書き込める箇所は、以下に限定する
- 画像フォルダ(html/upload/save_image)
- キャッシュフォルダ(4系: var, 3系: app/cache, 2系: data/cache, data/Smarty/templates_c)
プラグインのインストール等、管理画面機能の一部は動作しなくなるが、安全性を高めるためには利便性を削るしかない
CMS 機能は、 WordPress や Concrete5 などの他の優秀な CMS に任せた方が安全
他に注意すべきこと
- PHPはデフォルトの設定でファイルやディレクトリを生成した時点では、すべてのユーザーが書き込める状態なので注意(ファイル:666, ディレクトリ:777 になってしまう)
- 定期的にパーミッションをチェックし、変更してあげましょう
## 666 のファイルを検索 find . -type f -perm 666 ## 604 に変更 find . -type f -perm 666 -print0 | xargs -0 chmod 604 ## 777 のディレクトリを検索 find . -type d -perm 777 ## 705 に変更 find . -type d -perm 777 -print0 | xargs -0 chmod 705
そのほか
- .htaccess を改竄されるケースもある
- 画像ファイルに偽装したバックドアを設置されるケースもある
- .env も見られないように注意
- Nginx など .htaccess の効かない環境は注意
- WordPress の安全性を高める記事は、とても参考になります
まとめ
- 見えちゃいけないファイルは確実に隠そう
- Webサーバーの書き込み権限は最小限に
- 利便性と安全性はトレードオフ。管理画面の機能を限定することも選択肢に
ご静聴ありがとうございました!
2020-04-10追記
管理画面からのデザイン管理を外す方法について
ちなみに、 WordPress は FTP 権限でファイルを更新可能な CMS なので、EC-CUBEより堅牢な実装になっています。
EC-CUBE も、 FTP 権限でデザイン管理画面を更新できるようになれば、もっと安心して使えるようになります。2系
html/<管理画面ディレクトリ>/design
以下を削除するdata/Smarty/templates/admin/main_frame.tpl
から デザイン管理 のメニューを削除する3系
src/Eccube/ControllerProvider/AdminControllerProvider.php
の137行目付近から149行目付近までをコメントアウトdiff --git a/src/Eccube/ControllerProvider/AdminControllerProvider.php b/src/Eccube/ControllerProvider/AdminControllerProvider.php index b706b6be8..a77adff0a 100644 --- a/src/Eccube/ControllerProvider/AdminControllerProvider.php +++ b/src/Eccube/ControllerProvider/AdminControllerProvider.php @@ -134,19 +134,19 @@ class AdminControllerProvider implements ControllerProviderInterface $c->match('/content/file_download', '\Eccube\Controller\Admin\Content\FileController::download')->bind('admin_content_file_download'); $c->delete('/content/file_delete', '\Eccube\Controller\Admin\Content\FileController::delete')->bind('admin_content_file_delete'); - $c->match('/content/layout', '\Eccube\Controller\Admin\Content\LayoutController::index')->bind('admin_content_layout'); - $c->match('/content/layout/{id}/edit', '\Eccube\Controller\Admin\Content\LayoutController::index')->assert('id', '\d+')->bind('admin_content_layout_edit'); - $c->match('/content/layout/{id}/preview', '\Eccube\Controller\Admin\Content\LayoutController::preview')->assert('id', '\d+')->bind('admin_content_layout_preview'); - - $c->match('/content/block', '\Eccube\Controller\Admin\Content\BlockController::index')->bind('admin_content_block'); - $c->match('/content/block/new', '\Eccube\Controller\Admin\Content\BlockController::edit')->bind('admin_content_block_new'); - $c->match('/content/block/{id}/edit', '\Eccube\Controller\Admin\Content\BlockController::edit')->assert('id', '\d+')->bind('admin_content_block_edit'); - $c->delete('/content/block/{id}/delete', '\Eccube\Controller\Admin\Content\BlockController::delete')->assert('id', '\d+')->bind('admin_content_block_delete'); - - $c->match('/content/page', '\Eccube\Controller\Admin\Content\PageController::index')->bind('admin_content_page'); - $c->match('/content/page/new', '\Eccube\Controller\Admin\Content\PageController::edit')->bind('admin_content_page_new'); - $c->match('/content/page/{id}/edit', '\Eccube\Controller\Admin\Content\PageController::edit')->assert('id', '\d+')->bind('admin_content_page_edit'); - $c->delete('/content/page/{id}/delete', '\Eccube\Controller\Admin\Content\PageController::delete')->assert('id', '\d+')->bind('admin_content_page_delete'); + // $c->match('/content/layout', '\Eccube\Controller\Admin\Content\LayoutController::index')->bind('admin_content_layout'); + // $c->match('/content/layout/{id}/edit', '\Eccube\Controller\Admin\Content\LayoutController::index')->assert('id', '\d+')->bind('admin_content_layout_edit'); + // $c->match('/content/layout/{id}/preview', '\Eccube\Controller\Admin\Content\LayoutController::preview')->assert('id', '\d+')->bind('admin_content_layout_preview'); + + // $c->match('/content/block', '\Eccube\Controller\Admin\Content\BlockController::index')->bind('admin_content_block'); + // $c->match('/content/block/new', '\Eccube\Controller\Admin\Content\BlockController::edit')->bind('admin_content_block_new'); + // $c->match('/content/block/{id}/edit', '\Eccube\Controller\Admin\Content\BlockController::edit')->assert('id', '\d+')->bind('admin_content_block_edit'); + // $c->delete('/content/block/{id}/delete', '\Eccube\Controller\Admin\Content\BlockController::delete')->assert('id', '\d+')->bind('admin_content_block_delete'); + + // $c->match('/content/page', '\Eccube\Controller\Admin\Content\PageController::index')->bind('admin_content_page'); + // $c->match('/content/page/new', '\Eccube\Controller\Admin\Content\PageController::edit')->bind('admin_content_page_new'); + // $c->match('/content/page/{id}/edit', '\Eccube\Controller\Admin\Content\PageController::edit')->assert('id', '\d+')->bind('admin_content_page_edit'); + // $c->delete('/content/page/{id}/delete', '\Eccube\Controller\Admin\Content\PageController::delete')->assert('id', '\d+')->bind('admin_content_page_delete'); $c->match('/content/cache', '\Eccube\Controller\Admin\Content\CacheController::index')->bind('admin_content_cache');
src/Eccube/Resource/config/nav.yml.dist
の58行目付近から63行目付近までをコメントアウト
app/config/eccube/nav.yml
が存在する方は、 同様に58行目付近から63行目付近までをコメントアウトdiff --git a/src/Eccube/Resource/config/nav.yml.dist b/src/Eccube/Resource/config/nav.yml.dist index 32662a2a1..a1b5b29ba 100644 --- a/src/Eccube/Resource/config/nav.yml.dist +++ b/src/Eccube/Resource/config/nav.yml.dist @@ -55,12 +55,12 @@ - id: file name: ファイル管理 url: admin_content_file - - id: page - name: ページ管理 - url: admin_content_page - - id: block - name: ブロック管理 - url: admin_content_block + # - id: page + # name: ページ管理 + # url: admin_content_page + # - id: block + # name: ブロック管理 + # url: admin_content_block - id: cache name: キャッシュ管理 url: admin_content_cache4系
app/config/eccube/packages/eccube_nav.yaml
の61行目付近から66行目付近と、73行目付近から75行目付近をコメントアウトdiff --git a/app/config/eccube/packages/eccube_nav.yaml b/app/config/eccube/packages/eccube_nav.yaml index 5abb0b706f..d99603c01a 100644 --- a/app/config/eccube/packages/eccube_nav.yaml +++ b/app/config/eccube/packages/eccube_nav.yaml @@ -58,21 +58,21 @@ parameters: file: name: admin.content.file_management url: admin_content_file - layout: - name: admin.content.layout_management - url: admin_content_layout - page: - name: admin.content.page_management - url: admin_content_page + # layout: + # name: admin.content.layout_management + # url: admin_content_layout + # page: + # name: admin.content.page_management + # url: admin_content_page css: name: admin.content.css_management url: admin_content_css js: name: admin.content.js_management url: admin_content_js - block: - name: admin.content.block_management - url: admin_content_block + # block: + # name: admin.content.block_management + # url: admin_content_block cache: name: admin.content.cache_management url: admin_content_cache
- 以下の Controller の
@Route
を//@Route
に変更
src/Eccube/Controller/Admin/Content/BlockController.php
src/Eccube/Controller/Admin/Content/LayoutController.php
-
src/Eccube/Controller/Admin/Content/PageController.php
diff --git a/src/Eccube/Controller/Admin/Content/BlockController.php b/src/Eccube/Controller/Admin/Content/BlockController.php index ce78ae3a65..d5a0501536 100644 --- a/src/Eccube/Controller/Admin/Content/BlockController.php +++ b/src/Eccube/Controller/Admin/Content/BlockController.php @@ -51,7 +51,7 @@ class BlockController extends AbstractController } /** - * @Route("/%eccube_admin_route%/content/block", name="admin_content_block") + * //@Route("/%eccube_admin_route%/content/block", name="admin_content_block") * @Template("@admin/Content/block.twig") */ public function index(Request $request) @@ -77,8 +77,8 @@ class BlockController extends AbstractController } /** - * @Route("/%eccube_admin_route%/content/block/new", name="admin_content_block_new") - * @Route("/%eccube_admin_route%/content/block/{id}/edit", requirements={"id" = "\d+"}, name="admin_content_block_edit") + * //@Route("/%eccube_admin_route%/content/block/new", name="admin_content_block_new") + * //@Route("/%eccube_admin_route%/content/block/{id}/edit", requirements={"id" = "\d+"}, name="admin_content_block_edit") * @Template("@admin/Content/block_edit.twig") */ public function edit(Request $request, $id = null, Environment $twig, FileSystem $fs, CacheUtil $cacheUtil) @@ -180,7 +180,7 @@ class BlockController extends AbstractController } /** - * @Route("/%eccube_admin_route%/content/block/{id}/delete", requirements={"id" = "\d+"}, name="admin_content_block_delete", methods={"DELETE"}) + * //@Route("/%eccube_admin_route%/content/block/{id}/delete", requirements={"id" = "\d+"}, name="admin_content_block_delete", methods={"DELETE"}) */ public function delete(Request $request, Block $Block, Filesystem $fs, CacheUtil $cacheUtil) { diff --git a/src/Eccube/Controller/Admin/Content/LayoutController.php b/src/Eccube/Controller/Admin/Content/LayoutController.php index eddbb86f12..5b6c764096 100644 --- a/src/Eccube/Controller/Admin/Content/LayoutController.php +++ b/src/Eccube/Controller/Admin/Content/LayoutController.php @@ -100,7 +100,7 @@ class LayoutController extends AbstractController } /** - * @Route("/%eccube_admin_route%/content/layout", name="admin_content_layout") + * //@Route("/%eccube_admin_route%/content/layout", name="admin_content_layout") * @Template("@admin/Content/layout_list.twig") */ public function index() @@ -119,7 +119,7 @@ class LayoutController extends AbstractController } /** - * @Route("/%eccube_admin_route%/content/layout/{id}/delete", requirements={"id" = "\d+"}, name="admin_content_layout_delete", methods={"DELETE"}) + * //@Route("/%eccube_admin_route%/content/layout/{id}/delete", requirements={"id" = "\d+"}, name="admin_content_layout_delete", methods={"DELETE"}) * * @param Layout $Layout * @@ -148,8 +148,8 @@ class LayoutController extends AbstractController } /** - * @Route("/%eccube_admin_route%/content/layout/new", name="admin_content_layout_new") - * @Route("/%eccube_admin_route%/content/layout/{id}/edit", requirements={"id" = "\d+"}, name="admin_content_layout_edit") + * //@Route("/%eccube_admin_route%/content/layout/new", name="admin_content_layout_new") + * //@Route("/%eccube_admin_route%/content/layout/{id}/edit", requirements={"id" = "\d+"}, name="admin_content_layout_edit") * @Template("@admin/Content/layout.twig") */ public function edit(Request $request, $id = null, $previewPageId = null, CacheUtil $cacheUtil) @@ -236,7 +236,7 @@ class LayoutController extends AbstractController } /** - * @Route("/%eccube_admin_route%/content/layout/view_block", name="admin_content_layout_view_block", methods={"GET"}) + * //@Route("/%eccube_admin_route%/content/layout/view_block", name="admin_content_layout_view_block", methods={"GET"}) * * @param Request $request * @param Twig $twig @@ -272,7 +272,7 @@ class LayoutController extends AbstractController } /** - * @Route("/%eccube_admin_route%/content/layout/{id}/preview", requirements={"id" = "\d+"}, name="admin_content_layout_preview") + * //@Route("/%eccube_admin_route%/content/layout/{id}/preview", requirements={"id" = "\d+"}, name="admin_content_layout_preview") */ public function preview(Request $request, $id, CacheUtil $cacheUtil) { diff --git a/src/Eccube/Controller/Admin/Content/PageController.php b/src/Eccube/Controller/Admin/Content/PageController.php index 13bf8cfe0f..2d8d0e8a07 100644 --- a/src/Eccube/Controller/Admin/Content/PageController.php +++ b/src/Eccube/Controller/Admin/Content/PageController.php @@ -65,7 +65,7 @@ class PageController extends AbstractController } /** - * @Route("/%eccube_admin_route%/content/page", name="admin_content_page") + * //@Route("/%eccube_admin_route%/content/page", name="admin_content_page") * @Template("@admin/Content/page.twig") */ public function index(Request $request) @@ -86,8 +86,8 @@ class PageController extends AbstractController } /** - * @Route("/%eccube_admin_route%/content/page/new", name="admin_content_page_new") - * @Route("/%eccube_admin_route%/content/page/{id}/edit", requirements={"id" = "\d+"}, name="admin_content_page_edit") + * //@Route("/%eccube_admin_route%/content/page/new", name="admin_content_page_new") + * //@Route("/%eccube_admin_route%/content/page/{id}/edit", requirements={"id" = "\d+"}, name="admin_content_page_edit") * @Template("@admin/Content/page_edit.twig") */ public function edit(Request $request, $id = null, Environment $twig, RouterInterface $router, CacheUtil $cacheUtil) @@ -250,7 +250,7 @@ class PageController extends AbstractController } /** - * @Route("/%eccube_admin_route%/content/page/{id}/delete", requirements={"id" = "\d+"}, name="admin_content_page_delete", methods={"DELETE"}) + * //@Route("/%eccube_admin_route%/content/page/{id}/delete", requirements={"id" = "\d+"}, name="admin_content_page_delete", methods={"DELETE"}) */ public function delete(Request $request, $id = null, CacheUtil $cacheUtil) {
- 投稿日:2020-04-09T14:41:22+09:00
PHP組み込みのDateTimeクラスの定数を使えば日時フォーマットを頑張って書かなくて良い
PHPの場合はDateTimeクラスに定数が定義されているので、それを使うとdateフォーマット表現が簡単でした。
Laravel の Request Validation にも使えます。ref: https://www.php.net/manual/ja/class.datetime.php
例えば
2020-04-08T00:00:00+09:00
みたいなフォーマットを表現したいとき、
DateTime::RFC3339
で表現できます。
この定数の中にはY-m-d\TH:i:sP
が入っています。ここで最後のPが何を意味するかという情報はPHPのdate関数の項目にまとまっています。
ref: https://www.php.net/manual/ja/function.date.php一部抜粋。
O グリニッジ標準時 (GMT) との時差。時間と分の間にコロンは入りません。 例: +0200 P グリニッジ標準時 (GMT) との時差。時間と分をコロンで区切った形式 (PHP 5.1.3 で追加)。 例: +02:00 T タイムゾーンの略称 例: EST, MDT ...
- 投稿日:2020-04-09T12:13:34+09:00
array_spliceで多次元配列に配列を追加する
array_spliceで多次元配列の中に配列を追加したい
親配列 $hoge = [ ['id' => 1, 'name' => 'はげ'], ['id' => 2, 'name' => 'ひげ'] ]; 追加配列 $add = ['id' => 3, 'name' => 'ほげ'];直で追加配列を指定してみる。
array_splice($hoge, 1, 0, $add); 結果: [ ['id' => 1, 'name' => 'はげ'], 'id' => 3, 'name' => 'ほげ', ['id' => 2, 'name' => 'ひげ'] ]ぶっ壊れた(・ω・`
なので一度配列で入れ子にしてあげる。
array_splice($hoge, 1, 0, [$add]); 結果: [ ['id' => 1, 'name' => 'はげ'], ['id' => 3, 'name' => 'ほげ'], ['id' => 2, 'name' => 'ひげ'] ]おっお(^ω^
- 投稿日:2020-04-09T11:44:09+09:00
PHP 検索・置換系の引数の順番まとめ
\$needleと\$haystackどっちが先だったっけ?
といつも記憶喪失悩まされるのでメモ
関数 第1引数 第2引数 第3引数 第4引数 第5引数 strpos $haystack $needle $offset substr_count $haystack $needle $offset $length str_replace $search $replace $subject $count preg_match $pattern $subject $matches $flags $offset preg_replace $pattern $replace $subject $limit $count preg_replace_callback $pattern $callback $subject $limit $count array_search $needle $haystack $strict array_filter $array $callback $flag
- 投稿日:2020-04-09T11:00:34+09:00
Laravel触って1年経ったので過去の戒め(ソースコード)を改善してみた
Laravelのリファクタ記事にしようと思ったが、ただただ間違ったコードを直すだけの記事でした。
久々に過去練習用として作成したサイトのソースコードを覗いたら無駄な処理書いてたり、
Laravelの機能活かせれてなかったりそもそもPHP使えてなかったりと散々だったので、
いい反面教師コードだと思って改善記事(改善というか修正レベル)書いてみました。目に付いた部分しか改善しないので、一貫性はありませんし、
他の方が絶対やらないような事も多々ありますが、戒めとしてどうか生温かい目で見守ってください。環境
Laravel5.7
PHP7.1注意
改善とはいえ、これがベストとは思ってません。
あくまで出来る時間で簡単な改善(修正)を行っただけです。
その辺り、ご容赦くださいm(._.)m関係ないところは一部省略します。
例外処理等も省略します。フォームリクエストの謎の使い方
FormRequest便利ですよね。
Controllerにバリデーションを書かずに済むので良く使っています。
(他にもControllerで受け取る前の前加工とか)さて過去のソースコードを覗いてみましょう
過去コード
CreateController.phpuse App\Http\Requests\Validation; public function store(Validation $request) { //Validation Requestからルールを取得 $rules = $request->rules(); //Validation Requestからエラーメッセージを取得 $messages = $request->messages(); $data = Validator::make($request->all(), $rules, $messages); }フォームリクエストから受け取ってる時点でバリデーション処理は済んでるはずなので、色々と不要ですね。
それとValidationというクラス名だと分かりづらいので、クラス名も変更します。
改善コード
CreateController.phpuse App\Http\Requests\ProjectRequest; public function store(ProjectRequest $request) { $data = $request->all(); }ProjectRequestと命名した理由は案件登録で使用するのが一つと作成と更新で使用するのであえて
CreateProjectRequest
としませんでした。改善ポイント
- 無駄な記述を削除して本来の使い方を実装
- クラス名の役割が抽象的すぎたので、少し具体的にして明確化出来た?
fillable便利だよ
fillableもありがたいですよね〜
デフォルトで存在するUser.php見ると最初から存在するコイツですねUser.phpprotected $fillable = [ 'name', 'email', 'password', ];何が便利なのか、まずは悪い方の過去のコードを見てみましょう。
過去コード
CreateController.phpuse App\Http\Requests\ProjectRequest; public function store(ProjectRequest $request) { $project = new Project; $project->name = $request->name; $project->responsible_id = $request->responsible; $project->category_id = $request->category; $project->description = $request->description; $project->url = $request->url; $project->release_year_at = $request->release_year; $project->release_month_at = $request->release_month; $project->image_id = $image_id; $project->start_year_at = $request->start_year; $project->start_month_at = $request->start_month; $project->end_year_at = $request->end_year; $project->end_month_at = $request->end_month; $project->save(); }うーん行が無駄に多いのと保存処理のたびにこれを書くのはめんどくさいですね。
では改善コード
fillableも勿論活用しますが、そもそも保存処理をControllerでやるのはMVCとしてよろしくないのでModelに責務を分けましょう。
改善コード
ちなみに引数にモデル(というかクラス名)をタイプヒントするとLaravelがインスタンスを用意してくれます。
CreateController.phpuse App\Http\Requests\ProjectRequest; use App\Project; public function store(ProjectRequest $request, Project $project) { $results = $project->storeProject($request->all()); }ではModel
Project.phpprotected $fillable = [ 'responsible_id', 'category_id', 'image_id', 'name', 'url', 'description', 'release_year_at', 'release_month_at', 'start_year_at', 'start_month_at', 'end_year_at', 'end_month_at', ]; public function storeProject(array $data) { return $this->create($data); }保存の部分が1行で済みました!
fillable
というのは保存するときのホワイトリストなんですね〜
勿論更新の時にも適用されます!逆にブラックリストのguardedもあります
[Laravel 5.7] Eloquent Modelのfillableとguardedの違いProject.phppublic function storeProject(array $data, int $id) { return $this->where('id', $id)->update($data); }改善ポイント
- 入力内容が増えるたびに書き足す必要がなくなった
- MVCで責務をちゃんと分けた
- コード行短縮
resourceの恩恵を得ていない
Controllerを作成する時に良くみますね〜
説明は別記事に託します。Laravelのリソースコントローラを理解して使ってみよう!
ではルーティングをみてみましょう。
web.phpRoute::get('project/', 'ProjectsController@index'); Route::get('project/create', 'CreatesController@index'); Route::post('project/create', 'CreatesController@store'); Route::get('project/edit', 'CreatesController@edit'); Route::post('vupdate', 'CreatesController@update'); Route::get('project/delete', 'CreatesController@delete');突っ込みどころは多いですけど一旦スルー
改善コード
web.phpRoute::prefix('project')->name('project.')->group(function () { Route::resource('/', ProjectsController, ['except' => 'show']); });改善ポイント
- Projectに関連した物しかなく、restfullで完結できそうだったので、ProjectsControllerファイルにまとめました(これはたまたまなので、無理矢理真似なくてOK)
- groupにまとめて無駄な記述が減らせたのと関連したルーティングが見易くなった。
- Routeメソッドをresourceに変える事でメソッド毎に定義しなくて済んだ(showは使わないのでexceptで除外していますが本来はonly派)
ちょこっと番外編(LaravelというかPHP)
検索機能を付けていたのだが、過去のコードを見てみましょう。
過去コード
ProjectsControllerpublic function index(Request $request) { $query = Project::query(); if (isset($request)) { $category_id = $request->get('category_id'); $responsible_id = $request->get('responsible_id'); $tag_ids = $request->get('tag_id'); $release_year = $request->get('release_year'); $release_month = $request->get('release_month'); $start_year = $request->get('start_year'); $start_month = $request->get('start_month'); $end_year = $request->get('end_year'); $end_month = $request->get('end_month'); //カテゴリ if (!empty($category_id)) { $query->where('category_id', 'like', '%' .$category_id .'%'); } //ユーザー if (!empty($responsible_id)) { $query->where('responsible_id', 'like', '%' .$responsible_id .'%'); } //リリース年 if (!empty($release_year)) { $query->where('release_year_at', 'like', '%' .$release_year .'%'); } //リリース月 if (!empty($release_month)) { $query->where('release_month_at', 'like', '%' .$release_month .'%'); } //開発開始年 if (!empty($start_year)) { $query->where('start_year_at', 'like', '%' .$start_year .'%'); } //開発開始月 if (!empty($start_month)) { $query->where('start_month_at', 'like', '%' .$start_month .'%'); } //開発終了年 if (!empty($end_year)) { $query->where('end_year_at', 'like', '%' .$end_year .'%'); } //開発終了月 if (!empty($end_month)) { $query->where('end_month_at', 'like', '%' .$end_month .'%'); } } }なげーーーー
しかも検索条件増えるたびに書き足さないといけない、、
という事で今回は複雑な検索条件は無かったので短縮化ProjectsControllerpublic function index(Request $request, Project $project) { $query = $project->searchProject($request); }Modelに記述
Project.phppublic function searchProject(Request $request) { $query = $this->query(); if ($request->query() !== '') { foreach ($request->all() as $key => $val) { !empty($val) ? $query->where($key, 'LIKE', '%' .$val .'%') : ''; } } return $query; }これで検索条件が増えても安心ですね^^(簡単な条件に限るけど)
改善ポイント
- コード行短縮
- 条件が増えるたびに書き足す必要がない
Bladeのoldヘルパー使えてる?
良く編集画面とかで動的に変わる選択ボックスとか見かけますよね??(この辺割と記事ない印象)
そういう時入力値を優先させて、old()がなければDBの値を反映して一致した時にselected
とかif文でゴニョゴニョしまくってませんか?勿論過去の僕はしてます。
しかも型を厳密にチェックしてません。
悪い子です。
過去コード
edit.blade.php<select name="category_id" class="form-control"> @foreach ($categories as $category) <option value="{{ $category->id }}" @if(!empty(old('category'))) @if(old('category') == $category->id) selected @endif @elseif($project->category_id == $category->id) selected @endif >{{ $category->name }}</option> @endforeach </select>上のコードもold()の第二引数を使用すればここまでスッキリかけます!
(ちょっと横に長いけど、改行してもよし)
改善コード
edit.blade.php<select name="category_id" class="form-control"> @foreach ($categories as $category) <option value="{{ $category->id }}" @if ($category->id === (int) old('category_id', $project->category_id)) selected @endif>{{ $category->name }}</option> @endforeach </select>ちなみにold()はstringで返ってくるのでintに変換してます。
改善ポイント
- 無駄なif文を省いて見易くなった
終わり
誰もこんなクソコードを量産して欲しく無かったので戒めとして書きました。
皆さんも昔のソースコード久々に覗いてみては?
乾いた笑いが出ると思います。
- 投稿日:2020-04-09T09:32:39+09:00
?【CakePHP2】js.mapファイルが存在しないエラーの解消法
環境
PHP 7.2.21
CakePHP 2.10.18やりたいこと
pnotifyを追加したところ、下記の様なJsControllerが無いエラーが多数吐かれていたが動作に問題はなかった
が、このまま放置は良くないので出ないように修正したいerror.log2020-03-04 10:10:58 Error: [MissingControllerException] Controller class JsController could not be found. Exception Attributes: array ( 'class' => 'JsController', 'plugin' => NULL, ) Request URL: /js/vendor/jquery-pnotify/pnotify.js.map Stack Trace: #0 /***/***/***/webroot/index.php(100): Dispatcher->dispatch(Object(CakeRequest), Object(CakeResponse)) #1 {main}やったこと
pnotify.custom.min.js/* PNotify 3.2.0 sciactive.com/pnotify/ (C) 2015 Hunter Perrin; Google, Inc. license Apache-2.0 */ !function(t,i) *******省略******* {"feturn s(i)}); //# sourceMappingURL=pnotify.js.map ←これを削除もしくはmapファイルを追加で対応可能ここからmapファイルをダウンロードし同階層に格納
https://cdnjs.com/libraries/pnotifyもしくは最下部にあるmapファイルのリンクを削除
pnotify.custom.min.js//# sourceMappingURL=pnotify.js.map
- 投稿日:2020-04-09T01:13:23+09:00
fzf.vimでtagsを検索しながら色付きのpreviewを表示する
PHPでせめて定義元ぐらいは辿りたいんだけど、Language Serverが使えない、phpcdも使えない、けれど絶対Vim使うってときに、ctagsを使うことにした。他のプラグインとかで何とかなるかもしれないけど、何とかなるって情報が見つけられなかった。
仕方なくctagsでタグを作ってfzf.vimでpreviewを表示させながら選びたい。
どういうことか
こういうファイルがあって、test2()を辿りたい。
caller.php<?php require_once './functions.php'; test2();functions.php<?php function test1() { echo __FUNCTION__; } function test2() { echo __FUNCTION__; } function test3() { echo __FUNCTION__; }どうするか
ひとまずctagsでtagsファイルを作っておく。
$ ls caller.php functions.php $ ctags -R # 作る $ ls caller.php functions.php tags # tagsができあがる $ cat tags # tagsの中身 !_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ !_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ !_TAG_PROGRAM_NAME Exuberant Ctags // !_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ !_TAG_PROGRAM_VERSION 5.8 // test1 functions.php /^function test1()$/;" f test2 functions.php /^function test2()$/;" f test3 functions.php /^function test3()$/;" f設定
fzf.vimはpreviewを外部から受け取れる。今回はshellScriptを一つ作って、previewに渡す。
/path/to/ctags_preview.sh#!/usr/bin/env zsh NAME=$1 FILE=$2 #タブに囲まれた3つめの検索パターンの抽出 #/^ any $/;" を ^ any $ に置換 PATTERN=$(echo $3 | cut -f 3 | sed "s/^\///" | sed -E "s/\/;\".*$//" | sed "s/\"/\\\\\"/g") # 前5行、後5行を表示、-48でgrepしてるのは検索文字列に色をつけるため grep -B 5 -A 42 --color=never "${PATTERN}" $FILE | grep -48 --color=always $NAMEで、~/.vimrcに以下を書き込む。
~/.vimrcか他のconfigcommand! -bang Tags \ call fzf#vim#tags(expand('<cword>'), { \ 'options': '+i \ --exact \ --with-nth 1 \ --reverse \ --no-unicode \ --preview "/path/to/ctags_preview.sh {1} {2} {}" \ ' \ }) nnoremap <silent> <Leader>ft :<C-u>Tags<CR>こうなる
caller.phpのtest2の上で、ftを押すと、下記のようなプレビューが表示される。(floating windowにしてある)
まぁ……全然完全ではないんだけど……。
- 投稿日:2020-04-09T00:49:13+09:00
Laravel の Policy ってどんな場合に使うの?
特定のリソースに対するユーザーアクションを認可
する仕組みだそうです。
例えば、ブログの記事削除は本人にしかできないようにすることが可能になる仕組みのことです。Policyを使わないで書くと以下のようになり、
public function delete(Article $article) { if (request()->article()->isNot($article->user)) { return response([], 403); } $article->delete(); }
ArticlePolicy
を作成すると、ArticlePlicy.phppublic function delete(User $user, Article $article) { return $user->id == $article->user_id; }以下のように書ける。
public function delete(Article $article) { $this->authorize('delete', $article); $article->delete(); }また、ミドルウェアによる認可もできる。以下のように書ける。
api.phpRoute::delete('/articles/{article}', 'ArticlesController@destroy')->middleware('can:delete,article');今の所、アカウントの種類によって認可するアクションを切り分けたいときに使う認識でいます。