bbPress

bbAttachments で IPv6アドレスから画像が投稿できない

2013年2月3日

image

bbPress をローカルの Windows 8 上で動かしている場合、bbAttachments で画像を投稿した時に上記のように、画像が出てこなくなった。
デバックした結果、環境依存で、IPv6のアドレスから投稿していると認識された時にこのエラーが起きる事がわかった。投稿者のループバックアドレスの「::1」が見えている。

結構、苦労したので作業をメモ。

エラーの原因

エラーの原因は、以下の inet_aton という名前の関数の部分がエラーになったせいで、以下の INSERT 文が上手く動かないのが原因だった。
Debug は、あちこちに Debug 文を入れて、正常に動いてないこの SQL を突き止めた後、phpMyAdmin の管理画面から、実際に失敗している SQL 文を入力して SQL文のどこがエラーになっているか確認した。

$failed=$bbdb->get_var("
INSERT INTO ".$bb_attachments['db']." ( time  , post_id , user_id, user_ip, status , size , ext , mime , filename )
VALUES ('$time', '$post_id' ,  '$user_id' , inet_aton('$user_ip') , $status, '$size', '".addslashes($ext)."', '$mime', '".addslashes($filename)."')
");

IPを DBに格納する際のお作法

MySQL では、IP Address を VARCHAR で、文字列でDBに格納するとスペースが持ったいないので、INT型に変更して格納する事ができるようだ。
MySQL では、inet_aton もしくは inet_ntoa という関数が用意されている。この関数が今回のエラーポイントだった。関数仕様については以下のサイトが詳しかった。

ATON || NOTA ? Ip address IPV4 ? IPV6 ?

※inet_aton( )  の aton は、Address to Numeric Numberの略のようだ(12.16. Miscellaneous Functions)。

IP address を渡すと、人間では読めない数字列に変換される。人間が読める IP Address に戻すには、inet_ntoa( ) を使う。この関数は MySQL 5.6.3 から追加されているとある(INET6_ATON(expr))。残念ながら MySQL をアップグレードできないので、inet_ntoa の使用は断念。INT型での格納は諦めてVARCHAR で格納する事にする。

PHPで IPv6 を String 変換する

MySQLが古くSQL文の中で変換(inet_ntoa) できないので、PHP側で変換してからSQL文に代入する事にする。
PHPでは、inet_pton という関数が使えるようだ。IPv4 と IPv6 の両方に対応だが、戻り値はバイナリ形式になる。

string inet_pton ( string $address )

この関数は、人間が読める形式の IPv4 あるいは IPv6 (PHP が IPv6 サポートを有効にしてビルドされている場合) のアドレスを 32 ビットあるいは 128 ビットのバイナリ形式に変換します。

PHP: inet_pton - Manual

bb-attachments-init.php を変更する。

まず変換したバイナリの IP アドレスを格納するために bb_attachments テーブルに 「user_ip_bin (varchar (16))」を追加した。
IPv6の場合は、128bit バイナリという事で、8で割り算して 16Byte あれば足りるかな・・という事で、VARCHAR(16)にしてみた。

image

コードは bb-attachments-init.php の INSERT文周辺をざっくりと消して以下のように書き換えた。
ただし、テストはループバックアドレス(::1 だけしかテストしていないので、それ以外だと動かないかも。

 

// IP`v4 の場合と IPv6の場合で、処理を分割
if (strpos($user_ip, '.') !== FALSE) {     # ipv4
$int_ipv4=ip2long($user_ip); // user_id 列が integer で定義されている。
    $user_binip=inet_pton($user_ip);
}elseif(strpos($user_ip, ':') !== FALSE) {     # ipv6
$int_ipv4="0"; // dummy numeric because of "user_ip" column is defined as "not NULL".
    $bin_ip=inet_pton($user_ip); // IPv6 is converted to 128 bit binary.
}

// データのINSERT

$sql="INSERT INTO ".$bb_attachments['db']." ( time  , post_id , user_id, user_ip, user_ip_bin, status , size , ext , mime , filename )
VALUES ('$time', '$post_id' ,  '$user_id' , $int_ipv4, '$bin_ip', $status, '$size', '".addslashes($ext)."', '$mime', '".addslashes($filename)."')";
$failed=$bbdb->get_var($sql);

-bbPress

Copyright© エンジニアの何でもメモ帳 , 2024 All Rights Reserved.