Laravelでサービスプロバイダを追加した場合の、引っ越しにおける注意事項
laravel 5.2 で開発中のプロジェクトの別環境を作ろうとして、しばらく悩んだのでメモです。作業手順は概ね以下の通りです:
- ソースツリーを git で持ってくる
- vendor 配下と composer.lock を消して composer install
- DB ユーザーと DB インスタンスを作成(中身はまだカラの状態)
- php artisan migrate でテーブルを作る
(4) のところで以下のようなエラーが発生:
$ php artisan [Illuminate\Database\QueryException] SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "manuals" does not exist (以下略)
エラーログを遡ると、app/Providers/Ec2ServiceProvider.php という自作のソースが走っており、その中で Manual モデルの初期化に行って、SELECT しようとして引っかかってました。
artisan コンソールアプリをいくつか作って、当初はそれらを app/Console/Kernel.php に登録して使っていたんですが、本格的に使う場合(*1)はサービスプロバイダとして登録するべきらしいということで作ったのがこのファイルでした。
で、サービスプロバイダとして登録すると、php artisan レベルですでに使える状態になっていないといけないということらしいです。
しょうがないので、app/Providers/Ec2ServiceProvider.php の拡張子を .php_ にリネームして見えなくしてみると、今度は以下のエラー:
$ php artisan [Symfony\Component\Debug\Exception\FatalThrowableError] Class 'App\Providers\Ec2ServiceProvider' not found
Ec2ServiceProvider のエントリが config/app.config にいたので、その行をコメントアウト。これでやっと php artisan でコマンドの一覧表が出るようになりました。
その後、php artisan migrate でテーブルを作成し、コメントアウトと拡張子の変更を戻して php artisan すると、自分で作ったコマンドも表示されるようになりました。めでたしめでたし。
$ php artisan | grep ec2 ec2 ec2:autostop インスタンスの自動停止制御 ec2:list EC2 インスタンスの一覧を表示します ec2:reboot インスタンスを再起動します ec2:start インスタンスを起動します ec2:stop インスタンスを停止します
(*1)… Laravel パッケージにコマンドライン機能を含める場合がこれにあたるようです。
Apacheが起動できなくなった
CentOS7 でいろいろやってたら、ふと Apache が起動できなくなって10分ほど焦ったのでメモ。
[Wed Aug 19 16:07:31.191392 2015] [suexec:notice] [pid 14555] AH01232: suEXEC mechanism enabled (wrapper: /usr/sbin/suexec) [Wed Aug 19 16:07:31.238273 2015] [auth_digest:notice] [pid 14555] AH01757: generating secret for digest authentication ... [Wed Aug 19 16:07:31.238584 2015] [auth_digest:error] [pid 14555] (28)No space left on device: AH01762: Failed to create shared memory segment on file /run/httpd/authdigest_shm.14555 [Wed Aug 19 16:07:31.238608 2015] [auth_digest:error] [pid 14555] (28)No space left on device: AH01760: failed to initialize shm - all nonce-count checking, one-time nonces, and MD5-sess algorithm disabled
ログによると、共有メモリが容量オーバーで作れなくなっているらしい。
m-hotta@estonia:~/as-user-dev$ ipcs ------ メッセージキュー -------- キー msqid 所有者 権限 使用バイト数 メッセージ ------ 共有メモリセグメント -------- キー shmid 所有者 権限 バイト nattch 状態 0x00000000 xxxxx1 m-hotta 600 4194304 2 対象 0x00000000 xxxxx2 m-hotta 600 4194304 2 対象 0x00000000 xxxxx3 m-hotta 600 4194304 2 対象 0x00000000 xxxxx4 m-hotta 600 4194304 2 対象 0x00000000 xxxxx5 m-hotta 600 4194304 2 対象 0x00000000 xxxxx6 m-hotta 600 4194304 2 対象 (以下大量:xxxxxx は、実際にはランダムな6桁の10進数) ------ セマフォ配列 -------- キー semid 所有者 権限 nsems
自分が所有者の共有メモリで埋もれている。なんだこれは?
どうも、vncserver 利用終了時に(ウィンドウを「×」で終わらせたりして)
ちゃんと終わらせないと、リソースが解放されないみたいです。
ipcrm -a
なぜかこれでも全部は消えてくれなかった。面倒なのでリブート。
これでリソースが開放されて、httpd が自動起動しました。
めでたしめでたし。
httpd(+php) で SEGV
CentOS7 上で動いている httpd が、ログローテーションに伴う再起動時に
落ちていました。"[abrt] full crash report" というタイトルのメールが
管理者宛に来ていたので見てみると、以下のようになっていました(抜粋)。
core_backtrace: :{ "signal": 11 :, "executable": "/usr/sbin/httpd" :, "stacktrace": : [ { "crash_thread": true : , "frames": : [ { "address": 139643714280712 : , "build_id_offset": 25144584 : , "function_name": "profile_free_file_data" : , "file_name": "/usr/lib/oracle/12.1/client64/lib/libclntsh.so.12.1" : }
心当たりがあったので、/etc/php.d/{oci8, pdo_oci}.ini を呼ばれないように
リネームしてから httpd を再起動しました。現在は順調に動いています。
なお、当該ホストでは Oracle へのアクセス機能は使っていません。
問題のあった環境では、(他ホストとの環境統一の兼ね合いで)oci8 と
pdo_oci を入れていました。oci8 は pecl 経由で導入し、pdo_oci は
オレオレです。
http://php.net/manual/ja/oci8.requirements.php
https://github.com/hotta/pdo_oci
また、PHP 本体は以下の yum リポジトリを使わせてもらっていて、常に
本家リリースからあまり間をおかずに php-5.6.x の最新が入るように
なっています。
https://webtatic.com/packages/php56/
(すでに PHP7 系のパッケージもあるみたいです)
Apache がコケた原因は、以下の通りだと推測されます。
普段は ansible 経由で環境を作っているのでその時点の最新が入りますが、
今回は個別に yum update した後の障害でした。
なお、pdo_oci を php でシミュレートする
https://github.com/taq/pdooci
という実装もあるみたいです。どっちがいいのかな。
みなさん、PHP+Oracle の環境って、どうやってメンテしているんでしょうか?
Oracle のライセンスがこんな状態だと、いつまでたっても yum のサポート
対象にはなり得ないんでしょうか。Oracle さんが Instant Client を OSS 化
してくれれば解決?
TLS Support for openldap-2.4.x / php on CentOS7
やっと動いたので簡単にメモしておく。
前提
- LDAP Consumer として動作中のホストに対して TLS Support を追加する。
- 証明書は例によってオレオレ。
- Webサーバ用のワイルドカード証明書も取得済みだが、通信路の暗号化だけなら証明書の有効期限到達時の切り替えなどを考慮しなくていいのでオレオレが楽。
オレオレ証明書の作成
- openssl パッケージに含まれる make-dummy-cert コマンドを使うのが簡単
/etc/pki/tls/certs/make-dummy-cert /tmp/self-cert sed -n '/BEGIN PRIVATE KEY/,/END PRIVATE KEY/'p /tmp/self-cert > /etc/openldap/certs/localhost.key sed -n '/BEGIN CERTIFICATE/,/END ERTIFICATE/'p /tmp/self-cert > /etc/openldap/certs/localhost.crt
LDAP サーバへの設定追加
$ cat tls.ldif dn: cn=config changetype: modify add: olcTLSCertificateFile olcTLSCertificateFile: /etc/openldap/certs/localhost.crt - add: olcTLSCertificateKeyFile olcTLSCertificateKeyFile: /etc/openldap/certs/localhost.key $ /usr/bin/ldapmodify -x -D cn=config -w (内緒) -H ldap://localhost:389 -f tls.ldif
動作確認(別ホストからでも可)
- クライアントではサーバ証明書を求めないようにしておく
$ cat /etc/openldap/ldap.conf .... TLS_REQCERT never ←この行がなければ追加
- 従来の非暗号化でアクセスできることを確認
$ ldapsearch -x -LLL -h example.com -b ou=Users,dc=example,dc=com '(uid=test1)' dn dn: uid=test1,ou=Users,dc=example,dc=com
- TLS 接続 ( -Z オプション)でアクセスできることを確認
$ ldapsearch -Z -x -LLL -h example.com -b ou=Users,dc=example.com '(uid=test1)' dn dn: uid=test1,ou=Users,dc=example,dc=com
PHPからの認証動作確認
- 実際にはPHPで書かれたアプリからの認証で使いたいので、以下のようなサンプルプログラムを書いて検証
$ cat ldap_tls.php #!/usr/bin/php <?php define('LDAP_SERVER', 'ldap://example.com:389'); define('ACCOUNT', 'test1'); define('PASSWD', 'ok-pass'); $ds = ldap_connect(LDAP_SERVER) or die("ldap_connect()\n"); ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3) or die("LDAP_OPT_PROTOCOL_VERSION\n"); ldap_set_option($ds, LDAP_OPT_REFERRALS, 0) or die("LDAP_OPT_REFERRALS\n"); ldap_start_tls($ds) or die("ldap_start_tls()\n"); $dn = sprintf("uid=%s,ou=Users,dc=example.com", ACCOUNT); if (ldap_bind($ds, $dn, PASSWD)) { echo "Authentication succeeded.\n"; } else { echo "Authentication failure.\n"; }
- パスワードが正しければ Authentication succeeded が表示され、
- わざと間違えたら Authentication failure が表示されることを確認。
ということで、めでたしめでたし。
自動再表示の際の「フォームを再送信」ダイアログを抑制したい
リアルタイム監視のような用途の Web ページを作成する場合、
定周期(1分おきなど)で自動リロードするようにしておくと、
常に最新の情報が表示されて便利です。
HTMLでやる場合は
<meta http-equiv='refresh' content='60'>
JavaScriptでやる場合は
windows.location.reload();
といった感じで実現できます。
ところが HTML の中にフォームを含む場合、ブラウザによっては再表示の際、以下のようなダイアログが表示される場合があります。
いろいろ調べた結果、一番簡単な対処方法は URL を変えることのようです。なので、以下のように実装しました。
JS側で、POST先のURLをたとえば以下のように変更します。
windows.location = '/_reloaded';
次に、CakePHPのルーティング機能で本来のURLに戻してやります。
app/Config/route.php: Router::connect('/_reloaded', [ 'controller' => 'OriginalClassName', 'action' => 'index' ]);
これでダイアログが出なくなりました。めでたしめでたし。
Apache起動とCLI起動における、PHP の実行環境の違いを調べてみた
概要
項目 | Apache(libphp5.so) | CLI(/usr/bin/php) | 備考 | Server API | Apache 2.0 Handler | Command Line Interface | php_sapi_name()で判定可能 | Configuration File (php.ini) Path | /etc | /etc | -c で制御可能 | Loaded Configuration File | /etc/php.ini | /etc/php.ini | -n で制御可能 |
---|
$GLOBALS
- Web : 以下のスクリプトをコールした時の状態
<?php echo (nl2br(var_dump($GLOBALS)));
<?php var_dump($GLOBALS);
メンバー名 | Web(apache2handler) | CLI(cli) | _GET | [ ] | [ ] | _POST | [ ] | [ ] | _COOKIE | [ ] | [ ] | _FILES | [ ] | [ ] | argv | (なし) | [ ] | argc | (なし) | 0 | _ENV | [ ] | [ ] | _REQUEST | [ ] | [ ] | _SERVER | (後述) | (後述) |
---|
$_SERVER:WebとCLIいずれにも含まれるもの
- $GLOBALS に含まれるものは除いています。
メンバー名 | Web | CLI | DOCUMENT_ROOT | 絶対パス名 | "" | PATH | "/sbin:/usr/sbin:/bin:/usr/bin" | "/usr/lib64/qt-3.3/bin..." | PHP_SELF | DOCUMENT_ROOT からの相対パス名 | ファイル名 | REQUEST_TIME | int(1433378049) | int(1433390080) | REQUEST_TIME_FLOAT | float(1433390080.484) | double(1433378049.3198) | SCRIPT_FILENAME | スクリプトの物理パス名 | ファイル名 | SCRIPT_NAME | DOCUMENT_ROOT からの相対パス名 | ファイル名 |
---|
$_SERVER:Webのみに含まれるもの
- REDIRECT_STATUS
- REMOTE_{ADDR,PORT}
- SERVER_{ADDR,ADMIN,NAME,PORT,PROTOCOL,SIGNATURE,SOFTWARE}
NetBeansでリモートデバッグできなくなった
最近はCakePHPで開発をしていますが、フレームワークをIDEなしで開発するのは(少なくとも自分には)非現実的だと悟ったので、デバッグはもっぱら Xdebug+NetBeansによるCakePHPのデバッグ の手順に従ってNetBeansを使っています。
今日 NetBeans を使ったら、ふとしたことからリモートデバッグが動かなくなったので、原因を調査した時のメモです。
最初の症状としては、デバッグ開始後サーバからの応答待ちのまま先に進まない(ソースの開始行まで到達しない)が、IDE単体としては問題なく動いている、という感じです。
サーバ側で Xdebug の設定は以下のようにしています。Xdebug はポート 9000 を使っています。
$ grep ^xdebug /etc/php.ini xdebug.remote_connect_back = on xdebug.remote_port = 9000 xdebug.remote_handler = dbgp xdebug.remote_enable = On xdebug.remote_log = /tmp/xdebug_remote.log xdebug.idekey = netbeans-xdebug
端末(Windows)側でネットワークの状態を確認します。ちなみにすっかり忘れてましたが、以前 Windows に gow を入れていたようで grep 等が使えるようになっていました。
gow - Unix command line utilities installer for Windows.
W:\>which grep C:\Program Files (x86)\Gow\bin\grep.EXE W:\>netstat -an | grep -w 9000 TCP 10.28.1.53:9000 10.30.8.31:54321 CLOSE_WAIT
10.28.1.53 が開発機(Windows7 Pro)、10.30.8.31 がサーバ(CentOS7)です。
デバッグを中止してからしばらく待っても CLOSE-WAIT のまま。これは端末側のネットワークの内部状態がおかしくなっていると判断し、パソコンをリブートしたらこの状態は解消されました。
ただ、ブレークポイントで止まらないのは相変わらず。
今度はサーバ側で tcpdump を仕掛けてからデバッグを開始し、パケットを監視してみました。
root@germany:~# tcpdump -n -nn port 9000 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 11:07:54.998420 IP 10.30.8.11.36562 > 10.28.1.53.9000: Flags [S], seq 2531464156, win 14600, options [mss 1460,sackOK,TS val 1533355514 ecr 0,nop,wscale 7], length 0 11:07:55.238767 IP 10.30.8.11.36563 > 10.28.1.53.9000: Flags [S], seq 4273096071, win 14600, options [mss 1460,sackOK,TS val 1533355754 ecr 0,nop,wscale 7], length 0
サーバから端末に対して ポート 9000 への接続を張りに来ていますが、相変わらず端末がそれを無視しています。
W:\>netstat -an | grep -w 9000 TCP 0.0.0.0:9000 0.0.0.0:0 LISTENING TCP [::]:9000 [::]:0 LISTENING
端末側ではポートの待ち受けはしているようですが、まったくパケットを受けていない状態。 これは Windows 側のファイアーウォールが疑われるので、設定を見てみます。 まず、動いているプロセスのパスを調べます。
netbeans64.exe で右クリックしてプロパティを開きます。
フルパスは C:\Program Files\NetBeans 8.0\bin\netbeans64.exe ということがわかります。次は コントロール パネル>システムとセキュリティ>Windows ファイアウォール>詳細設定>受信の規則 を開きます。
実はここを開いた直後は、NetBeans の過去のバージョンに対するルールがたくさんゴミとして残っていました。気持ちが悪いので、旧バージョンの分はすべて削除しました。プログラムのアンインストールをしても、ルールは自動では消えてくれないんでしょうかね?
これによると、現在の状態は「ドメイン」は許可、「パブリック」はブロックになっています。 これは Windows(NT/AD) ドメインではなくネットワークプロファイルの用語のようです。 画面右下のアイコンにマウスを乗せると、現在の状態が表示されます。
この表示は「識別されていないネットワーク」につながってると言いたいのか、 それとも「アクセスできるネットワークがない」と言いたいのか…。
というか、そもそもルールが二重に登録されている時点でおかしい。
ということで、二重になっている部分を「ドメイン」と「パブリック」がそれぞれ1行だけになるようにしました。
ここまでシンプルにして、再度挑戦します。
どう見ても「パブリック」がブロックになっていることが原因のように思えます。 と思いきや、「パブリック」を許可しても、状況は変わりませんでした。
ファイアーウォールルールのエントリに不整合が出ているようなので、 いったん「NetBeans」のルールをすべて削除した後、 再度デバッグを開始したら、以下のダイアログが表示されました。
これで再度「アクセスを許可」してやったらうまくいくようになりました。めでたしめでたし。