2011年04月25日

iptableのチェインの途中にルールを差し込む

既に動いてるiptableの途中に新しくルールを差し込む方法。
INPUTにルールを追加する場合の例:
# /sbin/iptables -n -L INPUT --line-number
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 RH-Firewall-1-INPUT all -- 0.0.0.0/0 0.0.0.0/0
 INPUTチェインを見ると、RH-Firewall-1-INPUTチェインを参照しているので、そっちを見る。
# /sbin/iptables -n -L RH-Firewall-1-INPUT --line-number
Chain RH-Firewall-1-INPUT (1 references)
num target prot opt source destination
1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
2 ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmp type 255
3 ACCEPT udp -- 0.0.0.0/0 0.0.0.0/0 udp dpt:53
4 ACCEPT udp -- 0.0.0.0/0 0.0.0.0/0 udp dpt:445
5 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:53
6 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
7 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
8 DROP all -- 0.0.0.0/0 0.0.0.0/0
 リストの番号を見て、入れたい番号を見る。例えば、6番の次に192.168.0.0/16から3306番宛tcpを追加する時は、
# /sbin/iptables -I RH-Firewall-1-INPUT 6 \
-m state --state NEW -m tcp -p tcp --dport 3306 -s 192.168.0.0/16 -j ACCEPT
# /sbin/iptables -n -L RH-Firewall-1-INPUT --line-number
Chain RH-Firewall-1-INPUT (1 references)
num target prot opt source destination
1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
2 ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmp type 255
3 ACCEPT udp -- 0.0.0.0/0 0.0.0.0/0 udp dpt:53
4 ACCEPT udp -- 0.0.0.0/0 0.0.0.0/0 udp dpt:445
5 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:53
6 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
7 ACCEPT tcp -- 192.168.0.0/16 0.0.0.0/0 state NEW tcp dpt:3306
8 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
9 DROP all -- 0.0.0.0/0 0.0.0.0/0
 こんな具合。
 一時的なものでないなら、追加した後忘れず /etc/sysconfig/iptables あたりにも追加して、リブートしても忘れないようにしておくのがよい。
タグ:Linux 管理
posted by usoinfo at 10:47 | Comment(0) | 開発 | このブログの読者になる | 更新情報をチェックする

2011年04月23日

PEAR::HTTP_Client で普通のPOSTでも multipart/form-data にする

 HTTP_Client->post() では、4番目の引数にファイルを指定すると、自動的にマルチパートのPOSTデータを作成してmultipart/form-dataで投げてくれる。逆に言うと、2番目の引数のPOSTデータだけを渡した場合は、リクエストボディにname=value&name=value&...のデータが入れて投げられるので、multipart/form-data にはならない。
 
 あまり需要はないと思うが、ファイルでなく普通のPOSTデータだけを渡して、リクエストを multipart/form-data にしたい時は、こうである。
		$client = new HTTP_Client();
$header = array('Content-Type' => 'multipart/form-data');
$client->setDefaultHeader($header);
$resp = $client->post($url,$data);
 要するにContent-typeヘッダを強制的にmultipart/form-dataにセットしてやれば、勝手にマルチパートなリクエストになるという寸法である。例えば、送出データがメモリ上の変数内にあってテンポラリファイルに落としたくないとき、などに使えないこともない、かもしれない。
タグ:PHP PEAR Linux
posted by usoinfo at 15:03 | Comment(0) | 開発 | このブログの読者になる | 更新情報をチェックする

2011年04月22日

PHPで multipart/form-data でPOSTされた生データを取得する

 PHPでは、php://inputのストリームをオープンすることで、HTTPのリクエストボディを生データのまま取得できる。これで、PHPが文字コードをいじったり、デコードしたりして、意図しない操作をデータに加えていると思われるとき、デバッグに有効である。しかし、そこのドキュメントにも書いてあるように、「php://input は、 enctype="multipart/form-data" に対しては使用できません。」である。フォームからのファイル投入の時などに、生データを取ってデバッグしようとすると、ちょいと困る。
 そこで、このPHPの挙動をバイパスして、multipart/form-data の生データを取得する方法。

 これは結局の所、リクエストのContent-typeを見て、Content-type: multipart/form-data の時にそのようになっている。なので、受け取ったリクエストが multipart/form-data だったら、そのContent-typeを引っぺがしてやればいい(その代わり $_FILES は使えなくなると思うけど)。
 .htaccess(または環境によってhttp.confでも)に、こんな感じで引っぺがすSetEnvIfをくべてやる。
