リクエストのフィルタリングクラス
リクエストをフィルタリングするクラスを作ってみました。
<?php class Request { const GET = 0; const POST = 1; const COOKIE = 2; const SERVER = 3; const INT = 0; const STR = 1; const REG = 2; const HEX = 3; const TXT = 4; const DATE = 5; const EMAIL = 6; const PASSWORD = 7; const ASCII = 8; const CHECK = 9; const NOTEMPTY = 10; public static $Bans = array( 'http', '.net', '.com', '.jp', '.co.jp' ); private static function AllocateMethod ( $method ) { switch ( $method ) { case self::GET : return $_GET; case self::POST : return $_POST; case self::COOKIE : return $_COOKIE; case self::SERVER : return $_SERVER; } } public static function Checked ( $method, $name ) { $ary = self::AllocateMethod( $method ); return isset( $ary[ $name ] ) && strtolower( $ary[ $name ] ) == 'on'; } public static function SpecialCharacterCheck ( $method ) { $ary = self::AllocateMethod( $method ); foreach ( $ary as $name => $value ) { if ( preg_match( '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', $value ) ) { $name = Log::Escape( $name ); $value = Log::Escape( $value ); Log::Record( "Request containing special characters. ({$name}={$value})" ); header( "HTTP/1.0 403 Forbidden" ); exit; } } } public static function SafeString ( $str ) { return !preg_match( '/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/', $str ); } public static function Filter ( $method, $name, $type, $option1 = null, $option2 = null ) { $ary = self::AllocateMethod( $method ); $ret = false; if ( isset( $ary[ $name ] ) && self::SafeString( (binary)$ary[ $name ] ) ) { $value = $ary[ $name ]; switch ( $type ) { case self::INT : if ( $ret = $value == (string)(int)$value ) { if ( $option1 ) $ret = $option1 <= $value; if ( $option2 ) $ret = $value <= $option2; } break; case self::STR : case self::PASSWORD : $ret = mb_check_encoding( $value ); break; case self::TXT : $ret = mb_check_encoding( $value ) && TextCheck::NotContainBan( $option1, $value, static::$Bans ); break; case self::REG : $ret = preg_match( $option1, $value ); break; case self::HEX : $ret = preg_match( '/^[0-9a-fA-F]*$/', $value ); break; case self::DATE: $ret = strtotime( $value ) !== false; break; case self::EMAIL: $ret = empty( $value ) || filter_var( $value, FILTER_VALIDATE_EMAIL ); break; case self::ASCII: $ret = preg_match( '/^[\x00-\x7F]*$/', $value ); case self::CHECK: $ret = empty( $value ) || ( strtolower( $value ) == 'on' || strtolower( $value ) == 'off' ); break; case self::NOTEMPTY: $ret = !empty( $value ); break; } } if ( $ret == false && !empty( $value ) ) { $value = Log::Escape( $value ); $name = Log::Escape( $name ); Log::Record( "{$name} is Illegal value.({$name}={$value})" ); } return $ret; } public static function FilterAll ( $methods ) { $bit = 1; $code = 0; foreach ( $methods as $method => $names ) { foreach ( $names as $name => $options ) { if ( self::Filter( $method ,$name ,$options[ 0 ] ,isset( $options[ 1 ] ) ? $options[ 1 ] : null ,isset( $options[ 2 ] ) ? $options[ 2 ] : null ) == false ) $code |= $bit; $bit <<= 1; } } return $code; } }
使い方はこんな感じ
<?php $code = Request::FilterAll ( array ( Request::POST => array ( 'ID' => array ( Request::INT, 1 ) // ID は 1 以上の整数値で ,'NAME' => array ( Request::TXT, $dbh ) // NAME は禁止語句を含まないバイナリセーフな文字列 ,'EMAIL' => array ( Request::EMAIL ) // EMAIL はメールアドレス ) ) );
例えば、ID と EMAIL が引っかかった場合 0b0101 が返ってきます。ですので、
<?php if ( $code & 0x01 ) echo 'IDが不正です'; if ( $code & 0x02 ) echo 'NAMEが不正です'; if ( $code & 0x04 ) echo 'EMAILが不正です';
のようなことができます。