mPDF (5.7.4) はタイムゾーン設定を勝手に書き換えるので注意

HTML で書かれたコードから PDF を出力できる mPDF という PHP ライブラリがある。HTML と CSS を理解していれば思い通りに、とまではいかないまでも、それなりにレイアウトすることができる。

あるときこの mPDF を使っていたところ、出力される日時がずれてしまう問題が発生した。 date_default_timezone_set() を使ってタイムゾーンを設定しているのにおかしいと思い、コードを追いかけると mPDF を読み込む段階でタイムゾーン設定が書き換わっていることが分かった。

<?php
date_default_timezone_set('Asia/Tokyo');
echo date_default_timezone_get(); // => Asia/Tokyo

require_once '/path/to/mpdf.php';

echo date_default_timezone_get(); // => Europe/London

原因は mpdf.php の 54 行目に書かれている次の一文。

if (ini_get("date.timezone")=="") { date_default_timezone_set("Europe/London"); }

このコードではスクリプトタイムゾーンが設定されていても、ini ファイルにタイムゾーンの設定がなければ date_default_timezone_set("Europe/London") が実行されてしまう。もしタイムゾーンの設定がどこにもなければ PHP はデフォルトのタイムゾーンである UTC を使用するので、わざわざタイムゾーンを設定する必要はない。よって mpdf.php の 53〜55 行目をコメントアウトして使用する。

mPDF の GitHub プロジェクトでもこの問題がバグとして報告されている。

PostgreSQL でユーザとデータベースを新しく作る手順

備忘録。psql から行う。

# sudo -u postgres psql

または

> psql -U postgres

ユーザの作成

CREATE USER ユーザ名 WITH ENCRYPTED PASSWORD 'パスワード';

ユーザ一覧

SELECT * FROM pg_shadow;

ユーザの削除

DROP USER ユーザ名;

データベースの作成

CREATE DATABASE データベース名 OWNER ユーザ名 ENCODING 'UTF-8';

Swift でネットワーク状況を調べる

この記事は書かれてから1年以上経過しました。Swift の言語仕様や API の変更によって動作しない可能性があります

iOS アプリでネットワークへの接続状況を調べるとき、Objective-C では Tony Million による Reachability というライブラリが使用できた。

一方 Swift では IJReachabilityReachability.swift が使える。ここではネットワーク状況の変化を検出できる Reachability.swift を用いる。

ライブラリを使う準備

Reachability.swift から “Download ZIP” を選び、ライブラリをダウンロードする。

ダウンロードしたファイルを展開し、 Reachability.swift を AMReachability.swift にリネームする。さらに Xcode でこのファイルを開き、 “Edit All in Scope” を使ってクラス名を Reachability から AMReachability へ変更しよう。

こうするのは Tony Million のライブラリを使って App の審査に通らなかったという報告があるためだ。

WARNING there have been reports of apps being rejected when Reachability is used in a framework. The only solution to this so far is to rename the class.

https://github.com/tonymillion/Reachability

ライブラリをプロジェクトに追加する

ライブラリの使い方は簡単、先ほど作った AMReachability.swift をプロジェクトにコピーする。
画面左のファイル一覧に AMReachability.swift をドラッグすると、次のような画面が出るはずなので、“Copy items if needed” にチェックを入れ “Finish” を選ぶ。

Reachability.swift の使い方

使い方はいたって簡単。

単に現在のネットワーク状況を調べるときは次のようにする。

let reachability = AMReachability.reachabilityForInternetConnection()
if reachability.isReachable() {
	println("インターネット接続あり")
} else {
	println("インターネット接続なし")
}

もしインターネット接続ではなく、単にローカルネットワークに接続しているかどうかを調べるときは、代わりに reachabilityForLocalWiFi() を用いる。

ネットワークに接続や切断したときに何か処理をしたいという場合は次のように書ける。

let reachability = AMReachability.reachabilityForInternetConnection()
reachability.whenReachable = { reachability in
	println("インターネット接続あり")
}
reachability.whenUnreachable = { reachability in
	println("インターネット接続なし")
}

Dnsmasq を広告ブロックツールとして使う

DnsmasqDNS サービスを提供することができるソフトウェアだ。簡単な設定で名前解決のレコードほ書き換えることができる。これを利用して広告をブロックする。

この記事の対象読者は、次のすべてに当てはまることを想定している。

  • OS X を使っている(ここで試したのは 10.9.5/Mavericks, 10.10.5/Yosemite)
  • 今使っているマシンのネットワーク設定ができる
  • ターミナル上での操作に慣れている
  • ローカルに Web サーバを設定して使っている、あるいは設定できる

Dnsmasq のインストール

Dnsmasq のインストールには OS X であれば Homebrew で行える。次のコマンドを実行するだけだ。

brew install dnsmasq

(しばらく Homebrew を更新していない場合はこの前に brew update を実行するとよい)