SetEnvIf content-type (multipart/form-data)(.*) MULTIPART_FORMDATA=true
RequestHeader unset content-type env=MULTIPART_FORMDATA
 しかる後、PHP側で
	$stdin = fopen('php://input', 'r'))
while(!feof($stdin)){
echo fgets($stdin, 1024);
}
fclose($stdin);
 こんな感じで、ストリームからPOSTの生データが取れる。
タグ:PHP Linux HTTP
posted by usoinfo at 11:30 | Comment(0) | 開発 | このブログの読者になる | 更新情報をチェックする

2011年04月07日

納豆を作る

 地震から1ヶ月、未だ入手困難なものがある。納豆である。
 納豆生産量第1位は茨城県、納豆消費量第1位は福島県。震災の影響がセントラル納豆エリアを直撃なわけで、地震後の品薄も仕方ないことと諦めていたが、それ以降、時間が経ってもなかなか供給が回復しない。ひとつには計画停電のせいもあるようである。納豆は発酵食品で、納豆菌の繁殖に適した温度を保つには、電気が必要であろうと推測される。興味がなかったので気にしてなかったが、ヨーグルトも品薄である。乳酸菌発酵の温度管理を節電と計画停電が直撃らしい。むべなるかな。
 納豆の入荷がないではないのだが、スーパーの店頭では「1家族1パックまで」の規制がかかり、その上、開店1時間後でもう既に売り切れている。開店直後に行けば、なんとか1つ手に入る、そんな状況である。

 納豆を食わなくても直ちに健康に影響はないが、手に入らないとなると逆にどうしても食いたくなる人間の浅ましさ。万やむを得ず、納豆、自分で作ってみた。


必要なもの
  • 大豆
  •  買ってあった大豆を使うことにした。やや大粒。納豆には小粒の大豆がよいというが、この際贅沢は言わない。元々、豆もやしを栽培しようとして挫折したやつ(北海道産とよまさり)である。宮城産のミヤギシロメも結構安い。
  • 圧力鍋
  •  納豆を作るには大豆が柔らかくなるまで煮るか蒸すかしなければならないが、常圧で5時間も6時間も加熱してられない(ガス的な意味に於いても)。ということで、圧力鍋を使うのがお勧めだろう。安いのでいいのである。
  • 金属製ザル
  •  圧力鍋で蒸すときに使う、鍋の内側に収まるサイズのザル。あるいは金属製の裏ごし器でも可。100円ショップで適当なのを調達可。
  • なるべく薄いアルミ缶
  •  圧力鍋中の金属製ザルを底上げするのに使う。ベコベコして安い輸入品コーラの缶など、ハサミで切れるような奴が加工しやすくてよい。
  • 発泡スチロールの箱
  •  発酵過程で保温するのに使う。なにやら、ヨーグルトメーカーがよいという話もあるが、そんな結構なものはうちにはない(し、あっても電気を使っては残念)。魚屋さんが使ってるようなやつでいいし、あるいはレジャー用のクーラーボックスでも代用可。
  • 蓋の閉まる空き缶
  •  湯を詰めて保温容器に入れる。湯たんぽの如く保温しようという作戦である。ホットドリンクのペットボトルでもいいかもしれない。熱湯でも壊れない密閉容器ならなんでもいい。
  • 平たい感じの容器
  •  タッパーでいいと思われる。納豆菌の繁殖に空気が必要なので、あまり縦方向に豆が密集しないように、平たいタッパーがオススメらしい。
  • タネになる納豆菌を取る納豆
  •  冷凍でもいいし賞味期限切れでもいいし、わりと納豆なら何でもいい。納豆菌は相当過酷な環境でも死なないので、古い奴でもOKである。なかったら、仕方ないので、開店直後のスーパーで1コ買ってくるしかない。

作り方
IMG_7338s1.jpg
ステップ1
大豆100gを水につけて一晩置く。豆が水を吸って丸々すればよろしい。吸水すると、だいたい乾燥状態の2〜2.5倍にふくらむ。

