Compare commits

...
99 Commits
Author SHA1 Message Date
thisgun 3e002199d5 버전 5.6.28 수정 2026-06-01 03:40:35 +00:00
thisgunandClaude Opus 4.8 7dde02d396 SMS 모듈 Add/Add2 매개변수 기본값 보정 (PHP 8 호환)
기본값 있는 $strDate 뒤에 기본값 없는 $nCount 가 선언되어 PHP 8.0+
에서 경고가 발생하던 것을 $nCount=0 기본값 부여로 해소.

- plugin/sms5/sms5.lib.php: Add(), Add2()
- lib/icode.lms.lib.php: Add() (LMS 부모 클래스 동일 패턴)

LMS 분기 호출부는 $strDate, $nCount 를 항상 함께 전달하므로
동작 변화 없음. PHP 5.2~8.3 호환 유지.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 01:02:26 +00:00
thisgunandClaude Opus 4.8 31871ee3e6 [security] 주문자 휴대폰 출력 인코딩 및 리다이렉트 URL 호스트 검증
- adm/shop_admin/orderform.php: 주문상세 hidden 의 od_hp 출력에
  get_text() 적용 (인접한 od_name 과 동일 처리, 누락분 보완)
- bbs/member_cert_refresh_update.php: 본인확인 갱신 후 이동 URL 에
  check_url_host() 적용
- plugin/social/includes/functions.php: 소셜 로그인/연동 후 이동
  URL 2곳에 동일하게 check_url_host() 적용

login_check.php 등 기존 코드와 동일한 호스트 검증 패턴으로,
같은 도메인/상대경로 복귀는 그대로 동작하고 타 도메인 이동만 차단.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 09:16:29 +00:00
thisgun ff9a7534ed Restore data htaccess on admin and write upload 2026-05-29 07:22:08 +00:00
thisgunandClaude Opus 4.8 9869be5970 [security] 토스 결제창 customerName 출력 시 get_text 인코딩 적용
토스페이먼츠 결제 요청 폼의 customerName hidden 필드에 주문자명
($od_name)이 인코딩 없이 출력되던 것을 get_text() 적용으로 정리.
직전 주문 필드 인코딩 처리와 동일한 맥락의 마무리.

hidden value 의 엔티티는 결제 SDK 가 값을 읽을 때 브라우저가
디코딩하므로 토스로 전달되는 구매자명에는 영향 없음.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 06:30:29 +00:00
thisgunandClaude Opus 4.8 1fa4467cd1 [security] 주문 관련 필드 출력 시 get_text 인코딩 적용
영카트 주문자명/받는분/입금자명(od_name, od_b_name, od_deposit_name)
이 일부 출력 지점에서 인코딩 없이 노출되어, 저장된 값이 HTML/속성
컨텍스트에서 그대로 렌더링되던 문제 수정. 다음 출력에 get_text() 적용:

- adm/shop_admin/orderform.php, sale1today.php (관리자 주문 화면)
- shop/orderinquiryview.php (PC/모바일/테마 주문조회)
- shop/{inicis,kcp,lg,nicepay,toss}/taxsave_form.php (현금영수증 발행 폼)
- shop/mail/orderupdate{1,2,3}.mail.php, ordermail.mail.php (주문 메일)

비회원 주문 시 입력값이 관리자 화면에서 실행될 수 있는 경로를 차단.
폼 value 의 엔티티는 브라우저 제출 시 디코딩되므로 PG 전송값 및
정상 표시에는 영향 없음.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 06:25:12 +00:00
thisgun 3e75ccea65 NHN KCP 휴대폰 본인확인(api_v2) 버전 추가 2026-05-29 06:14:21 +00:00
thisgun be9f50f96b Fix RSS warnings for invalid board requests 2026-05-29 01:33:45 +00:00
thisgun 7c217cb41b Restore alert newline handling 2026-05-28 06:23:04 +00:00
thisgun 5fc1c3bc27 버전 5.6.27 수정 2026-05-27 03:35:09 +00:00
thisgunandClaude Opus 4.7 d707c5abac data/ 디렉터리 git 추적 제외 (.htaccess 인덱스 제거)
.gitignore 에는 이미 data/ 가 등록되어 있으나 data/.htaccess
한 파일이 이전부터 트래킹되고 있어 배포본에 함께 포함되던 문제 정리.
디스크 파일은 그대로 두고 인덱스에서만 제거.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 02:28:39 +00:00
thisgunandClaude Opus 4.7 eeea46cb69 NHN KCP 가상계좌 발급 응답 코드 V000 허용
KCP 가이드 개정으로 가상계좌 발급 정상 응답이 0000 에서 V000 으로
변경되어, 기존 코드가 발급 성공을 실패로 인식하던 문제를 수정.
결제 hub 의 res_cd 비교 두 곳에서 V000 을 0000 과 동등하게 처리.

가상계좌 입금 완료 처리는 Webhook 입금통보가 담당하므로 본 변경과
무관. 취소/현금영수증/본인인증 경로는 V000 응답 대상이 아니므로
0000 단독 비교 유지.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 11:55:56 +00:00
thisgunandClaude Opus 4.7 669cce7011 주소 jibeon 값 화이트리스트에 'J' 추가
카카오 우편번호 서비스의 oncomplete 콜백이 userSelectedType
으로 'R'(도로명) 또는 'J'(지번)을 반환하는데, 서버 측 정규식이
'N|R' 만 허용해 지번 선택 시 빈 문자열로 저장되던 문제를 수정.
N 은 print_address() 의 도로명 표기 분기를 위한 레거시 값으로
호환을 위해 유지.

적용 위치: 회원가입(bbs/register_form_update.php), PC/모바일
주문(shop/, mobile/shop/ orderformupdate.php), 관리자 미완료
주문(adm/shop_admin/inorderformupdate.php) 의 7곳.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 11:46:36 +00:00
thisgunandClaude Opus 4.7 ee8b57eb13 미완료 주문 목록 PG 표시에 토스페이먼츠/NICEPAY 케이스 추가
dt_pg 값이 'toss' 또는 'nicepay' 인 건이 default 분기로 빠져
일괄 'KCP' 로 잘못 표시되던 문제 수정.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 11:40:18 +00:00
thisgun c927925a05 Fix PHP 5.2 compatibility issues 2026-05-26 09:34:18 +00:00
thisgun d914a7843d Fix PHP legacy array syntax 2026-05-26 08:10:57 +00:00
thisgun c04591e24a NHN_KCP 가상계좌 테스트 url 변경 2026-05-26 07:34:49 +00:00
thisgunandClaude Opus 4.7 a6fbbe6ad2 [security] 엑셀/CSV 다운로드 출력값 안전 처리
lib/common.lib.php 에 csv_safe_cell() 헬퍼 추가 (function_exists
가드 포함). 셀 값이 = + - @ TAB CR 로 시작하면 작은따옴표를 prefix
하여 스프레드시트가 수식으로 해석하지 못하도록 변환.

다음 출력 지점에서 사용자 입력 컬럼에 적용:
- adm/shop_admin/orderprintresult.php (CSV + XLS 두 분기)
- adm/shop_admin/orderdeliveryexcel.php
- adm/member_list_exel_export.php
- adm/sms_admin/num_book_file_download.php

호출부는 function_exists('csv_safe_cell') ? ... : 원본 폴백 형태로
감싸서 lib 미업데이트 환경에서도 fatal error 없이 동작하도록 함.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 07:30:21 +00:00
thisgunandClaude Opus 4.7 4c00c60006 [security]KVE-2026-0882 race condition 잔액 부족 시 결제 취소 처리로 변경
이전 커밋(e53689ac3)의 미수금 처리 방식은 사용자에게 결제 금액과
다른 청구가 발생해 혼란/분쟁을 유발할 수 있어, 동시 주문 race 로
포인트 잔액이 부족하면 결제 자체를 취소하는 방식으로 변경.

- PG 결제가 진행된 경우 (\$tno 존재): cancel_pg.inc.php 로 환불 요청
- 장바구니 복구: 기존 line 839 동일 패턴 (od_id = tmp_cart_id, ct_status = '쇼핑')
- 주문 삭제: g5_shop_order_table 에서 od_id 제거
- 사용자에게 die 로 명확한 오류 메시지 표시

lock timeout 케이스도 동일하게 결제 취소 처리 (보수적).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 07:10:53 +00:00
thisgunandClaude Opus 4.7 56b1958d37 [security]KVE-2026-0882 주문 포인트 차감 Race Condition (Double Spend) 수정
shop/orderformupdate.php / mobile/shop/orderformupdate.php 의 포인트
검증과 차감 사이에 TOCTOU race 가 존재하여, 동일 회원이 여러 세션으로
동시에 주문 제출 시 같은 포인트 잔액을 반복 검증 통과 → 다중 차감으로
mb_point 가 음수가 되는 double spend 가 가능했음.

insert_point() 의 기존 named lock 은 (mb_id, rel_table, rel_id, rel_action)
조합 키 기반이라 서로 다른 od_id 주문 간에는 lock 이 다르고, 주문 차감
호출에 rel_* 가 전달되지 않아 lock 미적용 상태였음.

조치: KVE-2026-0687 (쇼핑몰 쿠폰) 와 동일한 회원 단위 MySQL GET_LOCK
패턴을 적용. lock 획득 후 g5_point SUM 으로 잔액을 재조회하여
- 충분하면 정상 차감
- race 로 부족하면 사용 가능한 만큼만 차감 + 부족분은 od_receipt_point
  보정 + od_misu(미수금) 으로 반영하여 매장 손실 방지.

MyISAM 정책상 트랜잭션 금지이므로 named lock 으로 직렬화하는 방식이
가장 적합. 데스크톱·모바일 동일 패턴 적용.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 06:52:25 +00:00
thisgunandClaude Opus 4.7 6b2f9e094c [security] ORDER BY sst/sod 화이트리스트 누락 Blind SQL Injection 수정
KVE-2026-0876 동일 패턴 추가 발견 5건 일괄 수정.

- shop/itemuselist.php / mobile/shop/itemuselist.php (상품후기 목록)
- shop/itemqalist.php / mobile/shop/itemqalist.php (상품문의 목록)
  → 비회원 접근 가능한 공개 페이지에서 sst/sod 가 ORDER BY 절에
    검증 없이 삽입되어 CASE WHEN/SLEEP 기반 blind SQLi 가능했음.
    sst 는 컬럼 화이트리스트, sod 는 asc/desc 정규식으로 검증.

- bbs/list.php (게시판 목록)
  → sst 는 wr_datetime/wr_hit/wr_good/wr_nogood 화이트리스트 적용
    되어 있으나 sod 가 검증 누락되어 ORDER BY 절에 함수 표현식
    삽입이 가능했음. sod 에 asc/desc 정규식 검증 추가.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 06:32:28 +00:00
thisgun a781b4aef3 [KVE-2026-0876] 모바일 상품 리스트 sort 파라미터 Blind SQL Injection 수정 2026-05-26 06:27:53 +00:00
thisgun 8be4476f56 [KVE-2026-0869] 인스톨러 관리자 입력값 SQL Injection 수정 2026-05-26 05:22:52 +00:00
thisgunandClaude Opus 4.7 59d0b3c19c [security]KVE-2026-0859 KCP CLI Windows 환경 명령 인젝션(RCE) 수정
shop/kcp/pp_cli_hub_lib.php, shop/kcp/pp_ax_hub_lib.php 의
mf_do_tx() Windows 분기가 사용자 입력이 포함된 KCP CLI 인자를
큰따옴표로 감싼 단일 문자열로 만들어 mf_exec() 첫 인자로 전달했고,
mf_exec() 는 첫 인자를 escape 없이 exec() 에 넘겨 Windows cmd.exe
메타문자(`"`, `&` 등)로 인증 없는 OS 명령 실행이 가능했음.

Linux 분기와 동일하게 실행 파일 경로와 콤마 구분 인자 문자열을
분리하여 mf_exec($bin_exe, $args) 형태로 호출하도록 변경.
mf_exec() 의 foreach 가 두 번째 이후 인자에 escapeshellarg() 를
자동 적용하여 cmd.exe 메타문자가 안전하게 wrapping 됨.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 03:35:51 +00:00
thisgunandClaude Opus 4.7 f4f8c57a74 [security] 관리자 영역 권한 검증 누락 및 CSRF 토큰 누락 수정
- adm/qa_config_update.php / adm/contentformupdate.php :
  qa_include_head/tail, co_include_head/tail 가 super 가드 없이 변경 가능해
  하위 관리자가 임의 PHP 경로를 include 시킬 수 있던 LFI 위험을
  board_form_update.php 와 동일한 패턴(super 외에는 기존 값 유지)으로 차단.

- adm/member_form_update.php / adm/member_list_update.php :
  신규 회원 생성·일괄 수정 시 부여하려는 mb_level 상한 검증이 없어
  하위 관리자가 자기보다 높은 등급을 부여할 수 있던 권한 상승을 차단.

- adm/shop_admin/categorylistupdate.php /
  adm/shop_admin/itemformupdate.php :
  is_include_path_check 호출에서 두 번째 인자(is_input=1) 누락으로
  rar/php/zip wrapper 등 경로 wrapper 차단이 동작하지 않던 부분을
  is_include_path_check($file, 1) 로 강화.

- adm/shop_admin/orderdeliveryupdate.php /
  adm/shop_admin/orderpartcancelupdate.php /
  adm/sendmail_test.php :
  상태 변경 동작에 check_admin_token() 누락으로 발생하던 CSRF 위험을
  토큰 검증 추가로 차단. sendmail_test 폼에는 hidden token 필드 추가.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 03:35:29 +00:00
thisgunandClaude Opus 4.7 d5619707bc [security] 인스톨러 g5_shop_prefix PHP 코드 인젝션(RCE) 수정
install/install_db.php 의 g5_shop_prefix 가 dbconfig.php 의
define('G5_SHOP_TABLE_PREFIX','...') 문자열에 작은따옴표 escape 없이
삽입되어, 설치 전 노출된 인스톨러를 통해 임의 PHP 코드 주입 후 RCE
가능하던 문제를 수정. table_prefix·admin_id 와 동일하게 [^0-9a-z_]+
정규식 검증을 추가하여 영문자·숫자·언더스코어만 허용하도록 함.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 03:34:55 +00:00
thisgunandClaude Opus 4.7 9e7465319b [security]KVE-2026-0822 댓글 수정 textarea wr_content 미이스케이프 Stored XSS 수정
view_comment.skin.php 8종(skin/, mobile/skin/, theme/basic/ 하위 basic·
gallery)에서 댓글 수정($w == 'cu') 시 \$c_wr_content 가 textarea 내부에
이스케이프 없이 출력되어 </textarea> 페이로드로 탈출 가능하던 문제를
get_text() 적용으로 일괄 수정. 게시글 본문 수정(bbs/write.php) 과
동일한 escape 패턴을 댓글 수정에도 적용함.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 03:32:43 +00:00
thisgunandClaude Opus 4.7 f1f2150c67 [security]KVE-2026-0795 게시물 이동/복사 시 대상 게시판 권한 검증 누락 수정
bbs/move_update.php 가 원본 게시판 기준 $is_admin 만 검사하고 사용자
입력 chk_bo_table[] 의 대상 게시판에 대해서는 존재 여부만 확인하던
문제를 수정. 게시판 관리자(board)·그룹 관리자(group) 권한일 경우
대상 게시판의 bo_admin 또는 그룹의 gr_admin 이 본인인지 재검증하고,
일치하지 않으면 해당 대상 게시판 처리를 건너뛰도록 함. super 관리자는
기존 동작 유지.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 03:32:18 +00:00
thisgunandClaude Opus 4.7 3de722d3df [security]KVE-2026-0787 alert() JavaScript 이스케이프 누락 Stored XSS 수정
bbs/alert.php, bbs/alert_close.php 가 alert("$msg") 형태로 메시지를
JS 문자열 컨텍스트에 직접 삽입하던 부분을 수정. lib/common.lib.php 에
PHP 5.2 호환 폴백을 갖춘 get_js_safe_string() 헬퍼를 추가하고,
호출부에는 function_exists 가드를 걸어 부분 패치 환경에서도 안전하게
폴백되도록 함.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 03:31:24 +00:00
thisgunandClaude Opus 4.7 7119b4f612 [security]KVE-2026-0711 PG 리턴 처리 POST 키 이름 Reflected XSS 수정
XenoPostToForm::makeInputArray() 에서 POST 값·배열 인덱스는 이스케이프
되지만 최상위 POST 키 이름이 name 속성에 그대로 삽입되던 문제를 수정.
재귀 진입 시점에 htmlspecialchars() 로 키를 이스케이프하여 모든 깊이에서
안전하도록 함.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 03:30:47 +00:00
thisgunandClaude Opus 4.7 efaefbbd0e [security]KVE-2026-0687 쇼핑몰 쿠폰 다운로드 TOCTOU Race Condition 수정
MySQL GET_LOCK 으로 동일 회원·동일 쿠폰 다운로드 요청을 직렬화하여,
동시 요청 시 is_coupon_downloaded() 체크를 중복 통과해 쿠폰이 중복
발급되는 문제를 방지함.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 03:30:19 +00:00
thisgun b12bf551ec [security]XSS 취약점 및 token 추가 2026-05-26 03:29:51 +00:00
thisgun 65a419e9cd 버전 5.6.26 수정 2026-04-16 04:38:38 +00:00
thisgunandClaude Opus 4.6 3f32ecd3e6 회원정보 수정 시 약관변경내역 로그가 매번 쌓이는 버그 수정
수신설정 섹션이 폼에 표시되지 않는 경우(cf_use_promotion 미사용, 휴대폰 미사용,
아이코드 미사용 등) _default 변수가 undefined 상태가 되어 비교 시 항상 "변경됨"으로
판단되던 문제를 해결. _default 변수를 명시적으로 초기화하고, 폼에 없는 항목은
기존 DB 값을 유지하도록 수정.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 04:01:37 +00:00
thisgun b5d218d446 인증서 교체로 인한 (구)엘지모듈 토스 결제 안되는 문제 수정 2026-04-16 03:46:30 +00:00
thisgun f2e7dbc5ed [security]그누보드5 XSS, SQL Injection 취약점 수정 2026-04-16 03:46:02 +00:00
thisgunandClaude Opus 4.6 c38de4c94b [security]KVE-2026-0701 .shtml 확장자 필터 누락으로 인한 RCE 수정
- bbs/write_update.php, bbs/qawrite_update.php: 업로드 블랙리스트에 shtml|shtm 추가
- install/install_db.php, data/.htaccess: FilesMatch 정규식에 [Ss]? 추가하여 .shtml 차단

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 03:39:31 +00:00
thisgunandClaude Opus 4.6 7d8a660642 [security]KVE-2026-0693 비밀번호 재설정 토큰 예측 가능 취약점 수정
rand() 대신 CSPRNG 기반 get_random_token_string() 사용
- mb_nonce: 128비트 CSPRNG 토큰으로 시드 브루트포스 차단
- change_password: CSPRNG 기반 10자리 hex로 변경

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 03:39:12 +00:00
thisgunandClaude Opus 4.6 5875e8b86b [security]KVE-2026-0690 설문조사 결과 페이지 Local File Inclusion 수정
skin_dir 파라미터에 디렉토리 트래버설 검증이 없어
임의 경로의 PHP 파일을 include할 수 있는 취약점을
clean_relative_paths()로 경로 조작 문자열 제거하여 수정

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 03:38:41 +00:00
thisgunandClaude Opus 4.6 68a5b9c25a [security]KVE-2026-0689 SNS 공유 스킨 Reflected XSS 수정
$_SERVER['REQUEST_URI']를 JavaScript 문자열에 이스케이프 없이
출력하여 URL을 통한 Reflected XSS가 가능한 취약점을
json_encode()로 안전하게 이스케이프 처리

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 03:38:21 +00:00
thisgun 2dff49914b [security]KVE-2026-0710 그누보드5 SQL Injection 수정 2026-04-16 03:35:29 +00:00
thisgun 51518e45e4 [security]KVE-2026-0709 그누보드5 SQL Injection 수정 2026-04-16 03:31:35 +00:00
thisgun 7883ff65dc check_token 함수 쓰는곳 없지만 요청사항으로 인해 타임스탬프 추가 수정 2026-04-16 03:30:19 +00:00
thisgunandClaude Opus 4.6 a2608754bd [fix]SMS 직접입력 발송 시 PHP 8.x Undefined array key 경고 수정
case 'h' 직접입력 항목에 bg_no, mb_id, bk_no 키 누락으로 257행에서 Warning 발생

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 03:24:09 +00:00
thisgunandClaude Opus 4.6 758bb67b7b [security]KVE-2026-0685 소셜 로그인 계정 연결 CSRF 방어
popup.php에서 mylink 진입 시 Referer 검증 및 세션 토큰 설정
functions.php에서 social_user_profile_replace() 호출 전 세션 토큰 검증

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 03:23:50 +00:00
thisgun 0037f72cce [security]KVE-2026-0678 사용자 영역 CSRF 방어 추가 2026-04-16 03:23:00 +00:00
thisgunandClaude Opus 4.6 df940f8168 [security]KVE-2026-0676 폼메일 발신자 위장 및 Rate Limit 우회 수정
비회원 폼메일 발송 시 From 헤더를 관리자 이메일로 고정하고 사용자 입력은 Reply-To로 설정
formmail_send.php에 세션 기반 발송 횟수 제한 추가 (직접 POST 우회 방지)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 03:18:19 +00:00
thisgunandClaude Opus 4.6 614b040960 [security]KVE-2026-0673 비인증 이메일 변경을 통한 계정 탈취 취약점 수정
register_email_update.php에 로그인 검증·소유권 강제·ckey HMAC 검증·SQL 이스케이프 추가
member_cert_refresh_update.php에 로그인 검증 및 소유권 강제 추가 (연관 IDOR 선제 조치)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 02:55:19 +00:00
thisgun dccb50d8a3 [security]회원 ID/이메일 열거 공격 차단 2026-04-16 02:54:05 +00:00
thisgun 5331aa8be5 [security]sql_query() 에러 노출 시 SQL/스키마 정보 차단
sql_query()의 에러 처리가 die()로 SQL 쿼리 전문, MySQL 에러 메시지,
스크립트 파일 경로를 사용자에게 그대로 노출하고 있었음. 기본값
G5_DISPLAY_SQL_ERROR=false 덕분에 일반 호출에서는 트리거되지 않으나,
일부 admin 파일이 명시적으로 sql_query(\$sql, true)로 호출하여
관리자에게 raw SQL을 노출했고, SQLi 공격 시도 중 발생한 에러로 DB
구조(테이블/컬럼명)가 학습되어 정밀 공격에 활용될 수 있었음.

조치:
- 서버 로그(error_log)에는 항상 상세 기록 → 운영자가 디버깅 가능
- \$is_debug 모드(G5_DEBUG=true 또는 super admin)에서만 상세 표시
  + XSS 방지를 위해 htmlspecialchars로 escape
- 그 외 환경에서는 "데이터베이스 처리 중 오류가 발생했습니다." 만 표시
- mysqli/mysql 폴백 분기 둘 다 동일하게 적용

변경:
- lib/common.lib.php:1932 (mysqli 분기)
- lib/common.lib.php:1942 (mysql 분기, 레거시 PHP 5.x 폴백)

PHP 5.2.17 호환 유지 (htmlspecialchars + ENT_QUOTES 모두 PHP 4.0+).
2026-04-16 02:48:31 +00:00
thisgun 79f915988b [security]개인결제 hash 검증을 strict 비교(===)로 강화
shop/personalpayformupdate.php와 lib/shop.lib.php의 ss_personalpay_hash
검증이 loose 비교(==/!=)를 사용하여 PHP type juggling 잠재적 우회 가능성이
있었음. md5 결과 중 "0e..." 형식 hash는 PHP의 loose 비교에서 0e 지수
표기법으로 해석되어 다른 "0e..." 해시와 동등 판정될 수 있음
(소위 magic hash collision 패턴).

실제 익스플로잇 가능성은 낮지만 (md5 출력은 32자 hex 문자열이고 PHP의
문자열 vs 문자열 비교에서는 0e... 패턴이 적용되지 않는 경우가 많음),
defense in depth 차원에서 strict 비교로 변경.

mobile/shop/personalpayformupdate.php는 이미 strict 비교를 사용 중이라
core 두 곳만 동일한 패턴으로 정렬.

- shop/personalpayformupdate.php:35: != / != → !== / !==
- lib/shop.lib.php:2333: == → ===
2026-04-16 02:46:49 +00:00
thisgun 3cfe8b6b84 [security]현금영수증 발급 페이지 IDOR 취약점 수정 2026-04-16 02:43:22 +00:00
thisgun 31ef78e916 [perf]strstr() 불린 검사를 strpos() !== false 로 교체
strstr()은 일치하는 부분 문자열 전체를 반환하므로 존재 여부만 체크할
때는 메모리 할당이 낭비됨. strpos()는 위치(int) 또는 false만 반환하여
메모리 할당 없이 더 빠르게 동일 동작 수행.

적용 파일 (19개, 약 25곳):
- lib/common.lib.php: wr_option html1/html2/secret 검사 3곳
- lib/shop.lib.php: de_taxsave_types 검사 2곳
- lib/latest.lib.php: wr_option secret 검사 1곳
- lib/thumbnail.lib.php: wr_option secret 검사 1곳
- lib/URI/uri.class.php: URI 확장자 검사 1곳
- bbs/view.php: subject/wr_option/content 검사 4곳
- bbs/view_comment.php: wr_option secret 검사 1곳
- bbs/search.php: wr_option/sfl 검사 3곳
- bbs/rss.php: wr_option html 검사 1곳
- bbs/write_update.php: html1/html2 검사 2곳
- bbs/move_update.php: wr_option html 검사 1곳
- adm/admin.lib.php: auth 권한 검사 1곳
- adm/admin.head.php: 메뉴 권한 검사 1곳
- adm/session_file_delete.php: sess_ prefix 검사 1곳
- adm/point_list.php, adm/auth_list.php: sfl mb_id 검사 2곳
- adm/sms_admin/_common.php: install.php 검사 1곳
- adm/shop_admin/configform.php: de_taxsave_types 검사 3곳
- head.sub.php: admin dir 검사 1곳

규칙:
  strstr($a, $b)       → strpos($a, $b) !== false
  !strstr($a, $b)      → strpos($a, $b) === false

제외:
- theme/, skin/, plugin/ (사용자 커스터마이징/서드파티)
- strstr() 반환값을 실제로 사용하는 케이스 (예: lib/common.lib.php:4135
  if( \$freg = strstr(\$ori_params, '#') ), extend/gif2mp4.extend.php)
2026-04-16 02:29:32 +00:00
thisgun a612e69d3e [perf]for 루프 조건의 count() 호출을 루프 밖으로 추출 (핵심 파일)
for ($i=0; $i<count(\$arr); $i++) 패턴은 매 반복마다 count()를 호출하여
불필요한 CPU 오버헤드를 발생시킴. 루프 전에 한 번만 count()를 계산하여
변수에 저장하는 고전적인 최적화.

적용 파일 (19개, 41곳):
- lib/common.lib.php (8)
- common.php (2)
- lib/shop.lib.php (5)
- lib/naverpay.lib.php (1)
- lib/thumbnail.lib.php (2)
- bbs/list.php (1), bbs/search.php (4), bbs/qalist.php (1), bbs/qawrite.php (1)
- bbs/ajax.filter.php (1), bbs/write_update.php (4)
- bbs/write_comment_update.php (1), bbs/memo_form_update.php (2)
- bbs/new_delete.php (1), bbs/move_update.php (4)
- shop/search.php (1), shop/orderform.sub.php (1)
- mobile/shop/search.php (1), mobile/shop/orderform.sub.php (1)

부수 효과:
- lib/shop.lib.php line 2115: 동일 루프 내 strstr($dlcomp, $company)를
  strpos($dlcomp, $company) !== false 로 변경 (strstr 최적화의 일부)