Dnsmasq の初期設定

Dnsmasq の設定ファイルをコピーする。

cp -a `brew --prefix dnsmasq`/dnsmasq.conf.example /usr/local/etc/dnsmasq.conf

設定ファイルは初期状態ではほぼコメントだった。なので、役立ちそうなコメントを除いてすべて消し、次の行を書き加えた。

# /usr/local/etc/dnsmasq.conf

# LaunchAgents で動かすため、常にforgroundで起動
keep-in-foreground  

# Dnsmasq 用の resolv.conf
resolv-file=/etc/resolv.dnsmasq.conf

# ローカルからの問い合わせのみ受け付ける
listen-address=127.0.0.1

Launchctl から起動できるように plist ファイルを LaunchAgents ディレクトリにコピーする。

sudo cp `brew --prefix dnsmasq`/homebrew.mxcl.dnsmasq.plist /Library/LaunchAgents

OS X で使われている resolv.conf を dnsmasq 用にコピーする。

sudo cp /etc/resolv.conf /etc/dnsmasq.conf

resolv.conf には OS X の環境設定で設定されている DNS サーバのアドレスが登録されている。DHCPDNS サーバを自動取得している場合、取得したサーバのアドレスが登録される。そのため、もし MacBook をいろいろな場所で複数のネットワークに接続する必要がある場合は面倒かもしれない。ただし LAN 上の DNS を参照する必要がない場合、Google の提供する Public DNS に向けておくという手もある。

Dnsmasq の起動と終了

Dnsmasq の起動と終了には launchctl を用いる。ps ax | grep [d]nsmasq などで起動を確認できる。

# 起動
sudo launchctl load -w /Library/LaunchAgents/homebrew.mxcl.dnsmasq.plist

# 終了
sudo launchctl unload -w /Library/LaunchAgents/homebrew.mxcl.dnsmasq.plist

もし OS X 起動時に自動的に起動させたい場合は、LaunchAgents のかわりに LaunchDaemons に homebrew.mxcl.dnsmasq.plist をコピーする。(LauchDaemons は OS の起動時、LaunchAgents は各ユーザのログイン時に実行される。dnsmasq の起動にはスーパーユーザ権限が必要なため、各ユーザの権限で実行される LaunchAgents では自動起動しない)

OS X が参照する DNS サーバを dnsmasq に向ける

次のコマンドのほか、OS X の環境設定パネルからも可能。“Wi-Fi” の部分は適宜書き換えてほしい。

sudo networksetup -setdnsservers Wi-Fi 127.0.0.1

Dnsmasq を使うのをやめ、DHCP での自動取得に戻したい場合は次のコマンドを使う。

sudo networksetup -setdnsservers Wi-Fi Empty

広告を提供しているドメインをローカルに向ける

dnsmasq.conf に次の設定を追記した。これで設定したドメインおよびそのサブドメインがローカルへ向く。

