PHP strcmp 작동 원리


strcmp ()

[ PHP 목차 보기 ]

  • 두 문자열의 (사전적) 순서를 비교할 때 사용한다.
  • 비슷한 함수로는 strcasecmp()[참고1] 그리고 strncmp()[참고2]가 있다.

strcmp 함수

strcmp($string1, $string2);
- 첫번째 인자 자료형($string1): 문자열
- 두번째 인자 자료형($string2): 문자열
- 반환 자료형: int

0을 반환

  • 인자로 전달된 두 문자열이 정확히 같다면 0을 반환한다.
  • 대소문자를 구별한다. 같은 글자라도 대소문자가 다르면 0을 반환하지 않는다.
1
2
3
4
5
6
7
<?php
    echo ‘$str1=”Hello”, $str2=”Hello”<br>’;
    echo ‘strcmp($str1, $str2)의 출력값:<br>’;
    $str1 = “Hello”;
    $str2 = “Hello”;
    var_dump(strcmp($str1$str2));
?>
cs
$str1=”Hello”, $str2=”Hello”
strcmp($str1, $str2)의 출력값:
int(0)

음수 반환

  • 첫 문자열이 두 번째 문자열보다 사전 순서가 앞에 있다면 음수를 반환한다.
  • 사전 순서는 아스키 숫자에 의해 결정된다. 예를 들어 a는 97이고, c는 99이다. 따라서 아래 코드의 결과는 음수를 반환한다. (참고로 echo ord(“a”); 를 하면 아스키 숫자를 볼 수 있다.)
  • 여기서 주의할 점은 운영체제 별로 반환하는 음수 숫자가 다르다는 점이다. Windows, Linux에서는 -1이 나오고, Mac OS X에서는 경우에는 아스키 값의 차이 값 -2 (=97-99)가 출력된다.[참고3]
1
2
3
4
5
6
7
<?php
    echo ‘$str1=”a”, $str2=”c”<br>’;
    echo ‘strcmp($str1, $str2)의 출력값:<br’;
    $str1 = “a”;
    $str2 = “c”;
    var_dump(strcmp($str1$str2));
?>
cs
$str1=”a”, $str2=”c”
strcmp($str1, $str2)의 출력값:
int(-1)

  • 두 문자열의 시작 문자가 똑같다면, 그 다음 다른 문자가 나올 때까지 비교한다.
  • 아래 코드를 보면, 첫 문자열과 두 번째 문자열이 달라지는 부분은 Hello이후의 ‘a’와 ‘c’이다. 첫 문자열의 a의 아스키 코드가 더 작으므로 -1를 반환한다. (앞서 설명한 것처럼 Mac OS X에서는 아스키 값의 차이인 -2 (=97-99)를 반환한다.)
1
2
3
4
5
6
7
<?php
    echo ‘$str1=”Helloa”, $str2=”Helloc”<br>’;
    echo ‘strcmp($str1, $str2)의 출력값:<br>’;
    $str1 = “Helloa”;
    $str2 = “Helloc”;
    var_dump(strcmp($str1$str2));
?>
cs
$str1=”Helloa”, $str2=”Helloc”
strcmp($str1, $str2)의 출력값:
int(-1)

양수 반환

  • 첫 문자열이 두 번째 문자열보다 사전 순서가 뒤에 있다면 양수를 반환한다.
  • 아래 코드에서 첫 문자열의 c는 두 번째 문자열의 a보다 사전 순서가 뒤에 있기 때문에, 양수 1를 반환한다.
  • 위에서 설명한 것 처럼, Mac OS X에서는 아스키 숫자의 차이(2)를 반환한다.

1
2
3
4
5
6
7
<?php
    echo ‘$str1=”c”, $str2=”a”<br>’;
    echo ‘strcmp($str1, $str2)의 출력값:<br>’;
    $str1 = “c”;
    $str2 = “a”;
    var_dump(strcmp($str1$str2));