IMG_7338s1.jpg
ステップ2
大豆を圧力鍋で蒸す。蒸し用の器具がないので、アルミ缶を5〜6センチの高さに切った輪っか状のものを置き、水を注いで、その上にザルに入れた大豆を置いた。鍋を強火に掛け蓋とおもりをして蒸気が上がったら、おもりがゆっくり回転するくらいの中弱火に加減する。20分ほど蒸したら火を止め、そのまま自然に圧が抜けるまで10分程放置。

IMG_7338s1.jpg
ステップ3
蒸し上がった大豆を平たい容器に入れる。タネになる納豆を数粒取って、お湯(蒸した奴の残り湯)を大さじ半分ほど掛けてよくまぜ、豆のぬめりを湯に移す。充分ぬめりが湯に移ったら、この湯を蒸した大豆に振りかけ、全体にまんべんなくまぜる。圧力鍋に残った湯とぬめりを取ったタネ納豆は、後で味噌汁にすると、うまい。

IMG_7338s1.jpg
ステップ4
保温用のスチロールの箱に、新聞紙やプチプチ梱包材などを敷いて、大豆のタッパーを置く。湯を沸かし、空き缶に詰め、蓋をして、納豆の周りに置く。大豆タッパーの蓋は、しめずにちょっと開けておく。スチロールの箱をちょっと開くように蓋をして、発酵過程に突入。金属缶に湯を詰めるときは一杯まで詰めること。冷却して体積が縮むので湯量が少ないとへっこんで曲がったところから穴が開き水漏れが発生する。

IMG_7338s1.jpg
ステップ5
入れた湯の量にもよるが、容器内の温度はだいたい50℃弱くらいになり、徐々に冷え、12時間くらいで室温と同じになる。なので、12時間に1回くらいの間隔で(適当でいい)、空き缶の湯を取り替えつつ、2日ほど発酵させる。すると、うっすら白く納豆菌が繁殖して、ねばっと糸を引くようになる

IMG_7338s1.jpg
ステップ6
発酵が終わったら、タッパーに蓋をして冷蔵庫にいれ、1日程置き、完成。お好みの薬味を入れて食うべし



 いろいろと各種パラメータ調整の末に、納豆らしいものができるようになった。モノが発酵食品だけに、パラメータを変えると言ってもイニシャライズしてから完成までの時間が長いので、フィードバックを掛けるのが大変である。大体、納豆菌の適切な発酵温度は42℃でその温度に容器を保温しろと言うが、保温の基本は密閉であって、暖気が逃げないようにするのが第一である。一方、納豆菌は好気性細菌で空気が必要だということで、外気との入れ替えが必要である。矛盾である。どうしろって感じである。

 そして、最大の問題は、これだけ労力を投入して出来上がった納豆よりも、いつも買っていた4個1パック80円の水戸納豆の方がおいしいという事実である。
 納豆メーカーの早期の被害からの復旧を心から願って已まない。
タグ:自作
posted by usoinfo at 12:02 | Comment(0) | 工作 | このブログの読者になる | 更新情報をチェックする

2011年04月04日

MySQL 5.5 ではDATE型とDATETIME型の比較結果が異なる

 端的に言うと、今までは日の00:00:00を指したDATETIME値と同日のDATE値は等しかったが、5.5.x では異なる。
 今までのMySQLでは、
mysql> SELECT CAST( DATE(SYSDATE()) AS DATETIME ) = CAST( DATE(SYSDATE()) AS DATE )
AS datecomp;
+----------+
| datecomp |
+----------+
| 1 |
+----------+
 結果は真だが、MySQL 5.5.10 では、
mysql> SELECT CAST( DATE(SYSDATE()) AS DATETIME ) = CAST( DATE(SYSDATE()) AS DATE )
AS datecomp;
+----------+
| datecomp |
+----------+
| 0 |
+----------+
 同じSQL文でも結果は偽である。

 これは、DATE型とDATETIME型を比較するときの暗黙の型変換に仕様変更があったということか。
 以前のMySQLでは、DATE型と、同日の'00:00:00'の時刻を持つDATETIME型は同じ値だった(DATE型がDATETIME型に暗黙に変換される時、'00:00:00'を加えられていた)が、5.5.xでは、違う値として処理される。
 次のようなSQLを実行してみると、
