<?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
}