# AD Block
address=/2o7.net/127.0.0.1
address=/a.adroll.com/127.0.0.1
address=/ad-arata.com/127.0.0.1
address=/adcash.com/127.0.0.1
address=/addthis.com/127.0.0.1
address=/adlantis.jp/127.0.0.1
address=/adkengage.com/127.0.0.1
address=/adjust-net.jp/127.0.0.1
address=/adresult.jp/127.0.0.1
address=/adtechjp.com/127.0.0.1
address=/advertising.com/127.0.0.1
address=/advg.jp/127.0.0.1
address=/agkn.com/127.0.0.1
address=/api.flipdesk.jp/127.0.0.1
address=/api.unthem.com/127.0.0.1
address=/apvdr.com/127.0.0.1
address=/atwola.com/127.0.0.1
address=/b3.yahoo.co.jp/127.0.0.1
address=/bidswitch.net/127.0.0.1
address=/bigmining.com/127.0.0.1
address=/bktrx.com/127.0.0.1
address=/bluekai.com/127.0.0.1
address=/brightcove.com/127.0.0.1
address=/cas.criteo.com/127.0.0.1
address=/cdn.bigmining.com/127.0.0.1
address=/cdn.cxense.com/127.0.0.1
address=/cdn.optimizely.com/127.0.0.1
address=/company-target.com/127.0.0.1
address=/coremetrics.com/127.0.0.1
address=/criteo.com/127.0.0.1
address=/d.adroll.com/127.0.0.1
address=/deqwas.net/127.0.0.1
address=/domdex.com/127.0.0.1
address=/doubleclick.net/127.0.0.1
address=/dsum-sec.casalemedia.com/127.0.0.1
address=/edge.simplereach.com/127.0.0.1
address=/eimg.jp/127.0.0.1
address=/exoclick.com/127.0.0.1
address=/fout.jp/127.0.0.1
address=/genieesspv.jp/127.0.0.1
address=/gmossp-sp.jp/127.0.0.1
address=/googleadservices.com/127.0.0.1
address=/googlesyndication.com/127.0.0.1
address=/googletagmanager.com/127.0.0.1
address=/googletagservices.com/127.0.0.1
address=/gssp.asia/127.0.0.1
address=/gsspat.jp/127.0.0.1
address=/gsspcln.jp/127.0.0.1
address=/gssprt.jp/127.0.0.1
address=/i-mobile.co.jp/127.0.0.1
address=/im-apps.net/127.0.0.1
address=/img.macromill.com/127.0.0.1
address=/impact-ad.jp/127.0.0.1
address=/js.ptengine.jp/127.0.0.1
address=/js.revsci.net/127.0.0.1
address=/loading-delivery1.com/127.0.0.1
address=/logly.co.jp/127.0.0.1
address=/microad.jp/127.0.0.1
address=/moatads.com/127.0.0.1
address=/mtcs.nhk.or.jp/127.0.0.1
address=/nakanohito.jp/127.0.0.1
address=/native.sharethrough.com/127.0.0.1
address=/nr-data.net/127.0.0.1
address=/omt.shinobi.jp/127.0.0.1
address=/openx.net/127.0.0.1
address=/openxmarket.jp/127.0.0.1
address=/outbrain.com/127.0.0.1
address=/pixel.facebook.com/127.0.0.1
address=/popin.cc/127.0.0.1
address=/pubmatic.com/127.0.0.1
address=/quantumads.com/127.0.0.1
address=/revcontent.com/127.0.0.1
address=/revsci.net/127.0.0.1
address=/rlcdn.com/127.0.0.1
address=/rtoaster.jp/127.0.0.1
address=/rubiconproject.com/127.0.0.1
address=/s.adroll.com/127.0.0.1
address=/s.thebrighttag.com/127.0.0.1
address=/scorecardresearch.com/127.0.0.1
address=/secure.eloqua.com/127.0.0.1
address=/sh.adingo.jp/127.0.0.1
address=/skimresources.com/127.0.0.1
address=/socdm.com/127.0.0.1
address=/spdeliver.i-mobile.co.jp/127.0.0.1
address=/static.quant.jp/127.0.0.1
address=/taboola.com/127.0.0.1
address=/tacoda.net/127.0.0.1
address=/textad.net/127.0.0.1
address=/trafficfactory.biz/127.0.0.1
address=/uliza.jp/127.0.0.1
address=/xml.affiliate.rakuten.co.jp/127.0.0.1
address=/yads.c.yimg.jp/127.0.0.1
address=/b90.yahoo.co.jp/127.0.0.1
address=/b91.yahoo.co.jp/127.0.0.1
address=/yads.yahoo.co.jp/127.0.0.1
address=/ybx.yahoo.co.jp/127.0.0.1
address=/yjtag.jp/127.0.0.1
address=/ziyu.net/127.0.0.1

ローカル Web サーバを設定する

OS X では Apache が入っているのでそれを使った。設定ファイルは /etc/apache2/httpd.conf にある。
ローカル Web サーバを使っていない場合は次の設定をする。

# デフォルトではこうなっているはずだ
DocumentRoot "/Library/WebServer/Documents"

# このセクションに記述する
<Directory "/Library/WebServer/Documents">
    ...

    # この2行を追記
    ErrorDocument 403 "404 AD Block"
    ErrorDocument 404 "404 AD Block"

    ...
</Directory>

すでにローカル Web サーバを使っている場合はバーチャルホストを設定し、特に名前を設定したホスト以外はダミーページを表示するようにする。

<VirtualHost *:80>
    ServerName localhost
    ServerAdmin webmaster@localhost
    DocumentRoot "/Users/theUser/Sites/dummy"
    ErrorLog /dev/null
    CustomLog /dev/null common env=0

    <Directory "/Users/theUser/Sites/dummy">
        ErrorDocument 403 "404 AD Block"
        ErrorDocument 404 "404 AD Block"
    </Directory>
</VirtualHost>

効果測定

これで大半の広告がブロックされたので、ためしに広告がいくつか入ったページの読み込み速度を測定した。

広告スクリプトの配置されているドメインの名前解決が必要なくなったぶん、かなり高速になった。

「管理者として実行する」のチェックが外せない場合の対処法

どういうわけか分からないが、ある日突然 Windows 7 上でプログラムを起動するときにユーザ アカウント制御のダイアログが表示されるようになってしまった。

実行ファイルのプロパティを見ると、「管理者としてこのプログラムを実行する」にチェックが入ったまま外せなくなっている。
解決方法はないかとレジストリ エディターを開いてプログラムのファイル名で検索したところ、次の場所にある値を削除すればよいことが分かった。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers

名前が実行ファイルのパス、値が RUNASADMIN となっているものを削除する。

これで「管理者としてこのプログラムを実行する」のチェックが外れ、ユーザ アカウント制御のダイアログも出なくなった。