2011/06/15

php の proc_open() を利用した openssl コマンドの実行

php ネタ

openssl (1) で暗号化されたファイルを復号化する処理を php で実装する必要があった。
pear を探せばその手のモジュールは多分あるだろうと思ったが、 標準で含まれないモジュールに依存したくなかったので 外部コマンドの openssl を利用する方法を試してみた。

php では入力、もしくは出力のみの外部コマンド実行は popen() を利用できるが、 入出力双方向が必要なので proc_open() を利用する。
最初は proc_open() した openssl の入力側パイプに 暗号化されたデータを全て出力 (fwrite()) した後で 出力側パイプから復号化されたデータを読み出し (fread()) ていたのだが、 入力データがある程度のサイズを越えると openssl はデータ読込みの途中でデータを出力しないと 読込み (もしくは処理) をブロックしてしまう様なので、 fwrite() の後に fread() を実行する様に修正した。
この時、当初は stream_select() を利用してパイプの出力側からの 入力可否を監視する様にしたのだが、 stream_set_bloking() を利用してパイプの出力側を 非ブロックモードにする事で、 パイプから読込めない場合でも fread() が即リターンするので stream_select() の呼出しによりコードが煩雑になる事が避けられた。

  1<?php
  2    /*
  3     * Copyright (c) 2011 Mitzyuki IMAIZUMI. All rights reserved.
  4     *
  5     * $Id: decrypt.php 3 2011-06-16 16:15:48Z mitz $
  6     */
  7
  8    define("OPENSSL",    "openssl enc -d -des3 -pass pass:%s");
  9    define("BLOCSIZE",   "4096");
 10
 11    /*
 12     * ファイルの復号化
 13     *   $1: ファイル名
 14     *   $2: サイズ
 15     *   $3: パスフレーズ
 16     */
 17    function    decrypt($file, $size, $pass)
 18    {
 19
 20        $desc = array(
 21            0 => array("pipe", "r"),                /* stdin:  pipe */
 22            1 => array("pipe", "w"),                /* stdout: pipe */
 23            2 => array("file", "/dev/null", "w")    /* stderr: /dev/null */
 24        );
 25
 26        if(($fp = fopen($file, "r+"))){
 27            if($data = fread($fp, $size)){
 28                if(preg_match("/^Salted_/", $data)){
 29                    /* 暗号化されている場合 */
 30                    if($pp = proc_open(sprintf(OPENSSL, $pass), $desc, $pipe)){
 31                        /*
 32                         * `openssl enc -d …' を実行する。
 33                         *
 34                         * ファイルの内容はすでに $data に格納されているので
 35                         * BLOCSIZE 単位で openssl の標準入力に出力する。
 36                         */
 37
 38                        stream_set_write_buffer($pipe[0], 0);
 39                        stream_set_blocking($pipe[1], 0);
 40
 41                        $buf = "";
 42                        
 43                        while($size > 0){
 44                            /*
 45                             * 1 ブロック出力
 46                             * substr() は開始位置に負の値を指定すると
 47                             * 文字列の終端を起点とした開始位置からの
 48                             * 部分文字列が取得できる。
 49                             */
 50                            fwrite($pipe[0], substr($data, 0 - $size, BLOCSIZE));
 51                            $size -= BLOCSIZE;
 52                            /*
 53                             * openssl からの読み出し処理
 54                             * 非ブロッキングなので、
 55                             * 読めない場合は即座に fread() から戻る。
 56                             *
 57                            $buf .= fread($pipe[1], BLOCSIZE);
 58                        }
 59                        fclose($pipe[0]);
 60
 61                        while(!feof($pipe[1]))
 62                            $buf .= fread($pipe[1], BLOCSIZE);
 63                        fclose($pipe[1]);
 64
 65                        proc_close($pp);
 66                    }
 67                    /*
 68                     * 復号化したデータの出力
 69                     * 入力ファイルを書き換える
 70                     */
 71                    fseek($fp, 0);
 72                    ftruncate($fp, 0);
 73                    fwrite($fp, $buf);
 74                }
 75            }
 76            /* 暗号化されていない場合はそのまま close() する */
 77            fclose($fp);
 78        }
 79
 80    }
 81
 82?>
    

2011/06/16 追記

ブロック転送のロジックを整理して最適化した。
データサイズ $size をループの制御変数とする事で 余計な変数や転送ブロック数の計算を削除し、 openssl への出力データの部分文字列切り出し処理で substr() を利用する際に負の値を指定して 開始位置を文字列後端からの位置で指定する様に変更した。

2011/05/24

シェル変数への情報セット

例えば wget (1) コマンドへ proxy サーバの情報を伝えるためには http_proxy シェル変数に URL を http://[ID[:pass@]]FQDN[:port] 形式でセットする必要があるが、 proxy 情報が以下の形式でファイル格納されていれば 1 行で簡単にシェル変数に設定できる。

proxy.example.com                           # プロキシサーバの FQDN
8080                                        # プロキシサーバのポート番号
user                                        # プロキシサーバの認証 ID 
passwd                                      # プロキシサーバの認証パスワード
	
  1#!/bin/sh
  2
  3setproxy()
  4{
  5
  6    local   _var
  7
  8    _var=${1}
  9
 10    if [ -f ${2} ]
 11    then
 12        set -- `sed 's/#.*//g' ${2}`
 13        test -n "${1}" && eval "${_var}=\${1:+http_proxy=http://\${3:+\$3\${4:+:\${4}}@}\${1}\${2:+:\${2}}}"
 14    fi
 15
 16}
 17
 18setproxy http_proxy ファイル名
 19sh -c "${http_proxy} wget …"
 20    :
    

2011/05/22

レアチーズケーキ

遙か 15 年以上昔にバイト先で作っていたレシピを思い出しながら、 週末にレアチーズケーキを作った。
基本的なレシピはフィラデルフィアのクリームチーズに同梱されている リーフレットの通りに作るのだが、 いくつか独自の手順を加える事で格段になめらかな舌触りのチーズケーキになる。

Image: RIMG0253.JPG

ブルーベリージャムとブランデーをたらして

  1. ゼラチンは水と白ワインを同量混ぜたものに浸しておくと ゼラチンの持つ臭みが消える。
  2. ヨーグルトではなくサワークリームを使うと ほどよい上品な酸味となる。
  3. クリームチーズ、サワークリーム、そして砂糖を混ぜる時には 消える寸前のとろ火にかけてゆっくり加熱しながらよく混ぜる。
  4. 火を止めたらレモン果汁 1 個分を加えて更によく混ぜる。
  5. 生クリームを 6 分立て程度にホイップする。
  6. 冷ましたクリームチーズを裏ごしして生クリームに混ぜる。
  7. ゼラチンを湯煎して溶かしてクリームチーズに手早く混ぜる。
あとは型に流し込んで冷やせば美味しいクリームチーズケーキの出来上がり。
カシスやブルーベリーなどのジャムと、 風味付けに少量のブランデーをたらして召し上がれ。

2011/05/19

Mac でシリアルターミナル

ルータなどのネットワーク機器の設定を行う場合や、 ディスプレイを接続しないでサーバ運用しているマシンの作業など、 シリアル接続をする必要は少なくなったとは言えまだまだ作業する機会はある。
しかし Mac Book (というか現在発売している殆どの Laptop) には 既にシリアル端子などは装備されていないので、 USB シリアル変換アダプタを利用して接続する必要がある。

メーカーが公式に Mac 対応を表明しているアダプタもあるが、 手持ちの Arvel SRC06-USB は 利用しているチップセットのメイカー (Future Technology Devices International Ltd. 社) の Web サイト から Mac 用のドライバをダウンロードしてインストールすると 正しく利用できる様になった。
ドライバをインストールした後でアダプタを接続すると、 /dev/tty.usbserial-FTEHW36L というデバイスが自動で生成されたので、 このデバイスを利用して通信する事ができる様になる。

通信に利用するターミナルソフトは 標準でインストールされている cu (1) や screen (1) を利用するのが手軽だ。
screen (1) を利用する場合は以下の様に起動すると接続できる。 切断する時は コマンド文字+k を入力すればよい。

$ screen /dev/tty.usbserial-FTEHW36L 9600
    
ここでは指定していないがフロー制御やパリティチェックの有無、 ストップビット長などシリアル通信で必要と思われる設定は一通り指定できる。
普段からターミナルで screen (1) を利用している場合は ~/.screenrc defkanji utf などと記述してあるだろうが、 シリアル接続の相手が EUC や MS 漢字コードのなどの場合は ~/.screenrc に以下の記述をして コマンド文字+Eコマンド文字+U を入力する事で screen の表示コードが変更できるので便利だろう。
bind E encoding euc
bind S encoding sjis
bind U encoding utf
	

ファームウェアの転送など XMODEM を利用したファイル転送が必要な場合は、 内部で kermit (1) を呼び出して様々な転送処理が実行できる 多機能な通信端末 minicom (1) をインストールすると便利になると思う。

2011/05/18

Imperia Pasta Machine

遙か昔、当時創刊されたばかりの雑誌 Brutus に パスタマシンが掲載されているのを見かけて漠然と良いなと思っていたのだが、 30 年余の年月を経て念願かなって入手する事ができた。
昔の事すぎて詳しくは覚えていないのだが、 当時の金額で 10 万円ほどのプライスタグがついていて、 パスタマシンというのは非常に高価なものだと 30 年もの間 何の疑いもなく信じ込んでいた。
しかし改めて調べてみると意外と安いものだと気がついたので、 今回 Imperia 社製の自家製パスタマシンを購入してみた。

Image: RIMG0241.JPG

Imperial SP-150

ホームベーカリーのメニューにパスタ生地があるので、 デュラム小麦粉のセモリナを使えばパスタ生地が割と簡単に作れる。
とりあえず今週末は自家製のパスタでペペロンチーノを作ってみる予定なのだが、 今から出来上がりが楽しみでしょうがない。

2011/05/16

ナチューラ ヌメ革マウスパッド

土屋鞄製造所 で作成・販売している ナチューラ ヌメ革マウスパッド。

Image: RIMG0238.JPG

以前からずっと欲しいと思っていたのだが、 先日やっと注文できたものが週末に届いた。
植物性のタンニンで丁寧になめした革で作られたマウスパッドなので、 これから使い込むにつれて革の持つ風合いが 良い感じで出てくるだろうと思うと今からワクワクする。

同じ素材で Happy Hacking Keyboard 用の 30cm 幅の パームレストも是非作って下さい。

2011/05/13

ディスク容量のチェックツール

随分と時間が開いてしまったが、友人の awk (1) の勉強支援の第 4 段。 ディスクの容量をチェックして警告メイルを送信するためのスクリプト。

df (1) の内容を簡単に解析して、 ルートパーティションの使用率が指定した値以上の場合は警告メイルを送信し logger (1) を利用して syslog にも警告を出力する。

  1#!/bin/sh
  2#
  3#   All rights reserved, copyright (c) 2011, Mitzyuki IMAIZUMI
  4#   $Id: rdf,v 1.1 2011/05/13 17:38:09 mitz Exp $
  5#
  6
  7myname=${0##*/}
  8tmpfile=${TMP:-/tmp}/${myname}.$$
  9logger=/usr/bin/logger
 10df="LANG=C df -h"
 11
 12# 警告メイルの宛先
 13to=root@example.com
 14
 15# 警告処理
 16warning()
 17{
 18
 19    LANG=C
 20    subject="##### [ ${1}: Disk Usage ] #####"
 21    ${logger} "${subject}"
 22    cat << EOF | mail ${to} -s "${subject}"
 23
 24${1}
 25
 26`date`
 27
 28`cat ${2}`
 29EOF
 30
 31}
 32
 33# 終了時に一時ファイルを削除
 34trap 'rm -r ${tmpfile}; exit' 0 1 2 3 9 13 15
 35
 36# メイン処理
 37
 38# tee(1) を使って df(1) の出力を awk(1) と一時ファイルの両方に出力
 39${df} | tee ${tmpfile} |
 40    awk '{
 41        # 最後のフィールドが '/' の場合 (ルートパーティション)
 42        if($NF == "/")
 43            # 最後の直前のフィールドが使用率なので閾値との比較結果をリターン
 44            exit($(NF-1) < '${1:-70}')
 45    }' && warning `hostname` ${tmpfile}
    

2011/04/22

国立商店 オイルドレザースリーブ

普段から毎日持ち歩いている MacBook Air なので、 鞄の中で美しいアルミニュームボディーが傷ついたりしない様に 国立商店の職人が作るオイルドレザースリーブ を購入した。

Image: RIMG0232.JPG

職人が作るオイルドレザースリーブ

オイルドレザーなので持った時の肌触りがしっくりと手に馴染み、 内側に貼られた肉厚フェルトが MacBook Air をしっかりと保護してくれる感じで安心感がある。 国立商店の製品は以前購入した MacBook 13″ 用のケースに続き 2 個目となるので、 手元に届く前から品質と素晴らしさは信頼していたのだが、 改めて手に取るとその信頼を凌駕する程の製品でより一層嬉しくなる。

2011/04/20

MocBook Air

Image: RIMG0208.JPG

MocBook Air late 2010

以前白ポリカーボネート製の MacBook の名刺入れをお願いしたのだが、 MacBook Air を購入したのでそちらの分もお願いしていた物が届いた。

Image: RIMG0210.JPG

MacBook Air と MocBook Air

以前届いた MocBook と並べると最高に可愛くて素敵である。 MocBook のデスクトップは娘の誕生日でお願いしたので、 MocBook Air のデスクトップ画像は奥さんの誕生日にしてみた。 キーボードは勿論英語キーボードの画像に変更して頂けた。
MacBook Air は普段から持ち歩いているので MocBook Air 名刺入れも届いてからは毎日持ち歩いているのだが、 仕事柄人に会う機会が少ないので名刺交換も稀なので 自慢する機会が少ないのがちょっと悲しい(そこか)。

Image: RIMG0219.JPG

MocBook と MocBook Air

この様な素晴らしいアイテムを手作りで作成して頂けて非常に感謝している。
最近購入した MacBook Pro の分も是非欲しいなと思う今日この頃 (デスクトップは自分の誕生日にしよう♪)

残念ながら諸処の事情で当面新規の受付は中止しているとの事なので、 作者の方のお名前や Web ペイジの URL は伏せさせて頂く。

2011/04/19

Mac で簡易バックアップ

Mac は rsync (1) が標準で搭載されていて 簡単に差分転送する事ができるので、 簡易的なバックアップが手軽に実施できて便利である。

以下のコードはリモートサーバのディスクを samba 形式で mount (8) し、 rsync (1) で同期するためのスクリプト。
バックアップ先のディスクを samba 形式でマウントするので、 バックアップ先が Windows パソコンでも動作する。
Finder の共有から一度バックアップ先のディスクにアクセスして パスワードをキーチェーンに記憶させると、 以降はパスワードの問い合わせがなくなるので便利だろう。
バックアップ先が unix 系のサーバの場合であれば、 mount (8) しないで rsync (1) に 直接リモートサーバを指定しても良い。 その場合 -e オプションを指定して ssh (1) 経由で転送する事が望ましい。

  1#!/bin/sh
  2
  3# バックアップ対象(= バックアップ先ディレクトリ)
  4target="Pictures Music"
  5# バックアップ先サーバ
  6Server="<u>リモートサーバ</u>"
  7# バックアップ元ディレクトリを格納しておき eval(1) で展開する
  8Pictures="Pictures"
  9Music="Music/iTunes/iTunes Music"
 10
 11# "-f" オプションを指定しない場合は実際には転送しない
 12test "$1" = "-f" || dry=n
 13
 14for i in ${target}
 15do
 16    src="${HOME}/`eval echo '$'${i}`"
 17    dst="/Volumes/${i}"
 18    
 19    mkdir -p ${dst}
 20    mount -t smbfs //${Server}/${i} ${dst}
 21    rsync -avz${dry} --delete --exclude '._*' --exclude .DS_Store "${src}/" "${dst}"
 22    umount ${dst}
 23done
    


Copyright © 2008-2020 Mitzyuki IMAIZUMI. All rights reserved.