それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

laravel で phpunitのテスト実行時に、PhpStormからXdebugを有効にする。user.iniを有効にして実行

xdebug を有効にしてphpunitを実行したい。

Xdebug の設定をしたとしても、phpunit の設定だとか、xdebugや日付などの php.iniを作るのが不便。

プロジェクトを切り替える毎に、php.iniを見直すのは割と面倒くさい。

phpには user.iniがある

php には実行時に、php.iniを読み込んでグローバル設定を、プロジェクト毎の設定で上書きすることが出来る。

これを laravelから使う。

やりかた

  1. IntelliJ(phpStrorm)で xdebugをリッスンする
  2. xdebug を有効にする設定を書く
  3. デバッグポイントを指定する
  4. artisan コマンドで 2のiniを読み込む

.iniを作る

takuya@laravel$ cat - > .php.user.ini
xdebug.remote_enable=1
xdebug.remote_autostart=1
xdebug.remote_host=localhost
xdebug.remote_port=9000
xdebug.remote_log=/tmp/xdebug.log
xdebug.idekey=takuya1st

Laravel のホームディレクトリに user.iniを作る

artisanコマンドの定義

php artisan:make command RunTest

実行

php artisan test

ソースコード

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class RunTest extends Command
{
  
  /**
   * The name and signature of the console command.
   * @var string
   */
  protected $signature = 'test {filter?}';
  /**
   * The console command description.
   * @var string
   */
  protected $description = 'phpunit でテスト実行';
  
  /**
   * Create a new command instance.
   * @return void
   */
  public function __construct () {
    parent::__construct();
  }
  
  /**
   * Execute the console command.
   * @return mixed
   */
  public function handle () {
    $filter = '';
    if($this->argument('filter')) {
      $filter = $this->argument('filter');
      $filter = "--filter=/$filter/i";
    }
    $cmd = "./vendor/bin/phpunit". ' '.$filter;
    
    // laravel ルートディレクトリにある .user.ini を読み込ませる
    $ini_scan_dir = base_path();
    $addtional_env=" PHP_INI_SCAN_DIR=:$ini_scan_dir  ";
    $cmd =  $addtional_env.$cmd;
    
    
    // dd($cmd);
    passthru($cmd);
  }
}

JetBrains での設定

別途、記事にします。ご参考ください

ポイント

メリット

xdebug がぱぱっと使えるようになるとメッチャ捗る。

laravel のdd/dumpよりも楽になる。

とくに phpunit は複数がマルチに動くので debugger があると助かる。

ディレクトリ単位でシェルの環境変数を切り替えるdirenv

npm / rbenv / pyenv みたいな感じの bashenv がほしい。

npm などを ディレクトリ単位で切り替えていると、どうしてもbashrc と整合性が合わなくなる時がある。

そのために、ディレクトリ単位でシェルの設定やエイリアスを切り替えられると便利だよね。

ってことで調べたてたら見つけたのでメモ

インストールと利用

brew install direnv

初期設定

eval "$(direnv hook bash)"

必要であれば、.bashrc に追記する。

利用

適当な作業用ディレクトリ(ここでは /tmp 、普段は Project フォルダ)に入る

takuya@$ cd /tmp
takuya@tmp$ mkdir tmp

direnv を有効にする

takuya@tmp$ direnv allow .

環境変数を設定した $DIR/.envrc を作る

カレントディレクトリに作った時点で即時にロードされてカッコイイ。

takuya@tmp$ echo "export foo=bar" > .envrc
direnv: loading .envrc
direnv: export +foo

別のディレクトリに移動すると環境変数が消される。

takuya@tmp$ cd ~
direnv: unloading
takuya@~$

先程のディレクトリに戻ると、環境変数が再ロードされる。

takuya@~$ cd -
/tmp/tmp
direnv: loading .envrc
direnv: export +foo

便利な点

毎回まいかい、source 叩かなくて良くなって嬉しい。

しかも、元の環境に戻してくれる。便利。

さらなる便利な点。

環境変数が名前かぶってたらどうなるのかな?

takuya@~$ cd ~
takuya@~$ pwd
/Users/takuya
takuya@~$ export foo=baaaa
takuya@~$ echo $foo
baaaa
## この状態で direnv による上書きをしてみる。
takuya@~$ cd /tmp/tmp
direnv: loading .envrc
direnv: export ~foo
takuya@tmp$ echo $foo
bar
takuya@tmp$ cd -
/Users/takuya
direnv: unloading
### 元通り!!!
takuya@~$ echo $foo
baaaa
takuya@~$

