* 자료공유가 아니라 작업기입니다ㅋ

 

드디어 (쓸데없이 만들어보는 습작) 회원탐색기 모듈을 (얼추) 완성했습니다. (얼쑤)

작업의 애초 목적은 닉네임 등을 한글 자소 분리한 뒤 DB에 담아둬서 좀 더 빠른 닉네임 자동완성을 해보려던 것이었습니다 :)

 

기진곰님의 모듈생성기로부터 시작해서,

기존에 제가 만들었던 회원소개 위젯회원검색 위젯을 기반으로,

개발해보쟈님의 사용자검색 모듈, 그리고 구름이님과 람보님의 썸씽 모듈을 살짝 참조했습니다.

 

엿보기 : https://bit.ly/2nMCn09 (엇? 근데 비회원도 볼 수 있게 돼 있는 거 맞죠?)

 

검색창에서 검색어를 입력하면 회원 프로필 이미지와 함께 닉네임이 자동완성 됩니다.

최대 5개의 회원정보를 불러오는데 exec_json 처리 속도가 0.08초가 조금 넘네요.

전체 회원수가 많은 사이트에서는 어떻게 될지... 는 아직 잘 모르겠습니다만, 기존의 사용자검색 모듈에 비해서는 속도가 빨라진 느낌이에요.

 

검색어를 입력하면 아래와 같은 액션?을 호출해서 자동완성으로 뿌려주게 됩니다.

