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

 

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

작업의 애초 목적은 닉네임 등을 한글 자소 분리한 뒤 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 자료를 활용할 위젯을 만들어야겠네요.

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

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

윤삼

profile
아무래도 중급 초반 수준의 코딩 오타쿠인 것 같습니다.
  • profile
    밤늦게까지!!!; 안주무시고! 또..!!!;
  • profile profile
    이제 잘 거예욧!! 이온디님도 얼른 주무세요ㅎㅎ
  • profile

    오.. 역시 뚝딱..!

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

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

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

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

    그리고 꿀팁..

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

    예를들어서

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

     


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

     

    단, 조건이 있습니다.

     

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

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

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

     

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

     

  • profile profile

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

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

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

  • profile profile

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

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

     

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

     

  • profile profile

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

     

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

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

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

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

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

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

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

    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);
    }

     

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

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

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

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