いろいろなバージョン取得

2010.03.07    C#, Windows, 馬場   タグ: —    baba   

バージョン情報と一口にいっても、実行ファイルのバージョン、DLLのバージョン、ClickOnceやインストーラのバージョンなど様々です。

バージョン情報ダイアログを作るために、これらのバージョンの取得方法を書いてみます。といってもコードで。

/// <summary>
/// ClickOnceで設定されたバージョンを取得
/// </summary>
public static Version ClickOnceVersion
{
	if (!System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed)
	{
		return null;
	}
	return System.Deployment.Application.ApplicationDeployment
		.CurrentDeployment.CurrentVersion;
}

/// <summary>
/// 実行中のexeファイルのバージョンを取得
/// </summary>
public static string AssemblyVersion
{
	return System.Windows.Forms.Application.ProductVersion;
}

/// <summary>
/// 実行中のexeファイルと同一ディレクトリにあるDLLの情報を取得
/// </summary>
public static List<System.Diagnostics.FileVersionInfo> DllVersion
{
	var versions = new List<System.Diagnostics.FileVersionInfo>();

	//自身のファイルパスを取得し、同一ディレクトリのdllファイルを一覧する
	string path = System.IO.Path.GetDirectoryName(
		System.Windows.Forms.Application.ExecutablePath);
	foreach (string name in System.IO.Directory.GetFiles(path, "*.dll"))
	{
		System.Diagnostics.FileVersionInfo info =
			System.Diagnostics.FileVersionInfo.GetVersionInfo(name);
		versions.Add(info);
	}

	return versions;
}

このような感じで、バージョン情報ダイアログが作れそうです。
※DLLのバージョン取得はもう少し工夫しないと問題がありそうですが・・・

ApplicationDeployment

2010.03.06    C#, Windows, 馬場   タグ: —    baba   

C#等のアプリで、自身がClickOnceでインストール・実行されているかをチェックするには、

System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed

を調べます。

しかしこのプロパティ、普通に起動するとfalseが取得できますが、Visual Studioから起動するとなぜかフリーズすることがあります。ありました。

この場合は、ClickOnceアプリの実体が保存される C:/Users/ユーザ名/AppData/Local/Apps/2.0 を削除して、コンピュータを再起動すると直るようです。直りました。

起動プロセスが複雑になるとたまに面倒ですね。

Ethna_DBでfetchArrayのようなことをする

2010.03.03    Ethna, PHP, 馬場   タグ: —    baba   

PHPでmysql_queryの結果オブジェクトは、mysql_fetch_row()しても良いですが、mysql_fetch_array()した方が便利ですよね。
※mysql_fetch_row()では、結果を通常の配列で取得しますが、mysql_fetch_array()では、カラム名をキーにした連想配列で取得できます

EthnaでAppObjectを使わずにEthna_DBを直接たたく場合、結果オブジェクトはPEAR::DB_Resultオブジェクトです。
これはfetchRow()のメソッドを持ちますが、fetchArray()は存在しません。
http://pear.plus-server.net/package.database.db.db-result.fetchrow.html

カラム名をキーにした連想配列が欲しい場合、queryを投げる前にsetFetchMode(DB_FETCHMODE_ASSOC)を実行しておく必要があります。
http://pear.plus-server.net/package.database.db.db-common.setfetchmode.html

EthnaのデフォルトDBアダプタ、DB_PEARは、内部にPEAR::DBを持っているので、以下のようなコードを書けばOKです。

$db = $this->backend->getDB();
$db->db->setFetchMode(DB_FETCHMODE_ASSOC);
$res = $db->query($sql);
print_r($res->fetchRow());

http://ethna.jp/ethna-document-dev_guide-db.html
Ethnaの デフォルトの DB接続クラス(Ethna_DB_PEAR) はPEAR::DBを継承しているので
と書いてありますが、継承ではなくて委譲なので、$db->db->setFetchMode()となります。

fputcsvの問題点と改良

2010.03.01    PHP, 馬場      baba   

PHPのfputcsv関数は便利です。
しかし、以下のような点が不便です。

エンコーディングを変換できない
主にCSV出力の目的になるExcelでは、Shift-JIS以外のCSVを開けません。
Excel 2007ならBOMを付けるとか、データインポートで実行するといった回避策はありますが、日本語のみならShift-JISで出力したいことが多いと思います。

このためにはあらかじめShift-JISに変換しておく必要があり、

$sjis = array_map(create_function(’$str’, ‘return mb_convert_encoding($str, “Shift-JIS”, “UTF-8″);’), $line);

といった処理をやっていましたが、正直めんどうです。

ダブルコーテーションのエスケープにバグがある
カンマが含まれる場合、ダブルコーテーションで囲ってくれます。
ダブルコーテーションが含まれる場合、ダブルコーテーションを二重にしてエスケープしてくれます。
しかし、\” (バックスラッシュ+ダブルコーテーション)があった場合、なぜかこの部分のダブルコーテーションは二重にしてくれません。