5.5.10
mysql> SELECT CAST( DATE(SYSDATE()) AS DATETIME ) > CAST( DATE(SYSDATE()) AS DATE )
AS test;
+------+
| test |
+------+
| 1 |
+------+

5.0.77
mysql> SELECT CAST( DATE(SYSDATE()) AS DATETIME ) > CAST( DATE(SYSDATE()) AS DATE )
AS test;
+------+
| test |
+------+
| 0 |
+------+
 となるので、DATE型がDATETIME型に暗黙に変換される場合、'00:00:00' より小さい時刻の値で埋められるように変更されたのではないだろうか(ドキュメントは軽くしか読んでないけどどっかに書いてあるかも)。

 DATE() 関数で日付の切り捨てをしていたりするプログラムは、注意を要する。
 今までと同じ結果を得るためには、CAST() で明示的にDATETIME型に変換してやる必要があるようである。
CREATE TABLE datetest (
idnum INTEGER,
tdate DATETIME,
CONSTRAINT pk_datetest PRIMARY KEY (idnum)
);
INSERT INTO datetest (idnum,tdate)
VALUES(1,STR_TO_DATE('2011/04/04','%Y/%m/%d'));
INSERT INTO datetest (idnum,tdate)
VALUES(2,STR_TO_DATE('2011/04/04 12:00:00','%Y/%m/%d %H:%i:%s'));

-- 5.0.77の場合 SYSDATEは11/04/04 07:00:00
mysql> SELECT * FROM datetest WHERE tdate <= DATE(SYSDATE());
+-------+---------------------+
| idnum | tdate |
+-------+---------------------+
| 1 | 2011-04-04 00:00:00 |
+-------+---------------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM datetest WHERE tdate <= CAST( DATE(SYSDATE()) AS DATETIME );
+-------+---------------------+
| idnum | tdate |
+-------+---------------------+
| 1 | 2011-04-04 00:00:00 |
+-------+---------------------+
1 row in set (0.00 sec)

-- 5.5.10の場合 SYSDATEは11/04/04 07:00:00
mysql> SELECT * FROM datetest WHERE tdate <= DATE(SYSDATE()); -- 5.0.77と違う結果が返される
Empty set (0.00 sec)

mysql> SELECT * FROM datetest WHERE tdate <= CAST( DATE(SYSDATE()) AS DATETIME );
+-------+---------------------+
| idnum | tdate |
+-------+---------------------+
| 1 | 2011-04-04 00:00:00 |
+-------+---------------------+
1 row in set (0.00 sec)
タグ:Linux MySQL
posted by usoinfo at 07:31 | Comment(1) | 開発 | このブログの読者になる | 更新情報をチェックする

2011年04月01日

LVMを使って既存のext3パーティションをオンラインリサイズ

 昨今のLinuxは、インストール時にパーティショニングをおまかせモードにすると、/boot 以外をLVMで作ってくれる。LVMを使われると、所謂パーティションツールで特定のところだけを移植したりするときに軽く困るのでわざと使わないこともあるのだが、LVMを使っているとそれはそれで便利なときもある。例えば、/ が足らない時。
 例えば、/dev/hda1が/boot、/dev/hda2がLVM、/dev/hda3 がFAT32、みたいなマシンがあって、こんな感じにファイルシステムが埋まってしまったとする。
% df -h
Filesystem サイズ 使用 残り 使用% マウント位置
/dev/mapper/VolGroup00-LogVol00
38G 36G 1.1G 95% /
/dev/hda1 99M 25M 70M 26% /boot
/tmpfs 501M 0 501M 0% /dev/shm
/dev/hda3 60G 20G 39G 33% /export/fat
 一昔前なら/をでかく取っておけば良かったと後悔後の祭りになるが、LVMだとオンラインで領域を追加できる。例えばこの時に、hda3のパーティションを潰して、/を拡張しみよう、ということである。
 おおざっぱに言うと、LVMパーティションを追加してPV作成->VGにPVを突っ込んで拡張->LVを拡張->ファイルシステムを拡張、という操作が必要である。

 まずfdiskでhda3を潰し、Linux LVMパーティションを確保する。IDは0x8e。d -> 3 -> n -> p -> 3 -> [RET] -> [RET] -> t -> 3 -> 8e -> w だ。
 こんなパーティションテーブルになった。
