2021年11月8日月曜日

PHP ip2longの罠

cakePHPのサーバー運用も多くやってますが、もっぱら cakePHP3.9 で作業することが多いです。
担当外の cakePHP1.2で構築されたサーバーくんのトラブルに駆り出されてみたので、そのお話です。

機器との接続がうまく行かないと言われましてですね。
機器は MySQLのテーブルに IPアドレス が記録されていまして、それを読み込んでアクセスしているわけです。

php には、ip2long(), long2ip() という関数が用意されていて、IPアドレスを整数値に変換したり逆に整数値をIPアドレスの文字列に変換できたりするわけで
データベースに文字列でIPアドレスを格納するよりも数値で格納しておく方が効果的なので、よく使われます。

たとえば、192.168.3.20 というIPアドレスを変換してDBに格納する場合は Windows10標準の電卓でHEX入力するといい。
192=C0, 168=A8, 20=14 なので、HEX(16進数)入力で C0A80314 と入力すると、DEC(10進数)部分に 3,232,236,308 が表示される。
DBには、この値 3232236308 を入れてしまえばいいわけ。

しかしだ。
動いてくれないのだよ。
なぜじゃ!?

ローカルに環境を構築する暇なんてなかったので、なかなかデバッグしづらい環境だったけど、原因を突き止めました。


Windows電卓は64bit演算なのですよ。
ターゲットの環境は32bit環境。

2148483647(0x80000000)以上の数値は long なので負数になるべきなのだYO!

ということで、2の補数を使って負数に変換しなきゃいけない。
64bit環境上に、こんなプログラムを作ってみました。

<?php
/*
    ip2long 32bit 処理
*/
$half = ip2long('128.0.0.0');   // 2148483647

$msg = '';
if(isset($_GET['ip']))
{
    $ip = $_GET['ip'];
    $long = ip2long($ip);
    if($half <= $long)
    {
        //MSB が1
        $long = ($long ^ (16 ** 8-1)) + 1;
        $long = 0 - $long;
    }
    $msg .= 'ip:' . $ip . ' value:' . $long;
}
?>

<HTML>
<BODY>
    <DIV>
        <?= $msg ?>
    </DIV>
</BODY>
</HTML>

https://seasoft.co.jp/bin/ip2long32.php で実際に動作できます。
2の補数なんて久しぶりに使ったから、ちょっと時間かかちゃったよ笑


めでたし、めでたし。

A4横 CSS(スタイルシート) の landscape がうまく行かない

「A4横」左図の帳票レイアウトを作成して印刷しようとしたら、横幅が狭く表示されてうまく行きませんでした。

WEBサイトを検索すると、あちこちにこうすればできると書いてある。

ちなみに、bootstrap5 を使ってレイアウトしてます(帳票なのでレスポンシブは考慮してない)

@page {
    size: A4 landscape; 
    size: 297mm 210mm;
    margin: 0mm;
}

A4横に、なるにはなるんだけど、コンテンツの横幅がどう見ても狭い。
A4縦の時の横幅を超えない(程度の)横幅でしか印刷されない・・・・
なぜじゃ!?

いろいろ調べたり、調べてもらったりして bootstrap がまずいことがわかりました。
(Hさん、ご協力、ありがと。)

bootstrap の次の部分が影響してましたよ、と。

.container, .container-lg, .container-md, .container-sm{
 max-width: 960px;
}

以下のようにスタイルシートを追記すると、ちゃんとA4横で印刷されるようになりました。

@media print {
    .container {
         max-width: 297mm !important;
    }
}


めでたし、めでたし。