- 投稿日:2020-11-28T21:05:42+09:00
MAMPのPHPのexec()からpython3を簡単実行。
MAMPのpythonはversion2なので、ずっとこの壁にぶつかってたんですが、
$command = "python test.py"; exec($command, $output, $return_var);python→python3でできました。意外と簡単でした。
$command = "python3 test.py"; exec($command, $output, $return_var);
- 投稿日:2020-11-28T20:53:02+09:00
DockerでPHP開発をしている際に、vscodeでの実装変更が反映されない。
環境
macOS
DockerでPHPを使用解決方法
順序1
Docker コンテナの停止・削除 $docker-compose down順序2
Docker コンテナの起動 $docker-compose up -dこれだけでした汗
発生状況&原因
発生状況
vscodeでいつものようにPHPの勉強をしていた際に、vscodeで新たな実装変更を行いました。ターミナルで動作確認すると実装変更が反映されない状況になってしまいました。
このような状況に、、、汗
ss@saaaMPro src % docker-compose exec app php book_log.php Could not open input file: book_log.phpなので原因を探るため
ターミナルでのディレクトリの位置が間違っていないか?
ファイル名が間違っていないか?
エラー内容が、入力ファイルが開けないと言っている、、、、なぜ、、(泣)原因
ここでは、server-sideディレクトリのpart2の中のディレクトリで作業を行っていました。
一旦、ファイルの中を確認!
ここで気になったのは、codeディレクトリの中に違う階層ではあるものの、同じpart2のディレクトリがあり、原因はここではないのか?と何の根拠もないのに自分の中で原因を発見できたと思ってしまいました。汗
記憶をたどると、作業前にFiderを開き、code/part2の中のファイルを直接コピーし、server-side/part2のファイルにペーストし、作業に取り掛かっていました。
その間、Dockerコンテナは最初から作動中だったので、移動前の状況のままになります(恐らく、、、)
なので、コピーしたファイルを移動し変更しても、Dockerコンテナの中は以前のままで反映さていないので、最初の項目(解決方法)を実行し、最新の状態にしてから、作業を行ったところ無事変更を行えました。
前提知識の不足や認識の間違いなど、ご指摘やアドバイスなどいただけましたら凄く有り難いので
お願いします!!!
- 投稿日:2020-11-28T20:30:48+09:00
ログイン機能例
<?php try { $post=sanitize($_POST); $staff_code=$post['code']; $staff_pass=$post['pass']; $staff_pass= md5($staff_pass); $dsn = 'mysql:dbname=hoge;host=localhost;charset=utf8'; $user='root'; $password=''; $dbh = new PDO($dsn, $user, $password); $dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); $sql = 'SELECT name FROM mst_staff WHERE code=? AND password=?'; $stmt = $dbh->prepare($sql); $data[]=$staff_code; $data[]=$staff_pass; $stmt->execute($data); $dbh =null; $rec = $stmt->fetch(PDO::FETCH_ASSOC); if($rec==false) { print 'スタッフコードかパスワードが間違っています。<br/>'; print '<a href="staff_login.html">戻る</a>'; } else { // $recがtrueであればログイン成功です session_start(); $_SESSION['login']=1; $_SESSION['staff_code']=$staff_code; $_SESSION['staff_name']=$rec['name']; header('Location: staff_top.php'); exit(); } } catch(Exception $e) { print 'ただいま障害により大変ご迷惑をお掛けしております。'; exit(); } ?>
- 投稿日:2020-11-28T19:26:15+09:00
curlの"-u"オプションで引き渡される認証情報をヘッダーに直接設定したい
先日プロダクトのアップデートを管理しているJenkinsサーバに対して新たにAPIを送るよう実装する機会があり、その際にインフラチームから共有いただいたAPIの呼び出し方法が下記のようなものでした。
curl -k -X GET "https://hogehoge.jp/job ?token=${api_job_token}" -u ${api_user_name}:${api_user_token}"-u"オプションって?
Specify the user name and password to use for server authentication. Overrides -n, --netrc and --netrc-optional.
If you simply specify the user name, curl will prompt for a password.参照:https://curl.se/docs/manpage.html#-u
curl先のサーバーで行われる認証に対し、ユーザ名とパスワードを引き渡しているオプションが
-u
オプションになります。"curl"経由じゃなくて直接ヘッダーに認証情報を設定したい。。。
今回のケースでは
curl
からではなくて、ヘッダーなどのリクエスト内容を直接規定する方法でJenkinsAPIへリクエストを送る必要がありました。下記のようにすることで、-u
オプションを利用して設定されるBasic認証情報をヘッダに設定することができます。(利用言語はPHP7.3)private static function createHttpRequestForJenkins(): HttpRequest { // Basic認証情報を設定 $encoded_user_info = base64_encode('user_name:password'); $request_header = [ 'Content-type' => 'application/json', 'Authorization' => "Basic $encoded_user_info", ]; ...... }Basic認証では引き渡すユーザ名とパスワードはbase64形式でエンコードされる必要があるため、
base64_encode
を使って認証情報を設定します。
エンコード済みの認証情報をヘッダーのAuthorization
要素として指定をすることで、リクエスト先サーバにBasic認証情報を送信することができます。その際、エンコードされた情報はBasic+半角空白
を接頭辞として持つ必要があります。
参照:https://ja.wikipedia.org/wiki/Basic%E8%AA%8D%E8%A8%BC上記のままでもリクエストを送る上では問題ないのですが、
createHttpRequestForJenkins
ではリクエストを送ることだけ知っていて欲しかったので、最終的には下記のようにして実装を行いました(メソッドの実装内容は割愛します)。private static function createHttpRequestForJenkins(): HttpRequest { $request_header = ApiRequestHeader::createContentTypeApplicationJsonHeader() // basic認証情報を設定 ->withBasicAuth('user_name', 'password'); ...... }まとめ
curl -u
はシンプルに認証情報をヘッダーに設定できる便利なオプションですが、いざ自分で同様の情報をヘッダーに設定する際に"?"となってしまったのでまとめてみました。どなたかのお役に立てば幸いです。
- 投稿日:2020-11-28T19:08:00+09:00
VScodeでPHPを書こうとすると右下に表示されるエラーを解消したい
環境
OS
- Windous10 Home x64
VScode
- Version 1.51.1
表示されたエラーメッセージ
【 phpcs: Request workspace/configuration failed with message: Unable to locate phpcs. Please add phpcs to your global path or use composer dependency manager to install it in your project locally. 】
ざっくりした意味
「phpcs」を見つけることができなくて、ワークスペースの構成ができていないよ!
phpcsを自力でインストールするか、「Composer」を利用してインストールしてください。解決するためにやったこと
Composer をインストールする
➤Composerインストール先コマンドプロンプトを起動して以下の呪文を入力する
composer global require squizlabs/php_codesniffer3.VScodeを再起動する
結果
ちゃんとエラーが消えました。
参考サイト
- 投稿日:2020-11-28T17:44:05+09:00
最近Webサイトに来た不審なアクセス(攻撃)のまとめ
グローバルIPアドレスを持つWebサーバーで自分のサイトを運営していますが、脆弱性を狙ったと思われる不審なアクセスが日常的に来ます。一度はまとめてみたい…と思っていたのですが、同じことをされている方の記事を見つけ、自分も同様の内容をまとめてみました。
不審なアクセスは種類を挙げればきりがありませんが、今回は主だったもの(件数が多いもの)について紹介したいと思います。最後には対策を挙げました。
ちなみに、数を数える時は、ログを一旦DBに入れSQLで集約して数えています。
環境
以下の通り。
- VPS (仮想環境のLinuxサーバー)
- WordPress
一応、WAF (Web Application Firewall)も導入したり、色々しています。
ちなみに、今回は11月の1か月分を対象に解析しています。WordPressに対する(と思われる)もの
日頃からログを見ていても、WordPressを狙ったと思われるアクセス試行が最も多いように感じます。
プラグインが多いせいもありますが、JVN iPediaでも脆弱性の登録数は結構な数のようです。
簡単に導入できて便利ですが、プラグインに脆弱性があると入り口を増やしてしまいかねないのと、導入数が多いので狙われやすいようです。
以下、実際に自サイトに来た不正アクセス試行のログです。
ログインページの存在確認
言わずと知られたWordPressのログインページのURLですが、存在しているかを調査しに来ているようです。
GET [url]/wp-login.php POST [url]/wp-login.php
404
(存在しないページへのアクセス)を記録しているアクセスの中では一番多いのが上の二つです。
wp-login.phpを探しにくるアクセスは、月に250件ほどあります。対策としては、ログインページのURL変更は基本だと思います。特定のIPアドレス(いわゆる踏み台)からのみアクセスを許可する方法も有効です。
プラグインを狙ったもの
WordPressのプラグインであるFile Managerを狙っているようです。readme.txtを取得しているのは、インストールしているかを確認するためでしょう。
GET /wp-content/plugins/wp-file-manager/readme.txtFileManagerについては、最近、深刻な脆弱性として報告されていたと思います。
WordPress 用プラグイン File Manager の脆弱性について(JPCERT CC)
xmlrpc.phpにたいするもの
この、xmlrpc.phpに対するPOSTは月に400件ほど来るリクエストで、正直、うんざりするほど見ます。
POST /xmlrpc.php POST /blog/xmlrpc.php POST /xmlrpc.phpWordPressのセキュリティ対策としてxmlrpc.phpへのアクセスを抑止するのはよく知られたことだとは思いますが、WordPress以外でもxmlrpc.phpを置いているものもあるようです。
ちなみに、↑のPOSTリクエストからは様々なパラメータでアクセスされてきますが、例を挙げると下の通りです。この
die(@md5(文字列))
は結構目にします。Magento=die(@md5(Apri1))MagentoはPHPで実装されたECプラットフォームのようです。
特定製品を狙った攻撃
NETGEAR製品の脆弱性を狙ったものです。
GET /currentsetting.htmNETGEAR 製の複数製品にバッファオーバーフローの脆弱性 (JVN)
↓はDasan製(韓国企業)ルーターの脆弱性を狙ったもの。かなり以前から頻繁に見ます。
POST /GponForm/diag_Form?images/Dasan GPON home router における認証に関する脆弱性 (JVN iPedia)
PHP絡み
PHPUnitの脆弱性を狙ったもの
これも月に40件程のアクセスがありました。
vendor
はcomposerで使用するものですが、Laravelを使用しているサイトでも注意する必要がありそうです。POST /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.phpこのアクセスからは、下のようなパラメータが送られてきていました。
<?php echo 'RCE_VULN|'; echo php_uname();?>PHPUnitには、任意のコードが実行される脆弱性があるようです。
JVN iPedia - PHPUnit の Util/PHP/eval-stdin.php における任意の PHP コードを実行される脆弱性
Xdebugへのアクセス
XdebugはPHPのデバッグ用のツールで、PHPStormはPHP用のIDE。
まぁ、インストールはしていないので404を返しているわけですが、不正な試行であることに変わりないです。GET /?XDEBUG_SESSION_START=phpstorm権限の設定漏れを突いてくるもの
.env
これも
404
で残ってました。GET /.envどうも、node.jsで使用される環境設定用のファイルらしいですが、アクセスが多かったです。
他
Linuxでは、"."で開始するファイルは隠しファイル(もしくはディレクトリ)なわけですが、そこを読み取ろうとしてくるアクセス試行は他にもありました。具体的には、以下。
GET /.wp-config.php.swp GET /.local GET /.gitignore GET /.production GET /.meta GET /.remote GET /.DS_Store GET /.well-known/security.txt GET /.vscode/sftp.json GET /.addressbook GET /.proclog GET /.dockerignoreその他
ログインページを探してくるアクセス
これもログインページを探す試行でしょうか。
HEAD /admindede/login.php HEAD /manage/login.php HEAD /admin/login.php HEAD /manager/login.php HEAD /dede/login.php HEAD /htadmin/login.phpちなみに、HEADメソッドはGETと違って本文を返しません。
存在の確認をしているのでしょう。同一IPからの大量リクエスト
こんな感じで瞬間的に大量アクセスを仕掛けられることも頻繁にあります(日時はアクセス日時)。
2020-11-02 07:54:57 GET /myadmin/scripts/db___.init.php 2020-11-02 07:54:58 GET /MyAdmin/scripts/db___.init.php 2020-11-02 07:54:58 GET /plugins/weathermap/editor.php 2020-11-02 07:54:59 GET /cacti/plugins/weathermap/editor.php 2020-11-02 07:54:59 GET /weathermap/editor.php 2020-11-02 07:55:01 GET /App/?content=die(md5(HelloThinkPHP)) 2020-11-02 07:55:01 GET /index.php/module/action/param1/${@die(md5(HelloThinkPHP))} 2020-11-02 07:55:01 GET /index.php?s=/module/action/param1/${@die(md5(HelloThinkPHP))} 2020-11-02 07:55:01 GET /?a=fetch&content=<php>die(@md5(HelloThinkCMF))</php> 2020-11-02 07:55:03 GET /joomla/ (中略) 2020-11-02 07:55:42 POST /my.php 2020-11-02 07:55:42 POST /qq.php 2020-11-02 07:55:46 POST /kpl.php 2020-11-02 07:55:46 POST /hgx.php 2020-11-02 07:55:46 POST /ppl.php 2020-11-02 07:55:46 POST /tty.php (以下略)実は以前、自サイト(WordPress)がダウンする事件がありました。
それがこの一連の大量アクセスで、該当のアクセス元IP(中国だった)は上のような大量アクセスをしてxmlrpc.phpまで来たところで、xmlrpc.phpに対して膨大なPOSTリクエストを送り付け、DBが死んだ…という。この辺りの対策は、「WordPress xmlrpc.php」でググると出てきます。
プラグイン(Site Guard WP Pluginとか)でも対処できますし、fail2banとか、WAFを導入して対処することも可能だと思います。しておくべき対策
自分なりに実施していることですが、
脆弱性情報は常に確認
IPA(情報処理推進機構)は脆弱性に関する情報を集約・発信しています。RSSでも取れるので、そこで重要な情報は拾えそうです。
また、JVN iPediaは脆弱性に関する情報をデータベースにして公開しています。
twitterアカウントをお持ちの方であれば、JVNやIPAのセキュリティ関連の最新ニュースは、以下のアカウントをフォローすれば自動的に目に飛び込んできます。
OS・ソフトウェアのアップデートは確認して怠らずにやる
更新があればWordPressのダッシュボードに通知されますし、SIte Guard WP Pluginを入れれば更新の通知をメールにも入れてくれます。
加えて、OS、Webサーバー、PHPの更新もきちんとやっておいたほうが良さそうです。
とは言いつつも、いきなり本番環境に適用なんて普通はせず、検証後の適用が普通と思います。なので、そう早急にはできないかもしれません。ですが、WAFの導入などで多層的な防御を可能にすることもできます。
上でも挙げましたが、ファイルに対するアクセス権限の設定も確認しておく必要がありますね。
以上です。
- 投稿日:2020-11-28T17:44:05+09:00
Webサイトに来る実際の攻撃(不審なアクセス)を実例付きで紹介してみる
グローバルIPアドレスを持つWebサーバーで自分のサイトを運営していますが、脆弱性を狙ったと思われる不審なアクセスが日常的に来ます。一度はまとめてみたい…と思っていたのですが、同じことをされている方の記事を見つけ、自分も同様の内容をまとめてみました。
不審なアクセスは種類を挙げればきりがありませんが、今回は主だったもの(件数が多いもの)について紹介したいと思います。最後には対策を挙げました。
ちなみに、数を数える時は、ログを一旦DBに入れSQLで集約して数えています。
環境
以下の通り。
- VPS (仮想環境のLinuxサーバー)
- WordPress
一応、WAF (Web Application Firewall)も導入したり、色々しています。
ちなみに、今回は11月の1か月分を対象に解析しています。WordPressに対する(と思われる)もの
日頃からログを見ていても、WordPressを狙ったと思われるアクセス試行が最も多いように感じます。
プラグインが多いせいもありますが、JVN iPediaでも脆弱性の登録数は結構な数のようです。
簡単に導入できて便利ですが、プラグインに脆弱性があると入り口を増やしてしまいかねないのと、導入数が多いので狙われやすいようです。
以下、実際に自サイトに来た不正アクセス試行のログです。
ログインページの存在確認
言わずと知られたWordPressのログインページのURLですが、存在しているかを調査しに来ているようです。
GET [url]/wp-login.php POST [url]/wp-login.php
404
(存在しないページへのアクセス)を記録しているアクセスの中では一番多いのが上の二つです。
wp-login.phpを探しにくるアクセスは、月に250件ほどあります。対策としては、ログインページのURL変更は基本だと思います。特定のIPアドレス(いわゆる踏み台)からのみアクセスを許可する方法も有効です。
プラグインを狙ったもの
WordPressのプラグインであるFile Managerを狙っているようです。readme.txtを取得しているのは、インストールしているかを確認するためでしょう。
GET /wp-content/plugins/wp-file-manager/readme.txtFileManagerについては、最近、深刻な脆弱性として報告されていたと思います。
WordPress 用プラグイン File Manager の脆弱性について(JPCERT CC)
xmlrpc.phpにたいするもの
この、xmlrpc.phpに対するPOSTは月に400件ほど来るリクエストで、正直、うんざりするほど見ます。
POST /xmlrpc.php POST /blog/xmlrpc.php POST /xmlrpc.phpWordPressのセキュリティ対策としてxmlrpc.phpへのアクセスを抑止するのはよく知られたことだとは思いますが、WordPress以外でもxmlrpc.phpを置いているものもあるようです。
ちなみに、↑のPOSTリクエストからは様々なパラメータでアクセスされてきますが、例を挙げると下の通りです。この
die(@md5(文字列))
は結構目にします。Magento=die(@md5(Apri1))MagentoはPHPで実装されたECプラットフォームのようです。
特定製品を狙った攻撃
NETGEAR製品の脆弱性を狙ったものです。
GET /currentsetting.htmNETGEAR 製の複数製品にバッファオーバーフローの脆弱性 (JVN)
↓はDasan製(韓国企業)ルーターの脆弱性を狙ったもの。かなり以前から頻繁に見ます。
POST /GponForm/diag_Form?images/Dasan GPON home router における認証に関する脆弱性 (JVN iPedia)
PHP絡み
PHPUnitの脆弱性を狙ったもの
これも月に40件程のアクセスがありました。
vendor
はcomposerで使用するものですが、Laravelを使用しているサイトでも注意する必要がありそうです。POST /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.phpこのアクセスからは、下のようなパラメータが送られてきていました。
<?php echo 'RCE_VULN|'; echo php_uname();?>PHPUnitには、任意のコードが実行される脆弱性があるようです。
JVN iPedia - PHPUnit の Util/PHP/eval-stdin.php における任意の PHP コードを実行される脆弱性
Xdebugへのアクセス
XdebugはPHPのデバッグ用のツールで、PHPStormはPHP用のIDE。
まぁ、インストールはしていないので404を返しているわけですが、不正な試行であることに変わりないです。GET /?XDEBUG_SESSION_START=phpstorm権限の設定漏れを突いてくるもの
.env
これも
404
で残ってました。GET /.envどうも、node.jsで使用される環境設定用のファイルらしいですが、アクセスが多かったです。
他
Linuxでは、"."で開始するファイルは隠しファイル(もしくはディレクトリ)なわけですが、そこを読み取ろうとしてくるアクセス試行は他にもありました。具体的には、以下。
GET /.wp-config.php.swp GET /.local GET /.gitignore GET /.production GET /.meta GET /.remote GET /.DS_Store GET /.well-known/security.txt GET /.vscode/sftp.json GET /.addressbook GET /.proclog GET /.dockerignoreその他
ログインページを探してくるアクセス
これもログインページを探す試行でしょうか。
HEAD /admindede/login.php HEAD /manage/login.php HEAD /admin/login.php HEAD /manager/login.php HEAD /dede/login.php HEAD /htadmin/login.phpちなみに、HEADメソッドはGETと違って本文を返しません。
存在の確認をしているのでしょう。同一IPからの大量リクエスト
こんな感じで瞬間的に大量アクセスを仕掛けられることも頻繁にあります(日時はアクセス日時)。
2020-11-02 07:54:57 GET /myadmin/scripts/db___.init.php 2020-11-02 07:54:58 GET /MyAdmin/scripts/db___.init.php 2020-11-02 07:54:58 GET /plugins/weathermap/editor.php 2020-11-02 07:54:59 GET /cacti/plugins/weathermap/editor.php 2020-11-02 07:54:59 GET /weathermap/editor.php 2020-11-02 07:55:01 GET /App/?content=die(md5(HelloThinkPHP)) 2020-11-02 07:55:01 GET /index.php/module/action/param1/${@die(md5(HelloThinkPHP))} 2020-11-02 07:55:01 GET /index.php?s=/module/action/param1/${@die(md5(HelloThinkPHP))} 2020-11-02 07:55:01 GET /?a=fetch&content=<php>die(@md5(HelloThinkCMF))</php> 2020-11-02 07:55:03 GET /joomla/ (中略) 2020-11-02 07:55:42 POST /my.php 2020-11-02 07:55:42 POST /qq.php 2020-11-02 07:55:46 POST /kpl.php 2020-11-02 07:55:46 POST /hgx.php 2020-11-02 07:55:46 POST /ppl.php 2020-11-02 07:55:46 POST /tty.php (以下略)実は以前、自サイト(WordPress)がダウンする事件がありました。
それがこの一連の大量アクセスで、該当のアクセス元IP(中国だった)は上のような大量アクセスをしてxmlrpc.phpまで来たところで、xmlrpc.phpに対して膨大なPOSTリクエストを送り付け、DBが死んだ…という。この辺りの対策は、「WordPress xmlrpc.php」でググると出てきます。
プラグイン(Site Guard WP Pluginとか)でも対処できますし、fail2banとか、WAFを導入して対処することも可能だと思います。しておくべき対策
自分なりに実施していることですが、
脆弱性情報は常に確認
IPA(情報処理推進機構)は脆弱性に関する情報を集約・発信しています。RSSでも取れるので、そこで重要な情報は拾えそうです。
また、JVN iPediaは脆弱性に関する情報をデータベースにして公開しています。
twitterアカウントをお持ちの方であれば、JVNやIPAのセキュリティ関連の最新ニュースは、以下のアカウントをフォローすれば自動的に目に飛び込んできます。
OS・ソフトウェアのアップデートは確認して怠らずにやる
更新があればWordPressのダッシュボードに通知されますし、SIte Guard WP Pluginを入れれば更新の通知をメールにも入れてくれます。
加えて、OS、Webサーバー、PHPの更新もきちんとやっておいたほうが良さそうです。
とは言いつつも、いきなり本番環境に適用なんて普通はせず、検証後の適用が普通と思います。なので、そう早急にはできないかもしれません。ですが、WAFの導入などで多層的な防御を可能にすることもできます。
上でも挙げましたが、ファイルに対するアクセス権限の設定も確認しておく必要がありますね。
以上です。
- 投稿日:2020-11-28T17:44:05+09:00
Webサイトに来る実際の攻撃(不審なアクセス)を公開してみる
グローバルIPアドレスを持つWebサーバーで自分のサイトを運営していますが、脆弱性を狙った不審なアクセスが毎日来ます。一度内容まとめたいと考えていたのですが、同様のことをされている方の記事を見つけ、自分もしてみました。
実際に来た不正アクセス試行は種類を挙げればきりがありませんが、件数が多いものを紹介したいと思います。有効な対策だと思われることについても言及しています。
ちなみに解析の方法は、ログを一旦DBに入れてSQLで集約しています。
インターネットにWebサーバーを公開すると、こんな攻撃が来る…という参考になればと思います。と考えると、はてなブログやレンタルサーバーはプロバイダーが責任を持ってくれるから安心ではありますね。
環境
- VPS (Virtual Private Server: 仮想環境のLinuxサーバー)
- WordPress
一応、WAF (Web Application Firewall)も導入したり、色々しています(詳細は伏せます)。分析ですが、今回は11月の直近の分のみを対象に解析しています。
WordPressに対する(と思われる)攻撃
日頃からログ・通知を見ていても、WordPressを標的にしたと思われるアクセス試行が最も多く感じます。
公開されているWordPressの脆弱性については、プラグインが多いせいもありますが、JVN iPediaでも結構な数が登録されています。
WPは導入が容易かつ機能拡張も楽にできるので便利ですが、プラグインに脆弱性があると不正アクセスの入り口を増やしてしまいますし、世界的にも導入数が多いこともあってターゲットになりやすいようです。
以下、実際に自サイトに来た不正アクセス試行のログです。
ログインページの存在確認
言わずと知られたWordPressのログインページ(wp-login.php)ですが、それがアクセス可能かを調査しに来ているようです。
GET [url]/wp-login.php POST [url]/wp-login.php
404
(存在しないページへのアクセス)を記録しているアクセスの中では一番多いのが上の二つです。wp-login.phpを探しにくるアクセスは、実は月に250件ほどあります。対策としては、ログインページのURL変更が可能で、これは基本と思います。また、アクセス元を特定のIPアドレスのみに制限する方法も有効です(いわゆる踏み台の利用)。
プラグインの脆弱性を狙った攻撃
WordPressのプラグインであるFile Managerを狙ったもの。readme.txtを取得しているのは、インストールしているかを確認するためでしょう。
GET /wp-content/plugins/wp-file-manager/readme.txtFileManagerについては、最近、深刻な脆弱性として報告されていました。
WordPress 用プラグイン File Manager の脆弱性について(JPCERT CC)
上でも書きましたが、WordPress本体に脆弱性がなくても、プラグインの脆弱性を突くことで攻撃ができてしまいます。WPは便利な反面、リスクも少なくありません。
xmlrpc.phpにたいする攻撃
この、xmlrpc.phpに対するPOSTは月に400件ほど来るリクエストで、正直、うんざりするほど見ます。
POST /xmlrpc.php POST /blog/xmlrpc.php POST /xmlrpc.phpxmlrpc.phpへのアクセス抑止はググれば結構な数のサイトで解説されています。
ちなみに、上のようなPOSTリクエストでは様々なパラメータ付きでアクセスがあります。例を挙げると下の通りです。この
die(@md5(文字列))
は結構目にします。Magento=die(@md5(Apri1))MagentoはPHPで実装されたECプラットフォームのようです。WP以外にも同一名称のファイル名を使用したパッケージがあるようです。
特定製品を狙った攻撃
NETGEAR製品の脆弱性を狙ったものです。
GET /currentsetting.htmNETGEAR 製の複数製品にバッファオーバーフローの脆弱性 (JVN)
↓はDasan製(韓国企業)ルーターの脆弱性を狙ったもの。かなり以前から頻繁に見ます。
POST /GponForm/diag_Form?images/Dasan GPON home router における認証に関する脆弱性 (JVN iPedia)
この辺りの情報は、JVN iPediaにもありますし、IPAのセキュリティに関するニュースを確認していれば自動的に目に飛び込んでくると思います。
PHP絡み
PHPUnitの脆弱性を狙った攻撃
これも月に40件程のアクセスがありました。
vendor
はcomposerで使用するものですが、Laravelを使用しているサイトでも注意が必要そうです。POST /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.phpこのアクセスからは、下のようなパラメータが送られてきていました。
<?php echo 'RCE_VULN|'; echo php_uname();?>PHPUnitには、任意のコードが実行される脆弱性があるようですので、そこを突いた攻撃でしょう。サーバーの情報を確認するコマンドを送っているようです。
JVN iPedia - PHPUnit の Util/PHP/eval-stdin.php における任意の PHP コードを実行される脆弱性
Xdebugへのアクセス
XdebugはPHPのデバッグ用のツールで、PHPStormはPHP用のIDE。
まぁ、インストールはしていないので404
を返しているわけですが、不正な試行であることに変わりありません。GET /?XDEBUG_SESSION_START=phpstorm権限の設定漏れを突いてくる攻撃
.env
これもHTTPステータス
404
を返したログとして残ってました。GET /.envどうも、node.jsで使用される環境設定用のファイルらしいですが、アクセスが多かったです。
他
Linuxでは、"."で開始するファイルは隠しファイル(もしくはディレクトリ)なわけですが、そこを読み取ろうとしてくるアクセス試行は他にもありました。具体的には、以下。
GET /.wp-config.php.swp GET /.local GET /.gitignore GET /.production GET /.meta GET /.remote GET /.DS_Store GET /.well-known/security.txt GET /.vscode/sftp.json GET /.addressbook GET /.proclog GET /.dockerignoreインストールや更新の後はディレクトリの中身が丸見えになっていないかや、アクセス権限の確認をきちんとしておく必要があります。
その他
ログインページの探索試行
下もログインページを探す試行でしょう。
HEAD /admindede/login.php HEAD /manage/login.php HEAD /admin/login.php HEAD /manager/login.php HEAD /dede/login.php HEAD /htadmin/login.phpちなみに、HEADメソッドはGETと違って本文を返しませんので、ファイルの存在の確認をしていると考えられます。
同一IPからの大量リクエスト
下の感じで短時間に大量アクセスを仕掛けられることも頻繁にあります(日時はアクセス日時)。
2020-11-02 07:54:57 GET /myadmin/scripts/db___.init.php 2020-11-02 07:54:58 GET /MyAdmin/scripts/db___.init.php 2020-11-02 07:54:58 GET /plugins/weathermap/editor.php 2020-11-02 07:54:59 GET /cacti/plugins/weathermap/editor.php 2020-11-02 07:54:59 GET /weathermap/editor.php 2020-11-02 07:55:01 GET /App/?content=die(md5(HelloThinkPHP)) 2020-11-02 07:55:01 GET /index.php/module/action/param1/${@die(md5(HelloThinkPHP))} 2020-11-02 07:55:01 GET /index.php?s=/module/action/param1/${@die(md5(HelloThinkPHP))} 2020-11-02 07:55:01 GET /?a=fetch&content=<php>die(@md5(HelloThinkCMF))</php> 2020-11-02 07:55:03 GET /joomla/ (中略) 2020-11-02 07:55:42 POST /my.php 2020-11-02 07:55:42 POST /qq.php 2020-11-02 07:55:46 POST /kpl.php 2020-11-02 07:55:46 POST /hgx.php 2020-11-02 07:55:46 POST /ppl.php 2020-11-02 07:55:46 POST /tty.php (以下略)実は以前、自サイト(WordPress)がダウンする事件がありました。それが上の一連の大量アクセスで、該当のアクセス元(中国だった)は大量のリクエストを送付してxmlrpc.phpまで来たところで、xmlrpc.phpに対し膨大なPOSTリクエストを送り付け、DBが死んだ…ことがありました。
対策については、「
WordPress xmlrpc.php
」でググると出てきます。プラグイン(Site Guard WP Pluginとか)でも対処できますし、fail2banとか、WAFの導入も有効です(fail2banもWAFもわりとメモリを消費しますが)。有効な対策
自分なりに実施していることです。
脆弱性情報は常に確認
IPA(情報処理推進機構)は脆弱性に関する情報を集約・発信しています。RSSも公開されているので、そこで重要な情報は拾えます。
また、JVN iPediaは脆弱性に関する情報をデータベース化し、公開しています。
また、twitterアカウントをお持ちであれば、JVNやIPAのセキュリティ関連の最新ニュースは、以下のアカウントをフォローすれば自動的に流れてきます(これが結構時短になるので、おすすめです)。
OS・ソフトウェアのアップデートは確認・怠らずに実施する
プラグインや本体の更新通知についてはWordPressのダッシュボードに通知されるはずですし、SIte Guard WP Pluginを使えば更新の通知をメールにも入れてくれます(他にも色々な対策が使用可能です)。
加えて、OS、Webサーバー、PHPの更新も可能な限り、きちんと実施したほうが良さそうです。
とは言いつつ、いきなり本番環境に適用は普通しませんし、検証後に適用するのが普通だと思います。ですので、そう早急にはできないかもしれません。この辺りは、WAFを導入することで多層的な防御を施すことも有効な施策になります。
ちなみに、yumでインストールしたWebサーバー(Apache HTTP Serverとか)のバージョンは、
httpd -v
で確認すると古いバージョンが見えますが、バックポート(古いバージョンのソフトウェアを更新すること)が施されているようなので、むやみにOSS版(ソースからコンパイルするやつ)にする必要はないかもしれません。でも、RHEL版とCentOS版は同様のバックポートが施されているんですかね? 試しにApacheのバグフィックスに関してRHELのサイトとCentOSのRPMのChangelogを見たりしてみましたが、CentOS版にも施されているようには…見えましたが。詳しい方がいらっしゃれば、むしろ、この辺りは教えいて頂きたいです。
また、上でも挙げましたが、ファイルに対するアクセス権限の設定にも注意を払う必要がありますね。
以上です。
- 投稿日:2020-11-28T16:46:59+09:00
牛丼で分かるオブジェクト指向
はじめに
今年もアドベントカレンダーはじまりました!
この記事はHamee Advent Calendar 2020の1日目の記事です。
Hameeのエンジニアが自分の興味あるテーマについて自由に書いていきます。
毎年一緒に参加して盛り上げてくれる皆さんに感謝です
今年で6年目の参加となりました!オブジェクト指向とは
僕の解釈ではデータを扱いやすいオブジェクト単位に設計し、それらを組み合わせることで効率よく開発をしていく指向のことだと思っています。
ただまぁ人によって解釈が違うし新卒や初心者にとっては「???」となることが多い考え方だと思います。
そこで、牛丼を例にオブジェクト指向を紐解いていこうと思います。なぜ牛丼?
Hameeは小田原にある会社です。
小田原には狭いエリアに牛丼チェーンが3つもあります。
この松屋・すき家・吉野家は日々Hamee社員の胃袋を支えています。
私も利用者の1人ですが、この3店舗のレシートの出方を見て今回の記事を書こうと思いつきました。これがその問題のレシート
左から松屋・すき家・吉野家
松屋「たっぷりネギたま牛めし」
すき家「牛丼弁当・ねぎ玉TP」
吉野家「牛丼・ねぎ玉子」松屋は1品なのに対して、すき家と吉野家は2品でレシートが切られています。
ここにオブジェクト指向の違いがあります。
松屋は非オブジェクト指向、すき家と吉野家はオブジェクト指向です。どういうことかclassで説明
Matsuya.phpclass Matsuya { public static function order($order){ $menu = [ 'Gyudon' => new Gyudon(), 'NegiTamaGyudon' => new NegiTamaGyudon(), ]; return $menu[$order]; } } class Gyudon{} class NegiTamaGyudon{} Matsuya::order('NegiTamaGyudon');Sukiya.php<?php class Sukiya { public static function order($order){ $menu = [ 'Gyudon' => new Gyudon(), 'NegiTamaGyudon' => [new Gyudon(), new NegiTama()], ]; return $menu[$order]; } } class Gyudon{} class NegiTama{} Sukiya::order('NegiTamaGyudon');以降吉野家はすき家と同様なので略
違いが分かりますか?
このままだと「え、こんなの作りの好みじゃないの?」って言われそうなので、ここから新メニュー開発した場合を想定しましょう。
エンジニア的に言うと「仕様変更」です。新メニュー「キムチ牛丼」
Matsuya.php<?php class Matsuya { public static function order($order){ $menu = [ 'Gyudon' => new Gyudon(), 'NegiTamaGyudon' => new NegiTamaGyudon(), 'KimchiGyudon' => new KimchiGyudon(), ]; return $menu[$order]; } } class Gyudon{} class NegiTamaGyudon{} class KimchiGyudon{} Matsuya::order('KimchiGyudon');Sukiya.php<?php class Sukiya { public static function order($order){ $menu = [ 'Gyudon' => new Gyudon(), 'NegiTamaGyudon' => [new Gyudon(), new NegiTama()], 'KimchiGyudon' => [new Gyudon(), new Kimchi()], ]; return $menu[$order]; } } class Gyudon{} class NegiTama{} class Kimchi{} Sukiya::order('KimchiGyudon');まだ違いが分からない?
じゃあ次の新メニューはどうでしょう。新メニュー「ネギ玉キムチ牛丼」
Matsuya.php<?php class Matsuya { public static function order($order){ $menu = [ 'Gyudon' => new Gyudon(), 'NegiTamaGyudon' => new NegiTamaGyudon(), 'KimchiGyudon' => new KimchiGyudon(), 'NegitamaKimchiGyudon' => new NegitamaKimchiGyudon(), ]; return $menu[$order]; } } class Gyudon{} class NegiTamaGyudon{} class KimchiGyudon{} class NegitamaKimchiGyudon{} Matsuya::order('NegitamaKimchiGyudon');Sukiya.php<?php class Sukiya { public static function order($order){ $menu = [ 'Gyudon' => new Gyudon(), 'NegiTamaGyudon' => [new Gyudon(), new NegiTama()], 'KimchiGyudon' => [new Gyudon(), new Kimchi()], 'NegitamaKimchiGyudon' => [new Gyudon(), new NegiTama(), new Kimchi()], ]; return $menu[$order]; } } class Gyudon{} class NegiTama{} class Kimchi{} Sukiya::order('NegitamaKimchiGyudon');ここで大きく異なるのはすき家の方は新しくクラス定義を追加していません。
既存のクラス(オブジェクト)の組み合わせで簡単に新メニューが作成できます。
それに対して松屋はどんな新メニューができても必ずクラス(オブジェクト)を追加する必要があります。
新メニュー開発はどちらが楽でしょう?
とどめにこんな新メニューはどうでしょうか。「豚丼」追加、もちろん全トッピング可
Matsuya.php<?php class Matsuya { public static function order($order){ $menu = [ 'Gyudon' => new Gyudon(), 'NegiTamaGyudon' => new NegiTamaGyudon(), 'KimchiGyudon' => new KimchiGyudon(), 'NegitamaKimchiGyudon' => new NegitamaKimchiGyudon(), 'Butadon' => new Butadon(), 'NegiTamaButadon' => new NegiTamaButadon(), 'KimchiButadon' => new KimchiButadon(), 'NegitamaKimchiButadon' => new NegitamaKimchiButadon(), ]; return $menu[$order]; } } class Gyudon{} class NegiTamaGyudon{} class KimchiGyudon{} class NegitamaKimchiGyudon{} class Butadon{} class NegiTamaButadon{} class KimchiButadon{} class NegitamaKimchiButadon{} Matsuya::order('NegitamaKimchiButadon');Sukiya.php<?php class Sukiya { public static function order($order){ $menu = [ 'Gyudon' => new Gyudon(), 'Butadon' => new Butadon(), 'NegiTamaGyudon' => [new Gyudon(), new NegiTama()], 'KimchiGyudon' => [new Gyudon(), new Kimchi()], 'NegitamaKimchiGyudon' => [new Gyudon(), new NegiTama(), new Kimchi()], 'NegiTamaButadon' => [new Butadon(), new NegiTama()], 'KimchiButadon' => [new Butadon(), new Kimchi()], 'NegitamaKimchiButadon' => [new Butadon(), new NegiTama(), new Kimchi()], ]; return $menu[$order]; } } class Gyudon{} class Butadon{} class NegiTama{} class Kimchi{} Sukiya::order('NegitamaKimchiButadon');松屋はメニュー分のクラスが増えましたがすき家は豚丼クラスを追加しただけです。
これがオブジェクト指向です。
オブジェクトを使い回せる点が非常に強いです。
このあと鶏丼や羊丼が来ても簡単に対応できます。ちなみに小話ですが、すき家と吉野家には豚丼がありますが、松屋にはありません。
まとめ
結構無理やり話をまとめたので異論はあると思いますがどうか温かい目で見ていただけるとw
少しでもオブジェクト指向の理解の助けになれば幸いです。おわりに
アドカレ6年目です。
毎年この時期になると「あぁもうそんな時期か、1年って早いなぁ」と実感します。
この後もHameeのアドカレをお楽しみに!ちなみにどのお店の牛丼もそれぞれ違った美味しさがあって、全部大変美味しかったです!
(撮影後はスタッフが美味しくいただきました。)
- 投稿日:2020-11-28T15:35:45+09:00
【PHP】ユーザー定義関数を初心者に説明してみる
初心者のみなさん、
関数
使ってますか?
普通に使ってるってツッコミありがとうございます笑公式から
公式の例から<?php function foo(引数1, 引数2, /* ..., */ 引数_n) { echo '関数の例' . '<br>'; return $retval; } ?>上の例は単に関数って
こんな形だよ
ってだけの例ですね。
あんまり参考になりません。ちょっと使える形にしてみます。
改造後<?php function add(num1, num2) { $sum = num1 + num2; return $sum; } //call $num1 = 5; $num2 = 10; echo add(num1, num2); //-> 15 ?>
使えない??
たしかに使えない
ですね笑
そもそも1行で書ける足し算を関数にしただけなので。では関数って
どんなときに使うと効果的
なんでしょうか?関数を使う場面
例えばこんな処理
DBに接続してユーザーがいたら、
ユーザー情報を取ってきて、
選択した値によって表示するカラムを変更して出力。関数を使った例<?php $input_column_int = 3; $dbh = connectDb(); $user = findUser($dbh, $id)); if ($user) { outputColumn($user, $input_column_int); } else { echo 'ユーザーが見つかりません'; }connectDb(); //->PDOを使ってDBに接続する関数 findUser(); //SQLをPDOで走らせて$idに対応するユーザー情報を取ってくる関数 outputColumn() //-> $userのカラム番号=$input_column_intの値を表示する関数詳しいコードは書きませんが、関数を使っていると
スッキリ
見えますよね?
全部のコードをベタ書き
すると読むのがウンザリする
のはなぜでしょうか?処理が2つ以上存在してくるとややこしくなる
なのでこういうことです!
関数で処理を隠す
関数名でなんの処理かわかるようにする
一気に可読性があがる
関数を作るときに意識したいこと
関数は大きく分けて
2種類
に分かれます。1.
状態を変化させる
2.数式などで値やオブジェクトを返す
1
は例えば出力
です。 やっている処理ブロック
に名前をつけてあげるイメージ
です。 ここでは1行の処理ですが20行ぐらいあって、それに適切な関数名
をつけてあげたらどうでしょう?関数名がコメントの役割を果たしてくれる
ってわけです!1.状態を変化させるfunction outputColumn($user, $id) { echo $user[$id]; }
2
は返り値のあるパターン
です 引数に入力された値を元に計算やDB処理を行い、値やオブジェクト
を返します。 関数はブラックボックスにすることができます。2.数式などで値やオブジェクトを返すfunction findUser($dbh, $id) { $sql = 'select * from users where ?'; $stmt = $dbh->prepare($sql); $stmt->execute([$id]); $user = $stmt->fetch(PDO::FETCH_ASSOC); return $user; }関数を1処理にすることのメリット
テスト
が容易になる使い回し
やすくなる関数名が明確
になり、コード内の可読性
があがるまとめ
・関数化するときに一番気をつけることは、
読みやすくすること
です。
・そして関数化した部分は十分なテスト
をし、ブラックボックス化して後々チェックする部分
を極力減らしましょう
。・
最初から関数化
しようとせずに、処理が増えてきた後にやる
ほうが無難です。
・最初からやってやろう
はあまりうまくいきません笑お願い
LGTMお願いします!
ストックのついでにお願いします!
モチベーションがあがります!
- 投稿日:2020-11-28T14:35:07+09:00
MAMPでphpのエラーをターミナルから問題を探す方法
MAMPでphpエラーが出た際にターミナルでエラーを探す方法
みなさんこんにちは。
今回はMAMP環境でエラーが出た時にエラーがどこから出てきているのかを確かめる方法を紹介します。また、間違えや指摘等ございましたらコメントよろしくお願い致します。
環境
今回僕のパソコンはmacなのでwindowsの方には対応しておりません。
エラーの確認方法1
初心者の頃(現在も初心者)にエラーが出たらどこを見て、何が問題なのかを見つけることさえできていませんでした。
まず、エラーが出た際にはブラウザのディベロッパーツールを利用して確認してみましょう。プログラムを反映させたいページ(現在エラーが出ていて動いていないページ)で右クリック→検証→consoleを確認してみましょう。
こちらにエラーが出てきます。これは大体利用されていると思うので次の方法も紹介します。
エラーの確認方法2
ターミナルから確認する方法です。ターミナルは真っ黒の画面になっていて、cuiなので初めは操作やりにくいけど意外と慣れたら使いやすいかもです。
方法としてはまず、ターミナルを開いてエラーが出ているログが見れる場所まで移動します。
cd /Applications/MAMP/logscdコマンドで移動します。そして'tail -f'コマンドでエラーログをみにいきます。例えば、、、
tail -f php_error.logこれでphpのエラーログを見ることができます。 ターミナルのコマンドについてはこちらのサイトでたくさん記載されていたので紹介いたします。
このようにログをみたりしながらエラーを解決していけばなんとかなることが多いです。
初めは何が悪いのかエラーをみてもわからないことがたくさんすぎて困りますよね。この記事が誰かの助けに慣れば幸いです。 ありがとうございました。
変更
タグの修正を行いました。指摘していただきありがとうございます。
- 投稿日:2020-11-28T14:08:50+09:00
【PHP】コメント機能実装
学習内容を備忘録としてまとめます。
コメント機能を実装しましたので、作成方法を記載します。
投稿に対してコメントを行えるようになっています。※動作画面に出てきているモーダル画面については下記をご参照ください。
【JavaScript】モーダル画面実装実装方法
実装方法について記載していきます。
テーブル構成
まずはコメントテーブルを作成していきます。
それぞれのカラムの役割としては下記のようになっています。
カラム名 役割 id コメントID text コメント内容 image コメントに添付される画像 comment_id コメントに対するコメントのID user_id コメントをしたユーザーID post_id コメントをした投稿ID created_id コメントをした時刻 コメントボタン作成
コメントをするためのボタンを作成します。
<div class="comment_confirmation"> <p class="modal_title" >この投稿にコメントしますか?</p> <p class="post_content"><?= nl2br($post['text']) ?></p> <form method="post" action="../comment/comment_add_done.php" enctype="multipart/form-data"> <textarea class="textarea form-control" placeholder="コメントを入力ください" name="text"></textarea> <div class="comment_img"> <input type="file" name="image_name" class="comment_image" accept="image/*" multiple> </div> <input type="hidden" name="id" value="<?= $post['id'] ?>"> <div class="post_btn"> <button class="btn btn-outline-danger" type="submit" name="comment" value="comment">コメント</button> <button class="btn btn-outline-primary modal_close" type="button">キャンセル</button> </div> </form> </div>コメント内容の記載と画像を添付できるようになっており、
comment_add.php
に遷移しコメントテーブルにINSERT
をかけるような処理になっています。
※上記のコードは説明上不要な部分を省略しているので、トップの動作画面とは違いがあります。<input type="hidden" name="id" value="<?= $post['id'] ?>">こちらで
投稿ID
を取得してどの投稿に対してのコメントなのかを判断しています。
先ほど説明したcomment_add.php
についてみていきます。コメント処理
comment_add.php<?php try { $date = new DateTime(); $date->setTimeZone(new DateTimeZone('Asia/Tokyo')); $comment_text=$_POST['text']; $comment_image_name=$_FILES['image_name']; if(!empty($_POST['comment_id'])) { $comment_id=$_POST['comment_id']; } $user_id=$_SESSION['user_id']; $post_id=$_POST['id']; if($comment_text=='') { set_flash('danger','コメントが空です'); reload(); } if($comment_image_name['size']>0) { if($comment_image_name['size']>1000000) { set_flash('danger','画像が大きすぎます'); reload(); } else { move_uploaded_file($comment_image_name['tmp_name'],'./image/'.$comment_image_name['name']); } } $comment_text=htmlspecialchars($comment_text,ENT_QUOTES,'UTF-8'); $user_id=htmlspecialchars($user_id,ENT_QUOTES,'UTF-8'); $dsn = 'mysql:dbname=db;host=localhost;charset=utf8'; $user = 'root'; $password = ''; $dbh = new PDO($dsn,$user,$password); $dbh -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $sql = 'INSERT INTO comment(text,image,user_id,created_at,post_id,comment_id) VALUES (?,?,?,?,?,?)'; $stmt = $dbh -> prepare($sql); $data[] = $comment_text; $data[] = $comment_image_name['name']; $data[] = $user_id; $data[] = $date->format('Y-m-d H:i:s'); $data[] = $post_id; if(!empty($comment_id)) { $data[] = $comment_id; } else { $data[] = ''; } $stmt -> execute($data); $dbh = null; set_flash('sucsess','コメントを追加しました'); header('Location:../post/post_disp.php?post_id='.$post_id.''); } catch (Exception $e) { print'ただいま障害により大変ご迷惑をお掛けしております。'; exit(); } ?>コメント内容と添付されている画像を確認して、コメントテーブルに
INSERT
しています。if(!empty($_POST['comment_id'])) { $comment_id=$_POST['comment_id']; }こちらの行は
comment_id
がPOSTされたときに、$comment_id
に値を渡しています。
後ほど説明しますが、コメントにコメントされた場合に$comment_id
に値を渡すようになっております。$comments = get_comments($post['id']); foreach($comments as $comment): if(empty($comment['comment_id'])): $comment_user = get_user($comment['user_id']); <div class="comment"> <div class="user_info"> <img src="/user/image/<?= $comment_user['image'] ?>"> <?php print''.$comment_user['name'].''; ?> </div> <span class="comment_text"><?= $comment['text'] ?></span> <?php if(!empty($comment['image'])){ print'<p class="comment_image"><img src="../comment/image/'.$comment['image'].'"></p>'; } print'<span class="comment_created_at">'.convert_to_fuzzy_time($comment['created_at']).'</span>'; endif; ?>あとはお好みの箇所へコメント情報をブラウザに表示します。
if(empty($comment['comment_id'])):
comment_id
が空であるかどうかでコメントのコメントなのかを判断して、
trueの場合は表示するようになっています。$comments = get_comments($post['id']); $comment_user = get_user($comment['user_id']);
get_comments
関数で引数の投稿IDを元にデータからコメント情報を取得し、
get_user
でコメントIDからコメントしたユーザー情報を取得しています。それぞれの関数については下記になります。
function get_comments($post_id){ try { $dsn='mysql:dbname=db;host=localhost;charset=utf8'; $user='root'; $password=''; $dbh=new PDO($dsn,$user,$password); $sql = "SELECT * FROM comment WHERE post_id = :id"; $stmt = $dbh->prepare($sql); $stmt->execute(array(':id' => $post_id)); return $stmt->fetchAll(); } catch (\Exception $e) { error_log('エラー発生:' . $e->getMessage()); set_flash('error',ERR_MSG1); } } function get_user($user_id){ try { $dsn='mysql:dbname=db;host=localhost;charset=utf8'; $user='root'; $password=''; $dbh=new PDO($dsn,$user,$password); $sql = "SELECT id,name,password,profile,image FROM user WHERE id = :id AND delete_flg = 0 "; $stmt = $dbh->prepare($sql); $stmt->execute(array(':id' => $user_id)); return $stmt->fetch(); } catch (\Exception $e) { error_log('エラー発生:' . $e->getMessage()); set_flash('error',ERR_MSG1); } }コメントに返信する機能
<div class="reply_comment_confirmation">このコメントに返信しますか?</p> <p class="post_content"><?= nl2br($comment['text']) ?></p> <form method="post" action="../comment/comment_add_done.php" enctype="multipart/form-data"> <p>コメント内容を入力ください。</p> <input type="text" name="text"> <p>画像を選んでください。</p> <input type="file" name="image_name"> <input type="hidden" name="id" value="<?= $post['id'] ?>"> <input type="hidden" name="comment_id" value="<?= $comment['id'] ?>"> <button class="btn btn-outline-danger" type="submit" name="comment" value="comment">コメント</button> <button class="btn btn-outline-primary modal_close" type="button">キャンセル</button> </form> </div>コメントに返信する機能を実装します。
上記はその機能のボタンになっているのですが、ほぼ通常にコメントするボタンと変わりません。<input type="hidden" name="comment_id" value="<?= $comment['id'] ?>">こちらで返信対象のコメントのIDを取得しています。
これでcomment_id
を用いてコメントに返信したコメントか、またコメントのコメントなのかを判断することができます。<?php $reply_comments = get_reply_comments($post['id'],$comment['id']); foreach($reply_comments as $reply_comment): ?> <div class="reply"> <?php if($reply_comment['comment_id']==$comment['id']): $reply_comment_user = get_user($reply_comment['user_id']); ?> <div class="user_info"> <img src="/user/image/<?= $reply_comment_user['image'] ?>"> <?php print''.$reply_comment_user['name'].''; ?> </div> <span class="comment_text">'.$reply_comment['text'].'</span>'; if(!empty($reply_comment['image'])){ <p class="comment_image"><img src="../comment/image/'.$reply_comment['image'].'"></p>'; }取得したコメントのコメント情報を元にブラウザに表示します。
こちらは対象になったコメントの中に記載しています。$reply_comments = get_reply_comments($post['id'],$comment['id']);
get_reply_comments
関数で投稿IDとコメントIDを元に、コメントに返信したコメント情報を取得しています。
下記のような処理が行われています。function get_reply_comments($post_id,$comment_id){ try { $dsn='mysql:dbname=db;host=localhost;charset=utf8'; $user='root'; $password=''; $dbh=new PDO($dsn,$user,$password); $sql = "SELECT * FROM comment WHERE post_id = :id AND comment_id = :comment_id"; $stmt = $dbh->prepare($sql); $stmt->execute(array(':id' => $post_id , ':comment_id' => $comment_id)); return $stmt->fetchAll(); } catch (\Exception $e) { error_log('エラー発生:' . $e->getMessage()); set_flash('error',ERR_MSG1); } }投稿IDと対象のコメントIDを元にコメント情報を取得しています。
先ほどのブラウザに表示する画面に戻りまして、$reply_comment_user = get_user($reply_comment['user_id']);先ほどの
$reply_comment
で、コメントに返信したユーザー情報をget_user
関数で取得しています。上記のようにコメントに返信することができるようになります。
※説明で余分な部分は省いているため、上の動作画面とは違う画面になる可能性があります。
- 投稿日:2020-11-28T13:19:32+09:00
[PHP] エラー解決 php artisan migrate
Udemyにて学習した際にエラーにハマりましたのでその解決方法を投稿したいと思います。
今回のエラー文は下記になります。
SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known (SQL: select * from information_schema.tables where table_schema = laravel_task and table_name = migrations and table_type = 'BASE TABLE')
エラー分の解説
データベースに接続する際、拒否されています。
つまりlaravelの.envにてはポート番号 password データベースの名前が間違っている可能性が
高いとなります。.env ポート番号 phpMyadmin を確認しよう
env.php//laravelの .envになります。 DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel_task DB_USERNAME=laravel_user //phpMyadminの特権にusernameがあります。 DB_PASSWORD=hosthostエラー解決
DB_HOST
を確認すると`phpMyadminでは[%] .envでは[127.0.0.1]
これがエラーの原因となります。こちらを下記に書き換えます。env.php//laravelの .envになります。 DB_CONNECTION=mysql DB_HOST=localhost //ここを書き換え DB_PORT=3306 DB_DATABASE=laravel_task DB_USERNAME=laravel_user //phpMyadminの特権にusernameがあります。 DB_PASSWORD=hosthostまた、念のためですが
database.php
も下記に書き換えます。database.php// 54行目を書き換えます 'mysql' => [ 'driver' => 'mysql', 'url' => env('DATABASE_URL'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => '/Applications/MAMP/tmp/mysql/mysql.sock', //'unix_socketを上記のように書き換え 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', 'prefix_indexes' => true, 'strict' => true, 'engine' => null, 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), ]) : [], ],最後にターミナルで
php artisan cache:clear
php artisan config:cache
を実行。
するとphp artisan migrate
を実行すると下記のように解決できます。
- 投稿日:2020-11-28T01:19:41+09:00
【Mac】任意のPHPバージョンをphpbrewで取得してみた
はじめに
MacはデフォでPHPがインストールされているけど、開発する際に指定したPHPバージョンを使いたい!
しかし、、WindowsのようにPHP公式サイトでダウンロードしPATHを通すことが難しい。。
Homebrewだとバージョンの[x.x.★]の★部分まで選べない。。phpbrewならバージョンの指定ができ、複数のバージョンを切り替えることができる為、
phpbrewを使って好きなバージョンを取得してみました。環境
- macOS 10.15.7
- Homebrew 2.5.11
- phpbrew 1.26.0
事前準備
Homebrewというツールを使用するので事前にインストールしておきます。
インストール方法は以下サイトを参考にしました。phpbrew本体のインストール
公式ドキュメントを参考に以下コマンドを実行していきます。
// ダウンロード $ curl -L -O https://github.com/phpbrew/phpbrew/releases/latest/download/phpbrew.phar $ chmod +x phpbrew.phar // $PATH の通っているディレクトリにファイルを移動 $ sudo mv phpbrew.phar /usr/local/bin/phpbrew // セットアップ $ phpbrew init $ echo 'source ~/.phpbrew/bashrc' >> ~/.bashrc $ phpbrew lookup-prefix homebrew以上を実行したら、
$ phpbrew
で確認します。$ phpbrew ______ _ _ ____________ | ___ \ | | || ___ \ ___ \ | |_/ / |_| || |_/ / |_/ /_ __ _____ __ | __/| _ || __/| ___ \ '__/ _ \ \ /\ / / | | | | | || | | |_/ / | | __/\ V V / \_| \_| |_/\_| \____/|_| \___| \_/\_/ Brew your latest php!この表示が出ればOKです。
インストール可能なPHPバージョンの確認
$ phpbrew known
を実行すると、インストール可能なバージョンが一覧で表示されます。$ phpbrew known 7.4: 7.4.12, 7.4.11, 7.4.10, 7.4.9, 7.4.8, 7.4.7, 7.4.6, 7.4.5 ... 7.3: 7.3.24, 7.3.23, 7.3.22, 7.3.21, 7.3.20, 7.3.19, 7.3.18, 7.3.17 ... 7.2: 7.2.34, 7.2.33, 7.2.32, 7.2.31, 7.2.30, 7.2.29, 7.2.28, 7.2.27 ... 7.1: 7.1.33, 7.1.32, 7.1.31, 7.1.30, 7.1.29, 7.1.28, 7.1.27, 7.1.26 ... 7.0: 7.0.33, 7.0.32, 7.0.31, 7.0.30, 7.0.29, 7.0.28, 7.0.27 ... 5.6: 5.6.40, 5.6.39, 5.6.38, 5.6.37, 5.6.36, 5.6.35, 5.6.34, 5.6.33 ... 5.5: 5.5.38, 5.5.37, 5.5.36, 5.5.35, 5.5.34, 5.5.33, 5.5.32, 5.5.31 ... 5.4: 5.4.45, 5.4.44, 5.4.43, 5.4.42, 5.4.41, 5.4.40, 5.4.39, 5.4.38 ...今回は " 7.4.5 " をインストールしていきます。
指定したバージョンのPHPバージョンをインストール
$ phpbrew install
コマンドを実行し、php-7.4.5をインストールします。
(デフォルトを7.4.5にしたいので、+default
を末尾に付け足します。)$ phpbrew install 7.4.5 +default ===> phpbrew will now build 7.4.5 You haven't enabled any variants. The default variant will be enabled: [bcmath, bz2, calendar, cli, ctype, dom, fileinfo, filter, ipc, json, mbregex, mbstring, mhash, pcntl, pcre, pdo, pear, phar, posix, readline, sockets, tokenizer, xml, curl, openssl, zip] Please run 'phpbrew variants' for more information. ===> Loading and resolving variants... Homebrew prefix "/usr/local/Cellar/libxml2/2.9.10" does not exist. Homebrew prefix "/usr/local/Cellar/bzip2/1.0.8" does not exist. Homebrew prefix "/usr/local/Cellar/mhash/0.9.9.9" does not exist. Homebrew prefix "/usr/local/Cellar/curl/7.68.0" does not exist. Downloading https://www.php.net/distributions/php-7.3.14.tar.bz2 via curl extensiondose not exist.
ソフトウェアが存在しないと言われてしまいました。。
足りないソフトウェアをbrew install
コマンドでまとめてインストールします。$ brew install libxml2 bzip2 mhash curlよしよし、再度チャレンジです。
改めてインストール
インストール完了するまでに時間がかかるので、休憩がてら猫と戯れてました。
$ phpbrew install 7.4.5 +default (略) * WARNING: You haven't setup your .bashrc file to load phpbrew shell script yet! Please run 'phpbrew init' to see the steps! To use the newly built PHP, try the line(s) below: $ phpbrew use php-7.4.5 Or you can use switch command to switch your default php to php-7.3.14: $ phpbrew switch php-7.4.5 Enjoy!インストール完了です!
再起動
インストールしたらコマンドプロンプトを再起動して
source
コマンドを実行します。$ source ~/.phpbrew/bashrcインストール済みのPHPバージョンを確認
list
コマンドを実行してインストールされたか改めて確認します。$ phpbrew list * php-7.4.5さらに
php -v
でバージョンが7.4.5になっているか確認します。$ php -v PHP 7.4.5 (cli) (built: Nov 25 2020 23:12:04) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologiesphp-7.4.5を使えるようになりました!
他バージョンの確認・切り替え
インストールした別のバージョンを確認し切り替えます。
1. インストール済みのバージョンを一覧で確認
$ phpbrew list php-7.4.6 * php-7.4.5"*"は現在使用されているバージョンです。
7.4.6に切り替えてみる。2. バージョンの切り替え
// 7.4.6を使用する $ phpbrew use php-7.4.6 // 切り替わったか確認 $phpbrew list * php-7.4.6 php-7.4.5切り替わりました!
最後にphp -v
でバージョンが7.4.6になっているか確認$ php -v PHP 7.4.6 (cli) (built: Nov 26 2020 00:53:12) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies7.4.6に切り替えることができました!
最後に
ここまで行き着くのに2日かかりました (›´ω`‹ )
これからコマンド慣れしていかねば、、!