?>
cs
$str1=”c”, $str2=”a”
strcmp($str1, $str2)의 출력값:
int(1)

strcmp vs. == vs. === 비교

문자열을 같은 값을 가지는지 비교하기 위해서 strcmp함수 또는 동등 연산자 (==), 일치 연산자 (===)을 사용할 수 있다. 이 3가지 중에서 문자열 비교를 할 때 무엇을 사용하면 좋을까?

결론부터 말하자면, 문자열을 비교할 땐 무조건 일치 연산자(===)을 사용해야 한다. strcmp를 사용할 수도 있지만, 성능면에서 일치 연산자(===)가 훨씬 우수하다. 절대로 동등 연산자(==)를 문자열 비교에 사용하면 안된다. 왜냐하면 동등 연산자는 “자료형 자동변환”에 의해 의도치 않은 결과가 나올 수도 있기 때문이다.

동등연산자(==)를 문자열 비교에 사용하면 안되는 이유

  • 동등 연산자(==)는 자료형을 자동으로 바꾸기 때문에, 우리가 생각하기에 같지 않은 값들도 같다고 처리되는 경우가 있다.
  • 예를 들어, 아래 코드는 로그인을 위해서 입력 받은 값 $input과 데이터 베이스에 저장된 암호 $password를 비교하여 로그인 처리한다. 입력한 값 $input = “14e4″이고, 저장된 암호 $password=”140000″라고 할 때, 이 둘은 서로 다른 문자열인데 반해, 숫자로는 같은 값을 나타낸다. 14e4는 과학적 표기법(scientific notation)으로 140000와 같은 숫자이기 때문이다. 만약 단순히 이 두 변수를 동등 연산자(==)로 비교하게 된다면, 의도치 않게 false가 아닌 true 값을 반환하게 되고 로그인에 성공하게 된다.
