Skip to content
isdnetworks
Go back

화면 번호로 조회했는데 0건이었다

사용자 번호 8461039 계정을 확인해 달라는 문의를 받았다. 그 번호로 WHERE user_no = ? 를 돌리니 0건이 나왔다.

Table of contents

Open Table of contents

화면 번호가 변환된 값이었다

그 사람이 화면에서 그 번호를 보고 적어 준 것이므로 존재하지 않을 리가 없었다. 그러면 내가 WHERE 에 넣은 값이 user_no 와 다르다는 뜻이라 grep -rn 으로 화면에 그 번호를 찍는 코드를 찾았다.

echo encodeId($user->user_no);

user_no 가 그대로 안 나가고 변환된다. 데이터베이스에는 1204 같은 작은 수인데 화면에는 8461039 로 보인다.

왜 이렇게 하는지 물어보니 이유가 둘 있었다. user_noAUTO_INCREMENT 라 순차 번호가 그대로 보이면 규모가 드러난다. 회원 번호가 1204면 회원이 천 명대라는 것이 보인다. 그리고 /user/1204/user/1205 로 바꾸면 다른 사람 화면이 나올 수 있다.

원인 — 되돌리는 함수가 있었다

변환 함수 옆에 되돌리는 함수도 있었다.

function encodeId($n) { ... }
function decodeId($s) { ... }

조회할 때는 되돌린 값을 쓴다.

$userNo = decodeId($input);
$user = $this->db->where('user_no', $userNo)->get('user')->row();

이것을 몰라서 화면 번호로 직접 조회하고 있었다. decodeId 로 문의받은 값을 바꾸니 실제 user_no 가 나왔다.

문의를 확인할 때마다 변환을 손으로 하는 것은 번거로워서 관리자 화면에 변환 도구를 넣었다.

입력: 8461039
결과: user_no = 1204

반대 방향도 넣어서 데이터베이스에서 본 번호로 화면 주소를 만들 수 있게 했다. 이것을 만들고 나서 확인 시간이 크게 줄었다.

로그에 무엇을 남길지 정했다

로그에도 어느 번호를 남길지 문제가 됐다. 화면 번호를 남기면 문의와 대조하기 쉽고 내부 번호를 남기면 조회하기 쉽다.

log_message('info', "주문 처리 user={$userNo}(disp:" . encodeId($userNo) . ")");

둘 다 남겼다. 길어지지만 어느 쪽에서 와도 grep 으로 찾을 수 있다.

변환이 안 되는 값의 처리

잘못된 값을 넣으면 decodeId 가 이상한 수를 돌려줬다.

decodeId('abc');   // 0
decodeId('');      // 0

WHERE user_no = 0 은 어차피 0건이라 잘못된 입력과 없는 사용자가 구분이 안 된다. 이 둘은 답이 달라야 한다.

function decodeId($s) {
    if (!preg_match('/^\d{7,10}$/', $s)) {
        return false;
    }
    ...
}
$userNo = decodeId($input);
if ($userNo === false) {
    return error('잘못된 번호 형식입니다');
}

preg_match 로 형식을 먼저 보고 안 맞으면 조회 전에 오류로 알린다.

문서화와 남은 정리

사용자 번호만 변환하는지도 확인했다.

$ grep -rn "encodeId\|decodeId" --include=*.php application/ | wc -l
      38

주문 번호와 상품 번호도 같은 방식이었다. 각각 변환 결과가 겹치면 안 되는데 같은 함수를 쓰면 user_no=1204order_no=1204 가 같은 문자열이 된다.

encodeId($n, 'user');
encodeId($n, 'order');

대상별로 다른 값을 섞는 인자가 있었다. 다만 몇 군데에서 인자를 안 주고 있어서 기본값으로 처리돼 겹칠 수 있었고 전부 인자를 주게 고쳤다.

이 규칙이 어디에도 안 적혀 있어서 docs/ 에 적었다.

## 식별자 표기

데이터베이스의 순차 번호(user_no, order_no 등)는 화면과 주소에
그대로 나가지 않는다. encodeId()로 변환한 값이 나간다.

- 화면 번호 → 내부 번호: decodeId($s, $type)
- 내부 번호 → 화면 번호: encodeId($n, $type)
- 두 번째 인자를 반드시 준다. 안 주면 대상 간에 값이 겹친다
- 관리자 화면의 변환 도구: /admin/tools/id

안 적으면 이 시스템을 처음 보는 사람이 똑같이 0건을 받고 똑같이 헤맨다. 실제로 나 말고도 같은 일을 겪은 사람이 있었다.

정리


Share this post on:

Previous Post
로그인 하나에 서버가 셋이었다
Next Post
서버를 사는 대신 빌려 쓰기 시작했다 — 처음 한 달의 기록