【AWStats】レポート更新時にセレクトボックスがリセットされる現象と対処法

# はじめに
オープンソースのアクセス解析ソフトAWStatsを利用した際、「1桁の日付を選択してレポートを更新するたびに、日付のセレクトボックスが1に戻ってしまう」という現象に困っていました。
ところが、ネットで調べてもそれらしい解決方法が見当たらなかったので、Perlに一切触れたことがありませんでしたが自力で原因を特定して修正してみました。
同じような現象で困っている方のお力添えになれればと思い、記録として残します。

AWStatsのバージョンは7.9です。

# 結論

レポートページを生成する`awstats.pl`の`10172行目`を以下のとおり書き換えたところ、解決しました！

```diff_perl:awstats.pl
# 10172行目
- . ( $DayRequired eq "$_" ? " selected=\"selected\"" : "" )
+ . ( $DayRequired == "$_" ? " selected=\"selected\"" : "" )
```

# 原因特定までの道のり

optionタグのselected属性がうまいこといっていないのはすぐに分かったので、該当部分のコードを確認してみました。

```pl:awstats.pl (10164行目~)
if (	$DatabaseBreak eq 'day' || 
        $DatabaseBreak eq 'hour') {
    if (!$DayRequired) {
        $DayRequired = $nowday; 
    }
    print "<select class=\"aws_formfield\" name=\"day\">\n";
    foreach ( 1 .. 31 ) {
        print "<option"
          . ( $DayRequired eq "$_" ? " selected=\"selected\"" : "" )
          . " value=\"$_\">$_</option>\n";
    }
    print "</select>\n";
}
```

optionタグにselected属性を付与するかどうか判断しているのはこの部分です。

```pl
foreach ( 1 .. 31 ) {
    print "<option"
      . ( $DayRequired eq "$_" ? " selected=\"selected\"" : "" )
      . " value=\"$_\">$_</option>\n";
}
```

1～31の数値のうち、`$DayRequired`という変数と合致する場合にselected属性が付与されるようですが、どうやら全てfalseになっているようです。

変数名からして選択した日付が代入されているのでしょうが、なぜfalseになるのでしょう。。。

```pl
$DayRequired = $nowday;
```
数行上を見てみると、`$DayRequired`には`$nowday`という変数が代入されています。

じゃあその`$nowday`って何だ？ということで探してみると、

```pl:awstats.pl (17303行目~)
# Change format of time variables
$nowweekofmonth = "0$nowweekofmonth";
if ( $nowweekofyear < 10 ) { $nowweekofyear = "0$nowweekofyear"; }
if ( $nowyear < 100 ) { $nowyear += 2000; }
else { $nowyear += 1900; }
$nowsmallyear = $nowyear;
$nowsmallyear =~ s/^..//;
if ( ++$nowmonth < 10 ) { $nowmonth = "0$nowmonth"; }
if ( $nowday < 10 )     { $nowday   = "0$nowday"; }
if ( $nowhour < 10 )    { $nowhour  = "0$nowhour"; }
if ( $nowmin < 10 )     { $nowmin   = "0$nowmin"; }
if ( $nowsec < 10 )     { $nowsec   = "0$nowsec"; }
$nowtime = int( $nowyear . $nowmonth . $nowday . $nowhour . $nowmin . $nowsec );
```

ありました。

```pl
if ( $nowday < 10 )     { $nowday   = "0$nowday"; }
```

日付を2桁に揃えるため、1桁の場合はゼロパディングしているようです。
ということはつまり、1桁の場合は`$nowday`は文字列になります。

ここで先ほどの三項演算子を見てみると、比較演算子に`eq`を使用しています。

```pl
$DayRequired eq "$_" ? " selected=\"selected\"" : ""
```

調べてみたところ、Perlの比較演算子には、数値での比較と文字列での比較を行うものがあるようです。

|数値比較演算子|文字列比較演算子|意味|
|---|---|---|
|A == B|A eq B|AとBは等しい|
|A != B|A ne B|AとBは等しくない|
|A > B|A gt B|AはBより大きい|
|A >= B|A ge B|AはBより大きいか等しい|
|A < B|A lt B|AはBより小さい|
|A <= B|A le B|AはBより小さいか等しい|

したがって、例えば日付を「2」に指定した場合は、`$DayRequired = "02"`と1～31の数値を文字列として比較することになり、三項演算子はfalseとなってしまいます。

どちらも数値として比較してあげればよいので、

```diff_perl
- . ( $DayRequired eq "$_" ? " selected=\"selected\"" : "" )
+ . ( $DayRequired == "$_" ? " selected=\"selected\"" : "" )
```

このように修正してあげればよいという訳でした。

# ちなみに

日付だけでなく、時間のセレクトボックスも同様の現象が起きていたので、同じように修正しました。

```diff_perl:awstats.pl (10178行目~)
if (	$DatabaseBreak eq 'hour') {
    if (!$HourRequired) {
        $HourRequired = $nowhour; 
    }
    print "<select class=\"aws_formfield\" name=\"hour\">\n";
    foreach ( 0 .. 23 ) {
        print "<option"
-         . ( $HourRequired eq "$_" ? " selected=\"selected\"" : "" )
+         . ( $HourRequired == "$_" ? " selected=\"selected\"" : "" )
          . " value=\"$_\">$_</option>\n";
    }
    print "</select>\n";
}
```

以上、お役に立てれば幸いです。