본문 바로가기

개발/PHP, Mysql

PHP 조작이 안되는 쿠폰번호 생성하기

PHP 조작 안되는 쿠폰 번호 생성하기.

PHP 조작 안되는 바코드 넘버 생성하기.


주민등록번호 생성 알고리즘을 이용하여, 조작이 안되는 쿠폰번호를 생성하는 방법입니다.

업무상 숫자로 구성된 쿠폰번호 5만개를 발행해야 하는 일이 생겨서, 만들어 본 김에

블로그에 포스팅 해봅니다.


쿠폰 번호의 제약 조건은 아래와 같습니다.

1. 숫자로만 구성되야 할 것.

2. 쿠폰의 번호는 20byte를 넘지 않을 것.

3. 임의로 쿠폰번호는 조작이 되지 않아야 할 것.


숫자로만 구성되야 하는 쿠폰 번호의 특성상 주민등록번호를 생성할 때 쓰이는 알고리즘을 사용하였습니다.

주민등록번호의 알고리즘은 "주민등록번호 알고리즘"을 구글에 검색하셔 참고하시는 편이 편하기에

여기서 따로 설명을 하지 않겠습니다.


위의 주민등록번호 알고리즘을 생성하여 쿠폰번호를 생성하는데, 문제는

주민등록번호의 각 자리수는 개인의 정보가 마킹 되어 있는데 

만들어야하는 쿠폰번호는 임의의 숫자로 구성되어 있지만 주민등록 생성 알고리즘을 이용하여

제작을 해야했습니다.


결론적으로 생성 순서를 정리하자면


1. Hash값을 추출한다.

2. Hash 값에서 숫자만 추출한다.

3. 숫자만 추출한 값에서 13자리의 숫자만 사용한다.

4. 추출한 13자리의 숫자를 주민등록번호의 검증 알고리즘으로 변경한다.

5. 1~11자리의 숫자는 추출한 숫자 그대로 사용한다.

6. 12자리의 숫자는 13번째 패리티비트에 알맞는 수로 변경한다.


Hash 함수는 md5를 사용하였습니다.

사용된 함수는 총 3개가 사용되었습니다.

1. makeHash(input) : 해시값을 생성하여, 해시값중 숫자만 추출, 숫자는 13자리까지만 추출하는 함수,

2. makeCoupon(input) : 추출한 13자리의 숫자를 이용하여 주민등록번호 검증이 가능한 쿠폰 번호로 생성해주는 함수,

3. checkCoupon(input) : 검증이 되는 숫자인지 체크하는 함수,


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
$count = 50000;
$make_count = 0;
$make_index = 0;
$coupon_array = array();
 
for($make_index=0$make_count<$count$make_index++) {
 
    $hash = makeHash($make_index);
    $coupon = makeCoupon($hash);
 
    if(checkCoupon($coupon)) {
        array_push($coupon_array$coupon);
        $make_count++;
    }
}
 
echo "Result <br/>";
echo "make_count : ".$make_count."<br/>";
echo "Coupon Count : ".count($coupon_array)."<br/>";
for($i=0$i<count($coupon_array); $i++) {
    
    if(checkCoupon($coupon_array[$i])) {
        $no = $i+1;
        echo $no." : ".$coupon_array[$i]." -- result : ";
        if(checkCoupon($coupon_array[$i])) {
            echo "TRUE <br/>";
            
            $query = "insert into coupon_list (coupon) value(?)";
            $stmt = $db->prepare($query);
            $stmt->execute(array($coupon_array[$i]));
            if(!$stmt) {
                echo "Error : ".$i."<br/>";
            }
        } else {
            echo "FALSE <br/>";
        }
    }
}
 
?>



위는 3가지 함수를 이용한 쿠폰 생성 프로그램의 Body 부분입니다.


Line 7 ~ 16 : 쿠폰번호를 생성하는 Body
Line 18 ~ 39 : 생성된 쿠폰 번호를 찍어보는 Body



1. makeHash(input)

1
2
3
4
5
6
7
8
<?php
function makeHash($input) {
    $hash = md5($input);
    $result = preg_replace("/[^0-9]*/s"""$hash);
 
    return substr($result013);
}
?>



해시 함수를 만드는 문자는 make_index의 변수를 사용하였습니다. make_index는 

위의 생성 body의 for문에서 생성되어 makeHash함수의 파라미터로 사용합니다.

