PHPで例外を出力するときにわざわざgetMessage()を使う必要はない
たまに見かけるので。
こんな感じにすれば__toString()が自動的に呼ばれる。エラーメッセージとスタックトレースの両方がついたいい感じの出力になる。
<?php function a() { throw new Exception("test"); } try { a(); } catch (Exception $e) { echo $e; }
exception 'Exception' with message 'test' in /tmp/vw50zKH/28:4 Stack trace: #0 /tmp/vw50zKH/28(8): a() #1 {main}
文字列コンテキストになっているか不安な場合は、"$e"
とすれば安心。
getMessage()
はスタックトレースがないし、getTraceAsString()
は逆にメッセージがない。そもそもどちらもファイル名・行数に関する表示はない。加工してrethrowするような場合以外は、__toString()
相当がおすすめ。
Nginxで権限があるはずなのにポートをバインドできない
ちょっと必要があって、Nginxを8000番で動かそうとしたらなぜかエラーが出た。1023までのポートならともかく8000だし、そもそもroot権限で動かしてるのに。
nginx: [emerg] bind() to 0.0.0.0:8000 failed (13: Permission denied)
Permission deniedと来たらseLinuxかなとaudit.logを見てみる。
type=AVC msg=audit(1564721070.008:4043): avc: denied { name_bind } for pid=26994 comm="nginx" src=8000 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:soundd_port_t:s0 tclass=tcp_socket permissive=0
やっぱり。semanage
というコマンドで許可できるっぽいが入ってない。yum provides
して調べる。policycoreutils-python
というパッケージに含まれてるとのこと。
sudo yum install policycoreutils-python
するとインストール済みと出る。なぜ。
sudo yum reinstall policycoreutils-python
で入ったっぽい。で、8000ポートをHTTP扱いに。
sudo semanage port -a -t http_port_t -p tcp 8000
すると、
ValueError: Port tcp/8000 already defined
ほかで使われているようだ。
sudo semanage port -l | grep 8000 # soundd_port_t tcp 8000, 9433, 16001
-mだと追加できるぽい。
sudo semanage port -m -t http_port_t -p tcp 8000
WindowsでMercurialが死んでた件
5.0.2で以下のようなエラーが出た。Python 3が別途入ってたからそのせいかと思ってPATHいじったりアンインストールしてみたりしたが駄目。
仕方ないので一応安全そうなところから4.9.1をダウンロードして入れてみたら動いたっぽい。
ちなみにChocolateyで定期的に自動アップデートしてる上、Mercurial自体も手動ではもう使っていないので気付くのがだいぶ遅れた。気をつけないと。
$ hg Traceback (most recent call last):[2019-07-29 19:58] File "hg", line 43, in <module> File "hgdemandimport\demandimportpy2.pyc", line 150, in __getattr__ File "hgdemandimport\demandimportpy2.pyc", line 94, in _load File "hgdemandimport\demandimportpy2.pyc", line 43, in _hgextimport File "mercurial\dispatch.pyc", line 22, in <module> File "hgdemandimport\demandimportpy2.pyc", line 248, in _demandimport File "hgdemandimport\demandimportpy2.pyc", line 43, in _hgextimport File "mercurial\i18n.pyc", line 28, in <module> File "hgdemandimport\demandimportpy2.pyc", line 150, in __getattr__ File "hgdemandimport\demandimportpy2.pyc", line 94, in _load File "hgdemandimport\demandimportpy2.pyc", line 43, in _hgextimport File "mercurial\encoding.pyc", line 24, in <module> File "mercurial\policy.pyc", line 101, in importmod File "mercurial\policy.pyc", line 63, in _importfrom File "hgdemandimport\demandimportpy2.pyc", line 164, in __doc__ File "hgdemandimport\demandimportpy2.pyc", line 94, in _load File "hgdemandimport\demandimportpy2.pyc", line 43, in _hgextimport File "mercurial\cext\parsers.pyc", line 12, in <module> File "mercurial\cext\parsers.pyc", line 10, in __load ImportError: DLL load failed: %1 は有効な Win32 アプリケーションではありません。
しかしググってももうMercurialの情報がろくに出てこなくてね、つらい……。
Laravelでドキュメントルートに静的ファイルを混在させる方法
作ったシステムに後から静的ページを追加したい、みたいな要望にどう対応すればいいだろうか。「有料です」で済ませたいところだが、なかなかそうも行かない場合も多い。
古のCGI/PHP環境でやってきたクライアントにとっては、既存のファイルと無関係なところにファイル/ディレクトリを追加することができないのはなぜ、となってしまうのもまあ仕方ないのかもしれない。
そういうときどうするか。
LaravelのデフォルトのApache/Nginxの設定では、ファイルが存在する場合はそちらを読み込むようになっているので、単純にpublic
ディレクトリにファイルを置けばそちらを優先してくれるが、public
ディレクトリは普通Git管理下にあるので、勝手にいじられたくない。1
解決法は、public
ディレクトリをドキュメントルートのサブディレクトリなどに置いて触らないよう伝えた上で、ほかは勝手にしてください、とすることだろうか。
ということで、ドキュメントルートにpublic/.htaccess
ベースの.htaccess
を置いて、URL上ではルートで動かしながら、じっさいのファイルはドキュメントルートのサブディレクトリに置くようにしてみる。
以下ではサブディレクトリ名はpublic
とする。
<IfModule mod_rewrite.c> <IfModule mod_negotiation.c> Options -MultiViews -Indexes </IfModule> RewriteEngine On # Handle Authorization Header RewriteCond %{HTTP:Authorization} . RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] # Redirect Trailing Slashes If Not A Folder... RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} (.+)/$ RewriteRule ^ %1 [L,R=301] # ここから追加 { RewriteCond %{REQUEST_URI} ^/$ RewriteRule ^ public/index.php [L] RewriteCond %{REQUEST_FILENAME} !-f # これがあれば、ドキュメントルート直下の同名ファイルを優先できるがなくてもいい。 RewriteCond %{DOCUMENT_ROOT}/public%{REQUEST_URI} -f RewriteRule (.*) public/$1 # } ここまで追加 # Handle Front Controller... RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ public/index.php [L] # ここも変更 </IfModule>
なおこれだけでは、https://example.com/public/への直アクセスが防げない。いい方法が思い付かなかった。思い付いた人いたら教えてください。
-
デプロイ方法にもよる。リンクでなく一方向のコピーであれば、上書きさえしなければ問題ない。↩
LaravelでAuth系のコントローラが最初から存在するのはなぜか
ご存知の通りLaravelではartisan make:auth
することでいくつかのファイルが生成・変更され、デフォルトの認証関係の機能を有効にできる。
だが、じつはこれを実行しなくとも、最初からApp\Http\Controllers\Auth\LoginController
をはじめとする各種コントローラが存在している。
GitHubで履歴を辿って調べてみた。確証はないがおそらく、単純な歴史的経緯が理由のようだ。
認証用のコントローラが laravel/laravel (Laravelのフレームワークのコア部分を除いたリポジトリ。いくつかのサンプル的なコードが含まれる)上で実装されたのは5.0のころ1のようだ。
この時点ではmake:auth
はなかった。こちらは5.2のころ2に実装されている。
もう一つ興味深いのが、このとき実装されたmake:auth
が一度削除されている3ということだ。各種ファイルがlaravel/laravel
にすでに含まれているから不要という理由で削除されている。このときは5.8現在とは違い、make:auth
が認証用のコントローラも生成していたようで、そのせいで重複と考えられたのだろう。
その後5.2のうち4に再度実装され、今度はlaravel/laravel
側で存在するコントローラは生成されない形で実装された。
ということで歴史だけ見ると、先にlaravel/laravel
内のファイルとして実装してしまったので、というだけでほかの理由などはなさそうだ。
現状はいまいちなので、laravel/laravel
から認証用コントローラを削除し、make:auth
で生成できるようになって欲しいが、リポジトリが違うことからいろいろ面倒そうではある。
余談なのだが、make:auth
の実体となるファイルは一度削除される前と後で名前が変わり、さらにその後再度名前が戻される形で変更されており、そのせいで履歴を辿るのがちょっとややこしい。5
-
https://github.com/laravel/laravel/commit/f2279c02107f28b8c3cb1b8627c22a6fb2e7fc74↩
-
https://github.com/laravel/framework/commit/29c9ba0197179c018a20df30f3330b90de0923a9↩
-
https://github.com/laravel/framework/commit/f7070f3092aa350f991125a294bbec0475cf6aa0↩
-
https://github.com/laravel/framework/commit/6f07584f9b80d51c80fab0fd35285401dc7e9967↩
ChocolateyでStrawberry Perlが更新できない
chocolatey upgrade strawberryperl
すると、
WARNING: Generic MSI Error. This is a local environment error, not an issue with a package or the MSI itself - it could mean a pending reboot is necessary prior to install or something else (like the same version is already installed). Please see MSI log if available. If not, try again adding '--install-arguments="'/l*v c:\StrawberryPerl_msi_install.log'"'. Then search the MSI Log for "Return Value 3" and look above that for the error. ERROR: Running ["C:\Windows\System32\msiexec.exe" /i "C:\Users\********\AppData\Local\Temp\chocolatey\StrawberryPerl\5.30.0.1\strawberry-perl-5.30.0.1-64bit.msi" /qn /norestart /l*v c:\StrawberryPerl_msi_install.log] was not successful. Exit code was '1603'. Exit code indicates the following: Generic MSI Error. This is a local environment error, not an issue with a package or the MSI itself - it could mean a pending reboot is necessary prior to install or something else (like the same version is already installed). Please see MSI log if available. If not, try again adding '--install-arguments="'/l*v c:\StrawberryPerl_msi_install.log'"'. Then search the MSI Log for "Return Value 3" and look above that for the error.. The upgrade of strawberryperl was NOT successful. Error while running 'C:\ProgramData\chocolatey\lib\StrawberryPerl\tools\chocolateyInstall.ps1'. See log for details. Unsuccessful operation for strawberryperl.
とか出る。
書いてある通り、
--install-arguments="'/l*v c:\StrawberryPerl_msi_install.log'"
を追加して再実行してみる。出力されたログにこんなことが書いてあった。
MSI (s) (E8:F8) [09:12:05:418]: Doing action: CA_UninstallOldVersion Action ended 9:12:05: FindRelatedProducts. Return value 1. Action start 9:12:05: CA_UninstallOldVersion. MSI (s) (E8:F8) [09:12:05:418]: Product: Strawberry Perl (64-bit) -- Already installed version of Strawberry Perl (64-bit) cannot be upgraded; it has to be uninstalled first. Already installed version of Strawberry Perl (64-bit) cannot be upgraded; it has to be uninstalled first. Action ended 9:12:05: CA_UninstallOldVersion. Return value 3. Action ended 9:12:05: INSTALL. Return value 3.
先にアンインストールしろってことかな?
C:\Users\********\AppData\Local\Temp\chocolatey\StrawberryPerl\5.30.0.1\strawberry-perl-5.30.0.1-64bit.msi
にあるのを直接叩いてみると、GUIで同じことを言われた。
つまりChocolateyのStrawberry Perlのパッケージでは、前のバージョンがうまくアンインストールできない(ことがある?)らしい。
もうちょっと調べたい気もしたが、今回はここまで。とりあえず手動でアンインストール後、再度、
choco upgrade strawberryperl
した。
Tridactylでデフォルトのsearchurlsのキーワードを無効にする
Tridactylではデフォルトで各種キーワードでの検索が設定されている。が、キーワードが名前そのままなので、キーワードと同じ単語を検索したい場合につらい。ので無効にしたいのだが、しばらくやり方がわからず、試行錯誤の末最近ようやくわかったので共有する。
以下はデフォルトでは、Googleで、maps
が検索される。
:open google maps
これを、google maps
というキーワードでデフォルトの検索エンジンでの検索にしたい。
結論から言うと、以下のようにsearchurls
のJSONを直接設定し、キーワードの値を空文字列にする。
:set searchurls {"google": "", ...}
引っかかる点としては、設定をクリアしようとするとデフォルト値が使われてしまうこと、またsearchurls.<KEYWORD>
の形のショートカット経由で設定を空文字列にすることはできないということ。
:unset searchurls.google
設定がデフォルトに戻る。
:set searchurls.google
後ろに空白。後ろに空白がない場合と同じように、現在の設定を表示するだけ。
:set searchurls.google '' :set searchurls.google ""
それぞれ''
, ""
自体が設定されて、検索はされずエラーになる。