ということで、結局自前でやった方が便利です。
mb_str_replaceは、http://fetus.k-hsu.net/document/programming/php/mb_str_replace.htmlを使わせて頂きました。

function _fputcsv($fp, $data, $toEncoding='Shift-JIS', $srcEncoding='UTF-8') {
	require_once 'mb_str_replace.php';

	$csv = '';
	foreach ($data as $col) {
		if (is_numeric($col)) {
			$csv .= $col;
		} else {
			$col = mb_convert_encoding($col, $toEncoding, $srcEncoding);
			$col = mb_str_replace('"', '""', $col, $toEncoding);
			$csv .= '"' . $col . '"';
		}
		$csv .= ',';
	}

	fwrite($fp, $csv);
	fwrite($fp, "\r\n");
}

ちゃんとテストしていないのでミスがあるかもしれませんが、このくらいシンプルで十分そうですね。

ウィンドウを背後に移動

2010.02.25    C++, Windows, 馬場      baba   

数年前に作ったミニアプリを公開してみました。

WinBottom

ウィンドウの最小化ボタンを右クリックすると、そのウィンドウが背面に移動するだけの常駐ソフトです。
くだらないですが、大型ディスプレイでは地味に便利です。

アイコンが猫の手なので、おすすめです。

極小なのでほとんど何も書いていないですが、もしソースが欲しい等の変な方がいたらご連絡ください。

SET NAMESが危険な理由のおさらい

2010.02.17    PHP, セキュリティ, 馬場   タグ: —    baba   

1年くらい前に社内MLに投げた、「MySQLでSET NAMESを使ってはいけない理由」をコピペしてみます。手抜きです、はい。
赤字は注釈です。


今更ながら、「MySQLで SET NAMES を使ってはいけない」の根拠のお話です。

下記のPHPスクリプトでは、入力値を元にSQL文を生成し、検索クエリを投げています。
※sqltestというDBには、カラムnameを持つuserテーブルが存在します。

GETで渡された値はきちんとmysql_real_escape_stringをかけているので、SQLインジェクションは出来ないように見えます。
しかし、
http://localhost/sqltest/index.php?name=%95%5c’%20OR%201=1%20–%20
にアクセスすると、全部のデータが見えてしまいます。
下にあるPHPスクリプトを、localhost/sqltest/index.php として配置してください。

“SET NAMES SJIS” を実行すると、MySQLのエンコードがShift-JISになりますが、mysql_real_escape_stringはUTF-8のまま動作します。
16進数で 95 5c 27 20 は、
UTF-8: (謎の文字)(バックスラッシュ)(シングルコーテーション)(スペース)
Shift-JIS: (表)(シングルコーテーション)(スペース)
になります。
mysql_real_escape_stringは、バックスラッシュとシングルコーテーションそれぞれをエスケープします。
95 5c 5c 5c 27 20
MySQLは、Shift-JISとして動作するので、 (表)(\)(\)(シングルコーテーション)(スペース) と認識します。
つまり、\が一つ余分に入ることで、入力値のシングルコーテーションがエスケープされなくなります。

マルチバイト非対応のエスケープ関数を使うのと同じ理屈で、SET NAMES は危険です。
基本的に文字コード中に5Cが入るShift-JISが危険ですが、他の文字コードでも似たようなことが起こる可能性があります。
mysql_set_charset(’SJIS’);
なら、mysql_real_escape_stringもShift-JISとして動作するようになるので、安全です。


<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>SQLテストページ</title>
<head>
</head>
<body>

<form action="<?php echo $_SERVER['SCRIPT_NAME'];?>">
	<input type="text" name="name" />
	<input type="submit" value="search" />
</form>

<?php
	//DBに接続
	if (! $db = mysql_connect('localhost', 'sqltest', 'sqltest'))
	{
		echo 'CONNECT ERROR';
		exit;
	}
	mysql_select_db('sqltest', $db);

	mysql_query('SET NAMES SJIS');
//	mysql_set_charset('SJIS');

	//SQLを生成
	$name = mysql_real_escape_string($_REQUEST['name']);
	$sql = "SELECT * FROM user WHERE name='$name'";
	echo $sql . '<br />';

	//実行
	if (! $res = mysql_query($sql))
	{
		echo "QUERY ERROR <br />";
		echo mysql_error();
		exit;
	}

	echo "<pre>";
	while ($row = mysql_fetch_array($res)) {
		print_r($row);
	}
	echo "</pre>";
?>

</body>
</html>

CakePHPでDBのエンコーディングを指定

2010.02.16    CakePHP, PHP, 馬場   タグ: —    baba   

PHPでMySQL 5をUTF8にして使う場合、文字が全部????になってしまう問題を防ぐため、

