001002003004005006007008009010011012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061062063064065066067068069070071072073074075076077078079080081082083084085086087088089090091092093094095096097098099100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
<?php // (2020.5.9, 차재복, Cha Jae Bok, http://www.ktword.co.kr) //** 텍스트 내 단어들 중 `정보통신용어해설`의 키워드와 일치하면 링크를 줌 ** // 공통 함수 라이브러리 include_once "../base_utils/common_utils.php"; // pair_delimiter() 함수 사용 // 외부에서 직접 호출시 if (basename($_SERVER["SCRIPT_FILENAME"]) == 'file_transform_v2.php' and !empty($_POST['string'])) { session_start(); // 세션 스타트 include "../base_utils/db_conn.php"; // db 접속 // 전달 파라미터 처리 $no = $_POST['no']; $string = $_POST['string']; if ( isset($_REQUEST[no]) and !empty($no) and !is_numeric($no) or $no<0 ) exit; // 해킹방지 (수치>0) // string_transform 함수 호출 echo string_transform($string,$dbi,$no); // 텍스트 변환 함수 호출 } // 스트링 링크 교체를 위한 쿼리, 매 단어 교체, 관련 용어 업데이트(dict_related) function string_transform($string, $dbi, $no='') { // 좌우 공백문자 제거 $string = trim($string); // 제외 번호 삽입 if(!empty($no)) $except_no = "and a.no!=$no"; // 쿼리문 생성 및 쿼리 요청 $query = "select a.no,a.word,length(a.word) as len,b.synopsis from dict_word_list a left join cjb_dict b on a.no=b.no group by binary a.word having ( count(*)<2 {$except_no} ) order by len desc"; $result = mysqli_query($dbi, $query); if (mysqli_errno($dbi)) { echo mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n";} // 쿼리 결과에 따라, 각 레코드별 단어 링크 처리 $count = 1; $related_arr = array(); while ($matched = mysqli_fetch_assoc($result)) { // 공백 카운트 $space_cnt = substr_count($matched['word']," "); // 공백 있을 때 링크 처리 if ($space_cnt > 0) { // 공백 놔둔채 링크 처리 $result_arr = word_replace($string, $matched['word'], $matched['no'], $count, $no, $matched['synopsis']); if (count($result_arr) > 0) $related_arr = array_merge($related_arr,$result_arr); // 공백 전부 없애고 링크 처리 $result_arr = word_replace($string, str_replace(' ','',$matched['word']), $matched['no'], $count, $no, $matched['synopsis']); if (count($result_arr) > 0) $related_arr = array_merge($related_arr,$result_arr); // 공백 앞부터 하나씩 없애가며 링크 처리 $rest = $matched['word']; for ($i=1; $i<$space_cnt; $i++) { $before = strstr($rest,' ',true); $after = substr(strstr($rest,' '),1); $rest = $before . $after; $result_arr = word_replace($string, $rest, $matched['no'], $count, $no, $matched['synopsis']); if (count($result_arr) > 0) $related_arr = array_merge($related_arr,$result_arr); } // 공백 뒷부터 하나씩 없애가며 링크 처리 $rest = $matched['word']; for ($i=1; $i<$space_cnt; $i++) { $pos = strrpos($rest,' ',-1); // 맨끝 첫바이트 부터 우->좌로 검색 $before = substr($rest,0,$pos); $after = substr($rest,$pos+1); $rest = $before . $after; $result_arr = word_replace($string, $rest, $matched['no'], $count, $no, $matched['synopsis']); if (count($result_arr) > 0) $related_arr = array_merge($related_arr,$result_arr); } // 공백 없을 때 (그대로) 링크 처리 } else if ($space_cnt == 0) { $result_arr = word_replace($string, $matched['word'], $matched['no'], $count, $no, $matched['synopsis']); if (count($result_arr) > 0) $related_arr = array_merge($related_arr,$result_arr); } } // string 내 실제 교채 및 dict_related 업데이트 준비 foreach ($related_arr as $row ) { $left_add = "<a href='/test/view/view.php?no={$row['no_related']}' title='{$row['title']}'>"; $right_add = "</a>"; $string = str_replace("{;[".$row[in_no]."]^}", $left_add.$row['term'].$right_add, $string); $arr[] = "({$row['no']},'{$row['term']}',{$row['no_related']},{$row['in_no']})"; } // dict_related 업데이트 if (!empty($no) and count($related_arr) > 0) { mysqli_query($dbi,"delete from dict_related where no=$no"); mysqli_query($dbi,"insert into dict_related (no,term,no_related,in_no) values ".implode(',', $arr)); } // 결과 리턴 return $string ; // . count($related_arr) . $temp; } // 스트링 내 해당 단어 실제 교체 function word_replace(&$string, $word, $no, &$count, $parent_no, $synopsis='') { // 스트링 중에 찾는 단어 없으면 무조건 복귀 if ( mb_strpos($string, $word, 0) === false ) return array(); $word_len = mb_strlen($word); $left = 0; while ( ($left = mb_strpos($string, $word, $left)) !== false ) { if (is_skip($string, $word, $left)) { $left = $left + $word_len; continue; } $right = $left + $word_len; if (!empty($no)) { $erase_arr = ["\n","\r","\'","\"",">","<","/","[#","{#","#]","#}"]; // 불필요 문자들 $synopsis = str_replace($erase_arr," ",$synopsis); // 불필요 문자들 제거 (공백 교체) } $middle_word = trim(pair_delimiter($word,'[',']')); $replaced = "{;[".$count."]^}"; // 교체 대상 배열화 $string = mb_substr($string,0,$left) . $replaced . mb_substr($string,$right); $related_arr[] = array('no' => $parent_no, 'term' => $middle_word, 'title' => $synopsis, 'no_related' => $no, 'in_no' => $count++ ); $left = $left + mb_strlen($replaced); } return $related_arr; } // 교체 여부 결정 function is_skip($string, $word, $pos) { // 완전 일치 if ( $string == $word ) { return false; // no skip } // (불가 ①) 이미 a 링크화된 문자열 내에서는 skip $left = "<a "; $center = ">"; $right = "</a>"; // $right_pos = mb_strrpos(mb_substr($string,0,$pos),$left); $right_pos = mb_strrpos($string,$left,-(mb_strlen($string)-$pos)); // 3번째 인수의 -부호 : 끝에서 -n번째부터 역검색 if ( ($left_pos=mb_strpos($string,$left,$right_pos)) and ($center_pos=mb_strpos($string,$center,$left_pos)) and ($right_pos=mb_strpos($string,$right,$center_pos)) and ($pos > $left_pos and $pos < $right_pos) ) { return true; // skip } // (불가 ②) mathjax 스트링 내에서는 skip $left = '[#'; $right = '#]'; $right_pos=0; while ( ($left_pos=mb_strpos($string,$left,$right_pos)) and ($right_pos=mb_strpos($string,$right,$left_pos)) ) { if ($pos > $left_pos and $pos < $right_pos) return true; // skip $right_pos = $right_pos + mb_strlen($right); } $left = '{#'; $right = '#}'; $right_pos=0; while ( ($left_pos=mb_strpos($string,$left,$right_pos)) and ($right_pos=mb_strpos($string,$right,$left_pos)) ) { if ($pos > $left_pos and $pos < $right_pos) return true; // skip $right_pos = $right_pos + mb_strlen($right); } // (불가 ③) 직전,직후 2개 문자 $nok_chars = ['<a','a>']; $before_two_char = mb_substr($string,$pos-2,2); $after_two_char = mb_substr($string,$pos+mb_strlen($word),2); if ( in_array($before_two_char,$nok_chars) or in_array($after_two_char,$nok_chars) ) return true; // skip // (허용) 직전,직후 1개 문자 $ok_char = [' ',',','/',':','`','(',')','[',']','<','>','-','"',"'","\n","\r","\t","."]; $before_char = mb_substr($string,$pos-1,1); $after_char = mb_substr($string,$pos+mb_strlen($word),1); if ( in_array($before_char,$ok_char) and in_array($after_char,$ok_char) ) { // 양쪽 ok_char인 경우 return false; // no skip } else if ( ($pos == 0) and in_array($after_char,$ok_char) ) { // 맨처음인 경우 return false; // no skip } else if ( in_array($before_char,$ok_char) and (mb_substr($string,$pos) == $word) ) { // 맨끝인 경우 return false; // no skip } else if ( in_array($before_char,$ok_char) and (preg_match("/[\x{ac00}-\x{d7a3}]/u",$after_char)) ) { // 바로다음 한글인 경우 return false; // no skip } // otherwise return true; // skip }