デバイス Boot      Start         End      Blocks   Id  System
/dev/hda1 * 1 13 104391 83 Linux
/dev/hda2 14 4864 38965657+ 8e Linux LVM
/dev/hda3 4865 12161 58613152+ 8e Linux LVM
 これで追加するLVMパーティションが確保できたので、これを既存のLVMに追加する。
 最初に、pvcreateでPVを作り、LVMパーティションを使えるようにする。
# pvcreate /dev/hda3
Physical volume "/dev/hda3" successfully created
# pvdisplay /dev/hda3
"/dev/hda3" is a new physical volume of "55.90 GB"
--- NEW Physical volume ---
PV Name /dev/hda3
VG Name
PV Size 55.90 GB
Allocatable NO
PE Size (KByte) 0
Total PE 0
Free PE 0
Allocated PE 0
PV UUID i3iHBK-Lm4l-wIR1-iKBl-gFlJ-063G-kDI9nM
次に、/ が入っているVGである VolGroup00 に、今作ったPVを追加する。VGを見るコマンドはvgdisplay。追加前は
# vgdisplay
--- Volume group ---
VG Name VolGroup00
System ID
Format lvm2
Metadata Areas 1
Metadata Sequence No 3
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 2
Open LV 2
Max PV 0
Cur PV 1
Act PV 1
VG Size 37.16 GB
PE Size 32.00 MB
Total PE 1189
Alloc PE / Size 1189 / 37.16 GB
Free PE / Size 0 / 0
VG UUID JOT4c8-pOkz-hVtX-Aprl-fOol-Ow01-EgeRfl
(以下略)
だったところに、vgextendで追加する。
# vgextend VolGroup00 /dev/hda3
Volume group "VolGroup00" successfully extended
# vgdisplay VolGroup00
--- Volume group ---
VG Name VolGroup00
System ID
Format lvm2
Metadata Areas 2
Metadata Sequence No 4
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 2
Open LV 2
Max PV 0
Cur PV 2
Act PV 2
VG Size 93.03 GB
PE Size 32.00 MB
Total PE 2977
Alloc PE / Size 1189 / 37.16 GB
Free PE / Size 1788 / 55.88 GB
VG UUID JOT4c8-pOkz-hVtX-Aprl-fOol-Ow01-EgeRfl
 VGサイズが拡張されたので、VGの中にあるLVの拡張を行う。LVを見るコマンドはlvdisplay。拡張前は
# lvdisplay
--- Logical volume ---
LV Name /dev/VolGroup00/LogVol00
VG Name VolGroup00
LV UUID rJeiKe-4a8g-52sS-nAwu-Yeah-z9wx-U2C5tm
LV Write Access read/write
LV Status available
# open 1
LV Size 35.19 GB
Current LE 1126
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 256
Block device 253:0
(以下略)
だったところに、lvresizeで追加する。
# lvresize -L +58G /dev/VolGroup00/LogVol00
Extending logical volume LogVol00 to 35.19 GB
Logical volume LogVol00 successfully resized
# lvdisplay
--- Logical volume ---
LV Name /dev/VolGroup00/LogVol00
VG Name VolGroup00
LV UUID rJeiKe-4a8g-52sS-nAwu-Yeah-z9wx-U2C5tm
LV Write Access read/write
LV Status available
# open 1
LV Size 91.06 GB
Current LE 2914
Segments 2
Allocation inherit
Read ahead sectors auto
- currently set to 256
Block device 253:0
(以下略)
 次がようやく最終段階。/ のファイルシステムをリサイズ。ext3 なら、resize2fsでオンラインのまま拡張できる(resize2fsは結構時間が掛かる)。
# resize2fs -p /dev/mapper/VolGroup00-LogVol00
resize2fs 1.39 (29-May-2006)
Filesystem at /dev/mapper/VolGroup00-LogVol00 is mounted on /; on-line resizing required
Performing an on-line resize of /dev/mapper/VolGroup00-LogVol00 to 23871488 (4k) blocks.
The filesystem on /dev/mapper/VolGroup00-LogVol00 is now 23871488 blocks long.
# df -h
Filesystem サイズ 使用 残り 使用% マウント位置
/dev/mapper/VolGroup00-LogVol00
89G 24G 61G 28% /
/dev/hda1 99M 25M 70M 26% /boot
/tmpfs 501M 0 501M 0% /dev/shm
 とまあ、これでめでたく、/が拡張された。