제외:
- theme/, skin/, plugin/ (사용자 커스터마이징/서드파티)
- lib/PHPExcel/ (서드파티 라이브러리)
- adm/ 및 shop/mail/ (관리자/드문 경로, 별도 후속 작업 여지)
- 주석 처리된 코드 (bbs/delete.php:127, bbs/delete_all.php:143)
2026-04-16 02:26:59 +00:00
thisgun 29e55de1fa [perf]url_auto_link() 다중 regex 호출 조건부 실행으로 최적화
기존 구현은 일반 텍스트 게시글(URL/이메일이 전혀 없는 대부분의 경우)
에서도 3개의 preg_replace를 항상 호출하여, 모든 게시글 본문 렌더링
마다 불필요한 regex 컴파일/스캔 오버헤드가 발생.

개선:
1. Fast bailout: ://, www., @, &, ' 가 하나도 없으면 즉시 반환하여
   forward/reverse str_replace와 3개의 preg_replace를 모두 생략.
2. 조건부 regex 실행: 각 regex 호출 전에 해당 패턴이 실제로 존재하는지
   strpos로 먼저 확인. URL 패턴 없으면 URL regex 생략, 이메일 없으면
   email regex 생략 등.

strpos x5 (~1ms) vs preg_replace x3 (~20ms+) 이므로 일반 텍스트 게시글
에서 10~20배 이상 빠르게 동작. 페이지에 수십~수백 개 게시글을 표시하는
목록/검색 페이지에서 누적 효과가 큼.

의미론적 동등성 유지: 각 marker가 없으면 해당 regex가 원래도 no-op였으므로
조건부 실행은 결과에 영향 없음. Fast path는 모든 marker가 없을 때만
동작하므로 str_replace의 부작용(& entity 디코딩 등)도 발생할 여지가 없음.
2026-04-16 02:25:49 +00:00
thisgun c4db6e7751 [perf]cut_str() 메모리 사용량과 CPU 오버헤드 감소
기존 구현은 preg_split("//u")로 입력 문자열의 모든 문자를 PHP 배열로
분해한 뒤 count/array_slice/join 3단계로 처리하여, 짧은 문자열이든
긴 문자열이든 항상 문자 수만큼 배열 원소를 할당하고 regex를 호출함.

게시글 목록의 제목/내용 표시 등 페이지당 수십~수백 회 호출되는
핫패스에서 불필요한 오버헤드를 발생시킴.

개선:
1. 바이트 길이 빠른 경로: strlen(str) <= len이면 UTF-8 특성상 문자 수도
   보장되므로 즉시 반환. ASCII/짧은 제목은 mb_strlen 호출 없이 종료.
2. mbstring 확장 사용: mb_strlen + mb_substr로 배열 생성 없이 상수
   메모리로 길이 체크/절단 처리.
3. preg_split 기반 기존 로직은 mbstring 미설치 환경 폴백으로 유지.

의미론적 동등성 유지 (잘라낸 결과와 suffix 부착 조건 모두 동일).
2026-04-16 02:25:12 +00:00
thisgun 47a3790c57 [perf]bbs/list.php N+1 쿼리 2건을 IN 쿼리로 배치 조회로 전환
게시판 목록 페이지에서 발생하던 N+1 쿼리 패턴 2건을 제거:

1. 공지 처리 루프 (line 94~120):
   기존에는 bo_notice의 각 wr_id마다 sql_fetch를 따로 호출하여 공지가 N개면
   N개의 쿼리가 발생. 유효한 wr_id를 정수화하여 수집한 뒤 단일 IN 쿼리로
   일괄 조회하고, id 기반 해시맵으로 원래 순서대로 처리.

2. 검색 결과 2차 조회 (line 199~200):
   DISTINCT wr_parent 쿼리로 ID만 받은 뒤, 각 행마다 sql_fetch를 호출하여
   검색 결과가 N건이면 추가로 N개의 쿼리가 발생. 단일 IN 쿼리로 모든 부모
   글을 일괄 조회 후 $rows_to_process 배열에 원래 순서대로 정렬하여 공통
   처리 루프에서 소비. 검색/비검색 분기에서 중복되던 row→list 변환 로직도
   공통화.

효과 (공지 5개 + 검색 결과 20건 기준):
  기존: 1 DISTINCT + 20 fetch + 5 notice fetch = 26 쿼리
  개선: 1 DISTINCT + 1 IN(search) + 1 IN(notice) = 3 쿼리

부수 효과:
- 삭제된 공지/부모글에 대한 에러 처리 개선
  (기존은 empty row를 get_list에 넘겨 잠재적 오류, 개선판은 자동 스킵)
- wr_id 정수화로 SQL injection 방지 계층 추가
2026-04-16 02:23:24 +00:00
thisgun 2894c269ea [security]이메일 인증 페이지 접근 토큰을 HMAC-SHA256으로 강화 2026-04-16 02:21:23 +00:00
thisgun c00c73465a [security]비회원 주문/개인결제 조회 uid를 HMAC-SHA256으로 강화 2026-04-16 02:15:29 +00:00
thisgun 3e0e8be6da [security]쇼핑몰 update 엔드포인트 CSRF 보호 추가 2026-04-16 02:02:26 +00:00
thisgun 92a052fa7a [perf]html_purifier() 메모리 사용량 최적화
한 요청에서 html_purifier()가 N번 호출되면 매번 약 10~15MB의 HTMLPurifier
인스턴스를 새로 생성하여, 게시글 목록처럼 반복 호출되는 페이지에서
수백 MB~GB 단위로 메모리가 낭비되었음.

- HTMLPurifier 인스턴스를 요청 단위로 캐싱 (admin/normal 2개 변형만 유지)
- safeiframe.txt 파일 I/O + 파싱 결과도 요청 단위로 캐싱
- G5_HTMLPURIFIER_NO_CACHE 상수로 캐싱 opt-out 가능
  ($html 내용에 따라 config를 동적 변경하는 플러그인 호환용)

동작 변경:
- html_purifier_config / html_purifier_safeiframes hook은 캐시 미스 시점에만
  실행됨 (요청당 최대 2회). 정적 config를 설정하는 일반적인 hook에는 영향 없음.
- html_purifier_result hook은 매 호출마다 정상 실행됨.

효과 (게시글 목록 30건 + 첨부파일 평균 3개 = 120회 호출 기준):
  기존 ~1.8GB → 개선 후 ~15MB
2026-04-16 01:36:59 +00:00
thisgun 4ebdd8ba30 [fix]포인트 사용/환원 함수의 race condition 수정
insert_use_point, delete_use_point, delete_expire_point 함수의 SELECT-then-UPDATE
패턴이 동시 호출 시 데이터 무결성을 깰 수 있는 race condition을 가지고 있었음.
같은 회원의 포인트 작업이 동시에 발생하면 PHP 단에서 캐시한 잔여량을 기준으로
판단하여 결과적으로 음수/초과 차감 등 포인트가 꼬이는 현상이 발생.

MyISAM은 트랜잭션과 FOR UPDATE를 지원하지 않으므로, 락 없이 무결성을 보장하는
lock-free atomic UPDATE 패턴으로 재구현:

- 매 단계마다 가장 우선 처리할 행 1개를 SELECT (LIMIT 1)
- WHERE 절에 사전 검증 조건(잔여량/상태)을 포함한 원자적 UPDATE
- get_sql_affected_rows()로 성공/실패 판별, 실패 시 재시도
- max_iter=1000 안전장치로 무한루프 방지