わりと安心して使えるし細かいことを考えなくて良くなるので便利だと思う。

残念な点

alias とか function は読み込んでくれないんだよなぁ。

参考資料

MacやLinuxでExcel用にUTF-8のCSVを作るための BOM

CSV なんてひさびさに使うわ

ExcelCSVを開くために、日本語を化けさせない方法は3つあって

  1. cp932(sjis)で保存する
  2. UTF-8で保存してBOMを付ける。
  3. UTF-16で保存する。

さすがに、cp932 はないし、とっとと退場していただきたい。utf16は後で面倒なのでパス

2のUTF-8とBOMつける方法を選ぶ。

CSV を BOM(byte order mark) の付加・除去

nkf が手っ取り早い

nkf --overwrite --oc=UTF-8-BOM src.csv
nkf --overwrite --oc=UTF-8 src.csv

Excel で開くときに重要

ExcelでUTF-8CSVを開くときに文字化けするんですよね。

Excel以外のソフトウェア、たとえばNumbers.appとかだとBOMとか無関係に文字化けしない。

Laravel artisan serve で storageの画像が配信されない問題とか.user.iniでxdebugを有効にできない問題。

Laravelに移行中。

ローカル開発環境でデバッグしてると、Storageにツッコんだファイルが見れないので困ってた。

しょせん、PHPなので期待してはいけない。

よくある解決策

artisan storage:link

これで、ストレージがリンクされるから見れるはずだよ。っていうんだけど、うん見えないんだよ。

本当の原因

Stroage::url 

Storage::url が返すURLがAPP_URL を見ているので、artisan serve のポートを書かないといけない。

artisan serve コマンドを上書きする。

artisan make:command MyServer 

で、自作の起動スクリプトを作って、次のように、上書きする。

<?php

namespace App\Console\Commands;

use Illuminate\Foundation\Console\ServeCommand;

class MyServer extends ServeCommand {
  
  /**
   * Get the full server command.
   * @return string
   */
  protected function serverCommand() {
    // ini ファイルを読み込む
    $ini_scan_dir = base_path();
    $addtional_env = " PHP_INI_SCAN_DIR=:$ini_scan_dir  ";
    // serve のときは.envを無視してAPP_URLを直接渡す。
    $addtional_env .= " APP_URL=http://{$this->host()}:{$this->port()}  ";
    $cmd = parent::serverCommand();
    $cmd = $addtional_env.$cmd;
    
    return $cmd;
  }
}

artisan serve を上書きして解決する問題。

artisan serve はメインで使うように設計されてないのだろう。みんなはHomesteadでやってるから多分永遠に気づかれない。

php の phpinfoで出てくる 設定の php.ini を直接書き換えるのは面倒なので、.user.ini でやって xdebugを有効にしたり xdebug.idekey を書いたり出来るんだけど、そういうことはマイナーらしくてやらないんですね。。。。

raspi(ARM) と intel でbashスクリプトを共通化する

linux で使ってるシェルスクリプトを汎用化したい

Raspberry Pi3 と Intel Core i7 で使ってるシェルスクリプトを使いまわそうとすると、たまにエラーになる。

判別できないので、「判別式」が必要

uname -m を使う解決策

intel CPU のとき

takuya@:~$ uname -m
x86_64

rPi 3 のとき

uname -m
armv7l

dpkg を使う解決策

dpkg --print-architecture

Intel / AMDx86_64 のとき

takuya@sakura:~$ dpkg --print-architecture
amd64

raspiberry Pi のとき

takuya@raspi3:~ $ dpkg --print-architecture
armhf

orange Pi なども同じだった。

注意するポイント

今回ハマったのは /usr/lib のなかで モジュールを調べて更新されてるかとか、ハッシュ値を比較してたので、ハマった。

/usr/lib/arm-linux-gnueabihf
/usr/lib/x86_64-linux-gnu/

python でSMTPの接続をチェック

メールというのは、老頭児なインフラのくせに、以外に今でも使われていてて困る。

SMTPでつながらないのでテスト。

で、SMTPでメールが送れないので接続テストしようと思った。

python

python は smtplib を使えばかんたんに認証できる。