posted by usoinfo at 10:52 | Comment(0) | 開発 | このブログの読者になる | 更新情報をチェックする

2011年03月30日

MySQL 5.5.x をソースからコンパイルしてインストール

 長らくMySQLは5.1.x系を使ってきたが、5.5.x系列も出てから1年程経って、マイナーバージョンも10になったので、そろそろ移行してもいいかなという気分になってきた。なんかマルチコアCPUでの性能が上がっているみたいだし。
 で、早速5.5.x系(今日の時点では5.5.10)のソースtarballをダウンロードしてきて、./configure;make しようと思ったのだが、、、、、アレ?configureがない。5.5.x は、今までとソースからのコンパイル方法が微妙に変わっていた。

 まず、コンパイルには cmake が必要。CentOSでは入ってないが、yumでRPMForgeから入れられる。(RPMForgeはこのへんからアーキテクチャに合ったrpmを導入)
 で、MySQLのソースをダウンロードして、ユーザーmysqlで展開。

 まずはコンパイルオプションを見る。
% cmake -LAH
-- MySQL 5.5.10
-- Configuring done
-- Generating done
-- Build files have been written to: /usr/local/mysql/src/mysql-5.5.10
-- Cache values
// path to the executable
ACLOCAL_EXECUTABLE:FILEPATH=/usr/bin/aclocal

// path to the executable
AUTOCONF_EXECUTABLE:FILEPATH=/usr/bin/autoconf
:
(略)
 5.1では、標準の文字コードをSJISで使っていたので、これもSJISでコンパイル。ついでにSSLもenableする。

% cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DWITH_SSL=system \
-DDEFAULT_CHARSET=sjis -DDEFAULT_COLLATION=sjis_japanese_ci
% make
 いくつかwarningは出たが、コンパイルは終了。今走ってる5.1を止めて、make installし、走らせる。ぱっと見、特に問題なく動いているようだ。
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 13
Server version: 5.5.10 Source distribution

Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
タグ:Linux MySQL
posted by usoinfo at 08:19 | Comment(0) | 開発 | このブログの読者になる | 更新情報をチェックする

2011年03月18日

ガーデンライトで室内補助灯

 停電に備えて、どこでも懐中電灯、乾電池は売り切れだそうである。停電でなくとも、家庭の照明は結構な量の電力を消費するらしいので、電気を消して小さな明かりにしておこう、というのもあるのだと思われる。

 懐中電灯も電池も増産されているそうだし当座に慌てる必要もないが、中長期的に節電の必要はあるので、そのために思うのは、ソーラーガーデンライト(こんなやつ)が実は優秀なアイテムなんじゃないかと思うのである。よくその辺のホームセンターでも売っている奴で、昼間に太陽光で充電して、夜になるとぼんやり光り始める、庭に置くやつである。

 こいつの構造は至って単純なもので、てっぺんに小さい太陽電池パネルがついていて、中に単3程度の充電池が入っていて、接着剤でくっついているだけのものである。何かの複雑な制御機構があるわけでもなく、自然なままに充放電を繰り返すという、電気製品とも呼べないようなものである。
 うちの部屋では、この太陽電池パネルだけを引きはがして窓際に置き、そこから電線を伸ばして(この電線もバラしたUSBケーブルの芯線を繋いだ廃品利用だが)部屋の中に置いたLED笠の中へ繋いでおいてある。すると、天気が良ければ昼間のうちに充電されて、陽が落ちてくると勝手にぼんやりLEDが灯り、電池がなくなれば勝手に切れる。翌朝はまた最初に戻る。

IMG_7258s.jpgIMG_7250s.jpg

 元々は、夜中にトイレに起きるときに電気をつけると目に刺さって痛いのが嫌だったために作った明かりである(なので経年劣化でだいぶ写真は汚い)。正直、照明の代わりになるほど明るくはない(この明かりで本は読めない)が、何しろ商用電源どころか電池も要らないし点けっぱなしにしても何らエネルギーの無駄な消費がないので、懐中電灯よりは省コストなのではないかと思うのである。光量が必要なら、もっとLEDの数か多い奴を使えばいいと思うし。

 節電の役に立てば幸いである。