function getUsers()
{
    $vars = Context::getRequestVars();
    $search_target = $vars->search_target;
    $search_keyword = $vars->search_keyword;

    $db_info = Context::getDBInfo();
    $prefix = $db_info->master_db['db_table_prefix'];
    $DB = DB::getInstance();
    $query = $DB->_query("SELECT *, 
        (LENGTH(". $search_target .") - LENGTH((REPLACE(". $search_target .", '". $search_keyword ."', '')))) / LENGTH('". $search_keyword ."') AS score, 
        INSTR(". $search_target .",'". $search_keyword ."') AS strpos 
        FROM ". $prefix ."user 
        WHERE ". $search_target ." LIKE '%". $search_keyword ."%' 
        ORDER BY score DESC, strpos ASC, ". $search_target ." ASC 
        LIMIT 0, 5");
    $result = $DB->_fetch($query);

    if ( !is_array($result) )
    {
        $result = array($result);
    }

    $user_list = array();
    if ( count($result) )
    {
        foreach ( $result as $key => $val )
        {
            $val->image = getModel('member')->getProfileImage($val->member_srl)->src;
            $user_list[$key] = $val;
        }
    }

    $this->add('user_list', $user_list);
}

검색어와의 유사도순으로 목록을 가져오려다보니 DB 쿼리가 조금 복잡하긴 합니다ㅎ

아직 완전히 구현하진 않았지만, 사용자정의 회원정보로도 자동완성을 구현하는 것도 무리가 없을 것 같습니다.

(현재 그냥 일반 검색 정도는 가능하게 해놨어요)

 

기진곰님 말씀으로는 글자 입력 때마다 작동을 하다보니 오버헤드가 발생할 수 있다고 하는데, 그건 좀 더 지켜봐야 할 것 같습니다.

jQuery UI의 자동완성 플러그인 자체적으로 시간 지연이 있어서인지 아직은 문제가 있는지 잘 모르겠더라구요.

 

... 모듈이 자리를 잡았으니, 여기서 생성한 DB 자료를 활용할 위젯을 만들어야겠네요.

이건 뭐, 기존에 만들었던 위젯이 있으니 금방 되겠죠?ㅎ

이제 자야겠습니다. 내일 일찍 일어나야 하는데ㅜㅜ

  • Lv16
    밤늦게까지!!!; 안주무시고! 또..!!!;
  • Lv16 Lv19
    이제 잘 거예욧!! 이온디님도 얼른 주무세요ㅎㅎ
  • Lv11

    오.. 역시 뚝딱..!

  • Lv11 Lv19
    뚝딱, 이라기보다는 정말 짬날 때마다 '똑딱똑딱똑딱..' 한 거여서 (단기 기억에 문제가 있는지라) 하다가 까먹고 하다가 까먹고의 반복이었어요ㅎ
  • ? Lv7
    리스펙!
  • Lv5
    고생하셨어요!!
  • ? Lv17
    경축 !! 윤삼님 모듈화 성공 (응?)
  • ? Lv17 Lv19
    제가 축하드려야죠ㅋㅋㅋ
    모듈의 세계는 정말 무궁무진한 거 같더라구요. 저는 아직 신생아 단계예요ㅎ
  • Lv24
    음..

    직접 쿼리문 쓰시지 말아요 ㅠㅠ

    저렇게 직접 쿼리문을 날리게 되면 오히려 보안이나 취약점이 생길 수 있어요 ㅠㅠㅠ..

    가급적이면 executeQuery 으로 xml 쿼리를 통해서 만드시는게 좋아요!
  • Lv24

    그리고 꿀팁..

    PHP 5.2 이던가 그 이상이라면 문자열을 나타낼때 쓰는 "" 쌍따옴표 안에 변수를 혼용해서 사용가능합니다.

    예를들어서

    $key = '문자열'
    
    $string = $key . '은 쌍따옴표안에서 점없이 사용해도됩니다.';
    
    $isString = "$key은 쌍따옴표안에서 점없이 사용해도됩니다.";
    
    if($string === $isString)
    {
        echo '참';
    }
    else
    {
        echo '거짓';
    }
     

     


    란 코드 있을때, 결과값은 "참" 이 나오게 됩니다.

     

    단, 조건이 있습니다.

     

    1. 무조건 변수로 들어가는 변수값은 문자열일 것.

    2. 오브젝트의 자식계열에서는 일부 에러가 생길 수 있습니다.

        e.g) $asd = "$string->isString은 오브젝트의 자식이라 오류가 생깁니다."

     

    무조건 변수자체가 스트링인게 확실한경우 이럴때 사용하시면 좋아요!

     

  • Lv24 Lv19

    쿼리문은 저야말로 xml로 만들고 싶었지만, 결과값을 유사도순으로 정렬해서 갖고 오려다보니 어쩔 수가 없었어요;;
    데이터를 갖고 온 다음에 php로 재정렬하는 방법도 생각해봤는데, 그러려면 일단 데이터를 전부 다 갖고 와야 하는 귀찮은 문제가 생기구요ㅜ

    근데 LENGTH, REPLACE, INSTR 같은 것들도 xml 쿼리문에서 구현이 되는 건가요? @.@
    된다면 완전 대박..

    PHP는 어차피 7.0 이상으로 초점이 맞춰지고 있으니 다음부턴 알려주신 '신세계' 꿀팁을 이용해봐야겠어요.
    변수 쓰고 마침표 찍고 따옴표 찍고 문자열 쓰고 따옴표 찍고 마침표 찍고 변수 쓰고;;; 쓰기에도 보기에도 늘 귀찮고 고된 일이었는데ㅎㅎ
    항상 많이 배웁니다. 감사합니다!

  • Lv19 Lv24

    http://www.xeschool.com/xe/xe_xml_query

    여기참고하셔서 사용하실 수 있으신것 어떤것이 있는지 확인해보시는것도 나쁘지 않습니다.

     

    아마 XE에서는 지원안될수 있겠네요 ㅠㅠ

     

  • Lv24 Lv19

    흐음, xml 쿼리에서 컬럼을 동적으로 생성하고 가져오는 방법을 시도해봐야겠네요.
    기존 자료들 보면 COUNT 말고는 딱히 이렇다 할 만한 게 없어서 지원이 아예 안 되는 줄 알았어요.

     

    덧: 그럼 그게 라이믹스에서만 되는 거예요? XEㅠ

  • Lv19 Lv24
    라이믹스에서는 XE에서 지원안되는 쿼리문중에서 몇몇 기능을 추가할 계획이 있다는 정도 아시면 될것같아요 ㅎㅎ
  • Lv19 Lv15

    참고로 <column name="" />에 LENGTH, REPLACE, INSTR 같은 함수도 쓸 수 있습니다. 함수 제한은 없습니다만, $search_target 와 같은 php 변수는 넣을 수 없습니다. 현재는 말이죠.

  • Lv15 Lv19
    대박이네요. php 변수를 xml 쿼리에 넣을 수 있다뇨. 이제 라이믹스 전용 서드파티가 속속 등장하겠네요. 완전 멋집니다!
  • Lv19 Lv15
    아뇨. 그게 아닌데요;;
  • Lv15 Lv19
    현재는 안 되지만 미래엔 도입된다는 말씀으로 이해했는데, 제가 너무 소망사고 + 확증편향을 한 건가요ㅜ
  • Lv19 Lv15
    반드시 필요하다면 도입되겠지만, 다른 길(php로 정렬)이 있고 성능상 별차이가 없다면 장담하기 어렵습니다.

    그리고 XML쿼리가 아닌 이상, 쿼리에 사용하는 $search_target 이런 파라미터 변수들은 반드시 필터링 과정을 거쳐야 합니다. 아니면 prepared statement 을 사용하거나... 안 그럼 SQL 인젝션 공격 당합니다.
  • Lv15 Lv19

    아, 어떤 말씀인지 알겠습니다.

    아마도 이런 이슈와 관련이 있는 거겠죠?

    https://github.com/xpressengine/xe-core/issues/882

     

    위의 링크 참조해서 이렇게 바꿔봤어요. (이건 model.php지만 view.php에서도 비슷한 방식으로 필터링을 했습니다)

    function getUsers()
    {
        $search_target_list = $this->getSearchOption(); // 지정된 검색옵션만 가져옴
        $vars = Context::getRequestVars();
    
        if( isset($search_target_list[$vars->search_target]) == FALSE )
        {
            $search_target = '';
        }
        else
        {
            $search_target = $vars->search_target;
        }
    
        $db_info = Context::getDBInfo();
        $prefix = $db_info->master_db['db_table_prefix'];
        $DB = DB::getInstance();
        $query = $DB->_query("SELECT *, 
            (LENGTH(". $search_target .") - LENGTH((REPLACE(". $search_target .", '". $search_keyword ."', '')))) / LENGTH('". $search_keyword ."') AS score, 
            INSTR(". $search_target .",'". $search_keyword ."') AS strpos 
            FROM ". $prefix ."user 
            WHERE ". $search_target ." LIKE '%". $search_keyword ."%' 
            ORDER BY score DESC, strpos ASC, ". $search_target ." ASC 
            LIMIT 0, 5");
        $result = $DB->_fetch($query);
     
        if ( !is_array($result) )
        {
            $result = array($result);
        }
     
        $user_list = array();
        if ( count($result) )
        {
            foreach ( $result as $key => $val )
            {
                $val->image = getModel('member')->getProfileImage($val->member_srl)->src;
                $user_list[$key] = $val;
            }
        }
     
        $this->add('user_list', $user_list);
    }

     

    제가 또 헛다리 짚은 건 아닌지;;;

  • Lv19 Lv15
    $search_target 변수에 , "' 이런게 들어가면 쿼리가 깨지니까요.
    https://opentutorials.org/module/411/3962
  • Lv15 Lv19

    으으으... 당분간 이 문제를 제대로 파악하는 공부를 해야겠네요.
    아아 즐거워라ㅠㅠㅠ

  • ? Lv4
    추천 드리고 갑니다. 통합 검색 하나를 만드셨네요!
  • ? Lv4 Lv19
    회원검색용 모듈이어서 그닥 쓸모가 막 있거나 그러진 않을 거 같아요. 특히 규모 있는 사이트에서 어떨지...
    그냥 경험 삼아 만들어보는 데 의의를 두려구요ㅎㅎ