読者です 読者をやめる 読者になる 読者になる

NHK の受信料収入と契約件数の推移

先日、ワンセグ携帯を所有した場合に NHK の放送契約を結ぶ義務があるかどうか裁判が行われたというニュースがあった。放送法64条の「受信設備を設置」に電話の「携帯」の意味を含めるのは「無理がある」として NHK は敗訴。

NHK(および総務省)が受信料の取り立てを強化したい背景として、都市部の若者を中心に受信料の未払いが増えているという説をよく耳にする。実際のところどうなのか、NHK の公表する決算書から受信料収入と契約数を調べてみた。

すると2001年度から2015年度までの受信料収入は横這いで、契約数は増加している傾向が見て取れた。契約数の増加は衛星契約の増加によるものが大きい(衛星契約を含まない地上契約は減少)。ここ数年に限って見れば、衛星契約の増加とともに受信料収入も増加している。

この結果には、契約数の減少が危機的だという印象があったため驚いた。

調査用に作成したデータ

Windows 上で .htpasswd を生成する

Apache において Basic 認証のユーザ名とパスワードを管理する .htpasswd ファイルは、LinuxFreeBSD, OS X では htpasswd コマンドで実行できるが、実は Windows 版の Apache にも同様のプログラムが含まれている。
そのプログラムは、Apache をインストールしたディレクトリの bin 以下にある。XAMPP でインストールした場合は通常 C:/xampp/apache/bin/htpasswd.exe にある。
使い方は htpasswd コマンドと同じで、たとえば .htpasswd を新規作成する場合は次のコマンドで行える。

> C:\xampp\apache\bin\htpasswd -c \path\to\.htpasswd ユーザ名
New password: ******** (パスワードを入力)
Re-type new password: ******** (同じパスワードを再度入力)
Adding password for user ユーザ名

こうすることで \path\to\.htpasswd にパスワードファイルが生成される。

主な使い方

パスワードファイルを新規作成する (-c)。すでにファイルがある場合は以前の内容は消去される。

htpasswd -c パスワードファイル ユーザ名

既存のパスワードファイルにユーザ名とパスワードの組み合わせを追記する。このとき引数は不要。

htpasswd パスワードファイル ユーザ名2

パスワードをコマンドライン引数として渡す (-b)。バッチ処理の際に使用する。

htpasswd -cb パスワードファイル ユーザ名 パスワード

テストのため、ファイルに書き込まず、標準出力に結果を出力する (-n)。

htpasswd -n パスワードファイル ユーザ名
htpasswd -nb パスワードファイル ユーザ名 パスワード

ハッシュアルゴリズムの指定

パスワードは通常、MD5 アルゴリズムでハッシュされる。変更するには次のオプション引数を指定する。

-m  MD5 アルゴリズムを使用する(デフォルト)
-B  bcrypt アルゴリズムを使用する(より安全)
-d  CRYPT アルゴリズムを使用する
-s  SHA アルゴリズムを使用する
-p  パスワードを平文で保存する

たとえば bcrypt を使用し、パスワードファイルを新規作成する場合は次のようになる。

htpasswd -cB パスワードファイル ユーザ名

Basic 認証の設定

Basic 認証は Apache の設定ファイルに次のように書くことで適用できる。通常 httpd.conf(あるいはそこから読み込まれる設定ファイル) の <Directory>〜</Directory> セクションまたは、Basic 認証を適用したいディレクトリの .htaccess に書く。

AuthUserfile /path/to/.htpasswd
AuthGroupfile /dev/null
AuthName "Please enter your ID and password"
AuthType Basic
require valid-user

.htpasswd のパスはフルパスで書く必要があることに注意。

NewsDigest の短縮URL ndjust.in を経由させない

NewsDigest(株式会社JX通信社運営)という Android/iOS アプリからシェアしたリンクは、 ndjust.in で始まる転送用アドレスを経由するよう変換される。
この ndjust.in には Google Analytics が設定されているのみだが、気持ち悪いので直接元のページに移動するようにしよう。


ここではローカルで Apache を動かしている場合の設定方法を説明する。
まず /etc/hosts (Windows の場合は通常 C:/Windows/System32/drivers/etc/hosts) に次の記述を行い、 ndjust.in へのアクセスをすべてローカルの Apache へ向ける。

127.0.0.1	ndjust.in

次にバーチャルホストの設定を行うが、他のサイトや書籍を参考にしてほしい。その際、次のような設定を行い、mod_rewrite を用いてすべてのアクセスを /index.php へ向け、GET パラメータ _url に短縮 URL の ID を格納するようにする。