md5로 생성된 해시함수에서 정규식을 이용하여, 숫자만 추출하고,

추출한 숫자의 문자열 중에선 13자리까지 사용할 목적의 함수입니다.



2. makeCoupon(input)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php
function makeCoupon($input) {
    $result = '';
    $hash_splite = str_split($input);
    $total = 0;
 
    $total += $hash_splite[0]*2;
    $total += $hash_splite[1]*3;
    $total += $hash_splite[2]*4;
    $total += $hash_splite[3]*5;
    $total += $hash_splite[4]*6;
    $total += $hash_splite[5]*7;
    $total += $hash_splite[6]*8;
    $total += $hash_splite[7]*9;
    $total += $hash_splite[8]*2;
    $total += $hash_splite[9]*3;
    $total += $hash_splite[10]*4;
 
    
    $buff_total = 0;
    $mod_result = 0;
 
    for($i=0$i<10$i++) {
        $buff_total = 0;
        $buff_total = $total + ($i*5);
        $mod_result = $buff_total % 11;
        $result_12 = 11 - $mod_result;
        if($result_12 == $hash_splite[12]) {
            $hash_splite[11= $i;
            break;
        }
    }
 
    for($j=0$j<13$j++) {
        $result .= $hash_splite[$j];
    }
 
    return $result;
}
?>



1번의 makeHash에서 만들어진 13자리의 숫자문자열을 배열로 나눕니다.

배열로 나뉜 각 자리수를 주민등록번호 생성알고리즘으로 사용하기 위해 각 자리수만큼 곱하는데,

중요한건 12자리수의 수는 13자리수(패리티비트) 검증에 맞는 숫자로 대체하기 위해 반복문을 통해

패리티 비트에 맞는 수로 변경해줍니다.

즉 makeCoupon의 함수 주목적은 13자리의 숫자중 12번째 숫자를 주민등록번호 생성 알고리즘에

부합하는 숫자로 변경해주는 함수 입니다.

완성된 13자의 숫자는 return 해줍니다.



3. checkCoupon(input)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
function checkCoupon($input) {
    $coupon_splite = str_split($input);
    $total = 0;
 
    $total += $coupon_splite[0]*2;
    $total += $coupon_splite[1]*3;
    $total += $coupon_splite[2]*4;
    $total += $coupon_splite[3]*5;
    $total += $coupon_splite[4]*6;
    $total += $coupon_splite[5]*7;
    $total += $coupon_splite[6]*8;
    $total += $coupon_splite[7]*9;
    $total += $coupon_splite[8]*2;
    $total += $coupon_splite[9]*3;
    $total += $coupon_splite[10]*4;
    $total += $coupon_splite[11]*5;
 
    $mod_result = $total%11;
 
    $check_num = 11 - $mod_result;
 
    if($coupon_splite[12== $check_num) {
        return TRUE;
    } else {
        return FALSE;
    }
}
?>



2번에서 생성된 13자리의 쿠폰번호가 주민등록생성 알고리즘으로 검사하여 올바르게 생성되었는지 체크해주는 함수입니다.
checkCoupon의 함수에는 실제 주민등록번호를 입력해도 검증이 됩니다.



생성된 쿠폰은 데이터베이스에 저장하여, 사용자가 조회시에 사용할려고 합니다.

추가로 쿠폰을 조작을 못하는 이유는 2가지로 정의됩니다.


1. 생성된 쿠폰번호번호가 주민등록번호 알고리즘으로 생성된 알고리즘이라는 것을 알더라도 hash값으로 생성된 값을 추출하여 쓴 무작위 숫자이기 때문에 어떤 수로 구성되어 있는지 알수 있는 방법이 없습니다.


2. 숫자를 임의로 조합하여 주민등록생성 알고리즘에 맞는 숫자를 생성해도 이미 생성된 쿠폰 번호는 데이터베이스에 저장되어 있기 때문에 데이터베이스에 저장되어 있는 수와 동일하게 만들지 않는 이상은 위변조가 어렵습니다.



결과 화면





#쿠폰번호생성#바코드번호생성#주민등록번호알고리즘



혹시 잘못된 정보로 인해 수정 요청을 하시거나, 다른 필요한 내용이 있으시면 댓글을 남겨주세요. 
댓글 피드백은 하루에 오전에 한번, 오후에 한번 확인 후 진행하겠습니다.