특징:
- 단일 행 차감(가장 흔한 케이스)에서 기존과 동일한 쿼리 수
- GET_LOCK 등 추가 락 없음 → 같은 사용자 동시 요청도 throughput 손실 없음
- MyISAM/InnoDB 모두 호환, MySQL 5.0~8.x 모두 동작
2026-04-16 01:35:45 +00:00
thisgun 4d5c597665 [KVE-2026-0610]그누보드5 자동 로그인 취약점 수정 2026-04-16 01:31:19 +00:00
thisgun 7e65a297bf [KVE-2026-0608]그누보드5 Race Condition 취약점 수정
- bbs/poll_update.php: 설문조사 중복 투표 방지 (FIND_IN_SET을 WHERE에 포함한 원자적 UPDATE)
- bbs/good.php: 추천/비추천 카운터 부풀리기 방지 (INSERT IGNORE 우선 후 카운터 증가)
- lib/common.lib.php: insert_point() 포인트 중복 지급 방지 (MySQL named lock GET_LOCK 사용)
2026-04-16 01:07:17 +00:00
thisgun ddcc82d89b .gitignore 에 CLAUDE.local.md 추가 2026-04-16 01:00:28 +00:00
thisgun ad99ea7673 [KVE-2026-0599]그누보드5 XSS 취약점 수정 2026-04-06 06:27:09 +00:00
thisgun b3fa6dc127 [KVE-2026-0595]영카트5 SQL Injection 취약점 수정 2026-04-06 06:26:20 +00:00
thisgun e6780f3b4b 버전 5.6.25 수정 2026-04-06 03:47:15 +00:00
thisgun bededeaf01 .gitignore에 IDE 및 AI 도구 설정 파일 추가 2026-04-06 03:46:41 +00:00
thisgunandClaude Opus 4.6 73b868a444 Cloudflare IPv4 대역 업데이트: 104.16.0.0/12 → 104.16.0.0/13
공식 Cloudflare IP 목록(https://www.cloudflare.com/ips)에 맞게 수정

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 03:29:55 +00:00
thisgun eb249a2aee Merge branch 'master' of github.com:gnuboard/gnuboard5 2026-04-06 03:21:45 +00:00
HanbitGaram(ハンビッガラム)andGitHub 813fdef0c7 다음 우편번호 서비스 네임스페이스 및 서비스 도메인 변경 (#374) 2026-04-06 12:20:42 +09:00
kms0219kmsandGitHub f8561e9398 ✏️ feat: 토스페이먼츠 상점관리자 - ‘테스트모드‘ 추가 반영, NHN KCP 상점관리자 주소 변경 (#368)
* ✏️ feat: 토스페이먼츠 테스트모드 반영, KCP 주소 업데이트

* ✏️ feat: 토스페이먼츠 테스트모드 문구 반영, KCP 주소 업데이트

* ✏️ typo: KCP 테스트환경 주소 변경
2026-04-06 12:19:11 +09:00
thisgun 52590509d5 [KVE-2026-0559]그누보드5 SQL Injection 취약점 수정 2026-04-03 03:59:23 +00:00
thisgun 604cef808e [보안패치]그누보드 영카트 SQL_injection 취약점 수정 2026-03-31 01:21:11 +00:00
thisgun 82574fd4a8 [KVE-2026-0570]그누보드,영카트 SQL Injection 취약점 수정 2026-03-30 12:01:44 +00:00
thisgun c3db9b454e [KVE-2026-0569]그누보드,영카트 SQL Injection 취약점 수정 2026-03-30 11:50:30 +00:00
thisgun bf19cd8bf5 [KVE-2026-0568]영카트 SQL Injection 취약점 수정 2026-03-30 11:03:16 +00:00
thisgun b2c0e1af29 [KVE-2026-0554]그누보드,영카트 SQL Injection 취약점 수정 2026-03-30 09:52:41 +00:00
thisgun 60d37b853b [KVE-2026-0553]그누보드 SQL Injection 취약점 수정 2026-03-30 09:50:38 +00:00
thisgun 919b75a138 [KVE-2026-0340]그누보드_SQL_Injection취약점_수정 2026-03-26 03:38:19 +00:00
thisgun 01fab8136e git commit -am "[KVE-2026-0330]영카트_SQL_Injection취약점_수정"; 2026-03-26 01:32:14 +00:00
thisgun 5054e24631 [KVE-2026-0243]영카트주문시_쿠폰중복사용취약점_수정 2026-03-25 09:18:48 +00:00
thisgun deff7d2079 warning 메시지 수정 2026-03-25 05:06:29 +00:00
thisgun 5e6b4fa668 [KVE-2026-0242]영카트주문취소시_포인트복구취약점_수정 2026-03-25 04:59:56 +00:00
thisgun ef1be317e1 버전 5.6.24 수정 2026-02-03 06:25:50 +00:00
thisgun 137d78ff73 영카트 관리자모드 분류출력 개선 2026-02-03 06:24:34 +00:00
thisgun 0ddcda4b0c toss 모바일결제 포인트 적용시 결제 오류 수정 2026-02-02 09:37:49 +00:00
thisgun bf27af3925 영카트 shop_is_taxsave 에서 볌수 코드 오타 수정 2026-02-02 07:33:36 +00:00
thisgun 607e15424d 토스결제 비회원결제가 안되는 오류 및 모바일 개인결제 취소과정 코드 수정 2026-02-02 07:18:28 +00:00
thisgun 7c490448ec 메일보내기 발신자 위장 방지 및 암호화 키의 안전성 취약점 수정 2026-01-30 05:00:43 +00:00
thisgun d775d2255f [KVE-2026-0029]Stored XSS 취약점 수정 2026-01-27 05:50:34 +00:00
thisgun b94771de92 썸네일 파일 코드 위치변경 2026-01-27 03:34:20 +00:00
thisgun b29e16a198 게시판 관리자가 게시판 수정시 자동등록방지 숫자가 틀렸습니다 라고 나오는 오류 수정 2026-01-26 09:40:43 +00:00
thisgun 0e06b4f9ce 영카트5에서 사용자가 현금영수증 발급버튼이 출력되지 않는 오류 수정 2026-01-26 09:33:19 +00:00
thisgun f2ab751e5f [KVE-2025-0828]영카트 취약점 수정 2025-11-14 07:30:47 +00:00
thisgun 3432497efe 삼성브라우저PC버전 대응 2025-11-14 02:08:02 +00:00
총andGitHub 60bb03049e Merge pull request #61 from gnuboard/fix/admin-member-header
style: 관리자 > 회원관리 > 목록, 광고성 정보 수신 동의에 따른 테이블 폭 조정 처리
2025-09-25 10:07:49 +09:00
whitedot a7541256cb style: 관리자 > 회원관리 > 목록, 광고성 정보 수신 동의에 따른 테이블 폭 조정 처리 2025-09-25 10:02:25 +09:00
236 changed files with 17939 additions and 11835 deletions
+11
View File
@@ -13,6 +13,17 @@ cheditor5.*/
log/
g5_tree/
.vscode/
.claude/
.cursor/
.windsurf/
.idea/
.playwright-mcp
.mcp.json
.agents
.DS_Store
*.swp
*.swo
CLAUDE.local.md
naver*.html
initests01/
SIRsoft000/
+4
View File
@@ -3,6 +3,10 @@ define('G5_IS_ADMIN', true);
require_once '../common.php';
require_once G5_ADMIN_PATH . '/admin.lib.php';
if (function_exists('g5_check_data_htaccess')) {
g5_check_data_htaccess();
}
if (isset($token)) {
$token = @htmlspecialchars(strip_tags($token), ENT_QUOTES);
}
+1 -1
View File
@@ -42,7 +42,7 @@ function print_menu2($key, $no = '')
continue;
}
if ($is_admin != 'super' && (!array_key_exists($menu[$key][$i][0], $auth) || !strstr($auth[$menu[$key][$i][0]], 'r'))) {
if ($is_admin != 'super' && (!array_key_exists($menu[$key][$i][0], $auth) || strpos($auth[$menu[$key][$i][0]], 'r') === false)) {
continue;
}
+2 -2
View File
@@ -281,7 +281,7 @@ function auth_check($auth, $attr, $return = false)
$attr = strtolower($attr);
if (!strstr($auth, $attr)) {
if (strpos($auth, $attr) === false) {
if ($attr == 'r') {
$msg = '읽을 권한이 없습니다.';
if ($return) {
@@ -389,7 +389,7 @@ function order_select($fld, $sel = '')
// 불법접근을 막도록 토큰을 생성하면서 토큰값을 리턴
function get_admin_token()
{
$token = md5(uniqid(rand(), true));
$token = get_random_token_string(16);
set_session('ss_admin_token', $token);
return $token;
+1 -1
View File
@@ -17,7 +17,7 @@ $print_version = ($is_admin == 'super') ? 'Version ' . G5_GNUBOARD_VER : '';
</div>
<footer id="ft">
<p>
Copyright &copy; <?php echo $_SERVER['HTTP_HOST']; ?>. All rights reserved. <?php echo $print_version; ?><br>
Copyright &copy; <?php echo htmlspecialchars($_SERVER['HTTP_HOST']); ?>. All rights reserved. <?php echo $print_version; ?><br>
<button type="button" class="scroll_top"><span class="top_img"></span><span class="top_txt">TOP</span></button>
</p>
</footer>
+4 -1
View File
@@ -23,6 +23,9 @@ if (!$sst) {
$sst = "a.mb_id, au_menu";
$sod = "";
}
$allowed_sst = array('a.mb_id', 'mb_nick', 'au_menu', 'au_auth', 'a.mb_id, au_menu');
if ($sst && !in_array($sst, $allowed_sst)) $sst = 'a.mb_id, au_menu';
if ($sod && !in_array(strtolower($sod), array('asc', 'desc'))) $sod = '';
$sql_order = " order by $sst $sod ";
$sql = " select count(*) as cnt
@@ -151,7 +154,7 @@ $colspan = 5;
//if (isset($stx))
// echo '<script>document.fsearch.sfl.value = "'.$sfl.'";</script>'."\n";
if (strstr($sfl, 'mb_id')) {
if (strpos($sfl, 'mb_id') !== false) {
$mb_id = $stx;
} else {
$mb_id = '';
+16 -13
View File
@@ -39,14 +39,17 @@ $bo_include_tail = isset($_POST['bo_include_tail']) ? preg_replace(array("#[\\\]
$check_captcha = false;
// 관리자가 자동등록방지 CAPTCHA를 사용해야 할 경우
if ($w === 'u') {
if (isset($board['bo_include_head'], $board['bo_include_tail']) &&
($board['bo_include_head'] !== $bo_include_head || $board['bo_include_tail'] !== $bo_include_tail)) {
$check_captcha = true;
}
} elseif ($w === '') {
if ($bo_include_head !== '_head.php' || $bo_include_tail !== '_tail.php') {
$check_captcha = true;
// 최고 관리자인 경우에만 수정가능
if ($is_admin === 'super') {
if ($w === 'u') {
if (isset($board['bo_include_head'], $board['bo_include_tail']) &&
($board['bo_include_head'] !== $bo_include_head || $board['bo_include_tail'] !== $bo_include_tail)) {
$check_captcha = true;
}
} elseif ($w === '') {
if ($bo_include_head !== '_head.php' || $bo_include_tail !== '_tail.php') {
$check_captcha = true;
}
}
}
@@ -136,7 +139,7 @@ $bo_hot = isset($_POST['bo_hot']) ? (int) $_POST['bo_hot'] : 0;
$bo_image_width = isset($_POST['bo_image_width']) ? (int) $_POST['bo_image_width'] : 0;
$bo_use_search = isset($_POST['bo_use_search']) ? (int) $_POST['bo_use_search'] : 0;
$bo_use_cert = isset($_POST['bo_use_cert']) ? preg_replace('/[^0-9a-z_]/i', '', $_POST['bo_use_cert']) : '';
$bo_device = isset($_POST['bo_device']) ? clean_xss_tags($_POST['bo_device'], 1, 1) : '';
$bo_device = isset($_POST['bo_device']) ? addslashes(clean_xss_tags(stripslashes($_POST['bo_device']), 1, 1)) : '';
$bo_list_level = isset($_POST['bo_list_level']) ? (int) $_POST['bo_list_level'] : 0;
$bo_read_level = isset($_POST['bo_read_level']) ? (int) $_POST['bo_read_level'] : 0;
$bo_write_level = isset($_POST['bo_write_level']) ? (int) $_POST['bo_write_level'] : 0;
@@ -152,9 +155,9 @@ $bo_read_point = isset($_POST['bo_read_point']) ? (int) $_POST['bo_read_point']
$bo_write_point = isset($_POST['bo_write_point']) ? (int) $_POST['bo_write_point'] : 0;
$bo_comment_point = isset($_POST['bo_comment_point']) ? (int) $_POST['bo_comment_point'] : 0;
$bo_download_point = isset($_POST['bo_download_point']) ? (int) $_POST['bo_download_point'] : 0;
$bo_select_editor = isset($_POST['bo_select_editor']) ? clean_xss_tags($_POST['bo_select_editor'], 1, 1) : '';
$bo_skin = isset($_POST['bo_skin']) ? clean_xss_tags($_POST['bo_skin'], 1, 1) : '';
$bo_mobile_skin = isset($_POST['bo_mobile_skin']) ? clean_xss_tags($_POST['bo_mobile_skin'], 1, 1) : '';
$bo_select_editor = isset($_POST['bo_select_editor']) ? addslashes(clean_xss_tags(stripslashes($_POST['bo_select_editor']), 1, 1)) : '';
$bo_skin = isset($_POST['bo_skin']) ? addslashes(clean_xss_tags(stripslashes($_POST['bo_skin']), 1, 1)) : '';
$bo_mobile_skin = isset($_POST['bo_mobile_skin']) ? addslashes(clean_xss_tags(stripslashes($_POST['bo_mobile_skin']), 1, 1)) : '';
$bo_content_head = isset($_POST['bo_content_head']) ? $_POST['bo_content_head'] : '';
$bo_content_tail = isset($_POST['bo_content_tail']) ? $_POST['bo_content_tail'] : '';
$bo_mobile_content_head = isset($_POST['bo_mobile_content_head']) ? $_POST['bo_mobile_content_head'] : '';
@@ -173,7 +176,7 @@ $bo_write_min = isset($_POST['bo_write_min']) ? (int) $_POST['bo_write_min'] : 0
$bo_write_max = isset($_POST['bo_write_max']) ? (int) $_POST['bo_write_max'] : 0;
$bo_comment_min = isset($_POST['bo_comment_min']) ? (int) $_POST['bo_comment_min'] : 0;
$bo_comment_max = isset($_POST['bo_comment_max']) ? (int) $_POST['bo_comment_max'] : 0;
$bo_sort_field = isset($_POST['bo_sort_field']) ? clean_xss_tags($_POST['bo_sort_field'], 1, 1) : '';
$bo_sort_field = isset($_POST['bo_sort_field']) ? addslashes(clean_xss_tags(stripslashes($_POST['bo_sort_field']), 1, 1)) : '';
if (strpbrk($bo_skin.$bo_mobile_skin, "?%*:|\"<>") !== false) {
alert('스킨 디렉토리명 오류!');
+3
View File
@@ -32,6 +32,9 @@ if (!$sst) {
$sst = "a.gr_id, a.bo_table";
$sod = "asc";
}
$allowed_sst = array('a.gr_id', 'bo_table', 'bo_skin', 'bo_mobile_skin', 'bo_subject', 'bo_use_sns', 'bo_use_search', 'bo_order', 'a.gr_id, a.bo_table');
if ($sst && !in_array($sst, $allowed_sst)) $sst = 'a.gr_id, a.bo_table';
if ($sod && !in_array(strtolower($sod), array('asc', 'desc'))) $sod = '';
$sql_order = " order by $sst $sod ";
$sql = " select count(*) as cnt {$sql_common} {$sql_search} {$sql_order} ";
+3
View File
@@ -34,6 +34,9 @@ if ($stx) {
$sql_search .= " ) ";
}
$allowed_sst = array('gr_id', 'gr_subject', 'gr_admin', 'gr_order');
if ($sst && !in_array($sst, $allowed_sst)) $sst = '';
if ($sod && !in_array(strtolower($sod), array('asc', 'desc'))) $sod = '';
if ($sst) {
$sql_order = " order by {$sst} {$sod} ";
} else {
+3
View File
@@ -28,6 +28,9 @@ if (!$sst) {
$sst = "gm_datetime";
$sod = "desc";
}
$allowed_sst = array('gm_datetime', 'b.mb_id', 'b.mb_name', 'b.mb_nick', 'b.mb_today_login', 'a.gm_datetime');
if ($sst && !in_array($sst, $allowed_sst)) $sst = 'gm_datetime';
if ($sod && !in_array(strtolower($sod), array('asc', 'desc'))) $sod = '';
$sql_order = " order by {$sst} {$sod} ";
$sql = " select count(*) as cnt
+1 -1
View File
@@ -21,7 +21,7 @@ if (!is_file(G5_DATA_PATH . '/cache/browscap_cache.php')) {
}
require_once G5_PLUGIN_PATH . '/browscap/Browscap.php';
$browscap = new phpbrowscap\Browscap(G5_DATA_PATH . '/cache');
$browscap = new Browscap(G5_DATA_PATH . '/cache');
$browscap->doAutoUpdate = false;
$browscap->cacheFilename = 'browscap_cache.php';
+1 -1
View File
@@ -17,7 +17,7 @@ if ($is_admin != 'super') {
require_once G5_PLUGIN_PATH . '/browscap/Browscap.php';
$browscap = new phpbrowscap\Browscap(G5_DATA_PATH . '/cache');
$browscap = new Browscap(G5_DATA_PATH . '/cache');
$browscap->updateMethod = 'cURL';
$browscap->cacheFilename = 'browscap_cache.php';
$browscap->updateCache();
+24 -7
View File
@@ -415,10 +415,10 @@ if (!isset($config['cf_cert_use_seed'])) {
sql_query($sql, false);
}
if (!isset($config['cf_cert_kcp_enckey'])) {
$sql = "ALTER TABLE `{$g5['config_table']}`
$sql = "ALTER TABLE `{$g5['config_table']}`
ADD COLUMN `cf_cert_kcp_enckey` VARCHAR(100) NOT NULL DEFAULT '' AFTER `cf_cert_kcp_cd`; ";
sql_query($sql, false);
$config['cf_cert_kcp_enckey'] = '';
}
@@ -1068,7 +1068,24 @@ if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
<?php echo option_selected("", $config['cf_cert_hp'], "사용안함"); ?>
<?php echo option_selected("kcb", $config['cf_cert_hp'], "코리아크레딧뷰로(KCB) 휴대폰 본인확인"); ?>
<?php echo option_selected("kcp", $config['cf_cert_hp'], "NHN KCP 휴대폰 본인확인"); ?>
<?php echo option_selected("kcp_v2", $config['cf_cert_hp'], "NHN KCP 휴대폰 본인확인(api_v2)"); ?>
</select>
<div id="cf_cert_hp_kcp_v2_notice" style="display:<?php echo ($config['cf_cert_hp'] == 'kcp_v2') ? 'block' : 'none'; ?>; margin-top:8px; padding:10px 12px; background:#fff8e1; border:1px solid #ffd54f; border-radius:4px; color:#5d4037; line-height:1.5;">
<strong>NHN KCP 휴대폰 본인확인(api_v2)</strong> 사용 시,<br>
NHN KCP 상점관리자 &gt; 부가서비스 &gt; 휴대폰본인확인 &gt; 연동방식 설정 에서 <strong>신규 연동방식(V2) 사용여부를 &lsquo;사용&rsquo;</strong> 으로 변경해야 정상 동작합니다.
</div>
<script>
jQuery(function($){
function toggle_kcp_v2_notice() {
var is_kcp_v2 = $('#cf_cert_hp').val() === 'kcp_v2';
$('#cf_cert_hp_kcp_v2_notice').toggle(is_kcp_v2);
$('#cf_cert_kcp_cd_prefix').toggle(!is_kcp_v2);
}
$('#cf_cert_hp').on('change', toggle_kcp_v2_notice);
toggle_kcp_v2_notice();
});
</script>
</td>
</tr>
<tr>
@@ -1104,16 +1121,16 @@ if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
<tr>
<th scope="row" class="cf_cert_service"><label for="cf_cert_kcp_cd">NHN KCP 사이트코드</label></th>
<td class="cf_cert_service">
<?php echo help('SM으로 시작하는 5자리 사이트 코드중 뒤의 3자리만 입력해 주십시오.<br>서비스에 가입되어 있지 않다면, 본인확인 서비스 신청페이지에서 서비스 신청 후 사이트코드를 발급 받으실 수 있습니다.') ?>
<span class="sitecode">SM</span>
<input type="text" name="cf_cert_kcp_cd" value="<?php echo get_sanitize_input($config['cf_cert_kcp_cd']); ?>" id="cf_cert_kcp_cd" class="frm_input" size="3"> <a href="http://sir.kr/main/service/p_cert.php" target="_blank" class="btn_frmline">NHN KCP 휴대폰 본인확인 서비스 신청페이지</a>
<?php echo help('기존 NHN KCP 휴대폰 본인확인은 SM으로 시작하는 5자리 사이트 코드 중 뒤의 3자리만 입력해 주십시오.<br>NHN KCP 휴대폰 본인확인(api_v2)은 KCP에서 발급받은 5자리 사이트코드를 그대로 입력해 주십시오.<br>서비스에 가입되어 있지 않다면, 본인확인 서비스 신청페이지에서 서비스 신청 후 사이트코드를 발급 받으실 수 있습니다.') ?>
<span class="sitecode" id="cf_cert_kcp_cd_prefix" style="display:<?php echo ($config['cf_cert_hp'] == 'kcp_v2') ? 'none' : 'inline'; ?>;">SM</span>
<input type="text" name="cf_cert_kcp_cd" value="<?php echo get_sanitize_input($config['cf_cert_kcp_cd']); ?>" id="cf_cert_kcp_cd" class="frm_input" size="10" maxlength="10"> <a href="http://sir.kr/main/service/p_cert.php" target="_blank" class="btn_frmline">NHN KCP 휴대폰 본인확인 서비스 신청페이지</a>
</td>
</tr>
<tr>
<th scope="row" class="cf_cert_service"><label for="cf_cert_kcp_enckey">NHN KCP 가맹점 인증키</label></th>
<td class="cf_cert_service">
<?php echo help('(선택사항, 추후 NHN_KCP 상점관리자에서 인증키 발급 메뉴 오픈일정 이후부터 적용되는 내용입니다.)<br>NHN_KCP 상점관리자 > 기술관리센터 > 인증센터 > 가맹점 인증키관리 에서 인증키 발급 후에 인증키 정보를 입력') ?>
<input type="text" name="cf_cert_kcp_enckey" value="<?php echo get_sanitize_input($config['cf_cert_kcp_enckey']); ?>" id="cf_cert_kcp_enckey" class="frm_input" maxlength="100" size="40"> <a href="https://partner.kcp.co.kr" target="_blank" class="btn_frmline">NHN KCP 상점관리자</a>
<?php echo help('NHN KCP 상점관리자 > 기술관리센터 > 인증센터 > 가맹점 인증키관리 에서 인증키를 발급받아 입력해 주십시오.<br>NHN KCP 휴대폰 본인확인(api_v2)도 이 인증키 값을 사용합니다.') ?>
<input type="text" name="cf_cert_kcp_enckey" value="<?php echo get_sanitize_input($config['cf_cert_kcp_enckey']); ?>" id="cf_cert_kcp_enckey" class="frm_input" maxlength="100" size="70"> <a href="https://partner.kcp.co.kr" target="_blank" class="btn_frmline">NHN KCP 상점관리자</a>
</td>
</tr>
<tr>
+13 -2
View File
@@ -29,14 +29,25 @@ $co_id = isset($_REQUEST['co_id']) ? preg_replace('/[^a-z0-9_]/i', '', $_REQUEST
$co_subject = isset($_POST['co_subject']) ? strip_tags(clean_xss_attributes($_POST['co_subject'])) : '';
$co_include_head = isset($_POST['co_include_head']) ? preg_replace(array("#[\\\]+$#", "#(<\?php|<\?)#i"), "", substr($_POST['co_include_head'], 0, 255)) : '';
$co_include_tail = isset($_POST['co_include_tail']) ? preg_replace(array("#[\\\]+$#", "#(<\?php|<\?)#i"), "", substr($_POST['co_include_tail'], 0, 255)) : '';
// 최고 관리자가 아니면 include 경로 변경 불가 (board_form_update.php 와 동일 정책)
if ($is_admin !== 'super') {
if ($w == 'u') {
$co_include_head = isset($co_row['co_include_head']) ? $co_row['co_include_head'] : '';
$co_include_tail = isset($co_row['co_include_tail']) ? $co_row['co_include_tail'] : '';
} else {
$co_include_head = '';
$co_include_tail = '';
}
}
$co_tag_filter_use = isset($_POST['co_tag_filter_use']) ? (int) $_POST['co_tag_filter_use'] : 1;
$co_himg_del = (isset($_POST['co_himg_del']) && $_POST['co_himg_del']) ? 1 : 0;
$co_timg_del = (isset($_POST['co_timg_del']) && $_POST['co_timg_del']) ? 1 : 0;
$co_html = isset($_POST['co_html']) ? (int) $_POST['co_html'] : 0;
$co_content = isset($_POST['co_content']) ? $_POST['co_content'] : '';
$co_mobile_content = isset($_POST['co_mobile_content']) ? $_POST['co_mobile_content'] : '';
$co_skin = isset($_POST['co_skin']) ? clean_xss_tags($_POST['co_skin'], 1, 1) : '';
$co_mobile_skin = isset($_POST['co_mobile_skin']) ? clean_xss_tags($_POST['co_mobile_skin'], 1, 1) : '';
$co_skin = isset($_POST['co_skin']) ? addslashes(clean_xss_tags(stripslashes($_POST['co_skin']), 1, 1)) : '';
$co_mobile_skin = isset($_POST['co_mobile_skin']) ? addslashes(clean_xss_tags(stripslashes($_POST['co_mobile_skin']), 1, 1)) : '';
// 관리자가 자동등록방지를 사용해야 할 경우
if (((isset($co_row['co_include_head']) && $co_row['co_include_head'] !== $co_include_head) || (isset($co_row['co_include_tail']) && $co_row['co_include_tail'] !== $co_include_tail)) && function_exists('get_admin_captcha_by') && get_admin_captcha_by()) {
+1 -1
View File
@@ -586,7 +586,7 @@ td.td_grpset {width:160px;border-left:1px solid #e9ecee;text-align:center}
.td_time{text-align:center;width:130px}
.td_center{text-align:center;}
.td_type{width:120px}
.td_consent{width:200px}
.td_consent{min-width:70px;max-width:200px}
.td_mng_s{width:60px}
.td_mng_m{width:100px}
+57
View File
@@ -317,6 +317,63 @@ if (!isset($member['mb_marketing_agree'])) {
$is_check = true;
}
// 쿠폰 로그 테이블에 UNIQUE 인덱스 추가 (쿠폰 이중사용 방지)
if (defined('G5_USE_SHOP') && G5_USE_SHOP) {
$result = sql_query("SHOW INDEX FROM `{$g5['g5_shop_coupon_log_table']}` WHERE Key_name = 'idx_coupon_use'", false);
if (!$result || !sql_num_rows($result)) {
// 기존에 동일 쿠폰이 중복 사용된 데이터가 있으면 UNIQUE 인덱스 생성 실패하므로 중복 데이터 정리
$dup_sql = " SELECT cp_id, mb_id, MIN(cl_id) as keep_id
FROM `{$g5['g5_shop_coupon_log_table']}`
GROUP BY cp_id, mb_id
HAVING COUNT(*) > 1 ";
$dup_result = sql_query($dup_sql, false);
if ($dup_result && sql_num_rows($dup_result)) {
while ($dup_row = sql_fetch_array($dup_result)) {
echo $dup_row['cp_id']." 의 동일 쿠폰이 중복 사용된 데이터가 있으므로 인덱스 생성이 불가합니다. <br>";
$sql = " DELETE FROM `{$g5['g5_shop_coupon_log_table']}`
WHERE cp_id = '{$dup_row['cp_id']}'
AND mb_id = '{$dup_row['mb_id']}'
AND cl_id != '{$dup_row['keep_id']}' ";
if ($is_admin === 'super') {
echo "데이터베이스에서 검토후에 이 쿼리문을 실행해 주세요.<br>$sql<br>";
}
// sql_query($sql);
}
}
// MyISAM + utf8mb4 환경에서 키 길이 초과 방지: cp_id varchar(100), mb_id varchar(100)으로 조정
sql_query("ALTER TABLE `{$g5['g5_shop_coupon_log_table']}` MODIFY `cp_id` varchar(100) NOT NULL DEFAULT '', MODIFY `mb_id` varchar(100) NOT NULL DEFAULT ''", false);
sql_query("ALTER TABLE `{$g5['g5_shop_coupon_log_table']}` ADD UNIQUE KEY `idx_coupon_use` (`cp_id`, `mb_id`)", false);
$is_check = true;
}
}
// 자동 로그인 토큰 테이블 생성 (KVE-2026-0610: 추측 가능한 자동 로그인 쿠키 위조 방지)
// 다중 디바이스 지원을 위해 회원당 여러 토큰을 별도 테이블로 관리
if (!isset($g5['member_auto_login_table'])) {
$g5['member_auto_login_table'] = G5_TABLE_PREFIX.'member_auto_login';
}
if (!sql_query(" DESC `{$g5['member_auto_login_table']}` ", false)) {
sql_query(" CREATE TABLE IF NOT EXISTS `{$g5['member_auto_login_table']}` (
`al_id` int(11) NOT NULL auto_increment,
`mb_id` varchar(20) NOT NULL default '',
`al_token` varchar(64) NOT NULL default '',
`al_user_agent` varchar(255) NOT NULL default '',
`al_ip` varchar(45) NOT NULL default '',
`al_created` datetime DEFAULT NULL,
`al_last_used` datetime DEFAULT NULL,
`al_expire` datetime DEFAULT NULL,
PRIMARY KEY (`al_id`),
UNIQUE KEY `al_token` (`al_token`),
KEY `mb_id` (`mb_id`),
KEY `al_expire` (`al_expire`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ", true);
$is_check = true;
}
$is_check = run_replace('admin_dbupgrade', $is_check);
$db_upgrade_msg = $is_check ? 'DB 업그레이드가 완료되었습니다.' : '더 이상 업그레이드 할 내용이 없습니다.<br>현재 DB 업그레이드가 완료된 상태입니다.';
+9 -4
View File
@@ -284,14 +284,19 @@ if (!auth_check_menu($auth, '200200', 'r', true)) {
</thead>
<tbody>
<?php
$row2['mb_id'] = '';
$row2 = array('mb_id'=>'');
for ($i = 0; $row = sql_fetch_array($result); $i++) {
if ($row2['mb_id'] != $row['mb_id']) {
if (empty($row2) || $row2['mb_id'] != $row['mb_id']) {
$sql2 = " SELECT mb_id, mb_name, mb_nick, mb_email, mb_homepage, mb_point from {$g5['member_table']} where mb_id = '{$row['mb_id']}' ";
$row2 = sql_fetch($sql2);
}
$mb_nick = get_sideview($row['mb_id'], $row2['mb_nick'], $row2['mb_email'], $row2['mb_homepage']);
$mb_nick = get_sideview(
$row['mb_id'],
isset($row2['mb_nick']) ? $row2['mb_nick'] : '',
isset($row2['mb_email']) ? $row2['mb_email'] : '',
isset($row2['mb_homepage']) ? $row2['mb_homepage'] : ''
);
$link1 = $link2 = "";
if (!preg_match("/^\@/", $row['po_rel_table']) && $row['po_rel_table']) {
@@ -302,7 +307,7 @@ if (!auth_check_menu($auth, '200200', 'r', true)) {
<tr>
<td class="td_mbid"><a href="./point_list.php?sfl=mb_id&amp;stx=<?php echo $row['mb_id'] ?>"><?php echo $row['mb_id'] ?></a></td>
<td class="td_mbname"><?php echo get_text($row2['mb_name']); ?></td>
<td class="td_mbname"><?php echo isset($row2['mb_name']) ? get_text($row2['mb_name']) : ''; ?></td>
<td class="td_name sv_use">
<div><?php echo $mb_nick ?></div>
</td>
+1 -1
View File
@@ -80,7 +80,7 @@ require_once './admin.head.php';
<tr>
<th scope="row"><label for="mb_email">E-mail</label></th>
<td>
<?php echo help("메일 주소에 단어 포함 (예 : @" . preg_replace('#^(www[^\.]*\.){1}#', '', $_SERVER['HTTP_HOST']) . ")") ?>
<?php echo help("메일 주소에 단어 포함 (예 : @" . htmlspecialchars(preg_replace('#^(www[^\.]*\.){1}#', '', $_SERVER['HTTP_HOST'])) . ")") ?>
<input type="text" name="mb_email" value="<?php echo get_sanitize_input($mb_email); ?>" id="mb_email" class="frm_input" size="50">
</td>
</tr>
+4 -4
View File
@@ -12,10 +12,10 @@ $sql_common = " from {$g5['member_table']} ";
$sql_where = " where (1) ";
$mb_id1 = isset($_POST['mb_id1']) ? (int) $_POST['mb_id1'] : 1;
$mb_id1_from = isset($_POST['mb_id1_from']) ? clean_xss_tags($_POST['mb_id1_from'], 1, 1, 30) : '';
$mb_id1_to = isset($_POST['mb_id1_to']) ? clean_xss_tags($_POST['mb_id1_to'], 1, 1, 30) : '';
$mb_email = isset($_POST['mb_email']) ? clean_xss_tags($_POST['mb_email'], 1, 1, 100) : '';
$mb_mailling = isset($_POST['mb_mailling']) ? clean_xss_tags($_POST['mb_mailling'], 1, 1, 100) : '';
$mb_id1_from = isset($_POST['mb_id1_from']) ? addslashes(clean_xss_tags(stripslashes($_POST['mb_id1_from']), 1, 1, 30)) : '';
$mb_id1_to = isset($_POST['mb_id1_to']) ? addslashes(clean_xss_tags(stripslashes($_POST['mb_id1_to']), 1, 1, 30)) : '';
$mb_email = isset($_POST['mb_email']) ? addslashes(clean_xss_tags(stripslashes($_POST['mb_email']), 1, 1, 100)) : '';
$mb_mailling = isset($_POST['mb_mailling']) ? addslashes(clean_xss_tags(stripslashes($_POST['mb_mailling']), 1, 1, 100)) : '';
$mb_level_from = isset($_POST['mb_level_from'])? (int) $_POST['mb_level_from'] : 1;
$mb_level_to = isset($_POST['mb_level_to']) ? (int) $_POST['mb_level_to'] : 10;
+11 -6
View File
@@ -19,8 +19,8 @@ $mb_certify = isset($_POST['mb_certify']) ? preg_replace('/[^0-9a-z_]/i', ''
$mb_zip = isset($_POST['mb_zip']) ? preg_replace('/[^0-9a-z_]/i', '', $_POST['mb_zip']) : '';
// 광고성 정보 수신
$mb_marketing_agree = isset($_POST['mb_marketing_agree']) ? clean_xss_tags($_POST['mb_marketing_agree'], 1, 1) : '0';
$mb_thirdparty_agree = isset($_POST['mb_thirdparty_agree']) ? clean_xss_tags($_POST['mb_thirdparty_agree'], 1, 1) : '0';
$mb_marketing_agree = isset($_POST['mb_marketing_agree']) ? addslashes(clean_xss_tags(stripslashes($_POST['mb_marketing_agree']), 1, 1)) : '0';
$mb_thirdparty_agree = isset($_POST['mb_thirdparty_agree']) ? addslashes(clean_xss_tags(stripslashes($_POST['mb_thirdparty_agree']), 1, 1)) : '0';
// 관리자가 자동등록방지를 사용해야 할 경우 ( 회원의 비밀번호 변경시 캡챠를 체크한다 )
if ($mb_password) {
@@ -84,9 +84,9 @@ for ($i = 1; $i <= 10; $i++) {
foreach ($check_keys as $key) {
if( in_array($key, array('mb_signature', 'mb_profile')) ){
$posts[$key] = isset($_POST[$key]) ? clean_xss_tags($_POST[$key], 1, 1, 0, 0) : '';
$posts[$key] = isset($_POST[$key]) ? addslashes(clean_xss_tags(stripslashes($_POST[$key]), 1, 1, 0, 0)) : '';
} else {
$posts[$key] = isset($_POST[$key]) ? clean_xss_tags($_POST[$key], 1, 1) : '';
$posts[$key] = isset($_POST[$key]) ? addslashes(clean_xss_tags(stripslashes($_POST[$key]), 1, 1)) : '';
}
}
@@ -127,6 +127,11 @@ $sql_common = " mb_name = '{$posts['mb_name']}',
mb_9 = '{$posts['mb_9']}',
mb_10 = '{$posts['mb_10']}' ";
// 부여하려는 mb_level 상한 검증 (자기보다 높은 권한 부여 차단)
if ($is_admin !== 'super' && (int) $posts['mb_level'] >= (int) $member['mb_level']) {
alert('자신보다 권한이 높거나 같은 등급은 부여할 수 없습니다.');
}
if ($w == '') {
$mb = get_member($mb_id);
if (isset($mb['mb_id']) && $mb['mb_id']) {
@@ -147,7 +152,7 @@ if ($w == '') {
alert('이미 존재하는 이메일입니다.\\nID : ' . $row['mb_id'] . '\\n이름 : ' . $row['mb_name'] . '\\n닉네임 : ' . $row['mb_nick'] . '\\n메일 : ' . $row['mb_email']);
}
$agree_items = [];
$agree_items = array();
// 마케팅 목적의 개인정보 수집 및 이용
if ($mb_marketing_agree == 1) {
$sql_common .= " , mb_marketing_date = '".G5_TIME_YMDHIS."' ";
@@ -230,7 +235,7 @@ if ($w == '') {
// 현재 데이터 조회
$row = sql_fetch("select * from {$g5['member_table']} where mb_id = '{$mb_id}' ");
$agree_items = [];
$agree_items = array();
// 마케팅 목적의 개인정보 수집 및 이용
$sql_marketing_date = "";
+14 -9
View File
@@ -6,6 +6,12 @@ auth_check_menu($auth, $sub_menu, 'r');
$sql_common = " from {$g5['member_table']} ";
// $sfl 화이트리스트 검증 (KVE-2026-0340)
$allowed_sfl = array('mb_id', 'mb_nick', 'mb_name', 'mb_level', 'mb_email', 'mb_tel', 'mb_hp', 'mb_point', 'mb_datetime', 'mb_ip', 'mb_recommend');
if (!in_array($sfl, $allowed_sfl)) {
$sfl = 'mb_id';
}
$sql_search = " where (1) ";
if ($stx) {
$sql_search .= " and ( ";
@@ -127,7 +133,7 @@ $colspan = 16;
<th scope="col" rowspan="2" id="mb_list_cert"><?php echo subject_sort_link('mb_certify', '', 'desc') ?>본인확인</a></th>
<th scope="col" id="mb_list_mailc"><?php echo subject_sort_link('mb_email_certify', '', 'desc') ?>메일인증</a></th>
<th scope="col" id="mb_list_open"><?php echo subject_sort_link('mb_open', '', 'desc') ?>정보공개</a></th>
<th scope="col" id="mb_list_mailr"><?php echo subject_sort_link('mb_mailling', '', 'desc') ?>광고성이메일수신</a></th>
<th scope="col" id="mb_list_mailr"><?php echo subject_sort_link('mb_mailling', '', 'desc') ?>광고성이메일</a></th>
<th scope="col" id="mb_list_auth">상태</th>
<th scope="col" id="mb_list_mobile">휴대폰</th>
<th scope="col" id="mb_list_lastcall"><?php echo subject_sort_link('mb_today_login', '', 'desc') ?>최종접속</a></th>
@@ -137,9 +143,9 @@ $colspan = 16;
<tr>
<th scope="col" id="mb_list_name"><?php echo subject_sort_link('mb_name') ?>이름</a></th>
<th scope="col" id="mb_list_nick"><?php echo subject_sort_link('mb_nick') ?>닉네임</a></th>
<th scope="col" id="mb_list_sms"><?php echo subject_sort_link('mb_sms', '', 'desc') ?>광고성SMS/카카오톡수신</a></th>
<th scope="col" id="mb_list_adultc"><?php echo subject_sort_link('mb_adult', '', 'desc') ?>성인인증</a></th>
<th scope="col" id="mb_list_auth"><?php echo subject_sort_link('mb_intercept_date', '', 'desc') ?>접근차단</a></th>
<th scope="col" id="mb_list_sms"><?php echo subject_sort_link('mb_sms', '', 'desc') ?>광고성SMS</a></th>
<th scope="col" id="mb_list_deny"><?php echo subject_sort_link('mb_level', '', 'desc') ?>권한</a></th>
<th scope="col" id="mb_list_tel">전화번호</th>
<th scope="col" id="mb_list_join"><?php echo subject_sort_link('mb_datetime', '', 'desc') ?>가입일</a></th>
@@ -258,7 +264,7 @@ $colspan = 16;
<input type="checkbox" name="mb_open[<?php echo $i; ?>]" <?php echo $row['mb_open'] ? 'checked' : ''; ?> value="1" id="mb_open_<?php echo $i; ?>">
</td>
<td headers="mb_list_mailr" class="td_consent">
<label for="mb_mailling_<?php echo $i; ?>" class="sound_only">메일수신</label>
<label for="mb_mailling_<?php echo $i; ?>" class="sound_only">광고성이메일수신</label>
<input type="checkbox" name="mb_mailling[<?php echo $i; ?>]" <?php echo $row['mb_mailling'] ? 'checked' : ''; ?> value="1" id="mb_mailling_<?php echo $i; ?>">
<input type="hidden" name="mb_mailling_default[<?php echo $i; ?>]" value="<?php echo isset($row['mb_mailling']) ? $row['mb_mailling'] : '0'; ?> " id="mb_mailling_default_<?php echo $i; ?>">
</td>
@@ -281,12 +287,6 @@ $colspan = 16;
<td headers="mb_list_nick" class="td_name sv_use">
<div><?php echo $mb_nick ?></div>
</td>
<td headers="mb_list_sms">
<label for="mb_sms_<?php echo $i; ?>" class="sound_only">SMS수신</label>
<input type="checkbox" name="mb_sms[<?php echo $i; ?>]" <?php echo $row['mb_sms'] ? 'checked' : ''; ?> value="1" id="mb_sms_<?php echo $i; ?>">
<input type="hidden" name="mb_sms_default[<?php echo $i; ?>]" value="<?php echo isset($row['mb_sms']) ? $row['mb_sms'] : '0'; ?> " id="mb_sms_default_<?php echo $i; ?>">
</td>
<td headers="mb_list_adultc">
<label for="mb_adult_<?php echo $i; ?>" class="sound_only">성인인증</label>
<input type="checkbox" name="mb_adult[<?php echo $i; ?>]" <?php echo $row['mb_adult'] ? 'checked' : ''; ?> value="1" id="mb_adult_<?php echo $i; ?>">
@@ -297,6 +297,11 @@ $colspan = 16;
<label for="mb_intercept_date_<?php echo $i; ?>" class="sound_only">접근차단</label>
<?php } ?>
</td>
<td headers="mb_list_sms">
<label for="mb_sms_<?php echo $i; ?>" class="sound_only">광고성SMS/카카오톡수신</label>
<input type="checkbox" name="mb_sms[<?php echo $i; ?>]" <?php echo $row['mb_sms'] ? 'checked' : ''; ?> value="1" id="mb_sms_<?php echo $i; ?>">
<input type="hidden" name="mb_sms_default[<?php echo $i; ?>]" value="<?php echo isset($row['mb_sms']) ? $row['mb_sms'] : '0'; ?> " id="mb_sms_default_<?php echo $i; ?>">
</td>
<td headers="mb_list_auth" class="td_mbstat">
<?php echo get_member_level_select("mb_level[$i]", 1, $member['mb_level'], $row['mb_level']) ?>
</td>
+25 -19
View File
@@ -21,8 +21,8 @@ define('MEMBER_LOG_DIR', G5_DATA_PATH . "/" . MEMBER_BASE_DIR . "/" . "log");
*/
function get_export_config($type = null)
{
$config = [
'sfl_list' => [
$config = array(
'sfl_list' => array(
'mb_id'=>'아이디',
'mb_name'=>'이름',
'mb_nick'=>'닉네임',
@@ -30,26 +30,26 @@ function get_export_config($type = null)
'mb_tel'=>'전화번호',
'mb_hp'=>'휴대폰번호',
'mb_addr1'=>'주소'
],
'point_cond_map' => [
),
'point_cond_map' => array(
'gte'=>'≥',
'lte'=>'≤',
'eq'=>'='
],
'intercept_list' => [
),
'intercept_list' => array(
'exclude'=>'차단회원 제외',
'only'=>'차단회원만'
],
'ad_range_list' => [
),
'ad_range_list' => array(
'all' => '수신동의 회원 전체',
'mailling_only' => '이메일 수신동의 회원만',
'sms_only' => 'SMS/카카오톡 수신동의 회원만',
'month_confirm' => date('m월').' 수신동의 확인 대상만',
'custom_period' => '수신동의 기간 직접 입력'
],
];
),
);
return $type ? (isset($config[$type]) ? $config[$type] : []) : $config;
return $type ? (isset($config[$type]) ? $config[$type] : array()) : $config;
}
/**
@@ -59,14 +59,14 @@ function get_member_export_params()
{
// 친구톡 양식 - 엑셀 양식에 포함할 항목
$fieldArray = array_map('trim', explode(',', isset($_GET['fields']) ? $_GET['fields'] : ''));
$vars = [];
$vars = array();
foreach ($fieldArray as $index => $field) {
if(!empty($field)){
$vars['var' . ($index + 1)] = $field;
}
}
$params = [
$params = array(
'page' => 1,
'formatType' => (int)(isset($_GET['formatType']) ? $_GET['formatType'] : 1),
'use_stx' => isset($_GET['use_stx']) ? $_GET['use_stx'] : 0,
@@ -92,24 +92,30 @@ function get_member_export_params()
'use_intercept' => isset($_GET['use_intercept']) ? $_GET['use_intercept'] : 0,
'intercept' => clean_xss_tags(isset($_GET['intercept']) ? $_GET['intercept'] : 'exclude'),
'vars' => $vars,
];
);
// 레벨 범위 검증
if ($params['level_start'] > $params['level_end']) {
[$params['level_start'] , $params['level_end']] = [$params['level_end'], $params['level_start']];
$tmp_level = $params['level_start'];
$params['level_start'] = $params['level_end'];
$params['level_end'] = $tmp_level;
}
// 가입기간 - 날짜 범위 검증
if ($params['use_date'] && $params['date_start'] && $params['date_end']) {
if ($params['date_start'] > $params['date_end']) {
[$params['date_start'] , $params['date_end']] = [$params['date_end'], $params['date_start']];
$tmp_date = $params['date_start'];
$params['date_start'] = $params['date_end'];
$params['date_end'] = $tmp_date;
}
}
// 수신동의기간 - 날짜 범위 검증
if ($params['ad_range_type'] == 'custom_period' && $params['agree_date_start'] && $params['agree_date_end']) {
if ($params['agree_date_start'] > $params['agree_date_end']) {
[$params['agree_date_start'] , $params['agree_date_end']] = [$params['agree_date_end'], $params['agree_date_start']];
$tmp_agree_date = $params['agree_date_start'];
$params['agree_date_start'] = $params['agree_date_end'];
$params['agree_date_end'] = $tmp_agree_date;
}
}
@@ -141,7 +147,7 @@ function member_export_get_total_count($params)
function member_export_build_where($params)
{
global $config;
$conditions = [];
$conditions = array();
// 기본 조건 - 탈퇴하지 않은 사용자
$conditions[] = "mb_leave_date = ''";
@@ -263,7 +269,7 @@ function member_export_build_where($params)
$conditions[] = "0=1"; // 둘 다 해제 ⇒ 결과 0건
} else {
// 조건 조립
$parts = [];
$parts = array();
if ($useEmail) $parts[] = "(mb_mailling = 1 AND {$emailDateCond})";
if ($useSms) $parts[] = "(mb_sms = 1 AND {$smsDateCond})";
+4 -4
View File
@@ -191,12 +191,12 @@ $colspan = 14;
<?php
$thirdpartyLbl = (!empty($config['cf_sms_use'])) ? ' / <b>개인정보 제3자 제공</b>' : '';
$ad_range_text = [
$ad_range_text = array(
'all' => "* <b>광고성 정보 수신(이메일 또는 SMS/카카오톡)</b> / <b>마케팅 목적의 개인정보 수집 및 이용</b>{$thirdpartyLbl}에 모두 동의한 회원을 선택합니다.",
'mailling_only' => "* <b>광고성 이메일 수신</b> / <b>마케팅 목적의 개인정보 수집 및 이용</b>{$thirdpartyLbl}에 모두 동의한 회원을 선택합니다.",
'sms_only' => "* <b>광고성 SMS/카카오톡 수신</b> / <b>마케팅 목적의 개인정보 수집 및 이용</b>{$thirdpartyLbl}에 모두 동의한 회원을 선택합니다.",
'month_confirm' => "* 23개월 전(" . date('Y년 m월', strtotime('-23 month')) . ") <b>광고성 정보 수신 동의(이메일 또는 SMS/카카오톡)</b>한 회원을 선택합니다."
];
);
if (isset($_GET['ad_range_only'], $_GET['ad_range_type']) && isset($ad_range_text[$_GET['ad_range_type']])) {
echo '<div class="ad_range_box"><p>' . $ad_range_text[$_GET['ad_range_type']] . '</p></div>';
@@ -210,7 +210,7 @@ $colspan = 14;
</div>
<!-- 채널 체크박스 -->
<div class="sch_row <?php echo isset($_GET['ad_range_only']) && in_array($_GET['ad_range_type'], ['month_confirm', 'custom_period']) ? '' : 'is-hidden'; ?>">
<div class="sch_row <?php echo isset($_GET['ad_range_only']) && in_array($_GET['ad_range_type'], array('month_confirm', 'custom_period')) ? '' : 'is-hidden'; ?>">
<div class="ad_range_wrap">
<div class="ad_range_box">
<div class="label">
@@ -480,4 +480,4 @@ function triggerAutoDownload(url, filename) {
</script>
<?php
require_once './admin.tail.php';
require_once './admin.tail.php';
+67 -53
View File
@@ -14,7 +14,7 @@ session_write_close(); // 세션 종료 및 잠금 해제 (백그라운드 작
$params = get_member_export_params();
if (!$params || !is_array($params)) {
member_export_send_progress("error", "데이터가 올바르게 전달되지 않아 작업에 실패하였습니다.");
member_export_write_log([], ['success' => false, 'error' => '데이터가 올바르게 전달되지 않아 작업에 실패하였습니다.']);
member_export_write_log(array(), array('success' => false, 'error' => '데이터가 올바르게 전달되지 않아 작업에 실패하였습니다.'));
exit;
}
@@ -28,7 +28,7 @@ member_export_set_sse_headers();
$mode = isset($_GET['mode']) ? $_GET['mode'] : '';
if ($mode !== 'start') {
member_export_send_progress("error", "잘못된 요청 입니다.");
member_export_write_log($params, ['success' => false, 'error' => '잘못된 요청 입니다.']);
member_export_write_log($params, array('success' => false, 'error' => '잘못된 요청 입니다.'));
exit;
}
@@ -43,7 +43,7 @@ catch (Exception $e)
// 에러 로그 저장 및 SSE 에러 전송
error_log("[Member Export Error] " . $e->getMessage());
member_export_send_progress("error", $e->getMessage());
member_export_write_log($params, ['success' => false, 'error' => $e->getMessage()]);
member_export_write_log($params, array('success' => false, 'error' => $e->getMessage()));
}
/**
@@ -62,7 +62,7 @@ function main_member_export($params)
}
$fileName = 'member_'.MEMBER_BASE_DATE;
$fileList = [];
$fileList = array();
$zipFileName = '';
if ($total > MEMBER_EXPORT_PAGE_SIZE) {
@@ -88,7 +88,7 @@ function main_member_export($params)
$zipResult = member_export_create_zip($fileList, $fileName); // 압축 파일 생성
if($zipResult['error']){
member_export_write_log($params, ['success' => false, 'error' => $zipResult['error']]);
member_export_write_log($params, array('success' => false, 'error' => $zipResult['error']));
member_export_send_progress("zippingError", $zipResult['error']);
}
@@ -107,19 +107,19 @@ function main_member_export($params)
member_export_send_progress("progress", "", 1, $total, $total);
}
member_export_write_log($params, ['success' => true, 'total' => $total, 'files' => $fileList, 'zip' => isset($zipFileName) ? $zipFileName : null]);
member_export_write_log($params, array('success' => true, 'total' => $total, 'files' => $fileList, 'zip' => isset($zipFileName) ? $zipFileName : null));
member_export_send_progress("done", "", 2, $total, $total, $pages, $pages, $fileList, $zipFileName);
}
/**
* 진행률 전송
*/
function member_export_send_progress($status, $message = "", $downloadType = 1, $total = 1, $current = 1, $totalChunks = 1, $currentChunk = 1, $files = [], $zipFile = '')
function member_export_send_progress($status, $message = "", $downloadType = 1, $total = 1, $current = 1, $totalChunks = 1, $currentChunk = 1, $files = array(), $zipFile = '')
{
// 연결 상태 확인
if (connection_aborted()) return;
$data = [
$data = array(
'status' => $status,
'message' => $message,
'downloadType' => $downloadType,
@@ -130,9 +130,10 @@ function member_export_send_progress($status, $message = "", $downloadType = 1,
'files' => $files,
'zipFile' => $zipFile,
'filePath' => G5_DATA_URL . "/" . MEMBER_BASE_DIR . "/" . MEMBER_BASE_DATE,
];
);
echo "data: " . json_encode($data, JSON_UNESCAPED_UNICODE) . "\n\n";
$json_options = defined('JSON_UNESCAPED_UNICODE') ? JSON_UNESCAPED_UNICODE : 0;
echo "data: " . json_encode($data, $json_options) . "\n\n";
// 더 안정적인 플러시
if (ob_get_level()) ob_end_flush();
@@ -145,18 +146,18 @@ function member_export_send_progress($status, $message = "", $downloadType = 1,
function member_export_get_config()
{
$type = 1;
$configs = [
1 => [
'title' => ["회원관리파일(일반)"],
'headers' => ['아이디', '이름', '닉네임', '휴대폰번호', '전화번호', '이메일', '주소', '회원권한', '포인트', '가입일', '차단',
$configs = array(
1 => array(
'title' => array("회원관리파일(일반)"),
'headers' => array('아이디', '이름', '닉네임', '휴대폰번호', '전화번호', '이메일', '주소', '회원권한', '포인트', '가입일', '차단',
'광고성 이메일 수신동의', '광고성 이메일 동의일자', '광고성 SMS/카카오톡 수신동의', '광고성 SMS/카카오톡 동의일자',
'마케팅목적의개인정보수집및이용동의', '마케팅목적의개인정보수집및이용동의일자', '개인정보제3자제공동의', '개인정보제3자제공동의일자'],
'fields' => ['mb_id', 'mb_name', 'mb_nick', 'mb_hp', 'mb_tel', 'mb_email', 'mb_addr1', 'mb_level', 'mb_point', 'mb_datetime', 'mb_intercept_date',
'마케팅목적의개인정보수집및이용동의', '마케팅목적의개인정보수집및이용동의일자', '개인정보제3자제공동의', '개인정보제3자제공동의일자'),
'fields' => array('mb_id', 'mb_name', 'mb_nick', 'mb_hp', 'mb_tel', 'mb_email', 'mb_addr1', 'mb_level', 'mb_point', 'mb_datetime', 'mb_intercept_date',
'mb_mailling','mb_mailling_date', 'mb_sms','mb_sms_date', 'mb_marketing_agree',
'mb_marketing_date', 'mb_thirdparty_agree', 'mb_thirdparty_date'],
'widths' => [20, 20, 20, 20, 20, 30, 30, 10, 15, 25, 10, 20, 25, 20, 25, 20, 25, 20, 25],
],
];
'mb_marketing_date', 'mb_thirdparty_agree', 'mb_thirdparty_date'),
'widths' => array(20, 20, 20, 20, 20, 30, 30, 10, 15, 25, 10, 20, 25, 20, 25, 20, 25, 20, 25),
),
);
return isset($configs[$type]) ? $configs[$type] : $configs[1];
}
@@ -195,7 +196,7 @@ function member_export_get_data($params)
$fields = array_unique($fields);
// SQL 변환 맵 (가공이 필요한 필드만 정의)
$sqlTransformMap = [
$sqlTransformMap = array(
'mb_datetime' => "IF(mb_datetime = '0000-00-00 00:00:00', '', mb_datetime) AS mb_datetime",
'mb_intercept_date' => "IF(mb_intercept_date != '', '차단됨', '정상') AS mb_intercept_date",
'mb_sms' => "IF(mb_sms = '1', '동의', '미동의') AS mb_sms",
@@ -206,10 +207,10 @@ function member_export_get_data($params)
'mb_marketing_date' => "IF(mb_marketing_agree != '1' OR mb_marketing_date = '0000-00-00 00:00:00', '', mb_marketing_date) AS mb_marketing_date",
'mb_thirdparty_agree' => "IF(mb_thirdparty_agree = '1', '동의', '미동의') AS mb_thirdparty_agree",
'mb_thirdparty_date' => "IF(mb_thirdparty_agree != '1' OR mb_thirdparty_date = '0000-00-00 00:00:00', '', mb_thirdparty_date) AS mb_thirdparty_date",
];
);
// SQL 필드 생성
$sqlFields = [];
$sqlFields = array();
foreach ($fields as $field) {
$sqlFields[] = isset($sqlTransformMap[$field]) ? $sqlTransformMap[$field] : $field;
}
@@ -228,12 +229,16 @@ function member_export_get_data($params)
throw new Exception("데이터 조회에 실패하였습니다");
}
$excelData = [$config['title'], $config['headers']];
$excelData = array($config['title'], $config['headers']);
while ($row = sql_fetch_array($result)) {
$rowData = [];
$rowData = array();
foreach ($fields as $field) {
$rowData[] = isset($row[$field]) ? $row[$field] : '';
if (isset($row[$field])) {
$rowData[] = function_exists('csv_safe_cell') ? csv_safe_cell($row[$field]) : $row[$field];
} else {
$rowData[] = '';
}
}
$excelData[] = $rowData;
}
@@ -257,10 +262,10 @@ function member_export_create_excel($data, $fileName, $index = 0)
$currentCache = PHPExcel_Settings::getCacheStorageMethod();
// 캐싱 모드 설정 (엑셀 생성 전용)
$cacheMethods = [
$cacheMethods = array(
PHPExcel_CachedObjectStorageFactory::cache_to_discISAM,
PHPExcel_CachedObjectStorageFactory::cache_in_memory_serialized
];
);
foreach ($cacheMethods as $method) {
if (PHPExcel_Settings::setCacheStorageMethod($method)) {
@@ -274,12 +279,12 @@ function member_export_create_excel($data, $fileName, $index = 0)
// 헤더 스타일 적용
$last_char = member_export_column_char(count($config['headers']) - 1);
$sheet->getStyle("A2:{$last_char}2")->applyFromArray([
'fill' => [
$sheet->getStyle("A2:{$last_char}2")->applyFromArray(array(
'fill' => array(
'type' => PHPExcel_Style_Fill::FILL_SOLID,
'startcolor' => ['rgb' => 'D9E1F2'], // 연파랑 배경
],
]);
'startcolor' => array('rgb' => 'D9E1F2'), // 연파랑 배경
),
));
// 셀 정렬 및 줄바꿈 설정
$sheet->getStyle("A:{$last_char}")->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER)->setWrapText(true);
@@ -309,14 +314,15 @@ function member_export_create_excel($data, $fileName, $index = 0)
}
catch (Exception $e)
{
throw new Exception("엑셀 파일 생성에 실패하였습니다: " . $e->getMessage());
}
finally
{
// 캐싱 모드 원래 상태로 복원
if ($currentCache) {
PHPExcel_Settings::setCacheStorageMethod($currentCache);
}
throw new Exception("엑셀 파일 생성에 실패하였습니다: " . $e->getMessage());
}
// 캐싱 모드 원래 상태로 복원
if ($currentCache) {
PHPExcel_Settings::setCacheStorageMethod($currentCache);
}
return $filename;
@@ -329,7 +335,7 @@ function member_export_create_zip($files, $zipFileName)
{
if (!class_exists('ZipArchive')) {
error_log('[Member Export Error] ZipArchive 클래스를 사용할 수 없습니다.');
return ['error' => '파일을 압축하는 중 문제가 발생했습니다. 개별 파일로 제공됩니다.<br>: ZipArchive 클래스를 사용할 수 없습니다.'];
return array('error' => '파일을 압축하는 중 문제가 발생했습니다. 개별 파일로 제공됩니다.<br>: ZipArchive 클래스를 사용할 수 없습니다.');
}
member_export_ensure_directory(MEMBER_EXPORT_DIR);
@@ -337,7 +343,7 @@ function member_export_create_zip($files, $zipFileName)
$zip = new ZipArchive();
if ($zip->open($destinationZipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) {
return ['error' => "파일을 압축하는 중 문제가 발생했습니다. 개별 파일로 제공됩니다."];
return array('error' => "파일을 압축하는 중 문제가 발생했습니다. 개별 파일로 제공됩니다.");
}
foreach ($files as $file) {
@@ -349,11 +355,11 @@ function member_export_create_zip($files, $zipFileName)
$result = $zip->close();
return [
return array(
'result' => $result,
'zipFile' => $zipFileName . ".zip",
'zipPath' => $destinationZipPath,
];
);
}
/**
@@ -378,7 +384,7 @@ function member_export_ensure_directory($dir)
* - 알집 생성 완료 시 엑셀 파일 제거
* - 작업 전 오늘 날짜 폴더 및 log 폴더를 제외한 나머지 파일 모두 제거
*/
function member_export_delete($fileList = [])
function member_export_delete($fileList = array())
{
$cnt = 0;
@@ -397,7 +403,7 @@ function member_export_delete($fileList = [])
function deleteFolder($dir) {
foreach (glob($dir . '/{.,}*', GLOB_BRACE) as $item) {
if (in_array(basename($item), ['.', '..'])) continue;
if (in_array(basename($item), array('.', '..'))) continue;
is_dir($item) ? deleteFolder($item) : unlink($item);
}
rmdir($dir);
@@ -424,7 +430,7 @@ function member_export_delete($fileList = [])
/**
* 로그 작성
*/
function member_export_write_log($params, $result = [])
function member_export_write_log($params, $result = array())
{
global $member;
@@ -438,10 +444,13 @@ function member_export_write_log($params, $result = [])
@chmod(MEMBER_LOG_DIR, G5_DIR_PERMISSION);
}
$logFiles = glob(MEMBER_LOG_DIR . "/export_log_*.log") ?: [];
$logFiles = glob(MEMBER_LOG_DIR . "/export_log_*.log");
if (!$logFiles) {
$logFiles = array();
}
// 최신 파일 기준 정렬 (최신 → 오래된)
usort($logFiles, fn($a, $b) => filemtime($b) - filemtime($a));
usort($logFiles, 'member_export_compare_log_mtime');
$latestLogFile = isset($logFiles[0]) ? $logFiles[0] : null;
@@ -464,7 +473,7 @@ function member_export_write_log($params, $result = [])
$status = $success ? '성공' : '실패';
// 조건 정리
$condition = [];
$condition = array();
// 검색 조건
if ($params['use_stx'] == 1 && !empty($params['stx'])) {
@@ -506,11 +515,11 @@ function member_export_write_log($params, $result = [])
$condition[] = "수신동의일: {$params['agree_date_start']}~{$params['agree_date_end']}";
}
if (in_array($params['ad_range_type'], ["month_confirm", "custom_period"])){
$channels = array_filter([
if (in_array($params['ad_range_type'], array("month_confirm", "custom_period"))){
$channels = array_filter(array(
!empty($params['ad_mailling']) && (int)$params['ad_mailling'] === 1 ? '이메일' : null,
!empty($params['ad_sms']) && (int)$params['ad_sms'] === 1 ? 'SMS/카카오톡' : null,
]);
));
if ($channels) {
$condition[] = '수신채널: ' . implode(', ', $channels);
@@ -531,7 +540,7 @@ function member_export_write_log($params, $result = [])
// 성공일 경우 추가 정보
if ($success) {
$total = isset($result['total']) ? $result['total'] : 0;
$fileCount = isset($result['zip']) ? 1 : count(isset($result['files']) ? $result['files'] : []);
$fileCount = isset($result['zip']) ? 1 : count(isset($result['files']) ? $result['files'] : array());
$line1 .= " | 총 {$total}건 | 파일: {$fileCount}개";
}
@@ -548,4 +557,9 @@ function member_export_write_log($params, $result = [])
if (@file_put_contents($latestLogFile, $logEntry, FILE_APPEND | LOCK_EX) === false) {
error_log("[Member Export Error] 로그 파일 기록 실패: {$latestLogFile}");
}
}
}
function member_export_compare_log_mtime($a, $b)
{
return filemtime($b) - filemtime($a);
}
+3 -1
View File
@@ -27,7 +27,7 @@ if ($_POST['act_button'] == "선택수정") {
$post_mb_sms = isset($_POST['mb_sms'][$k]) ? (int) $_POST['mb_sms'][$k] : 0;
$post_mb_open = isset($_POST['mb_open'][$k]) ? (int) $_POST['mb_open'][$k] : 0;
$agree_items = [];
$agree_items = array();
// 광고성 이메일 수신동의 일자 추가
$post_mb_mailling_default = isset($_POST['mb_mailling_default'][$k]) ? (int) $_POST['mb_mailling_default'][$k] : 0;
$sql_mailling_date = "";
@@ -57,6 +57,8 @@ if ($_POST['act_button'] == "선택수정") {
$msg .= $mb['mb_id'] . ' : 회원자료가 존재하지 않습니다.\\n';
} elseif ($is_admin != 'super' && $mb['mb_level'] >= $member['mb_level']) {
$msg .= $mb['mb_id'] . ' : 자신보다 권한이 높거나 같은 회원은 수정할 수 없습니다.\\n';
} elseif ($is_admin != 'super' && $post_mb_level >= (int) $member['mb_level']) {
$msg .= $mb['mb_id'] . ' : 자신보다 권한이 높거나 같은 등급은 부여할 수 없습니다.\\n';
} elseif ($member['mb_id'] == $mb['mb_id']) {
$msg .= $mb['mb_id'] . ' : 로그인 중인 관리자는 수정 할 수 없습니다.\\n';
} else {
+4 -1
View File
@@ -25,6 +25,9 @@ if (!$sst) {
$sst = "po_id";
$sod = "desc";
}
$allowed_sst = array('po_id', 'mb_id', 'po_content', 'po_point', 'po_datetime');
if ($sst && !in_array($sst, $allowed_sst)) $sst = 'po_id';
if ($sod && !in_array(strtolower($sod), array('asc', 'desc'))) $sod = '';
$sql_order = " order by {$sst} {$sod} ";
$sql = " select count(*) as cnt
@@ -66,7 +69,7 @@ if ($config['cf_point_term'] > 0) {
$po_expire_term = $config['cf_point_term'];
}
if (strstr($sfl, "mb_id")) {
if (strpos($sfl, "mb_id") !== false) {
$mb_id = $stx;
} else {
$mb_id = "";
+3
View File
@@ -21,6 +21,9 @@ if (!$sst) {
$sst = "po_id";
$sod = "desc";
}
$allowed_sst = array('po_id', 'po_subject', 'po_level', 'po_use', 'po_etc');
if ($sst && !in_array($sst, $allowed_sst)) $sst = 'po_id';
if ($sod && !in_array(strtolower($sod), array('asc', 'desc'))) $sod = '';
$sql_order = " order by {$sst} {$sod} ";
$sql = " select count(*) as cnt
+5
View File
@@ -6,6 +6,8 @@ auth_check_menu($auth, $sub_menu, 'r');
// 체크된 자료 삭제
if (isset($_POST['chk']) && is_array($_POST['chk'])) {
check_admin_token();
for ($i = 0; $i < count($_POST['chk']); $i++) {
$pp_id = (int) $_POST['chk'][$i];
@@ -36,6 +38,9 @@ if (!$sst) {
$sst = "pp_id";
$sod = "desc";
}
$allowed_sst = array('pp_id', 'pp_word', 'pp_date', 'pp_ip');
if ($sst && !in_array($sst, $allowed_sst)) $sst = 'pp_id';
if ($sod && !in_array(strtolower($sod), array('asc', 'desc'))) $sod = '';
$sql_order = " order by {$sst} {$sod} ";
$sql = " select count(*) as cnt
+6
View File
@@ -21,6 +21,12 @@ foreach ($check_keys as $key) {
$qa_include_head = isset($qa_include_head) ? preg_replace(array("#[\\\]+$#", "#(<\?php|<\?)#i"), "", substr($qa_include_head, 0, 255)) : '';
$qa_include_tail = isset($qa_include_tail) ? preg_replace(array("#[\\\]+$#", "#(<\?php|<\?)#i"), "", substr($qa_include_tail, 0, 255)) : '';
// 최고 관리자가 아니면 include 경로 변경 불가 (board_form_update.php 와 동일 정책)
if ($is_admin !== 'super') {
$qa_include_head = isset($qaconfig['qa_include_head']) ? $qaconfig['qa_include_head'] : '';
$qa_include_tail = isset($qaconfig['qa_include_tail']) ? $qaconfig['qa_include_tail'] : '';
}
// 관리자가 자동등록방지를 사용해야 할 경우
if ($board && ($qaconfig['qa_include_head'] !== $qa_include_head || $qaconfig['qa_include_tail'] !== $qa_include_tail) && function_exists('get_admin_captcha_by') && get_admin_captcha_by()) {
include_once G5_CAPTCHA_PATH . '/captcha.lib.php';
+5
View File
@@ -9,10 +9,14 @@ if (!$config['cf_email_use'])
include_once(G5_LIB_PATH.'/mailer.lib.php');
$token = get_token();
$g5['title'] = '메일 테스트';
include_once('./admin.head.php');
if (isset($_POST['email'])) {
check_admin_token();
$_POST['email'] = strip_tags($_POST['email']);
$email = explode(',', $_POST['email']);
@@ -61,6 +65,7 @@ if (isset($_POST['email'])) {
</p>
</div>
<form name="fsendmailtest" method="post">
<input type="hidden" name="token" value="<?php echo $token; ?>">
<fieldset id="fsendmailtest">
<legend>테스트메일 발송</legend>
<label for="email">받는 메일주소<strong class="sound_only"> 필수</strong></label>
+1 -1
View File
@@ -31,7 +31,7 @@ include_once("./admin.head.php");
echo $list_tag_st;
while($file=readdir($dir)) {
if (!strstr($file,'sess_')) continue;
if (strpos($file,'sess_') === false) continue;
if (strpos($file,'sess_')!=0) continue;
$session_file = G5_DATA_PATH.'/session/'.$file;
+3
View File
@@ -42,6 +42,9 @@ if (!$sst)
$sst = "ca_id";
$sod = "asc";
}
$allowed_sst = array('ca_id', 'ca_name', 'ca_mb_id', 'ca_use');
if ($sst && !in_array($sst, $allowed_sst)) $sst = 'ca_id';
if ($sod && !in_array(strtolower($sod), array('asc', 'desc'))) $sod = '';
$sql_order = "order by $sst $sod";
// 출력할 레코드를 얻음
+1 -1
View File
@@ -51,7 +51,7 @@ for ($i=0; $i<$post_ca_id_count; $i++)
alert('스킨파일명에 포함될수 없는 문자가 들어있습니다.');
}
if( ! is_include_path_check($file) ){
if( ! is_include_path_check($file, 1) ){
alert('오류 : 데이터폴더가 포함된 path 또는 잘못된 path 를 포함할수 없습니다.');
}
+11 -11
View File
@@ -640,7 +640,7 @@ if(!$default['de_kakaopay_cancelpwd']){
<tr id="kcp_vbank_url" class="pg_vbank_url">
<th scope="row">NHN KCP 가상계좌<br>입금통보 URL</th>
<td>
<?php echo help("NHN KCP 가상계좌 사용시 다음 주소를 <strong><a href=\"http://admin.kcp.co.kr\" target=\"_blank\">NHN KCP 관리자</a> &gt; 상점정보관리 &gt; 정보변경 &gt; 공통URL 정보 &gt; 공통URL 변경후</strong>에 넣으셔야 상점에 자동으로 입금 통보됩니다."); ?>
<?php echo help("NHN KCP 가상계좌 사용시 다음 주소를 <strong><a href=\"https://partner.kcp.co.kr\" target=\"_blank\">NHN KCP 관리자</a> &gt; 상점정보관리 &gt; 정보변경 &gt; 공통URL 정보 &gt; 공통URL 변경후</strong>에 넣으셔야 상점에 자동으로 입금 통보됩니다."); ?>
<?php echo G5_SHOP_URL; ?>/settle_kcp_common.php</td>
</tr>
<tr id="inicis_vbank_url" class="pg_vbank_url">
@@ -694,7 +694,7 @@ if(!$default['de_kakaopay_cancelpwd']){
<tr>
<th scope="row"><label for="de_easy_pay_use">PG사 간편결제 버튼 사용</label></th>
<td>
<?php echo help("주문서 작성 페이지에 PG사 간편결제(PAYCO, PAYNOW, KPAY) 버튼의 별도 사용 여부를 설정합니다.", 50); ?>
<?php echo help("주문서 작성 페이지에 PG사 간편결제(PAYCO, 토스, KPAY...) 버튼의 별도 사용 여부를 설정합니다.", 50); ?>
<select id="de_easy_pay_use" name="de_easy_pay_use">
<option value="0" <?php echo get_selected($default['de_easy_pay_use'], 0); ?>>노출안함</option>
<option value="1" <?php echo get_selected($default['de_easy_pay_use'], 1); ?>>노출함</option>
@@ -715,13 +715,13 @@ if(!$default['de_kakaopay_cancelpwd']){
<?php
$account_checked = $vbank_checked = $transfer_checked = '';
if (strstr($default['de_taxsave_types'], 'account')) {
if (strpos($default['de_taxsave_types'], 'account') !== false) {
$account_checked = 'checked="checked"';
}
if (strstr($default['de_taxsave_types'], 'vbank')) {
if (strpos($default['de_taxsave_types'], 'vbank') !== false) {
$vbank_checked = 'checked="checked"';
}
if (strstr($default['de_taxsave_types'], 'transfer')) {
if (strpos($default['de_taxsave_types'], 'transfer') !== false) {
$transfer_checked = 'checked="checked"';
}
?>
@@ -1097,8 +1097,7 @@ if(!$default['de_kakaopay_cancelpwd']){
<a href="http://testadmin8.kcp.co.kr/" target="_blank" class="btn_frmline">테스트 관리자</a>
</div>
<div class="scf_cardtest lg_cardtest">
<a href="https://app.tosspayments.com/" target="_blank" class="btn_frmline">실결제 관리자</a>
<a href="https://pgweb.tosspayments.com/tmert" target="_blank" class="btn_frmline">테스트 관리자</a>
<a href="https://app.tosspayments.com/" target="_blank" class="btn_frmline">상점 관리자</a>
</div>
<div class="scf_cardtest toss_cardtest">
<a href="https://app.tosspayments.com/" target="_blank" class="btn_frmline">상점 관리자</a>
@@ -1122,14 +1121,14 @@ if(!$default['de_kakaopay_cancelpwd']){
<dt>휴대폰</dt><dd>테스트 지원되지 않음.</dd>
</dl>
<ul id="kcp_cardtest_tip" class="scf_cardtest_tip_adm scf_cardtest_tip_adm_hide">
<li>테스트결제의 <a href="http://testadmin8.kcp.co.kr/assist/login.LoginAction.do" target="_blank">상점관리자</a> 로그인 정보는 NHN KCP로 문의하시기 바랍니다. (기술지원 1544-8661)</li>
<li>테스트결제의 <a href="https://testpartner.kcp.co.kr/" target="_blank">상점관리자</a> 로그인 정보는 NHN KCP로 문의하시기 바랍니다. (기술지원 1544-8661)</li>
<li><b>일반결제</b>의 테스트 사이트코드는 <b>T0000</b> 이며, <b>에스크로 결제</b>의 테스트 사이트코드는 <b>T0007</b> 입니다.</li>
</ul>
<ul id="lg_cardtest_tip" class="scf_cardtest_tip_adm scf_cardtest_tip_adm_hide">
<li>테스트결제의 <a href="https://pgweb.tosspayments.com/tmert" target="_blank">상점관리자</a> 로그인 정보는 토스페이먼츠 상점아이디 첫 글자에 t를 추가해서 로그인하시기 바랍니다. 예) tsi_lguplus</li>
<li>테스트 결제건에 대한 <a href="https://app.tosspayments.com/" target="_blank">상점관리자</a> 접근은, 상점관리자 상단 '테스트 모드'를 활성화 하여서 접근할 수 있습니다.</li>
</ul>
<ul id="toss_cardtest_tip" class="scf_cardtest_tip_adm scf_cardtest_tip_adm_hide">
<li>테스트 결제 시 <a href="https://app.tosspayments.com/" target="_blank">상점관리자</a> 로그인 정보는 실결제용 키와는 다르니 반드시 <b>[테스트] API 연동 키</b>로 로그인해야 합니다. 예) test_ck_toss</li>
<li>테스트 결제건에 대한 <a href="https://app.tosspayments.com/" target="_blank">상점관리자</a> 접근은, 상점관리자 상단 '테스트 모드'를 활성화 하여서 접근할 수 있습니다.</li>
</ul>
<ul id="inicis_cardtest_tip" class="scf_cardtest_tip_adm scf_cardtest_tip_adm_hide">
<li><b>일반결제</b>의 테스트 사이트 mid는 <b>INIpayTest</b> 이며, <b>에스크로 결제</b>의 테스트 사이트 mid는 <b>iniescrow0</b> 입니다.</li>
@@ -2142,4 +2141,5 @@ if($default['de_iche_use'] || $default['de_vbank_use'] || $default['de_hp_use']
}
}
include_once (G5_ADMIN_PATH.'/admin.tail.php');
include_once (G5_ADMIN_PATH.'/admin.tail.php');
+2
View File
@@ -64,6 +64,8 @@ foreach($check_skin_keys as $key){
if( isset($_POST[$key]) && preg_match('#\.+(\/|\\\)#', $_POST[$key]) ){
alert('스킨설정에 유효하지 문자가 포함되어 있습니다.');
}
$$key = $_POST[$key] = sql_real_escape_string($_POST[$key]);
}
// 현금영수증 발급수단
+5
View File
@@ -6,6 +6,8 @@ auth_check_menu($auth, $sub_menu, "r");
$sql_common = " from {$g5['g5_shop_coupon_table']} ";
if ($sfl && !in_array($sfl, array('mb_id', 'cp_subject', 'cp_id'))) $sfl = '';
$sql_search = " where (1) ";
if ($stx) {
$sql_search .= " and ( ";
@@ -24,6 +26,9 @@ if (!$sst) {
$sst = "cp_no";
$sod = "desc";
}
$allowed_sst = array('cp_no', 'cp_id', 'cp_subject', 'mb_id', 'cp_end', 'cp_start', 'cp_method');
if ($sst && !in_array($sst, $allowed_sst)) $sst = 'cp_no';
if ($sod && !in_array(strtolower($sod), array('asc', 'desc'))) $sod = '';
$sql_order = " order by {$sst} {$sod} ";
$sql = " select count(*) as cnt
+16 -16
View File
@@ -212,28 +212,28 @@ if($data['od_settle_case'] == 'KAKAOPAY')
$od_pg = 'KAKAOPAY';
$od_email = get_email_address($data['od_email']);
$od_name = clean_xss_tags($data['od_name']);
$od_tel = clean_xss_tags($data['od_tel']);
$od_hp = clean_xss_tags($data['od_hp']);
$od_name = addslashes(clean_xss_tags($data['od_name']));
$od_tel = addslashes(clean_xss_tags($data['od_tel']));
$od_hp = addslashes(clean_xss_tags($data['od_hp']));
$od_zip = preg_replace('/[^0-9]/', '', $data['od_zip']);
$od_zip1 = substr($od_zip, 0, 3);
$od_zip2 = substr($od_zip, 3);
$od_addr1 = clean_xss_tags($data['od_addr1']);
$od_addr2 = clean_xss_tags($data['od_addr2']);
$od_addr3 = clean_xss_tags($data['od_addr3']);
$od_addr_jibeon = preg_match("/^(N|R)$/", $data['od_addr_jibeon']) ? $data['od_addr_jibeon'] : '';
$od_b_name = clean_xss_tags($data['od_b_name']);
$od_b_tel = clean_xss_tags($data['od_b_tel']);
$od_b_hp = clean_xss_tags($data['od_b_hp']);
$od_addr1 = addslashes(clean_xss_tags($data['od_addr1']));
$od_addr2 = addslashes(clean_xss_tags($data['od_addr2']));
$od_addr3 = addslashes(clean_xss_tags($data['od_addr3']));
$od_addr_jibeon = preg_match("/^(N|R|J)$/", $data['od_addr_jibeon']) ? $data['od_addr_jibeon'] : '';
$od_b_name = addslashes(clean_xss_tags($data['od_b_name']));
$od_b_tel = addslashes(clean_xss_tags($data['od_b_tel']));
$od_b_hp = addslashes(clean_xss_tags($data['od_b_hp']));
$od_b_zip = preg_replace('/[^0-9]/', '', $data['od_b_zip']);
$od_b_zip1 = substr($od_b_zip, 0, 3);
$od_b_zip2 = substr($od_b_zip, 3);
$od_b_addr1 = clean_xss_tags($data['od_b_addr1']);
$od_b_addr2 = clean_xss_tags($data['od_b_addr2']);
$od_b_addr3 = clean_xss_tags($data['od_b_addr3']);
$od_b_addr_jibeon = preg_match("/^(N|R)$/", $data['od_b_addr_jibeon']) ? $data['od_b_addr_jibeon'] : '';
$od_memo = clean_xss_tags($data['od_memo'], 0, 1, 0, 0);
$od_deposit_name = clean_xss_tags($data['od_deposit_name']);
$od_b_addr1 = addslashes(clean_xss_tags($data['od_b_addr1']));
$od_b_addr2 = addslashes(clean_xss_tags($data['od_b_addr2']));
$od_b_addr3 = addslashes(clean_xss_tags($data['od_b_addr3']));
$od_b_addr_jibeon = preg_match("/^(N|R|J)$/", $data['od_b_addr_jibeon']) ? $data['od_b_addr_jibeon'] : '';
$od_memo = addslashes(clean_xss_tags($data['od_memo'], 0, 1, 0, 0));
$od_deposit_name = addslashes(clean_xss_tags($data['od_deposit_name']));
$od_tax_flag = $default['de_tax_flag_use'];
$od_receipt_price = $tot_ct_price + $od_send_cost + $od_send_cost2 - ($od_temp_point + $tot_cp_price + $tot_sc_cp_price);
$od_receipt_point = $od_temp_point;
+6
View File
@@ -104,6 +104,12 @@ $colspan = 10;
case 'lg':
$pg = 'LGU+';
break;
case 'toss':
$pg = '토스페이먼츠';
break;
case 'nicepay':
$pg = 'NICEPAY';
break;
default:
$pg = 'KCP';
break;
+3 -1
View File
@@ -67,7 +67,9 @@ for ($i=0; $row=sql_fetch_array($result); $i++)
for ($i=0; $i<$len; $i++)
$nbsp .= "&nbsp;&nbsp;&nbsp;";
$category_select .= "<option value=\"{$row['ca_id']}\">$nbsp{$row['ca_name']}</option>\n";
// 전체 카테고리 경로 표시
$category_path = function_exists('get_shop_category_path') ? get_shop_category_path($row['ca_id']) : $row['ca_name'];
$category_select .= "<option value=\"{$row['ca_id']}\">$nbsp{$category_path}</option>\n";
}
// 모바일 1줄당 이미지수 필드 추가
+3 -1
View File
@@ -107,7 +107,9 @@ if($ev_id) {
$len = strlen($row1['ca_id']) / 2 - 1;
$nbsp = "";
for ($i=0; $i<$len; $i++) $nbsp .= "&nbsp;&nbsp;&nbsp;";
echo '<option value="'.$row1['ca_id'].'" '.get_selected($sel_ca_id, $row1['ca_id']).'>'.$nbsp.$row1['ca_name'].'</option>'.PHP_EOL;
// 전체 카테고리 경로 표시
$category_path = function_exists('get_shop_category_path') ? get_shop_category_path($row1['ca_id']) : $row1['ca_name'];
echo '<option value="'.$row1['ca_id'].'" '.get_selected($sel_ca_id, $row1['ca_id']).'>'.$nbsp.$category_path.'</option>'.PHP_EOL;
}
?>
</select>
+8 -4
View File
@@ -146,9 +146,11 @@ for ($i=0; $row=sql_fetch_array($result); $i++)
$nbsp = "";
for ($i=0; $i<$len; $i++)
$nbsp .= "&nbsp;&nbsp;&nbsp;";
$category_select .= "<option value=\"{$row['ca_id']}\">$nbsp{$row['ca_name']}</option>\n";
// 전체 카테고리 경로 표시 (예: 남성의류 > 상의 > 셔츠)
$category_path = function_exists('get_shop_category_path') ? get_shop_category_path($row['ca_id']) : $row['ca_name'];
$category_select .= "<option value=\"{$row['ca_id']}\">$nbsp{$category_path}</option>\n";
$script .= "ca_use['{$row['ca_id']}'] = {$row['ca_use']};\n";
$script .= "ca_stock_qty['{$row['ca_id']}'] = {$row['ca_stock_qty']};\n";
//$script .= "ca_explan_html['$row[ca_id]'] = $row[ca_explan_html];\n";
@@ -1394,7 +1396,9 @@ $(function(){
for ($i=0; $i<$len; $i++)
$nbsp .= "&nbsp;&nbsp;&nbsp;";
echo "<option value=\"{$row['ca_id']}\">$nbsp{$row['ca_name']}</option>\n";
// 전체 카테고리 경로 표시
$category_path = function_exists('get_shop_category_path') ? get_shop_category_path($row['ca_id']) : $row['ca_name'];
echo "<option value=\"{$row['ca_id']}\">$nbsp{$category_path}</option>\n";
}
?>
</select>
+26
View File
@@ -365,6 +365,32 @@ $it_explan = isset($_POST['it_explan']) ? $_POST['it_explan'] : '';
if ($it_name == "")
alert("상품명을 입력해 주십시오.");
// 스킨 경로 검증
$it_skin = isset($_POST['it_skin']) ? strip_tags(clean_xss_attributes($_POST['it_skin'])) : '';
$it_mobile_skin = isset($_POST['it_mobile_skin']) ? strip_tags(clean_xss_attributes($_POST['it_mobile_skin'])) : '';
$check_files = array();
if( !empty($it_skin) ) $check_files[] = $it_skin;
if( !empty($it_mobile_skin) ) $check_files[] = $it_mobile_skin;
foreach( $check_files as $file ){
if( empty($file) ) continue;
if( preg_match('#\.+(\/|\\\)#', $file) ){
alert('스킨파일명에 포함될수 없는 문자가 들어있습니다.');
}
if( ! is_include_path_check($file, 1) ){
alert('오류 : 데이터폴더가 포함된 path 또는 잘못된 path 를 포함할수 없습니다.');
}
$file_ext = pathinfo($file, PATHINFO_EXTENSION);
if( ! $file_ext || ! in_array($file_ext, array('php', 'htm', 'html')) || ! preg_match('/^.*\.(php|htm|html)$/i', $file) ) {
alert('스킨 파일 경로의 확장자는 php, htm, html 만 허용합니다.');
}
}
$sql_common = " ca_id = '$ca_id',
ca_id2 = '$ca_id2',
ca_id3 = '$ca_id3',
+8 -2
View File
@@ -25,7 +25,8 @@ for ($i=0; $row=sql_fetch_array($result); $i++)
for ($i=0; $i<$len; $i++) {
$nbsp .= '&nbsp;&nbsp;&nbsp;';
}
$ca_list .= '<option value="'.$row['ca_id'].'">'.$nbsp.$row['ca_name'].'</option>'.PHP_EOL;
$category_path = function_exists('get_shop_category_path') ? get_shop_category_path($row['ca_id']) : $row['ca_name'];
$ca_list .= '<option value="'.$row['ca_id'].'">'.$nbsp.$category_path.'</option>'.PHP_EOL;
}
$where = " and ";
@@ -67,6 +68,9 @@ if (!$sst) {
$sst = "it_id";
$sod = "desc";
}
$allowed_sst = array('it_id', 'it_name', 'it_order', 'it_use', 'it_soldout', 'it_hit', 'it_price', 'it_cust_price', 'it_point', 'it_stock_qty');
if ($sst && !in_array($sst, $allowed_sst)) $sst = 'it_id';
if ($sod && !in_array(strtolower($sod), array('asc', 'desc'))) $sod = '';
$sql_order = "order by $sst $sod";
@@ -100,7 +104,9 @@ $listall = '<a href="'.$_SERVER['SCRIPT_NAME'].'" class="ov_listall">전체목
$len = strlen($row1['ca_id']) / 2 - 1;
$nbsp = '';
for ($i=0; $i<$len; $i++) $nbsp .= '&nbsp;&nbsp;&nbsp;';
echo '<option value="'.$row1['ca_id'].'" '.get_selected($sca, $row1['ca_id']).'>'.$nbsp.$row1['ca_name'].'</option>'.PHP_EOL;
// 전체 카테고리 경로 표시
$category_path = function_exists('get_shop_category_path') ? get_shop_category_path($row1['ca_id']) : $row1['ca_name'];
echo '<option value="'.$row1['ca_id'].'" '.get_selected($sca, $row1['ca_id']).'>'.$nbsp.$category_path.'</option>'.PHP_EOL;
}
?>
</select>
+6 -1
View File
@@ -31,6 +31,9 @@ if (!$sst) {
$sst = "iq_id";
$sod = "desc";
}
$allowed_sst = array('iq_id', 'a.it_id', 'it_name', 'iq_time');
if ($sst && !in_array($sst, $allowed_sst)) $sst = 'iq_id';
if ($sod && !in_array(strtolower($sod), array('asc', 'desc'))) $sod = '';
$sql_common = " from {$g5['g5_shop_item_qa_table']} a
left join {$g5['g5_shop_item_table']} b on (a.it_id = b.it_id)
@@ -79,7 +82,9 @@ $listall = '<a href="'.$_SERVER['SCRIPT_NAME'].'" class="ov_listall">전체목
$nbsp = "";
for ($i=0; $i<$len; $i++) $nbsp .= "&nbsp;&nbsp;&nbsp;";
$selected = ($row1['ca_id'] == $sca) ? ' selected="selected"' : '';
echo '<option value="'.$row1['ca_id'].'"'.$selected.'>'.$nbsp.$row1['ca_name'].'</option>'.PHP_EOL;
// 전체 카테고리 경로 표시
$category_path = function_exists('get_shop_category_path') ? get_shop_category_path($row1['ca_id']) : $row1['ca_name'];
echo '<option value="'.$row1['ca_id'].'"'.$selected.'>'.$nbsp.$category_path.'</option>'.PHP_EOL;
}
?>
</select>
+3 -1
View File
@@ -83,7 +83,9 @@ $listall = '<a href="'.$_SERVER['SCRIPT_NAME'].'" class="ov_listall">전체목
$len = strlen($row1['ca_id']) / 2 - 1;
$nbsp = "";
for ($i=0; $i<$len; $i++) $nbsp .= "&nbsp;&nbsp;&nbsp;";
echo '<option value="'.$row1['ca_id'].'" '.get_selected($sel_ca_id, $row1['ca_id']).'>'.$nbsp.$row1['ca_name'].'</option>'.PHP_EOL;
// 전체 카테고리 경로 표시
$category_path = function_exists('get_shop_category_path') ? get_shop_category_path($row1['ca_id']) : $row1['ca_name'];
echo '<option value="'.$row1['ca_id'].'" '.get_selected($sel_ca_id, $row1['ca_id']).'>'.$nbsp.$category_path.'</option>'.PHP_EOL;
}
?>
</select>
+3 -1
View File
@@ -82,7 +82,9 @@ $listall = '<a href="'.$_SERVER['SCRIPT_NAME'].'" class="ov_listall">전체목
$len = strlen($row1['ca_id']) / 2 - 1;
$nbsp = "";
for ($i=0; $i<$len; $i++) $nbsp .= "&nbsp;&nbsp;&nbsp;";
echo '<option value="'.$row1['ca_id'].'" '.get_selected($sel_ca_id, $row1['ca_id']).'>'.$nbsp.$row1['ca_name'].'</option>'.PHP_EOL;
// 전체 카테고리 경로 표시
$category_path = function_exists('get_shop_category_path') ? get_shop_category_path($row1['ca_id']) : $row1['ca_name'];
echo '<option value="'.$row1['ca_id'].'" '.get_selected($sel_ca_id, $row1['ca_id']).'>'.$nbsp.$category_path.'</option>'.PHP_EOL;
}
?>
</select>
+6 -1
View File
@@ -46,6 +46,9 @@ if (!$sst) {
$sst = "it_id";
$sod = "desc";
}
$allowed_sst = array('it_id', 'it_name', 'it_type1', 'it_type2', 'it_type3', 'it_type4', 'it_type5', 'ca_id');
if ($sst && !in_array($sst, $allowed_sst)) $sst = 'it_id';
if ($sod && !in_array(strtolower($sod), array('asc', 'desc'))) $sod = '';
$sql_order = "order by $sst $sod";
$sql_common = " from {$g5['g5_shop_item_table']} ";
@@ -98,7 +101,9 @@ $listall = '<a href="'.$_SERVER['SCRIPT_NAME'].'" class="ov_listall">전체목
$len = strlen($row1['ca_id']) / 2 - 1;
$nbsp = "";
for ($i=0; $i<$len; $i++) $nbsp .= "&nbsp;&nbsp;&nbsp;";
echo '<option value="'.$row1['ca_id'].'" '.get_selected($sca, $row1['ca_id']).'>'.$nbsp.$row1['ca_name'].PHP_EOL;
// 전체 카테고리 경로 표시
$category_path = function_exists('get_shop_category_path') ? get_shop_category_path($row1['ca_id']) : $row1['ca_name'];
echo '<option value="'.$row1['ca_id'].'" '.get_selected($sca, $row1['ca_id']).'>'.$nbsp.$category_path.PHP_EOL;
}
?>
</select>
+6 -1
View File
@@ -33,6 +33,9 @@ if (!$sst) {
$sst = "is_id";
$sod = "desc";
}
$allowed_sst = array('is_id', 'a.it_id', 'it_name', 'is_name', 'is_score', 'is_time');
if ($sst && !in_array($sst, $allowed_sst)) $sst = 'is_id';
if ($sod && !in_array(strtolower($sod), array('asc', 'desc'))) $sod = '';
$sql_common = " from {$g5['g5_shop_item_use_table']} a
left join {$g5['g5_shop_item_table']} b on (a.it_id = b.it_id)
@@ -81,7 +84,9 @@ $listall = '<a href="'.$_SERVER['SCRIPT_NAME'].'" class="ov_listall">전체목
$nbsp = "";
for ($i=0; $i<$len; $i++) $nbsp .= "&nbsp;&nbsp;&nbsp;";
$selected = ($row1['ca_id'] == $sca) ? ' selected="selected"' : '';
echo '<option value="'.$row1['ca_id'].'"'.$selected.'>'.$nbsp.$row1['ca_name'].'</option>'.PHP_EOL;
// 전체 카테고리 경로 표시
$category_path = function_exists('get_shop_category_path') ? get_shop_category_path($row1['ca_id']) : $row1['ca_name'];
echo '<option value="'.$row1['ca_id'].'"'.$selected.'>'.$nbsp.$category_path.PHP_EOL;
}
?>
</select>
+3 -1
View File
@@ -84,7 +84,9 @@ $listall = '<a href="'.$_SERVER['SCRIPT_NAME'].'" class="ov_listall">전체목
$len = strlen($row1['ca_id']) / 2 - 1;
$nbsp = "";
for ($i=0; $i<$len; $i++) $nbsp .= "&nbsp;&nbsp;&nbsp;";
echo '<option value="'.$row1['ca_id'].'" '.get_selected($sel_ca_id, $row1['ca_id']).'>'.$nbsp.$row1['ca_name'].'</option>'.PHP_EOL;
// 전체 카테고리 경로 표시
$category_path = function_exists('get_shop_category_path') ? get_shop_category_path($row1['ca_id']) : $row1['ca_name'];
echo '<option value="'.$row1['ca_id'].'" '.get_selected($sel_ca_id, $row1['ca_id']).'>'.$nbsp.$category_path.'</option>'.PHP_EOL;
}
?>
</select>
+11 -11
View File
@@ -30,17 +30,17 @@ if(! function_exists('column_char')) {
$rows = array();
for($i=1; $row=sql_fetch_array($result); $i++) {
$rows[] =
array(' '.$row['od_id'],
$row['od_name'],
' '.$row['od_tel'],
' '.$row['od_hp'],
$row['od_b_name'],
' '.$row['od_b_tel'],
' '.$row['od_b_hp'],
print_address($row['od_b_addr1'], $row['od_b_addr2'], $row['od_b_addr3'], $row['od_b_addr_jibeon']),
$row['od_delivery_company'],
$row['od_invoice']);
$rows[] =
array(' '.$row['od_id'],
function_exists('csv_safe_cell') ? csv_safe_cell($row['od_name']) : $row['od_name'],
' '.$row['od_tel'],
' '.$row['od_hp'],
function_exists('csv_safe_cell') ? csv_safe_cell($row['od_b_name']) : $row['od_b_name'],
' '.$row['od_b_tel'],
' '.$row['od_b_hp'],
function_exists('csv_safe_cell') ? csv_safe_cell(print_address($row['od_b_addr1'], $row['od_b_addr2'], $row['od_b_addr3'], $row['od_b_addr_jibeon'])) : print_address($row['od_b_addr1'], $row['od_b_addr2'], $row['od_b_addr3'], $row['od_b_addr_jibeon']),
function_exists('csv_safe_cell') ? csv_safe_cell($row['od_delivery_company']) : $row['od_delivery_company'],
function_exists('csv_safe_cell') ? csv_safe_cell($row['od_invoice']) : $row['od_invoice']);
}
$data = array_merge(array($headers), $rows);
+2
View File
@@ -6,6 +6,8 @@ include_once(G5_LIB_PATH.'/mailer.lib.php');
auth_check_menu($auth, $sub_menu, "w");
check_admin_token();
define("_ORDERMAIL_", true);
$sms_count = 0;
+12 -18
View File
@@ -382,8 +382,8 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
<input type="hidden" name="sel_field" value="<?php echo $sel_field; ?>">
<input type="hidden" name="search" value="<?php echo $search; ?>">
<input type="hidden" name="page" value="<?php echo $page; ?>">
<input type="hidden" name="od_name" value="<?php echo $od['od_name']; ?>">
<input type="hidden" name="od_hp" value="<?php echo $od['od_hp']; ?>">
<input type="hidden" name="od_name" value="<?php echo get_text($od['od_name']); ?>">
<input type="hidden" name="od_hp" value="<?php echo get_text($od['od_hp']); ?>">
<input type="hidden" name="od_tno" value="<?php echo $od['od_tno']; ?>">
<input type="hidden" name="od_escrow" value="<?php echo $od['od_escrow']; ?>">
<input type="hidden" name="od_pg" value="<?php echo $od['od_pg']; ?>">
@@ -509,39 +509,33 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
<?php
if ($od['od_settle_case'] != '무통장') {
switch($od['od_pg']) {
case 'lg':
$pg_url = 'https://app.tosspayments.com';
$pg_test = '토스페이먼츠(구버전)';
if ($default['de_card_test']) {
$pg_url = 'https://pgweb.tosspayments.com/tmert';
$pg_test .= ' 테스트 ';
}
break;
case 'inicis':
$pg_url = 'https://iniweb.inicis.com/';
$pg_test = 'KG이니시스';
$pg_test = 'KG이니시스 ';
break;
case 'KAKAOPAY':
$pg_url = 'https://mms.cnspay.co.kr';
$pg_test = 'KAKAOPAY';
$pg_test = 'KAKAOPAY ';
break;
case 'nicepay':
$pg_url = 'https://npg.nicepay.co.kr/';
$pg_test = 'NICEPAY';
$pg_test = 'NICEPAY ';
break;
case 'lg':
case 'toss':
$pg_url = 'https://app.tosspayments.com';
$pg_test = '토스페이먼츠 ';
// 상점관리자 로그인 후 상단 '테스트 모드' 활성화 시 테스트 화면 노출
break;
default:
$pg_url = 'http://admin8.kcp.co.kr';
$pg_test = 'KCP';
$pg_url = 'https://partner.kcp.co.kr';
$pg_test = 'KCP ';
if ($default['de_card_test']) {
// 로그인 아이디 / 비번
// 일반 : test1234 / test12345
// 에스크로 : escrow / escrow913
$pg_url = 'http://testadmin8.kcp.co.kr';
$pg_test .= ' 테스트 ';
$pg_url = 'https://testpartner.kcp.co.kr';
$pg_test .= '테스트 ';
}
}
@@ -1170,4 +1164,4 @@ function chk_receipt_price()
</script>
<?php
include_once(G5_ADMIN_PATH.'/admin.tail.php');
include_once(G5_ADMIN_PATH.'/admin.tail.php');
+3 -3
View File
@@ -26,8 +26,8 @@ $od_cancel_price = isset($_GET['od_cancel_price']) ? preg_replace('/[^0-9a-z]/i'
$od_refund_price = isset($_GET['od_refund_price']) ? preg_replace('/[^0-9a-z]/i', '', $_GET['od_refund_price']) : '';
$od_receipt_point = isset($_GET['od_receipt_point']) ? preg_replace('/[^0-9a-z]/i', '', $_GET['od_receipt_point']) : '';
$od_coupon = isset($_GET['od_coupon']) ? preg_replace('/[^0-9a-z]/i', '', $_GET['od_coupon']) : '';
$od_settle_case = isset($_GET['od_settle_case']) ? clean_xss_tags($_GET['od_settle_case'], 1, 1) : '';
$od_escrow = isset($_GET['od_escrow']) ? clean_xss_tags($_GET['od_escrow'], 1, 1) : '';
$od_settle_case = isset($_GET['od_settle_case']) ? addslashes(clean_xss_tags(stripslashes($_GET['od_settle_case']), 1, 1)) : '';
$od_escrow = isset($_GET['od_escrow']) ? addslashes(clean_xss_tags(stripslashes($_GET['od_escrow']), 1, 1)) : '';
$tot_itemcount = $tot_orderprice = $tot_receiptprice = $tot_ordercancel = $tot_misu = $tot_couponprice = 0;
$sql_search = "";
@@ -350,7 +350,7 @@ if( function_exists('pg_setting_check') ){
if($default['de_escrow_use'] && $row['od_escrow'])
$od_paytype .= '<span class="list_escrow">에스크로</span>';
$uid = md5($row['od_id'].$row['od_time'].$row['od_ip']);
$uid = function_exists('get_shop_uid') ? get_shop_uid('order', $row['od_id'], $row['od_time'], $row['od_ip']) : md5($row['od_id'].$row['od_time'].$row['od_ip']);
$invoice_time = is_null_time($row['od_invoice_time']) ? G5_TIME_YMDHIS : $row['od_invoice_time'];
$delivery_company = $row['od_delivery_company'] ? $row['od_delivery_company'] : $default['de_delivery_company'];
+2
View File
@@ -4,6 +4,8 @@ include_once('./_common.php');
auth_check_menu($auth, $sub_menu, "w");
check_admin_token();
$tax_mny = isset($_POST['mod_tax_mny']) ? preg_replace('/[^0-9]/', '', $_POST['mod_tax_mny']) : 0;
$free_mny = isset($_POST['mod_free_mny']) ? preg_replace('/[^0-9]/', '', $_POST['mod_free_mny']) : 0;
+14 -14
View File
@@ -118,21 +118,21 @@ if ($csv == 'csv')
}
echo '"\''.$row['od_b_zip1'].$row['od_b_zip2'].'"\''.',';
echo '"'.$pull_address.'"'.',';
echo '"'.$row['od_b_name'].'"'.',';
echo '"'.(function_exists('csv_safe_cell') ? csv_safe_cell($pull_address) : $pull_address).'"'.',';
echo '"'.(function_exists('csv_safe_cell') ? csv_safe_cell($row['od_b_name']) : $row['od_b_name']).'"'.',';
//echo '"'.multibyte_digit((string)$row[od_b_tel]).'"'.',';
//echo '"'.multibyte_digit((string)$row[od_b_hp]).'"'.',';
echo '"'.conv_telno($row['od_b_tel']) . '"'.',';
echo '"'.conv_telno($row['od_b_hp']) . '"'.',';
echo '"'.preg_replace("/\"/", "&#034;", $row['it_name']) . '"'.',';
echo '"'.(function_exists('csv_safe_cell') ? csv_safe_cell(preg_replace("/\"/", "&#034;", $row['it_name'])) : preg_replace("/\"/", "&#034;", $row['it_name'])) . '"'.',';
echo '"'.$row['ct_qty'].'"'.',';
echo '"'.$row['ct_option'].'"'.',';
echo '"'.(function_exists('csv_safe_cell') ? csv_safe_cell($row['ct_option']) : $row['ct_option']).'"'.',';
echo '"'.$ct_send_cost.'"'.',';
echo '"\''.$row['it_id'].'\'"'.',';
echo '"\''.$row['od_id'].'\'"'.',';
echo '"'.$row['od_invoice'].'"'.',';
echo '"'.(function_exists('csv_safe_cell') ? csv_safe_cell($row['od_invoice']) : $row['od_invoice']).'"'.',';
//echo '"'.preg_replace("/\"/", "&#034;", preg_replace("/\n/", "", $row[od_memo])).'"';
echo '"'.preg_replace("/\"/", "&#034;", $row['od_memo']).'"';
echo '"'.(function_exists('csv_safe_cell') ? csv_safe_cell(preg_replace("/\"/", "&#034;", $row['od_memo'])) : preg_replace("/\"/", "&#034;", $row['od_memo'])).'"';
echo "\n";
}
if ($i == 0)
@@ -217,18 +217,18 @@ if ($csv == 'xls')
}
$rows[] = array(' '.$row['od_b_zip1'].$row['od_b_zip2'],
$pull_address,
$row['od_b_name'],
' '.conv_telno($row['od_b_tel']),
' '.conv_telno($row['od_b_hp']),
preg_replace("/\"/", "&#034;", $row['it_name']),
' '.$row['ct_qty'],
$row['ct_option'],
function_exists('csv_safe_cell') ? csv_safe_cell($pull_address) : $pull_address,
function_exists('csv_safe_cell') ? csv_safe_cell($row['od_b_name']) : $row['od_b_name'],
' '.conv_telno($row['od_b_tel']),
' '.conv_telno($row['od_b_hp']),
function_exists('csv_safe_cell') ? csv_safe_cell(preg_replace("/\"/", "&#034;", $row['it_name'])) : preg_replace("/\"/", "&#034;", $row['it_name']),
' '.$row['ct_qty'],
function_exists('csv_safe_cell') ? csv_safe_cell($row['ct_option']) : $row['ct_option'],
$ct_send_cost,
' '.$row['it_id'],
' '.$row['od_id'],
' '.$row['od_invoice'],
preg_replace("/\"/", "&#034;", $row['od_memo']));
function_exists('csv_safe_cell') ? csv_safe_cell(preg_replace("/\"/", "&#034;", $row['od_memo'])) : preg_replace("/\"/", "&#034;", $row['od_memo']));
}
$data = array_merge(array($headers), $rows);
+1 -1
View File
@@ -87,7 +87,7 @@ $result = sql_query($sql);
?>
<tr>
<td class="td_alignc"><a href="./orderform.php?od_id=<?php echo $row['od_id']; ?>"><?php echo $row['od_id']; ?></a></td>
<td class="td_name"><?php echo $href; ?><?php echo $row['od_name']; ?></a></td>
<td class="td_name"><?php echo $href; ?><?php echo get_text($row['od_name']); ?></a></td>
<td class="td_numsum"><?php echo number_format($row['orderprice']); ?></td>
<td class="td_numincome"><?php echo number_format($row['couponprice']); ?></td>
<td class="td_numincome"><?php echo number_format($receipt_bank); ?></td>
+3 -1
View File
@@ -71,7 +71,9 @@ $listall = '<a href="'.$_SERVER['SCRIPT_NAME'].'" class="ov_listall">전체목
$len = strlen($row1['ca_id']) / 2 - 1;
$nbsp = "";
for ($i=0; $i<$len; $i++) $nbsp .= "&nbsp;&nbsp;&nbsp;";
echo "<option value='{$row1['ca_id']}'".get_selected($row1['ca_id'], $sel_ca_id).">$nbsp{$row1['ca_name']}\n";
// 전체 카테고리 경로 표시
$category_path = function_exists('get_shop_category_path') ? get_shop_category_path($row1['ca_id']) : $row1['ca_name'];
echo "<option value='{$row1['ca_id']}'".get_selected($row1['ca_id'], $sel_ca_id).">$nbsp{$category_path}\n";
}
?>
</select>
+1 -1
View File
@@ -4,7 +4,7 @@ include_once ('../../common.php');
include_once(G5_ADMIN_PATH.'/admin.lib.php');
include_once(G5_SMS5_PATH.'/sms5.lib.php');
if (!strstr($_SERVER['SCRIPT_NAME'], 'install.php')) {
if (strpos($_SERVER['SCRIPT_NAME'], 'install.php') === false) {
// SMS5 테이블 G5_TABLE_PREFIX 적용
if($g5['sms5_prefix'] != 'sms5_' && sql_num_rows(sql_query("show tables like 'sms5_config'")))
{
+7 -7
View File
@@ -10,14 +10,14 @@ check_admin_token();
$g5['title'] = "SMS 기본설정";
$cf_phone = isset($_REQUEST['cf_phone']) ? clean_xss_tags($_REQUEST['cf_phone'], 1, 1) : '';
$cf_sms_use = isset($_REQUEST['cf_sms_use']) ? clean_xss_tags($_REQUEST['cf_sms_use'], 1, 1) : '';
$cf_sms_type = isset($_REQUEST['cf_sms_type']) ? clean_xss_tags($_REQUEST['cf_sms_type'], 1, 1) : '';
$cf_icode_id = isset($_REQUEST['cf_icode_id']) ? clean_xss_tags($_REQUEST['cf_icode_id'], 1, 1) : '';
$cf_icode_pw = isset($_REQUEST['cf_icode_pw']) ? clean_xss_tags($_REQUEST['cf_icode_pw'], 1, 1) : '';
$cf_icode_server_ip = isset($_REQUEST['cf_icode_server_ip']) ? clean_xss_tags($_REQUEST['cf_icode_server_ip'], 1, 1) : '';
$cf_phone = isset($_REQUEST['cf_phone']) ? addslashes(clean_xss_tags(stripslashes($_REQUEST['cf_phone']), 1, 1)) : '';
$cf_sms_use = isset($_REQUEST['cf_sms_use']) ? addslashes(clean_xss_tags(stripslashes($_REQUEST['cf_sms_use']), 1, 1)) : '';
$cf_sms_type = isset($_REQUEST['cf_sms_type']) ? addslashes(clean_xss_tags(stripslashes($_REQUEST['cf_sms_type']), 1, 1)) : '';
$cf_icode_id = isset($_REQUEST['cf_icode_id']) ? addslashes(clean_xss_tags(stripslashes($_REQUEST['cf_icode_id']), 1, 1)) : '';
$cf_icode_pw = isset($_REQUEST['cf_icode_pw']) ? addslashes(clean_xss_tags(stripslashes($_REQUEST['cf_icode_pw']), 1, 1)) : '';
$cf_icode_server_ip = isset($_REQUEST['cf_icode_server_ip']) ? addslashes(clean_xss_tags(stripslashes($_REQUEST['cf_icode_server_ip']), 1, 1)) : '';
$cf_icode_server_port = isset($_REQUEST['cf_icode_server_port']) ? clean_xss_tags($_REQUEST['cf_icode_server_port'], 1, 1) : '';
$cf_icode_token_key = isset($_REQUEST['cf_icode_token_key']) ? clean_xss_tags($_REQUEST['cf_icode_token_key'], 1, 1) : '';
$cf_icode_token_key = isset($_REQUEST['cf_icode_token_key']) ? addslashes(clean_xss_tags(stripslashes($_REQUEST['cf_icode_token_key']), 1, 1)) : '';
// 회신번호 체크
if(!check_vaild_callback($cf_phone))
+2 -2
View File
@@ -65,7 +65,7 @@ function book_all_checked(chk)
function book_del(fo_no)
{
if (confirm("한번 삭제한 자료는 복구할 방법이 없습니다.\n\n그래도 삭제하시겠습니까?"))
location.href = "./form_update.php?w=d&fo_no=" + fo_no + "&page=<?php echo $page?>&fg_no=<?php echo $fg_no?>&st=<?php echo get_text($st); ?>&sv=<?php echo get_text($sv); ?>";
location.href = "./form_update.php?w=d&fo_no=" + fo_no + "&page=<?php echo $page?>&fg_no=<?php echo $fg_no?>&st=<?php echo get_text($st); ?>&sv=<?php echo get_text($sv); ?>&token=<?php echo $token; ?>";
}
function multi_update(sel)
@@ -114,7 +114,7 @@ function multi_update(sel)
<div class="local_sch01 local_sch sms_preset_sch">
<form>
<label for="fg_no" class="sound_only">그룹명</label>
<select name="fg_no" id="fg_no" onchange="location.href='<?php echo $_SERVER['SCRIPT_NAME']?>?fg_no='+this.value;">
<select name="fg_no" id="fg_no" onchange="location.href='<?php echo htmlspecialchars($_SERVER['SCRIPT_NAME'])?>?fg_no='+this.value;">
<option value="" <?php echo $fg_no?'':'selected'?>> 전체 </option>
<option value="0" <?php echo $fg_no=='0'?'selected':''?>> 미분류 (<?php echo number_format($no_count)?>) </option>
<?php for($i=0; $i<count($group); $i++) {?>
+2
View File
@@ -4,6 +4,8 @@ include_once("./_common.php");
auth_check_menu($auth, $sub_menu, "w");
check_admin_token();
$fo_name = isset($_REQUEST['fo_name']) ? strip_tags(clean_xss_attributes($_REQUEST['fo_name'])) : '';
$fo_content = isset($_REQUEST['fo_content']) ? strip_tags(clean_xss_attributes($_REQUEST['fo_content'])) : '';
$fo_receipt = isset($_REQUEST['fo_receipt']) ? clean_xss_tags($_REQUEST['fo_receipt'], 1, 1) : '';
+3
View File
@@ -4,6 +4,8 @@ include_once("./_common.php");
auth_check_menu($auth, $sub_menu, "w");
$token = get_token();
$g5['title'] = "이모티콘 ";
$fo_no = isset($_REQUEST['fo_no']) ? (int) $_REQUEST['fo_no'] : 0;
@@ -34,6 +36,7 @@ include_once(G5_ADMIN_PATH.'/admin.head.php');
<input type="hidden" name="page" value="<?php echo $page?>">
<input type="hidden" name="fo_no" value="<?php echo $write['fo_no']; ?>">
<input type="hidden" name="get_fg_no" value="<?php echo $fg_no?>">
<input type="hidden" name="token" value="<?php echo $token; ?>">
<div class="tbl_frm01 tbl_wrap">
<table>
+7 -6
View File
@@ -161,11 +161,12 @@ function all_send()
if( $write['wr_memo'] ){
$tmp_wr_memo = @unserialize($write['wr_memo']);
if( count($tmp_wr_memo) && is_array($tmp_wr_memo) ){
if(function_exists('array_fill_keys')){
$tmp_wr_hp = array_replace($tmp_wr_memo['hp'],array_fill_keys(array_keys($tmp_wr_memo['hp'], null),''));
} else {
$tmp_wr_hp = $tmp_wr_memo['hp'];
}
$tmp_wr_hp = $tmp_wr_memo['hp'];
if (is_array($tmp_wr_hp)) {
foreach (array_keys($tmp_wr_hp, null) as $empty_key) {
$tmp_wr_hp[$empty_key] = '';
}
}
$arr_wr_memo = @array_count_values( $tmp_wr_hp );
?>
<h2>중복번호 <?php echo $tmp_wr_memo['total'];?>건</h2>
@@ -265,4 +266,4 @@ function all_send()
<?php echo sms5_sub_paging(G5_IS_MOBILE ? $config['cf_mobile_pages'] : $config['cf_write_pages'], $spage, $total_spage, $_SERVER['SCRIPT_NAME']."?wr_no=$wr_no&amp;wr_renum=$wr_renum&amp;page=$page&amp;st=$st&amp;sv=$sv&amp;sst=$sst&amp;ssv=$ssv", "", "spage"); ?>
<?php
include_once(G5_ADMIN_PATH.'/admin.tail.php');
include_once(G5_ADMIN_PATH.'/admin.tail.php');
+3 -1
View File
@@ -4,6 +4,8 @@ include_once("./_common.php");
auth_check_menu($auth, $sub_menu, "r");
$token = get_token();
$g5['title'] = "회원정보 업데이트";
include_once(G5_ADMIN_PATH.'/admin.head.php');
@@ -37,7 +39,7 @@ include_once(G5_ADMIN_PATH.'/admin.head.php');
$( "#mb_update_form" ).submit(function( e ) {
e.preventDefault();
$("#res_msg").html('업데이트 중입니다. 잠시만 기다려 주십시오...');
var params = { mtype : 'json' };
var params = { mtype : 'json', token : '<?php echo $token; ?>' };
$.ajax({
url: $(this).attr("action"),
cache:false,
+2
View File
@@ -26,6 +26,8 @@ if( $mtype == "json" ){
auth_check_menu($auth, $sub_menu, "w");
}
check_admin_token();
$count = 0;
$hp_yes = 0;
$hp_no = 0;
+1 -1
View File
@@ -130,7 +130,7 @@ function no_hp_click(val)
<form name="search_form" class="local_sch01 local_sch">
<label for="bg_no" class="sound_only">그룹명</label>
<select name="bg_no" id="bg_no" onchange="location.href='<?php echo $_SERVER['SCRIPT_NAME']?>?bg_no='+this.value;">
<select name="bg_no" id="bg_no" onchange="location.href='<?php echo htmlspecialchars($_SERVER['SCRIPT_NAME'])?>?bg_no='+this.value;">
<option value=""<?php echo get_selected('', $bg_no); ?>> 전체 </option>
<option value="<?php echo $no_group['bg_no']?>"<?php echo get_selected($no_group['bg_no'], $bg_no); ?>> <?php echo $no_group['bg_name']?> (<?php echo number_format($no_group['bg_count'])?> 명) </option>
<?php for($i=0; $i<count($group); $i++) {?>
+1 -1
View File
@@ -46,7 +46,7 @@ for($i=1; $res=sql_fetch_array($qry); $i++)
if ($no_hp && $res['bk_hp'] != '' && !$hp) continue;
$rows[] = array($res['bk_name'], ' '.$hp);
$rows[] = array(function_exists('csv_safe_cell') ? csv_safe_cell($res['bk_name']) : $res['bk_name'], ' '.$hp);
}
$data = array_merge(array($headers), $rows);
+1 -1
View File
@@ -125,7 +125,7 @@ while ($row = array_shift($send_list))
continue 2;
}
array_push($list, array('bk_hp' => $hp, 'bk_name' => $name));
array_push($list, array('bk_hp' => $hp, 'bk_name' => $name, 'mb_id' => '', 'bg_no' => '', 'bk_no' => ''));
array_push($hps, $hp);
break;
+2 -1
View File
@@ -7,7 +7,8 @@ $content = isset($_POST['content']) ? strip_tags($_POST['content']) : '';
//$filter = explode(",", strtolower(trim($config['cf_filter'])));
// strtolower 에 의한 한글 변형으로 아래 코드로 대체 (곱슬최씨님이 알려 주셨습니다.)
$filter = explode(",", trim($config['cf_filter']));
for ($i=0; $i<count($filter); $i++) {
$filter_cnt = count($filter);
for ($i=0; $i<$filter_cnt; $i++) {
$str = $filter[$i];
// 제목 필터링 (찾으면 중지)
+5
View File
@@ -2,6 +2,11 @@
include_once('./_common.php');
include_once(G5_LIB_PATH.'/register.lib.php');
// 회원 ID 열거 공격 방지를 위한 Rate Limit (분당 30회)
if (function_exists('check_rate_limit') && !check_rate_limit('ajax_mb_id_check', 30, 60)) {
die('너무 많은 요청이 발생했습니다. 잠시 후 다시 시도해 주세요.');
}
$mb_id = isset($_POST['reg_mb_id']) ? trim($_POST['reg_mb_id']) : '';
set_session('ss_check_mb_id', '');
+5
View File
@@ -2,6 +2,11 @@
include_once('./_common.php');
include_once(G5_LIB_PATH.'/register.lib.php');
// 회원 닉네임 열거 공격 방지를 위한 Rate Limit (분당 30회)
if (function_exists('check_rate_limit') && !check_rate_limit('ajax_mb_nick_check', 30, 60)) {
die('너무 많은 요청이 발생했습니다. 잠시 후 다시 시도해 주세요.');
}
$mb_nick = isset($_POST['reg_mb_nick']) ? trim($_POST['reg_mb_nick']) : '';
$mb_id = isset($_POST['reg_mb_id']) ? trim($_POST['reg_mb_id']) : '';
+5
View File
@@ -2,6 +2,11 @@
include_once("./_common.php");
include_once(G5_LIB_PATH."/register.lib.php");
// 추천인 ID 열거 공격 방지를 위한 Rate Limit (분당 30회)
if (function_exists('check_rate_limit') && !check_rate_limit('ajax_mb_recommend_check', 30, 60)) {
die('너무 많은 요청이 발생했습니다. 잠시 후 다시 시도해 주세요.');
}
$mb_recommend = isset($_POST["reg_mb_recommend"]) ? trim($_POST["reg_mb_recommend"]) : '';
if ($msg = valid_mb_id($mb_recommend)) {
+116 -115
View File
@@ -1,116 +1,117 @@
<?php
global $lo_location;
global $lo_url;
include_once('./_common.php');
if($error) {
$g5['title'] = "오류안내 페이지";
} else {
$g5['title'] = "결과안내 페이지";
}
include_once(G5_PATH.'/head.sub.php');
// 필수 입력입니다.
// 양쪽 공백 없애기
// 필수 (선택 혹은 입력)입니다.
// 전화번호 형식이 올바르지 않습니다. 하이픈(-)을 포함하여 입력하세요.
// 이메일주소 형식이 아닙니다.
// 한글이 아닙니다. (자음, 모음만 있는 한글은 처리하지 않습니다.)
// 한글이 아닙니다.
// 한글, 영문, 숫자가 아닙니다.
// 한글, 영문이 아닙니다.
// 숫자가 아닙니다.
// 영문이 아닙니다.
// 영문 또는 숫자가 아닙니다.
// 영문, 숫자, _ 가 아닙니다.
// 최소 글자 이상 입력하세요.
// 이미지 파일이 아닙니다..gif .jpg .png 파일만 가능합니다.
// 파일만 가능합니다.
// 공백이 없어야 합니다.
$msg = isset($msg) ? strip_tags($msg) : '';
$msg2 = str_replace("\\n", "<br>", $msg);
$url = isset($url) ? clean_xss_tags($url, 1) : '';
if (!$url) $url = isset($_SERVER['HTTP_REFERER']) ? clean_xss_tags($_SERVER['HTTP_REFERER'], 1) : '';
$url = preg_replace("/[\<\>\'\"\\\'\\\"\(\)]/", "", $url);
$url = preg_replace('/\r\n|\r|\n|[^\x20-\x7e]/','', $url);
// url 체크
check_url_host($url, $msg);
if($error) {
$header2 = "다음 항목에 오류가 있습니다.";
} else {
$header2 = "다음 내용을 확인해 주세요.";
}
?>
<script>
alert("<?php echo $msg; ?>");
<?php if ($url) { ?>
document.location.replace("<?php echo str_replace('&amp;', '&', $url); ?>");
<?php } else { ?>
history.back();
<?php } ?>
</script>
<noscript>
<div id="validation_check">
<h1><?php echo $header2 ?></h1>
<p class="cbg">
<?php echo $msg2 ?>
</p>
<?php if($post) { ?>
<form method="post" action="<?php echo $url ?>">
<?php
foreach($_POST as $key => $value) {
$key = clean_xss_tags($key);
$value = clean_xss_tags($value);
if(strlen($value) < 1)
continue;
if(preg_match("/pass|pwd|capt|url/", $key))
continue;
?>
<input type="hidden" name="<?php echo htmlspecialchars($key); ?>" value="<?php echo htmlspecialchars($value); ?>">
<?php
}
?>
<input type="submit" value="돌아가기">
</form>
<?php } else { ?>
<div class="btn_confirm">
<a href="<?php echo $url ?>">돌아가기</a>
</div>
<?php } ?>
<?php /*
<article id="validation_check">
<header>
<hgroup>
<!-- <h1>회원가입 정보 입력 확인</h1> --> <!-- 수행 중이던 작업 내용 -->
<h1><?php echo $header ?></h1> <!-- 수행 중이던 작업 내용 -->
<h2><?php echo $header2 ?></h2>
</hgroup>
</header>
<p>
<!-- <strong>항목</strong> 오류내역 -->
<!--
<strong>이름</strong> 필수 입력입니다. 한글만 입력할 수 있습니다.<br>
<strong>이메일</strong> 올바르게 입력하지 않았습니다.<br>
-->
<?php echo $msg2 ?>
</p>
<a href="<?php echo $url ?>">돌아가기</a>
</article>
*/ ?>
</div>
</noscript>
<?php
<?php
global $lo_location;
global $lo_url;
include_once('./_common.php');
if($error) {
$g5['title'] = "오류안내 페이지";
} else {
$g5['title'] = "결과안내 페이지";
}
include_once(G5_PATH.'/head.sub.php');
// 필수 입력입니다.
// 양쪽 공백 없애기
// 필수 (선택 혹은 입력)입니다.
// 전화번호 형식이 올바르지 않습니다. 하이픈(-)을 포함하여 입력하세요.
// 이메일주소 형식이 아닙니다.
// 한글이 아닙니다. (자음, 모음만 있는 한글은 처리하지 않습니다.)
// 한글이 아닙니다.
// 한글, 영문, 숫자가 아닙니다.
// 한글, 영문이 아닙니다.
// 숫자가 아닙니다.
// 영문이 아닙니다.
// 영문 또는 숫자가 아닙니다.
// 영문, 숫자, _ 가 아닙니다.
// 최소 글자 이상 입력하세요.
// 이미지 파일이 아닙니다..gif .jpg .png 파일만 가능합니다.
// 파일만 가능합니다.
// 공백이 없어야 합니다.
$msg = isset($msg) ? strip_tags($msg) : '';
$msg2 = str_replace(array("\\r\\n", "\\n", "\\r"), "<br>", $msg);
$alert_msg = str_replace(array("\\r\\n", "\\n", "\\r"), "\n", $msg);
$url = isset($url) ? clean_xss_tags($url, 1) : '';
if (!$url) $url = isset($_SERVER['HTTP_REFERER']) ? clean_xss_tags($_SERVER['HTTP_REFERER'], 1) : '';
$url = preg_replace("/[\<\>\'\"\\\'\\\"\(\)]/", "", $url);
$url = preg_replace('/\r\n|\r|\n|[^\x20-\x7e]/','', $url);
// url 체크
check_url_host($url, $msg);
if($error) {
$header2 = "다음 항목에 오류가 있습니다.";
} else {
$header2 = "다음 내용을 확인해 주세요.";
}
?>
<script>
alert(<?php echo function_exists('get_js_safe_string') ? get_js_safe_string($alert_msg) : '""'; ?>);
<?php if ($url) { ?>
document.location.replace("<?php echo str_replace('&amp;', '&', $url); ?>");
<?php } else { ?>
history.back();
<?php } ?>
</script>
<noscript>
<div id="validation_check">
<h1><?php echo $header2 ?></h1>
<p class="cbg">
<?php echo $msg2 ?>
</p>
<?php if($post) { ?>
<form method="post" action="<?php echo $url ?>">
<?php
foreach($_POST as $key => $value) {
$key = clean_xss_tags($key);
$value = clean_xss_tags($value);
if(strlen($value) < 1)
continue;
if(preg_match("/pass|pwd|capt|url/", $key))
continue;
?>
<input type="hidden" name="<?php echo htmlspecialchars($key); ?>" value="<?php echo htmlspecialchars($value); ?>">
<?php
}
?>
<input type="submit" value="돌아가기">
</form>
<?php } else { ?>
<div class="btn_confirm">
<a href="<?php echo $url ?>">돌아가기</a>
</div>
<?php } ?>
<?php /*
<article id="validation_check">
<header>
<hgroup>
<!-- <h1>회원가입 정보 입력 확인</h1> --> <!-- 수행 중이던 작업 내용 -->
<h1><?php echo $header ?></h1> <!-- 수행 중이던 작업 내용 -->
<h2><?php echo $header2 ?></h2>
</hgroup>
</header>
<p>
<!-- <strong>항목</strong> 오류내역 -->
<!--
<strong>이름</strong> 필수 입력입니다. 한글만 입력할 수 있습니다.<br>
<strong>이메일</strong> 올바르게 입력하지 않았습니다.<br>
-->
<?php echo $msg2 ?>
</p>
<a href="<?php echo $url ?>">돌아가기</a>
</article>
*/ ?>
</div>
</noscript>
<?php
include_once(G5_PATH.'/tail.sub.php');
+4 -3
View File
@@ -4,7 +4,8 @@ include_once(G5_PATH.'/head.sub.php');
$msg = isset($msg) ? strip_tags($msg) : '';
$msg2 = str_replace("\\n", "<br>", $msg);
$msg2 = str_replace(array("\\r\\n", "\\n", "\\r"), "<br>", $msg);
$alert_msg = str_replace(array("\\r\\n", "\\n", "\\r"), "\n", $msg);
if($error) {
$header2 = "다음 항목에 오류가 있습니다.";
@@ -16,7 +17,7 @@ if($error) {
?>
<script>
alert("<?php echo $msg; ?>");
alert(<?php echo function_exists('get_js_safe_string') ? get_js_safe_string($alert_msg) : '""'; ?>);
try {
window.close();
} catch(error) {
@@ -69,4 +70,4 @@ setTimeout(function() {
</noscript>
<?php
include_once(G5_PATH.'/tail.sub.php');
include_once(G5_PATH.'/tail.sub.php');
+2
View File
@@ -1,6 +1,8 @@
<?php
include_once('./_common.php');
if (function_exists('check_request_origin')) check_request_origin(G5_BBS_URL);
$count = (isset($_POST['chk_wr_id']) && is_array($_POST['chk_wr_id'])) ? count($_POST['chk_wr_id']) : 0;
$post_btn_submit = isset($_POST['btn_submit']) ? clean_xss_tags($_POST['btn_submit'], 1, 1) : '';
+1 -1
View File
@@ -1,7 +1,7 @@
<?php
include_once('./_common.php');
$mb_id = isset($_REQUEST['mb_id']) ? clean_xss_tags($_REQUEST['mb_id'], 1, 1) : '';
$mb_id = isset($_REQUEST['mb_id']) ? addslashes(clean_xss_tags(stripslashes($_REQUEST['mb_id']), 1, 1)) : '';
$sql = " select mb_id, mb_email, mb_datetime from {$g5['member_table']} where mb_id = '{$mb_id}' ";
$row = sql_fetch($sql);
+24 -1
View File
@@ -9,6 +9,13 @@ if (!$config['cf_email_use'])
if (!$is_member && $config['cf_formmail_is_member'])
alert_close('회원만 이용하실 수 있습니다.');
// 발송 횟수 제한 (직접 POST 우회 방지)
$sendmail_count = (int)get_session('ss_sendmail_count') + 1;
set_session('ss_sendmail_count', $sendmail_count);
if ($sendmail_count > 3) {
alert_close('폼메일 발송 횟수를 초과하였습니다.');
}
$email_enc = new str_encrypt();
$to = $email_enc->decrypt($to);
@@ -40,7 +47,23 @@ if ($type) {
else
$mail_content = $content;
mailer($fnick, $fmail, $to, $subject, $mail_content, $type, $file);
// 발신자 정보 서버측 강제 설정
$reply_to_email = '';
if ($is_member) {
$fnick = (isset($member['mb_nick']) && $member['mb_nick']) ? $member['mb_nick'] : $member['mb_name'];
$fmail = $member['mb_email'];
} else {
// 비회원: From을 관리자 이메일로 고정 (발신자 위장 방지)
// 비회원이 입력한 이메일은 Reply-To로 설정하여 회신 기능 유지
$user_email = get_email_address(trim($fmail));
$fnick = strip_tags(trim($fnick));
$fmail = $config['cf_admin_email'];
if ($user_email) {
$reply_to_email = $user_email;
}
}
mailer($fnick, $fmail, $to, $subject, $mail_content, $type, $file, '', '', $reply_to_email);
// 임시 첨부파일 삭제
if(!empty($file)) {
+19 -8
View File
@@ -76,16 +76,22 @@ if(isset($_POST['js']) && $_POST['js'] === "on") {
}
else
{
// 추천(찬성), 비추천(반대) 카운트 증가
// 레이스 컨디션 방지: g5_board_good 테이블의 UNIQUE KEY(bo_table, wr_id, mb_id)를
// 이용해 INSERT IGNORE를 먼저 수행하고, 성공한 경우에만 카운터를 증가시킨다.
sql_query(" insert ignore into {$g5['board_good_table']} set bo_table = '{$bo_table}', wr_id = '{$wr_id}', mb_id = '{$member['mb_id']}', bg_flag = '{$good}', bg_datetime = '".G5_TIME_YMDHIS."' ");
if (get_sql_affected_rows() <= 0) {
$error = '이미 추천 또는 비추천 하신 글 입니다.';
print_result($error, $count);
}
// INSERT 성공 시에만 카운터 증가
sql_query(" update {$g5['write_prefix']}{$bo_table} set wr_{$good} = wr_{$good} + 1 where wr_id = '{$wr_id}' ");
// 내역 생성
sql_query(" insert {$g5['board_good_table']} set bo_table = '{$bo_table}', wr_id = '{$wr_id}', mb_id = '{$member['mb_id']}', bg_flag = '{$good}', bg_datetime = '".G5_TIME_YMDHIS."' ");
$sql = " select wr_{$good} as count from {$g5['write_prefix']}{$bo_table} where wr_id = '$wr_id' ";
$row = sql_fetch($sql);
$count = $row['count'];
run_event('bbs_increase_good_json', $bo_table, $wr_id, $good);
print_result($error, $count);
@@ -140,10 +146,15 @@ if(isset($_POST['js']) && $_POST['js'] === "on") {
}
else
{
// 추천(찬성), 비추천(반대) 카운트 증가
// 레이스 컨디션 방지: g5_board_good 테이블의 UNIQUE KEY(bo_table, wr_id, mb_id)를
// 이용해 INSERT IGNORE를 먼저 수행하고, 성공한 경우에만 카운터를 증가시킨다.
sql_query(" insert ignore into {$g5['board_good_table']} set bo_table = '{$bo_table}', wr_id = '{$wr_id}', mb_id = '{$member['mb_id']}', bg_flag = '{$good}', bg_datetime = '".G5_TIME_YMDHIS."' ");
if (get_sql_affected_rows() <= 0) {
alert('이미 추천 또는 비추천 하신 글 입니다.');
}
// INSERT 성공 시에만 카운터 증가
sql_query(" update {$g5['write_prefix']}{$bo_table} set wr_{$good} = wr_{$good} + 1 where wr_id = '{$wr_id}' ");
// 내역 생성
sql_query(" insert {$g5['board_good_table']} set bo_table = '{$bo_table}', wr_id = '{$wr_id}', mb_id = '{$member['mb_id']}', bg_flag = '{$good}', bg_datetime = '".G5_TIME_YMDHIS."' ");
if ($good == 'good')
$status = '추천';
@@ -151,7 +162,7 @@ if(isset($_POST['js']) && $_POST['js'] === "on") {
$status = '비추천';
$href = get_pretty_url($bo_table, $wr_id);
run_event('bbs_increase_good_html', $bo_table, $wr_id, $good, $href);
alert("이 글을 $status 하셨습니다.", '', false);
+90 -43
View File
@@ -14,7 +14,8 @@ if ($board['bo_use_category']) {
$category_option .= '>전체</a></li>';
$categories = explode('|', $board['bo_category_list']); // 구분자가 , 로 되어 있음
for ($i=0; $i<count($categories); $i++) {
$categories_cnt = count($categories);
for ($i=0; $i<$categories_cnt; $i++) {
$category = trim($categories[$i]);
if ($category=='') continue;
$category_option .= '<li><a href="'.(get_pretty_url($bo_table,'','sca='.urlencode($category))).'"';
@@ -89,15 +90,31 @@ if (!$is_search_bbs) {
$from_notice_idx = ($page - 1) * $page_rows;
if($from_notice_idx < 0)
$from_notice_idx = 0;
$board_notice_count = count($arr_notice);
for ($k=0; $k<$board_notice_count; $k++) {
if (trim($arr_notice[$k]) == '') continue;
// 유효한 공지 wr_id만 수집 (정수화로 SQL injection 방지)
$notice_ids_int = array();
foreach ($arr_notice as $k_idx => $nid_raw) {
$nid_int = (int) trim($nid_raw);
if ($nid_int > 0) {
$notice_ids_int[$k_idx] = $nid_int;
}
}
$row = sql_fetch(" select * from {$write_table} where wr_id = '{$arr_notice[$k]}' ");
// N+1 쿼리 제거: 공지 전체를 단일 IN 쿼리로 일괄 조회
$notice_rows_by_id = array();
if (!empty($notice_ids_int)) {
$sql = " select * from {$write_table} where wr_id in (" . implode(',', $notice_ids_int) . ") ";
$result = sql_query($sql);
while ($nrow = sql_fetch_array($result)) {
$notice_rows_by_id[$nrow['wr_id']] = $nrow;
}
}
if (!isset($row['wr_id']) || !$row['wr_id']) continue;
// 원래 bo_notice 순서대로 처리 (페이징 로직의 $k 인덱스 의미 보존)
foreach ($notice_ids_int as $k => $nid) {
if (!isset($notice_rows_by_id[$nid])) continue;
$row = $notice_rows_by_id[$nid];
$notice_array[] = $row['wr_id'];
if($k < $from_notice_idx) continue;
@@ -106,7 +123,7 @@ if (!$is_search_bbs) {
$list[$i]['is_notice'] = true;
$list[$i]['list_content'] = $list[$i]['wr_content'];
// 비밀글인 경우 리스트에서 내용이 출력되지 않게 글 내용을 지웁니다.
// 비밀글인 경우 리스트에서 내용이 출력되지 않게 글 내용을 지웁니다.
if (strstr($list[$i]['wr_option'], "secret")) {
$list[$i]['wr_content'] = '';
}
@@ -174,49 +191,79 @@ if (!$sst) {
if(!$sst)
$sst = "wr_num, wr_reply";
// 정렬 방향 화이트리스트
$sod = preg_match("/^(asc|desc)$/i", $sod) ? $sod : '';
if ($sst) {
$sql_order = " order by {$sst} {$sod} ";
}
if ($is_search_bbs) {
$sql = " select distinct wr_parent from {$write_table} where {$sql_search} {$sql_order} limit {$from_record}, $page_rows ";
} else {
$sql = " select * from {$write_table} where wr_is_comment = 0 ";
if(!empty($notice_array))
$sql .= " and wr_id not in (".implode(', ', $notice_array).") ";
$sql .= " {$sql_order} limit {$from_record}, $page_rows ";
// 페이지의 공지개수가 목록수 보다 작을 때만 실행
$rows_to_process = array();
if ($page_rows > 0) {
if ($is_search_bbs) {
// 1차: 검색 결과의 wr_parent ID 목록 조회
$sql = " select distinct wr_parent from {$write_table} where {$sql_search} {$sql_order} limit {$from_record}, $page_rows ";
$result = sql_query($sql);
$parent_ids_in_order = array();
while ($id_row = sql_fetch_array($result)) {
$pid = (int) $id_row['wr_parent'];
if ($pid > 0) {
$parent_ids_in_order[] = $pid;
}
}
// 2차: N+1 쿼리 제거 - 단일 IN 쿼리로 전체 행 일괄 조회
if (!empty($parent_ids_in_order)) {
$batch_sql = " select * from {$write_table} where wr_id in (" . implode(',', $parent_ids_in_order) . ") ";
$batch_result = sql_query($batch_sql);
$rows_by_id = array();
while ($br = sql_fetch_array($batch_result)) {
$rows_by_id[$br['wr_id']] = $br;
}
// DISTINCT 쿼리의 원래 정렬 순서대로 재구성
foreach ($parent_ids_in_order as $pid) {
if (isset($rows_by_id[$pid])) {
$rows_to_process[] = $rows_by_id[$pid];
}
}
}
} else {
$sql = " select * from {$write_table} where wr_is_comment = 0 ";
if(!empty($notice_array))
$sql .= " and wr_id not in (".implode(', ', $notice_array).") ";
$sql .= " {$sql_order} limit {$from_record}, $page_rows ";
$result = sql_query($sql);
while ($row = sql_fetch_array($result)) {
$rows_to_process[] = $row;
}
}
}
// 페이지의 공지개수가 목록수 보다 작을 때만 실행
if($page_rows > 0) {
$result = sql_query($sql);
$k = 0;
while ($row = sql_fetch_array($result))
{
// 검색일 경우 wr_id만 얻었으므로 다시 한행을 얻는다
if ($is_search_bbs)
$row = sql_fetch(" select * from {$write_table} where wr_id = '{$row['wr_parent']}' ");
$list[$i] = get_list($row, $board, $board_skin_url, G5_IS_MOBILE ? $board['bo_mobile_subject_len'] : $board['bo_subject_len']);
if (strstr($sfl, 'subject')) {
$list[$i]['subject'] = search_font($stx, $list[$i]['subject']);
}
$list[$i]['is_notice'] = false;
$list[$i]['list_content'] = $list[$i]['wr_content'];
// 비밀글인 경우 리스트에서 내용이 출력되지 않게 글 내용을 지웁니다.
if (strstr($list[$i]['wr_option'], "secret")) {
$list[$i]['wr_content'] = '';
}
$list_num = $total_count - ($page - 1) * $list_page_rows - $notice_count;
$list[$i]['num'] = $list_num - $k;
$i++;
$k++;
$k = 0;
foreach ($rows_to_process as $row)
{
$list[$i] = get_list($row, $board, $board_skin_url, G5_IS_MOBILE ? $board['bo_mobile_subject_len'] : $board['bo_subject_len']);
if (strstr($sfl, 'subject')) {
$list[$i]['subject'] = search_font($stx, $list[$i]['subject']);
}
$list[$i]['is_notice'] = false;
$list[$i]['list_content'] = $list[$i]['wr_content'];
// 비밀글인 경우 리스트에서 내용이 출력되지 않게 글 내용을 지웁니다.
if (strstr($list[$i]['wr_option'], "secret")) {
$list[$i]['wr_content'] = '';
}
$list_num = $total_count - ($page - 1) * $list_page_rows - $notice_count;
$list[$i]['num'] = $list_num - $k;
$i++;
$k++;
}
g5_latest_cache_data($board['bo_table'], $list);
+27 -4
View File
@@ -54,7 +54,7 @@ if ($mb['mb_leave_date'] && $mb['mb_leave_date'] <= date("Ymd", G5_SERVER_TIME))
// 메일인증 설정이 되어 있다면
if ( is_use_email_certify() && !preg_match("/[1-9]/", $mb['mb_email_certify'])) {
$ckey = md5($mb['mb_ip'].$mb['mb_datetime']);
$ckey = function_exists('get_email_cert_key') ? get_email_cert_key($mb_id, $mb['mb_datetime']) : md5($mb['mb_ip'].$mb['mb_datetime']);
confirm("{$mb['mb_email']} 메일로 메일인증을 받으셔야 로그인 가능합니다. 다른 메일주소로 변경하여 인증하시려면 취소를 클릭하시기 바랍니다.", G5_URL, G5_BBS_URL.'/register_email.php?mb_id='.$mb_id.'&ckey='.$ckey);
}
@@ -90,10 +90,33 @@ if($config['cf_use_point']) {
if (isset($auto_login) && $auto_login) {
// 3.27
// 자동로그인 ---------------------------
// 쿠키 한달간 저장
$key = md5($_SERVER['SERVER_ADDR'] . $_SERVER['SERVER_SOFTWARE'] . $_SERVER['HTTP_USER_AGENT'] . $mb['mb_password']);
// 예측 불가능한 랜덤 토큰을 생성하여 g5_member_auto_login 테이블에 저장.
// 다중 디바이스 지원: 디바이스마다 별도의 토큰 행이 생성되며 서로 독립적으로 동작.
$auto_token = get_random_token_string(32); // 64자 hex - 쿠키에는 원본
$auto_token_hash = hash('sha256', $auto_token); // 64자 hex - DB에는 해시
$auto_ua = isset($_SERVER['HTTP_USER_AGENT']) ? substr($_SERVER['HTTP_USER_AGENT'], 0, 255) : '';
$auto_ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
$auto_now = G5_TIME_YMDHIS;
$auto_expire = date('Y-m-d H:i:s', G5_SERVER_TIME + 86400 * 31);
// 만료된 토큰 정리 (해당 회원 한정)
sql_query(" delete from {$g5['member_auto_login_table']}
where mb_id = '{$mb['mb_id']}'
and al_expire < '{$auto_now}' ");
// 새 토큰 INSERT (해시값만 저장)
sql_query(" insert into {$g5['member_auto_login_table']}
set mb_id = '{$mb['mb_id']}',
al_token = '{$auto_token_hash}',
al_user_agent = '".addslashes($auto_ua)."',
al_ip = '".addslashes($auto_ip)."',
al_created = '{$auto_now}',
al_last_used = '{$auto_now}',
al_expire = '{$auto_expire}' ");
set_cookie('ck_mb_id', $mb['mb_id'], 86400 * 31);
set_cookie('ck_auto', $key, 86400 * 31);
set_cookie('ck_auto', $auto_token, 86400 * 31); // 쿠키에는 원본 토큰
// 자동로그인 end ---------------------------
} else {
set_cookie('ck_mb_id', '', 0);
+12
View File
@@ -11,6 +11,18 @@ session_unset(); // 모든 세션변수를 언레지스터 시켜줌
session_destroy(); // 세션해제함
// 자동로그인 해제 --------------------------------
// DB에 저장된 해당 디바이스의 자동 로그인 토큰만 무효화
// (다른 디바이스의 자동 로그인은 유지)
// DB에는 토큰의 SHA256 해시가 저장되어 있으므로 비교 시에도 해시값 사용
$logout_token = get_cookie('ck_auto');
$logout_mb_id = get_cookie('ck_mb_id');
if (isset($g5['member_auto_login_table']) && $logout_token && $logout_mb_id && preg_match('/^[a-f0-9]{64}$/', $logout_token)) {
$logout_mb_id = substr(preg_replace("/[^a-zA-Z0-9_]*/", "", $logout_mb_id), 0, 20);
$logout_token_hash = hash('sha256', $logout_token);
sql_query(" delete from {$g5['member_auto_login_table']}
where mb_id = '{$logout_mb_id}'
and al_token = '{$logout_token_hash}' ");
}
set_cookie('ck_mb_id', '', 0);
set_cookie('ck_auto', '', 0);
// 자동로그인 해제 end --------------------------------
+13 -2
View File
@@ -3,13 +3,19 @@ define('G5_CERT_IN_PROG', true);
include_once('./_common.php');
global $g5;
// 로그인 검증 (본인인증 갱신은 로그인 필수)
if (!$is_member) {
alert('로그인 후 이용해 주십시오.', G5_BBS_URL.'/login.php');
}
if (!($w == '' || $w == 'u')) {
alert('w 값이 제대로 넘어오지 않았습니다.');
}
$url = urldecode($url);
if($w == '') {
$mb_id = isset($_POST['mb_id']) ? trim($_POST['mb_id']) : '';
// 본인 계정만 수정 가능 (POST mb_id 무시, 세션 회원 ID 사용)
$mb_id = $member['mb_id'];
$mb_name = isset($_POST['mb_name']) ? trim($_POST['mb_name']) : '';
$mb_hp = isset($_POST['mb_hp']) ? trim($_POST['mb_hp']) : '';
} else
@@ -81,4 +87,9 @@ run_event('cert_refresh_update_after', $mb_id);
//===============================================================
(empty($url))? goto_url(G5_URL) : goto_url($url);
if ($url) {
check_url_host($url, '', G5_URL, true);
goto_url($url);
} else {
goto_url(G5_URL);
}
+2 -2
View File
@@ -13,8 +13,8 @@ if (!$member['mb_open'] && $is_admin != 'super' && $member['mb_id'] != $mb_id) {
}
$content = "";
$me_recv_mb_id = isset($_REQUEST['me_recv_mb_id']) ? clean_xss_tags($_REQUEST['me_recv_mb_id'], 1, 1) : '';
$me_id = isset($_REQUEST['me_id']) ? clean_xss_tags($_REQUEST['me_id'], 1, 1) : '';
$me_recv_mb_id = isset($_REQUEST['me_recv_mb_id']) ? addslashes(clean_xss_tags(stripslashes($_REQUEST['me_recv_mb_id']), 1, 1)) : '';
$me_id = isset($_REQUEST['me_id']) ? addslashes(clean_xss_tags(stripslashes($_REQUEST['me_id']), 1, 1)) : '';
// 탈퇴한 회원에게 쪽지 보낼 수 없음
if ($me_recv_mb_id)
+6 -2
View File
@@ -2,6 +2,8 @@
include_once('./_common.php');
include_once(G5_CAPTCHA_PATH.'/captcha.lib.php');
if (function_exists('check_request_origin')) check_request_origin(G5_BBS_URL);
if ($is_guest)
alert('회원만 이용하실 수 있습니다.');
@@ -18,7 +20,8 @@ $me_memo = isset($_POST['me_memo']) ? preg_replace("#[\\\]+$#", "", substr(trim(
run_event('memo_form_update_before', $recv_list);
for ($i=0; $i<count($recv_list); $i++) {
$recv_list_cnt = count($recv_list);
for ($i=0; $i<$recv_list_cnt; $i++) {
$recv_list_id = substr(preg_replace("/[^a-zA-Z0-9_]*/", "", $recv_list[$i]), 0, 20);
@@ -63,7 +66,8 @@ if (!$is_admin) {
}
}
for ($i=0; $i<count($member_list['id']); $i++) {
$member_list_cnt = count($member_list['id']);
for ($i=0; $i<$member_list_cnt; $i++) {
$tmp_row = sql_fetch(" select max(me_id) as max_me_id from {$g5['memo_table']} ");
$me_id = $tmp_row['max_me_id'] + 1;
+24 -5
View File
@@ -41,6 +41,21 @@ while ($row = sql_fetch_array($result))
// 존재하지 않다면
if( !$move_board['bo_table'] ) continue;
// 대상 게시판에 대한 권한 재검증 (KVE-2026-0795)
// 원본 게시판 기준의 $is_admin 만으로는 타 게시판 이동/복사가 허용되지 않도록 함.
if ($is_admin !== 'super') {
$is_target_admin = false;
if ($is_admin === 'board' && isset($move_board['bo_admin']) && $move_board['bo_admin'] !== '' && $move_board['bo_admin'] === $member['mb_id']) {
$is_target_admin = true;
} else if ($is_admin === 'group' && isset($move_board['gr_id']) && $move_board['gr_id'] !== '') {
$move_group = sql_fetch(" select gr_admin from {$g5['group_table']} where gr_id = '".sql_real_escape_string($move_board['gr_id'])."' ");
if (!empty($move_group['gr_admin']) && $move_group['gr_admin'] === $member['mb_id']) {
$is_target_admin = true;
}
}
if (!$is_target_admin) continue;
}
$move_write_table = $g5['write_prefix'] . $move_bo_table;
$src_dir = G5_DATA_PATH.'/file/'.$bo_table; // 원본 디렉토리
@@ -61,7 +76,7 @@ while ($row = sql_fetch_array($result))
$nick = cut_str($member['mb_nick'], $config['cf_cut_name']);
if (!$row2['wr_is_comment'] && $config['cf_use_copy_log']) {
if(strstr($row2['wr_option'], 'html')) {
if(strpos($row2['wr_option'], 'html') !== false) {
$log_tag1 = '<div class="content_'.$sw.'">';
$log_tag2 = '</div>';
} else {
@@ -233,10 +248,12 @@ delete_cache_latest($bo_table);
if ($sw == 'move')
{
for ($i=0; $i<count($save); $i++)
$save_cnt = count($save);
for ($i=0; $i<$save_cnt; $i++)
{
if( isset($save[$i]['bf_file']) && $save[$i]['bf_file'] ){
for ($k=0; $k<count($save[$i]['bf_file']); $k++) {
$bf_file_cnt = count($save[$i]['bf_file']);
for ($k=0; $k<$bf_file_cnt; $k++) {
$del_file = run_replace('delete_file_path', clean_relative_paths($save[$i]['bf_file'][$k]), $save[$i]);
if ( is_file($del_file) && file_exists($del_file) ){
@@ -248,7 +265,8 @@ if ($sw == 'move')
}
}
for ($k=0; $k<count($save[$i]['wr_contents']); $k++){
$wr_contents_cnt = count($save[$i]['wr_contents']);
for ($k=0; $k<$wr_contents_cnt; $k++){
delete_editor_thumbnail($save[$i]['wr_contents'][$k]);
}
@@ -262,7 +280,8 @@ if ($sw == 'move')
$sql = " select bo_notice from {$g5['board_table']} where bo_table = '{$bo_table}' ";
$row = sql_fetch($sql);
$arr_notice = explode(',', $row['bo_notice']);
for ($i=0; $i<count($arr_notice); $i++) {
$arr_notice_cnt = count($arr_notice);
for ($i=0; $i<$arr_notice_cnt; $i++) {
$move_id = (int)$arr_notice[$i];
// 게시판에 wr_id 가 있다면 이동한게 아니므로 bo_notice 에 다시 넣음
$row2 = sql_fetch(" select count(*) as cnt from $write_table where wr_id = '{$move_id}' ");
+2 -1
View File
@@ -97,7 +97,8 @@ for($i=0;$i<$count_chk_bn_id;$i++)
$notice_array = explode(",", trim($board['bo_notice']));
$bo_notice = "";
$lf = '';
for ($k=0; $k<count($notice_array); $k++) {
$notice_array_cnt = count($notice_array);
for ($k=0; $k<$notice_array_cnt; $k++) {
if ((int)$write['wr_id'] != (int)$notice_array[$k])
$bo_notice .= $lf.$notice_array[$k];
+18 -11
View File
@@ -16,25 +16,32 @@ $email = get_email_address(trim($_POST['mb_email']));
if (!$email)
alert_close('메일주소 오류입니다.');
// OWASP 권장: 이메일 존재 여부와 무관하게 동일한 응답 메시지 사용
// (이메일 열거 공격 방지)
$generic_message = $email.' 메일로 회원아이디와 비밀번호를 인증할 수 있는 메일이 발송 되었습니다.\\n\\n메일을 확인하여 주십시오.';
$sql = " select count(*) as cnt from {$g5['member_table']} where mb_email = '$email' ";
$row = sql_fetch($sql);
if ($row['cnt'] > 1)
alert('동일한 메일주소가 2개 이상 존재합니다.\\n\\n관리자에게 문의하여 주십시오.');
if ($row['cnt'] > 1) {
// 시스템 데이터 무결성 이슈 - 운영자 로그에만 기록하고 사용자에겐 일반 메시지
@error_log("[g5 password_lost2] Duplicate email detected: $email (count={$row['cnt']})");
alert_close($generic_message);
}
$sql = " select mb_no, mb_id, mb_name, mb_nick, mb_email, mb_datetime, mb_leave_date from {$g5['member_table']} where mb_email = '$email' ";
$mb = sql_fetch($sql);
if (empty($mb['mb_id']) || $mb['mb_leave_date']) {
alert('존재하지 않는 회원입니다.');
} elseif (is_admin($mb['mb_id'])) {
alert('관리자 아이디는 접근 불가합니다.');
// 회원이 없거나 탈퇴했거나 관리자이면 메일 발송 없이 동일한 메시지로 응답
if (empty($mb['mb_id']) || $mb['mb_leave_date'] || is_admin($mb['mb_id'])) {
alert_close($generic_message);
}
// 임시비밀번호 발급
$change_password = rand(100000, 999999);
// 임시비밀번호 발급 (CSPRNG 사용)
$change_password = get_random_token_string(5); // 10자리 hex (0-9, a-f)
$mb_lost_certify = get_encrypt_string($change_password);
// 어떠한 회원정보도 포함되지 않은 일회용 난수를 생성하여 인증에 사용
$mb_nonce = md5(pack('V*', rand(), rand(), rand(), rand()));
// 어떠한 회원정보도 포함되지 않은 일회용 난수를 생성하여 인증에 사용 (CSPRNG 사용)
$mb_nonce = get_random_token_string(16);
// 임시비밀번호와 난수를 mb_lost_certify 필드에 저장
$sql = " update {$g5['member_table']} set mb_lost_certify = '$mb_nonce $mb_lost_certify' where mb_id = '{$mb['mb_id']}' ";
@@ -74,4 +81,4 @@ mailer($config['cf_admin_email_name'], $config['cf_admin_email'], $mb['mb_email'
run_event('password_lost2_after', $mb, $mb_nonce, $mb_lost_certify);
alert_close($email.' 메일로 회원아이디와 비밀번호를 인증할 수 있는 메일이 발송 되었습니다.\\n\\n메일을 확인하여 주십시오.');
alert_close($generic_message);
+14 -2
View File
@@ -2,16 +2,28 @@
include_once('./_common.php');
include_once(G5_LIB_PATH.'/mailer.lib.php');
if (function_exists('check_request_origin')) check_request_origin(G5_BBS_URL);
if ($w == '')
{
$po_id = isset($_POST['po_id']) ? (int) $_POST['po_id'] : '';
$pc_name = isset($_POST['pc_name']) ? clean_xss_tags($_POST['pc_name'], 1, 1) : '';
$pc_idea = isset($_POST['pc_idea']) ? clean_xss_tags($_POST['pc_idea'], 1, 1) : '';
$po = sql_fetch(" select * from {$g5['poll_table']} where po_id = '{$po_id}' ");
if (!$po['po_id'])
alert('po_id 값이 제대로 넘어오지 않았습니다.');
// 기타의견 사용 여부 검사
if (!$po['po_etc'])
alert('기타의견이 비활성화되어 있습니다.');
// 접근 권한 검사
if ($member['mb_level'] < $po['po_level'])
alert('권한이 없습니다.');
$pc_name = isset($_POST['pc_name']) ? addslashes(clean_xss_tags(stripslashes($_POST['pc_name']), 1, 1)) : '';
$pc_name = preg_replace("#[\\\]+$#", "", $pc_name);
$pc_idea = isset($_POST['pc_idea']) ? addslashes(clean_xss_tags(stripslashes($_POST['pc_idea']), 1, 1)) : '';
$tmp_row = sql_fetch(" select max(pc_id) as max_pc_id from {$g5['poll_etc_table']} ");
$pc_id = $tmp_row['max_pc_id'] + 1;
+1
View File
@@ -3,6 +3,7 @@ include_once('./_common.php');
include_once(G5_CAPTCHA_PATH.'/captcha.lib.php');
$po_id = isset($_REQUEST['po_id']) ? (int) $_REQUEST['po_id'] : '';
$skin_dir = isset($skin_dir) ? clean_relative_paths(strip_tags($skin_dir)) : '';
$po = sql_fetch(" select * from {$g5['poll_table']} where po_id = '{$po_id}' ");
if (!$po['po_id'])
+21 -37
View File
@@ -1,6 +1,8 @@
<?php
include_once('./_common.php');
if (function_exists('check_request_origin')) check_request_origin(G5_BBS_URL);
$po_id = isset($_POST['po_id']) ? preg_replace('/[^0-9]/', '', $_POST['po_id']) : 0;
$po = sql_fetch(" select * from {$g5['poll_table']} where po_id = '$po_id' ");
@@ -14,50 +16,32 @@ $gb_poll = isset($_POST['gb_poll']) ? preg_replace('/[^0-9]/', '', $_POST['gb_po
if(!$gb_poll)
alert_close('항목을 선택하세요.');
$search_mb_id = false;
$search_ip = false;
if($is_member) {
// 투표했던 회원아이디들 중에서 찾아본다
$ids = explode(',', trim($po['mb_ids']));
for ($i=0; $i<count($ids); $i++) {
if ($member['mb_id'] == trim($ids[$i])) {
$search_mb_id = true;
break;
}
}
} else {
// 투표했던 ip들 중에서 찾아본다
$ips = explode(',', trim($po['po_ips']));
for ($i=0; $i<count($ips); $i++) {
if ($_SERVER['REMOTE_ADDR'] == trim($ips[$i])) {
$search_ip = true;
break;
}
}
}
$post_skin_dir = isset($_POST['skin_dir']) ? clean_xss_tags($_POST['skin_dir'], 1, 1) : '';
$result_url = G5_BBS_URL."/poll_result.php?po_id=$po_id&skin_dir={$post_skin_dir}";
// 없다면 선택한 투표항목을 1증가 시키고 ip, id를 저장
if (!($search_ip || $search_mb_id)) {
$po_ips = $po['po_ips'] . $_SERVER['REMOTE_ADDR'].",";
$mb_ids = $po['mb_ids'];
if ($is_member) { // 회원일 때는 id만 추가
$mb_ids .= $member['mb_id'].',';
$sql = " update {$g5['poll_table']} set po_cnt{$gb_poll} = po_cnt{$gb_poll} + 1, mb_ids = '$mb_ids' where po_id = '$po_id' ";
} else {
$sql = " update {$g5['poll_table']} set po_cnt{$gb_poll} = po_cnt{$gb_poll} + 1, po_ips = '$po_ips' where po_id = '$po_id' ";
}
sql_query($sql);
// 레이스 컨디션 방지: MyISAM은 트랜잭션을 지원하지 않으므로,
// WHERE 조건에 중복 검증(FIND_IN_SET)을 포함한 원자적 UPDATE로 처리한다.
// 기존 투표자 목록에 없을 때만 갱신되며, 동시 요청이 와도 DB 서버 레벨에서 직렬화된다.
if ($is_member) {
$sql = " update {$g5['poll_table']}
set po_cnt{$gb_poll} = po_cnt{$gb_poll} + 1,
mb_ids = concat(ifnull(mb_ids, ''), '".$member['mb_id'].",')
where po_id = '$po_id'
and find_in_set('".$member['mb_id']."', ifnull(mb_ids, '')) = 0 ";
} else {
$sql = " update {$g5['poll_table']}
set po_cnt{$gb_poll} = po_cnt{$gb_poll} + 1,
po_ips = concat(ifnull(po_ips, ''), '".$_SERVER['REMOTE_ADDR'].",')
where po_id = '$po_id'
and find_in_set('".$_SERVER['REMOTE_ADDR']."', ifnull(po_ips, '')) = 0 ";
}
sql_query($sql);
if (get_sql_affected_rows() <= 0) {
alert(addcslashes($po['po_subject'], '"\\/').'에 이미 참여하셨습니다.', $result_url);
}
if (!$search_mb_id)
insert_point($member['mb_id'], $po['po_point'], $po['po_id'] . '. ' . cut_str($po['po_subject'],20) . ' 투표 참여 ', '@poll', $po['po_id'], '투표');
insert_point($member['mb_id'], $po['po_point'], $po['po_id'] . '. ' . cut_str($po['po_subject'],20) . ' 투표 참여 ', '@poll', $po['po_id'], '투표');
//goto_url($g5['bbs_url'].'/poll_result.php?po_id='.$po_id.'&amp;skin_dir='.$skin_dir);
goto_url($result_url);
+2 -1
View File
@@ -29,7 +29,8 @@ if ($qaconfig['qa_category']) {
$category_option .= '>전체</a></li>';
$categories = explode('|', $qaconfig['qa_category']); // 구분자가 | 로 되어 있음
for ($i=0; $i<count($categories); $i++) {
$categories_cnt = count($categories);
for ($i=0; $i<$categories_cnt; $i++) {
$category = trim($categories[$i]);
if ($category=='') continue;
$category_msg = '';
+2 -1
View File
@@ -54,7 +54,8 @@ if(is_file($skin_file)) {
$category_option = '';
if(trim($qaconfig['qa_category'])) {
$category = explode('|', $qaconfig['qa_category']);
for($i=0; $i<count($category); $i++) {
$category_cnt = count($category);
for($i=0; $i<$category_cnt; $i++) {
$category_option .= option_selected($category[$i], $write['qa_category']);
}
} else {
+1 -1
View File
@@ -219,7 +219,7 @@ for ($i=1; $i<=$upload_count; $i++) {
$upload[$i]['filesize'] = $filesize;
// 아래의 문자열이 들어간 파일은 -x 를 붙여서 웹경로를 알더라도 실행을 하지 못하도록 함
$filename = preg_replace("/\.(php|pht|phtm|htm|cgi|pl|exe|jsp|asp|inc|phar)/i", "$0-x", $filename);
$filename = preg_replace("/\.(php|pht|phtm|htm|shtml|shtm|cgi|pl|exe|jsp|asp|inc|phar|svg|svgz)/i", "$0-x", $filename);
shuffle($chars_array);
$shuffle = implode('', $chars_array);
+4 -3
View File
@@ -5,7 +5,7 @@ include_once(G5_CAPTCHA_PATH.'/captcha.lib.php');
$g5['title'] = '메일인증 메일주소 변경';
include_once('./_head.php');
$mb_id = isset($_GET['mb_id']) ? substr(clean_xss_tags($_GET['mb_id']), 0, 20) : '';
$mb_id = isset($_GET['mb_id']) ? substr(addslashes(clean_xss_tags(stripslashes($_GET['mb_id']), 1, 1)), 0, 20) : '';
$sql = " select mb_email, mb_datetime, mb_ip, mb_email_certify, mb_id from {$g5['member_table']} where mb_id = '{$mb_id}' ";
$mb = sql_fetch($sql);
@@ -18,9 +18,9 @@ if (substr($mb['mb_email_certify'],0,1)!=0) {
}
$ckey = isset($_GET['ckey']) ? trim($_GET['ckey']) : '';
$key = md5($mb['mb_ip'].$mb['mb_datetime']);
$key = get_email_cert_key($mb_id, $mb['mb_datetime']);
if(!$ckey || $ckey != $key)
if(!$ckey || $ckey !== $key)
alert('올바른 방법으로 이용해 주십시오.', G5_URL);
?>
@@ -28,6 +28,7 @@ if(!$ckey || $ckey != $key)
<form method="post" name="fregister_email" action="<?php echo G5_HTTPS_BBS_URL.'/register_email_update.php'; ?>" onsubmit="return fregister_email_submit(this);">
<input type="hidden" name="mb_id" value="<?php echo $mb_id; ?>">
<input type="hidden" name="ckey" value="<?php echo $key; ?>">
<div class="tbl_frm01 tbl_frm rg_em">
<table>
+22 -7
View File
@@ -3,13 +3,28 @@ include_once('./_common.php');
include_once(G5_CAPTCHA_PATH.'/captcha.lib.php');
include_once(G5_LIB_PATH.'/mailer.lib.php');
$mb_id = isset($_POST['mb_id']) ? substr(clean_xss_tags($_POST['mb_id']), 0, 20) : '';
// 로그인 검증
if (!$is_member) {
alert('로그인 후 이용해 주십시오.', G5_BBS_URL.'/login.php');
}
// 본인 계정만 수정 가능 (POST mb_id 무시, 세션 회원 ID 사용)
$mb_id = $member['mb_id'];
$mb_email = isset($_POST['mb_email']) ? get_email_address(trim($_POST['mb_email'])) : '';
if(!$mb_id || !$mb_email)
alert('올바른 방법으로 이용해 주십시오.', G5_URL);
$sql = " select mb_name from {$g5['member_table']} where mb_id = '{$mb_id}' and substring(mb_email_certify, 1, 1) = '0' ";
// ckey 검증 (register_email.php 폼에서 전달받은 인증키)
$ckey = isset($_POST['ckey']) ? trim($_POST['ckey']) : '';
$key = get_email_cert_key($mb_id, $member['mb_datetime']);
if (!$ckey || $ckey !== $key) {
alert('올바른 방법으로 이용해 주십시오.', G5_URL);
}
$esc_mb_id = sql_real_escape_string($mb_id);
$sql = " select mb_name from {$g5['member_table']} where mb_id = '{$esc_mb_id}' and substring(mb_email_certify, 1, 1) = '0' ";
$mb = sql_fetch($sql);
if (!$mb) {
alert("이미 메일인증 하신 회원입니다.", G5_URL);
@@ -19,7 +34,7 @@ if (!chk_captcha()) {
alert('자동등록방지 숫자가 틀렸습니다.');
}
$sql = " select count(*) as cnt from {$g5['member_table']} where mb_id <> '{$mb_id}' and mb_email = '$mb_email' ";
$sql = " select count(*) as cnt from {$g5['member_table']} where mb_id <> '{$esc_mb_id}' and mb_email = '$mb_email' ";
$row = sql_fetch($sql);
if ($row['cnt']) {
alert("{$mb_email} 메일은 이미 존재하는 메일주소 입니다.\\n\\n다른 메일주소를 입력해 주십시오.");
@@ -30,10 +45,10 @@ $subject = '['.$config['cf_title'].'] 인증확인 메일입니다.';
$mb_name = $mb['mb_name'];
// 어떠한 회원정보도 포함되지 않은 일회용 난수를 생성하여 인증에 사용
$mb_md5 = md5(pack('V*', rand(), rand(), rand(), rand()));
// 어떠한 회원정보도 포함되지 않은 일회용 난수를 생성하여 인증에 사용 (CSPRNG 사용)
$mb_md5 = get_random_token_string(16);
sql_query(" update {$g5['member_table']} set mb_email_certify2 = '$mb_md5' where mb_id = '$mb_id' ");
sql_query(" update {$g5['member_table']} set mb_email_certify2 = '$mb_md5' where mb_id = '{$esc_mb_id}' ");
$certify_href = G5_BBS_URL.'/email_certify.php?mb_id='.$mb_id.'&amp;mb_md5='.$mb_md5;
@@ -44,7 +59,7 @@ ob_end_clean();
mailer($config['cf_admin_email_name'], $config['cf_admin_email'], $mb_email, $subject, $content, 1);
$sql = " update {$g5['member_table']} set mb_email = '$mb_email' where mb_id = '$mb_id' ";
$sql = " update {$g5['member_table']} set mb_email = '$mb_email' where mb_id = '{$esc_mb_id}' ";
sql_query($sql);
alert("인증메일을 {$mb_email} 메일로 다시 보내 드렸습니다.\\n\\n잠시후 {$mb_email} 메일을 확인하여 주십시오.", G5_URL);
+1 -1
View File
@@ -6,7 +6,7 @@ include_once(G5_LIB_PATH.'/register.lib.php');
run_event('register_form_before');
// 불법접근을 막도록 토큰생성
$token = md5(uniqid(rand(), true));
$token = get_random_token_string(16);
set_session("ss_token", $token);
set_session("ss_cert_no", "");
set_session("ss_cert_hash", "");
+32 -18
View File
@@ -63,20 +63,34 @@ $mb_7 = isset($_POST['mb_7']) ? trim($_POST['mb_7'])
$mb_8 = isset($_POST['mb_8']) ? trim($_POST['mb_8']) : "";
$mb_9 = isset($_POST['mb_9']) ? trim($_POST['mb_9']) : "";
$mb_10 = isset($_POST['mb_10']) ? trim($_POST['mb_10']) : "";
$mb_name = clean_xss_tags($mb_name, 1, 1);
$mb_name = addslashes(clean_xss_tags(stripslashes($mb_name), 1, 1));
$mb_email = get_email_address($mb_email);
$mb_homepage = clean_xss_tags($mb_homepage, 1, 1);
$mb_tel = clean_xss_tags($mb_tel, 1, 1);
$mb_homepage = addslashes(clean_xss_tags(stripslashes($mb_homepage), 1, 1));
$mb_tel = addslashes(clean_xss_tags(stripslashes($mb_tel), 1, 1));
$mb_zip1 = preg_replace('/[^0-9]/', '', $mb_zip1);
$mb_zip2 = preg_replace('/[^0-9]/', '', $mb_zip2);
$mb_addr1 = clean_xss_tags($mb_addr1, 1, 1);
$mb_addr2 = clean_xss_tags($mb_addr2, 1, 1);
$mb_addr3 = clean_xss_tags($mb_addr3, 1, 1);
$mb_addr_jibeon = preg_match("/^(N|R)$/", $mb_addr_jibeon) ? $mb_addr_jibeon : '';
$mb_addr1 = addslashes(clean_xss_tags(stripslashes($mb_addr1), 1, 1));
$mb_addr2 = addslashes(clean_xss_tags(stripslashes($mb_addr2), 1, 1));
$mb_addr3 = addslashes(clean_xss_tags(stripslashes($mb_addr3), 1, 1));
$mb_addr_jibeon = preg_match("/^(N|R|J)$/", $mb_addr_jibeon) ? $mb_addr_jibeon : '';
$mb_marketing_agree = isset($_POST['mb_marketing_agree']) ? trim($_POST['mb_marketing_agree']) : "0";
$mb_thirdparty_agree = isset($_POST['mb_thirdparty_agree']) ? trim($_POST['mb_thirdparty_agree']) : "0";
// _default 변수 명시적 초기화 (폼에 해당 섹션이 없으면 null)
$mb_marketing_agree_default = isset($_POST['mb_marketing_agree_default']) ? trim($_POST['mb_marketing_agree_default']) : null;
$mb_mailling_default = isset($_POST['mb_mailling_default']) ? trim($_POST['mb_mailling_default']) : null;
$mb_sms_default = isset($_POST['mb_sms_default']) ? trim($_POST['mb_sms_default']) : null;
$mb_thirdparty_agree_default = isset($_POST['mb_thirdparty_agree_default']) ? trim($_POST['mb_thirdparty_agree_default']) : null;
// 폼에 수신설정 섹션이 없는 경우 기존 DB 값 유지 (회원정보 수정 시)
if ($w == 'u') {
if ($mb_marketing_agree_default === null) $mb_marketing_agree = $member['mb_marketing_agree'];
if ($mb_mailling_default === null) $mb_mailling = $member['mb_mailling'];
if ($mb_sms_default === null) $mb_sms = $member['mb_sms'];
if ($mb_thirdparty_agree_default === null) $mb_thirdparty_agree = $member['mb_thirdparty_agree'];
}
run_event('register_form_update_before', $mb_id, $w);
if ($w == '' || $w == 'u') {
@@ -261,7 +275,7 @@ if ($w == '') {
if (!$config['cf_use_email_certify'])
$sql .= " , mb_email_certify = '".G5_TIME_YMDHIS."' ";
$agree_items = [];
$agree_items = array();
// 마케팅 목적의 개인정보 수집 및 이용
if ($mb_marketing_agree == 1) {
$sql .= " , mb_marketing_date = '".G5_TIME_YMDHIS."' ";
@@ -305,9 +319,9 @@ if ($w == '') {
if ($config['cf_email_mb_member']) {
$subject = '['.$config['cf_title'].'] 회원가입을 축하드립니다.';
// 어떠한 회원정보도 포함되지 않은 일회용 난수를 생성하여 인증에 사용
// 어떠한 회원정보도 포함되지 않은 일회용 난수를 생성하여 인증에 사용 (CSPRNG 사용)
if ($config['cf_use_email_certify']) {
$mb_md5 = md5(pack('V*', rand(), rand(), rand(), rand()));
$mb_md5 = get_random_token_string(16);
sql_query(" update {$g5['member_table']} set mb_email_certify2 = '$mb_md5' where mb_id = '$mb_id' ");
$certify_href = G5_BBS_URL.'/email_certify.php?mb_id='.$mb_id.'&amp;mb_md5='.$mb_md5;
}
@@ -382,32 +396,32 @@ if ($w == '') {
if ($old_email != $mb_email && $config['cf_use_email_certify'])
$sql_email_certify = " , mb_email_certify = '' ";
$agree_items = [];
$agree_items = array();
// 마케팅 목적의 개인정보 수집 및 이용
$sql_marketing_date = "";
if ($mb_marketing_agree_default !== $mb_marketing_agree) {
if ($mb_marketing_agree_default !== null && $mb_marketing_agree_default !== $mb_marketing_agree) {
$sql_marketing_date .= " , mb_marketing_date = '".G5_TIME_YMDHIS."' ";
$agree_items[] = "마케팅 목적의 개인정보 수집 및 이용(" . ($mb_marketing_agree == 1 ? "동의" : "철회") . ")";
}
// 광고성 이메일 수신
$sql_mailling_date = "";
if ($mb_mailling_default !== $mb_mailling) {
if ($mb_mailling_default !== null && $mb_mailling_default !== $mb_mailling) {
$sql_mailling_date .= " , mb_mailling_date = '".G5_TIME_YMDHIS."' ";
$agree_items[] = "광고성 이메일 수신(" . ($mb_mailling == 1 ? "동의" : "철회") . ")";
}
// 광고성 SMS/카카오톡 수신
$sql_sms_date = "";
if ($mb_sms_default !== $mb_sms) {
if ($mb_sms_default !== null && $mb_sms_default !== $mb_sms) {
$sql_sms_date .= " , mb_sms_date = '".G5_TIME_YMDHIS."' ";
$agree_items[] = "광고성 SMS/카카오톡 수신(" . ($mb_sms == 1 ? "동의" : "철회") . ")";
}
// 개인정보 제3자 제공
$sql_thirdparty_date = "";
if ($mb_thirdparty_agree_default !== $mb_thirdparty_agree) {
if ($mb_thirdparty_agree_default !== null && $mb_thirdparty_agree_default !== $mb_thirdparty_agree) {
$sql_thirdparty_date .= " , mb_thirdparty_date = '".G5_TIME_YMDHIS."' ";
$agree_items[] = "개인정보 제3자 제공(" . ($mb_thirdparty_agree == 1 ? "동의" : "철회") . ")";
}
@@ -590,8 +604,8 @@ if( $config['cf_member_img_size'] && $config['cf_member_img_width'] && $config['
if ($config['cf_use_email_certify'] && $old_email != $mb_email) {
$subject = '['.$config['cf_title'].'] 인증확인 메일입니다.';
// 어떠한 회원정보도 포함되지 않은 일회용 난수를 생성하여 인증에 사용
$mb_md5 = md5(pack('V*', rand(), rand(), rand(), rand()));
// 어떠한 회원정보도 포함되지 않은 일회용 난수를 생성하여 인증에 사용 (CSPRNG 사용)
$mb_md5 = get_random_token_string(16);
sql_query(" update {$g5['member_table']} set mb_email_certify2 = '$mb_md5' where mb_id = '$mb_id' ");
@@ -699,4 +713,4 @@ if ($w == '') {
</body>
</html>';
}
}
}
+22 -10
View File
@@ -3,6 +3,8 @@ include_once('./_common.php');
// 특수문자 변환
function specialchars_replace($str, $len=0) {
$str = (string)$str;
if ($len) {
$str = substr($str, 0, $len);
}
@@ -18,19 +20,29 @@ function specialchars_replace($str, $len=0) {
return $str;
}
if (!isset($bo_table) || !$bo_table) {
echo '존재하지 않는 게시판입니다.';
exit;
}
$sql = " select gr_id, bo_subject, bo_page_rows, bo_read_level, bo_use_rss_view from {$g5['board_table']} where bo_table = '$bo_table' ";
$row = sql_fetch($sql);
$subj2 = specialchars_replace($row['bo_subject'], 255);
$lines = $row['bo_page_rows'];
$rss_board = sql_fetch($sql);
if (!isset($rss_board['gr_id']) || !$rss_board['gr_id']) {
echo '존재하지 않는 게시판입니다.';
exit;
}
$subj2 = specialchars_replace($rss_board['bo_subject'], 255);
$lines = (int)$rss_board['bo_page_rows'];
// 비회원 읽기가 가능한 게시판만 RSS 지원
if ($row['bo_read_level'] >= 2) {
if ((int)$rss_board['bo_read_level'] >= 2) {
echo '비회원 읽기가 가능한 게시판만 RSS 지원합니다.';
exit;
}
// RSS 사용 체크
if (!$row['bo_use_rss_view']) {
if (!$rss_board['bo_use_rss_view']) {
echo 'RSS 보기가 금지되어 있습니다.';
exit;
}
@@ -39,9 +51,9 @@ header('Content-type: text/xml');
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache');
$sql = " select gr_subject from {$g5['group_table']} where gr_id = '{$row['gr_id']}' ";
$row = sql_fetch($sql);
$subj1 = specialchars_replace($row['gr_subject'], 255);
$sql = " select gr_subject from {$g5['group_table']} where gr_id = '{$rss_board['gr_id']}' ";
$rss_group = sql_fetch($sql);
$subj1 = isset($rss_group['gr_subject']) ? specialchars_replace($rss_group['gr_subject'], 255) : '';
echo '<?xml version="1.0" encoding="utf-8" ?>'."\n";
?>
@@ -60,7 +72,7 @@ $result = sql_query($sql);
for ($i=0; $row=sql_fetch_array($result); $i++) {
$file = '';
if (strstr($row['wr_option'], 'html'))
if (strpos($row['wr_option'], 'html') !== false)
$html = 1;
else
$html = 0;
@@ -88,4 +100,4 @@ $date = substr($date,0,10) . "T" . substr($date,11,8) . "+09:00";
}
echo '</channel>'."\n";
echo '</rss>'."\n";
echo '</rss>'."\n";
+11 -7
View File
@@ -72,7 +72,9 @@ if ($stx) {
$field = explode('||', trim($sfl));
$str = '(';
for ($i=0; $i<count($s); $i++) {
$s_cnt = count($s);
$field_cnt = count($field);
for ($i=0; $i<$s_cnt; $i++) {
if (trim($s[$i]) == '') continue;
$search_str = $s[$i];
@@ -85,7 +87,7 @@ if ($stx) {
$op2 = '';
// 필드의 수만큼 다중 필드 검색 가능 (필드1+필드2...)
for ($k=0; $k<count($field); $k++) {
for ($k=0; $k<$field_cnt; $k++) {
$str .= $op2;
switch ($field[$k]) {
case 'mb_id' :
@@ -119,7 +121,8 @@ if ($stx) {
$time1 = get_microtime();
$total_count = 0;
for ($i=0; $i<count($g5_search['tables']); $i++) {
$tables_cnt = count($g5_search['tables']);
for ($i=0; $i<$tables_cnt; $i++) {
$tmp_write_table = $g5['write_prefix'] . $g5_search['tables'][$i];
$sql = " select wr_id from {$tmp_write_table} where {$sql_search} ";
@@ -148,7 +151,8 @@ if ($stx) {
if ($page < 1) { $page = 1; } // 페이지가 없으면 첫 페이지 (1 페이지)
$from_record = ($page - 1) * $rows; // 시작 열을 구함
for ($i=0; $i<count($search_table); $i++) {
$search_table_cnt = count($search_table);
for ($i=0; $i<$search_table_cnt; $i++) {
if ($from_record < $search_table_count[$i]) {
$table_index = $i;
$from_record = $from_record - ($i > 0 ? $search_table_count[$i-1] : 0);
@@ -183,11 +187,11 @@ if ($stx) {
}
// 비밀글은 검색 불가
if (strstr($row['wr_option'].(isset($row2['wr_option']) ? $row2['wr_option'] : ''), 'secret'))
if (strpos($row['wr_option'].(isset($row2['wr_option']) ? $row2['wr_option'] : ''), 'secret') !== false)
$row['wr_content'] = '[비밀글 입니다.]';
$subject = get_text($row['wr_subject']);
if (strstr($sfl, 'wr_subject'))
if (strpos($sfl, 'wr_subject') !== false)
$subject = search_font($stx, $subject);
if ($read_level[$idx] <= $member['mb_level'])
@@ -199,7 +203,7 @@ if ($stx) {
$content = str_replace('&nbsp;', '', $content);
$content = cut_str($content, 300, "…");
if (strstr($sfl, 'wr_content'))
if (strpos($sfl, 'wr_content') !== false)
$content = search_font($stx, $content);
}
else
+4 -4
View File
@@ -111,17 +111,17 @@ if ($is_member) {
$view = get_view($write, $board, $board_skin_path);
if (strstr($sfl, 'subject'))
if (strpos($sfl, 'subject') !== false)
$view['subject'] = search_font($stx, $view['subject']);
$html = 0;
if (strstr($view['wr_option'], 'html1'))
if (strpos($view['wr_option'], 'html1') !== false)
$html = 1;
else if (strstr($view['wr_option'], 'html2'))
else if (strpos($view['wr_option'], 'html2') !== false)
$html = 2;
$view['content'] = conv_content($view['wr_content'], $html);
if (strstr($sfl, 'content'))
if (strpos($sfl, 'content') !== false)
$view['content'] = search_font($stx, $view['content']);
//$view['rich_content'] = preg_replace("/{이미지\:([0-9]+)[:]?([^}]*)}/ie", "view_image(\$view, '\\1', '\\2')", $view['content']);

Some files were not shown because too many files have changed in this diff Show More