PHP Filter는 사용자 입력과 같은 안전하지 않은 소스들로부터 오는 데이터를 필터링하고 유효한지 확인하는데 사용됩니다.


PHP Filter는 무엇인가?

PHP filter는 안전하지 않은 소스들로부터 오는 데이터를 필터링하고 유효성을 확인하는데 사용됩니다.

사용자의 입력 혹은 임의의 데이터를 테스트하고, 유효성을 확인하고, 필터링하는것은 어떤 웹 애플리케이션에서라도 중요한 부분입니다.

PHP filter 확장은 데이터 필터링을 더 쉽고, 더 빠르게 하기위해서 디자인되었습니다.



왜 Filter를 사용하는가?

거의 모든 웹 애플리케이션들이 외부 입력에 의존합니다. 대체로 외부 입력은 사용자 혹은 다른 웹 애플리케이션(웹서비스 같은것)으로부터 옵니다. filter를 사용함으로서 웹애플리케이션이 제대로 값을 입력받았는지 확인할 수 있습니다.


웹애플리케이션을 만드실때, 항상 모든 외부 데이터에 대해 filter를 사용하세요!

입력값의 필터링은 가장 중요한 애플리케이션 보안 이슈중 하나입니다.

외부 데이터는 아래의것들이 해당됩니다:

  • 폼으로부터 입력된 데이터
  • 쿠키
  • 웹서비스 데이터
  • 서버 변수
  • 데이터베이스 쿼리 결과

Filter 함수

변수를 필터링하려면, 아래 filter함수중 하나를 사용하세요:

  • filter_var() - 지정된 필터로 하나의 변수를 필터링합니다.
  • filter_var_array() - 몇 개의 변수들을 같은, 혹은 다른 필터들로 필터링합니다.
  • filter_input - 하나의 입력값을 받은다음, 그걸 필터링합니다.
  • filter_input_array - 몇 개의 입력값들을 받은다음 그것들을 같은, 혹은 다른 필터들로 필터링합니다.

아래의 예제에서, filter_var() 함수를 사용해서 정수의 유효성을 확인합니다.

<?php
$int = 123;
if(!filter_var($int, FILTER_VALIDATE_INT))
 {
 echo("Integer is not valid");
 }
else
 {
 echo("Integer is valid");
 }
?>


위의 코드에서는 "FILTER_VALIDATE_INT" 필터를 사용해서 변수를 필터링하고 있습니다. 정수가 유효하기 때문에, 위 코드의 출력 결과는 "Interger is valid"가 됩니다.

변수에 정수가 아닌값이 대입될 경우 (예: 123abc), 출력 결과는 "Integer is not valid"가 됩니다.



Validating(=유효성 확인)과 Sanitizing(=불필요한 문자열 제거) Filter

크게 아래와 같은 두 종류의 filter가 있습니다:


Validating filter:

  • 사용자 입력의 유효성을 확인하는데 사용됩니다.
  • 특정 형태/포맷으로 제한시킵니다. (URL 주소 혹은 E-Mail 주소의 유효성 확인 같은것.)
  • 문제가 발생했을때 성공 혹은 실패에 대해 기대된 타입이 반환되도록 합니다.

Sanitizing filter:

  • 문자열에서 특정한 문자들을 허용하거나 거부할때 사용됩니다.
  • 데이터 형태/포맷에 대해 제한시킬 수 없습니다.
  • 항상 문자열값을 반환합니다.

옵션(Option)과 플래그(Flag)

옵션과 플래그들은 지정된 필터에 부가적인 필터링 옵션들을 추가하기 위해서 사용됩니다.

서로 다른 필터는 서로 다른 옵션과 플래그들을 가지고 있습니다.

아래의 예제에서는 정수값을 filter_var() 함수와 "min_range", "max_range" 옵션들을 사용해서 유효성을 확인합니다.


<?php
$var=300;
$int_options = array(
"options"=>array
 (
 "min_range"=>0,
 "max_range"=>256
 )
);
if(!filter_var($var, FILTER_VALIDATE_INT, $int_options))
 {
 echo("Integer is not valid");
 }
else
 {
 echo("Integer is valid");
 }
?>

예제 코드처럼, 옵션은 위의 배열과 같은 "options"라는 이름을 가진 배열에 있어야 합니다. 플래그가 사용된다면 꼭 배열에 있어야할 필요는 없습니다.

정수값이 "300"으로 지정된 범위에 있지 않기 때문에, 위 코드의 출력 결과는 "Integer is not valid"가 됩니다.



입력값 유효성 확인하기(Validate Input)

이제 폼으로부터 입력된 값의 유효성을 확인해 봅시다.

우선 해야할일은 찾고있는 입력 데이터가 존재하는지 확인하는것 입니다.

그런다음 filter_input() 함수를 사용해서 입력 데이터를 필터링합니다.

아래의 예제에서는, 입력 변수 "email"이 PHP 페이지로 보내집니다:


<?php
if(!filter_has_var(INPUT_GET, "email"))
 {
 echo("Input type does not exist");
 }
else
 {
 if (!filter_input(INPUT_GET, "email", FILTER_VALIDATE_EMAIL))
  {
  echo "E-Mail is not valid";
  }
 else
  {
  echo "E-Mail is valid";
  }
 }
