PEAK XOOPS - News in englishin japanese

Archive | RSS |
  
Poster : GIJOE on 2008-05-16 04:55:48 (11639 reads)

get_html_translation_table()の罠in englishin japanese
最近、unhtmlspecialchars() も実装されたようですが、get_html_translation_table() を利用して、htmlspecialchars() の逆関数を作っていた人も多いでしょう。


function my_unhtmlspecialchars( $text , $quotes = ENT_QUOTES )
{
	return strtr( $text , array_flip( get_html_translation_table( HTML_SPECIALCHARS , $quotes ) ) ) ;
}


ところが、それだとなぜかシングルクオートだけがうまく処理されないことに、今さら気づきました。

おかしいなと調べてみたら、get_html_translation_table( HTML_SPECIALCHARS , ENT_QUOTES ) と htmlspecialchars( $text , ENT_QUOTES ) では、結果が違います。

コード:

<?php
        var_dump( htmlspecialchars( '"\'<>&' , ENT_QUOTES ) ) ;
        var_dump( get_html_translation_table( HTML_SPECIALCHARS , ENT_QUOTES ) ) ;
?>

結果:

string(25) "& quot;& #039;& lt;& gt;& amp;"
array(5) {
  ["""]=>
  string(6) "& quot;"
  ["'"]=>
  string(5) "& #39;"
  ["<"]=>
  string(4) "& lt;"
  [">"]=>
  string(4) "& gt;"
  ["& "]=>
  string(5) "& amp;"
}

& #39; と & #039; …。
そりゃ逆変換できないのも当然です。

ええ〜、そりゃないんじゃないの! という感じです。以前、PHPのマニュアルにも、逆関数の作り方として、get_html_translation_table()の結果をarray_flip()する、なんてコードが載っていたような記憶もあるのですが…

もしかすると有名な不具合なのかもしれませんが、うちでビルドしたCLI版PHPは、4.3.10から5.2.5までことごとくこういう食い違いを見せていたので、もしかしたら誰も気づいていないのかもと思って書いてみました。


Poster : GIJOE on 2007-09-18 04:00:24 (12042 reads)

in englishin japanese
WYSIWYGエディタを有効にするなら、基本的にHTML表示許可でデータを受け取るしかないのですが、そうするとScriptInsertionが避けられません。

HTMLを再構築してくれるライブラリさえあればなあ、と思っていたら、kentaulsさんが教えてくれました。
HTMLPurifier
http://htmlpurifier.org/

この手のライブラリってあまり信用していなかったのですが、アーカイブ内にあるsmoketestのXSSがあまりにも圧巻で、これはいけるかも! と期待してます。

ただこのライブラリ、手元で一通り試した限りでは、PHP5専用ですね。サイトにはPHP4でも動くと書いてありますし、一応、エラーを吐かずに通過はしますが、惨憺たる変換状況です。

逆に、PHP5だとおかしな動作が見つかりません。EUC-JPを通しても、ちゃんとiconvで内部的にUTF-8に変換してから処理してくれます。もちろん、返り値もEUC-JPとなります。

INSTALLにも書いてありますが、キャッシュの置き場所と、エンコーディング指定だけはちゃんとやった方が良いでしょう。


require_once dirname(__FILE__).'/library/HTMLPurifier.auto.php' ;
$config = HTMLPurifier_Config::createDefault();
$config->set('Cache', 'SerializerPath',dirname(__FILE__).'/cache');
$config->set('Core', 'Encoding', 'EUC-JP');
$purifier = new HTMLPurifier($config);


ただ個人的には、それでも不特定多数にHTMLを許可するべきではないと考えてます。
どうしても仕方がない状況にだけ、このHTMLPurifierを通過させることで自分を納得させる、なんて使い方が正しいでしょうか。

HTMLPurifierの性能を信用しないわけではありません。でも、世界で広く使われている某ブラウザは信用できません。いきなり恐ろしい機能拡張がされない保証はないのです。


Poster : GIJOE on 2007-03-24 05:50:55 (7946 reads)

in englishin japanese
つい最近ハマったのですが、PHP5.1から、shutdown関数と出力バッファリング関数の両方を使った時の処理順が変更になっているようです。(PHP5.0.x は、PHP4と同じ)

<?php
register_shutdown_function( 'sf' ) ;
ob_start( 'ob' ) ;
echo 'main ' ;

function ob( $s )
{
	return $s.'ob ' ;
}

function sf()
{
	echo 'sf ' ;
}
?>

このコードを実行した時、以下のような結果になります。(すべてcli版でテスト)
PHP4.4.4およびPHP5.0.3
main ob sf 


PHP5.1.3
main sf ob 


後者の場合、shutdown関数の出力も、バッファリングされているわけで、動作としてはまるっきり別のものとなります。

しばし悩みましたが、両者の非互換性を吸収するコードはこんな感じ。

<?php
register_shutdown_function( 'sf' ) ;
ob_start( 'ob' ) ;
echo 'main ' ;

function ob( $s )
{
	return $s.'ob ' ;
}

function sf()
{
	while( @ob_end_flush() ) ;
	echo 'sf ' ;
}
?>

shutdown関数先頭でバッファリングをクリアすることで、PHP5.1未満とPHP5.1以降が同じ処理順になります。(PHP4と同じ順番に統一)

もし、PHP5.1未満をPHP5.1以上の処理順に統一するなら、バッファリング関数内で呼び出すしかないでしょうかね。

0 comments

Poster : GIJOE on 2007-03-20 13:06:04 (12523 reads)

in englishin japanese
PHPコードを書くとき、処理速度の関係から、極力ビルトイン関数を使うようにしているのだが、最近のお気に入りはarray_map()。
これがいろいろな局面で使える。

例えば、フォームにカンマ区切りで、複数の値を入力してもらう時。
1,2,3,4 とか。
これをint型の配列で取得したい場合、explodeしたものをforeach()で回しがちだけど、実はこの1行で済む。


$myarray = array_map( 'intval' , explode( ',' , $post_data ) ) ;


あと、役に立つのが、重複無しで配列の和を取る場合。
配列同士を+演算子で「足す」と、同じindexを持った要素の片方が消えてしまう。
かといって、array_merge()で「足す」と、同じ内容の要素が重複してしまう。

通常、array_merge()などで重複したデータを消すためには、array_unique() を利用するのだが、この関数はあくまで、文字列での比較しかしない。だから、配列要素が配列やオブジェクトの場合は、そのままだと使えない。

このケースでも、array_map() の出番となる。

$merged_array = array_map( 'unserialize' , array_unique( array_map( 'serialize' , array_merge( $array1 , $array2 ) ) ) ) ;

0 comments

Poster : GIJOE on 2007-03-10 04:56:00 (7735 reads)

in englishin japanese
前の記事じゃあまりにも、単なる落書きなので、一応まとめてみました。

インデックスが以下の型で指定された場合、すべてintval()された値の整数インデックスになる。
- boolean
- float(double)
- int

ただし、符号付き32bit範囲外の整数については、intval()と挙動が違う。
floatの整数化も、ceil()でもround()でもfloor()でもなく、intval()であるのだが、この知識も何の役にも立たないだろう。

インデックスが文字列で指定された場合は2通りに処理分けされる


/^[-]?[1-9][0-9]*$/

この正規表現にマッチする時のみ、整数インデックスになる。
それ以外はすべて、文字列インデックス(連想配列)になる。

あと、当たり前だけど、それ以外の型をインデックスには指定できません。
配列・オブジェクト・リソース等、全部Warningが出て、空配列になる(かな?)

0 comments

« 1 (2) 3 4 5 6 »
Login
Username or e-mail:

Password:

Remember Me

Lost Password?

Register now!