php で実行環境をチェックするには
PHP_OS という、ウルトラ素晴らしい定数が、最初から組み込まれています。
<?php var_dump(PHP_OS);
実行結果
string(6) "Darwin"
Ubuntu での実行結果
string(5) "Linux"
とてもかんたんにOSを判別できます。
000123 のように数字を0で埋めることで、桁数が揃ったり、視認性があるので採用する人も多いと思います。
また、最大桁数が一瞥してわかるのも魅力ですね。
ゼロ埋めはヒューマンインタフェース*1として、対人間との情報のやり取りとして非常に優秀です。
( A列は比較用です
セルの書式設定を呼び出します。
ゼロの数でゼロ埋めの個数が決まります。
0000: 123→ 0123 00000: 123→00123
今回は、0 を6つ書きました。
では、最大桁数より少ないゼロの数を指定したらどうなるでしょうか。
結果は次のようになります。
一度書式を指定したら、次から、ユーザー定義に出現します。
そこから選ぶのが速いでしょう。
ユーザー定義書式に名前をつけられたいいのにな。
数字のゼロ埋め 00123 のように記載するのは、文字列と数値をごっちゃにするので、あまりよろしくないのですが。
何がよろしくいかというと、数字であるところを、文字列にしてしまう方がいらっしゃいます。
さら悪いことには、ごっちゃにする方々への予防策のために、担当者が「うちでは0埋めを採用しない」とか「0埋めをみたら文字列だと思え」などと、謎なローカル・ルールが誕生してたりします。
声の大きいひとの意見が通るのは良くないですよね。理性的に行動してほしい。
セルの値を「数字」としてあつかい、表示の書式設定で0を補って数字を書式表示するのが正しい。
プログラミングを習ったことがある人だと printf(%06d, 134 )
のような printf による書式を考えてしまいがちです。
しかし、ExcelのVBAには GNU bash のような 組み込み printf も、C言語のような stdio による printf もありません。
Excelにはエクセルの流儀があり、プログラミングの世界にはプログラミングの流儀があがります。
私はプログラマなので、これをExcel異世界だと思うようにしています。プログラミングとExcelの世界は似ていますが、違いますね。
「郷に入れば郷に従え」の通り、あれこれローカルルールや独自基準をつくらず、素直な解決方法を受け入れるようにしたいです。
*1:今どきの呼び方をするなら、UI/UXでしょうか
ALTER TABLE "TABLE_NAME" add constraint "your_name_of_constraint_key" uniq ("COLUNM_NAMES");
ALTER TABLE "TABLE_NAME" drop constraint "your_name_of_constraint_key" uniq ("COLUNM_NAMES");
docker コンテナ側からインターネットへのネットワークの疎通を確認する。
今回は、なぜか、通信ができなかったので、エラーになる。いきなり発生したので原因を探っておく。
docker run busybox ping -c 1 8.8.8.8
これは、docker のコンテナを起動してpingを起動して実行する。
こんどは、docker コンテナからインターネットへのDNS名前解決を確認する
takuya@:docker run busybox ping -c 1 t.co
今回は、ここでエラーになっていた。
takuya@:~$ docker run busybox cat /etc/resolv.conf nameserver 192.168.11.111
あ・・・ホストのDNS設定そのままコピーされてるやん
そうなんですね、Dockerのネームサーバーの設定は、ホストからコピーされることがあります。
DNS の設定は、docker ホスト側のresolv.confに従うが、私のサーバーのresolve.conf は localhost の unbound を見に行く。
そのため、ホスト側のDNSと同じ設定が適用されるのだが、これが必ずしも使えるとは限らない。
takuya@:bwdata$ ip addr show docker0 5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:58:e2:8b:63 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:58ff:fee2:8b63/64 scope link valid_lft forever preferred_lft forever
私の場合、次のようなdocker0 ネットワークインターフェースが存在するので、このIPレンジからの問い合わせに答えてあげなくていはいけない。
access-control: 172.17.0.1/16 allow_snoop ## docker network
今回は、私のホスト側に設定している dns サーバーがIPアドレス制限を行ってたのでapt に失敗してた。
takuya@:~$ docker run --dns=8.8.8.8 busybox cat /etc/resolv.conf nameserver 8.8.8.8
dokcer のホスト側にdocker のオプションを書きところがあり、そこの記述を追記してあげれば固定できる。
takuya@:~$ sudo cat /etc/docker/daemon.json { "dns": ["8.8.8.8"] }
上記の方法を試すなど、として様子を見てみるのもいいだろう。
takuya@:~$ cat /etc/resolv.conf nameser 127.0.0.1
ホスト側がlocalhostを参照しているので、docker コンテナにこのままコピーされると詰む、なので、
takuya@:~$ docker run busybox cat /etc/resolv.conf nameser 8.8.8.8
この場合、127.0.0.1をコピーすると詰むので、docker のコンテナには、8.8.8.8 が自動で設定されるのかもしれない。
VPN を接続したときだけメニューバーに表示してくれればいいのに、VPNを使わないときもVPNメニューがでてくるのは邪魔だよね。
メニューバーの項目は、defaults で設定値を取り出せるんです。
takuya@menubar$ defaults read com.apple.systemuiserver menuExtras ( "/System/Library/CoreServices/Menu Extras/Clock.menu", "/System/Library/CoreServices/Menu Extras/Battery.menu", "/System/Library/CoreServices/Menu Extras/TextInput.menu", "/System/Library/CoreServices/Menu Extras/User.menu", "/System/Library/CoreServices/Menu Extras/TimeMachine.menu", "/System/Library/CoreServices/Menu Extras/AirPort.menu", "/System/Library/CoreServices/Menu Extras/Volume.menu", "/System/Library/CoreServices/Menu Extras/Bluetooth.menu" )
これを使えば、書き込むことも可能でしょ。欲しい物だけ、トグル出来たら便利なので。
VPNメニューのボタンアイコンって、ダサいんですよ。
特に工夫もなく、思いつくままに書き加えたコードがこちら。
import ast import subprocess import argparse from pprint import pprint as pp def toggle_vpn_menu( enable=True ): vpn_menu = '/System/Library/CoreServices/Menu Extras/VPN.menu' ret = subprocess.check_output("defaults read com.apple.systemuiserver menuExtras", shell=True, universal_newlines=True) menus = ast.literal_eval(ret) vpn_menu_exists = any([vpn_menu in e for e in menus]) if vpn_menu_exists and enable is False : # disable ## menus = [x for x in menus if not vpn_menu in x] cmd = 'defaults write com.apple.systemuiserver menuExtras -array '.split() + menus subprocess.check_call(cmd) ## cmd = "killall SystemUIServer -HUP".split() subprocess.check_call(cmd) return if not vpn_menu_exists and enable is True: # enable menus = list(menus) menus.append(vpn_menu) cmd = 'defaults write com.apple.systemuiserver menuExtras -array '.split() + menus subprocess.check_call(cmd) ## cmd = "killall SystemUIServer -HUP".split() subprocess.check_call(cmd) def main(): parser = argparse.ArgumentParser(description=u'VPNメニューをオンオフする。') parser.add_argument('-e ', '--enable', action="store_true", help=u'有効化') parser.add_argument('-d ', '--disable', action="store_true", help=u'無効化') args = parser.parse_args() if args.enable: toggle_vpn_menu(True) else: toggle_vpn_menu(False) if __name__ == '__main__': main()
` '/System/Library/CoreServices/Menu Extras' `` にある該当メニューをダブルクリックして開くだけで、表示だけならできる。
"open '/System/Library/CoreServices/Menu Extras/VPN.menu'"
nginx でドメインをキャッチオールして、別サーバーのnginx へ丸投げする、多段nginx の設定を書いていたら、80 だと動くんだけど、443 で動かない。
listen 443 ssl https default_server
をつけると動かなくなる件
Chrome で接続すると、次のようになる。
SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET
原因がわからず結構苦労した。
SNI かと思ったけど、どうも違う。SSLのセッションチケットが変わってしまうようです。
これは動くんですが、
listen 80 http default_server listen 8080 http default_server
ssl をつけると動かない。
listen 443 ssl http2 default_server listen 8443 ssl http2 default_server
nginx の メインの設定( server { } 外)に 次の設定を書いて、既存のSSLのセッションを無視するようにする。
ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets off;
SSLのセッションはChromeが管理していて、以前の接続と違うSSLが開始したら、MITMとか?エラー検出してるんだと思う。
そういえば、default_server と server で使ってる証明書は別でした。
https://community.letsencrypt.org/t/errors-from-browsers-with-ssl-session-tickets-off-nginx/18124/5
ファイルとして取り出せるんです。
ショートカットをファイルとして保存することができ、中身を閲覧することが出来ます。中身は plist です。plitul などで中身編集することも出来ます。
テキストファイルにしておけば、git でバージョン管理に突っ込めるし、
Javascriptについては、MacやPCでぱぱっと編集ができるぞ
ショートカットをファイルとして保存する歩法。
コレクションから、保存したいショートカットを開きます。
保存先には iOS Files に対応したアプリや NextCloud、Evernoteや Google Drive など、
手っ取り早いのは、AirDropで作成されたファイルをMacに送ること。
あれ、これできるってことは、bookmarklet を iOSショートカット変換が、すぐできるんじゃ。
次を参照のこと。
s3互換ストレージminio をインストール(2021版) - それマグで!
s3 の設定をいちいちするのはめんどくさいので、使い捨ての s3 が欲しくなる。
minio というS3と同様のオブジェクトストレージが使えるサーバを使って、開発コスト(時間設定金銭)を下げてしまえ。
MASTER_KEY=$( cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1 ):$(openssl rand -hex 32) docker run -it -e MINIO_SSE_MASTER_KEY=$MASTER_KEY restart=always -p 127.0.0.1:4569:9000 minio/minio server /data
ちなみに 4569 は fakes3 と合わせてある。
docker-compose に含めて、オブジェクトストレージ使い捨てのエミュレーションならdockerで十分
オブジェクトストレージを自分で運営しようとすると、docker でもいいけど、フロント側でサーバー起動したほうが楽かもしれない。
サーバーのバイナリをとってきて、起動するのがいい。
/usr/bin/curl -LJO https://dl.min.io/server/minio/release/linux-amd64/minio chmod +x ./minio MASTER_KEY=$( cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1 ):$(openssl rand -hex 32) export MINIO_SSE_MASTER_KEY=$MASTER_KEY ./minio server /var/www/virtualhosts/path/storage --address 127.0.0.1:4569
こうしておけば、サービスとして動かせるので、S3の代わりにデータをどんどん放り込んでいける。
ただしmino にs3の完璧は互換性は無いし、ファイルのバージョニングなどの機能はないから注意が必要。
ここで AccessKey と Secret Keyを取得しておく
ブラウザで( 今回は 127.0.0.1:4569:9000) にアクセスすると、なんとWebUIが使える。
これは評価高い。
nginx でプロキシして、公開サーバとして使ってもいいと思う。
systemd 起動する minio.service
[Unit] Description=minio サーバーのインスタンス [Service] WorkingDirectory=/var/www/minio ExecStartPre=/bin/bash update-minio.sh ExecStart=/var/www/minio/minio server /var/www/minio/storage --address 127.0.0.1:4569 ## 定期的に再起動して最新版を取得する Restart=always RuntimeMaxSec=864000 [Install] WantedBy=network-online.target
sudo systemctl daemon-reload sudo systemctl start minio sudo systemctl status minio
systemdで起動しても、もともとがwget で取得したバイナリなので、定期的にアップデートする必要がある。 apt で更新できる *.debが公開されてればよかったんだけどね。提供されてないようなので、自分で更新チェックをすることにした。どうせ1ファイルだし。
定期的に再起動しつつ、定期的にminio のサーバーバイナリを取得する
#!/usr/bin/env bash cd /var/www/minio server_shas=$(curl -s https://dl.min.io/server/minio/release/linux-amd64/minio.shasum | cut -d' ' -f 1 ) local_sha=$( sha1sum minio | cut -d' ' -f 1 ) if [[ ! -e minio ]] || [[ $server_shas != $local_sha ]] || (( $(( $(date +%s) - $(date -r minio +%s) )) > $(( 60*60*24*30 )) )); then /usr/bin/curl -LJO https://dl.min.io/server/minio/release/linux-amd64/minio chmod +x ./minio fi
s3 互換ということなので、s3cmd のような s3 管理ツールからオブジェクトストレージとして使ってみる。
brew install s3cmd
設定ファイルを作っておく
[default] host_base = 127.0.0.1:4569 host_bucket = 127.0.0.1:4569/%(bucket)s bucket_location = us-east-1 use_https = True access_key = HEDXXXXXXXXXXXXXXXXXXXXX secret_key = cenXXXXXXXXX+XXXXXXXXXIkKe7LrqA signature_v2 = True
takuya@.config$ s3cmd -c ~/.config/minio mb s3://sample Bucket 's3://sample/' created
ファイルをアップロードする
takuya@.config$ s3cmd -c ~/.config/minio put -r /Users/takuya/Pictures/EAWBB3YUEAEmkOl-1.jpg s3://sample upload: '/Users/takuya/Pictures/EAWBB3YUEAEmkOl-1.jpg' -> 's3://sample/EAWBB3YUEAEmkOl-1.jpg' [1 of 1] 53125 of 53125 100% in 0s 388.63 kB/s done
バケットの中身を確認する。
takuya@~$ s3cmd -c ~/.config/minio ls s3://sample 2019-08-29 03:27 53125 s3://sample/EAWBB3YUEAEmkOl-1.jpg
サイトにURLとして埋め込んで、アクセスキーなしにバケットを閲覧(HTTP/GET)しようとするには、管理画面でバケットのポリシーを設定するか,
公開ポリシーをs3cmd などで設定する必要がある。
minio でAWS S3 にいちいちクレジットカードを登録しなくても、Amazon S3を使ったサーバーアプリケーションを使ったり、開発ができる。
クレジットカードの登録を経理通すとかめんどくさいし、ぱぱっと試せてるのは強いと思う。
今回は、試すというより、S3なくてminioでもういいじゃんってこと思ったので、S3をエミュレーションして永続ストレージとして使うような感じにした。
バージョニングとかgracier のようなバックアップなどは使えないが、分散ストレージは出来たりするので結構面白いソフトウェアなんじゃないかな
開発中のモックアップとしてはminioは大きすぎるのでfakes3のほうがいいかなと思った
このファイルが、作成されてから何秒経過したか。それ知りたいことありませんか?
ファイルAがファイルBより古いときはファイルAを更新するとか
echo $(( $(date +%s) - $(date -r FILE +%s) ))
これだけです。かんたんですね
コマンドの、細かいところを一つずつ見ていきます。
まずは date コマンドで秒数を出す方法。これは現在のunix 秒が出ます。
date +%s
次に、ファイルの更新時刻を date の引数として指定してあげる。
date -r FILE
date -r FILE +%s
unix 秒が取れる なら、これを比較のために引き算して上げる必要があります。
echo $(( 100 -1 ))
ファイルが作られてから何秒(何時間)経過しているかが計算できる
echo $(( $(date +%s) - $(date -r FILE +%s) ))
ファイルが作成されてから1000秒経過してたら再起動するような条件分岐に使うことが出来ます。
(( $(( $(date +%s) - $(date -r FILE +%s) )) > 1000 )) && restart-server
(( $(( $(date +%s -r FILEA ) - $(date -r FILEB +%s) )) < 0 )) && echo old
Bashの記号については、過去記事を参考にしてください
man bash
nginx でアプリケーションへ reverse proxy してたんだけど、アプリケーション側にcontent-security-policy の設定が最新版のChromeと合わなかった。とくに blog/data
add_header で csp を追記しようとしたけど、セキュリティは全部OKから絞っていくほうが設定が楽。
なので、一旦全部許可しようと思ったんだけど、あれ除去ってどうやるんだよ。と気づいて調べたのでメモ
これでは、上書きにならない。あくまでついか
add_header content-security-policy '';
そこで、アプリケーションからのレスポンス中のヘッダを除去して応答を再生成することにした。
proxy_hide_header "content-security-policy";
これで、ブラウザに返すレスポンスから特定のヘッダを削除して見えなくすることができる。
ちなみに、proxy_set_header で空文字を与えても同じようなことはできるけど
proxy_set_header cache-control ''
こちらは空文字を送信するので完全に消えるわけじゃない。
ちなみに、proxy_ignore_headersと似たような名前の設定が他にもあるが、これは proxy - proxy 間で使われるヘッダ( X-REAL-IP のような ) を除去するものらしい。
上書きならセットをつかう。追加なら
proxy_set_header cache-control 'default ...' add_header cache-control 'image ...'
ヘッダの追加・削除、上書き(削除追加)でそれぞれちょっと工夫が必要
引数 -d に @11234567 をつけます。
takuya@~$ date -d @1566808184 +"%F %T" 2019-08-26 17:29:44
date コマンドはミリ秒を解釈しないので、いったんint へ数値計算してやる
takuya@~$ date -d @$((1566808184122/1000)) +"%F %T" 2019-08-26 17:29:44
数値計算の方法は、過去記事にあるので、そっちへ
bashの似てて紛らわしいもの (( / $(( - それマグで!
date コマンドでフォーマットの方法は、過去記事があるので。参照
dateコマンドでiso/rfc日付時刻タイムゾーンをぱぱっとフォーマットして作る - それマグで!
npm でインストールしたパッケージはどうも使い捨ての傾向があり、アップデートを継続するにはちょっと手間が必要で。
npm のサブコマンドを使えばできる
npm update npm outdated
これらのコマンドを実行して更新可能な最新版にアップデート可能なモジュールを見つけて更新していくわけだが。
めんどくさい。
npm-check-updates 略して、 ncu というパッケージがある。
これを使うと package.json の中身を更新してくれるわけで、便利そうである。
npm install npm-check-updates npx ncu -u npm update npm install
これで、一通りのアップデートが可能になる。思ってたより楽である。
開発者が想定したpackage.json を更新するのである。当然であるが、依存モジュールをアップデートすると、decrepcated なメソッドやバージョン差異による動作不良に悩まされることもあるので注意が必要である。
which コマンドを使うと 環境変数 PATH にあるコマンドのうち、最初に見つかったもの(実行されるもの)を表示してくれます。
which python
どのコマンドが実行されるのか調べるのに便利ですし、よく使ってると思います。
pyenv や nvm や rbenv などを使っていると、あれ?バージョンが合わない?パスがおかしい????
などという事がよくあります。
こういうときにPATHに含まれる全てのもの列挙できたらと思いませんか
コマンドがいくつも同じ名前で入っている場合に、全てを表示してくれます。
表示順は、PATHの優先順位が高い順に表示してくれます。
takuya@-api$ which -a grep /Users/takuya/.bin/grep /usr/bin/grep
takuya@-api$ which -a java /usr/bin/java
takuya@-api$ which -a python /Users/takuya/.pyenv/shims/python /usr/local/bin/python /usr/bin/python
これをすることで、 python が同名でいくつもあることがわかったり、$PATHに同じパスが重複していたり、bashrc や pipenv shell などで .bashrc の意図した動作にならない。 順序がおかしくなっていることに気づくことができます。
https://takuya-1st.hatenablog.jp/entry/2017/04/06/153337
systemd で作ったサービスを定期的に再起動したい。
定期的に再起動する必要があるのか。と問われれば、私自身も答えに窮するのだけれど。
今回は pip install しているpython パッケージや npm run で起動している元になっている npm/node_moduleを、定期的更新して再起動をしたいなと思ったんですよ。
[Service] Restart=always RuntimeMaxSec=864000
unit ファイルに上記のように書くと定期的に再起動がかかる。
RuntimeMaxSec=60
RuntimeMaxSec をつけることで、サービスのプロセスの継続実行時間を秒単位で指定できる。今回は 60*60*24*10 = 864,000
を指定した。
Restart=always
Restart の設定を alwaysにしておくと、サービスに定義したプロセスが異常終了など、終了したときに自動再実行によりプロセスが起動している状態を維持してくれる。
これらを組合わたら、定期的に再起動のコマンドが実現する
[Service] Restart=always RuntimeMaxSec=864000
組み合わせてしまうと、指定時間経過後にプロセスが終了して、always により再度サーバーが実行される。
crontab に書いてしまうと、管理がsystemd と分かれてしまうのであまり好ましくないし。
サーバーが自分を自分で再起動するように sleep を使った定期的に再起動が仕込まれた起動用python スクリプトを書くのは煩雑すぎるし。
systemd の timer を使っても、設定が2つに別れてしまって面倒だ。
今回採用した方法だと、設定ファイルが1つにまとまるので書き捨てて仕様書を残さなくても気付けるメリットが有る。
systemd の設計者は、こういう利用は想定外なんだろうと思うんだけど、1箇所に必要な設定が集まるのは嬉しい
npm でパッケージをいれて、npm run で動かせるサーバーアプリケーションがおおいけど、パッケージはlock されて基本的には更新を考慮してない。
debian の apt などは セキュリティ・パッチが含まれた deb などをaptの設定自動的にダウンロードして再実行してくれる。ほんとうにこの差は大きいと思う。
gitlab とは自動的に自分で自分を更新してくれるし、そういう意味で node のnpm で作られたサーバーって今後危ういなぁなどと思う。
再起動するサービスと、タイマー、この2つのユニットを分けて書くときは、ネットにいっぱいサンプルが転がってる。
うちのサイトでの作成サンプルは、この記事でtimer/serviceのunits を使ってsystemdのユニットを定期的に起動している。
分ける場合のサンプル → https://takuya-1st.hatenablog.jp/entry/2020/04/09/051239
分ける場合のtimer の書式 → https://takuya-1st.hatenablog.jp/entry/2020/04/24/032822
再起動スクリプト+Service+Timer+タイマ書式の4つが必要になる。こういうことを考えるのが面倒なので再起動がすぐ終わるServiceなら今回紹介しているMaxTimeによる再起動が楽だと思うの。