<?xml version="1.0" encoding="UTF-8"?><!-- generator="wordpress/2.3.3" -->
<rss version="0.92">
<channel>
	<title>MT312 &#187; 2007 &#187; 9 月</title>
	<link>http://www.mt312.com</link>
	<description></description>
	<lastBuildDate>Mon, 12 May 2008 02:56:06 +0000</lastBuildDate>
	<docs>http://backend.userland.com/rss092</docs>
	<language>ja</language>
	
	<item>
		<title>携帯端末番号（個体識別番号）判別</title>
		<description>携帯の端末番号の取得方法を紹介します。こういった携帯にまつわる問題は各社仕様がバラバラで面倒です。とにかく簡単に済ませたいもんです。
方法
DoCoMoとSoftBankはユーザーエージェントに番号が含まれますので、これを解析すればすぐにわかります。AUはユーザーエージェントには含まれず$_SERVER['HTTP_X_UP_SUBNO'];に格納されています。この特殊な変数があれば、ほぼ端末番号であると分かる訳ですが、ログとして保存したい場合には個別に保存項目が必要になりやっかいです。そこで前の番号部分を抜いてユーザーエージェントに連結させます。これで大手三社の番号をユーザーエージェントだけで確認できます。
DoCoMo

// MOVA
DoCoMo/1.0/X503i/c10/ser12345678901
serの後に11桁英数字

// FOMA
DoCoMo/2.0 N2001(c10;ser12345678901;
icc12345678901234567890)
serの後に15桁英数字
iccの後に20桁英数字
改行が含まれます。

[php]
// ser以降で判別
$agent = $_SERVER['HTTP_USER_AGENT'];
$hasSubno = preg_match('/ser[0-9A-Za-z]{11,15}/', $agent);
[/php]
SoftBank

// Vodafone
Vodafone/1.0/V802SH/SHJ002/SN123456789012345 Browser/UP.Browser/7.0.2.1 Profile/
MIDP-2.0 Configuration/CLDC-1.1 Ext-J-Pr

// SoftBank
SoftBank/1.0/705P/PJP10/SN123456789012345 Browser/Teleca-Browser/3.1 Profile/
MIDP-2.0 Configuration/CLDC-1.1

いずれも/SNの後に15桁英数字

[php]
// /SN以降で判別
$agent = $_SERVER['HTTP_USER_AGENT'];
$hasSubno = preg_match('/\/SN[0-9A-Za-z]{15}/', $agent);
[/php]
AU
AUの場合だけ先にユーザーエージェントに番号を付けます。
[php]
// 05051234567890_ae.ezweb.ne.jp
// 4桁地域コードと10桁端末コード
$subno = $_SERVER['HTTP_X_UP_SUBNO'];
// KDDI-CA23 UP.Browser/5.1 (GUI) MMP/2.0/SUB05051234567890_ae
$_SERVER['HTTP_USER_AGENT'] .= '/SUB'.substr($subno, 0, -12);
[/php]
[php]
// 連結した末尾で判別
$agent = $_SERVER['HTTP_USER_AGENT'];
$hasSubno = preg_match('/\/SUB0\d0\d\d{10}_[a-z\d]{2}$/', $agent);
[/php]
まとめ
これで端末番号を送信しているかどうかユーザーエージェントだけで判断できるし、特定の端末番号を拒否する事もできます。今回は省略しましたが、以前の携帯判別のコードと合わせれば便利に書けるかもしれません。
ユーザーエージェント携帯判別
注意
これらの環境変数($_SERVER)は信用してはいけません。保存したり、ページへ出力させる場合にはどんな文字が入っていても問題ない様にしましょう。 </description>
		<link>http://www.mt312.com/php/45/</link>
			</item>
	<item>
		<title>$fpが権限を握るflockによるファイルロック</title>
		<description>果たして、この記事が役に立つか疑問ですが、私の様にポカをする人がいないとも限りませんし、忘備録的に書いてみます。

先日カウンターのログが頻繁に壊れると指摘があり、原因が分からず2日程考えていた時、ふと疑問が。テストしてみると、全くロックできていない。実はこう書いていました。
[php]
function lock() {
  $fp = fopen('./lock', 'w');
  return $fp && flock($fp, LOCK_EX);
}
if(!lock()) {
  // ロック失敗で終了
}
// ログ保存
$fp = fopen(LOG_FILE, 'wb');
fwrite($fp, $lines);
fclose($fp);
[/php]
自分では正しいと思っていたんですけど、実はlock()はtrueしか返さず、後にロックが外れます。どうなっているかと言うと、lcok()と同時にロックされ真が返りますが、$fpがローカル変数で既に用済みな為、ロックが外れてしまうのです。flockによるファイルロックは$fpが生きている必要があります。つまり、以下でもロックが外れます。
[php]
$fp = fopen('./lock', 'w');
flock($fp, LOCK_EX);
unset($fp);
[/php]
よって、こう書いて解決。
関数にしなきゃいいだけの話。
[php]
// ファイル生成可能で空にするコストがないaを指定
$l_fp = fopen('./lock', 'a+');
$locked = $l_fp && flock($l_fp, LOCK_EX);
if(!$locked) {
  // ロック失敗で終了
}
// ログ保存
$fp = fopen(LOG_FILE, 'wb');
fwrite($fp, $lines);
fclose($fp);
[/php]
上の例と違い、ログファイルを追記モードで扱う場合はロックファイルを用意する必要はありません。また、追記モードで書込モードの様に空にしてから書き込む事もできます。
[php]
// ファイルがなければ生成
$fp = fopen(LOG_FILE, 'a+b');
// ロックしてファイルを空にする
$prepared ...</description>
		<link>http://www.mt312.com/php/44/</link>
			</item>
</channel>
</rss>