?>

예제 코드 설명

위의 예제에는 "GET" 방식으로 보내진 입력 (email)이 하나 있습니다:

  1. "GET" 타입의 "email" 입력 변수가 존재하는지 확인합니다.
  2. 입력 변수가 존재한다면, 유효한 e-mail 주소인지 확인합니다.

불필요한 문자열 제거하기(Sanitize Input)

폼으로부터 보내진 URL을 정리해 봅시다.

우선 찾고있는 입력 데이터가 존재하는지 확인해야 합니다. 

그리고 나선 filter_input() 함수를 사용해서 입력 데이터의 불필요한 문자열을 제거합니다.

아래의 예제에서는, 입력 변수 "url"이 PHP 페이지로 보내집니다:


<?php
if(!filter_has_var(INPUT_POST, "url"))
 {
 echo("Input type does not exist");
 }
else
 {
 $url = filter_input(INPUT_POST, 
 "url", FILTER_SANITIZE_URL);
 }
?>

예제 코드 설명

위의 예제에는 "POST" 방식으로 보내진 입력 (url)이 하나 있습니다:

  1. "POST" 타입의 "url" 입력이 존재하는지 확인합니다.
  2. 입력 변수가 존재한다면, sanitize로 잘못된 문자열들을 제거한다음, 그걸 $url 변수에 저장합니다.

잘못된 URL 주소가 입력되면 올바르게 고쳐지게 됩니다.


다중 입력 필터링하기

폼은 거의 대부분 1개의 입력필드 이상으로 구성되어 있습니다. filter_var나 filter_input 함수를 계속해서 반복적으로 호출하지 않으려면, filter_var_array 혹은 filter_input_array 함수를 대신 사용할 수 있습니다.

이번 예제에서는 3개의 GET 변수를 필터링하기 위해서 filter_input_array() 함수를 사용합니다.

입력받게되는 GET 변수는 이름, 나이, 그리고 e-mail 주소입니다:


<?php
$filters = array
 (
 "name" => array
  (
  "filter"=>FILTER_SANITIZE_STRING
  ),
 "age" => array
  (
  "filter"=>FILTER_VALIDATE_INT,
  "options"=>array
   (
   "min_range"=>1,
   "max_range"=>120
   )
  ),
 "email"=> FILTER_VALIDATE_EMAIL,
 );
$result = filter_input_array(INPUT_GET, $filters);
if (!$result["age"])
 {
 echo("Age must be a number between 1 and 120.<br />");
 }
elseif(!$result["email"])
 {
 echo("E-Mail is not valid.<br />");
 }
else
 {
 echo("User input is valid");
 }
?>

예제 코드 설명

위의 예제에는 "GET" 방식으로 보내진 3개의 입력 (이름, 나이, email)이 있습니다:

  1. 입력 변수들의 이름과 지정된 입력 변수들에 대해 사용된 필터들을 포함하는 배열을 설정합니다.
  2. GET 입력 변수들, 배열과 함께 filter_intput_array() 함수를 호출합니다. 
  3. $result 변수에 담겨있는 "age", "email" 변수가 올바른 입력인지 확인합니다. (입력 변수가 올바르지 않다면, filter_input_array() 함수 이후에서 거짓이되서 알맞은 오류 메시지가 표시됩니다.)

filter_input_array() 함수의 두번째 파라미터는 배열이나 하나의 filter ID가 될 수 있습니다.

만일 파라미터가 단일 filter ID 라면 입력 배열의 모든 값은 지정된 필터에 의해서 필터링됩니다.

만일 파라미터가 배열이라면 아래의 규칙들을 따라야 합니다:

  • 입력 변수들을 하나의 배열키로서 포함하고 있는 Associative 배열이어야만 합니다. ("age" 입력 변수처럼 말이지요)
  • 배열값은 filter ID 혹은 필터, 플래그, 옵션을 지정하고 있는 배열이어야 합니다.

Filter Callback 사용하기

사용자 정의된 함수를 호출하고 그걸 필터로 사용하는것이 FILTER_CALLBACK 필터를 사용하면 가능합니다.

이렇게하면, 데이터 컨트롤에 대해 풀로 컨트롤 할 수 있습니다.

자신만의 사용자 정의된 함수를 만들거나, 혹은 이미 존재하는 PHP 함수를 사용하는것이 가능합니다.

필터로 사용하려는 함수는 옵션이 지정되는것과 같은 방법으로 지정됩니다. "options"이란 이름을 가진 associative 배열안에 말이지요.

아래의 예제에서는, 모든 "_"을 공백으로 변환하는 커스텀 함수를 사용합니다.


<?php
function convertSpace($string)
{
return str_replace("_", " ", $string);
}

$string = "Peter_is_a_great_guy!";

echo filter_var($string, FILTER_CALLBACK,
array("options"=>"convertSpace"));
?>

위 코드로부터의 결과는 아래와 같아야합니다:

Peter is a great guy!

예제 코드 설명

위의 예제는 모든 "_"를 공백으로 바꿉니다:

  1. "_"를 공백으로 바꾸기위한 함수를 생성합니다.
  2. filter_var() 함수를 FILTER_CALLBACK 필터, 그리고 생성된 함수를 포함하고 있는 배열과 함께 호출합니다.