PowerShellを便利に使う

2010.03.09    Windows, 馬場      baba   

Windows Vista以降では、PowerShellが標準搭載されています。

慣れてくると、コマンドプロンプトよりもPowerShellの方がいろいろ便利です。とりあえず、うっかりlsと打っても大丈夫なのが一番重要。

ただし、起動手順は
・コマンドプロンプト: Windows + R → cmd
・PowerShell: Windows + R → powershell
このように、powershellと打ち込むのがめんどくさいですね。

そこで、ファイル名を指定して実行のショートカットに追加してしまいましょう。

C:/Users/baba/shortcuts などのフォルダを作り、その中にPowerShellへのショートカット「ps」という名前で作ります。
ps → C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe

後は、環境変数のPATHにC:/Users/baba/shortcuts を追加すればOKです。

環境変数のPATHを設定

環境変数のPATHを設定

これで、Windows + R → ps でPowerShellが開くため、コマンドプロンプトを使う機会が減りそうです。
ショートカットを作成する際、作業フォルダを指定できるのもポイントですね。

もちろん、PowerShell以外にもショートカットおき放題なので、ランチャーいらずです。

プライバシーマーク取得

2010.03.08    馬場   タグ: —    baba   

早速プライバシーマークが届きました!

Pマーク付与認定証

Pマーク付与認定証

3日にBPSから速達で契約書を発送 → 6日にPマーク到着(ただし不在)なので、かなり迅速な手続きですね。
#今回も宅急便で届きましたが・・・ 大丈夫かな??

11日から正式に使えるので、名刺に組み込む準備中です。

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

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 を削除して、コンピュータを再起動すると直るようです。直りました。

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

SSHでパスワードなしログイン

2010.03.05    Linux, 馬場      baba   

SSHでパスワードなしログインするための環境構築で、基本的なところで躓いてしまいました。

■手順

  1. ssh-keygen -t rsa で、パスフレーズなしのSSH鍵を生成する
  2. ~/.ssh/id_rsa.pub を、リモートホストにコピーする
  3. リモートホストで、cat id_rsa >> ~/.ssh/authorized_keys する
  4. リモートホストで、authorized_keys のパーミッションを600にする
  5. ssh -i (IDファイル) (リモートホスト)

だけなのですが、authorized_keys の所有者がrootになってしまっていました。
パーミッションを600にしても、ownerが間違っていたらだめですよね・・・

Pマーク付与認定

2010.03.04    馬場      baba   

ずいぶん長いことかかってしまいましたが、ようやくプライバシーマーク付与認定通知が届きました。
来週からBPSはプライバシーマーク付与事業者になる予定です。

この区切りに、審査からの数ヶ月で変化した点を踏まえ、再度個人情報取り扱いのレビューを行っていこうと思います。
引き続きよろしくお願いします。

#ところで、Pマーク事務局からの請求書・契約書がクロネコヤマトで届いたのですが、これって信書ですよね・・・?

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()となります。

dekiwikiで画面が真っ白に

    MindTouch Deki, 馬場   タグ: —    baba   

社内のサーバを仮想化したのに伴い、社内wikiとして使っているdekiwikiも環境移行しました。

dekiwikiは優れたツールですが、移行やバージョンアップはいまいち考えられていない感もありますね。
次のような手順で移行しました。

・新サーバで、aptitudeから普通にdekiwikiをインストール(この際、DBパスワードなどを同じにしておく)
・旧サーバのmysqlデータを、新サーバにコピー
・/var/www/dekiwiki/attachments 以下を、新サーバにコピー

これで一通りは使えるようになります。
インストール後はコントロールパネルからキャッシュの再構築が必要です。

ついでにmonoをバージョンアップしたせいか、動作が劇的に速くなりました。古いmonoはCPUをずっと食い散らかしていたので、何かバグがあったのでしょう。

しかし、新wikiでは以下の問題が発生しました。
・検索すると画面が真っ白になる
・コントロールパネル「削除済みファイル」を開くと画面が真っ白になる

これは2つの問題が複合していました。

まず削除済みファイルの件ですが、attachmentsの中身のコピーが不完全で、エラーになっていたようです。
ファイルのインデックスはmysqlに保存されるため、インデックスが存在してファイル実体が無い場合、エラーになってしまいます。
/var/log/dekiwiki/deki-api.log に表示されるエラーを参考にしながら、完全なコピーを実施します。万が一ファイルを無くしてしまっていたら、とりあえず同名ダミーファイルでもおいておけば良いかもしれません。

次に検索が出来ない件ですが、PHPのメモリ不足でした。
php.iniでmemory_limit を16MBから64MBにしたら、無事検索できるようになりました。ページやファイル数が多くなっているため、結構メモリを食うのですね。

PHPエラーを出力する設定にしないと気づかないので注意が必要です。

MySQLのサブクエリを改善

2010.03.02    馬場   タグ: —    baba   

MySQLのサブクエリは、一見問題なさそうなものも相関サブクエリに置換されて、極端に遅くなることがありますね。
INを適切に処理できないのが原因らしいです。

なぜMySQLのサブクエリは遅いのか。

今回は、以下のような「ユーザごとにスコアの履歴を保持していて、最新のスコアが有効」というテーブル設計で、「全ユーザの最新スコア合計を取得」しようとして問題が起きました。

score_log
id int primary key auto_increment
user_id int ※外部キー
score int  

最初考えたSQLは以下のようなものです。
ユーザごとの最新スコアIDを一括取得し、それに該当するスコアの合計を計算しました。

SELECT SUM(score_log.score) FROM score_log WHERE score_log.id IN (SELECT MAX(log2.id) FROM score_log AS log2 GROUP BY log2.user_id)

しかしこれだと、EXPLAINをつけると分かるように、DEPENDENT SUBQUERYになってしまいます。
参考サイトによると、MySQLがINをEXISTSに変換する際に、相関サブクエリにしてしまっているようです。
実行速度も、データ件数の二乗に比例し、極端に遅くなってしまいました。

結果的に、以下のクエリに変更して解決しました。

SELECT SUM(score_log.score) FROM score_log, (SELECT MAX(log2.id) id FROM score_log AS log2 GROUP BY log2.user_id) each_cur WHERE score_log.id = each_cur.id

ユーザごとの最新スコアIDの一覧をテーブルとして、それをFROMに使ってしまうというわけですね。

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");
}

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

古い投稿 »

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