タグ:節電
posted by usoinfo at 10:49 | Comment(0) | 工作 | このブログの読者になる | 更新情報をチェックする

2011年03月07日

逆ジオコーダーTwitter BOTを位置情報付きツイートに対応

逆ジオコーダーTwitter BOTを、位置情報を含むツイートに対応させてみた。

statuses/mentions で位置情報の緯度経度が取れないと思ったのは勘違いで、取れてはいたが、PHPのsimplexml_load_stringがXMLを処理するときに、うまく処理できていないらしくてデータが落ちていただけだった。
というわけで、JSONで取って、json_decode を使ったら、ちゃんと緯度経度が取れた。

携帯のツイッタークライアントから、位置情報を付加して @usogeo2addr に何か言うと、住所に変換します。
posted by usoinfo at 16:27 | Comment(0) | 開発 | このブログの読者になる | 更新情報をチェックする

2011年03月04日

PHPでHTTPのマルチパートレスポンスをデコードする

 HTTPでファイルアップロード等をするときは enctype="multipart/form-data" を指定してマルチパートのデータをPOSTするが、その逆バージョンで、HTTPサーバがマルチパートになったデータを返してきた時の処理。ブラウザがあんまり対応していないせいか、PHPのライブラリでデコード処理が用意されていそうでいて、そんなことはないようだ。
 PEARのライブラリに、MIMEのマルチパートメールをデコードするMail_MimeDecodeがあるので、これを流用することにする。

 マルチパートレスポンスと言っても、メールのマルチパートと構造はほぼ一緒で、バウンダリを含むContent-typeがレスポンスヘッダにあるので、ヘッダのContent-typeとレスポンスボディをくっつけて、Mail_mimeDecode::decodeに渡してやればいいわけだ。PEAR の HTTP_Client で取れば、HTTP_Client::currentResponse の返値に ['headers']['content-type'] があるので、これをそのまま使える。

 というわけで、こんな関数を用意して
require_once("Mail/mime.php");
function decode_multipart_httpresp($contenttype, $body)
{
$data['include_bodies'] = true;
$data['input'] = "Content-type: ".$contenttype."\r\n\r\n".$body;

$res = Mail_mimeDecode::decode($data);

$ret = array();
foreach( $res->parts as $i => $obj){
$ret[ $obj->d_parameters['name'] ] = $obj->body;
}
return $ret;
}
HTTP_Clientで取ってきたデータをくべてやる。
require_once("HTTP/Client.php");
$client = new HTTP_Client();
$rcode = $client->get('http://usouso.hogehoge/xxx/');
$resp = $client->currentResponse();
$ret = decode_multipart_httpresp($resp['headers']['content-type'], $resp['body']);
var_dump($ret);
HTTPサーバが返却したマルチパートレスポンスがこんな感じだったとすると
HTTP/1.1 200 OK
Date: Fri, 13 Feb 2011 06:51:44 GMT
Content-Type: multipart/mixed; boundary=HoNgErAbOuNdArY
Connection: close

--HoNgErAbOuNdArY
Content-Disposition: form-data; name="param01"
Content-Type: text/html; charset=utf-8

HTMLデータ....

--HoNgErAbOuNdArY
Content-Disposition: form-data; name="param02"
Content-Type: image/jpeg

JPEGデータ...

--HoNgErAbOuNdArY
Content-Disposition: form-data; name="param03"
Content-Type: application/json; charset=utf-8

{
"JSON":"データ"
}

--HoNgErAbOuNdArY--
デコードしたらこうなる。
Array
(
[param01] => HTMLデータ....


[param02] => JPEGデータ...


[param03] => {
"JSON":"データ"
}
)
ただ、細かいところは、状況に応じて変える必要はある。マルチパートじゃないレスポンスが来たときとか、マルチパートの中身を更にデコードするとか、パート毎のcontenttypeを取るとか。
posted by usoinfo at 10:48 | Comment(0) | 開発 | このブログの読者になる | 更新情報をチェックする