from smtplib  import SMTP_SSL
smtp = SMTP_SSL('xxxx.znlc.jp',465)
smtp.login('takuyaXXXX','MY_PASSWORD')
>> (235, b'2.7.0 Authentication successful')

もし、接続に失敗しログインに失敗すると

smtplib.SMTPAuthenticationError: (535, b'5.7.8 Error: authentication failed:')

になる。

TELNET( openssl s_client ) で実験するのも良い。

パスワードをメールで送るのやめてほしい

とくにパスワードの復旧やアカウントのアクティベーションには、欠かせない 不安定なSMSよりは信頼できるツールではある。

そんなメールですが、メールアドレスを貰ってももらったメールのドメイン名(MX)やユーザー名とアカウントがただしいか接続チェックしないとメールソフトの設定がうまくいかないときに切り分けができない

SMSは電話番号に紐づくので変更が面倒だし、電話がいつでも手元にあるとは限らない SMSの電話番号は個人情報に深く関連づいていて、いったん流出すると手がつけられないので 余り使いたくない・・・

メールって以外になくならないよね。

ただ、たんなるSMTP通信プロトコルして使われているので、応用性もあるので20世紀世代が死ぬまで、まだまだ使われるんだろうな。 いまじゃ、「パスワードの定期変更のお願い」が来るのばかりだけど。

通知代わりにメール送るの割とやめてほしいんだよね。

IMAPは優秀だよね。

php7で拡張機能のAPIが変わって動かなくなってる pamをなんとかした

php 7 で pamモジュールが動かなかった。

install してもPHPのPAMが動かなかったんですね。

PHPC言語APIが変わってた

コンパイルエラーなので、調べていくと型宣言辺で落ちてた。 調べていくと、拡張機能APIが更新されてたことがわかったなど

この方法で、PAMを使ったphp拡張の作り方がわかった。

PHPの拡張をCで書く方法が分かったし世界が広がリング

http://keicode.com/cgi/how-to-handle-parameters-php-extension.php

php-pamについて

ドコをどう書き換えるべきか書いてあるのはこちら。

https://wiki.php.net/phpng-upgrading

