<?php // (2024.12.20, 차재복, Cha Jae Bok, http://www.ktword.co.kr)
# 세션 스타트 (매 웹페이지 마다 필요)
session_start();
# db 접속 (dbi)
include_once "../base_utils/db_conn.php";
# (Ajax) 전달 파라미터 및 관련 함수 호출 목록
$script_file = substr($_SERVER['SCRIPT_NAME'],strrpos($_SERVER['SCRIPT_NAME'],"/")+1);
// if($script_file!='naviFetch.php') exit('ajax 형태가 아닌, 임의 외부 php로부터의 호출 의심');
// (type, choice, id, no)
$type = $_REQUEST['type'];
$choice = $_REQUEST['choice'];
$id = $_REQUEST['id'];
if ( isset($_REQUEST['id']) and !empty($id) and !is_numeric($id) or $id<0 ) exit('잘못된 fetch id'); // 해킹방지 (수치>0)
$no = $_REQUEST['no'];
if ( isset($_REQUEST['no']) and !empty($no) and !is_numeric($no) or $no<0 ) exit('잘못된 fetch no'); // 해킹방지 (수치>0)
$no = substr($no,0,10); // 해킹 방지 (글자 수 제한)
if($choice=='treeView' and isset($_REQUEST['id'])) {
if (!isset($_REQUEST['type']) or $type == 'word' or $type == 'multi')
ajaxFetchChildWord ($id, $dbi);
else if ($type == 'source') {
include_once "naviFetch_source.php";
ajaxFetchChildFile ($id, $dbi);
} else if ($type == 'src_tree') {
include_once "naviFetch_source.php";
ajaxFetchChildSrcTree ($id, $dbi);
} else if ($type == 'manual') ajaxFetchChildManual ($id, $dbi);
else if ($type == 'db_table') ajaxFetchChildDB ($id, $dbi);
} else if ($choice == 'ajaxFetchDetailSeparate' and isset($_REQUEST['no'])) {
include_once '../navigation/naviFetch_utils.php';
ajaxFetchDetailSeparate($no, $dbi);
} else if ($choice == 'ajaxFetchWord' and isset($_REQUEST['no'])) {
ajaxFetchWord($no, $dbi);
// 분류 검색
} else if ($choice == 'bunryuSearch' and isset($_REQUEST['sh'])) {
// (해킹방어) 긴 쿼리 스트링이면 무조건 거부
if (strlen($_SERVER['QUERY_STRING'])>120) exit;
// 해킹방어
$sh = $_REQUEST['sh'];
if (strtolower($sh) !== 'c++')
// $sh = urldecode($sh); // url decode
$sh = strip_tags($sh); // tag 제거
$sh = mb_substr(trim($sh),0,40,'utf-8'); // 좌 우 공백 제거 및 글자수 제한
$sh = str_replace(array(' ','\''),array(' ',' '),$sh); // 연속 공백 제거
$sh = str_ireplace('union all',' ',$sh); // union all 제거
// bunryu_search ($sh, $dbi);
bunryu_search_v2 ($sh, $dbi); // sql injection 해킹 공격 방어 (prepare statement)
} else if ($choice == 'ajaxFetchSourceView' and isset($_REQUEST['id'])) {
include_once "naviFetch_source.php";
ajaxFetchSourceView($id, $dbi);
} else if ($choice == 'srcScanDir') {
include_once "naviFetch_source.php";
srcScanDir($dbi);
// 소스 검색
} else if ($choice == 'srcSearch' and isset($_REQUEST['sh'])) {
include_once "naviFetch_source.php";
// (해킹방어) 긴 쿼리 스트링이면 무조건 거부
if (strlen($_SERVER['QUERY_STRING'])>120) exit;
// 해킹방어
$sh = $_REQUEST['sh'];
if (strtolower($sh) !== 'c++')
$sh = urldecode($sh); // url decode
$sh = strip_tags($sh); // tag 제거
$sh = mb_substr(trim($sh),0,40,'utf-8'); // 좌 우 공백 제거 및 글자수 제한
$sh = str_replace(array(' ','\''),array(' ',' '),$sh); // 연속 공백 제거
$sh = str_ireplace('union all',' ',$sh); // union all 제거
srcSearch($sh, $dbi); // sql injection 해킹 공격 방어
// id,no => path,name (ajaxIdNo4PathName)
} else if ($choice == 'ajaxIdNo4PathName' and (isset($_REQUEST['id']) or isset($_REQUEST['no']))) {
ajaxIdNo4PathName($id,$no,$dbi);
// default
} else if ($script_file=='naviFetch.php') {
echo json_encode( array('err_msg'=>'해당되는 선택 사항 없음'), JSON_UNESCAPED_UNICODE);
}
# (Ajax : 용어해설 분류) 용어해설 분류 id에 대해, 해당 관련 no들과 자식 id들을 쿼리하여, JSON 변환시켜 출력
// (대상 테이블 : gubun_tree_v2, book_idx)
function ajaxFetchChildWord ($id, $dbi) {
$query = "(select 'no' as item_type, titlename as name, no as id, 1 as rank, list_ord as ord, '0' as child, yoyak,
'0' as id_list
from book_idx where tree_id=$id)
union all
(select 'id' as item_type, name, id, 2 as rank, sub_seq as ord, child, yoyak,
path2node_v2 as id_list
from gubun_tree_v2 where parent=$id)
order by rank,ord,name";
$result = mysqli_query($dbi, $query);
if (mysqli_errno($dbi)) { $err_msg .= mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n"; }
if (!empty($err_msg)){
$return = array('err_msg'=>$err_msg);
} else {
while ( $matched = mysqli_fetch_assoc($result) ) {
$data[] = array('item_type'=>$matched['item_type'], 'id'=>$matched['id'], 'name'=>$matched['name'], 'child'=>$matched['child'], 'desc'=>$matched['yoyak'], 'parent' => $id, 'seq' =>$matched['ord'],
'idlist' =>$matched['id_list']);
}
if (count($data)<1) $return = array('err_msg'=>'해당 id 없음!');
else $return = array('data' => $data);
}
echo json_encode($return, JSON_UNESCAPED_UNICODE);
}
# (Ajax : 소스 관리 메뉴얼) 메뉴얼(reform) id에 대해, 해당 자식 id들을 쿼리하여, JSON 변환시켜 출력
// (대상 테이블 : reform)
function ajaxFetchChildManual ($id, $dbi) {
$query = "select id,name,child,yoyak from reform where parent=$id order by sub_seq";
$result = mysqli_query($dbi, $query);
if (mysqli_errno($dbi)) { $err_msg .= mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n"; }
if (!empty($err_msg)){
$return = array('err_msg'=>$err_msg);
} else {
while ( $matched = mysqli_fetch_assoc($result) ) {
$data[] = array('id'=>$matched[id], 'name'=>$matched[name], 'child'=>$matched[child], 'desc'=>$matched[yoyak]);
}
if (count($data)<1) $return = array('err_msg'=>'해당 id 없음!');
else $return = array('data' => $data);
}
echo json_encode($return, JSON_UNESCAPED_UNICODE);
}
# (Ajax : db 테이블 및 칼럼) database table을 쿼리하여, JSON 변환시켜 출력
// (대상 테이블 : information_schema.tables)
function ajaxFetchChildDB ($id, $dbi) {
if(!empty($_SESSION['db_name'])) $db_name = $_SESSION['db_name'];
else $db_name = 'test';
// $db_name = 'test';
$query = "select (@row_number:=@row_number + 1) as id,
table_name as name,
table_comment as yoyak,
'1' as child,
'table' as item_type
from (select @row_number:=0) as t, information_schema.tables
where table_schema='{$db_name}'";
$result = mysqli_query($dbi,$query);
if (mysqli_errno($dbi)) { $err_msg .= mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n"; }
if (!empty($err_msg)){
$return = array('err_msg'=>$err_msg);
} else {
while ( $matched = mysqli_fetch_assoc($result) ) {
// db 테이블
if($id == 0) {
$data[] = array('id'=>$matched['id'], 'name'=>$matched['name'], 'child'=>$matched['child'], 'desc'=>$matched['yoyak'], 'item_type' => $matched['item_type']);
// 특정 테이블 내 칼럼
} else if ($id == $matched['id']) {
$query = "select (@row_number:=@row_number + 1) as id,
concat(column_name,' : ',column_type) as name,
column_comment as yoyak,
'0' as child,
'field' as item_type
from (select @row_number:=0) as t, information_schema.columns
where table_name = '".$matched['name']."'
and table_schema = '{$db_name}'
order by name";
$result = mysqli_query($dbi,$query);
if (mysqli_errno($dbi)) { $err_msg .= mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n"; }
while ( $matched = mysqli_fetch_assoc($result) ) {
$data[] = array('id'=>$matched['id'], 'name'=>$matched['name'], 'child'=>$matched['child'], 'desc'=>$matched['yoyak'], 'item_type' => $matched['item_type']);
}
}
}
$return = array('data' => $data);
}
echo json_encode($return, JSON_UNESCAPED_UNICODE);
}
# (PHP included) 해당 no(leaf node)로부터 path 가져오기
// (대상 테이블 : gubun_tree_v2, book_idx)
function phpFetchPath ($no, $dbi) {
if(empty($no)) return;
$query = "select
c.id as leaf_id, c.titlename as leaf_name, c.path2node_v2 as full_path,
d.id as sub_id, d.name as sub_name, d.path2node_v2 as sub_path,
e.no as no_1st, e.list_ord
from
(select a.titlename,a.no,a.list_ord,b.id,b.name,b.path2node_v2 from book_idx a left join gubun_tree_v2 b on a.tree_id=b.id where a.no=$no) c
left join
gubun_tree_v2 d
on find_in_set(d.id,c.path2node_v2)
left join
book_idx e
on d.id=e.tree_id and e.list_ord=1
order by full_path,sub_path,list_ord";
$result=mysqli_query($dbi,$query);
if (mysqli_errno($dbi)) {echo mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n";}
while ( $matched = mysqli_fetch_assoc($result) ) {
// 적용 필드 (5) : leaf_id, leaf_name, sub_id, sub_name, no_1st
$name = ( $matched['sub_id']=='0' ? 'Top' : $matched['sub_name'] );
// $path_lines[$matched['leaf_id']]['upper_name'] = $matched['leaf_name'];
// $path_lines[$matched['leaf_id']]['leaf_id'] = $matched['leaf_id'];
if($matched['leaf_id'] == $matched['sub_id']) {
$path_lines[$matched['leaf_id']]['upper_id'] = $matched['sub_id'];
$path_lines[$matched['leaf_id']]['upper_name'] = $matched['sub_name'];
$path_lines[$matched['leaf_id']]['sub_path'] = $matched['sub_path'];
}
$path_lines[$matched['leaf_id']]['url_str'][$matched['sub_id']] =
"<span class='subMenu' data-id='".$matched['sub_id']."' data-direction='v' style='position:relative;'>
<span class='bullet'>▷</span>
<span class='title'>{$name}</span>
</span>
";
}
/*
echo "<pre>";
var_dump($path_lines);
echo "</pre>";
exit;
*/
$path = '';
if(count($path_lines) > 0)
foreach($path_lines as $key => $value) {
$path .= implode('',$value['url_str']);
$path .= '<br>';
}
else
$path .= "해당 id에 대한 path 없음";
return array('output'=>$path,'src_arr'=>$path_lines);
}
// 분류 검색
function bunryu_search ($sh, $dbi) {
if(mb_strlen($sh)<2) {
echo '최소 2자 이상';
return;
}
if(mb_strlen($sh)>15) {
echo '최대 15자 미만';
return;
}
$sh = mysqli_real_escape_string($dbi,$sh);
// 한글 (1),영어 (0) 구분
$lang = ( preg_match("/[\x{ac00}-\x{d7a3}][\x{ac00}-\x{d7a3}]/u", $sh) ? 1 : 0 );
if($lang==1) { // 한글
$sh_nospace = str_replace(' ','',$sh);
$where_phrase = "REPLACE(a.name,' ','') like '%{$sh_nospace}%'
or REPLACE(b.titlename,' ','') like '%{$sh_nospace}%'
or REPLACE(c.word,' ','') like '%{$sh_nospace}%'";
} else { // 영어
if(mb_strlen($sh) > 3) {
$where_phrase = "a.name like '%{$sh}%' or b.titlename like '%{$sh}%' or c.word like '%{$sh}%'";
} else if(mb_strlen($sh) <= 3) {
$where_phrase = "a.name like '{$sh}' or b.titlename like '{$sh}' or c.word like '{$sh}' or c.word like '{$sh} %'";
}
}
$query = "select a.id,a.name,a.yoyak,a.path2node_v2,b.titlename,b.no,
@path:=getpath_v2(a.id),
substring_index(substring_index(@path,'|',2),'|',-1) as pre_ord,
substring_index(substring_index(@path,'|',3),'|',-1) as path_str
from gubun_tree_v2 a left join book_idx b on a.id=b.tree_id left join dict_word_list c on b.no=c.no
where {$where_phrase}
order by pre_ord";
$result=mysqli_query($dbi,$query);
if (mysqli_errno($dbi)) {echo mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n";}
$str = '';
$prev = '';
$i = 0;
while ( $matched = mysqli_fetch_assoc($result) ) {
if($prev_titlename == $matched['titlename']) continue;
if($prev != $matched['name']) {
if($i!=0) {
$str = $str.' . . . ';
$str = $str."</span>";
$str = $str.'<br>';
}
$prev = $matched['name'];
$str = $str."<span class='idPathFocusEvent' data-idpath='{$matched['path2node_v2']}'
style='cursor:pointer;'>";
$str = $str.($j+1).') ';
// $str = $str.$matched['name'];
$str = $str."<span style='text-decoration:underline'>".str_replace('::','>',$matched['path_str'])."</span>";
$str = $str." : ";
$j = $j + 1;
}
if(!empty($matched['titlename'])) {
$str = $str.$matched['titlename'].', ';
$prev_titlename = $matched['titlename'];
}
$i = $i + 1;
}
if(mysqli_num_rows($result) <= 0) {
echo "검색 실패";
} else {
$str = $str.' . . . ';
$str = $str."</span>";
echo $str;
}
}
// 분류 검색 ver.2 (sql injection 해킹 공격 방어)
function bunryu_search_v2 ($sh, $dbi) {
if(mb_strlen($sh)<2) {
echo '최소 2자 이상';
return;
}
if(mb_strlen($sh)>20) {
echo '최대 20자 미만';
return;
}
$exclude = '/[.?*|^${}]/'; // '/[.?\+*|^$[\](){}]/'
$sh = preg_replace($exclude, ' ', $sh);
//echo $sh;
//return;
$sh = mysqli_real_escape_string($dbi, $sh);
// sql 특정 구문을 php로 동적 구현
$pattern_1 = ''; // where 구문에 들어갈 정규식 패턴 1
$pattern_2 = ''; // where 구문에 들어갈 정규식 패턴 2
$where = ''; // where 구문
$placeholder = ''; // stmt에서 바인딩될 변수들의 데이터 유형을 나타내는 문자열
$bindingArray = []; // stmt에서 바인딩될 문자열 배열
sql_para($sh, $placeholder, $bindingArray, $score, $pattern_1, $pattern_2, $where);
//echo $placeholder;
//echo strlen($placeholder).' '.count($bindingArray);
//return;
$query = "select a.id,a.name,a.yoyak,a.path2node_v2,b.titlename,b.no,c.word,
@path:=getpath_v2(a.id), # 재귀적(recursive)
substring_index(substring_index(@path,'|',2),'|',-1) as pre_ord,
substring_index(substring_index(@path,'|',3),'|',-1) as path_str,
{$score} as priority
from gubun_tree_v2 a left join book_idx b on a.id=b.tree_id left join dict_word_list c on b.no=c.no
where {$where}
order by
priority desc,
pre_ord, b.list_ord";
$stmt = mysqli_prepare($dbi, $query);
// if (mysqli_errno($dbi)) { echo mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n"; }
if (mysqli_errno($dbi)) { $err_msg .= mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n"; }
mysqli_stmt_bind_param($stmt, $placeholder, ...$bindingArray);
if (mysqli_errno($dbi)) { $err_msg .= mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n"; }
mysqli_stmt_execute($stmt);
// if (mysqli_errno($dbi)) { echo mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n"; }
if (mysqli_errno($dbi)) { $err_msg .= mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n"; }
$result = mysqli_stmt_get_result($stmt);
// if (mysqli_errno($dbi)) { echo mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n"; }
if (mysqli_errno($dbi)) { $err_msg .= mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n"; }
$prev_name = '';
$j = 0;
while ( $matched = mysqli_fetch_assoc($result) ) {
$name = $matched['name'];
$titlename = $matched['titlename'];
$word = $matched['word'];
// 분류명
if($prev_name != $name) {
$path_str_parts = explode('::', $matched['path_str']); // 문자열 분리
$last_name = end($path_str_parts); // 마지막 항목 추출, 배열의 마지막 요소 가져오기
$str_added = '';
// href
$str_added .= "<a href=\"javascript:idPathFocusDirect('".$matched['path2node_v2']."','','{$last_name}')\"
class='clickSpread' data-idpath='{$matched['path2node_v2']}' data-name='{$last_name}'
style='cursor:pointer;'>"; // idPathFocusEvent
// path 목록
$str_added .= "<span style='text-decoration:underline'>";
$str_added .= str_replace('::','>',$matched['path_str']);
$str_added .= "</span>";
// 빈 칸
$str_added .= "</a> : ";
$str .= $str_added;
$lines[$name]['path_html'] = $str_added;
$lines[$name]['path_idpath'] = $matched['path2node_v2'];
$lines[$name]['path_leafname'] = $last_name;
if ($matched['priority'] > 0) $lines[$name]['priority'] = $matched['priority'];
$prev_name = $name;
$j = $j + 1; // 줄 번호
}
// 대표명
if($prev_titlename != $titlename) {
// 대표명
$str_added = '';
$str_added .= "<a
href=\"javascript:idPathFocusDirect('".$matched['path2node_v2']."','".$matched['no']."','".$matched['titlename']."')\"
class='clickSpread' ";
$str_added .= " title=''>";
$str_added .= $titlename."</a>, ";
$str .= $str_added;
$lines[$name]['items'][$titlename]['word_html'] = $str_added;
$prev_titlename = $titlename;
}
// 용어명
if(empty($lines[$name]['items'][$titlename]['no'])) {
$lines[$name]['items'][$titlename]['no'] = $matched['no'];
$lines[$name]['items'][$titlename]['name'] = $word;
}
if(empty($lines[$name]['items'][$titlename]['word_list']))
$lines[$name]['items'][$titlename]['word_list'] = $word;
else
$lines[$name]['items'][$titlename]['word_list'] .= ', '.$word;
}
// $num_rows = mysqli_stmt_num_rows($stmt);
mysqli_stmt_close($stmt);
if(!empty($lines)) {
$str = '';
$j = 1;
foreach($lines as $key=>$value) {
if ($value['priority'] > 0) $str .= "<b>*";
$str .= "$j) ";
if ($value['priority'] > 0) $str .= "</b>";
$str .= $value['path_html'];
foreach($value['items'] as $ikey=>$ivalue) {
$ivalue['word_html'] = str_replace("title=''","title='{$ivalue['word_list']}'",$ivalue['word_html']);
$str .= $ivalue['word_html'];
}
$str .= ' . . . '.'<br>';
$j = $j + 1;
}
} else {
$err_msg .= "검색 실패";
}
$return = array('str'=>$str, 'err_msg'=>$err_msg, 'lines'=>$lines);
echo json_encode($return, JSON_UNESCAPED_UNICODE);
}
// sql 특정 구문을 php로 동적 구현
function sql_para($sh, &$placeholder, &$bindingArray, &$score, &$pattern_1, &$pattern_2, &$where) {
// 한글 (1),영어 (0) 구분
$lang = ( preg_match("/[\x{ac00}-\x{d7a3}][\x{ac00}-\x{d7a3}]/u", $sh) ? 1 : 0 ); // 1: 한글, 0 : 영어
// 용어명(c.word)에서, 순수 문자열 만 추출 (예: `블록 [전산]` => `블록`)
$pure = "replace(substring_index(c.word,'[',1),' ','')";
$sh = str_replace(['-','='],' ',$sh); // '-'를 ' '로 대치
$varStrArr = explode(' ',$sh); // 검색어를 빈 칸 구분자로 하는 부분문자열들의 배열로 변환
$varStrArr = processStringArray($varStrArr); // 변환된 부분문자열 배열 중 요소 문자열 길이가 1인 경우 처리 (예: c 언어)
if($lang==1) { // 한글
$score = "(case
when a.name=? or replace(a.name,' ','')=replace(?,' ','') then 3
when b.titlename=? or replace(b.titlename,' ','')=replace(?,' ','') then 2
when trim(substring_index(c.word,'[',1))=? or replace(c.word,' ','')=replace(?,' ','') then 1
# when (c.word regexp substring_index(?,' ',1)) and
# (c.word regexp substring_index(?,' ',-1)) then 1
else 0
end)";
// $placeholder .= str_repeat('s',substr_count($score,'?'));
$placeholder .= 'ssssss';
array_push($bindingArray, $sh,$sh,$sh,$sh,$sh,$sh);
// 배열 요소를 '(^| )요소($| )'로 감싸기
$wrappedArray = array_map(function($item) {
return '(^| )' . $item . '($| )';
}, $varStrArr);
// 구분자로 '|'를 사용하여 문자열로 합치기
$pattern_1 = implode('|', $wrappedArray); // 검색어를 빈 칸 구분자로 구분된 부분문자열로 변환 후, 정확한 단어별 매칭 패턴
$pattern_2 = str_replace(' ','',$sh); // 검색어 빈 칸 없앤 후에, 검색어를 앞,뒤부분 부분 매칭하기 위한 정규식 패턴
$pattern_3 = "(^| )$sh";
$where = "
concat( # 분류명,대표명,유사용어명을 한 줄로 표현
' ' # 앞 빈 칸
, concat_ws( # 결합 시 각 문자열 사이에 지정된 구분자를 삽입하는 함수
' ' # 결합 구분자를 `빈 칸`으로 정함
, a.name, replace(a.name,' ','') # 분류명
, b.titlename, replace(b.titlename,' ','') # 대표명
, c.word, replace(c.word,' ','') # 유사용어명
)
, ' ' # 뒤 빈 칸
)
REGEXP
? # 검색어 정규표현식 패턴 (pattern_1)
or
? like concat(replace(c.word,' ',''),'%') # 검색어 앞부분 부분 매칭을 위한 필드명 적용 (pattern_2)
or
? like concat('%',replace(c.word,' ','')) # 검색어 뒤부분 부분 매칭을 위한 필드명 적용 (pattern_2)
or
replace(c.word,' ','') regexp ? # 검색어가 용어명 앞,뒤부분 매칭 (pattern_3)
"; //
$placeholder .= str_repeat('s',substr_count($where,'?'));
array_push($bindingArray, $pattern_1,$pattern_2,$pattern_2,$pattern_3);
} else { // 영어
$score = "(case
when a.name=? then 3
when b.titlename=? then 2
when trim(substring_index(c.word,'[',1))=? then 1
when (? regexp substring_index(c.word,' ',1)) and
(? regexp substring_index(c.word,' ',-1)) then 1
when (c.word regexp substring_index(?,' ',1)) and
(c.word regexp substring_index(?,' ',-1)) then 1
else 0
end)";
$placeholder .= str_repeat('s',substr_count($score,'?'));
array_push($bindingArray, $sh,$sh,$sh,$sh,$sh,$sh,$sh);
/*
$array_sh = implode(' | ', $varStrArr);
$pattern_1 = " {$array_sh} ";
*/
// 배열 요소를 '(^| )요소($| )'로 감싸기
$wrappedArray = array_map(function($item) {
return '(^| )' . $item . '($| )';
}, $varStrArr);
// 구분자로 '|'를 사용하여 문자열로 합치기
$pattern_1 = implode('|', $wrappedArray); // 검색어를 빈 칸 구분자로 구분된 부분문자열로 변환 후, 정확한 단어별 매칭 패턴
$where = " concat(
' '
, concat_ws(
' '
, replace(a.name,'-',' ')
, replace(b.titlename,'-',' ')
, replace(c.word,'-',' ')
)
, ' '
)
REGEXP
? # $pattern_1
or
((? like concat(c.word,'%') or ? like concat('%',c.word)) and (char_length(c.word) > 3))
# 검색어 앞,뒤 부분 매칭을 위한 필드명 적용
";
$placeholder .= str_repeat('s',substr_count($where,'?'));
array_push($bindingArray, $pattern_1,$sh,$sh);
}
}
// 배열 중 요소 문자열 길이가 1인 경우
function processStringArray($arr) {
$count = count($arr);
// 첫 번째 조건 처리: 문자열 길이가 1 이하인 요소와 그 다음 요소 합치기
for ($i = 0; $i < $count - 1; $i++) {
if (strlen($arr[$i]) <= 1) {
// 길이가 1 이하인 요소와 그 다음 요소를 합치고, 그 자리에 삽입
$arr[$i] .= ' ' . $arr[$i + 1];
// 합친 후, 다음 요소를 제거
array_splice($arr, $i + 1, 1);
// 배열의 길이가 하나 줄어듦, 따라서 인덱스를 하나 빼고 다음 요소로 넘어가야 함
$count--;
$i--; // 다음 요소를 확인할 수 있도록 인덱스를 다시 조정
}
}
// 두 번째 조건 처리: 배열의 마지막 요소가 길이가 1 이하일 경우
if (strlen($arr[$count - 1]) <= 1 && $count > 1) {
$arr[$count - 2] .= ' ' . $arr[$count - 1];
array_splice($arr, $count - 1, 1);
}
return $arr;
}
// 용어 설명 fetch 송출
function ajaxFetchWord($no, $dbi) {
$query = "select abbr from cjb_dict where no={$no} limit 1";
$result = mysqli_query($dbi,$query);
if (mysqli_errno($dbi)) { $err_msg .= mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n"; }
$matched = mysqli_fetch_assoc($result);
if (!empty($err_msg)){
$return = array('err_msg'=>$err_msg);
} else {
$return = array('abbr' => $matched['abbr']);
}
echo json_encode($return, JSON_UNESCAPED_UNICODE);
}
function ajaxIdNo4PathName($id,$no,$dbi) {
if(empty($no) and !empty($id)) $where = "b.id={$id}";
else if(!empty($no) and empty($id)) $where = "a.no={$no}";
else if(!empty($no) and !empty($id)) $where = "b.id={$id} and a.no={$no}";
$query = "select a.no, a.titlename, b.id, b.path2node_v2, b.name
from book_idx a left join gubun_tree_v2 b on a.tree_id=b.id
where {$where}";
$result=mysqli_query($dbi,$query);
if (mysqli_errno($dbi)) {echo mysqli_errno($dbi)." : ".mysqli_error($dbi)."\n";}
while ( $matched = mysqli_fetch_assoc($result) ) {
$return[] = array('no'=>$matched['no'],'titlename'=>$matched['titlename'],'id'=>$matched['id'],'path'=>$matched['path2node_v2'],'name'=>$matched['name']);
}
echo json_encode($return, JSON_UNESCAPED_UNICODE);
}
?>