RewriteRule ^(.*)$ index.php?_url=$1 [L]

そして移動先ページの URL を取得するスクリプトは次のようになる。自動でのリダイレクトはしないようにした。

<?php
// コンソールでのテスト用
$path = isset($_GET['_url']) ? $_GET['_url'] : '6zMYUOOtsI';

$addresses = array(
	'54.192.233.19',
	'54.192.233.62',
	'54.192.233.93',
	'54.192.233.116',
	'54.192.233.173',
	'54.192.233.187',
	'54.192.233.191',
	'54.192.233.244',
);
$protocol = 'http://';
$host = 'ndjust.in';
$timeout = 5;

$headers = array(
	'Host: ' . $host,
	'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
	'Accept-Encoding: gzip,deflate',
	'Accept-Language: ja,en-us;q=0.7,en;q=0.3',
	'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0',
);

shuffle($addresses);
$url = $protocol . $addresses[0] . '/' . $path;

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_NOBODY, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
curl_close($ch);

$redirectTo = null;
if (preg_match('{<a href="(https?://.*?)" id="destination">}', $data, $matches)) {
	$redirectTo = $matches[1];
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>NewsDigest 経由のリダイレクト警告</title>
</head>
<body>
<?php if ($redirectTo) : ?>
<p>次の URL へリダイレクトしようとしています</p>
<p><a href="<?= htmlspecialchars($redirectTo) ?>"><?= htmlspecialchars($redirectTo) ?></a></p>
<?php else : ?>
<p>リダイレクト先が見つかりません</p>
<?php endif; ?>
</body>
</html>

以上で NewsDigest からシェアされたリンクに安心してアクセスできる。


Windows で PNG 画像を最適化するドロップレットを作る

PNG 画像の画質をあまり落とさずにファイルサイズを最適化するサービスとして TinyPNG というものがある。画像形式や内容によって最適な圧縮をかけてくれるところは便利だが、いちいちダウンロードして再配置する必要があるので手間がかかる。
私が主に TinyPNG を使用したい場面は、アルファチャンネルを持つ PNG 画像を PNG-24 から PNG-8 にしたい場合だ (現在の Photoshop ではアルファチャンネルを持つ PNG-8 の出力に対応していないため)。そこでアルファチャンネルを持つ PNG-8 の出力のみに対応したドロップレットを作ることにした。

ドロップレットの作成

TinyPNG では内部的に pngquant というツールが使われているようなので、これを用いる。

まずこのページから「Binary for Windows (v2.7.2)」をダウンロードし、適当なディレクトリに展開する。
そして pngquant.exe と同じディレクトリに Optimize PNG.bat という名前でファイルを作成する。内容は付属の Drag PNG here to reduce palette automatically.bat を参考にした。

@echo off

set path=%~d0%~p0

:start

"%path%pngquant.exe" --force --verbose --ordered --speed=1 --quality=50-90 --ext "-new.png" %1
rename %1 "%~n1.orig%~x1"
rename "%~d1%~p1%~n1-new%~x1" "%~n1%~x1"

shift
if NOT x%1==x goto start

最後に使いやすい場所、たとえばデスクトップに、このバッチファイルへのショートカットを作成する。アイコンや名前を変えておくと分かりやすい。

ドロップレットの使い方

PNG 画像を最適化するには、ファイルをドロップレットにドラッグ & ドロップする。
すると元のファイルは 〜.orig.png という名前に変更され、最適化されたファイルが元のファイル名となる。
ファイルは複数選択できるが、ディレクトリ内のすべての画像を処理する、といった使い方はできない。また PNG 以外のファイルを指定した場合、もとのファイルの名前を変更してしまう。今後の課題としたい。

オープンソースの家計簿 Economizzer をレンタルサーバにインストールして使う

Economizzer は PHP + MySQL で動作する、オープンソースの家計簿 Web アプリ。集計のグラフがちょっとかっこいい。

機能はいたってシンプルで次のことができる。

  • 収入・支出項目の追加・変更・削除・検索
  • 費目カテゴリの管理
    カテゴリは必ず2層にする必要がある(たとえば「教養娯楽費 > 旅行代」というカテゴリを設定して、費目には必ず下層の「旅行代」を設定する)
  • ログイン認証
  • ユーザの追加
    複数のユーザを作成し、1ユーザにつき1家計簿のみ管理できる
  • レスポンシブデザインで、スマートフォンタブレット、PC どの端末からでも使いやすい
  • CSV, TSV, Excel 形式でのエクスポート

現金や銀行口座といった資産の管理機能はないので、月々のお金の流れだけ分かればいいという方におすすめ。

Economizzer のインストール

パッケージは用意されていないので Github から開発版をダウンロードする。現在でも更新が続けられているようで、以下の内容は変更されている可能性がある。
作者によるドキュメントに従い、次のコマンドを実行する。

git clone https://github.com/gugoan/economizzer.git
cd economizzer
composer global require "fxp/composer-asset-plugin:~1.1.1"
composer install

このままだとエラーが出たので少し調べてみた。--no-plugins オプションを試してみるとうまくいくようだ。

composer global require "fxp/composer-asset-plugin:~1.1.1" --no-plugins
composer install

次に MySQL のユーザとテータベースを作成する。

mysql> CREATE USER economizzer_user@localhost;
mysql> SET PASSWORD FOR economizzer_user@localhost=PASSWORD('パスワード');
mysql> CREATE DATABASE economizzer DEFAULT CHARACTER SET utf8;
mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER ON economizzer.* TO economizzer_user@localhost;
mysql> FLUSH PRIVILEGES;

続いて economizzer/config/db.php を編集し、データベースの設定を行う。

<?php
return [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=127.0.0.1;dbname=economizzer',
    'username' => 'economizzer_user',
    'password' => 'パスワード',
    'charset' => 'utf8',
    'enableSchemaCache' => true,
];

データベース定義と初期データを設定するため、次のコマンドを実行する。

./yii migrate

なお、このスクリプトで初期化できる RDBMSMySQL のみなので注意。
ここまでの手順が完了すれば Economizzer が使えるようになる。設定した URL を開き、User: joe / Password: 123456 でログインするとテストデータを見ることができる。

レンタルサーバに設置する

Economizzer は Github からクローンしてきた状態ではデバッグデータを残すようになっている。サーバに設置する際には economizzer/web/index.php の次の2行をコメントアウトする。

defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

日本語化する

見慣れた日本語の方が良かったので、次のファイルを変更して部分的に翻訳した。興味がある方は全てのメッセージを完全に訳して本家にコミットしてほしい。

  • config/web.php(選択できる言語を追加する)
  • messages/ja/app.php(他の言語からコピー)
  • messages/ja/user.php(他の言語からコピー)
  • views/cashbook/index.php(日付フォーマットを Yii::t() に通す)
  • views/cashbook/view.php(日付フォーマットを Yii::t() に通す)
  • views/user/register.php(選択できる言語を追加する)

views/cashbook/index.php, view.php において日付をローカライズするヒント。「’16 7/6」という表示にしたくて DataView::widget() のパラメータで format を ['date', '’y n/j'] のようにすると、年の値が想定している下二桁ではなく4桁で表示されてしまう。スマートではないが次の書き方で対処した。

<?php
...
[
    'value' => Yii::$app->formatter->asDate($model->date, 'php:'.Yii::t('app', 'F j, Y')),
],
...

SQLite3 で動かす

レンタルサーバでは MySQL のデータベースをバックアップすることに不安があるので、代わりに SQLite3 を使い、定期的にデータベースファイルをバックアップすることにした。
MySQL から SQLite3 へのデータ移行は次のページを参考にした。

また、Economizzer では SQL 文を手動で生成している部分があるが、ここに MySQL 独自の関数が含まれているため、一部うまく動作しないところがあった。ここはデータベースシステムによって振り分けることにする。
まずは PHP で SQLite3 を使っているかどうかを判定する関数を用意する。

function UU_isSQLite3() {
	global $config;
	static $isSQLite3;
	if (!isset($isSQLite3)) {
		$isSQLite3 = strpos($config['components']['db']['dsn'], 'sqlite:') === 0;
	}
	return $isSQLite3;
}

そして、MySQL 独自の関数を使用している controllers/DashboardController.php において、判定関数の結果によりクエリを振り分ける。
関数の書き換えは次のようにした。日付関数はデータベースシステムによりまちまちだが、IF 関数に関しては SQL99 標準の CASE 文に置き換えることで MySQL にも対応できる。

MONTH(date) = $thismonth AND YEAR(date) = $thisyear
→ STRFTIME('%Y-%m', date) = '$thisyear-$thismonth'

MONTHNAME(date)
→ STRFTIME('%m', date)

YEAR(date) = $thisyear
→ STRFTIME('%Y', date)

IF(cashbook.type_id = 1, value, 0)
→ CASE WHEN cashbook.type_id = 1 THEN value ELSE 0 END