default-character-set=utf8
character-set-server=utf8
collation-server=utf8_general_ci
skip-character-set-client-handshake

を指定する、というのが定石になっています(よね?)。

しかし、共用サーバなどでmy.iniを編集できない場合、mysql_set_charset() などを使うと思います。

CakePHPでは、bootstrapでDB設定を読んで手動で設定するのも面倒だな、と思っていたら、さすがはCakePHP。便利な設定が。
app/config/database.php

var $default = array(
	'driver' => 'mysql',
	'persistent' => false,
	'host' => 'localhost',
	'login' => 'baba',
	'password' => 'hoge',
	'database' => 'testdb',
	'prefix' => '',
    'encoding' => 'utf8',
);

このようにencodingを指定するだけで、勝手にSET NAMESやmysql_set_charset()を実行してくれます。便利便利。

XAMPP 1.7.3 でいろいろ困った

2010.02.11    PHP, 馬場   タグ: —    baba   

XAMPP はPHPやMySQLなどもいっぺんに入ってとても便利ですが、その分バージョン違いで混乱することも多いですね。

最新版1.7.3 では、PHPも5.3.1になっていて、以下の点で既存システムが動かなくなりました。php.iniのデフォルトが変わったようです。

エラー表示をE_ALLにしたら、deprecatedが大量に出る
php.ini で error_reporting = E_ALL & ~E_DEPRECATED にすればOK

cURLエクステンションが無効で、PEAR::XML_RPC2が動かない(エラーも出ない)
php.ini で extension=php_curl.dll のコメントアウトを外せばOK

特定の環境に慣れていると、開発したシステムの動作環境を正確に把握・記述することを怠ってしまうので、注意しないといけませんね。

C#でUDPパケットをひたすら送り続ける

先日のiPhone UDP受信テストの際に使った、WindowsからUDPパケットを送りつけるプログラムを載せてみます。
一切の遠慮無く、1秒に20枚のペースで、デスクトップに置いてあるimg0.png~img9.pngの画像ファイルを一方的に送りつけます。

///一定時間ごとにUDPで画像を一方的に送りつける
private void SendData()
{
    //ローカルポート番号2222にバインドする
    System.Net.Sockets.UdpClient udp = new System.Net.Sockets.UdpClient(2222);

    int count = 0; //何番目の画像を送信するかのカウンタ

    Timer timer = new Timer();
    timer.Tick += new EventHandler((s, e) =>
    {
	    if (++count > 9)
	    {
	        count = 0;
	    }

	    //デスクトップのimg0.png~img9.pngを送る
	    string filename = @"C:\Users\baba\desktop\img\" + count + ".png";
	    using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read))
	    {
	        byte[] sendBytes = new byte[fs.Length];
	        fs.Read(sendBytes, 0, sendBytes.Length);
	        //宛先IPとポート番号を指定する
	        udp.Send(sendBytes, sendBytes.Length, "192.168.100.50", 5555);
	    }
    });
    timer.Interval = 50;
    timer.Start();
}

.NETは簡単にこういったコードが書けて便利ですね。
何の工夫も最適化も無いですが、50枚/秒くらいなら全然問題にならない程度の速度は出ていました。

古いIEだとAjaxのUserAgentが変わるので、CakePHPでセッションが切れてしまう

2010.02.01    CakePHP, IE, javascript, 馬場      baba   

CakePHPでjQueryを使ったAjaxを実装した際、IEの古いバージョンでのみエラーになる現象に見舞われました。
調べてみると、Ajaxリクエストを送った際にログインが切れているようです。

どうやら原因は、CakePHPのユーザエージェント検証機能でした。
app/config/core.phpで

Configure::write(’Session.checkAgent’, false);

を設定することで解決しました。

つまり、古いIEでは、通常時のリクエストとAjaxリクエストで、ユーザエージェントが違う、ということですね。
これはたぶん、歴史的な理由からXMLHttpRequestがActiveXオブジェクトで実装されていることに由来するのでしょう。

以下に、各ブラウザで確認したユーザエージェントを書いておきます。
PHPで、$_SERVER['HTTP_USER_AGENT'] を表示しています。また、Ajax通信は、jQueryの$.ajax()を使っています。

■Firefox 3.5.6
通常: Mozilla/5.0 (Windows; U; Windows NT 6.1; ja; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729)
Ajax: Mozilla/5.0 (Windows; U; Windows NT 6.1; ja; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729)

■Chrome 4 beta
通常: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.64 Safari/532.5
Ajax: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.64 Safari/532.5

■IE8
通常: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)
Ajax: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)

■IE7
通常: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)
Ajax: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)

■IE6
通常: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 6.1; WOW64; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)
Ajax: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)

古い投稿 »

COPYRIGHT [C] 2009 BEYOND PERSPECTIVE SOLUTIONS LTD. ALL RIGHTS RESERVED.