忍者ブログ
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。



2024/11/24 10:52 |
PHPのストリームフィルタでCSV読み込み
利用できるフィルタのリスト』という謎の項目があります。
filter_input()とかのFilterとはまた別の、PHPにデフォルトで用意されているフィルタです。

何ができるかというと、入出力ストリームに対して操作が可能です。
ストリームとはfopen()とかでオープンされるリソースで、というか他に何か使えるものあるんですかね?
<?php
	
	$text = 'abcdefg';
	
	// ストリームフィルタ
	$crypt   = 'mcrypt.'.MCRYPT_3DES;
	$decrypt = 'mdecrypt.'.MCRYPT_3DES;
	$params = array('iv'=>'hoge', 'key'=>'fuga');
	
	// 書き込み
	$fp = fopen('foo.txt', 'w');
	// 暗号化ストリームフィルタを適用
	stream_filter_append($fp, $crypt, STREAM_FILTER_WRITE, $params);
	fwrite($fp, $text);
	fclose($fp);
	
	// 読み出し
	$fp = fopen('foo.txt', 'rb');
	// 復号ストリームフィルタを適用
	stream_filter_append($fp, $decrypt, STREAM_FILTER_READ, $params);
	$text = fread($fp, 10000);
	fclose($fp);
	
	var_dump($text); // abcdefg
foo.txtは人間には読めない形に暗号化されていますが、fread()するだけで透過的に復号されます。
あとはラッパークラスなりで囲えば簡単に暗号化ファイル操作クラスができあがります。

デフォルトのフィルタには、str_rot13()みたいな絶対使わないのがあるわりに有用なものがあまりありません。
ストリームフィルタは自作可能なので、役に立ちそうなものを自作してみます。
<?php
	/*
	* SJISのCSVをUTF-8で取り込むフィルタ
	*/
	class fgetcsv_filter extends php_user_filter{
		/**
		* @Override
		* @param resource 入力ストリーム
		* @param resource 出力ストリーム
		* @param int 変更したデータ長を参照渡しで返す
		* @param boolean フィルタチェインの最後の処理であればtrue
		* @return int PSFS_PASS_ON / PSFS_FEED_ME / PSFS_ERR_FATAL
		*/
		public function filter($in, $out, &$consumed, $closing){
			$locale = setlocale(LC_ALL, 0);
			setlocale(LC_ALL,'ja_JP.UTF-8');
			while ($bucket = stream_bucket_make_writeable($in)) {
				$bucket->data = mb_convert_encoding($bucket->data, 'UTF-8', 'SJIS-win');
				$consumed += $bucket->datalen;
				stream_bucket_append($out, $bucket);
			}
			setlocale(LC_ALL, $locale);
			return PSFS_PASS_ON;
		}
	}
	// fgetcsv_filterをfgetcsv_regという名前で登録
	stream_filter_register('fgetcsv_reg', 'fgetcsv_filter');
	
	$fp = fopen('hoge.csv', 'r');
	// $fpにfgetcsv_regフィルタを適用
	stream_filter_append($fp, 'fgetcsv_reg');
	
	// 以後普通に読める
	$data = fgetcsv($fp);
	var_dump($data);

hoge.csv
1ソ,Ⅱ表,③能,"ⅳ
"
CSVの文字コードはSJISです。
結果。
  array(4) {
    [0]=>
    string(4) "1ソ"
    [1]=>
    string(6) "Ⅱ表"
    [2]=>
    string(6) "③能"
    [3]=>
    string(5) "ⅳ
"
  }
文字化けせずに読み込み成功しました。
めでたし。

まあ正直わかりにくいので、あえてストリームフィルタを使わなくてもfgetcsv_reg()でいいじゃないという気もしますが。

PR


2014/08/08 22:48 | Comments(0) | PHP

コメント

コメントを投稿する






Vodafone絵文字 i-mode絵文字 Ezweb絵文字 (絵文字)



<<買ったものリスト 2014/08/10 | HOME | 骸骨楽団とリリア、パーフェクト>>
忍者ブログ[PR]