다음과 같은 커스텀 쿼리를 통해 동적 쿼리를 실행하려 하고 있습니다.
$columns = implode(',', $this->columnList); $tables = 'documents'; $conditions = 'documents.module_srl = ?'; $cond_args = array($args->module_srl); foreach ( $args->statusList as $key => $val ) { if ( $key === 0 ) { $conditions .= ' AND documents.status IN (?'; } else { $conditions .= ', ?'; } if ( $key === count($args->statusList) - 1 ) { $conditions .= ')'; } $cond_args[] = $val; } // (중간 생략) ~~~~ 각 변수들에 내용을 추가해서 동적 쿼리 생성 $navigation = ' ORDER BY ' . $args->sort_index . ' '. strtoupper($args->order_type) .' LIMIT ' . $args->list_count; $query = 'SELECT ' . $columns . ' FROM ' . $tables . ' WHERE ' . $conditions . $navigation; $oDB = DB::getInstance(); $stmt = $oDB->query($query, $cond_args); $result = $stmt->fetchAll(); debugPrint($result);
위와 같이 하면 $result에 목록은 잘 담깁니다.
다만 하이라이트한 6~21행처럼 status 컬럼으로부터 PUBLIC, SECRET, TEMP 등의 문서 상태를 가져오는 부분이 너무 발코딩이어서요ㅜ
https://github.com/rhymix/rhymix/pull/1332
여기에 있는 커스텀 쿼리 부분을 참고해서 하긴 했는데 이런 식으로 해도 되나요?
혹시 더 현명한 코드가 있을지 여쭙습니다.
아니면 제가 모르는 다른 문법이나 메소드가 더 있을지요.
커스텀 쿼리 방식은 제대로 따라하신 것이 맞습니다. 테이블 접두사 붙일 필요 없는 것까지 잘 파악하셨네요.
IN ( ... ) 쿼리는 XML 쿼리 문법을 사용하는 것이 압도적으로 편리합니다. operation="in"이라고 선언해 놓고 배열을 그대로 넘겨주기만 하면 알아서 SQL을 작성해 주니까요. (옛날처럼 쉼표로 구분해서 넘겨주는 방식도 지원하지만, 권장하지 않습니다. 어차피 다시 뜯어서 배열로 만듭니다. 비효율적이죠...)
굳이 IN ( ... ) 부분을 직접 작성하고 싶으시다면 아래와 같이 하는 것이 그나마 깔끔합니다.
그런데 쿼리문 작성에 관여하는 $this->columnList, $args->sort_index, $args->order_type, $args->list_count 등의 변수들 중 사용자 입력값에 영향을 받을 만한 것이 하나라도 있다면 SQL 인젝션 공격에 당할 수 있습니다. 그나마 LIMIT 뒤의 숫자는 물음표로 치환할 수 있지만, 컬럼명이나 정렬 방식은 prepared statement 처리가 불가능하기 때문에 언제나 위험에 노출되어 있습니다. 어떤 이유로든 SQL문에 PHP 변수를 끼워넣고 있다면 매우 높은 확률로 잘못하고 있는 것입니다.^^
결론: XML 쿼리 쓰세요.