Compare commits

...
47 Commits
Author SHA1 Message Date
섭웨이bandGitHub c91b74d991 Merge pull request #383 from gnuboard/promote/v5.6.36
release: 그누보드 5.6.36 배포
2026-09-01 11:41:35 +09:00
whitedot 7ec4d3a66c chore: 그누보드 배포 버전을 5.6.36으로 변경 2026-09-01 11:40:16 +09:00
whitedot 05fe1b0cdb fix: JS와 CSS 캐시 버전을 파일 수정시간으로 자동 갱신
정적 자산 URL의 캐시 키를 파일 수정시간으로 생성하고 요청 내에서 같은 파일의 조회 결과를 재사용한다.
2026-09-01 11:40:15 +09:00
whitedot 0242e8f1a3 security: SVG 및 SVGZ 파일 업로드 차단
게시판, 1:1문의, 폼메일 및 쇼핑몰 설정의 클라이언트와 서버 검증에서 SVG 계열 파일 업로드를 거부한다.
2026-09-01 11:40:15 +09:00
whitedot 4e8474f231 chore: 제거된 알림톡 기능의 잔여 참조 정리
관리자 회원 내보내기와 결제 공통 파일에 남은 알림톡 관련 코드 및 스타일을 제거한다.
2026-09-01 11:40:15 +09:00
whitedot 71209fc7c9 security: KVE-2026-1899 KVE-2026-1900 KVE-2026-1909 입력 및 권한 검증 강화
상품 정렬값을 허용 목록으로 검증하고 관리자 권한 컨텍스트를 명확히 구분한다.

모바일 KCP의 Windows 명령 인자를 안전하게 조립하고 검증한다.
2026-09-01 11:40:15 +09:00
섭웨이bandGitHub 375a8336e8 Merge pull request #380 from gnuboard/promote/readme-public-pr-test
docs: 프로젝트 안내와 설치·보안·커밋 규칙 문서 추가
2026-08-25 15:30:14 +09:00
whitedot 120d2960f2 docs: 압축파일 설치에 GitHub Releases 다운로드 경로 추가 2026-08-25 15:28:04 +09:00
whitedot 9659cceae6 docs: README에 PHP·DB와 기능별 설치 요구사항 명시 2026-08-25 15:28:04 +09:00
whitedot 7e42eb78e4 docs: 한국어 문서와 커밋 메시지 작성 규칙 추가 2026-08-25 15:28:04 +09:00
whitedot e475219115 docs: expand installation and security guidance 2026-08-25 15:28:04 +09:00
whitedot c70260c8cf docs: add project README 2026-08-25 14:37:07 +09:00
thisgun bb6ed59052 버전 5.6.35 수정 2026-08-25 01:25:04 +00:00
thisgun d4dddaca57 [KVE-2026-1927] 관리자 메뉴 코드 요청값 개입 차단 및 회원 내보내기 저장 경로 보완
관리자 페이지는 자신의 메뉴 코드를 변수에 지정한 뒤 공통 파일을 include
하는데, 공통 파일의 extract 처리로 그 값이 요청값으로 대체될 수 있었다.
extract 이전에 요청 배열에서 해당 키를 제거하여 각 페이지가 지정한 값이
유지되도록 한다. 해당 키를 요청값으로 참조하는 코드는 없으므로 동작에
영향이 없다.

변수 자체를 unset 하는 방식은 페이지가 지정한 값까지 사라져 관리권한을
위임받은 계정이 자신의 메뉴에도 접근하지 못하게 되므로 사용하지 않는다.

회원 내보내기 파일의 저장 폴더와 파일 이름이 생성 시각만으로 구성되어
경로를 추측할 여지가 있어, 임의 문자열을 덧붙인다. 다운로드 주소는 서버가
생성해 전달하므로 기존 흐름에는 영향이 없으며, 지난 폴더 정리 조건도 함께
맞춘다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 7739b95be1fcbe764d888a9f0fba1522cc1ebacb)
2026-08-24 07:56:32 +00:00
thisgun 0080b199ea [KVE-2026-1823] 장바구니 배송비 구분값을 서버에서 결정하도록 수정
장바구니 담기에서 배송비 구분값을 요청값으로 받은 뒤 무료배송 상품과
착불 상품만 서버 값으로 다시 지정하고 있어, 일반 유료배송 상품은 요청값이
그대로 저장되고 배송비 산정 대상에서 빠졌다. 요청값 참조를 제거하고 상품
설정만으로 값을 결정하도록 하여 같은 기능의 AJAX 경로와 동작을 맞춘다.

네이버페이 주문에서도 장바구니에서 읽은 배송비 구분값을 요청 배열에 다시
담아 사용하던 것을 서버 전용 변수로 분리한다. 같은 키를 미리 채워 보내면
인덱스가 밀려 요청값이 사용될 수 있었다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3dbb9034f6f9d6e91916d6dcb78b4c06bc11d733)
2026-08-24 07:56:32 +00:00
thisgun ebd18b6001 [KVE-2026-1813] 미완료주문 확정 처리 필드 정제 및 결제수단 출력 인코딩
미완료주문을 주문으로 확정할 때 임시 데이터에서 복원한 결제수단, 접속 IP,
테스트 결제 여부를 정제 없이 사용하던 것을 이웃 필드와 동일한 방식으로
처리한다. 접속 IP는 표기 형식에 맞지 않으면 저장하지 않고, 테스트 결제
여부는 정수로만 저장하며, 세 값 모두 배열로 전달된 경우를 함께 걸러낸다.

임시주문 저장 시 접속 IP와 테스트 결제 여부를 서버에서 결정하는 처리가
일반 주문 분기 안에만 있어 개인결제 경로에서는 요청값이 그대로 저장되던
것을 분기 밖으로 옮겨 항상 서버 값을 사용하도록 한다.

결제수단 값이 그대로 출력되던 관리자 주문상세, 주문목록, 부분취소 화면과
구매자 주문조회 화면(웹/모바일/테마)에 get_text() 인코딩을 적용한다.
주문상세는 표시 문자열을 여러 곳에서 재사용하므로 생성 지점에서 처리한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 77069575096881a31b29fdf130c83226610bf8df)
2026-08-24 07:56:32 +00:00
thisgun 04a4de4923 스킨 목록 옵션 생성 시 디렉토리 열기 실패 처리 보강
get_list_skin_options()에서 존재하지 않는 스킨 경로가 지정된 경우
opendir() 반환값을 그대로 readdir()에 넘겨 PHP 8 이상에서 스크립트가
중단되던 문제를 수정한다. 아울러 결과 배열을 미리 초기화하여 패턴에
일치하는 스킨 파일이 하나도 없을 때 sort()에서 중단되던 경로도 함께
처리하고, readdir() 종료 조건을 명시적으로 비교하도록 변경한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 4010d29295001c43b6ccd7b4e6414d0adfcc7b2e)
2026-08-24 07:44:22 +00:00
thisgun 96df43480b 게시판·1:1문의·쇼핑몰분류 상단/하단 파일 경로 처리 보강
콘텐츠와 동일하게, 게시판(bo_include)·1:1문의(qa_include)·쇼핑몰 분류
(ca_include)의 상단/하단 파일 경로도 저장 전에 먼저 정규화한 뒤 확장자와
위치를 검증하도록 순서를 조정한다. 정규화 과정에서 확장자가 사라져 검증을
우회하던 경로를 차단하고, data 디렉터리로 귀결되는 경로를 거부한다.

실행 직전 board_head/board_tail, qahead/qatail, shop 목록·상품 페이지에서도
승인 확장자와 data 디렉터리 여부를 다시 확인하는 is_content_include_allowed()
를 적용한다. 이미 저장된 경로도 실행 시 재확인된다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 0c6bca704725ebea2a584d4c06366282e9bc36d6)
2026-08-24 07:44:22 +00:00
thisgun 6571119db6 [KVE-2026-1806] 콘텐츠 include 경로 및 미완료주문 출력 처리 보강
콘텐츠 상단/하단 파일 경로를 저장 전에 먼저 정규화한 뒤 확장자와 위치를
검증하도록 순서를 조정한다. 정규화 과정에서 확장자가 사라져 검증을
우회하던 경로를 차단한다. 실행 직전 bbs/content.php 에서도 승인 확장자와
data 디렉터리 귀결 여부를 다시 확인하는 is_content_include_allowed() 를
적용하고, 콘텐츠 상단/하단 이미지 업로드는 이미지 파일만 허용하도록 검사한다.

미완료주문 상세의 결제방법 출력에 get_text() 인코딩을 적용하고, 임시주문
저장 시 정제한 결제수단 값을 원본에도 반영한다. 개인결제 주문 세션은
결제정보 검증을 통과한 뒤에만 설정한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 196255d76912531d7e13861821bd59ca15c967d1)
2026-08-24 07:44:22 +00:00
thisgun 35acbfa750 나이스페이 API 통신 시 서버 인증서 검증 적용
nicepay_reqPost() 가 원격 서버 인증서를 검증하지 않고 통신하던 것을
검증하도록 변경한다. 이니시스 연동부는 이미 동일하게 처리하고 있다.
API 호스트 4곳(webapi, pg-api, dc1-api, dc2-api) 인증서 검증 통과를
확인했다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 6c888bd53d0a5949bb1e2fc96567c132622a6f8b)
2026-08-24 07:44:22 +00:00
thisgun d9c21ea018 나이스페이 에스크로 배송등록 및 현금영수증 처리 보정
에스크로 배송등록 실패 시 알림 대신 주문 관리자 메모에 결과를 기록하고
이후 처리를 중단한다. 현금영수증 발급 후 DB 반영에 실패한 경우 자동 취소
요청을 제거하고 관리자가 나이스페이에서 직접 확인하도록 안내를 변경한다.
가상계좌 취소 요청금액이 없을 때의 응답 코드를 명시한다.

patch_5631 의 '회귀 점검 후 결제 및 쿠폰존 보강'(4405ddc1c) 중
나이스페이 관련 변경만 적용했다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3f6d013f9466d11eacba29e81ad515a9a0ceeeef)
2026-08-24 07:44:22 +00:00
thisgun 68be1c1f86 나이스페이 부분취소 및 취소응답 검증 보강
(cherry picked from commit df0bfff88cdccc93dd6a8315c166e49a9bb03a5a)
2026-08-24 07:44:22 +00:00
thisgun ff1f6d723b 나이스페이 승인 취소 안정성 보강
(cherry picked from commit 7c26e621c66805b2d162ed0293e570e29a11b4e8)
2026-08-24 07:44:22 +00:00
thisgun bb4d345add 나이스페이 부분취소 처리 보강
(cherry picked from commit ef0da4a903983f46934d5c14ac10adb93a673398)
2026-08-24 07:44:22 +00:00
thisgun 3678b92b2f 나이스페이 가상계좌 취소 환불정보 입력 추가
(cherry picked from commit bb6381d7a58e4690e438dafb0b625a175be4c34b)
2026-08-24 07:44:22 +00:00
thisgun c8d51529d1 관리자 나이스페이 결제 조회 추가
(cherry picked from commit 104123872ada30e75c3e11e6322b6ab16d808efa)
2026-08-24 07:44:22 +00:00
thisgun 129d0ea766 모바일 나이스페이 결제금액 동기화 수정
(cherry picked from commit 671693d3adefd7b9e7a1447fee2d046d8ebdf600)
2026-08-24 07:44:22 +00:00
thisgun d80289ff28 나이스페이 결제 검증 보강
(cherry picked from commit 8c8099c63eb30c5cfd4678cecedbfd029471065e)
2026-08-24 07:44:22 +00:00
thisgun c4b54a6219 나이스페이 실패 응답 처리 보강
(cherry picked from commit 1caea3176ef8d3fd6057fc9a7e6646878cdf3e0c)
2026-08-24 07:44:22 +00:00
thisgun 8e7ec335c3 나이스페이 결제 검증과 영수증 처리 보강
(cherry picked from commit 8bcd1bcbea25371bd0a5b196b71d2c1b4308479a)
2026-08-24 07:44:22 +00:00
thisgun 5a36b2d85d 나이스페이 통지와 취소 응답 처리 보강
(cherry picked from commit e65d17d227028fc5eabe4d6a831485bf27685c01)
2026-08-24 07:44:22 +00:00
thisgun 2b21804111 나이스페이 입금통지 주문 조건 완화
(cherry picked from commit 9c363f4bc31cfd9361b7631977c7f892942aee0b)
2026-08-24 07:44:22 +00:00
thisgun a21f3103bb 나이스페이 결제 응답 검증 보강
(cherry picked from commit 50c2d6b6cfeaa10bbb65b2537a05c0525528cc63)
2026-08-24 07:44:22 +00:00
thisgun f7106379b8 나이스페이 결제 검증 및 취소 처리 보강
(cherry picked from commit 1e03160280e0a6b23e9d4b01a8bd726bddccf2cd)
2026-08-24 07:44:22 +00:00
thisgun f4d184979f 쿠폰존 폼 초기화 배열의 중복 항목 정리
cp_price 가 두 번 선언되어 있어 하나를 제거하고, 폼 본문에서 참조하는
cz_id 를 초기화 대상에 추가한다.

cz_id 참조 지점은 현재 앞쪽 조건의 단축 평가로 도달하지 않으나,
조건이 바뀔 경우를 대비해 초기화 목록을 참조 항목과 일치시킨다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit c03b311e789642f0af3fe898e040afea28733e7c)
2026-08-24 07:44:22 +00:00
thisgun f6ec58ca18 session_check() 의 잘못된 이동 함수명 수정
그누보드4에서 5로 전환할 때 상수와 전역변수만 변경되고 함수명이
그대로 남아, 정의되지 않은 gotourl() 을 호출하고 있었다.
세션이 없는 상태로 이 함수가 실행되면 치명적 오류가 발생한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit f62b0559b4c757da693e7fe1b78a5d5ec2364504)
2026-08-24 07:44:22 +00:00
thisgun a0e86f2bc8 환경설정 캡챠 입력란을 확인 버튼 옆으로 이동
캡챠가 문서 최하단에 생성되어, 확인을 누르면 페이지 끝까지 강제로
스크롤된 뒤 입력해야 했다. 페이지가 길어 위치를 찾기 어렵다는 의견이
있어 상단 고정 영역의 확인 버튼 옆에 노출하도록 변경한다.

- 캡챠 영역을 확인 버튼과 같은 고정 영역으로 이동하고 패널 형태로 표시
- 고정 노출이므로 강제 스크롤을 제거하고 입력란 포커스로 대체
- 좁은 화면에서 관리자 메뉴에 가려지지 않도록 표시 순서 조정

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 39b7637bab609600a21118966968f46ab1fb6546)
2026-08-24 07:44:22 +00:00
thisgun 4ecacec171 게시판그룹 삭제 경고의 게시판목록 링크 검색대상 값 정정
board_list.php 의 검색대상 값은 a.gr_id 이나 링크가 gr_id 로 전달하여
그룹에 속한 게시판이 조회되지 않던 문제를 수정한다.

접두사가 없는 gr_id 는 최고관리자가 아닌 경우 그룹 테이블을 함께
조회하는 구조에서 컬럼 모호성 오류가 발생하므로 a.gr_id 로 맞춘다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit c6dd497a450bd5ba08d743efc26ba73fcdd9e626)
2026-08-24 07:44:22 +00:00
thisgun 913d1c66c7 쿠폰 다운로드 포인트 검사를 회원 단위로 직렬화
기존에는 쿠폰별로 잠금을 잡아, 같은 회원이 서로 다른 포인트 쿠폰을
동시에 요청하면 각 요청이 요청 시작 시점의 보유 포인트 값으로 검사를
통과하여 잔액보다 많은 쿠폰을 받을 수 있었다.

- 잠금 범위를 쿠폰별에서 회원별로 변경
- 보유 포인트를 잠금 획득 후 회원 테이블에서 다시 조회하여 검사

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit fd04b432cf34dfba52e281fc74391f8e2d48fe6b)
2026-08-24 07:44:22 +00:00
thisgun 42859072eb 회원가입 쿠폰 발급 재시도 상한 동작하도록 수정
쿠폰번호 중복 시 재생성을 반복하는 구간에서 재시도 횟수가 증가하지
않아 상한 검사가 동작하지 않았다. 중복이 계속 발생하면 조회를 반복하며
루프를 빠져나가지 못하므로 횟수 증가를 추가한다.

- bbs/register_form_update.php
- plugin/social/register_member_update.php

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit ad396a59d463df880739c1e9514e4aa61d883850)
2026-08-24 07:44:22 +00:00
thisgun 0ae67a652c [KVE-2026-1803] 쿠폰번호 생성에 안전한 난수원 적용
get_coupon_id() 가 microtime 기반 시드로 난수 생성기를 재시드하여
생성 가능한 쿠폰번호가 시드 공간 크기로 제한되던 문제를 수정한다.
기존 구현은 33^16 이 아닌 10^6 개의 값만 생성할 수 있어 전체 집합을
사전 계산할 수 있었다.

- get_random_token_string() 으로 난수 바이트를 얻어 쿠폰번호를 구성
- 문자 종류 수로 나누어 떨어지는 구간만 사용하여 문자 분포 편중 제거
- 헬퍼 미정의 환경을 위해 function_exists 가드 및 mt_rand 보완 경로 유지
- 쿠폰번호 형식(16자, 4자리 하이픈 구분)과 사용 문자는 기존과 동일

plugin/lgxpay/lgdacom/XPayClient.php 의 불필요한 재시드 호출 제거

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit a6cf071f405c79904f7861d5e5efc118f29005dc)
2026-08-24 07:44:22 +00:00
thisgun 516eac386f [KVE-2026-1785] 관리자 목록 검색필드 화이트리스트 누락 보완
검색필드가 SQL 컬럼명 위치에 검증 없이 삽입되던 관리자 목록 9개
파일에 허용 컬럼 목록을 추가한다. 허용 컬럼은 각 화면의 검색 UI가
제공하는 항목 기준이며, 미허용 값은 빈 문자열이 아닌 유효 컬럼으로
대체하여 SQL 문법 오류를 방지한다.

- adm/auth_list.php
- adm/board_list.php
- adm/boardgroup_list.php
- adm/boardgroupmember_list.php
- adm/point_list.php
- adm/poll_list.php
- adm/popular_list.php
- adm/shop_admin/inorderlist.php
- adm/shop_admin/personalpaylist.php