--- /tmp/pam-1.0.3/pam.c        2009-11-29 19:49:35.000000000 +0900
+++ pam.c       2017-10-19 01:52:15.028468810 +0900
@@ -227,8 +227,13 @@
 PHP_FUNCTION(pam_auth)
 {
        char *username, *password;
-       int username_len, password_len;
-       zval *status = NULL, **server, **remote_addr;
+       size_t username_len, password_len;
+       /* zval status; */
+       /* zval *server; */
+       /* zval *remote_addr; */
+       zval *status = NULL;
+       zval *server;
+       zval *remote_addr;
        zend_bool checkacctmgmt = 1;

        pam_auth_t userinfo = {NULL, NULL};
@@ -244,26 +249,28 @@
        userinfo.name = username;
        userinfo.pw = password;

+       /* printf("Hello"); */
+
        if ((result = pam_start(PAM_G(servicename), userinfo.name, &conv_info, &pamh)) != PAM_SUCCESS) {
                if (status) {
                        spprintf(&error_msg, 0, "%s (in %s)", (char *) pam_strerror(pamh, result), "pam_start");
-                       zval_dtor(status);
-                       ZVAL_STRING(status, error_msg, 0);
+                       ZVAL_STRING(status, error_msg);
+                       efree(error_msg);
                }
                RETURN_FALSE;
        }

-       if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **)&server) == SUCCESS && Z_TYPE_PP(server) == IS_ARRAY) {
-               if (zend_hash_find(Z_ARRVAL_PP(server), "REMOTE_ADDR", sizeof("REMOTE_ADDR"), (void **)&remote_addr) == SUCCESS && Z_TYPE_PP(remote_addr) == IS_STRING) {
-                       pam_set_item(pamh, PAM_RHOST, Z_STRVAL_PP(remote_addr));
+       if ( (server=zend_hash_str_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER")-1 ) )  != NULL  && Z_TYPE_P(server) == IS_ARRAY) {
+               if ( ( remote_addr = zend_hash_str_find( Z_ARRVAL_P(server), "REMOTE_ADDR", sizeof("REMOTE_ADDR")-1 ) )   != NULL && Z_TYPE_P(remote_addr) == IS_STRING) {
+                       pam_set_item(pamh, PAM_RHOST, Z_STRVAL_P(remote_addr));
                }
        }

        if ((result = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) {
                if (status) {
                        spprintf(&error_msg, 0, "%s (in %s)", (char *) pam_strerror(pamh, result), "pam_authenticate");
-                       zval_dtor(status);
-                       ZVAL_STRING(status, error_msg, 0);
+                       ZVAL_STRING(status, error_msg);
+                       efree(error_msg);
                }
                pam_end(pamh, PAM_SUCCESS);
                RETURN_FALSE;
@@ -274,7 +281,8 @@
                        if (status) {
                                spprintf(&error_msg, 0, "%s (in %s)", (char *) pam_strerror(pamh, result), "pam_acct_mgmt");
                                zval_dtor(status);
-                               ZVAL_STRING(status, error_msg, 0);
+                               ZVAL_STRING(status, error_msg);
+                               efree(error_msg);
                        }
                        pam_end(pamh, PAM_SUCCESS);
                        RETURN_FALSE;
@@ -312,7 +320,8 @@
                if (status) {
                        spprintf(&error_msg, 0, "%s (in %s)", (char *) pam_strerror(pamh, result), "pam_start");
                        zval_dtor(status);
-                       ZVAL_STRING(status, error_msg, 0);
+                       ZVAL_STRING(status, error_msg);
+                       efree(error_msg);
                }
                RETURN_FALSE;
        }
@@ -321,7 +330,8 @@
                if (status) {
                        spprintf(&error_msg, 0, "%s (in %s)", (char *) pam_strerror(pamh, result), "pam_authenticate");
                        zval_dtor(status);
-                       ZVAL_STRING(status, error_msg, 0);
+                       ZVAL_STRING(status, error_msg);
+                       efree(error_msg);
                }
                pam_end(pamh, PAM_SUCCESS);
                RETURN_FALSE;
@@ -331,7 +341,8 @@
                if (status) {
                        spprintf(&error_msg, 0, "%s (in %s)", (char *) pam_strerror(pamh, result), "pam_chauthtok");
                        zval_dtor(status);
-                       ZVAL_STRING(status, error_msg, 0);
+                       ZVAL_STRING(status, error_msg);
+                       efree(error_msg);
                }
                pam_end(pamh, PAM_SUCCESS);
                RETURN_FALSE;

htop の更新頻度(インターバル)を指定する

htop コマンドで更新の時間を指定する。

htop -d X

X には in tenths of second つまり 10分のX秒で更新される

何もしないとデフォルトは2秒(X=20)だった

1秒おきに更新させるには

htop -d 10

0.5 秒間隔の更新は

htop -d 5

こんな感じ。

わかりにくいよねコレ ミリ秒とか指定できたほうが便利だよね・・・

htop はの更新間隔はデフォルト2秒ってことがわかったことのほうが大きいかな。

WEBユーザのログイン認証をssh経由でやる、割と強引な方法

認証面倒くさい。

LDAPで連携くんだり、PAMで認証したり、OAuthしたり、ユーザ認証をする方法は山ほどある。 でも、それぞれ一長一短があってそれらを解決するいい方法がほしいと思っていた。

WEBのユーザのログイン認証をSSHでやる

ひょんなことから、sshpass というコマンドを知ったので、これをつかって、WEBなどのユーザ認証をローカルのLinuxユーザーとパスワードで出来るんじゃないかと思ってやってみた。

仕組み

フォームから受け取ったユーザ名パスワードをつかってSSHで認証してOKならセッションを発行する

ssh のコマンドはパスワードを受け付けないし、expectなどは面倒なので sshpass コマンドを使うと解決する

サンプルコード

<?php
function alternative_pam_auth_by_shell_ssh( $user , $pass ){

  $allow_group='students'; //このグループに所属するユーザーだけに限定する
  if ( ! check_user_group($user, $allow_group ) ) {
    return false;
  }

  $sshpass = exec('/usr/bin/which sshpass');
  $user_esc = escapeshellarg($user);
  $pass_esc = escapeshellarg($pass);

  $cmd = "{$sshpass} -p ${pass_esc}  ssh -o 'StrictHostKeyChecking no' {$user_esc}@192.168.0.22 whoami 2>&1";
  $str = exec($cmd,$out,$ret);
  if ( $ret > 0  ){
    return false;
  }
  return strpos( $str, $user ) !== false;
}

root に総当りされる・・・

このままだとroot に総当りされるので、WEBからのssh経由でログインできるユーザのグループを限定する

<?php
function check_user_group( $user, $group ) {

  $user = escapeshellarg($user);
  $groups = exec('/usr/bin/which groups');
  $cmd = "{$groups} '${user}'";
  $ret = exec($cmd, $code );
  $ok = strpos($ret ,$group) !== false ;

  return $ok;
}

割りと解決する

ユーザのログインを別個に作るのは、面倒だし。登録画面も面倒だ、SSHSSHで管理したいと思うし。

かといって、次のアイデアには各種の懸念もある。

  • LDAPにユーザ管理を任せるの設定が煩雑だ
  • LDAPだととldif を覚えるのがメンテ上のハードルになり教えるのが面倒だ。
  • PAMだとwww-data に 読み取り権限を与える必要がある。
  • あらゆるプログラムが/etc/shadow を読み取るわけにも行かないし。
  • setuid したコマンドを別途用意するのも面倒だ。
  • OAuthにたよるとSSHログインと管理が別になる
  • SSHをOAuth対応させるとなるとAuthenticator必須になったりコレも面倒だ。
  • MySQLをPAM認証してMySQLに投げるとshell経由じゃないと怒られる

どの方法も一長一短があってむずかしい。

SSH に丸投げでどうだろう。

そこで、ユーザー認証してくれるプログラムで常時起動してるものに認証を投げたら楽じゃんと思って試してみた。

sshにお願いするのはパスワードのチェックだけで権限などは別にいらないしセッション管理もWEBは独立してるので楽だ。 こういう専用のライブラリがアレば良いのだけれど。。。

しかたないんので こういう sshヒューリスティックなハックに頼ることになった。

どうせどの方法もメリットデメリットがあるので、一番手軽な方法があっても良いんじゃないかと思ったり。

認証ハック関連の商品

gitignroeの除外まとめ2〜指定ディレクトリのみ有効化 - 除外の無視で特定フォルダを管理下に

指定したフォルダだけをgit対象にしたいことありませんか?

10個あるファイルのうち1ファイルだけをgit対象にし、残り9ファイルを無視したい。

私であれば ln -sシンボリックリンクを使うのですが、世の中にはシンボリックリンクを使えない不幸な人達と環境があるのです。wordpress のみが動くレンサバにFTPアクセスをしている場合とか。

オススメは ~/.configのgit管理

全部除外して、必要なものだけをいれる。

# ignore all
*
# ## but exclude thees files
!rclone
!rclone/*
!nvim
!nvim/*

ディレクトリの指定とファイルの指定を2重に書いてるのはgitの空フォルダの仕様と、フォルダと無視の取扱にある。

だめな例

*
!rclone/

フォルダだけ対象にすると rclone/は入るけど、中のファイルは先頭の * にマッチして無視される。

そしてgitには空フォルダに見える。gitは空フォルダを無視するので、結果として除外の無視を書いた結果でも

このために、フォルダの中身も無視除外と書く必要があるわけ。

この辺が分からず、サブディレクトリの無視の除外設定に手間取る人が多い様に思った。とくにQootaとか見てると。

gitignore の無視ファイルで無視したい

ワードプレスを例に説明します。

wordpress の直下のファイルで wp-content / wp-config だけを対象にしたい。

f:id:takuya_1st:20180305172803p:plain

gitignore で指定ファイルだけを管理下に置く(ignoreの除外)を使う

最初に、全部除外して、必要なファイルだけを git に入れます。

## 全部除外する
*
####################
## 必要なものだけをいれる
!wp-config.php
!wp-content/
!wp-content/*

サブディレクトリのサブディレクトリだけを入れたいときは?

再帰的にフォルダ内部を最下層まで除外に含めるときは、次のようにbash見たいなワイルドカードを書いてあげると上手く当たる。

## 全部除外する
*
####################
## 必要なものだけをいれる
!wp-config.php
!wp-content/
!wp-content/*
!wp-content/thmes/**

これで、好きな場所をgit 管理して、好きなようにフォルダをgit push して楽ができるよ。

man 読んだら書いてた

 A trailing "/**" matches everything inside. 
For example, "abc/**" matches all files inside directory "abc", relative to the location of ...(..)

参考資料

  • man gitignore

gitignore は man に記述在るので楽だよね*1

ignore and commit に関係する商品

*1:ポエム書く前に man 読んでほしいけど、man よむよりググちゃうんだろうな。

SSHのパスワード認証をシェル経由で手軽に行えるコマンド

ssh のパスワード認証を使いたい。

ssh で鍵登録は場合によって面倒くさい。

パスワードは弱いってのはわかる。でもシェルを実行するユーザごとに鍵をつかったり鍵管理は煩雑になる。

sshpass コマンド

ssh の認証をパスワードで、シェルコマンドでおこなえるコマンドが作られていた。それがsshpass

apt install sshpass

使い方

使い方も超簡単です。基本的な使い方は次の通り。

sshpass -p 'MySecretPassword' ssh username@example.com

シェルコマンドの実行に便利

SSH経由でリモートサーバーにログインをしてコマンドを実行したいときにパスワード認証でぱぱっと作ることが出来る。

私はこれをつかって raspi を一斉に更新したり、raspiに動画再生させたりしてる。手軽で便利すぎ

#!/usr/bin/env bash 

function get_pass(){
  ## ここで何かパスワード取り出し処理
}

MY_PASSWORD=$( get_pass )

sshpass -p MY_PASSWORD  ssh username@example.com /usr/local/sbin/remote_command

利用上の注意点

SSHdにパスワードログインを許可するのは基本的に危険。

SSHのパスワード認証は総当りで絶対突破されると思ったほうが良い。

そのためパスワード認証を有効にするときは /etc/ssh/sshd_config でサーバーへのパスワードをローカルIPに限定するなどの処理を書いておくほうが無難。ルーターがミライに乗っ取られたときはアウトだけど・・・

PasswordAuthentication no
## 指定アドレスからのSSHログインのみに限定する
match address 192.168.0.*
  PasswordAuthentication yes
## 指定ユーザにだけSSHパスワードログインを許可する
### ユーザ名にも総当りされないようにランダムキーを含めたほうが無難
match user my-own-admin-5ooOuA8bXKesVqCQ
  PasswordAuthentication yes

他にもポートを変えるとか

# What ports, IPs and protocols we listen for
Port 2223
Port 2222

他にも iptables recent を有効にするとか、Listenアドレスからv6を外すとか、あれこれ対策をした上でパスワードを使ったほうが良いと思います。

関連資料

参考資料

https://unix.stackexchange.com/questions/38737/ssh-login-with-clear-text-password-as-a-parameter

関連アイテム

OpenSSH[実践]入門 Software Design plus

OpenSSH[実践]入門 Software Design plus

nginx で特定の拡張子をphpで処理する(SetHandler代替)

特定の拡張子をphpなどで処理する

css や js だけじゃなく 画像などをphpで処理したい。Apacheだと addhandler / sethandler で出来るアレ。nginx でもやろうかなと。

画像のリクエストログやリサイズをWebサーバーでやってるとかったるいので、phpで処理してキャッシュ制御すれば楽だよね。セッションチェックとかさ。

nginx での設定例

拡張子php と zip を php-fpmに飛ばしている例。

    location ~ \.(php|zip)$ {
      include fastcgi_params;
      fastcgi_param PATH_INFO $fastcgi_path_info;
      fastcgi_param SCRIPT_FILENAME /var/www/example.com/public/info.php$fastcgi_script_name;
      fastcgi_split_path_info ^(.+\.php)(/.+)$;
      fastcgi_pass unix:/path/to/php-fpm.sock;
    }

ポイント

SCRIPT_FILENAME の指定 。

php の場合は SCRIPT_FILENAME を使ってPATHINFOで実行するファイルを指定することが出来て、これをphp-fpm経由にしてあげれば、任意のファイルを好きなファイルで処理できる。便利。

PATHINFOで取得した場合

$_SERVER['ORIG_SCRIPT_FILENAME']
$_SERVER['ORIG_SCRIPT_NAME']

リクエストされたファイル名

$_SERVER['PATH_TRANSLATED']

php-fpm で php.iniの設定渡す/display_errorsなどをPHP_VALUEで設定する。

PHP_FLAGを使いたい。

apache の mod_phpapachefcgiなら簡単にできるんだけど、nginxだとfcgiでどうやって 初期設定を渡したら良いんだろうか。

こうすれば出来る。

fastcgi_param PHP_FLAG "display_errors=on \n display_startup_errors=on";
fastcgi_param PHP_VALUE "error_reporting=-1";

php をfpm で設定するときに、在るサイトだけ display_errors をオンにしたいとか在るんですよ。

日本語でググっても php-fpm.ini のグローバル設定を変えろ的な記事しかなかったので、アレコレ調べた。

サイトごとにエラー設定を変える。

トラブルが出ているサイトを一時的にdisplay_errors して見てみるとか。

デプロイ時だけエラーになってなんだコレ??ってphpのエラーを追いかけるときかに便利。

サイトごとのエラーログが便利。

fastcgi_param PHP_VALUE  "error_log=/var/log/nginx/my-site.error.log"

複数書きたいときは改行

改行で書くのが楽でいいよ。スペース区切りはダメ。

    fastcgi_param   PHP_VALUE "
        display_errors=on
        display_startup_errors=on
        error_reporting=E_ALL
        error_log=/var/log/nginx/comic-viewer.error.log";

または Name=Value\nName=Value にする.

だめな例

  fastcgi_param   PHP_VALUE "display_errors=on";
  fastcgi_param   PHP_VALUE "display_startup_errors=on";

PHP_VALUE は1つしか取ってくれない。 (そのうちに、nginxやphp-fpmのバージョンアップで解決するんじゃないかな。

ただし再起動が必要

 sudo systemctl restart  nginx php7.0-fpm

fpm の再起動をすると設定が反映される。再起動をしなくてもキャッシュが消えたら反映されると思うけど、php-fpmのキャッシュ機構は多分複雑だろうから追いかけ用途思っても時間が足りなくて出来てない。

前の記事

nginx + php-fpm で display_startup_erros=on にしてシンタックスエラーを表示する。 - それマグで!

PHP

phpで別アプリへのセッション受け渡し

php から別のアプリへセッションを受け渡したい

認証済みのセッションキーを、別のアプリへ受け渡ししたい。今回は mp4 と vlc でテストした。

渡す時

<?php
$url = 'http://example.com/sample.mp4';
$uri = "${uri}&PHPSESSID=".session_id();
$url = 'vlc-x-callback://x-callback-url/stream?url=$url'
header("Location: {$uri}");

受け取る時

ini_set("session.use_trans_sid",true;)
session_start();

フレームワークのサポートも、GET引数のチェックも何も要らない。便利。

引数の名前

デフォルトは "PHPSESSID" なので、ソレを入れても良い。 厳密にやるなら session_name()を使う。

$uri = "${uri}&".session_name()."=".session_id();
$uri = "${uri}&sid=".session_id();

サンプル

<?php

// これだけ
ini_set("session.use_trans_sid",true);
ini_set('session.use_only_cookies', 'off');
session_start();

if ( !empty($_SESSION['is_login']) && $_SESSION['is_login'] ) {
  echo "OK";
  http_response_code(200);
  return ;
}else{
  echo "OK";
  http_response_code(401);
  return ;
}

参考資料

http://php.net/manual/en/session.idpassing.php

セッション

ハンマーセッション!(7) (週刊少年マガジンコミックス)

ハンマーセッション!(7) (週刊少年マガジンコミックス)

ls コマンドで結果を1行ごと1列にならべてループを楽にしたい

ls の結果からディレクトリ名を除きたい。

ls すると結果がズラッと並んでしまって、後処理をしにくい

takuya@Desktop$ ls /
'['     cat     cp    date   df           echo   expr       kill   launchctl   ln   mkdir   pax   pwd   rm      sh      stty   tcsh   unlink      zsh
 bash   chmod   csh   dd     domainname   ed     hostname   ksh    link        ls   mv      ps    rcp   rmdir   sleep   sync   test   wait4path

1行に並べたい

なんと、手軽に1行に並べることが出来ます!single-column -1 オプションです。

takuya@Desktop$ ls -1 /bin
'['
bash
cat
chmod
cp
csh
date
dd
df
domainname
echo
ed
expr
hostname

man からの抜粋

え?カンマ区切りとかできるんだけどwww

      --format=WORD
              across -x, commas -m, horizontal -x, long -l, single-column -1, verbose -l, vertical -C

-1 (one) と -l (エル) は似てる上に同じカテゴリの仲間だったなんて驚き!

ループで回すならIFSで済むんだ。

IFSで済むんだけど、ruby IO.readlineやExcel など、ファイル読み込み系のプログラムから読み込むときは、開業が楽だよねやっぱり。

関連する記事

IFS 関連の記事

参考資料

ls -d 関連商品

L.S.D(1) (NINO)

L.S.D(1) (NINO)