1
2
3
4
5
6
7
8
9
<?php
    echo ‘입력받은 값 $input=”14e4″, 저장된 암호 $password=”140000″<br>’;
    echo ‘if ($password == $input)<br>’;
 
    $input = “14e4”;
    $password = “140000”;
    if ($password == $inputecho “- true: 로그인 되었습니다.”;
    else echo “- false: 비밀번호가 다릅니다.”;
?>
cs
입력받은 값 $input=”14e4″, 저장된 암호 $password=”140000″
if ($password == $input)
– true: 로그인 되었습니다.

  • 따라서 문자열의 정확한 비교를 하기 위해서는 strcmp함수 또는 일치 연산자(===)을 사용해야 한다. 하지만 성능면에서 일치 연산자가 우수하므로, 단순 비교를 위해서는 일치 연산자를 사용하고, 두 문자열의 크기(사전적 순서)를 비교할 때는 strcmp 함수를 사용한다.
1
2
3
4
5
6
7
8
9
<?php
    echo ‘입력받은 값 $input=”14e4″, 저장된 암호 $password=”140000″<br>’;
    echo ‘if ($password === $input)<br>’;
 
    $input = “14e4”;
    $password = “140000”;
    if ($password === $inputecho “- true: 로그인 되었습니다.”;
    else echo “- false: 비밀번호가 다릅니다.”;
?>
cs
입력받은 값 $input=”14e4″, 저장된 암호 $password=”140000″
if ($password === $input)
– false: 비밀번호가 다릅니다.

  • 일치 연산자(===) 말고 strcmp 함수를 문자열 비교에 사용하는 경우도 있다.
  • 일치 연산자는 boolean으로 반환하는 반면, strcmp는 int를 반환하기 때문에 usort, array_intersect 등의 함수에 바로 사용될 수 있다.
  • 아래의 코드는 다중 배열의 값들을 사전 순서로 배열하는 예제이다. usort()는 사용자 정의 함수에 따라 배열을 정렬하는 함수이고, 여기서 사용자 정의 함수는 0 또는 양수/음수를 반환해야 한다. 이런 경우 strcmp 함수를 응용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
    function cmp($a$b)
    {
        return strcmp($a[“fruit”], $b[“fruit”]);
    }
 
    $fruits[0][“fruit”= “lemons”;
    $fruits[1][“fruit”= “apples”;
    $fruits[2][“fruit”= “grapes”;
 
    usort($fruits“cmp”);
 
    print_r($fruits);
?>
cs
Array ( [0] => Array ( [fruit] => apples ) [1] => Array ( [fruit] => grapes ) [2] => Array ( [fruit] => lemons ) )

주의할 점: PHP 5.3과 그 이후 몇몇 버젼

  • PHP 5.3 (그 이후 몇몇 버젼)에서 strcmp의 인자로 배열을 넣게 되면, NULL 반환한다. 따라서 사용하는 서버의 PHP 버젼이 이에 해당하면 아래와 같은 코드를 조심해야 한다.
  • NULL 반환의 문제가 되는 상황을 생각해보면, 아래와 같은 코드로 로그인 인증을 했을 때 심각한 문제가 발생할 수 있다. 입력받은 값 $input이 배열로 들어오게 된다면, 저장된 암호 $password와 상관없이 strcmp($input, $password)는 NULL을 반환하게 된다. NULL == 0 은 true를 반환하게 되고, 로그인이 되어 버린다. 비번이 틀렸는데도 말이다.
  • 최신 버젼의 PHP에서는 strcmp 인자의 자료형으로 배열이 못 들어오게 막아 놨기 때문에 이러한 함정이 빠지지 않지만, 항상 일치 연산자(===)의 사용에 익숙해져 있는 것이 좋다.
1
2
3
4
5
6
7
8
9
<?php
    echo “strcmp(배열, 문자열): <br>”;
    
    $input = array(“any value”); // 실제로는 $input=$_POST[“input”] 식으로 값을 받을 수 있다.
    $password = “saved password”;
 
    if (strcmp($input$password== 0echo “- true: 로그인 되었습니다.”;
    else echo “- false: 암호가 틀렸습니다.”;
?>
cs
strcmp(배열, 문자열):
– true: 로그인 되었습니다.

Form Input에 배열(array)를 넣는 방법

  • 그럼, 어떻게 입력값에 배열로 넣을 수 있을까?
  • GET 방식으로 데이터를 받는다고 할 때, 주소창에 https://주소/?input[]=a 을 하게 되면 $input = array(“a”)와 같이 배열값이 입력된다.
  • 아래 예제처럼 코드를 작성하고, 주소창에 http://localhost/파일이름.php/?input[]=a 라고 입력해 보자. 그러면 $input의 자료형이 배열임을 확인할 수 있다.
1
2
3
4
<?php
    $input = $_GET[‘input’];
    var_dump($input);
?>
cs
array(1) { [0]=> string(1) “a” }

  • POST 방식으로 데이터를 받는다고 할 때도, curl이라는 프로그램을 이용하면 배열값을 입력할 수 있다.
  • curl -d input[]=a http://주소/파일.php 이라고 입력하면, $input의 자료형은 배열이된다.
  • 또는 아래와 같이 input 태그의 name 속성을 name=”input[]” 으로 바꿔줌으로써 배열값을 입력할 수도 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang=“en” dir=“ltr”>
    <head>
        <meta charset=“utf-8”>
        <title></title>
    </head>
    <body>
        <form action=“<?php echo $_SERVER[‘PHP_SELF’]?>” method=“post”>
            암호: <input type=“text” name=“input[]” value=“”>
            <input type=“submit”>
        </form>
 
        <?php
            if ($_SERVER[‘REQUEST_METHOD’=== “POST”) {
                $input = $_POST[‘input’];
                var_dump($input);
            }
        ?>
    </body>
</html>
cs
암호:
array(1) { [0]=> string(0) “” }

참고
[1] strcasecmp() 함수
[2] strncmp() 함수
[3] PHP 버그 리포트

[ PHP 목차 보기 ]

Leave a Reply