adm/member_list.php 의 불필요한 주석 제거

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit ff56beff8c6804013e830eb828779e02493cee52)
2026-08-24 07:44:22 +00:00
thisgun 188d0e30a0 KG이니시스 PRO 판정 조회 컬럼 통일
- 모니터 알림과 KG 대사 배치 쿼리에도 주문 환불금액을 포함해
  현황 목록·상세 화면과 동일한 기준으로 판정하도록 정리

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 1388bc323724128acf78b15a49767e39f9709491)
2026-08-24 07:44:22 +00:00
thisgun c450f8bbde 관리자 권한 문맥 오염 계열 접근권한 점검 및 보완
게시판/그룹 관리자 문맥(bo_table)으로 타 회원 콘텐츠에 접근·변조되지
않도록 $is_admin 판정을 최고관리자(super) 기준으로 통일.
- bbs/poll_etc_update.php : 설문 기타의견 삭제 소유권
- shop/itemqaformupdate.php : 상품문의 수정/삭제 소유권
- shop/itemuseformupdate.php : 사용후기 삭제 소유권
- bbs/current_connect.php : 게스트 IP 원본 표기
- shop/kakaopay/kakaopay_cancel.php : TID 기반 결제취소

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 46a005129464d1fbab518fcb70bf524b258e65fc)
2026-08-24 07:44:22 +00:00
thisgun b3aa81c74a [KVE-2026-1640] 1:1 문의 접근권한 우회 취약점 수정
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit a719c6ea5f6d38350f9dcda682a04dad31f6a454)
2026-08-24 07:44:22 +00:00
thisgun 11a26c82af [KVE-2026-1639] 쇼핑몰 주문정보 접근권한 우회 취약점 수정
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit d3e8ffc3d6a0af4e2abe9b798316ae1c504e7d37)
2026-08-24 07:44:21 +00:00
thisgun 43f626885e [KVE-2026-1638] 쇼핑몰 쿠폰 중복적용 취약점 수정
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 88bfddd0e83353c15c424549b594b8f36593220f)
2026-08-24 07:44:21 +00:00
164 changed files with 2242 additions and 741 deletions
+50
View File
@@ -0,0 +1,50 @@
# 저장소 작업 지침
## 적용 범위
이 문서는 저장소 루트와 모든 하위 디렉터리에 적용한다.
## 문서 작성 언어
- README, 보안 정책, 설치 안내, 개발 가이드 등 저장소 문서는 원칙적으로 한국어로 작성한다.
- 파일명, 코드 식별자, 명령어, API 명칭, 설정값과 외부 서비스의 고유 명칭은 원문을 유지한다.
- 영문 문서나 번역본이 별도로 필요한 경우에는 해당 작업에서 명시적으로 요청된 범위에 한해 추가한다.
## 커밋 메시지
- 커밋 메시지는 한국어로 작성한다.
- 제목은 `<접두어>: <변경 내용>` 형식을 사용한다.
- 접두어는 아래 권장 목록에서 변경 목적에 가장 가까운 항목을 선택한다.
- 변경 대상을 포함해 무엇을 왜 변경했는지 알 수 있도록 구체적으로 작성한다.
- `수정`, `업데이트`, `작업`처럼 변경 내용을 식별하기 어려운 표현만 사용하지 않는다.
- 하나의 커밋에는 가능한 한 하나의 목적에 해당하는 변경만 포함한다.
- 제목만으로 설명이 부족하면 본문에 변경 이유, 영향 범위와 검증 방법을 추가한다.
- 관련 이슈가 있으면 커밋 본문이나 꼬리말에 이슈 번호를 기록한다.
### 권장 접두어
- `feat`: 새로운 기능 추가
- `fix`: 버그 또는 잘못된 동작 수정
- `security`: 보안 취약점 수정이나 보안 강화
- `docs`: 문서 추가 또는 변경
- `refactor`: 동작 변경 없는 코드 구조 개선
- `perf`: 성능 개선
- `test`: 테스트 추가 또는 변경
- `build`: 빌드 시스템이나 의존성 변경
- `ci`: CI/CD 설정이나 자동화 변경
- `chore`: 기능과 직접 관련 없는 유지보수 작업
- `revert`: 이전 변경 되돌리기
### 보안 이슈 식별자
- KVE, CVE 등 식별자가 부여된 보안 이슈를 조치하는 커밋은 제목에 관련 식별자를 반드시 병기한다.
- 식별자는 `security:` 접두어 바로 뒤에 원문 그대로 작성한다.
- 하나의 커밋이 여러 보안 이슈를 함께 조치하면 관련 식별자를 모두 병기한다.
- 예: `security: KVE-2026-1909 모바일 KCP Windows 명령 인자 주입 차단`
### 작성 예시
- `docs: Git과 압축파일 설치 절차를 구분해 README에 안내`
- `fix: 품목 일부 취소 시 PG 취소금액 불일치 수정`
- `security: KVE-2026-1899 상품 정렬값 화이트리스트 검증으로 SQL 삽입 차단`
- `refactor: 객체 캐시의 유형별 저장 키 생성 로직 분리`
+78
View File
@@ -0,0 +1,78 @@
# 그누보드5
그누보드5는 PHP와 MySQL 또는 MariaDB 기반의 오픈소스 CMS입니다. 게시판과 회원 관리 기능을 제공하며 쇼핑몰 솔루션 영카트를 포함합니다.
## 버전 확인
현재 소스 코드의 버전은 [`version.php`](version.php)에서 확인할 수 있습니다.
## 다운로드 및 설치
### 설치 환경
#### 기본 요구사항
- PHP 5.2.17 이상
- 최소 요구 버전은 PHP 5.2.17이며 PHP 7.2 이상을 권장합니다.
- MySQL 5.0 이상 또는 MySQL 5.0 이상의 기능을 지원하는 MariaDB
- Linux 호환 운영체제
#### 필수 라이브러리
- GD Library 2.0 이상
- iconv
#### 추가로 필요한 모듈 및 프로그램
- 글을 SNS로 복사하는 기능 사용 시
- cURL
- JSON
- 영카트5 모바일 결제 사용 시
- SOAP
- OpenSSL
> SIR에서 직접 제작한 그누보드5 및 호환 프로그램은 Linux에서만 개발하고 테스트했습니다. 다른 운영체제에서의 정상 동작은 보장하지 않습니다.
설치 환경에 관한 자세한 내용은 [그누보드5 공식 매뉴얼](https://sir.kr/manuals/g5/1)을 확인하십시오.
### Git을 이용하는 방법
Git을 사용할 수 있는 서버에서는 [GitHub 저장소](https://github.com/gnuboard/gnuboard5)를 복제하여 설치할 수 있습니다.
```bash
git clone https://github.com/gnuboard/gnuboard5.git
cd gnuboard5
```
복제한 `gnuboard5` 디렉터리를 웹 서버의 서비스 경로로 사용하거나, 서비스 경로 안에 소스 전체를 배치합니다. 이후 아래의 공통 설치 절차를 진행합니다.
### 압축파일을 이용하는 방법
1. 다음 중 한 곳에서 설치할 버전의 압축파일을 내려받습니다.
- [GitHub Releases](https://github.com/gnuboard/gnuboard5/releases)에서 원하는 버전을 선택하고 `Source code (zip)`을 내려받습니다. `*.patch.zip` 파일은 기존 설치본을 업데이트하기 위한 패치이므로 신규 설치에는 사용하지 않습니다.
- [SIR 그누보드5 다운로드](https://sir.kr/boards/g5_pds)에서 원하는 버전의 배포본을 내려받습니다.
2. 내려받은 압축파일을 풉니다.
3. 압축을 푼 디렉터리의 파일과 하위 디렉터리를 FTP, SFTP 등의 방법으로 웹 서버의 서비스 경로에 업로드합니다.
4. 업로드가 끝나면 아래의 공통 설치 절차를 진행합니다.
### 공통 설치 절차
1. 브라우저에서 소스를 배치한 주소로 접속하여 설치 화면을 엽니다.
2. `data` 디렉터리를 만들라는 안내가 표시되면 `config.php`가 있는 디렉터리에 `data`를 만들고 웹 서버가 쓸 수 있도록 권한을 설정합니다. 공식 매뉴얼에서는 `707` 권한을 예시로 사용합니다.
3. 라이선스 내용을 확인하고 동의한 뒤 설치를 계속합니다.
4. MySQL 또는 MariaDB 접속 정보와 최고관리자 정보를 입력합니다.
5. 설치 완료 화면을 확인한 뒤 생성한 최고관리자 계정으로 로그인합니다.
> 기존 사이트에 재설치하면 데이터가 삭제될 수 있습니다. 진행하기 전에 파일과 데이터베이스를 백업하십시오.
## 문서 및 지원
- [그누보드5 공식 페이지](https://sir.kr/main/g5/)
- [그누보드5 공식 매뉴얼](https://sir.kr/manuals/g5/1)
- [그누보드5 Q&A](https://sir.kr/questions?s_tag=%EA%B7%B8%EB%88%84%EB%B3%B4%EB%93%9C5)
보안 취약점 신고 방법은 [`SECURITY.md`](SECURITY.md)를 확인하십시오.
## 라이선스
라이선스 전문과 적용 조건은 [`LICENSE.txt`](LICENSE.txt)를 확인하십시오.
+4 -2
View File
@@ -1,3 +1,5 @@
# Gnuboard5 Security Policy
# 그누보드5 보안 정책
Please ask [https://sir.kr/security/.](https://sir.kr/co_qa)
그누보드5에서 보안 취약점을 발견한 경우 악용 가능한 상세 내용을 공개 GitHub 이슈에 게시하지 마십시오.
취약점 정보와 재현 방법은 [SIR 보안 취약점 신고 게시판](https://sir.kr/boards/co_qa)을 통해 제보해 주십시오.
+2 -2
View File
@@ -52,8 +52,8 @@ $print_version = ($is_admin == 'super') ? 'Version ' . G5_GNUBOARD_VER : '';
<!-- <p>실행시간 : <?php echo get_microtime() - $begin_time; ?> -->
<script src="<?php echo G5_ADMIN_URL ?>/admin.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="<?php echo G5_JS_URL ?>/jquery.anchorScroll.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="<?php echo get_versioned_asset_url(G5_ADMIN_URL.'/admin.js'); ?>"></script>
<script src="<?php echo get_versioned_asset_url(G5_JS_URL.'/jquery.anchorScroll.js'); ?>"></script>
<script>
$(function() {
+5
View File
@@ -8,6 +8,11 @@ if ($is_admin != 'super') {
$sql_common = " from {$g5['auth_table']} a left join {$g5['member_table']} b on (a.mb_id=b.mb_id) ";
$allowed_sfl = array('a.mb_id');
if (!in_array($sfl, $allowed_sfl)) {
$sfl = 'a.mb_id';
}
$sql_search = " where (1) ";
if ($stx) {
$sql_search .= " and ( ";
+1 -1
View File
@@ -14,7 +14,7 @@ if (empty($bo_table)) {
<script>
var g5_admin_csrf_token_key = "<?php echo (function_exists('admin_csrf_token_key')) ? admin_csrf_token_key() : ''; ?>";
</script>
<script src="<?php echo G5_ADMIN_URL ?>/admin.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="<?php echo get_versioned_asset_url(G5_ADMIN_URL.'/admin.js'); ?>"></script>
<div class="new_win">
<h1><?php echo $g5['title']; ?></h1>
+12 -3
View File
@@ -62,6 +62,12 @@ if ($check_captcha) {
}
}
// 저장·검증 전에 경로를 먼저 정규화하여, 검증 이후 경로가 달라지지 않도록 한다.
if (function_exists('filter_input_include_path')) {
$bo_include_head = filter_input_include_path($bo_include_head);
$bo_include_tail = filter_input_include_path($bo_include_tail);
}
if ($file = $bo_include_head) {
$file_ext = pathinfo($file, PATHINFO_EXTENSION);
@@ -86,9 +92,12 @@ if (!is_include_path_check($bo_include_tail, 1)) {
alert('하단 파일 경로에 포함시킬수 없는 문자열이 있습니다.');
}
if (function_exists('filter_input_include_path')) {
$bo_include_head = filter_input_include_path($bo_include_head);
$bo_include_tail = filter_input_include_path($bo_include_tail);
if ($bo_include_head && function_exists('is_content_include_allowed') && !is_content_include_allowed($bo_include_head)) {
alert('상단 파일 경로로 사용할 수 없는 위치입니다.');
}
if ($bo_include_tail && function_exists('is_content_include_allowed') && !is_content_include_allowed($bo_include_tail)) {
alert('하단 파일 경로로 사용할 수 없는 위치입니다.');
}
$board_path = G5_DATA_PATH . '/file/' . $bo_table;
+5
View File
@@ -12,6 +12,11 @@ if ($is_admin != "super") {
$sql_search .= " and (a.gr_id = b.gr_id and b.gr_admin = '{$member['mb_id']}') ";
}
$allowed_sfl = array('bo_table', 'bo_subject', 'a.gr_id');
if (!in_array($sfl, $allowed_sfl)) {
$sfl = 'bo_table';
}
if ($stx) {
$sql_search .= " and ( ";
switch ($sfl) {
+5
View File
@@ -20,6 +20,11 @@ if ($is_admin != 'super') {
$sql_search .= " and (gr_admin = '{$member['mb_id']}') ";
}
$allowed_sfl = array('gr_subject', 'gr_id', 'gr_admin');
if (!in_array($sfl, $allowed_sfl)) {
$sfl = 'gr_subject';
}
if ($stx) {
$sql_search .= " and ( ";
switch ($sfl) {
+1 -1
View File
@@ -42,7 +42,7 @@ for ($i = 0; $i < $chk_count; $i++) {
} elseif ($act_button == '선택삭제') {
$row = sql_fetch(" select count(*) as cnt from {$g5['board_table']} where gr_id = '$gr_id' ");
if ($row['cnt']) {
alert("이 그룹에 속한 게시판이 존재하여 게시판 그룹을 삭제할 수 없습니다.\\n\\n이 그룹에 속한 게시판을 먼저 삭제하여 주십시오.", './board_list.php?sfl=gr_id&amp;stx=' . $gr_id);
alert("이 그룹에 속한 게시판이 존재하여 게시판 그룹을 삭제할 수 없습니다.\\n\\n이 그룹에 속한 게시판을 먼저 삭제하여 주십시오.", './board_list.php?sfl=a.gr_id&amp;stx=' . $gr_id);
}
// 그룹 삭제
+5
View File
@@ -13,6 +13,11 @@ $sql_common = " from {$g5['group_member_table']} a
left outer join {$g5['member_table']} b on (a.mb_id = b.mb_id) ";
$sql_search = " where gr_id = '{$gr_id}' ";
$allowed_sfl = array('a.mb_id');
if (!in_array($sfl, $allowed_sfl)) {
$sfl = 'a.mb_id';
}
// 회원아이디로 검색되지 않던 오류를 수정
if (isset($stx) && $stx) {
$sql_search .= " and ( ";
+22 -13
View File
@@ -1616,17 +1616,24 @@ if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
</div>
</section>
<div id="config_captcha_wrap" style="display:none">
<h2>캡챠입력</h2>
<?php
require_once G5_CAPTCHA_PATH . '/captcha.lib.php';
$captcha_html = captcha_html();
$captcha_js = chk_captcha_js();
echo $captcha_html;
?>
</div>
<style>
.btn_fixed_top.btn_confirm {display:flex;align-items:flex-start;gap:8px;z-index:1001}
#config_captcha_wrap {max-width:calc(100vw - 40px);padding:10px 12px;border:1px solid #c5cbd5;border-radius:3px;background:#fff;box-shadow:0 2px 8px rgba(0,0,0,0.15);text-align:left}
#config_captcha_wrap h2 {margin:0 0 6px;padding:0;font-size:1em;line-height:1.2;color:#3a3a3a}
#config_captcha_wrap #mp_captcha_tooltip {margin:6px 0 0;color:#e8180c}
</style>
<div class="btn_fixed_top btn_confirm">
<div id="config_captcha_wrap" style="display:none">
<h2>캡챠입력</h2>
<?php
require_once G5_CAPTCHA_PATH . '/captcha.lib.php';
$captcha_html = captcha_html();
$captcha_js = chk_captcha_js();
echo $captcha_html;
?>
</div>
<input type="submit" value="확인" class="btn_submit btn" accesskey="s">
</div>
@@ -1731,7 +1738,6 @@ if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
if(isChanged){
$wrap.show();
if(! is_invisible_recaptcha) {
$wrap.css("margin-top","1em");
if(! $("#"+tooptipid).length){ $children.after($p_text) }
}
} else {
@@ -1747,8 +1753,11 @@ if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
var cf_intercept_ip_val = f.cf_intercept_ip.value;
if (check_config_captcha_open()){
jQuery("html, body").scrollTop(jQuery("#config_captcha_wrap").offset().top);
// 캡챠는 확인 버튼 옆에 고정 노출되므로 별도 이동 없이 입력란으로 포커스만 옮긴다.
if (jQuery("#captcha_key").is(":visible")) {
jQuery("#captcha_key").focus();
}
<?php echo $captcha_js; // 캡챠 사용시 자바스크립트에서 입력된 캡챠를 검사함 ?>
}
+28 -5
View File
@@ -40,6 +40,12 @@ if ($is_admin !== 'super') {
$co_include_tail = '';
}
}
// 저장·검증 전에 경로를 먼저 정규화하여, 검증 이후 경로가 달라지지 않도록 한다.
if (function_exists('filter_input_include_path')) {
$co_include_head = filter_input_include_path($co_include_head);
$co_include_tail = filter_input_include_path($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;
@@ -86,6 +92,14 @@ if ($co_include_tail) {
}
}
if ($co_include_head && function_exists('is_content_include_allowed') && !is_content_include_allowed($co_include_head)) {
alert('상단 파일 경로로 사용할 수 없는 위치입니다.');
}
if ($co_include_tail && function_exists('is_content_include_allowed') && !is_content_include_allowed($co_include_tail)) {
alert('하단 파일 경로로 사용할 수 없는 위치입니다.');
}
if ($co_include_head && !is_include_path_check($co_include_head, 1)) {
$co_include_head = '';
$error_msg = '/data/file/ 또는 /data/editor/ 포함된 문자를 상단 파일 경로에 포함시킬수 없습니다.';
@@ -96,11 +110,6 @@ if ($co_include_tail && !is_include_path_check($co_include_tail, 1)) {
$error_msg = '/data/file/ 또는 /data/editor/ 포함된 문자를 하단 파일 경로에 포함시킬수 없습니다.';
}
if (function_exists('filter_input_include_path')) {
$co_include_head = filter_input_include_path($co_include_head);
$co_include_tail = filter_input_include_path($co_include_tail);
}
$co_seo_title = exist_seo_title_recursive('content', generate_seo_title($co_subject), $g5['content_table'], $co_id);
$sql_common = " co_include_head = '$co_include_head',
@@ -147,6 +156,20 @@ if (function_exists('get_admin_captcha_by')) {
g5_delete_cache_by_prefix('content-' . $co_id . '-');
if ($w == "" || $w == "u") {
foreach (array('co_himg', 'co_timg') as $content_img_field) {
if (empty($_FILES[$content_img_field]['name']) || empty($_FILES[$content_img_field]['tmp_name']))
continue;
// 상단/하단 이미지 슬롯에는 이미지만 허용하고, 실행 가능한 태그가 담긴 파일은 거부한다.
$tmp_file = $_FILES[$content_img_field]['tmp_name'];
$is_valid_image = @getimagesize($tmp_file);
$head_bytes = @file_get_contents($tmp_file, false, null, 0, 8192);
if ($is_valid_image === false || ($head_bytes !== false && preg_match('/<\?php|<\?=|<\?|<script/i', $head_bytes))) {
alert('상단/하단 이미지에는 이미지 파일만 등록할 수 있습니다.');
}
}
if ($_FILES['co_himg']['name']) {
$dest_path = G5_DATA_PATH . "/content/" . $co_id . "_h";
@move_uploaded_file($_FILES['co_himg']['tmp_name'], $dest_path);
+2 -11
View File
@@ -354,16 +354,7 @@ border-bottom: 5px solid black;}
.excel-download-progress .progress-download-box a:hover { border-color: #6f809a; box-shadow: 0 2px 4px rgba(111, 128, 154, 0.15); }
.excel-download-progress .progress-download-box a:active { box-shadow: inset 0 1px 2px rgba(0,0,0,0.1); }
.field-select-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 15px; gap: 0px 10px; padding: 10px; background-color: #f9fafb; border: 1px solid #e5e7eb; border-radius: 8px; color: #374151; }
.field-select-form label { display: flex; align-items: center; cursor: pointer; padding: 6px 10px; border-radius: 4px; }
.field-select-form label:hover { background-color: #f3f4f6; }
.field-select-form input[type="checkbox"] { margin-right: 8px; transform: scale(1.2); }
.field-separator { grid-column: 1 / -1; border-top: 1px solid #d1d5db; margin: 8px 0; }
.selected-fields-preview { padding: 8px; background-color: #eef2f7; border: 1px solid #d1d5db; border-radius: 6px; margin: 10px 0px; color: #1f2937; display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.selected-fields-preview strong { padding: 4px 8px; }
.selected-fields-preview .field-tag { background-color: #dbeafe; color: #1e40af; padding: 4px 8px; border-radius: 4px; }
/* 페이지 내 실행 */
/* 페이지 내 실행 */
.local_cmd {min-width:960px}
.local_cmd01 {margin:0 0 10px;padding:0 }
.local_cmd01 .cmd_tit {font-weight:bold}
@@ -1217,4 +1208,4 @@ input[type="text"]{max-width:200px}
@media only screen and (max-device-width : 480px) and (orientation : portrait){
/* Styles */
input[type="text"]{max-width:200px}
}
}
-1
View File
@@ -6,7 +6,6 @@ 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';
+3 -12
View File
@@ -7,7 +7,9 @@
define('MEMBER_EXPORT_PAGE_SIZE', 10000); // 파일당 처리할 회원 수
define('MEMBER_EXPORT_MAX_SIZE', 300000); // 최대 처리할 회원 수
define('MEMBER_BASE_DIR', "member_list"); // 엑셀 베이스 폴더
define('MEMBER_BASE_DATE', date('YmdHis')); // 폴더/파일명용 날짜
// 폴더/파일명용 날짜 - 저장 경로가 추측되지 않도록 임의 문자열을 덧붙인다.
define('MEMBER_BASE_SALT', function_exists('get_random_token_string') ? get_random_token_string(8) : substr(md5(uniqid(mt_rand(), true)), 0, 8));
define('MEMBER_BASE_DATE', date('YmdHis') . '_' . MEMBER_BASE_SALT);
define('MEMBER_EXPORT_DIR', G5_DATA_PATH . "/" . MEMBER_BASE_DIR . "/" . MEMBER_BASE_DATE); // 엑셀 파일 저장 경로
define('MEMBER_LOG_DIR', G5_DATA_PATH . "/" . MEMBER_BASE_DIR . "/" . "log"); // 로그 파일 저장 경로
@@ -57,18 +59,8 @@ function get_export_config($type = null)
*/
function get_member_export_params()
{
// 친구톡 양식 - 엑셀 양식에 포함할 항목
$fieldArray = array_map('trim', explode(',', isset($_GET['fields']) ? $_GET['fields'] : ''));
$vars = array();
foreach ($fieldArray as $index => $field) {
if(!empty($field)){
$vars['var' . ($index + 1)] = $field;
}
}
$params = array(
'page' => 1,
'formatType' => (int)(isset($_GET['formatType']) ? $_GET['formatType'] : 1),
'use_stx' => isset($_GET['use_stx']) ? $_GET['use_stx'] : 0,
'stx_cond' => clean_xss_tags(isset($_GET['stx_cond']) ? $_GET['stx_cond'] : 'like'),
'sfl' => clean_xss_tags(isset($_GET['sfl']) ? $_GET['sfl'] : ''),
@@ -91,7 +83,6 @@ function get_member_export_params()
'agree_date_end' => clean_xss_tags(isset($_GET['agree_date_end']) ? $_GET['agree_date_end'] : ''),
'use_intercept' => isset($_GET['use_intercept']) ? $_GET['use_intercept'] : 0,
'intercept' => clean_xss_tags(isset($_GET['intercept']) ? $_GET['intercept'] : 'exclude'),
'vars' => $vars,
);
// 레벨 범위 검증
+3 -29
View File
@@ -271,7 +271,7 @@ function closePreviousEventSource() {
}
// 2. FormData QueryString 변환
function buildDownloadParams(selectedFields = []) {
function buildDownloadParams() {
const formData = new FormData(document.getElementById('fsearch'));
const params = new URLSearchParams(formData);
@@ -281,10 +281,10 @@ function buildDownloadParams(selectedFields = []) {
}
// 3. 메인 함수
function startExcelDownload(selectedFields = []) {
function startExcelDownload() {
closePreviousEventSource();
const query = buildDownloadParams(selectedFields);
const query = buildDownloadParams();
showDownloadPopup();
eventSource = new EventSource(`member_list_exel_export.php?${query}`);
@@ -340,32 +340,6 @@ function handlePopupCloseWithConfirm(e) {
PopupManager.close('popupOverlay');
}
// 체크박스 선택 시 최대 3개 제한 및 선택된 항목 미리보기 표시
function bindFieldSelectEvents() {
const fieldSelectForm = document.getElementById('fieldSelectForm');
if (!fieldSelectForm) return;
fieldSelectForm.addEventListener('change', function (e) {
if (e.target.name === 'fields') {
const selected = fieldSelectForm.querySelectorAll('input[name="fields"]:checked');
if (selected.length > 3) {
alert("최대 3개까지 선택 가능합니다.");
e.target.checked = false;
return;
}
// 선택된 항목 표시
const previewContainer = document.getElementById('selectedFieldsPreview');
let spans = '<strong>선택된 항목:</strong>';
selected.forEach(field => {
const label = field.parentElement.textContent.trim();
spans += `<span class="field-tag">${label}</span>`;
});
previewContainer.innerHTML = spans;
}
});
}
// 엑셀 생성 및 다운로드 실행
function handleProgressUpdate() {
return function(e) {
+1 -1
View File
@@ -413,7 +413,7 @@ function member_export_delete($fileList = array())
$name = basename($file);
// log 폴더와 오늘 날짜로 시작하는 폴더는 제외
if ($name === 'log' || preg_match('/^' . date('Ymd') . '\d{6}$/', $name)) continue;
if ($name === 'log' || preg_match('/^' . date('Ymd') . '\d{6}(_[A-Za-z0-9]+)?$/', $name)) continue;
if (is_file($file) && pathinfo($file, PATHINFO_EXTENSION) !== 'log' && @unlink($file)) {
$cnt++;
+5
View File
@@ -6,6 +6,11 @@ auth_check_menu($auth, $sub_menu, 'r');
$sql_common = " from {$g5['point_table']} po";
$allowed_sfl = array('mb_id', 'po_content');
if (!in_array($sfl, $allowed_sfl)) {
$sfl = 'mb_id';
}
$sql_search = " where (1) ";
if ($stx) {
+5
View File
@@ -6,6 +6,11 @@ auth_check_menu($auth, $sub_menu, 'r');
$sql_common = " from {$g5['poll_table']} ";
$allowed_sfl = array('po_subject');
if (!in_array($sfl, $allowed_sfl)) {
$sfl = 'po_subject';
}
$sql_search = " where (1) ";
if ($stx) {
$sql_search .= " and ( ";
+5
View File
@@ -16,6 +16,11 @@ if (isset($_POST['chk']) && is_array($_POST['chk'])) {
}
$sql_common = " from {$g5['popular_table']} a ";
$allowed_sfl = array('pp_word', 'pp_date');
if (!in_array($sfl, $allowed_sfl)) {
$sfl = 'pp_word';
}
$sql_search = " where (1) ";
if ($stx) {
+12 -3
View File
@@ -36,6 +36,12 @@ if ($board && ($qaconfig['qa_include_head'] !== $qa_include_head || $qaconfig['q
}
}
// 저장·검증 전에 경로를 먼저 정규화하여, 검증 이후 경로가 달라지지 않도록 한다.
if (function_exists('filter_input_include_path')) {
$qa_include_head = filter_input_include_path($qa_include_head);
$qa_include_tail = filter_input_include_path($qa_include_tail);
}
if ($qa_include_head) {
$file_ext = pathinfo($qa_include_head, PATHINFO_EXTENSION);
@@ -62,9 +68,12 @@ if ($qa_include_tail && !is_include_path_check($qa_include_tail, 1)) {
$error_msg = '/data/file/ 또는 /data/editor/ 포함된 문자를 하단 파일 경로에 포함시킬수 없습니다.';
}
if (function_exists('filter_input_include_path')) {
$qa_include_head = filter_input_include_path($qa_include_head);
$qa_include_tail = filter_input_include_path($qa_include_tail);
if ($qa_include_head && function_exists('is_content_include_allowed') && !is_content_include_allowed($qa_include_head)) {
alert('상단 파일 경로로 사용할 수 없는 위치입니다.');
}
if ($qa_include_tail && function_exists('is_content_include_allowed') && !is_content_include_allowed($qa_include_tail)) {
alert('하단 파일 경로로 사용할 수 없는 위치입니다.');
}
// 분류에 & 나 = 는 사용이 불가하므로 2바이트로 바꾼다.
+2 -2
View File
@@ -208,7 +208,7 @@ function is_cancel_shop_pg_order($od){
$is_od_pg_cancel = true;
}
if ($od['od_pg'] === 'nicepay' && in_array($od['od_settle_case'], array('계좌이체', '휴대폰'))) {
if ($od['od_pg'] === 'nicepay' && in_array($od['od_settle_case'], array('계좌이체', '휴대폰', '가상계좌'))) {
$is_od_pg_cancel = true;
}
@@ -303,7 +303,7 @@ function check_order_inicis_pro_payments_run($run_external = true){
$sql_fields = " select p.*,
o.od_id as order_oid, o.od_tno as order_tid, o.od_status as order_status,
o.od_receipt_price as order_receipt_price, o.od_misu as order_misu, o.od_cancel_price as order_cancel_price,
o.od_settle_case as order_settle_case, $order_amount_sql as order_amount,
o.od_refund_price as order_refund_price, o.od_settle_case as order_settle_case, $order_amount_sql as order_amount,
pp.pp_id as personal_oid, pp.pp_tno as personal_tid, pp.pp_price as personal_amount, pp.pp_receipt_price as personal_receipt_price ";
$recover_result = sql_query(" select ip_oid from `{$tables['summary']}`
+13 -5
View File
@@ -6,6 +6,11 @@ auth_check_menu($auth, $sub_menu, "w");
$ca_include_head = isset($_POST['ca_include_head']) ? trim($_POST['ca_include_head']) : '';
$ca_include_tail = isset($_POST['ca_include_tail']) ? trim($_POST['ca_include_tail']) : '';
// 저장·검증 전에 경로를 먼저 정규화하여, 검증 이후 경로가 달라지지 않도록 한다.
if( function_exists('filter_input_include_path') ){
$ca_include_head = filter_input_include_path($ca_include_head);
$ca_include_tail = filter_input_include_path($ca_include_tail);
}
$ca_id = isset($_REQUEST['ca_id']) ? preg_replace('/[^0-9a-z]/i', '', $_REQUEST['ca_id']) : '';
if( ! $ca_id ){
@@ -93,6 +98,14 @@ if(!is_include_path_check($ca_include_tail, 1)) {
alert('하단 파일 경로에 포함시킬수 없는 문자열이 있습니다.');
}
if($ca_include_head && function_exists('is_content_include_allowed') && !is_content_include_allowed($ca_include_head)) {
alert('상단 파일 경로로 사용할 수 없는 위치입니다.');
}
if($ca_include_tail && function_exists('is_content_include_allowed') && !is_content_include_allowed($ca_include_tail)) {
alert('하단 파일 경로로 사용할 수 없는 위치입니다.');
}
$check_keys = array('ca_skin_dir', 'ca_mobile_skin_dir', 'ca_skin', 'ca_mobile_skin');
foreach( $check_keys as $key ){
@@ -101,11 +114,6 @@ foreach( $check_keys as $key ){
}
}
if( function_exists('filter_input_include_path') ){
$ca_include_head = filter_input_include_path($ca_include_head);
$ca_include_tail = filter_input_include_path($ca_include_tail);
}
if ($w == "u" || $w == "d")
check_demo();
+10
View File
@@ -15,6 +15,16 @@ if(! (isset($_POST['de_admin_company_tel']) && check_vaild_callback($_POST['de_a
// 로그인을 바로 이 주소로 하는 경우 쇼핑몰설정값이 사라지는 현상을 방지
if (!$_POST['de_admin_company_owner']) goto_url("./configform.php");
$logo_img_fields = array('logo_img', 'logo_img2', 'mobile_logo_img', 'mobile_logo_img2');
foreach ($logo_img_fields as $logo_img_field) {
if (isset($_FILES[$logo_img_field]['name']) && $_FILES[$logo_img_field]['name']) {
$filename = get_safe_filename($_FILES[$logo_img_field]['name']);
if (is_disallowed_svg_filename($filename)) {
alert('허용되지 않는 파일 확장자입니다. (svg, svgz)');
}
}
}
if (! empty($_POST['logo_img_del'])) @unlink(G5_DATA_PATH."/common/logo_img");
if (! empty($_POST['logo_img_del2'])) @unlink(G5_DATA_PATH."/common/logo_img2");
if (! empty($_POST['mobile_logo_img_del'])) @unlink(G5_DATA_PATH."/common/mobile_logo_img");
+1 -1
View File
@@ -4,6 +4,7 @@ include_once('./_common.php');
$cz_id = isset($_REQUEST['cz_id']) ? (int) $_REQUEST['cz_id'] : 0;
$cp = array(
'cz_id'=>'',
'cp_method'=>'',
'cz_subject'=>'',
'cp_target'=>'',
@@ -13,7 +14,6 @@ $cp = array(
'mb_id'=>'',
'cz_type'=>'',
'cz_point'=>'',
'cp_price'=>'',
'cz_file'=>'',
'cp_minimum'=>'',
'cp_maximum'=>'',
+1 -1
View File
@@ -24,7 +24,7 @@ if ($mode === 'batch') {
$result = sql_query(" select p.*,
o.od_id as order_oid, o.od_tno as order_tid, o.od_status as order_status,
o.od_receipt_price as order_receipt_price, o.od_misu as order_misu, o.od_cancel_price as order_cancel_price,
o.od_settle_case as order_settle_case, $order_amount_sql as order_amount,
o.od_refund_price as order_refund_price, o.od_settle_case as order_settle_case, $order_amount_sql as order_amount,
pp.pp_id as personal_oid, pp.pp_tno as personal_tid, pp.pp_price as personal_amount, pp.pp_receipt_price as personal_receipt_price
from `{$tables['summary']}` p
left join {$g5['g5_shop_order_table']} o on p.ip_order_type <> 'personal' and o.od_id = p.ip_oid
+1 -1
View File
@@ -367,7 +367,7 @@ $pg_anchor = '<ul class="anchor">
<tbody>
<tr>
<td><?php echo $od['od_id']; ?></td>
<td class="td_paybybig"><?php echo $s_receipt_way; ?></td>
<td class="td_paybybig"><?php echo get_text($s_receipt_way); ?></td>
<td class="td_numbig td_numsum"><?php echo display_price($amount['order']); ?></td>
<td class="td_numbig"><?php echo display_price($od_send_cost + $od_send_cost2); ?></td>
<td class="td_numbig"><?php echo display_point($od_temp_point); ?></td>
+6 -3
View File
@@ -246,6 +246,9 @@ $od_bank_account = isset($data['od_bank_account']) ? addslashes(clean_xss_tags(
$od_tno = '';
$od_app_no = '';
$od_hope_date = isset($data['od_hope_date']) ? addslashes(clean_xss_tags(stripslashes($data['od_hope_date']), 1, 1)) : '';
$od_ip = (isset($data['od_ip']) && !is_array($data['od_ip']) && preg_match('/^[0-9a-fA-F:.]{1,45}$/', $data['od_ip'])) ? $data['od_ip'] : '';
$od_settle_case = (isset($data['od_settle_case']) && !is_array($data['od_settle_case'])) ? addslashes(clean_xss_tags(stripslashes($data['od_settle_case']), 1, 1)) : '';
$od_test = (isset($data['od_test']) && !is_array($data['od_test'])) ? (int) $data['od_test'] : 0;
// 주문서에 입력
$sql = " insert {$g5['g5_shop_order_table']}
@@ -297,9 +300,9 @@ $sql = " insert {$g5['g5_shop_order_table']}
od_shop_memo = '',
od_hope_date = '{$od_hope_date}',
od_time = '{$od['dt_time']}',
od_ip = '{$data['od_ip']}',
od_settle_case = '{$data['od_settle_case']}',
od_test = '{$data['od_test']}'
od_ip = '$od_ip',
od_settle_case = '$od_settle_case',
od_test = '$od_test'
";
$result = sql_query($sql, true);
+5
View File
@@ -6,6 +6,11 @@ auth_check_menu($auth, $sub_menu, "r");
$sql_common = " from {$g5['g5_shop_order_data_table']} ";
$allowed_sfl = array('od_id');
if (!in_array($sfl, $allowed_sfl)) {
$sfl = 'od_id';
}
$sql_search = " where cart_id <> '0' ";
if ($stx) {
$sql_search .= " and ( ";
+393 -10
View File
@@ -113,8 +113,120 @@ if ($od['od_pg'] === 'nicepay' && $od['od_settle_case'] === '가상계좌' && $o
$print_od_deposit_name .= '_NICE';
}
if (!function_exists('shop_admin_get_nicepay_status')) {
function shop_admin_get_nicepay_status($tid, $default)
{
$result = array(
'data' => array(),
'error' => ''
);
if (!function_exists('curl_init')) {
$result['error'] = 'cURL 모듈이 설치되어 있지 않아 나이스페이 거래 상태를 조회할 수 없습니다.';
return $result;
}
$tid = preg_replace('/[^0-9a-zA-Z]/', '', (string) $tid);
if ($tid === '') {
$result['error'] = '거래 ID가 없어 나이스페이 거래 상태를 조회할 수 없습니다.';
return $result;
}
if (!empty($default['de_card_test'])) {
$mid = 'nicepay00m';
$merchantKey = 'EYzu8jGGMfqaDEp76gSckuvnaHHu+bC4opsSN6lHv3b2lurNYkVXrZ7Z1AoqQnXI3eLuaUFyoRNC6FkrzVjceg==';
} else {
$mid = 'SR'.$default['de_nicepay_mid'];
$merchantKey = $default['de_nicepay_key'];
}
if ($mid === 'SR' || $merchantKey === '') {
$result['error'] = '나이스페이 MID 또는 KEY가 설정되어 있지 않아 거래 상태를 조회할 수 없습니다.';
return $result;
}
$ediDate = preg_replace('/[^0-9]/', '', G5_TIME_YMDHIS);
$signData = bin2hex(hash('sha256', $tid.$mid.$ediDate.$merchantKey, true));
$postUrl = 'https://webapi.nicepay.co.kr/webapi/inquery/trans_status.jsp';
$data = array(
'TID' => $tid,
'MID' => $mid,
'EdiDate' => $ediDate,
'SignData' => $signData,
'CharSet' => 'utf-8',
'EdiType' => 'JSON'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $postUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
curl_setopt($ch, CURLOPT_TIMEOUT, 25);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_POST, true);
$response = curl_exec($ch);
$curl_error = curl_error($ch);
curl_close($ch);
if ($response === false || $response === '') {
$result['error'] = '나이스페이 거래 상태 조회 응답이 없습니다.'.($curl_error ? ' '.$curl_error : '');
return $result;
}
$responseData = json_decode($response, true);
if (!is_array($responseData)) {
$utf8_response = @iconv('EUC-KR', 'UTF-8//IGNORE', $response);
if ($utf8_response) {
$responseData = json_decode($utf8_response, true);
}
}
if (!is_array($responseData)) {
$result['error'] = '나이스페이 거래 상태 조회 응답을 해석할 수 없습니다.';
return $result;
}
$result['data'] = $responseData;
return $result;
}
}
if (!function_exists('shop_admin_format_nicepay_auth_date')) {
function shop_admin_format_nicepay_auth_date($auth_date)
{
$auth_date = preg_replace('/[^0-9]/', '', (string) $auth_date);
if (strlen($auth_date) === 12) {
return '20'.substr($auth_date, 0, 2).'-'.substr($auth_date, 2, 2).'-'.substr($auth_date, 4, 2).' '.substr($auth_date, 6, 2).':'.substr($auth_date, 8, 2).':'.substr($auth_date, 10, 2);
}
if (strlen($auth_date) === 14) {
return substr($auth_date, 0, 4).'-'.substr($auth_date, 4, 2).'-'.substr($auth_date, 6, 2).' '.substr($auth_date, 8, 2).':'.substr($auth_date, 10, 2).':'.substr($auth_date, 12, 2);
}
return $auth_date;
}
}
$nicepay_status_result = array();
$nicepay_status_error = '';
if ($od['od_pg'] === 'nicepay') {
$nicepay_status = shop_admin_get_nicepay_status($od['od_tno'], $default);
$nicepay_status_result = $nicepay_status['data'];
$nicepay_status_error = $nicepay_status['error'];
}
// add_javascript('js 구문', 출력순서); 숫자가 작을 수록 먼저 출력됨
add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
$is_nicepay_vbank_pg_cancel = ($od['od_pg'] === 'nicepay' && $od['od_settle_case'] === '가상계좌' && is_cancel_shop_pg_order($od));
if ($is_nicepay_vbank_pg_cancel) {
add_stylesheet('<link rel="stylesheet" href="'.G5_JS_URL.'/remodal/remodal.css">', 11);
add_stylesheet('<link rel="stylesheet" href="'.G5_JS_URL.'/remodal/remodal-default-theme.css">', 12);
add_javascript('<script src="'.G5_JS_URL.'/remodal/remodal.js"></script>', 10);
}
?>
<section id="anc_sodr_list">
@@ -144,6 +256,13 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
<input type="hidden" name="search" value="<?php echo $search; ?>">
<input type="hidden" name="page" value="<?php echo $page;?>">
<input type="hidden" name="pg_cancel" value="0">
<input type="hidden" name="submit_ct_status" value="">
<?php if ($is_nicepay_vbank_pg_cancel) { ?>
<input type="hidden" name="RefundAcctNo" value="">
<input type="hidden" name="RefundBankCd" value="">
<input type="hidden" name="RefundAcctNm" value="">
<input type="hidden" name="nicepay_vbank_refund_confirmed" value="0">
<?php } ?>
<div class="tbl_head01 tbl_wrap">
<table>
@@ -311,6 +430,52 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
} //end if
?>
<?php if ($od['od_pg'] === 'nicepay') { ?>
<section id="anc_sodr_nicepay_status">
<h2 class="h2_frm">나이스페이 결제 조회</h2>
<?php if ($nicepay_status_error) { ?>
<div class="local_desc01 local_desc">
<p><?php echo get_text($nicepay_status_error); ?></p>
</div>
<?php } else {
$nicepay_status_map = array(
'0' => '승인 상태',
'1' => '취소 상태',
'9' => '승인 거래 없음'
);
$nicepay_status_code = isset($nicepay_status_result['Status']) ? (string) $nicepay_status_result['Status'] : '';
$nicepay_status_text = isset($nicepay_status_map[$nicepay_status_code]) ? $nicepay_status_map[$nicepay_status_code] : '';
$nicepay_auth_date = isset($nicepay_status_result['AuthDate']) ? shop_admin_format_nicepay_auth_date($nicepay_status_result['AuthDate']) : '';
?>
<div class="tbl_head01 tbl_wrap">
<table>
<caption>나이스페이 결제 조회</caption>
<thead>
<tr>
<th scope="col">결과코드</th>
<th scope="col">결과 메시지</th>
<th scope="col">거래 ID</th>
<th scope="col">거래 상태</th>
<th scope="col">승인번호</th>
<th scope="col">승인일시</th>
</tr>
</thead>
<tbody>
<tr>
<td><?php echo isset($nicepay_status_result['ResultCode']) ? get_text($nicepay_status_result['ResultCode']) : '-'; ?></td>
<td><?php echo isset($nicepay_status_result['ResultMsg']) ? get_text($nicepay_status_result['ResultMsg']) : '-'; ?></td>
<td><?php echo isset($nicepay_status_result['TID']) ? get_text($nicepay_status_result['TID']) : get_text($od['od_tno']); ?></td>
<td><?php echo $nicepay_status_code !== '' ? get_text($nicepay_status_code.($nicepay_status_text ? ' ('.$nicepay_status_text.')' : '')) : '-'; ?></td>
<td><?php echo isset($nicepay_status_result['AuthCode']) && $nicepay_status_result['AuthCode'] !== '' ? get_text($nicepay_status_result['AuthCode']) : '-'; ?></td>
<td><?php echo $nicepay_auth_date !== '' ? get_text($nicepay_auth_date) : '-'; ?></td>
</tr>
</tbody>
</table>
</div>
<?php } ?>
</section>
<?php } ?>
<section id="anc_sodr_pay">
<h2 class="h2_frm">주문결제 내역</h2>
<?php echo $pg_anchor; ?>
@@ -332,7 +497,7 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
//$amount['미수'] = $amount['order'] - $amount['receipt'] - $amount['coupon'];
// 결제방법
$s_receipt_way = check_pay_name_replace($od['od_settle_case'], $od);
$s_receipt_way = get_text(check_pay_name_replace($od['od_settle_case'], $od));
if ($od['od_receipt_point'] > 0)
$s_receipt_way .= "+포인트";
@@ -409,7 +574,7 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
</tr>
<?php } ?>
<tr>
<th scope="row"><?php echo $od['od_settle_case']; ?> 입금액</th>
<th scope="row"><?php echo get_text($od['od_settle_case']); ?> 입금액</th>
<td><?php echo display_price($od['od_receipt_price']); ?></td>
</tr>
<tr>
@@ -432,7 +597,7 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
<td><?php echo get_text($od['od_bank_account']); ?></td>
</tr>
<tr>
<th scope="row"><?php echo $od['od_settle_case']; ?> 결제액</th>
<th scope="row"><?php echo get_text($od['od_settle_case']); ?> 결제액</th>
<td><?php echo display_price($od['od_receipt_price']); ?></td>
</tr>
<tr>
@@ -705,7 +870,7 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
<?php } ?>
<tr>
<th scope="row"><label for="od_receipt_price"><?php echo $od['od_settle_case']; ?> 입금액</label></th>
<th scope="row"><label for="od_receipt_price"><?php echo get_text($od['od_settle_case']); ?> 입금액</label></th>
<td>
<?php echo $html_receipt_chk; ?>
<input type="text" name="od_receipt_price" value="<?php echo $od['od_receipt_price']; ?>" id="od_receipt_price" class="frm_input"> 원
@@ -739,7 +904,7 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
<td><?php echo get_text($od['od_bank_account']); ?></td>
</tr>
<tr>
<th scope="row"><label for="od_receipt_price"><?php echo $od['od_settle_case']; ?> 결제액</label></th>
<th scope="row"><label for="od_receipt_price"><?php echo get_text($od['od_settle_case']); ?> 결제액</label></th>
<td>
<?php echo $html_receipt_chk; ?>
<input type="text" name="od_receipt_price" value="<?php echo $od['od_receipt_price']; ?>" id="od_receipt_price" class="frm_input"> 원
@@ -870,8 +1035,8 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
<?php if($od['od_status'] == '주문' && $od['od_misu'] > 0) { ?>
<a href="./personalpayform.php?popup=yes&amp;od_id=<?php echo $od_id; ?>" id="personalpay_add" class="btn btn_02">개인결제추가</a>
<?php } ?>
<?php if($od['od_misu'] < 0 && ($od['od_receipt_price'] - $od['od_refund_price']) > 0 && ($od['od_settle_case'] == '신용카드' || $od['od_settle_case'] == '계좌이체' || $od['od_settle_case'] == 'KAKAOPAY')) { ?>
<a href="./orderpartcancel.php?od_id=<?php echo $od_id; ?>" id="orderpartcancel" class="btn btn_02"><?php echo $od['od_settle_case']; ?> 부분취소</a>
<?php if($od['od_misu'] < 0 && ($od['od_receipt_price'] - $od['od_refund_price']) > 0 && ($od['od_settle_case'] == '신용카드' || $od['od_settle_case'] == '계좌이체' || $od['od_settle_case'] == 'KAKAOPAY' || ($od['od_pg'] == 'nicepay' && $od['od_settle_case'] == '간편결제'))) { ?>
<a href="./orderpartcancel.php?od_id=<?php echo $od_id; ?>" id="orderpartcancel" class="btn btn_02"><?php echo get_text($od['od_settle_case']); ?> 부분취소</a>
<?php } ?>
<a href="./orderlist.php?<?php echo $qstr; ?>" class="btn btn_02">목록</a>
</div>
@@ -1044,7 +1209,157 @@ add_javascript(G5_POSTCODE_JS, 0); //다음 주소 js
</form>
</section>
<?php if ($is_nicepay_vbank_pg_cancel) {
$nicepay_refund_bank_codes = array(
'은행/기관' => array(
'001' => '한국은행',
'002' => '산업은행',
'003' => '기업은행',
'004' => '국민은행',
'005' => '외환은행',
'007' => '수협은행',
'008' => '수출입은행',
'011' => 'NH농협은행',
'012' => '농협중앙회(지역농축협)',
'020' => '우리은행',
'023' => 'SC제일은행',
'026' => '서울은행',
'027' => '한국씨티은행',
'030' => '수협중앙회',
'031' => 'iM뱅크(대구)',
'032' => '부산은행',
'034' => '광주은행',
'035' => '제주은행',
'037' => '전북은행',
'039' => '경남은행',
'045' => '새마을금고',
'048' => '신협',
'050' => '저축은행',
'051' => '기타 외국계은행',
'052' => '모건스탠리은행',
'054' => 'HSBC은행',
'055' => '도이치은행',
'056' => '알비에스피엘씨은행',
'057' => '제이피모간체이스은행',
'058' => '미즈호은행',
'059' => '엠유에프지은행',
'060' => 'BOA은행',
'061' => '비엔피파리바은행',
'062' => '중국공상은행',
'063' => '중국은행',
'064' => '산림조합중앙회',
'065' => '대화은행',
'071' => '우체국',
'076' => '신용보증기금',
'077' => '기술보증기금',
'081' => '하나은행',
'088' => '신한은행',
'089' => '케이뱅크',
'090' => '카카오뱅크',
'092' => '토스뱅크',
'093' => '한국주택금융공사',
'094' => '서울보증보험',
'095' => '경찰청',
'099' => '금융결제원'
),
'증권사' => array(
'209' => '유안타증권',
'218' => 'KB증권',
'238' => '미래에셋증권',
'240' => '삼성증권',
'243' => '한국투자증권',
'247' => 'NH투자증권',
'261' => '교보증권',
'262' => 'iM증권',
'263' => '현대차증권',
'264' => '키움증권',
'265' => 'LS증권',
'266' => '에스케이증권',
'267' => '대신증권',
'269' => '한화투자증권',
'270' => '하나증권',
'271' => '토스증권',
'278' => '신한투자증권',
'279' => 'DB증권',
'280' => '유진투자증권',
'287' => '메리츠증권',
'288' => '카카오페이증권',
'289' => '엔에이치투자증권',
'290' => '부국증권',
'291' => '신영증권',
'292' => '케이프투자증권'
)
);
?>
<div class="remodal" data-remodal-id="nicepay-vbank-refund" data-remodal-options="hashTracking:false, closeOnOutsideClick:false">
<button data-remodal-action="close" class="remodal-close"></button>
<h3>나이스페이 가상계좌 환불 정보</h3>
<p>입금 후 환불 건은 환불계좌 정보를 입력해야 합니다. 입금 전 발급취소 건은 비워두고 진행할 수 있습니다.</p>
<div class="tbl_frm01 tbl_wrap">
<table>
<caption>나이스페이 가상계좌 환불 정보 입력</caption>
<colgroup>
<col class="grid_4">
<col>
</colgroup>
<tbody>
<tr>
<th scope="row"><label for="nicepay_refund_acct_no">환불계좌번호</label></th>
<td><input type="text" id="nicepay_refund_acct_no" class="frm_input" size="22" maxlength="16" inputmode="numeric" autocomplete="off"> 숫자만 입력</td>
</tr>
<tr>
<th scope="row"><label for="nicepay_refund_bank_cd">환불은행</label></th>
<td>
<select id="nicepay_refund_bank_cd" class="frm_input">
<option value="">은행을 선택해 주세요</option>
<?php foreach ($nicepay_refund_bank_codes as $bank_group => $bank_codes) { ?>
<optgroup label="<?php echo $bank_group; ?>">
<?php foreach ($bank_codes as $bank_code => $bank_name) { ?>
<option value="<?php echo $bank_code; ?>"><?php echo $bank_name; ?> (<?php echo $bank_code; ?>)</option>
<?php } ?>
</optgroup>
<?php } ?>
</select>
</td>
</tr>
<tr>
<th scope="row"><label for="nicepay_refund_acct_nm">환불계좌주명</label></th>
<td><input type="text" id="nicepay_refund_acct_nm" class="frm_input" size="18" maxlength="10" autocomplete="off"> 10 byte 이하</td>
</tr>
</tbody>
</table>
</div>
<br>
<button type="button" class="remodal-cancel" data-remodal-action="cancel">취소</button>
<button type="button" class="remodal-confirm" id="nicepay_vbank_refund_submit">확인</button>
</div>
<?php } ?>
<script>
<?php if ($is_nicepay_vbank_pg_cancel) { ?>
var nicepayVbankCancel = true;
var nicepayVbankRefundRequired = <?php echo ((int) $od['od_receipt_price'] > 0) ? 'true' : 'false'; ?>;
<?php } else { ?>
var nicepayVbankCancel = false;
var nicepayVbankRefundRequired = false;
<?php } ?>
function nicepay_submit_orderform(f)
{
var status = document.pressed || (f.submit_ct_status ? f.submit_ct_status.value : "");
var statusInput = f.querySelector("input[type=hidden][name=ct_status]");
if (!statusInput) {
statusInput = document.createElement("input");
statusInput.type = "hidden";
statusInput.name = "ct_status";
f.appendChild(statusInput);
}
statusInput.value = status;
f.submit();
}
$(function() {
// 전체 옵션선택
$("#sit_select_all").click(function() {
@@ -1080,12 +1395,70 @@ $(function() {
window.open(href, "partcancelwin", "left=100, top=100, width=600, height=350, scrollbars=yes");
return false;
});
$("#nicepay_refund_acct_no").on("input", function() {
this.value = this.value.replace(/[^0-9]/g, "");
});
$("#nicepay_vbank_refund_submit").on("click", function() {
var f = document.frmorderform;
var acctNo = $.trim($("#nicepay_refund_acct_no").val()).replace(/[^0-9]/g, "");
var bankCd = $.trim($("#nicepay_refund_bank_cd").val()).replace(/[^0-9]/g, "");
var acctNm = $.trim($("#nicepay_refund_acct_nm").val());
var hasRefundInfo = (acctNo !== "" || bankCd !== "" || acctNm !== "");
if (!nicepayVbankRefundRequired && !hasRefundInfo) {
f.RefundAcctNo.value = "";
f.RefundBankCd.value = "";
f.RefundAcctNm.value = "";
f.nicepay_vbank_refund_confirmed.value = 1;
if (form_submit(f)) {
nicepay_submit_orderform(f);
}
return false;
}
if (acctNo === "" || acctNo.length > 16) {
alert("환불계좌번호를 숫자 16자리 이하로 입력해 주십시오.");
$("#nicepay_refund_acct_no").focus();
return false;
}
if (!/^[0-9]{3}$/.test(bankCd)) {
alert("환불은행을 선택해 주십시오.");
$("#nicepay_refund_bank_cd").focus();
return false;
}
if (acctNm === "") {
alert("환불계좌주명을 입력해 주십시오.");
$("#nicepay_refund_acct_nm").focus();
return false;
}
f.RefundAcctNo.value = acctNo;
f.RefundBankCd.value = bankCd;
f.RefundAcctNm.value = acctNm;
f.nicepay_vbank_refund_confirmed.value = 1;
if (form_submit(f)) {
nicepay_submit_orderform(f);
}
return false;
});
});
function form_submit(f)
{
var check = false;
var status = document.pressed;
var status = document.pressed || (f.submit_ct_status ? f.submit_ct_status.value : "");
if (f.submit_ct_status) {
f.submit_ct_status.value = status;
}
for (i=0; i<f.chk_cnt.value; i++) {
if (document.getElementById('ct_chk_'+i).checked == true)
@@ -1107,7 +1480,7 @@ function form_submit(f)
<?php if($od['od_pg'] == 'KAKAOPAY') { ?>
var cancel_pg = "카카오페이";
<?php } else { ?>
var cancel_pg = "PG사의 <?php echo $od['od_settle_case']; ?>";
var cancel_pg = "PG사의 <?php echo get_text($od['od_settle_case']); ?>";
<?php } ?>
// 체크하지 않은 나머지 품목이 모두 취소류 상태이면 이번 처리로 주문 전체가 취소된다.
@@ -1117,9 +1490,16 @@ function form_submit(f)
}).length;
if(chked_cnt > 0 && remain_active_cnt == 0) {
if(confirm(cancel_pg+" 결제를 함께 취소하시겠습니까?\n\n한번 취소한 결제는 다시 복구할 수 없습니다.")) {
if(nicepayVbankCancel && f.nicepay_vbank_refund_confirmed.value == "1") {
f.pg_cancel.value = 1;
msg = cancel_pg+" 결제 취소와 함께 ";
} else if(confirm(cancel_pg+" 결제를 함께 취소하시겠습니까?\n\n한번 취소한 결제는 다시 복구할 수 없습니다.")) {
f.pg_cancel.value = 1;
msg = cancel_pg+" 결제 취소와 함께 ";
if (nicepayVbankCancel && f.nicepay_vbank_refund_confirmed.value != "1") {
$('[data-remodal-id=nicepay-vbank-refund]').remodal().open();
return false;
}
} else {
f.pg_cancel.value = 0;
msg = "";
@@ -1131,6 +1511,9 @@ function form_submit(f)
if (confirm(msg+"\'" + status + "\' 상태를 선택하셨습니다.\n\n선택하신대로 처리하시겠습니까?")) {
return true;
} else {
if (nicepayVbankCancel && f.nicepay_vbank_refund_confirmed) {
f.nicepay_vbank_refund_confirmed.value = 0;
}
return false;
}
}
+56 -7
View File
@@ -6,6 +6,16 @@ auth_check_menu($auth, $sub_menu, "w");
check_admin_token();
$od_id = isset($_POST['od_id']) ? safe_replace_regex($_POST['od_id'], 'od_id') : '';
$ct_status = isset($_POST['ct_status']) ? clean_xss_tags($_POST['ct_status'], 1, 1) : '';
if ($ct_status === '' && isset($_POST['submit_ct_status'])) {
$ct_status = clean_xss_tags($_POST['submit_ct_status'], 1, 1);
}
$pg_cancel = isset($_POST['pg_cancel']) ? (int) $_POST['pg_cancel'] : 0;
$nicepay_refund_acct_no = isset($_POST['RefundAcctNo']) ? preg_replace('/[^0-9]/', '', $_POST['RefundAcctNo']) : '';
$nicepay_refund_bank_cd = isset($_POST['RefundBankCd']) ? preg_replace('/[^0-9]/', '', $_POST['RefundBankCd']) : '';
$nicepay_refund_acct_nm = isset($_POST['RefundAcctNm']) ? trim(clean_xss_tags($_POST['RefundAcctNm'], 1, 1)) : '';
$ct_chk_count = isset($_POST['ct_chk']) ? count($_POST['ct_chk']) : 0;
if(!$ct_chk_count)
alert('처리할 자료를 하나 이상 선택해 주십시오.');
@@ -13,7 +23,7 @@ if(!$ct_chk_count)
$status_normal = array('주문','입금','준비','배송','완료');
$status_cancel = array('취소','반품','품절');
if (in_array($_POST['ct_status'], $status_normal) || in_array($_POST['ct_status'], $status_cancel)) {
if (in_array($ct_status, $status_normal) || in_array($ct_status, $status_cancel)) {
; // 통과
} else {
alert('변경할 상태가 올바르지 않습니다.');
@@ -146,6 +156,38 @@ if (in_array($_POST['ct_status'], $status_cancel)) {
}
}
if ($pg_cancel === 1 && in_array($ct_status, $status_cancel)) {
$nicepay_refund_order = sql_fetch(" select od_id, od_pg, od_settle_case, od_status, od_receipt_price from {$g5['g5_shop_order_table']} where od_id = '$od_id' ");
if (isset($nicepay_refund_order['od_id']) && $nicepay_refund_order['od_pg'] === 'nicepay' && $nicepay_refund_order['od_settle_case'] === '가상계좌' && is_cancel_shop_pg_order($nicepay_refund_order)) {
$nicepay_refund_required = ((int) $nicepay_refund_order['od_receipt_price'] > 0);
$nicepay_refund_inputted = ($nicepay_refund_acct_no !== '' || $nicepay_refund_bank_cd !== '' || $nicepay_refund_acct_nm !== '');
if (!$nicepay_refund_required && !$nicepay_refund_inputted) {
$nicepay_refund_acct_no = '';
$nicepay_refund_bank_cd = '';
$nicepay_refund_acct_nm = '';
} else {
if ($nicepay_refund_acct_no === '' || strlen($nicepay_refund_acct_no) > 16) {
alert('나이스페이 가상계좌 취소를 위해 환불계좌번호를 숫자 16자리 이하로 입력해 주십시오.');
}
if (!preg_match('/^[0-9]{3}$/', $nicepay_refund_bank_cd)) {
alert('나이스페이 가상계좌 취소를 위해 환불계좌코드를 숫자 3자리로 입력해 주십시오.');
}
if ($nicepay_refund_acct_nm === '') {
alert('나이스페이 가상계좌 취소를 위해 환불계좌주명을 입력해 주십시오.');
}
$nicepay_refund_acct_nm_euckr = function_exists('iconv') ? @iconv('UTF-8', 'EUC-KR//IGNORE', $nicepay_refund_acct_nm) : $nicepay_refund_acct_nm;
if (strlen($nicepay_refund_acct_nm_euckr) > 10) {
alert('나이스페이 환불계좌주명은 10 byte 이하로 입력해 주십시오.');
}
}
}
}
$search = isset($_REQUEST['search']) ? get_search_string($_REQUEST['search']) : '';
$sort1 = isset($_REQUEST['sort1']) ? clean_xss_tags($_REQUEST['sort1'], 1, 1) : '';
$sort2 = isset($_REQUEST['sort2']) ? clean_xss_tags($_REQUEST['sort2'], 1, 1) : '';
@@ -299,7 +341,7 @@ if(is_array($arr_it_id) && !empty($arr_it_id)) {
// 장바구니 상품 모두 취소일 경우 주문상태 변경
$cancel_change = false;
if (in_array($_POST['ct_status'], $status_cancel)) {
if (in_array($ct_status, $status_cancel)) {
$sql = " select count(*) as od_count1,
SUM(IF(ct_status = '취소' OR ct_status = '반품' OR ct_status = '품절', 1, 0)) as od_count2
from {$g5['g5_shop_cart_table']}
@@ -385,17 +427,24 @@ if (in_array($_POST['ct_status'], $status_cancel)) {
$tno = $od['od_tno'];
$cancelAmt = $od['od_receipt_price'];
$cancelAmt = (int)$od['od_receipt_price'];
if($od['od_settle_case'] == '가상계좌' && $od['od_status'] == '주문' && $cancelAmt == 0)
$cancelAmt = (int)$od['od_misu'];
// 0:전체 취소, 1:부분 취소(별도 계약 필요)
$partialCancelCode = 0;
if($cancelAmt <= 0) {
$pg_res_cd = 'NO_CANCEL_AMT';
$pg_res_msg = '취소 요청금액이 없습니다.';
break;
}
include G5_SHOP_PATH.'/nicepay/cancel_process.php';
if (isset($result['ResultCode'])) {
// 실패했다면
if ($result['ResultCode'] !== '2001') {
if (! in_array($result['ResultCode'], array('2001', '2211'), true)) {
$pg_res_cd = $result['ResultCode'];
$pg_res_msg = $result['ResultMsg'];
}
@@ -467,7 +516,7 @@ if (in_array($_POST['ct_status'], $status_cancel)) {
}
// 관리자 주문취소 로그
$mod_history .= G5_TIME_YMDHIS.' '.$member['mb_id'].' 주문'.$_POST['ct_status'].' 처리'.$pg_cancel_log."\n";
$mod_history .= G5_TIME_YMDHIS.' '.$member['mb_id'].' 주문'.$ct_status.' 처리'.$pg_cancel_log."\n";
}
}
@@ -495,8 +544,8 @@ if ($mod_history) { // 주문변경 히스토리 기록
if($cancel_change) {
$sql .= " , od_status = '취소' "; // 주문상품 모두 취소, 반품, 품절이면 주문 취소
} else {
if (isset($_POST['ct_status']) && in_array($_POST['ct_status'], $status_normal)) { // 정상인 주문상태만 기록
$sql .= " , od_status = '{$_POST['ct_status']}' ";
if ($ct_status && in_array($ct_status, $status_normal)) { // 정상인 주문상태만 기록
$sql .= " , od_status = '$ct_status' ";
}
}
+2 -2
View File
@@ -305,7 +305,7 @@ if( function_exists('pg_setting_check') ){
$s_receipt_way = $s_br = "";
if ($row['od_settle_case'])
{
$s_receipt_way = check_pay_name_replace($row['od_settle_case'], $row);
$s_receipt_way = get_text(check_pay_name_replace($row['od_settle_case'], $row));
$s_br = '<br />';
}
else
@@ -402,7 +402,7 @@ if( function_exists('pg_setting_check') ){
<?php echo $row['od_status']; ?>
</td>
<td headers="odrpay" class="odrpay">
<input type="hidden" name="current_settle_case[<?php echo $i ?>]" value="<?php echo $row['od_settle_case'] ?>">
<input type="hidden" name="current_settle_case[<?php echo $i ?>]" value="<?php echo get_text($row['od_settle_case']) ?>">
<?php echo $s_receipt_way; ?>
</td>
<td headers="delino" class="delino">
+7 -6
View File
@@ -21,7 +21,7 @@ if($od['od_settle_case'] == '계좌이체' && substr($od['od_receipt_time'], 0,
if($od['od_receipt_price'] - $od['od_refund_price'] <= 0)
alert_close('부분취소 처리할 금액이 없습니다.');
$g5['title'] = $od['od_settle_case'].' 부분취소';
$g5['title'] = get_text($od['od_settle_case']).' 부분취소';
include_once(G5_PATH.'/head.sub.php');
// 취소가능금액
@@ -29,10 +29,11 @@ $od_misu = abs($od['od_misu']);
?>
<form name="forderpartcancel" method="post" action="./orderpartcancelupdate.php" onsubmit="return form_check(this);">
<input type="hidden" name="token" value="<?php echo get_admin_token(); ?>">
<input type="hidden" name="od_id" value="<?php echo $od_id; ?>">
<div class="new_win">
<h1><?php echo $od['od_settle_case']; ?> 부분취소</h1>
<h1><?php echo get_text($od['od_settle_case']); ?> 부분취소</h1>
<div class="tbl_frm01 tbl_wrap">
<table>
@@ -78,10 +79,10 @@ var g5_admin_csrf_token_key = "<?php echo (function_exists('admin_csrf_token_key
function form_check(f)
{
var max_mny = parseInt(<?php echo $od_misu; ?>);
var tax_mny = parseInt(f.mod_tax_mny.value.replace("/[^0-9]/g", ""));
var tax_mny = parseInt(f.mod_tax_mny.value.replace(/[^0-9]/g, ""), 10) || 0;
var free_mny = 0;
if(typeof f.mod_free_mny.value != "undefined")
free_mny = parseInt(f.mod_free_mny.value.replace("/[^0-9]/g", ""));
if(typeof f.mod_free_mny != "undefined")
free_mny = parseInt(f.mod_free_mny.value.replace(/[^0-9]/g, ""), 10) || 0;
if(!tax_mny && !free_mny) {
alert("과세 취소금액 또는 비과세 취소금액을 입력해 주십시오.");
@@ -108,4 +109,4 @@ function form_check(f)
</script>
<?php
include_once(G5_PATH.'/tail.sub.php');
include_once(G5_PATH.'/tail.sub.php');
+4 -2
View File
@@ -6,6 +6,8 @@ auth_check_menu($auth, $sub_menu, "w");
check_admin_token();
$od_id = isset($_POST['od_id']) ? safe_replace_regex($_POST['od_id'], 'od_id') : '';
$mod_memo = isset($_POST['mod_memo']) ? trim(clean_xss_tags($_POST['mod_memo'], 1, 1)) : '';
$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;
@@ -44,10 +46,10 @@ include_once(G5_PATH.'/head.sub.php');
?>
<script>
alert("<?php echo $od['od_settle_case']; ?> 부분취소 처리됐습니다.");
alert("<?php echo get_text($od['od_settle_case']); ?> 부분취소 처리됐습니다.");
opener.document.location.reload();
self.close();
</script>
<?php
include_once(G5_PATH.'/tail.sub.php');
include_once(G5_PATH.'/tail.sub.php');
+5
View File
@@ -6,6 +6,11 @@ auth_check_menu($auth, $sub_menu, "r");
$sql_common = " from {$g5['g5_shop_personalpay_table']} ";
$allowed_sfl = array('pp_id', 'pp_name', 'od_id');
if (!in_array($sfl, $allowed_sfl)) {
$sfl = 'pp_id';
}
$sql_search = " where (1) ";
if ($stx) {
$sql_search .= " and ( ";
+2 -1
View File
@@ -9,7 +9,8 @@ if (G5_IS_MOBILE) {
} else {
// 상단 파일 경로를 입력하지 않았다면 기본 상단 파일도 include 하지 않음
if (trim($board['bo_include_head'])) {
if (is_include_path_check($board['bo_include_head'])) { //파일경로 체크
if (is_include_path_check($board['bo_include_head'])
&& (!function_exists('is_content_include_allowed') || is_content_include_allowed($board['bo_include_head']))) { //파일경로 체크
@include ($board['bo_include_head']);
} else { //파일경로가 올바르지 않으면 기본파일을 가져옴
include_once(G5_BBS_PATH.'/_head.php');
+2 -1
View File
@@ -10,7 +10,8 @@ if (G5_IS_MOBILE) {
echo run_replace('board_content_tail', html_purifier(stripslashes($board['bo_content_tail'])), $board);
// 하단 파일 경로를 입력하지 않았다면 기본 하단 파일도 include 하지 않음
if (trim($board['bo_include_tail'])) {
if (is_include_path_check($board['bo_include_tail'])) { //파일경로 체크
if (is_include_path_check($board['bo_include_tail'])
&& (!function_exists('is_content_include_allowed') || is_content_include_allowed($board['bo_include_tail']))) { //파일경로 체크
@include ($board['bo_include_tail']);
} else { //파일경로가 올바르지 않으면 기본파일을 가져옴
include_once(G5_BBS_PATH.'/_tail.php');
+4 -2
View File
@@ -31,7 +31,8 @@ if (! (isset($co['co_id']) && $co['co_id']))
$g5['title'] = $co['co_subject'];
if ($co['co_include_head'] && is_include_path_check($co['co_include_head']))
if ($co['co_include_head'] && is_include_path_check($co['co_include_head'])
&& (!function_exists('is_content_include_allowed') || is_content_include_allowed($co['co_include_head'])))
@include_once($co['co_include_head']);
else
include_once('./_head.php');
@@ -99,7 +100,8 @@ if(is_file($skin_file)) {
echo '<p>'.str_replace(G5_PATH.'/', '', $skin_file).'이 존재하지 않습니다.</p>';
}
if ($co['co_include_tail'] && is_include_path_check($co['co_include_tail']))
if ($co['co_include_tail'] && is_include_path_check($co['co_include_tail'])
&& (!function_exists('is_content_include_allowed') || is_content_include_allowed($co['co_include_tail'])))
@include_once($co['co_include_tail']);
else
include_once('./_tail.php');
+1 -1
View File
@@ -18,7 +18,7 @@ for ($i=0; $row=sql_fetch_array($result); $i++) {
if ($row['mb_id']) {
$list[$i]['name'] = get_sideview($row['mb_id'], cut_str($row['mb_nick'], $config['cf_cut_name']), $row['mb_email'], $row['mb_homepage']);
} else {
if ($is_admin)
if ($is_admin === 'super')
$list[$i]['name'] = $row['lo_ip'];
else
$list[$i]['name'] = preg_replace("/([0-9]+).([0-9]+).([0-9]+).([0-9]+)/", G5_IP_DISPLAY, $row['lo_ip']);
+16 -3
View File
@@ -28,9 +28,22 @@ if (!preg_match("/([0-9a-zA-Z_-]+)@([0-9a-zA-Z_-]+)\.([0-9a-zA-Z_-]+)/", $to)){
}
$file = array();
// 첨부파일을 이동하기 전에 모든 파일명을 먼저 확인한다.
for ($i=1; $i<=$attach; $i++) {
if ($_FILES['file'.$i]['name'])
$file[] = attach_file($_FILES['file'.$i]['name'], $_FILES['file'.$i]['tmp_name']);
$file_key = 'file'.$i;
if (isset($_FILES[$file_key]['name']) && $_FILES[$file_key]['name']) {
$filename = get_safe_filename($_FILES[$file_key]['name']);
if (is_disallowed_svg_filename($filename)) {
alert_close('허용되지 않는 파일 확장자입니다. (svg, svgz)');
}
}
}
for ($i=1; $i<=$attach; $i++) {
$file_key = 'file'.$i;
if (isset($_FILES[$file_key]['name']) && $_FILES[$file_key]['name'])
$file[] = attach_file($_FILES[$file_key]['name'], $_FILES[$file_key]['tmp_name']);
}
$content = stripslashes($content);
@@ -78,4 +91,4 @@ include_once(G5_PATH.'/head.sub.php');
alert_close('메일을 정상적으로 발송하였습니다.');
include_once(G5_PATH.'/tail.sub.php');
include_once(G5_PATH.'/tail.sub.php');
+2 -1
View File
@@ -61,7 +61,8 @@ else if ($w == 'd')
if ($member['mb_id'] || $is_admin == 'super')
{
$sql = " delete from {$g5['poll_etc_table']} where pc_id = '{$pc_id}' ";
if (!$is_admin)
// 최고관리자가 아니면 본인 기타의견만 삭제 (게시판/그룹 관리자 문맥으로 우회 불가)
if ($is_admin !== 'super')
$sql .= " and mb_id = '{$member['mb_id']}' ";
sql_query($sql);
}
+3 -1
View File
@@ -1,6 +1,8 @@
<?php
include_once('./_common.php');
$is_admin = get_super_admin_type($is_admin);
if($is_guest)
alert('회원이시라면 로그인 후 이용해 주십시오.', G5_URL);
@@ -93,4 +95,4 @@ for($i=0; $i<$count; $i++) {
*/
run_event('qa_delete', $tmp_array, $deleted);
goto_url(G5_BBS_URL.'/qalist.php'.preg_replace('/^&amp;/', '?', $qstr));
goto_url(G5_BBS_URL.'/qalist.php'.preg_replace('/^&amp;/', '?', $qstr));
+18 -2
View File
@@ -1,6 +1,8 @@
<?php
include_once('./_common.php');
$is_admin = get_super_admin_type($is_admin);
// clean the output buffer
ob_end_clean();
@@ -11,11 +13,25 @@ $no = isset($_REQUEST['no']) ? (int) $_REQUEST['no'] : 0;
if (!get_session('ss_qa_view_'.$qa_id))
alert('잘못된 접근입니다.');
$sql = " select qa_subject, qa_file{$no}, qa_source{$no} from {$g5['qa_content_table']} where qa_id = '$qa_id' ";
$sql = " select qa_subject, mb_id, qa_type, qa_parent, qa_file{$no}, qa_source{$no} from {$g5['qa_content_table']} where qa_id = '$qa_id' ";
$file = sql_fetch($sql);
if (!$file['qa_file'.$no])
alert_close('파일 정보가 존재하지 않습니다.');
// 세션 표식만으로는 권한을 보장하지 못하므로 문의 스레드의 실제 소유자를 다시 확인
if ($is_admin !== 'super') {
if ($file['qa_type']) {
// 답변 첨부는 부모 질문의 소유자를 기준으로 판정
$parent = sql_fetch(" select mb_id from {$g5['qa_content_table']} where qa_id = '{$file['qa_parent']}' ");
$thread_owner = isset($parent['mb_id']) ? $parent['mb_id'] : '';
} else {
$thread_owner = $file['mb_id'];
}
if (! ($is_member && $thread_owner !== '' && $thread_owner === $member['mb_id']))
alert('다운로드 권한이 없습니다.');
}
if($is_guest) {
alert('다운로드 권한이 없습니다.\\n회원이시라면 로그인 후 이용해 보십시오.', G5_BBS_URL.'/login.php?url='.urlencode(G5_BBS_URL.'/qaview.php?qa_id='.$qa_id));
}
@@ -71,4 +87,4 @@ while(!feof($fp)) {
usleep(1000);
}
fclose ($fp);
flush();
flush();
+2 -1
View File
@@ -9,7 +9,8 @@ if (G5_IS_MOBILE) {
include_once('./_head.php');
echo run_replace('qa_mobile_content_head', conv_content($qaconfig['qa_mobile_content_head'], 1), $qaconfig);
} else {
if($qaconfig['qa_include_head'] && is_include_path_check($qaconfig['qa_include_head']))
if($qaconfig['qa_include_head'] && is_include_path_check($qaconfig['qa_include_head'])
&& (!function_exists('is_content_include_allowed') || is_content_include_allowed($qaconfig['qa_include_head'])))
@include ($qaconfig['qa_include_head']);
else
include ('./_head.php');
+8 -5
View File
@@ -1,13 +1,15 @@
<?php
include_once('./_common.php');
$is_admin = get_super_admin_type($is_admin);
if($is_guest)
alert('회원이시라면 로그인 후 이용해 보십시오.', './login.php?url='.urlencode(G5_BBS_URL.'/qalist.php'));
$qaconfig = get_qa_config();
$token = '';
if( $is_admin ){
if($is_admin === 'super') {
$token = _token();
set_session('ss_qa_delete_token', $token);
}
@@ -16,7 +18,7 @@ $g5['title'] = $qaconfig['qa_title'];
include_once('./qahead.php');
$skin_file = $qa_skin_path.'/list.skin.php';
$is_auth = $is_admin ? true : false;
$is_auth = ($is_admin === 'super');
$category_option = '';
@@ -47,7 +49,8 @@ if(is_file($skin_file)) {
$sql_common = " from {$g5['qa_content_table']} ";
$sql_search = " where qa_type = '0' ";
if(!$is_admin)
// 최고관리자가 아니면 본인 문의만 조회 (게시판/그룹 관리자 문맥으로 우회 불가)
if($is_admin !== 'super')
$sql_search .= " and mb_id = '{$member['mb_id']}' ";
if($sca) {
@@ -131,7 +134,7 @@ if(is_file($skin_file)) {
$is_checkbox = false;
$admin_href = '';
if($is_admin) {
if($is_admin === 'super') {
$is_checkbox = true;
$admin_href = G5_ADMIN_URL.'/qa_config.php';
}
@@ -147,4 +150,4 @@ if(is_file($skin_file)) {
echo '<div>'.str_replace(G5_PATH.'/', '', $skin_file).'이 존재하지 않습니다.</div>';
}
include_once('./qatail.php');
include_once('./qatail.php');
+2 -1
View File
@@ -7,7 +7,8 @@ if (G5_IS_MOBILE) {
include_once('./_tail.php');
} else {
echo run_replace('qa_content_tail', conv_content($qaconfig['qa_content_tail'], 1), $qaconfig);
if($qaconfig['qa_include_tail'] && is_include_path_check($qaconfig['qa_include_tail']))
if($qaconfig['qa_include_tail'] && is_include_path_check($qaconfig['qa_include_tail'])
&& (!function_exists('is_content_include_allowed') || is_content_include_allowed($qaconfig['qa_include_tail'])))
@include ($qaconfig['qa_include_tail']);
else
include ('./_tail.php');
+7 -5
View File
@@ -2,6 +2,8 @@
include_once('./_common.php');
include_once(G5_EDITOR_LIB);
$is_admin = get_super_admin_type($is_admin);
$qa_id = isset($_REQUEST['qa_id']) ? (int) $_REQUEST['qa_id'] : 0;
if($is_guest)
@@ -21,7 +23,7 @@ $skin_file = $qa_skin_path.'/view.skin.php';
if(is_file($skin_file)) {
$sql = " select * from {$g5['qa_content_table']} where qa_id = '$qa_id' ";
if(!$is_admin) {
if($is_admin !== 'super') {
$sql .= " and mb_id = '{$member['mb_id']}' ";
}
@@ -50,7 +52,7 @@ if(is_file($skin_file)) {
$sql = " select qa_id, qa_subject
from {$g5['qa_content_table']}
where qa_type = '0' ";
if(!$is_admin) {
if($is_admin !== 'super') {
$sql .= " and mb_id = '{$member['mb_id']}' ";
}
@@ -115,7 +117,7 @@ if(is_file($skin_file)) {
}
*/
if(($view['qa_type'] && $is_admin) || (!$view['qa_type'] && $view['qa_status'] == 0)) {
if(($view['qa_type'] && $is_admin === 'super') || (!$view['qa_type'] && $view['qa_status'] == 0)) {
$update_href = G5_BBS_URL.'/qawrite.php?w=u&amp;qa_id='.$view['qa_id'].$qstr;
$delete_href = G5_BBS_URL.'/qadelete.php?qa_id='.$view['qa_id'].'&amp;token='.$token.$qstr;
}
@@ -131,7 +133,7 @@ if(is_file($skin_file)) {
and qa_parent = '{$view['qa_id']}' ";
$answer = sql_fetch($sql);
if($is_admin) {
if($is_admin === 'super') {
$answer_update_href = G5_BBS_URL.'/qawrite.php?w=u&amp;qa_id='.$answer['qa_id'].$qstr;
$answer_delete_href = G5_BBS_URL.'/qadelete.php?qa_id='.$answer['qa_id'].'&amp;token='.$token.$qstr;
}
@@ -216,4 +218,4 @@ if(is_file($skin_file)) {
echo '<div>'.str_replace(G5_PATH.'/', '', $skin_file).'이 존재하지 않습니다.</div>';
}
include_once('./qatail.php');
include_once('./qatail.php');
+7 -5
View File
@@ -2,6 +2,8 @@
include_once('./_common.php');
include_once(G5_EDITOR_LIB);
$is_admin = get_super_admin_type($is_admin);
if($w != '' && $w != 'u' && $w != 'r') {
alert('올바른 방법으로 이용해 주십시오.');
}
@@ -30,7 +32,7 @@ if(is_file($skin_file)) {
if($w == 'u' || $w == 'r') {
$sql = " select * from {$g5['qa_content_table']} where qa_id = '$qa_id' ";
if(!$is_admin) {
if($is_admin !== 'super') {
$sql .= " and mb_id = '{$member['mb_id']}' ";
}
@@ -40,7 +42,7 @@ if(is_file($skin_file)) {
if(!$write['qa_id'])
alert('게시글이 존재하지 않습니다.\\n삭제되었거나 자신의 글이 아닌 경우입니다.');
if(!$is_admin) {
if($is_admin !== 'super') {
if($write['qa_type'] == 0 && $write['qa_status'] == 1)
alert('답변이 등록된 문의글은 수정할 수 없습니다.');
@@ -117,7 +119,7 @@ if(is_file($skin_file)) {
if($w == '' || $w == 'r')
$write['qa_email'] = $member['mb_email'];
if($w == 'u' && $is_admin && $write['qa_type'])
if($w == 'u' && $is_admin === 'super' && $write['qa_type'])
$is_email = false;
}
@@ -132,7 +134,7 @@ if(is_file($skin_file)) {
if($w == '' || $w == 'r')
$write['qa_hp'] = $member['mb_hp'];
if($w == 'u' && $is_admin && $write['qa_type'])
if($w == 'u' && $is_admin === 'super' && $write['qa_type'])
$is_hp = false;
}
@@ -145,4 +147,4 @@ if(is_file($skin_file)) {
echo '<div>'.str_replace(G5_PATH.'/', '', $skin_file).'이 존재하지 않습니다.</div>';
}
include_once('./qatail.php');
include_once('./qatail.php');
+17 -5
View File
@@ -1,6 +1,8 @@
<?php
include_once('./_common.php');
$is_admin = get_super_admin_type($is_admin);
/*==========================
$w == a : 답변
$w == r : 추가질문
@@ -98,11 +100,12 @@ for ($i=1; $i<=5; $i++) {
}
if($w == 'u' || $w == 'a' || $w == 'r') {
if($w == 'a' && !$is_admin)
if($w == 'a' && $is_admin !== 'super')
alert('답변은 관리자만 등록할 수 있습니다.');
$sql = " select * from {$g5['qa_content_table']} where qa_id = '$qa_id' ";
if(!$is_admin) {
// 최고관리자가 아니면 본인 문의만 대상으로 (게시판/그룹 관리자 문맥으로 우회 불가)
if($is_admin !== 'super') {
$sql .= " and mb_id = '{$member['mb_id']}' ";
}
@@ -112,7 +115,7 @@ if($w == 'u' || $w == 'a' || $w == 'r') {
if(!$write['qa_id'])
alert('게시글이 존재하지 않습니다.\\n삭제되었거나 자신의 글이 아닌 경우입니다.');
if(!$is_admin) {
if($is_admin !== 'super') {
if($write['qa_type'] == 0 && $write['qa_status'] == 1)
alert('답변이 등록된 문의글은 수정할 수 없습니다.');
@@ -130,6 +133,15 @@ if($w == 'u' || $w == 'a' || $w == 'r') {
}
}
if (isset($_FILES['bf_file']['name']) && is_array($_FILES['bf_file']['name'])) {
foreach ($_FILES['bf_file']['name'] as $filename) {
$filename = get_safe_filename($filename);
if (is_disallowed_svg_filename($filename)) {
alert('허용되지 않는 파일 확장자입니다. (svg, svgz)');
}
}
}
// 파일개수 체크
$file_count = 0;
$upload_count = isset($_FILES['bf_file']['name']) ? count($_FILES['bf_file']['name']) : 0;
@@ -184,8 +196,8 @@ for ($i=1; $i<=$upload_count; $i++) {
}
if (is_uploaded_file($tmp_file)) {
// 관리자가 아니면서 설정한 업로드 사이즈보다 크다면 건너뜀
if (!$is_admin && $filesize > $qaconfig['qa_upload_size']) {
// 최고관리자가 아니면서 설정한 업로드 사이즈보다 크다면 건너뜀
if ($is_admin !== 'super' && $filesize > $qaconfig['qa_upload_size']) {
$file_upload_msg .= '"'.$filename.'" 파일의 용량('.number_format($filesize).' 바이트)이 게시판에 설정('.number_format($qaconfig['qa_upload_size']).' 바이트)된 값보다 크므로 업로드 하지 않습니다.\\n';
continue;
}
+2
View File
@@ -646,6 +646,8 @@ if($w == '' && isset($default['de_member_reg_coupon_use']) && $default['de_membe
if($j > 20)
break;
}
$j++;
} while(1);
if($create_coupon) {
+9
View File
@@ -137,6 +137,15 @@ for ($i=1; $i<=10; $i++) {
}
}
if (isset($_FILES['bf_file']['name']) && is_array($_FILES['bf_file']['name'])) {
foreach ($_FILES['bf_file']['name'] as $filename) {
$filename = get_safe_filename($filename);
if (is_disallowed_svg_filename($filename)) {
alert('허용되지 않는 파일 확장자입니다. (svg, svgz)');
}
}
}
@include_once($board_skin_path.'/write_update.head.skin.php');
run_event('write_update_before', $board, $wr_id, $w, $qstr);
+4
View File
@@ -125,6 +125,10 @@ $_REQUEST = array_map_deep(G5_ESCAPE_FUNCTION, $_REQUEST);
// PHP 4.1.0 부터 지원됨
// php.ini 의 register_globals=off 일 경우
// 관리자 메뉴 코드는 각 스크립트가 직접 지정하므로 요청값이 개입하지 못하게 한다.
unset($_GET['sub_menu'], $_POST['sub_menu'], $_REQUEST['sub_menu'], $_SERVER['sub_menu']);
@extract($_GET);
@extract($_POST);
@extract($_SERVER);
-8
View File
@@ -1,8 +0,0 @@
<?php
if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
// 자바스크립트와 CSS 파일을 새로 다운로드 하도록 파일의 끝에 년월일 지정
// 예) https://도메인/css/default.css?ver=220620
// 예) https://도메인/js/common.js?ver=220620
define('G5_CSS_VER', '2303229');
define('G5_JS_VER', '2605291');
+6 -6
View File
@@ -58,11 +58,11 @@ if($config['cf_add_meta'])
<?php
if (defined('G5_IS_ADMIN')) {
if(!defined('_THEME_PREVIEW_'))
echo '<link rel="stylesheet" href="'.run_replace('head_css_url', G5_ADMIN_URL.'/css/admin.css?ver='.G5_CSS_VER, G5_URL).'">'.PHP_EOL;
echo '<link rel="stylesheet" href="'.get_versioned_asset_url(run_replace('head_css_url', G5_ADMIN_URL.'/css/admin.css', G5_URL)).'">'.PHP_EOL;
} else {
$shop_css = '';
if (defined('_SHOP_')) $shop_css = '_shop';
echo '<link rel="stylesheet" href="'.run_replace('head_css_url', G5_CSS_URL.'/'.(G5_IS_MOBILE?'mobile':'default').$shop_css.'.css?ver='.G5_CSS_VER, G5_URL).'">'.PHP_EOL;
echo '<link rel="stylesheet" href="'.get_versioned_asset_url(run_replace('head_css_url', G5_CSS_URL.'/'.(G5_IS_MOBILE?'mobile':'default').$shop_css.'.css', G5_URL)).'">'.PHP_EOL;
}
?>
<!--[if lte IE 8]>
@@ -91,13 +91,13 @@ add_javascript('<script src="'.G5_JS_URL.'/jquery-1.12.4.min.js"></script>', 0);
add_javascript('<script src="'.G5_JS_URL.'/jquery-migrate-1.4.1.min.js"></script>', 0);
if (defined('_SHOP_')) {
if(!G5_IS_MOBILE) {
add_javascript('<script src="'.G5_JS_URL.'/jquery.shop.menu.js?ver='.G5_JS_VER.'"></script>', 0);
add_javascript('<script src="'.G5_JS_URL.'/jquery.shop.menu.js"></script>', 0);
}
} else {
add_javascript('<script src="'.G5_JS_URL.'/jquery.menu.js?ver='.G5_JS_VER.'"></script>', 0);
add_javascript('<script src="'.G5_JS_URL.'/jquery.menu.js"></script>', 0);
}
add_javascript('<script src="'.G5_JS_URL.'/common.js?ver='.G5_JS_VER.'"></script>', 0);
add_javascript('<script src="'.G5_JS_URL.'/wrest.js?ver='.G5_JS_VER.'"></script>', 0);
add_javascript('<script src="'.G5_JS_URL.'/common.js"></script>', 0);
add_javascript('<script src="'.G5_JS_URL.'/wrest.js"></script>', 0);
add_javascript('<script src="'.G5_JS_URL.'/placeholders.min.js"></script>', 0);
add_stylesheet('<link rel="stylesheet" href="'.G5_JS_URL.'/font-awesome/css/font-awesome.min.css">', 0);
+91 -1
View File
@@ -59,6 +59,72 @@ function trim(s)
return t;
}
// SVG/SVGZ 업로드 파일 차단
function is_disallowed_svg_filename(filename)
{
// 서버의 파일명 정규화와 동일하게 특수문자를 제거
filename = (filename || "").replace(/[\0"'<>=#&!%\\()*+?]/g, "");
filename = filename.substring(filename.lastIndexOf("/") + 1);
filename = filename.replace(/[ .\t\n\r\v]+$/, "");
return /\.(svg|svgz)$/i.test(filename);
}
function is_svg_upload_target(input)
{
var name = input.name || "";
if (name.indexOf("bf_file[") === 0) {
return true;
}
if (input.form && input.form.name == "fformmail" && (name == "file1" || name == "file2")) {
return true;
}
return input.form && input.form.name == "fconfig" &&
(name == "logo_img" || name == "logo_img2" || name == "mobile_logo_img" || name == "mobile_logo_img2");
}
function has_disallowed_svg_file(input)
{
var i;
if (input.files && input.files.length) {
for (i=0; i<input.files.length; i++) {
if (is_disallowed_svg_filename(input.files[i].name)) {
return true;
}
}
return false;
}
return is_disallowed_svg_filename(input.value);
}
function check_disallowed_svg_upload(form)
{
var invalid_file = null;
$(form).find("input[type=file]").each(function() {
if (is_svg_upload_target(this) && has_disallowed_svg_file(this)) {
invalid_file = this;
return false;
}
});
if (!invalid_file) {
return true;
}
alert("허용되지 않는 파일 확장자입니다. (svg, svgz)");
$(form).find("input:submit, button:submit, input:image").prop("disabled", false);
invalid_file.focus();
return false;
}
// 자바스크립트로 PHP의 number_format 흉내를 냄
// 숫자에 , 를 출력
function number_format(data)
@@ -728,6 +794,30 @@ function get_write_token(bo_table)
}
$(function() {
$(document).on("change", "input[type=file]", function() {
if (!is_svg_upload_target(this) || !has_disallowed_svg_file(this)) {
return true;
}
alert("허용되지 않는 파일 확장자입니다. (svg, svgz)");
this.value = "";
return false;
});
if (document.addEventListener) {
document.addEventListener("submit", function(event) {
if (!check_disallowed_svg_upload(event.target)) {
event.preventDefault();
event.stopPropagation();
}
}, true);
} else {
$(document).on("submit", "form", function() {
return check_disallowed_svg_upload(this);
});
}
$(document).on("click", "form[name=fwrite] input:submit, form[name=fwrite] button:submit, form[name=fwrite] input:image", function() {
var f = this.form;
@@ -752,4 +842,4 @@ $(function() {
return true;
});
});
});
+141 -6
View File
@@ -20,6 +20,13 @@ function get_microtime()
}
// 게시판/그룹 관리자 문맥을 제외하고 최고관리자 권한만 반환
function get_super_admin_type($admin_type)
{
return $admin_type === 'super' ? 'super' : '';
}
// 한페이지에 보여줄 행, 현재페이지, 총페이지수, URL
function get_paging($write_pages, $cur_page, $total_page, $url, $add="")
{
@@ -3241,6 +3248,90 @@ function add_javascript($javascript, $order=0)
get_html_process_cls()->merge_javascript($javascript, $order);
}
// 로컬 정적 자산 URL에 파일 수정시간을 버전으로 추가
function get_versioned_asset_url($url)
{
if (!is_string($url) || $url === '' || !defined('G5_PATH') || G5_PATH === '') {
return $url;
}
$asset_url = preg_replace('/[?#].*$/', '', $url);
$g5_url = defined('G5_URL') ? rtrim(G5_URL, '/') : '';
$relative_path = '';
if ($g5_url !== '' && strpos($asset_url, $g5_url.'/') === 0) {
$relative_path = substr($asset_url, strlen($g5_url) + 1);
} else {
if (preg_match('#^[a-z][a-z0-9+.-]*://#i', $asset_url) || strpos($asset_url, '//') === 0 || substr($asset_url, 0, 1) !== '/') {
return $url;
}
$g5_url_path = $g5_url !== '' ? parse_url($g5_url, PHP_URL_PATH) : '';
$g5_url_path = rtrim((string) $g5_url_path, '/');
if ($g5_url_path !== '') {
if (strpos($asset_url, $g5_url_path.'/') !== 0) {
return $url;
}
$relative_path = substr($asset_url, strlen($g5_url_path) + 1);
} else {
$relative_path = ltrim($asset_url, '/');
}
}
$relative_path = str_replace('\\', '/', rawurldecode($relative_path));
if ($relative_path === '' || strpos($relative_path, "\0") !== false) {
return $url;
}
$root_path = @realpath(G5_PATH);
$file_path = @realpath(G5_PATH.'/'.$relative_path);
if ($root_path === false || $file_path === false || !is_file($file_path)) {
return $url;
}
$root_path = rtrim(str_replace('\\', '/', $root_path), '/');
$file_path = str_replace('\\', '/', $file_path);
if (strpos($file_path, $root_path.'/') !== 0) {
return $url;
}
$filetime = @filemtime($file_path);
if ($filetime === false) {
return $url;
}
$fragment = '';
$fragment_pos = strpos($url, '#');
if ($fragment_pos !== false) {
$fragment = substr($url, $fragment_pos);
$url = substr($url, 0, $fragment_pos);
}
if (preg_match('/([?&](?:amp;)?)ver=[^&#]*/i', $url)) {
$url = preg_replace('/([?&](?:amp;)?)ver=[^&#]*/i', '${1}ver='.$filetime, $url, 1);
} else {
$url .= (strpos($url, '?') === false ? '?' : '&').'ver='.$filetime;
}
return $url.$fragment;
}
function _callback_version_asset_url($matches)
{
return $matches[1].get_versioned_asset_url($matches[2]).$matches[3];
}
function add_filetime_version_to_html($html)
{
return preg_replace_callback(
'~(<(?:script|link)\b[^>]*\b(?:src|href)\s*=\s*[\'"])([^\'"]+?\.(?:js|css)(?:[?#][^\'"]*)?)([\'"])~i',
'_callback_version_asset_url',
$html
);
}
class html_process {
protected static $id = '0';
private static $instances = array();
@@ -3300,8 +3391,6 @@ class html_process {
// 현재접속자 처리
$tmp_sql = " select count(*) as cnt from {$g5['login_table']} where lo_ip = '{$_SERVER['REMOTE_ADDR']}' ";
$tmp_row = sql_fetch($tmp_sql);
$http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];
if (!isset($member['mb_id'])) {
$member['mb_id'] = '';
}
@@ -3342,7 +3431,7 @@ class html_process {
if(!trim($link[1]))
continue;
$link[1] = preg_replace('#\.css([\'\"]?>)$#i', '.css?ver='.G5_CSS_VER.'$1', $link[1]);
$link[1] = add_filetime_version_to_html($link[1]);
$stylesheet .= PHP_EOL.$link[1];
}
@@ -3369,9 +3458,8 @@ class html_process {
foreach($scripts as $js) {
if(!trim($js[1]))
continue;
$add_version_str = (stripos($js[1], $http_host) !== false) ? '?ver='.G5_JS_VER : '';
$js[1] = preg_replace('#\.js([\'\"]?>)<\/script>$#i', '.js'.$add_version_str.'$1</script>', $js[1]);
$js[1] = add_filetime_version_to_html($js[1]);
$javascript .= $php_eol.$js[1];
$php_eol = PHP_EOL;
@@ -4004,6 +4092,26 @@ function get_safe_filename($name)
return $name;
}
// 업로드 파일명이 SVG 또는 SVGZ 확장자인지 확인
function is_disallowed_svg_filename($filename)
{
if (!is_string($filename) || $filename === '') {
return false;
}
$filename = str_replace(array("\0", '\\'), array('', '/'), $filename);
$filename = basename($filename);
$filename = rtrim($filename, " .\t\n\r\0\x0B");
if ($filename === '') {
return false;
}
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
return in_array($extension, array('svg', 'svgz'), true);
}
// 파일명 치환
function replace_filename($name)
{
@@ -4853,6 +4961,33 @@ function filter_input_include_path($path){
return str_replace('//', '/', strip_tags($path));
}
// 콘텐츠 상단/하단 include 대상이 템플릿 파일인지 실행 직전 재확인한다.
// 승인 확장자만 허용하고, 업로드가 저장되는 data 디렉터리로 귀결되는 경로는 거부한다.
function is_content_include_allowed($path){
if( !is_string($path) || $path === '' ){
return false;
}
$ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
if( !in_array($ext, array('php', 'htm', 'html')) ){
return false;
}
$real = @realpath($path);
if( $real !== false && defined('G5_DATA_PATH') ){
$data_real = @realpath(G5_DATA_PATH);
if( $data_real !== false ){
$real_norm = str_replace('\\', '/', $real);
$data_norm = rtrim(str_replace('\\', '/', $data_real), '/').'/';
if( strpos($real_norm, $data_norm) === 0 ){
return false;
}
}
}
return true;
}
function option_array_checked($option, $arr=array()){
$checked = '';
+78 -20
View File
@@ -26,11 +26,51 @@ function get_shop_uid($type, $id, $time, $ip)
return hash_hmac('sha256', $payload, $key);
}
/**
* 상품 목록 정렬 요청을 허용된 DB 컬럼과 방향으로 변환한다.
*
* @param mixed $sort 외부 정렬 키
* @param mixed $sortodr 외부 정렬 방향
* @return array 검증된 정렬 컬럼과 방향. 잘못된 입력이면 모두 빈 문자열
*/
function get_shop_item_sort($sort, $sortodr)
{
$sort_columns = array(
'it_name' => 'it_name',
'it_sum_qty' => 'it_sum_qty',
'it_price' => 'it_price',
'it_use_avg' => 'it_use_avg',
'it_use_cnt' => 'it_use_cnt',
'it_update_time' => 'it_update_time',
);
if (!is_string($sort) || !isset($sort_columns[$sort])) {
return array('', '');
}
if (!is_string($sortodr)) {
return array('', '');
}
$sortodr = strtolower($sortodr);
if (!in_array($sortodr, array('asc', 'desc'), true)) {
return array('', '');
}
return array($sort_columns[$sort], $sortodr);
}
// 쇼핑몰 리소스 소유자 또는 최고관리자인지 확인
function is_shop_resource_owner_or_super_admin($owner_id, $member_id, $admin_type)
{
return $admin_type === 'super' || ($member_id !== '' && $owner_id === $member_id);
}
/**
* 현금영수증 발급 또는 조회에 대한 검증
*
* 다음 셋 중 하나여야 접근 허용:
* 1. 관리자
* 1. 최고관리자 (게시판/그룹 관리자 권한은 제외)
* 2. 본인 주문/개인결제 (로그인 회원이고 mb_id 일치)
* 3. 비회원이지만 정당한 세션 uid 보유 (orderinquiry.php에서 비밀번호 검증 통과 후
* 또는 주문 완료 직후 세션에 저장된 ss_orderview_uid / ss_personalpay_uid가
@@ -48,8 +88,9 @@ function is_shop_order_owner($od, $type = 'order')
return false;
}
// 관리자
if ($is_admin) {
// 최고관리자만 전체 주문/개인결제 접근 허용
// (요청 bo_table 로 좌우되는 게시판/그룹 관리자 문맥은 인정하지 않음)
if ($is_admin === 'super') {
return true;
}
@@ -1021,7 +1062,7 @@ function session_check()
global $g5;
if (!trim(get_session('ss_uniqid')))
gotourl(G5_SHOP_URL);
goto_url(G5_SHOP_URL);
}
// 상품 선택옵션
@@ -1353,14 +1394,16 @@ function get_list_skin_options($pattern, $dirname='./', $sval='')
{
$str = '<option value="">선택</option>'.PHP_EOL;
unset($arr);
$handle = opendir($dirname);
while ($file = readdir($handle)) {
if (preg_match("/$pattern/", $file, $matches)) {
$arr[] = $matches[0];
$arr = array();
$handle = @opendir($dirname);
if ($handle !== false) {
while (false !== ($file = readdir($handle))) {
if (preg_match("/$pattern/", $file, $matches)) {
$arr[] = $matches[0];
}
}
closedir($handle);
}
closedir($handle);
sort($arr);
foreach($arr as $value) {
@@ -1631,17 +1674,32 @@ function get_coupon_id()
{
$len = 16;
$chars = "ABCDEFGHJKLMNPQRSTUVWXYZ123456789";
srand((double)microtime()*1000000);
$i = 0;
$chars_len = strlen($chars);
$str = '';
while ($i < $len) {
$num = rand() % strlen($chars);
$tmp = substr($chars, $num, 1);
$str .= $tmp;
$i++;
if (function_exists('get_random_token_string')) {
// 문자 종류 수로 나누어 떨어지는 구간만 사용하여 특정 문자에 치우치지 않도록 한다.
$limit = 256 - (256 % $chars_len);
$round = 0;
while (strlen($str) < $len && $round < 8) {
$bytes = pack('H*', get_random_token_string($len + 8));
$bytes_len = strlen($bytes);
for ($i = 0; $i < $bytes_len && strlen($str) < $len; $i++) {
$num = ord($bytes[$i]);
if ($num >= $limit)
continue;
$str .= substr($chars, $num % $chars_len, 1);
}
$round++;
}
}
while (strlen($str) < $len) {
$str .= substr($chars, mt_rand(0, $chars_len - 1), 1);
}
$str = preg_replace("/([0-9A-Z]{4})([0-9A-Z]{4})([0-9A-Z]{4})([0-9A-Z]{4})/", "\\1-\\2-\\3-\\4", $str);
@@ -2076,7 +2134,7 @@ function check_itemuse_write($it_id, $mb_id, $close=true)
{
global $g5, $default, $is_admin;
if(!$is_admin && $default['de_item_use_write'])
if($is_admin !== 'super' && $default['de_item_use_write'])
{
$sql = " select count(*) as cnt
from {$g5['g5_shop_cart_table']}
+9 -15
View File
@@ -1,20 +1,14 @@
<?php
include_once('../../common.php');
// SQL 주석 토큰 차단 추가 — 데스크톱 shop/_common.php 와 동일 패턴
if (isset($_REQUEST['sort']) && !preg_match("/(--|#|\/\*|\*\/)/", $_REQUEST['sort'])) {
$sort = trim($_REQUEST['sort']);
$sort = preg_replace("/[\<\>\'\"\\\'\\\"\%\=\(\)\s]/", "", $sort);
} else {
$sort = '';
}
if (isset($_REQUEST['sortodr'])) {
$sortodr = preg_match("/^(asc|desc)$/i", $sortodr) ? $sortodr : '';
} else {
$sortodr = '';
}
if (!defined('G5_USE_SHOP') || !G5_USE_SHOP)
die('<p>쇼핑몰 설치 후 이용해 주십시오.</p>');
define('_SHOP_', true);
$is_admin = get_super_admin_type($is_admin);
$request_sort = (isset($_REQUEST['sort']) && is_string($_REQUEST['sort'])) ? $_REQUEST['sort'] : '';
$request_sortodr = (isset($_REQUEST['sortodr']) && is_string($_REQUEST['sortodr'])) ? $_REQUEST['sortodr'] : '';
list($sort, $sortodr) = get_shop_item_sort($request_sort, $request_sortodr);
unset($request_sort, $request_sortodr);
define('_SHOP_', true);
+2 -2
View File
@@ -36,8 +36,8 @@ $result = sql_query($sql);
$cart_count = sql_num_rows($result);
?>
<script src="<?php echo G5_JS_URL; ?>/shop.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="<?php echo G5_JS_URL; ?>/shop.override.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="<?php echo get_versioned_asset_url(G5_JS_URL.'/shop.js'); ?>"></script>
<script src="<?php echo get_versioned_asset_url(G5_JS_URL.'/shop.override.js'); ?>"></script>
<div id="sod_bsk">
+1 -1
View File
@@ -93,4 +93,4 @@ echo '<div id="sev_thtml">'.conv_content($ev['ev_tail_html'], 1).'</div>';
</div>
<?php
include_once(G5_MSHOP_PATH.'/_tail.php');
include_once(G5_MSHOP_PATH.'/_tail.php');
+1 -1
View File
@@ -203,7 +203,7 @@ echo run_replace('shop_it_mobile_head_html', '<div id="sit_hhtml">'.conv_content
?>
<?php if($is_orderable) { ?>
<script src="<?php echo G5_JS_URL; ?>/shop.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="<?php echo get_versioned_asset_url(G5_JS_URL.'/shop.js'); ?>"></script>
<?php } ?>
<?php
+2 -2
View File
@@ -31,7 +31,7 @@ if ($w == "u")
$it_id = $qa['it_id'];
if (!$is_admin && $qa['mb_id'] != $member['mb_id']) {
if (!is_shop_resource_owner_or_super_admin($qa['mb_id'], $member['mb_id'], $is_admin)) {
alert_close("자신의 상품문의만 수정이 가능합니다.");
}
@@ -59,4 +59,4 @@ if(!file_exists($itemqaform_skin)) {
include_once($itemqaform_skin);
}
include_once(G5_PATH.'/tail.sub.php');
include_once(G5_PATH.'/tail.sub.php');
+2 -2
View File
@@ -29,7 +29,7 @@ if ($w == "") {
$it_id = $use['it_id'];
$is_score = $use['is_score'];
if (!$is_admin && $use['mb_id'] != $member['mb_id']) {
if (!is_shop_resource_owner_or_super_admin($use['mb_id'], $member['mb_id'], $is_admin)) {
alert_close("자신의 사용후기만 수정이 가능합니다.");
}
}
@@ -54,4 +54,4 @@ if(!file_exists($itemuseform_skin)) {
include_once($itemuseform_skin);
}
include_once(G5_PATH.'/tail.sub.php');
include_once(G5_PATH.'/tail.sub.php');
+15 -9
View File
@@ -168,9 +168,10 @@
{
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
{
$bin_exe = $home_dir.'/bin/pp_cli_exe ';
// 실행 파일 경로와 인자를 분리하여 mf_exec 호출 → escapeshellarg 자동 적용
$bin_exe = $home_dir.'/bin/pp_cli_exe';
$res_data = $this->mf_exec($bin_exe . "\"".
$res_data = $this->mf_exec($bin_exe,
"site_cd=" . $site_cd . "," .
"site_key=" . $site_key . "," .
"tx_cd=" . $tx_cd . "," .
@@ -188,8 +189,7 @@
$ordr_data .
$rcvr_data .
$escw_data .
$modx_data .
"\"") ;
$modx_data) ;
}
else
{
@@ -276,21 +276,27 @@
return $my_data;
}
function mf_exec()
function mf_build_exec_cmd( $arg )
{
$arg = func_get_args();
if ( is_array( $arg[0] ) ) $arg = $arg[0];
$exec_cmd = array_shift( $arg );
foreach($arg as $i)
foreach((array) $arg as $key=>$i)
{
$exec_cmd .= " " . escapeshellarg( $i );
}
return $exec_cmd;
}
function mf_exec()
{
$arg = func_get_args();
$exec_cmd = $this->mf_build_exec_cmd( $arg );
$rt = exec( $exec_cmd );
return $rt;
}
}
}
+1 -6
View File
@@ -11,11 +11,6 @@ if(defined('G5_THEME_MSHOP_PATH')) {
unset($theme_list_file);
}
// 상품 리스트에서 다른 필드로 정렬을 하려면 아래의 배열 코드에서 해당 필드를 추가하세요.
if( isset($sort) && ! in_array($sort, array('it_name', 'it_sum_qty', 'it_price', 'it_use_avg', 'it_use_cnt', 'it_update_time')) ){
$sort='';
}
$sql = " select *
from {$g5['g5_shop_category_table']}
where ca_id = '$ca_id'
@@ -200,4 +195,4 @@ var g5_shop_url = "<?php echo G5_SHOP_URL; ?>";
<?php
include_once(G5_MSHOP_PATH.'/_tail.php');
echo "\n<!-- {$ca['ca_mobile_skin']} -->\n";
echo "\n<!-- {$ca['ca_mobile_skin']} -->\n";
+1 -4
View File
@@ -1,9 +1,6 @@
<?php
include_once('./_common.php');
// 상품 정렬 컬럼 화이트리스트 — 데스크톱 shop/listtype.php 와 동일 패턴
$sort = (isset($_REQUEST['sort']) && in_array($_REQUEST['sort'], array('it_name', 'it_sum_qty', 'it_price', 'it_use_avg', 'it_use_cnt', 'it_update_time'))) ? $_REQUEST['sort'] : '';
$type = isset($_REQUEST['type']) ? (int) preg_replace("/[^0-9]/", "", $_REQUEST['type']) : 1;
if ($type === 1) $g5['title'] = '히트상품';
else if ($type === 2) $g5['title'] = '추천상품';
@@ -78,4 +75,4 @@ echo get_paging($config['cf_mobile_pages'], $page, $total_page, "{$_SERVER['SCRI
?>
<?php
include_once(G5_MSHOP_PATH.'/_tail.php');
include_once(G5_MSHOP_PATH.'/_tail.php');
+152 -47
View File
@@ -16,14 +16,23 @@ $txTid = isset($_POST['TxTid']) ? clean_xss_tags($_POST['TxTid']) : ''; //
$authToken = isset($_POST['AuthToken']) ? clean_xss_tags($_POST['AuthToken']) : ''; // authentication TOKEN
$payMethod = isset($_POST['PayMethod']) ? clean_xss_tags($_POST['PayMethod']) : ''; // payment method
$mid = isset($_POST['MID']) ? clean_xss_tags($_POST['MID']) : ''; // merchant id
$moid = isset($_POST['Moid']) ? addslashes(clean_xss_tags(stripslashes($_POST['Moid']))) : ''; // order number
$amt = isset($_POST['Amt']) ? (int) preg_replace('/[^0-9]/', '', $_POST['Amt']) : 0; // Amount of payment
$reqReserved = isset($_POST['ReqReserved']) ? clean_xss_tags($_POST['ReqReserved']) : ''; // mall custom field
$netCancelURL = isset($_POST['NetCancelURL']) ? clean_xss_tags($_POST['NetCancelURL']) : ''; // netCancelURL
if (isset($pp['pp_id']) && $pp['pp_id']) { //개인결제
$session_order_id = get_session('ss_personalpay_id');
$order_price = (int) $pp['pp_price'];
$moid = isset($_POST['Moid']) ? addslashes(clean_xss_tags(stripslashes($_POST['Moid']))) : ''; // order number
$amt = isset($_POST['Amt']) ? (int) preg_replace('/[^0-9]/', '', $_POST['Amt']) : 0; // Amount of payment
$reqReserved = isset($_POST['ReqReserved']) ? clean_xss_tags($_POST['ReqReserved']) : ''; // mall custom field
$netCancelURL = isset($_POST['NetCancelURL']) ? clean_xss_tags($_POST['NetCancelURL']) : ''; // netCancelURL
$Signature = isset($_POST['Signature']) ? clean_xss_tags($_POST['Signature']) : ''; // authentication signature
if($authResultCode !== "0000"){
//When authentication fail
$ResultCode = $authResultCode;
$ResultMsg = $authResultMsg;
alert($ResultMsg.' 실패 코드 : '.$ResultCode);
}
if (isset($pp['pp_id']) && $pp['pp_id']) { //개인결제
$session_order_id = get_session('ss_personalpay_id');
$order_price = (int) $pp['pp_price'];
} else {
$session_order_id = get_session('ss_order_id'); // 쇼핑몰 일반결제
}
@@ -36,12 +45,12 @@ if ($default['de_nicepay_mid'] != $mid) {
alert("요청한 상점 mid와 설정된 mid가 틀리므로 결제를 진행할수 없습니다.", G5_SHOP_URL);
}
if ($order_price != $amt) {
alert("요청한 결제금액이 틀리므로 결제를 진행할수 없습니다.", G5_SHOP_URL);
}
// API CALL foreach example
if (! function_exists('jsonRespDump')) {
if ($order_price != $amt) {
alert("요청한 결제금액이 틀리므로 결제를 진행할수 없습니다.", G5_SHOP_URL);
}
// API CALL foreach example
if (! function_exists('jsonRespDump')) {
function jsonRespDump($resp){
$respArr = json_decode($resp);
foreach ( $respArr as $key => $value ){
@@ -50,13 +59,27 @@ if (! function_exists('jsonRespDump')) {
}
}
if (! function_exists('nicepay_res')) {
function nicepay_res($key, $data, $default_val='') {
$response_val = isset($data[$key]) ? $data[$key] : $default_val;
return ($response_val ? $response_val : $default_val);
}
}
if (! function_exists('nicepay_res')) {
function nicepay_res($key, $data, $default_val='') {
$response_val = isset($data[$key]) ? $data[$key] : $default_val;
return ($response_val ? $response_val : $default_val);
}
}
if (! function_exists('nicepay_expected_pay_result')) {
function nicepay_expected_pay_result($settle_case) {
$pay_results = array(
'신용카드' => array('PayMethod'=>'CARD', 'ResultCode'=>'3001'),
'간편결제' => array('PayMethod'=>'CARD', 'ResultCode'=>'3001'),
'계좌이체' => array('PayMethod'=>'BANK', 'ResultCode'=>'4000'),
'가상계좌' => array('PayMethod'=>'VBANK', 'ResultCode'=>'4100'),
'휴대폰' => array('PayMethod'=>'CELLPHONE', 'ResultCode'=>'A000')
);
return isset($pay_results[$settle_case]) ? $pay_results[$settle_case] : false;
}
}
/*
****************************************************************************************
@@ -65,10 +88,25 @@ if (! function_exists('nicepay_res')) {
*/
$response = "";
if($authResultCode === "0000"){
/*
****************************************************************************************
* <Hash encryption> (do not modify)
if($authResultCode === "0000"){
// hex(sha256(AuthToken+MID+Amt+MerchantKey)), 위변조 검증 데이터
$authSignData = bin2hex(hash('sha256', $authToken. $default['de_nicepay_mid'] . $order_price . $default['de_nicepay_key'], true));
if ($Signature != $authSignData) {
alert("유효성 검증이 틀려서 결제를 진행할수 없습니다.");
}
if (! nicepay_is_allowed_api_url($nextAppURL, array('/webapi/pay_process.jsp'))) {
alert("승인 요청 url이 올바르지 않습니다.", G5_SHOP_URL);
}
if (! nicepay_is_allowed_api_url($netCancelURL, array('/webapi/cancel_process.jsp'))) {
alert("망취소 요청 url이 올바르지 않습니다.", G5_SHOP_URL);
}
/*
****************************************************************************************
* <Hash encryption> (do not modify)
****************************************************************************************
*/
$ediDate = preg_replace('/[^0-9]/', '', G5_TIME_YMDHIS);
@@ -97,28 +135,95 @@ if($authResultCode === "0000"){
// A000 : 휴대폰 소액결제 성공코드
// 7001 : 현금영수증
// https://developers.nicepay.co.kr/manual-auth.php
*/
$response = nicepay_reqPost($data, $nextAppURL);
$respArr = json_decode($response, true);
$ResultCode = nicepay_res('ResultCode', $respArr);
$ResultMsg = nicepay_res('ResultMsg', $respArr);
$tno = nicepay_res('TID', $respArr);
$amount = (int) nicepay_res('Amt', $respArr, 0);
$app_time = nicepay_res('AuthDate', $respArr);
$pay_method = nicepay_res('PayMethod', $respArr);
$od_app_no = $app_no = nicepay_res('AuthCode', $respArr); // 승인 번호 (신용카드, 계좌이체, 휴대폰)
$pay_type = $NICEPAY_METHOD[$pay_method];
// 승인된 코드가 아니면 결제가 되지 않게 합니다.
if (! in_array($ResultCode, array('3001', '4000', '4100', 'A000', '7001'))) {
alert($ResultMsg.' 코드 : '.$ResultCode, G5_SHOP_URL);
die();
}
if ($ResultCode == '3001') { // 신용카드
$card_cd = nicepay_res('CardCode', $respArr); // 카드사 코드
*/
$response = nicepay_reqPost($data, $nextAppURL);
if (! $response) {
alert('응답이 없거나 잘못된 url 입니다.', G5_SHOP_URL);
}
$respArr = json_decode($response, true);
$ResultCode = nicepay_res('ResultCode', $respArr);
$ResultMsg = nicepay_res('ResultMsg', $respArr);
$tno = nicepay_res('TID', $respArr);
$response_amt = nicepay_res('Amt', $respArr, 0);
$response_mid = nicepay_res('MID', $respArr);
$response_moid = nicepay_res('Moid', $respArr);
$amount = (int) $response_amt;
$app_time = nicepay_res('AuthDate', $respArr);
$pay_method = nicepay_res('PayMethod', $respArr);
$od_app_no = $app_no = nicepay_res('AuthCode', $respArr); // 승인 번호 (신용카드, 계좌이체, 휴대폰)
$pay_type = isset($NICEPAY_METHOD[$pay_method]) ? $NICEPAY_METHOD[$pay_method] : '';
// 승인된 코드가 아니면 결제가 되지 않게 합니다.
if (! in_array($ResultCode, array('3001', '4000', '4100', 'A000', '7001'))) {
alert($ResultMsg.' 코드 : '.$ResultCode, G5_SHOP_URL);
die();
}
$responseSignature = nicepay_res('Signature', $respArr);
$responseSignData = bin2hex(hash('sha256', $tno . $mid . $response_amt . $merchantKey, true));
if ($responseSignature != $responseSignData) {
if($amount > 0 && $tno) {
$od_id = $moid;
$cancel_msg = '승인 응답 유효성 검증 실패';
$cancelAmt = $amount;
$partialCancelCode = 0;
include G5_SHOP_PATH.'/nicepay/cancel_process.php';
}
alert("승인 응답 유효성 검증이 틀려서 결제를 진행할수 없습니다.", G5_SHOP_URL);
}
if ($response_mid != $mid || $response_moid != $moid) {
if($amount > 0) {
$od_id = $moid;
$cancel_msg = '승인 응답 주문정보 불일치';
$cancelAmt = $amount;
$partialCancelCode = 0;
include G5_SHOP_PATH.'/nicepay/cancel_process.php';
}
alert("승인 응답 주문정보가 틀려서 결제를 진행할수 없습니다.", G5_SHOP_URL);
}
if ($amount != $order_price) {
if($amount > 0) {
$od_id = $moid;
$cancel_msg = '결제금액 불일치';
$cancelAmt = $amount;
$partialCancelCode = 0;
include G5_SHOP_PATH.'/nicepay/cancel_process.php';
}
alert("승인된 결제금액이 틀리므로 결제를 진행할수 없습니다.", G5_SHOP_URL);
}
$nicepay_settle_case = '';
if (isset($pp['pp_id']) && $pp['pp_id'] && isset($pp_settle_case)) {
$nicepay_settle_case = $pp_settle_case;
} else if (isset($od_settle_case)) {
$nicepay_settle_case = $od_settle_case;
}
$expected_pay_result = nicepay_expected_pay_result($nicepay_settle_case);
if ($expected_pay_result && ($pay_method !== $expected_pay_result['PayMethod'] || $ResultCode !== $expected_pay_result['ResultCode'])) {
if($amount > 0 && $tno) {
$od_id = $moid;
$cancel_msg = '결제수단 불일치';
$cancelAmt = $amount;
$partialCancelCode = 0;
include G5_SHOP_PATH.'/nicepay/cancel_process.php';
}
alert("선택한 결제수단과 승인된 결제수단이 일치하지 않아 결제를 진행할수 없습니다.", G5_SHOP_URL);
}
if ($ResultCode == '3001') { // 신용카드
$card_cd = nicepay_res('CardCode', $respArr); // 카드사 코드
$card_name = nicepay_res('CardName', $respArr); // 카드 종류
} else if ($ResultCode == '4100') { // 가상계좌
+6 -5
View File
@@ -71,10 +71,11 @@ function nicepay_create_signdata(frm)
var result = true;
$.ajax({
url: g5_url+"/shop/nicepay/createsigndata.php",
type: "POST",
data: {
price : frm.good_mny.value
},
type: "POST",
data: {
price : frm.good_mny.value,
moid : frm.Moid ? frm.Moid.value : ''
},
dataType: "json",
async: false,
cache: false,
@@ -137,4 +138,4 @@ function nicepay_create_signdata(frm)
<input type="hidden" name="comm_vat_mny" value="<?php echo $comm_vat_mny; ?>"> <!-- 부가세 -->
<input type="hidden" name="comm_free_mny" value="<?php echo $comm_free_mny; ?>"> <!-- 비과세 금액 -->
<?php } ?>
</form>
</form>
+47 -13
View File
@@ -3,12 +3,46 @@ include_once('./_common.php');
include_once(G5_MSHOP_PATH.'/settle_nicepay.inc.php');
$authResultCode = isset($_POST['AuthResultCode']) ? clean_xss_tags($_POST['AuthResultCode']) : ''; // authentication result code 0000:success
$authResultMsg = isset($_POST['AuthResultMsg']) ? clean_xss_tags($_POST['AuthResultMsg']) : ''; // authentication result message
$mid = isset($_POST['MID']) ? clean_xss_tags($_POST['MID']) : ''; // merchant id
$moid = isset($_POST['Moid']) ? addslashes(clean_xss_tags(stripslashes($_POST['Moid']))) : ''; // order number
$sql = " select * from {$g5['g5_shop_order_data_table']} where od_id = '$moid' ";
$row = sql_fetch($sql);
$authResultMsg = isset($_POST['AuthResultMsg']) ? clean_xss_tags($_POST['AuthResultMsg']) : ''; // authentication result message
$mid = isset($_POST['MID']) ? clean_xss_tags($_POST['MID']) : ''; // merchant id
$moid = isset($_POST['Moid']) ? addslashes(clean_xss_tags(stripslashes($_POST['Moid']))) : ''; // order number
$session_order_id = get_session('ss_order_id');
$session_personalpay_id = get_session('ss_personalpay_id');
if ($authResultCode !== '0000') {
$page_return_url = G5_SHOP_URL;
if ($moid && ($session_order_id == $moid || $session_personalpay_id == $moid)) {
$sql = " select * from {$g5['g5_shop_order_data_table']} where od_id = '$moid' and dt_pg = 'nicepay' ";
$row = sql_fetch($sql);
if (!empty($row)) {
$data = unserialize(base64_decode($row['dt_data']));
if(isset($data['pp_id']) && $data['pp_id']) {
$page_return_url = G5_SHOP_URL.'/personalpayform.php?pp_id='.$data['pp_id'];
} else {
$page_return_url = G5_SHOP_URL.'/orderform.php';
if(isset($_SESSION['ss_direct']) && $_SESSION['ss_direct'])
$page_return_url .= '?sw_direct=1';
}
}
}
alert('오류 : '.$authResultMsg.' 코드 : '.$authResultCode, $page_return_url);
}
if ($default['de_nicepay_mid'] != $mid) {
alert("요청한 상점 mid와 설정된 mid가 틀리므로 결제를 진행할수 없습니다.", G5_SHOP_URL);
}
if (!$moid || ($session_order_id != $moid && $session_personalpay_id != $moid)) {
alert("요청한 주문번호가 틀려서 결제를 진행할수 없습니다.", G5_SHOP_URL);
}
$sql = " select * from {$g5['g5_shop_order_data_table']} where od_id = '$moid' and dt_pg = 'nicepay' ";
$row = sql_fetch($sql);
if (empty($row)) {
die('');
@@ -19,12 +53,12 @@ $data = unserialize(base64_decode($row['dt_data']));
if(isset($data['pp_id']) && $data['pp_id']) {
$order_action_url = G5_HTTPS_MSHOP_URL.'/personalpayformupdate.php';
$page_return_url = G5_SHOP_URL.'/personalpayform.php?pp_id='.$data['pp_id'];
} else {
$order_action_url = G5_HTTPS_MSHOP_URL.'/orderformupdate.php';
$page_return_url = G5_SHOP_URL.'/orderform.php';
if($_SESSION['ss_direct'])
$page_return_url .= '?sw_direct=1';
}
} else {
$order_action_url = G5_HTTPS_MSHOP_URL.'/orderformupdate.php';
$page_return_url = G5_SHOP_URL.'/orderform.php';
if(isset($_SESSION['ss_direct']) && $_SESSION['ss_direct'])
$page_return_url .= '?sw_direct=1';
}
$params = array();
$var_datas = array();
@@ -84,4 +118,4 @@ if ($authResultCode === '0000') {
// 실패시
alert('오류 : '.$authResultMsg.' 코드 : '.$authResultCode, $page_return_url);
}
}
+8 -4
View File
@@ -1204,7 +1204,7 @@ function calculate_order_price()
var send_coupon = parseInt($("input[name=od_send_coupon]").val());
var tot_price = sell_price + send_cost + send_cost2 - send_coupon;
$("form[name=sm_form] input[name=good_mny]").val(tot_price);
$("form[name=sm_form] input[name=good_mny], form[name=forderform] input[name=good_mny]").val(tot_price);
$("#od_tot_price").text(number_format(String(tot_price)));
<?php if($temp_point > 0 && $is_member) { ?>
calculate_temp_point();
@@ -1321,6 +1321,9 @@ function pay_approval()
var send_cost2 = parseInt(pf.od_send_cost2.value);
var send_coupon = parseInt(pf.od_send_coupon.value);
f.good_mny.value = od_price + send_cost + send_cost2 - send_coupon - temp_point;
if(pf.good_mny) {
pf.good_mny.value = f.good_mny.value;
}
}
// 카카오페이 지불
@@ -1617,9 +1620,6 @@ function pay_approval()
f.TaxFreeAmt.value = pf.comm_free_mny.value;
<?php } ?>
if (! nicepay_create_signdata(f)) {
return false;
}
<?php } ?>
// 주문 정보 임시저장
@@ -1646,6 +1646,10 @@ function pay_approval()
<?php } ?>
<?php if ($default['de_pg_service'] == 'nicepay') { ?>
if (! nicepay_create_signdata(f)) {
return false;
}
nicepayStart(f);
return false;
<?php } ?>
+25 -3
View File
@@ -145,6 +145,11 @@ if($is_member) {
for($i=0; $i<$it_cp_cnt; $i++) {
$cid = isset($_POST['cp_id'][$i]) ? safe_replace_regex($_POST['cp_id'][$i], 'cp_id') : '';
$it_id = isset($_POST['it_id'][$i]) ? safe_replace_regex($_POST['it_id'][$i], 'it_id') : '';
// 한 상품에는 상품쿠폰 하나만 적용 (동일 상품 반복 전송 무시)
if(isset($arr_it_cp_prc[$it_id]))
continue;
$sql = " select cp_id, cp_method, cp_target, cp_type, cp_price, cp_trunc, cp_minimum, cp_maximum
from {$g5['g5_shop_coupon_table']}
where cp_id = '$cid'
@@ -347,6 +352,13 @@ $order_price = $tot_od_price + $send_cost + $send_cost2 - $tot_sc_cp_price - $od
$od_status = '주문';
$od_tno = '';
// PG사의 가상계좌 또는 계좌이체의 자동 현금영수증 초기배열값
$pg_receipt_infos = array(
'od_cash' => 0,
'od_cash_no' => '',
'od_cash_info' => '',
);
if (function_exists('check_payment_method')) {
check_payment_method($od_settle_case);
}
@@ -694,6 +706,9 @@ $sql = " insert {$g5['g5_shop_order_table']}
od_ip = '$REMOTE_ADDR',
od_settle_case = '$od_settle_case',
od_other_pay_type = '$od_other_pay_type',
od_cash = '{$pg_receipt_infos['od_cash']}',
od_cash_no = '{$pg_receipt_infos['od_cash_no']}',
od_cash_info = '{$pg_receipt_infos['od_cash_info']}',
od_test = '{$default['de_card_test']}'
";
$result = sql_query($sql, false);
@@ -713,9 +728,9 @@ if(! $result && (isset($exists_order['od_id']) && $od_id && $exists_order['od_id
// 주문정보 입력 오류시 결제 취소
if(! $result || ! (isset($exists_order['od_id']) && $od_id && $exists_order['od_id'] === $od_id)) {
if($tno) {
$cancel_msg = '주문정보 입력 오류 : '.$sql;
include G5_SHOP_PATH.'/cancel_pg.inc.php';
}
$cancel_msg = '주문정보 입력 오류';
include G5_SHOP_PATH.'/cancel_pg.inc.php';
}
// 관리자에게 오류 알림 메일발송
$error = 'order';
@@ -822,11 +837,16 @@ $od_memo = nl2br(htmlspecialchars2(stripslashes($od_memo))) . "&nbsp;";
$coupon_duplicate = false;
if($is_member) {
$it_cp_cnt = (isset($_POST['cp_id']) && is_array($_POST['cp_id'])) ? count($_POST['cp_id']) : 0;
$arr_it_cp_logged = array();
for($i=0; $i<$it_cp_cnt; $i++) {
$cid = isset($_POST['cp_id'][$i]) ? safe_replace_regex($_POST['cp_id'][$i], 'cp_id') : '';
$cp_it_id = isset($_POST['it_id'][$i]) ? safe_replace_regex($_POST['it_id'][$i], 'it_id') : '';
$cp_prc = isset($arr_it_cp_prc[$cp_it_id]) ? (int) $arr_it_cp_prc[$cp_it_id] : 0;
// 한 상품에는 상품쿠폰 하나만 기록 (동일 상품 반복 전송 무시)
if(isset($arr_it_cp_logged[$cp_it_id]))
continue;
if(trim($cid)) {
// 쿠폰 이중사용 방지: INSERT 직전 재확인
if(is_used_coupon($member['mb_id'], $cid)) {
@@ -848,6 +868,8 @@ if($is_member) {
$coupon_duplicate = true;
break;
}
$arr_it_cp_logged[$cp_it_id] = true;
}
// 쿠폰사용금액 cart에 기록
+12 -8
View File
@@ -280,7 +280,7 @@ if($od['od_pg'] == 'lg') {
</tr>
<tr>
<th scope="row">결제방식</th>
<td><?php echo check_pay_name_replace($od['od_settle_case'], $od, 1); ?></td>
<td><?php echo get_text(check_pay_name_replace($od['od_settle_case'], $od, 1)); ?></td>
</tr>
<tr>
<th scope="row">결제금액</th>
@@ -438,13 +438,17 @@ if($od['od_pg'] == 'lg') {
$cash_receipt_script = 'javascript:showCashReceipts(\''.$LGD_MID.'\',\''.$od['od_id'].'\',\''.$od['od_casseqno'].'\',\''.$trade_type.'\',\''.$CST_PLATFORM.'\');';
} else if($od['od_pg'] == 'toss') {
$cash_receipt_script = 'window.open(\'https://dashboard.tosspayments.com/receipt/mids/si_'.$config['cf_lg_mid'].'/orders/'.$od['od_id'].'/cash-receipt?ref=dashboard\',\'receipt\',\'width=430,height=700\');';
} else if($od['od_pg'] == 'inicis') {
$cash = unserialize($od['od_cash_info']);
$cash_receipt_script = 'window.open(\'https://iniweb.inicis.com/DefaultWebApp/mall/cr/cm/Cash_mCmReceipt.jsp?noTid='.$cash['TID'].'&clpaymethod=22\',\'showreceipt\',\'width=380,height=540,scrollbars=no,resizable=no\');';
} else if($od['od_pg'] == 'nicepay') {
$cash_receipt_script = 'window.open(\'https://npg.nicepay.co.kr/issue/IssueLoader.do?type=1&TID='.$od['od_tno'].'&noMethod=1\',\'receipt\',\'width=430,height=700\');';
} else {
require_once G5_SHOP_PATH.'/settle_kcp.inc.php';
} else if($od['od_pg'] == 'inicis') {
$cash = unserialize($od['od_cash_info']);
$cash_receipt_script = 'window.open(\'https://iniweb.inicis.com/DefaultWebApp/mall/cr/cm/Cash_mCmReceipt.jsp?noTid='.$cash['TID'].'&clpaymethod=22\',\'showreceipt\',\'width=380,height=540,scrollbars=no,resizable=no\');';
} else if($od['od_pg'] == 'nicepay') {
$cash = $od['od_cash_info'] ? unserialize($od['od_cash_info']) : array();
if(!is_array($cash))
$cash = array();
$cash_tid = isset($cash['TID']) && $cash['TID'] ? $cash['TID'] : $od['od_tno'];
$cash_receipt_script = 'window.open(\'https://npg.nicepay.co.kr/issue/IssueLoader.do?type=1&TID='.$cash_tid.'&noMethod=1\',\'receipt\',\'width=430,height=700\');';
} else {
require_once G5_SHOP_PATH.'/settle_kcp.inc.php';
$cash = unserialize($od['od_cash_info']);
$cash_receipt_script = 'window.open(\''.G5_CASH_RECEIPT_URL.$default['de_kcp_mid'].'&orderid='.$od_id.'&bill_yn=Y&authno='.$cash['receipt_no'].'\', \'taxsave_receipt\', \'width=360,height=647,scrollbars=0,menus=0\');';
+4 -4
View File
@@ -305,10 +305,6 @@ function pay_approval()
f.TaxFreeAmt.value = pf.comm_free_mny.value;
<?php } ?>
if (! nicepay_create_signdata(f)) {
return false;
}
<?php } ?>
//var new_win = window.open("about:blank", "tar_opener", "scrollbars=yes,resizable=yes");
@@ -338,6 +334,10 @@ function pay_approval()
<?php } ?>
<?php if($default['de_pg_service'] == 'nicepay') { ?>
if (! nicepay_create_signdata(f)) {
return false;
}
nicepayStart(f);
return;
+16
View File
@@ -244,11 +244,19 @@ if(!$result) {
case 'inicis':
include G5_SHOP_PATH.'/inicis/inipay_cancel.php';
break;
case 'nicepay':
$od_id = $pp['pp_id'];
$tno = $pp_tno;
$cancelAmt = (int)$pg_price;
$partialCancelCode = 0;
include G5_SHOP_PATH.'/nicepay/cancel_process.php';
break;
default:
include G5_SHOP_PATH.'/kcp/pp_ax_hub_cancel.php';
break;
}
if(function_exists('add_order_post_log')) add_order_post_log($cancel_msg);
die('개인결제 정보를 처리하는 중 오류가 발생했습니다. 결제 취소 여부를 관리자에게 문의해 주십시오.');
}
@@ -288,11 +296,19 @@ if($pp_receipt_price > 0 && $pp['pp_id'] && $pp['od_id']) {
case 'inicis':
include G5_SHOP_PATH.'/inicis/inipay_cancel.php';
break;
case 'nicepay':
$od_id = $pp['pp_id'];
$tno = $pp_tno;
$cancelAmt = (int)$pg_price;
$partialCancelCode = 0;
include G5_SHOP_PATH.'/nicepay/cancel_process.php';
break;
default:
include G5_SHOP_PATH.'/kcp/pp_ax_hub_cancel.php';
break;
}
if(function_exists('add_order_post_log')) add_order_post_log($cancel_msg);
die('주문 결제정보를 처리하는 중 오류가 발생했습니다. 결제 취소 여부를 관리자에게 문의해 주십시오.');
}
+6 -2
View File
@@ -232,7 +232,11 @@ if($pp['pp_pg'] == 'lg') {
$cash = unserialize($pp['pp_cash_info']);
$cash_receipt_script = 'window.open(\'https://iniweb.inicis.com/DefaultWebApp/mall/cr/cm/Cash_mCmReceipt.jsp?noTid='.$cash['TID'].'&clpaymethod=22\',\'showreceipt\',\'width=380,height=540,scrollbars=no,resizable=no\');';
} else if($pp['pp_pg'] == 'nicepay') {
$cash_receipt_script = 'window.open(\'https://npg.nicepay.co.kr/issue/IssueLoader.do?type=1&TID='.$od['od_tno'].'&noMethod=1\',\'receipt\',\'width=430,height=700\');';
$cash = $pp['pp_cash_info'] ? unserialize($pp['pp_cash_info']) : array();
if(!is_array($cash))
$cash = array();
$cash_tid = isset($cash['TID']) && $cash['TID'] ? $cash['TID'] : $pp['pp_tno'];
$cash_receipt_script = 'window.open(\'https://npg.nicepay.co.kr/issue/IssueLoader.do?type=1&TID='.$cash_tid.'&noMethod=1\',\'receipt\',\'width=430,height=700\');';
} else {
require_once G5_SHOP_PATH.'/settle_kcp.inc.php';
@@ -326,4 +330,4 @@ if($pp['pp_pg'] == 'lg') {
<!-- } 개인결제상세내역 끝 -->
<?php
include_once(G5_MSHOP_PATH.'/_tail.php');
include_once(G5_MSHOP_PATH.'/_tail.php');
@@ -4,7 +4,7 @@ if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
// add_stylesheet('css 구문', 출력순서); 숫자가 작을 수록 먼저 출력됨
add_stylesheet('<link rel="stylesheet" href="' . $member_skin_url . '/style.css">', 0);
if ($config['cf_cert_use'] && ($config['cf_cert_simple'] || $config['cf_cert_ipin'] || $config['cf_cert_hp']))
add_javascript('<script src="'.G5_JS_URL.'/certify.js?v='.G5_JS_VER.'"></script>', 0);
add_javascript('<script src="'.G5_JS_URL.'/certify.js"></script>', 0);
?>
<!-- 기존 회원 본인인증 시작 { -->
<div class="member_cert_refresh">
@@ -5,7 +5,7 @@ if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
add_stylesheet('<link rel="stylesheet" href="'.$member_skin_url.'/style.css">', 0);
if($config['cf_cert_use'] && ($config['cf_cert_simple'] || $config['cf_cert_ipin'] || $config['cf_cert_hp'])) { ?>
<script src="<?php echo G5_JS_URL ?>/certify.js?v=<?php echo G5_JS_VER; ?>"></script>
<script src="<?php echo get_versioned_asset_url(G5_JS_URL.'/certify.js'); ?>"></script>
<?php } ?>
<!-- 회원정보 찾기 시작 { -->
@@ -5,7 +5,7 @@ if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
add_stylesheet('<link rel="stylesheet" href="'.$member_skin_url.'/style.css">', 0);
add_javascript('<script src="'.G5_JS_URL.'/jquery.register_form.js"></script>', 0);
if ($config['cf_cert_use'] && ($config['cf_cert_simple'] || $config['cf_cert_ipin'] || $config['cf_cert_hp']))
add_javascript('<script src="'.G5_JS_URL.'/certify.js?v='.G5_JS_VER.'"></script>', 0);
add_javascript('<script src="'.G5_JS_URL.'/certify.js"></script>', 0);
?>
<div class="register">
@@ -4,7 +4,7 @@ if (!defined("_GNUBOARD_")) exit; // 개별 페이지 접근 불가
<section id="bo_v_ans">
<?php
if($is_admin) // 관리자이면 답변등록
if($is_admin === 'super') // 최고관리자이면 답변등록
{
?>
<h2>답변등록</h2>
@@ -151,4 +151,4 @@ if (!defined("_GNUBOARD_")) exit; // 개별 페이지 접근 불가
<?php
}
?>
</section>
</section>
+1 -1
View File
@@ -11,7 +11,7 @@ add_javascript('<script src="'.G5_JS_URL.'/jquery.bxslider.js"></script>', 10);
<script>
var kakao_javascript_apikey = "<?php echo $config['cf_kakao_js_apikey']; ?>";
</script>
<script src="<?php echo G5_JS_URL; ?>/kakaolink.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="<?php echo get_versioned_asset_url(G5_JS_URL.'/kakaolink.js'); ?>"></script>
<?php } ?>
<form name="fitem" action="<?php echo $action_url; ?>" method="post" onsubmit="return fitem_submit(this);">
+3 -3
View File
@@ -27,7 +27,7 @@ add_stylesheet('<link rel="stylesheet" href="'.G5_MSHOP_SKIN_URL.'/style.css">',
if($row['iq_secret']) {
$iq_subject .= ' <img src="'.G5_MSHOP_SKIN_URL.'/img/icon_secret.gif" alt="비밀글">';
if($is_admin || $member['mb_id' ] == $row['mb_id']) {
if(is_shop_resource_owner_or_super_admin($row['mb_id'], $member['mb_id'], $is_admin)) {
$iq_question = get_view_thumbnail(conv_content($row['iq_question'], 1), $thumbnail_width);
} else {
$iq_question = '비밀글로 보호된 문의입니다.';
@@ -87,7 +87,7 @@ add_stylesheet('<link rel="stylesheet" href="'.G5_MSHOP_SKIN_URL.'/style.css">',
<?php } ?>
</div>
<?php if ($is_admin || ($row['mb_id'] == $member['mb_id'] && !$is_answer)) { ?>
<?php if ($is_admin === 'super' || ($row['mb_id'] == $member['mb_id'] && !$is_answer)) { ?>
<div class="sit_qa_cmd">
<a href="<?php echo $itemqa_form."&amp;iq_id={$row['iq_id']}&amp;w=u"; ?>" class="itemqa_form btn01" onclick="return false;">수정</a>
<a href="<?php echo $itemqa_formupdate."&amp;iq_id={$row['iq_id']}&amp;w=d&amp;hash={$hash}"; ?>" class="itemqa_delete btn01">삭제</a>
@@ -148,4 +148,4 @@ $(function(){
});
});
</script>
<!-- } 상품문의 목록 끝 -->
<!-- } 상품문의 목록 끝 -->
+2 -2
View File
@@ -46,7 +46,7 @@ add_stylesheet('<link rel="stylesheet" href="'.G5_MSHOP_SKIN_URL.'/style.css">',
if($row['iq_secret']) {
$iq_subject .= ' <i class="fa fa-lock" aria-hidden="true"></i>';
if($is_admin || $member['mb_id' ] == $row['mb_id']) {
if(is_shop_resource_owner_or_super_admin($row['mb_id'], $member['mb_id'], $is_admin)) {
$iq_question = get_view_thumbnail(conv_content($row['iq_question'], 1), $thumbnail_width);
} else {
$iq_question = '비밀글로 보호된 문의입니다.';
@@ -141,4 +141,4 @@ $(function(){
});
});
</script>
<!-- } 전체 상품 사용후기 목록 끝 -->
<!-- } 전체 상품 사용후기 목록 끝 -->
+2 -2
View File
@@ -52,7 +52,7 @@ add_stylesheet('<link rel="stylesheet" href="'.G5_MSHOP_SKIN_URL.'/style.css">',
<?php echo $is_content; // 사용후기 내용 ?>
</div>
<?php if ($is_admin || $row['mb_id'] == $member['mb_id']) { ?>
<?php if (is_shop_resource_owner_or_super_admin($row['mb_id'], $member['mb_id'], $is_admin)) { ?>
<div class="sit_use_cmd">
<a href="<?php echo $itemuse_form."&amp;is_id={$row['is_id']}&amp;w=u"; ?>" class="itemuse_form btn01" onclick="return false;">수정</a>
<a href="<?php echo $itemuse_formupdate."&amp;is_id={$row['is_id']}&amp;w=d&amp;hash={$hash}"; ?>" class="itemuse_delete btn01">삭제</a>
@@ -130,4 +130,4 @@ $(function(){
});
});
</script>
<!-- } 상품 사용후기 끝 -->
<!-- } 상품 사용후기 끝 -->
+1 -1
View File
@@ -13,7 +13,7 @@ add_javascript('<script src="'.G5_JS_URL.'/shop.list.action.js"></script>', 10);
<script>
var kakao_javascript_apikey = "<?php echo $config['cf_kakao_js_apikey']; ?>";
</script>
<script src="<?php echo G5_JS_URL; ?>/kakaolink.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="<?php echo get_versioned_asset_url(G5_JS_URL.'/kakaolink.js'); ?>"></script>
<?php } ?>
<!-- 메인상품진열 10 시작 { -->
+1 -1
View File
@@ -13,7 +13,7 @@ add_javascript('<script src="'.G5_JS_URL.'/shop.list.action.js"></script>', 10);
<script>
var kakao_javascript_apikey = "<?php echo $config['cf_kakao_js_apikey']; ?>";
</script>
<script src="<?php echo G5_JS_URL; ?>/kakaolink.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="<?php echo get_versioned_asset_url(G5_JS_URL.'/kakaolink.js'); ?>"></script>
<?php } ?>
<!-- 메인상품진열 10 시작 { -->
+1 -1
View File
@@ -14,7 +14,7 @@ add_javascript('<script src="'.G5_JS_URL.'/shop.list.action.js"></script>', 10);
<script>
var kakao_javascript_apikey = "<?php echo $config['cf_kakao_js_apikey']; ?>";
</script>
<script src="<?php echo G5_JS_URL; ?>/kakaolink.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="<?php echo get_versioned_asset_url(G5_JS_URL.'/kakaolink.js'); ?>"></script>
<?php } ?>
<!-- 메인상품진열 20 시작 { -->
+1 -1
View File
@@ -14,7 +14,7 @@ add_javascript('<script src="'.G5_JS_URL.'/shop.list.action.js"></script>', 10);
<script>
var kakao_javascript_apikey = "<?php echo $config['cf_kakao_js_apikey']; ?>";
</script>
<script src="<?php echo G5_JS_URL; ?>/kakaolink.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="<?php echo get_versioned_asset_url(G5_JS_URL.'/kakaolink.js'); ?>"></script>
<?php } ?>
<div class="st_30_wr">
<!-- 메인상품진열 30 시작 { -->
+1 -1
View File
@@ -11,7 +11,7 @@ add_stylesheet('<link rel="stylesheet" href="'.G5_MSHOP_SKIN_URL.'/style.css">',
<script>
var kakao_javascript_apikey = "<?php echo $config['cf_kakao_js_apikey']; ?>";
</script>
<script src="<?php echo G5_JS_URL; ?>/kakaolink.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="<?php echo get_versioned_asset_url(G5_JS_URL.'/kakaolink.js'); ?>"></script>
<?php } ?>
<!-- 상품진열 10 시작 { -->
+1 -1
View File
@@ -14,7 +14,7 @@ if( G5_SOCIAL_USE_POPUP ) {
$self_url = G5_SOCIAL_LOGIN_URL.'/popup.php';
}
add_stylesheet('<link rel="stylesheet" href="'.get_social_skin_url().'/style.css?ver='.G5_CSS_VER.'">', 10);
add_stylesheet('<link rel="stylesheet" href="'.get_social_skin_url().'/style.css">', 10);
?>
<div class="login-sns sns-wrap-32 sns-wrap-over" id="sns_login">
@@ -14,7 +14,7 @@ if( G5_SOCIAL_USE_POPUP ) {
$self_url = G5_SOCIAL_LOGIN_URL.'/popup.php';
}
add_stylesheet('<link rel="stylesheet" href="'.get_social_skin_url().'/style.css?ver='.G5_CSS_VER.'">', 10);
add_stylesheet('<link rel="stylesheet" href="'.get_social_skin_url().'/style.css">', 10);
?>
<div class="login-sns sns-wrap-32 sns-wrap-over" id="sns_outlogin">
+1 -1
View File
@@ -15,7 +15,7 @@ if( G5_SOCIAL_USE_POPUP ) {
}
// add_stylesheet('css 구문', 출력순서); 숫자가 작을 수록 먼저 출력됨
add_stylesheet('<link rel="stylesheet" href="'.get_social_skin_url().'/style.css?ver='.G5_CSS_VER.'">', 10);
add_stylesheet('<link rel="stylesheet" href="'.get_social_skin_url().'/style.css">', 10);
?>
<div>
<div class="login-sns sns-wrap-32 sns-wrap-over" id="sns_register">
@@ -8,11 +8,11 @@ if (!$config['cf_social_login_use']) { //소셜 로그인을 사용하지
// add_stylesheet('css 구문', 출력순서); 숫자가 작을 수록 먼저 출력됨
add_stylesheet('<link rel="stylesheet" href="'.G5_JS_URL.'/remodal/remodal.css">', 11);
add_stylesheet('<link rel="stylesheet" href="'.G5_JS_URL.'/remodal/remodal-default-theme.css">', 12);
add_stylesheet('<link rel="stylesheet" href="'.get_social_skin_url().'/style.css?ver='.G5_CSS_VER.'">', 13);
add_stylesheet('<link rel="stylesheet" href="'.get_social_skin_url().'/style.css">', 13);
add_javascript('<script src="'.G5_JS_URL.'/remodal/remodal.js"></script>', 10);
add_javascript('<script src="<?php echo G5_JS_URL ?>/jquery.register_form.js"></script>', 14);
if ($config['cf_cert_use'] && ($config['cf_cert_simple'] || $config['cf_cert_ipin'] || $config['cf_cert_hp']))
add_javascript('<script src="'.G5_JS_URL.'/certify.js?v='.G5_JS_VER.'"></script>', 15);
add_javascript('<script src="'.G5_JS_URL.'/certify.js"></script>', 15);
$email_msg = $is_exists_email ? '등록할 이메일이 중복되었습니다.다른 이메일을 입력해 주세요.' : '';
?>
@@ -9,7 +9,7 @@ $socials = social_get_provider_service_name('', 'all');
$session_id = session_id();
add_stylesheet('<link rel="stylesheet" href="'.get_social_skin_url().'/style.css?ver='.G5_CSS_VER.'">', 10);
add_stylesheet('<link rel="stylesheet" href="'.get_social_skin_url().'/style.css">', 10);
?>
<li>
-1
View File
@@ -217,7 +217,6 @@ class XPayClient
}
else
{
mt_srand((double)microtime()*10000);//optional for php 4.2.0 and up.
$charid = strtoupper(md5(uniqid(rand(), true)));
$hyphen = chr(45);
//$uuid = chr(123).substr($charid, 0, 8).$hyphen.substr($charid, 8, 4).$hyphen.substr($charid,12, 4).$hyphen.substr($charid,16, 4).$hyphen.substr($charid,20,12).chr(125);
+1 -1
View File
@@ -25,7 +25,7 @@ $bo_v_sns_class = $config['cf_kakao_js_apikey'] ? 'show_kakao' : '';
<?php if($config['cf_kakao_js_apikey']) { ?>
<script src="//developers.kakao.com/sdk/js/kakao.min.js" async charset="utf-8"></script>
<script src="<?php echo G5_JS_URL; ?>/kakaolink.js?ver=<?php echo G5_JS_VER; ?>" charset="utf-8"></script>
<script src="<?php echo get_versioned_asset_url(G5_JS_URL.'/kakaolink.js'); ?>" charset="utf-8"></script>
<script type='text/javascript'>
//<![CDATA[
var kakao_javascript_apikey = "<?php echo $config['cf_kakao_js_apikey']; ?>";
+2
View File
@@ -305,6 +305,8 @@ if($result) {
if($j > 20)
break;
}
$j++;
} while(1);
if($create_coupon) {
+8 -14
View File
@@ -1,22 +1,16 @@
<?php
include_once('../common.php');
if (isset($_REQUEST['sort']) && !preg_match("/(--|#|\/\*|\*\/)/", $_REQUEST['sort'])) {
$sort = trim($_REQUEST['sort']);
$sort = preg_replace("/[\<\>\'\"\\\'\\\"\%\=\(\)\s]/", "", $sort);
} else {
$sort = '';
}
if (isset($_REQUEST['sortodr'])) {
$sortodr = preg_match("/^(asc|desc)$/i", $sortodr) ? $sortodr : '';
} else {
$sortodr = '';
}
if (!defined('G5_USE_SHOP') || !G5_USE_SHOP)
die('<p>쇼핑몰 설치 후 이용해 주십시오.</p>');
$is_admin = get_super_admin_type($is_admin);
$request_sort = (isset($_REQUEST['sort']) && is_string($_REQUEST['sort'])) ? $_REQUEST['sort'] : '';
$request_sortodr = (isset($_REQUEST['sortodr']) && is_string($_REQUEST['sortodr'])) ? $_REQUEST['sortodr'] : '';
list($sort, $sortodr) = get_shop_item_sort($request_sort, $request_sortodr);
unset($request_sort, $request_sortodr);
define('_SHOP_', true);
define('_SHOP_COMMON_', true); // 모바일 페이지의 직접 접근을 막는 경우에 사용
?>
?>
+10 -5
View File
@@ -19,7 +19,8 @@ if(!($cp['cz_start'] <= G5_TIME_YMD && $cp['cz_end'] >= G5_TIME_YMD))
die(json_encode(array('error' => '다운로드할 수 없는 쿠폰입니다.')));
// 동시 요청으로 인한 쿠폰 중복 발급 방지
$lock_key = 'g5_coupon_dl_'.$cz_id.'_'.addslashes($member['mb_id']);
// 포인트는 회원 단위 자원이므로 쿠폰이 달라도 같은 회원의 요청은 직렬화한다.
$lock_key = 'g5_coupon_dl_'.addslashes($member['mb_id']);
$lock_row = sql_fetch(" select get_lock('$lock_key', 5) as lk ");
if(empty($lock_row['lk']))
die(json_encode(array('error' => '잠시 후 다시 시도해 주십시오.')));
@@ -30,10 +31,14 @@ if(is_coupon_downloaded($member['mb_id'], $cp['cz_id'])) {
die(json_encode(array('error' => '이미 다운로드하신 쿠폰입니다.')));
}
// 포인트 쿠폰은 회원포인트 체크
if($cp['cz_type'] && ($member['mb_point'] - $cp['cz_point']) < 0) {
sql_query(" do release_lock('$lock_key') ");
die(json_encode(array('error' => '보유하신 포인트가 부족하여 쿠폰을 다운로드할 수 없습니다.')));
// 포인트 쿠폰은 회원포인트 체크 (락 획득 후 최신 잔액으로 재확인)
if($cp['cz_type']) {
$row_pt = sql_fetch(" select mb_point from {$g5['member_table']} where mb_id = '{$member['mb_id']}' ");
if(($row_pt['mb_point'] - $cp['cz_point']) < 0) {
sql_query(" do release_lock('$lock_key') ");
die(json_encode(array('error' => '보유하신 포인트가 부족하여 쿠폰을 다운로드할 수 없습니다.')));
}
}
// 쿠폰발급
+6 -2
View File
@@ -15,6 +15,12 @@ sql_query($sql);
*/
$od_settle_case = isset($_POST['od_settle_case']) ? clean_xss_tags($_POST['od_settle_case'], 1, 1) : '';
// 저장되는 원본에도 정제한 값을 반영한다.
$_POST['od_settle_case'] = $od_settle_case;
// 결제환경 정보는 요청값을 사용하지 않고 서버에서 결정한다.
$_POST['od_test'] = $default['de_card_test'];
$_POST['od_ip'] = function_exists('get_real_client_ip') ? get_real_client_ip() : $_SERVER['REMOTE_ADDR'];
if(isset($_POST['pp_id']) && $_POST['pp_id']) {
$od_id = get_session('ss_personalpay_id');
@@ -32,8 +38,6 @@ if(isset($_POST['pp_id']) && $_POST['pp_id']) {
} else {
$od_id = get_session('ss_order_id');
$_POST['sw_direct'] = get_session('ss_direct');
$_POST['od_test'] = $default['de_card_test'];
$_POST['od_ip'] = $_SERVER['REMOTE_ADDR'];
if ($_POST['sw_direct']) {
$cart_id = get_session('ss_cart_direct');

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