GPF 버전2 개발자 설명서 > 개발자 포럼

본문 바로가기

[메뉴얼] GPF 버전2 개발자 설명서


GPF 버전2 개발자 설명서

이 문서는 그누보드 플러그인 프레임워크(GPF) 버전2 를 이용하여 플러그인을 개발하기 위한 설명서입니다. 순서는 아래와 같습니다.

  1. 개요
  2. 플러그인 생성하기
  3. 플러그인 프로그래밍하기
  4. 플러그인 적용 범위 (Scope)
  5. 플러그인 독립 실행
  6. 플러그인 데이터
  7. GPF 상수
  8. GPF 함수 API

대상

이 문서는 GPF 플러그인을 개발하고자 하는 개발자를 대상으로 합니다.

용어

  • GPF : 그누보드 플러그인 프레임워크 (Gnuboard Plugin Framework)
  • 플러그인(Plugin) : 그누보드를 변경하지 않고 기능을 구현하는 프로그램

문서이력

  • 2013-08-27 : 플러그인 데이터 부분 추가
  • 2013-08-26 : 초안 작성

1. 개요

GPF 플러그인은 그누보드 원본의 수정 없이 그누보드에 기능을 추가하거나, 그누보드와 연동하는 프로그램을 제작하는 등의 일을 할 수 있습니다.

2. 플러그인 생성하기

플러그인을 어떻게 만들 수 있는지에 대해 알아보도록 하겠습니다.

2.1 플러그인 이름

플러그인을 만들기로 결정했으면 우선 고유한 이름을 생각하시고, 플러그인 디렉토리를 생성합니다. 플러그인 디렉토리명은 GPF에서 플러그인 ID로 사용됩니다. 디렉토리명은 영어 소문자와 숫자, _ 로만 만들어주세요.

2.2 플러그인 파일

다음으로 플러그인 디렉토리에 plugin.php 파일을 생성합니다. plugin.php 파일은 플러그인이 활성화 되어있을 때에만 시스템에 로드됩니다. 이 파일에서 액션과 필터를 등록합니다. 액션과 필터에 대해서는 아래에서 설명드리도록 하겠습니다. 맛보기로 간단하게 게시글 보기 상단에 광고를 출력하는 플러그인을 소개합니다.

2.3 readme.txt 파일

플러그인의 정보를 포함하는 readme.txt (반드시 소문자) 파일을 반드시 작성하셔야 합니다. readme.txt 파일은 플러그인 정보를 제외하고는 마크다운 포멧으로 작성하시면 됩니다. 마크다운으로 작성된 내용은 러블리어스 플러그인 자료실에 업로드 되었을때, 본문 내용으로 보이게 됩니다. readme.txt 파일의 플러그인 파일은 아래와 같이 작성하세요.

Plugin Name: 내 플러그인
Description: 내가 처음 작성한 플러그인
Plugin URI: http://lovelyus.net/plugins/g4/my_plugin
Author: 내 이름
Author URI: http://mysite.com
Version: 1.0.0
Platform: GPF
Plugin Scope: BOARD
Required GPF Version: 2.0.0
Tested up to: 2.0.0
Plugin License: GPLv2
Tags: byfun, lovelyus
Donation URI: http://lovelyus.net/donation

내 플러그인
==========

이 플러그인은... 블라블라..

특징
----

  - 특징 1
  - 특징 2

업데이트
-------
   - 업데이트내역...

2.3.1 플러그인 정보

readme.txt 파일에 들어가는 플러그인 정보는 "필드명: 값" 의 형식으로 작성합니다. 필드명과 콜론(:)은 반드시 붙여서 작성합니다. 아래 설명을 참고해주세요. 반드시 입력해야 하는 정보는 굵게 표시하였습니다.

  • Plugin Name: 플러그인 이름. 원격 설치 페이지에 플러그인 명으로 나타납니다.
  • Description: 플러그인 설명. 원격 설치 페이지에 플러그인 설명으로 나타납니다.
  • Plugin URI: 플러그인 관련 URI 를 입력합니다. http 를 포함하여 작성합니다. 원격 설치 페이지에 링크가 나타납니다.
  • Author: 저자 이름, 원격 설치 페이지에 저자명으로 나타납니다.
  • Author URI: 저자 홈페이지. 원격 설치 페이지의 저자명에 링크가 생깁니다.
  • Version: 플러그인 버전.
  • Platform: 플러그인 플랫폼. GPF 나 GPF4S 를 입력합니다.
  • Plugin Scope: 플러그인 적용 범위. BOARD 나 SITE 를 입력합니다. (반드시 대문자)
  • Required GPF Version: 플러그인이 동작하기 위한 GPF 버전을 입력합니다.
  • Tested up to: 플러그인이 실행 가능한.. 테스트된 GPF 버전을 입력합니다.
  • Plugin License: 플러그인 라이선스 (GPLv2 .. 등을 간단히)
  • Tags: 태그. 콤마로 구분하여 작성합니다.
  • Donation URI: 플러그인 후원 링크. 원격 설치 페이지에 '플러그인 후원하기' 링크가 생깁니다.

3. 플러그인 프로그래밍 하기

플러그인 디렉토리, plugin.php, readme.txt 생성까지 했습니다. 이제 실제로 뭔가 동작하도록 하는 방법을 알아보도록 하겠습니다.

3.1 플러그인 후킹 (Hooks)

GPF 는 그누보드, GPF 또는 플러그인이 동작할 때 이벤트를 발생시킵니다. 플러그인은 이 이벤트를 잡아서(Hook) 원하는 기능을 구현합니다.

GPF 플러그인의 Hooks 에는 액션과 필터가 있습니다.

3.2 액션 (action)

액션은 게시글이 저장되거나, 사용자가 로그인하거나, 글을 읽거나 하는 등의 특정 시점에 실행되는 이벤트 핸들러입니다. 액션은 반환값(return)이 없으며, 플러그인의 기능만 수행하면 됩니다.

기본적으로 작성하는 순서는 아래와 같습니다.

  • GPF 가 발생시키는 이벤트를 실행할 PHP 함수를 plugin.php 파일에 작성
  • gp_add_action() 함수를 이용하여 이 함수를 이벤트에 등록
  • 플러그인 관리자에서 활성화 후, 테스트

3.2.1 액션 함수 만들기

plugin.php 파일에 이벤트를 처리하기 위한 액션 함수를 작성합니다. 예를 들어, 게시글 보기 상단에 광고를 넣는 함수를 만들고자 한다면, 액션 함수가 view.skin.php 가 include 되기 전에 실행되야 하고, view.skin.php 파일의 $view['content'] 변수 위에 광고 내용을 추가하면 될것입니다. 따라서 다음과 같이 작성합니다.

// view.skin.php 의 $view['content'] 앞에 광고 내용을 추가
function my_show_ads()
{
   // 전역변수 $view 의 'content' 필드에 광고 내용을 추가
   // 일반적으로 view.skin.php 에서 $view['content'] 를 출력하므로
   // 스킨에 관계없이 광고를 붙일 수 있겠죠?
   $GLOBALS['view']['content'] .= '<div class="my_ads">내 광고를 여기에...</div>';
}

주의할 점은 함수를 작성할 때, 함수명에 주의해야 합니다. 다른 플러그인에서 같은 함수를 사용할 경우, 에러가 나겠죠? 따라서 함수명 앞에 자신만의 prefix 를 붙인다던가 class 기반으로 작성하시면 되겠습니다. 클래스 기반으로 작성하면 아래와 같이 될 수 있습니다.

class MyPlugin 
{
   // view.skin.php 의 $view['content'] 앞에 광고 내용을 추가
   function my_show_ads()
   {
      // 전역변수 $view 의 'content' 필드에 광고 내용을 추가
      // 일반적으로 view.skin.php 에서 $view['content'] 를 출력하므로
      // 스킨에 관계없이 광고를 붙일 수 있겠죠?
      $GLOBALS['view']['content'] .= '<div class="my_ads">내 광고를 여기에...</div>';
   }
}

3.2.2 액션함수를 이벤트에 등록

액션 함수를 작성했으면, gp_add_action() 를 이용하여 액션함수를 GPF 에 등록합니다.

gp_add_action('이벤트명', '액션함수명', [우선순위], [허용파라미터수]);
// 이벤트명 : GPF 에서 발생시키는 이벤트명. (e.g. pre_write_update, post_list, pre_member_confirm ..)
// 액션함수명 : 이벤트를 처리할 함수명
// 우선순위 : 동일 이벤트에 대해 액션함수가 다수 등록되어있을 경우, 우선순위 값이 작은 순서대로 실행됩니다.
// 허용파라미터수 : 액션함수에서 사용하는 파라미터 개수. 그누보드의 스킨 이벤트에는 파라미터가 없습니다.

만약, 액션함수를 클래스 기반으로 작성했을 경우에는 아래와 같이 사용할 수 있습니다.

gp_add_action('이벤트명', array('플러그인 인스턴스', '액션함수 메소드명'), [우선순위], [허용파라미터수]);
// 플러그인 인스턴스 : 액션함수를 구현하고 있는 클래스의 인스턴스
// 액션함수 메소드명 : 클래스 내의 액션함수명

또는 간단한 기능의 경우 아래와 같이도 사용할 수 있습니다.

// PHP 5.3 이전 버전
gp_add_action('이벤트명', create_function('', '...'), [우선순위], [허용파라미터수]);

// PHP 5.3 버전부터 익명 함수 사용
gp_add_action('이벤트명', function() { .... }, [우선순위], [허용파라미터수]);

광고를 붙이는 예제 플러그인 코드를 합쳐보면 아래와 같습니다.

<?php
/**
  * 내 플러그인
  *
  * @package 내 패키지
  * @author Chongmyung Park <[email protected]>
  * @copyright Chongmyung Park
  * @license GPLv2 License http://www.gnu.org/licenses/gpl-2.0.html
  * @link http://lovelyus.net
  **/
if (!defined("_GNUBOARD_")) exit; // 개별 페이지 접근 불가

// 'bbs/view.php 에서 view.skin.php 가 include 되기전에 my_show_ads 함수를 실행시켜라'
// 라고 액션 등록
gp_add_action('pre_view', 'my_show_ads');

// view.skin.php 가 include 되기전 실행되는 함수
function my_show_ads()
{
   // 전역변수 $view 의 'content' 필드에 광고 내용을 추가
   // 일반적으로 view.skin.php 에서 $view['content'] 를 출력하므로
   // 스킨에 관계없이 광고를 붙일 수 있겠죠?
   $GLOBALS['view']['content'] .= '<div class="my_ads">내 광고를 여기에...</div>';
}
?>

클래스 기반으로 작성하면 아래와 같습니다.

<?php
/**
  * 내 플러그인
  *
  * @package 내 패키지
  * @author Chongmyung Park <[email protected]>
  * @copyright Chongmyung Park
  * @license GPLv2 License http://www.gnu.org/licenses/gpl-2.0.html
  * @link http://lovelyus.net
  **/
if (!defined("_GNUBOARD_")) exit; // 개별 페이지 접근 불가

// 플러그인 인스턴스 생성
$myPluginInstance = new MyPlugin();

// 'bbs/view.php 에서 view.skin.php 가 include 되기전에 my_show_ads 함수를 실행시켜라'
// 라고 액션 등록
gp_add_action('pre_view', array($myPluginInstance, 'my_show_ads') );

class MyPlugin 
{
   // view.skin.php 가 include 되기전 실행되는 함수
   function my_show_ads()
   {
      // 전역변수 $view 의 'content' 필드에 광고 내용을 추가
      // 일반적으로 view.skin.php 에서 $view['content'] 를 출력하므로
      // 스킨에 관계없이 광고를 붙일 수 있겠죠?
      $GLOBALS['view']['content'] .= '<div class="my_ads">내 광고를 여기에...</div>';
   }
}
?>

3.2.3 플러그인 활성화 및 테스트

플러그인을 작성하였으면, 플러그인 디렉토리를 [g4]/gp/plugins 에 업로드 합니다. 그리고 '그누보드 관리자 > 플러그인 > 플러그인' 에서 플러그인을 활성화 합니다. 잘 동작하는지 확인합니다.

3.3 필터 (Filter)

필터는 GPF 에서 필터함수에 데이터를 파라미터로 전달하고 필터함수로 부터 반환되는 데이터를 전달했던 데이터에 다시 셋팅합니다. 즉, 어떤 데이터를 가공할 필요가 있을 경우에 사용됩니다. 예를들면, 마크다운 플러그인에서 저장된 내용을 마크다운 라이브러리로 파싱한 후, 파싱된 데이터를 필터링하도록 작성했다면, 다른 플러그인에서 마크다운으로 파싱된 데이터를 재가공하여 자신만의 문법을 추가로 작성할 수 도 있을 것입니다.

필터의 사용방법은 액션함수와 동일하지만 등록하는 함수가 gp_add_action() 이 아니라 gp_add_filter 입니다. 그리고 필터함수는 반드시 데이터를 다시 반환해야 합니다. 그래야 다른 필터에서도 그 데이터를 재가공할 수 있을 것입니다.

3.3.1 필터 등록 방법

gp_add_filter('이벤트명', '필터함수명', [우선순위], [허용파라미터수]);
// 이벤트명 : GPF 에서 발생시키는 이벤트명.
// 필터함수명 : 이벤트를 처리할 함수명
// 우선순위 : 동일 이벤트에 대해 필터함수가 다수 등록되어있을 경우, 우선순위 값이 작은 순서대로 실행됩니다.
// 허용파라미터수 : 필터함수에서 사용하는 파라미터 개수. 그누보드의 스킨 이벤트에는 파라미터가 없습니다.

3.3.2 필터 작성 예제

// 필터 함수의 정의 및 등록 (plugin.php)
// 필터 등록 : 'plugin_filter_event' 이벤트에 'my_filter' 필터함수를 실행시켜라
gp_add_filter('plugin_filter_event', 'my_filter');
// 필터 정의 : $data 를 전달받아서 $data 뒤에 'Filtered Data' 문자열을 붙여서 반환함
function my_filter($data)
{
   return $data. '<br/>Filtered Data';
}

//////////////////

// 필터를 발생시키는 코드 (a.php)
// 데이터 준비
$data = 'This is test data';
// 데이터에 필터 적용
$data = gp_do_filter('plugin_filter_event', $data);
// 결과 출력
echo $data; 
// 결과 : This is test data<br/>Filtered Data

3.4 그누보드 액션

그누보드의 기능을 커스터마이징 하기 위해서는 그누보드의 스킨 시스템을 이해하고 있으면 도움이 됩니다.

GPF 는 그누보드가 게시판 스킨을 include 하기 전에 'pre_스킨명', include 한 후에 'post_스킨명' 의 액션 이벤트를 발생합니다. 예를 들어, [g4]/bbs/write_update.php 에서 write_update.skin.php 파일을 include 합니다. 이때, GPF는 'pre_write_update' 이벤트와 'post_write_update' 이벤트를 발생시킵니다. 마찬가지로 write_update.head.skin.php 가 include 될 때는, 'pre_write_update.head'와 'post_write_update.tail' 이벤트를 발생시킵니다.

GPF 에서 지원하는 그누보드 스킨은 아래와 같습니다. "include_once("...../스킨명.skin.php");" 의 각 스킨들에 대해 "pre_스킨명", "post_스킨명" 액션을 hook 하셔서 사용하세요.

calendar.php:include_once("$member_skin_path/calendar.skin.php");
current_connect.php:include_once("$connect_skin_path/current_connect.skin.php");
delete.php:@include_once("$board_skin_path/delete.head.skin.php");
delete.php:@include_once("$board_skin_path/delete.skin.php");
delete.php:@include_once("$board_skin_path/delete.tail.skin.php");
delete_all.php:@include_once("$board_skin_path/delete_all.head.skin.php");
delete_all.php:@include_once("$board_skin_path/delete_all.skin.php");
delete_all.php:@include_once("$board_skin_path/delete_all.tail.skin.php");
delete_comment.php:@include_once("$board_skin_path/delete_comment.head.skin.php");
delete_comment.php:@include_once("$board_skin_path/delete_comment.skin.php");
delete_comment.php:@include_once("$board_skin_path/delete_comment.tail.skin.php");
download.php:@include_once("$board_skin_path/download.head.skin.php");
download.php:@include_once("$board_skin_path/download.skin.php");
download.php:@include_once("$board_skin_path/download.tail.skin.php");
formmail.php:include_once("$member_skin_path/formmail.skin.php");
good.php:@include_once("$board_skin_path/good.head.skin.php");
good.php:@include_once("$board_skin_path/good.tail.skin.php");
list.php:include_once("$board_skin_path/list.skin.php");
login.php:include_once("$member_skin_path/login.skin.php");
login_check.php:@include_once("$member_skin_path/login_check.skin.php");
member_confirm.php:include_once("$member_skin_path/member_confirm.skin.php");
memo.php:include_once("$member_skin_path/memo.skin.php");
memo_form.php:include_once("$member_skin_path/memo_form.skin.php");
memo_view.php:include_once("$member_skin_path/memo_view.skin.php");
password.php:include_once("$member_skin_path/password.skin.php");
password_lost.php:include_once("$member_skin_path/password_lost.skin.php");
profile.php:include_once("$member_skin_path/profile.skin.php");
register.php:include_once("$member_skin_path/register.skin.php");
register_form.php:include_once("$member_skin_path/register_form.skin.php");
register_form_update.php:@include_once ("$g4[path]/skin/member/$config[cf_member_skin]/register_update.skin.php");
register_result.php:include_once("$member_skin_path/register_result.skin.php");
scrap.php:include_once("$member_skin_path/scrap.skin.php");
scrap_popin.php:include_once("$member_skin_path/scrap_popin.skin.php");
search.php:include_once("$search_skin_path/search.skin.php");
view.php:@include_once("$board_skin_path/view.head.skin.php");
view.php:include_once("$board_skin_path/view.skin.php");
view.php:@include_once("$board_skin_path/view.tail.skin.php");
view_comment.php:@include_once("$board_skin_path/view_comment.head.skin.php");
view_comment.php:include_once("$board_skin_path/view_comment.skin.php");
view_comment.php:@include_once("$board_skin_path/view_comment.tail.skin.php");
write.php:@include_once ("$g4[path]/skin/board/write.head.skin.php");
write.php:@include_once ("$board_skin_path/write.head.skin.php");
write.php:include_once ("$board_skin_path/write.skin.php");
write.php:@include_once ("$board_skin_path/write.tail.skin.php");
write_comment_update.php:@include_once("$board_skin_path/write_comment_update.head.skin.php");
write_comment_update.php:@include_once("$board_skin_path/write_comment_update.skin.php");
write_comment_update.php:@include_once("$board_skin_path/write_comment_update.tail.skin.php");
write_update.php:@include_once("$board_skin_path/write_update.head.skin.php");
write_update.php:@include_once ("$board_skin_path/write_update.skin.php");
write_update.php:@include_once("$board_skin_path/write_update.tail.skin.php");
zip.php:include_once("$member_skin_path/zip.skin.php");

4. 플러그인 적용 범위 (Scope)

GPF의 플러그인은 게시판 플러그인과 사이트 플러그인으로 나눕니다. (이에 대한 설명은 'GPF 버전2 사용자 설명서'를 참고해주세요) 이에 따라 플러그인을 설정하기 위해, GPF 에서는 SCOPE 라는 개념을 두었습니다. SCOPE 는 다음과 같이 정의되어 있습니다.

  • GP_SCOPE_SITE : 'SITE'
  • GP_SCOPE_GROUP : 'GROUP'
  • GP_SCOPE_BOARD : 'BOARD'

주의할 점은 readme.txt 의 'Plugin Scope' 에는 'GROUP' 은 사용되지 않습니다.

GPF 에서 플러그인들을 불러올 때, 전역변수로 $gp_scope 변수에 위 세 값중 하나가 설정되어있습니다. 따라서 플러그인에서는 이 $gp_scope 값을 다른 변수에 따로 저장하고, 필요에 따라 사용할 수 있습니다.

예를들어, GP_SCOPE_BOARD 인 플러그인을 개발했을 경우, 사용자는 '그룹'에 이 플러그인을 적용할 수 도 있고, '게시판'에 이 플러그인을 적용할 수 도 있습니다. 이때, 플러그인이 현재 '그룹' 범위에 활성화 된것인지, '게시판' 그룹에 활성화된 것인지를 판단하기 위해서는, plugin.php 에서 $gp_scope 를 가지고 판단할 수 밖에 없습니다.

이 $gp_scope 변수가 꼭 필요한 경우는, [g4]/gp/do.php 나 [g4]/adm/gp/admin_do.php 파일을 호출할 때 입니다. 'do.php?scope=GROUP&bo_table=게시판' 처럼 호출할 때, scope 파라미터를 넘기지 않고 bo_table 파라미터를 같이 넘길 경우, do.php 에서는 실행시 scope 를 'BOARD'로 판단하게 됩니다. 현재, 플러그인이 'BOARD' 로 활성화 되었는데도 말이죠.

5. 플러그인 실행 페이지 만들기

앞서 설명된 플러그인 개발은 그누보드가 실행 시 특정 이벤트에 대한 처리를 하는 형식이었습니다. 지금부터는 플러그인 자체로 실행되는 페이지를 만드는 방법을 설명드리겠습니다. 플러그인의 독립적인 실행 페이지가 필요한 경우 이 방법을 사용하실 수 있습니다.

플러그인 실행 페이지는 [g4]/gp/do.php 파일에 scope와 id, act 파라미터를 전달하므로써 구현할 수 있습니다. do.php 파일에서는 id 를 가진 plugin 만 로드를 하고, 'px_'.$act 액션 이벤트를 트리거합니다. 따라서 플러그인에서는 do.php 로 위 파라미터를 넘기고, 'px_'.$act 액션 이벤트 핸들러를 등록하여 기능을 구현합니다.

예를들어, 화면에 'Hello World'라고 출력하는 플러그인 실행 페이지를 만들어 보겠습니다.

// file:plugin.php
// GPF 에서 플러그인을 include 할 때, 설정된 $gp_scope 변수를 다른 변수에 저장함.
// BOARD, GROUP, SITE 각 유형의 플러그인들을 include 할 때마다, $gp_scope 값이 변하므로 임시로 저장해서 사용
$my_scope = $gp_scope;

// view.skin.php 가 include 되기 직전, link_to_helloworld()를 실행시키도록 등록
gp_add_action('pre_view', 'link_to_helloworld');

// do.php 에서는 URL 파라미터로 넘어온 act 값 앞에 'px_' 를 붙여서 액션함수를 호출함
// link_to_helloworld() 에서 do.php?...&act=hello_world ... 로 호출하므로,
// 'px_hello_world' 이벤트에 액션함수 등록
gp_add_action('px_hello_world', 'print_helloworld');

// 실행 페이지로의 링크 출력
function link_to_helloworld()
{
   global $my_scope;
   $my_plugin_id = gp_plugin_id(__FILE__);
   echo '<a href="'.GP_URL.'/do.php?scope='.$my_scope.'&id='.$my_plugin_id.'&act=hello_world">안녕 세상아~</a>';
}

// 실행 페이지
function print_helloworld()
{
   // 함수에서 전역 변수를 그대로 사용하기 위해서...(head.php 를 include 할꺼기 때문에)
   extract($GLOBALS);
   // [g4]의 head.php 불러옴 (G4_PATH 은 그누보드 설치 디렉토리의 절대경로로 define 되어있음)
   include_once G4_PATH.'/head.php';

   // 화면에 출력
   echo '<h1>안녕 세상아~</h1>';
   echo '내 플러그인의 실행 페이지 ^^';
   
   // [g4]의 tail.php 불러옴
   include_once G4_PATH.'/tail.php';
}

관리자 페이지에서는 [g4]/gp/do.php 가 아니라 [g4]/adm/gp/admin_do.php 를 사용하시면 됩니다. admin_do.php 는 최고관리자만 접근할 수 있으며, prefix 로 'px_' 가 붙지 않고 'pxa_' 가 붙습니다. 그 외에 사용법은 같습니다.

이와 같은 방법으로 그누보드 스킨 이벤트에 반응하는 플러그인 외에 독립적으로 실행되는 플러그인을 제작할 수 있습니다. 약간 템플릿 같은 방법으로 사용하는 방법을 예로 들어보겠습니다.

// file:plugin.php

// 플러그인 실행(PX) 핸들러 등록
gp_add_action('px_run', 'on_px');

// PX 핸들러
function on_px()
{
   // 함수에서 전역 변수를 그대로 사용하기 위해서...
   extract($GLOBALS);
   
   // 플러그인의 절대 경로
   $plugin_path = gp_plugin_path(__FILE__);

   // URL 로 전달된 s 파라미터
   $s = basename($_REQUEST['s']);

   // include 할 파일, $s 에 따라서 다른 파일을 include 해서 실행시킬 것임
   $module_file = $this->plugin_path.'/inc/'.$s.'.php';
   
   // 파일이 존재한다면...
   if(file_exists($module_file))
   {
     // 모듈 파일 include
     // 모듈 파일에 필요한 기능들을 구현함
     include_once $module_file;
     return;
   }
   
   // inc 폴더에 $s.php 파일이 존재하지 않을 경우, 잘못된 접근
   alert('내 플러그인 : 잘못된 접근');
}

6. 플러그인 데이터

플러그인을 개발하다보면, 임시로 저장하고 싶은 데이터가 있을 것입니다. 플러그인에도 여러 옵션을 둘 수 있을 테니까요. 이럴때 사용할 수 있는 방법은 플러그인 내에 직접 DB나 파일을 이용한 데이터 저장 메커니즘을 만들어 넣거나 또는 GPF에서 제공하는 플러그인 설정 저장/읽기 API 를 사용하는 것입니다.

설정 저장 시에는 gp_write_config() 를 사용할 수 있고, 설정을 로드할 때는 gp_read_config() API를 사용합니다. 함수의 원형은 아래와 같습니다.

 /**
  * gp_write_config : 플러그인 설정 저장
  *
  * <g4>/data/gp/ 하위의 각 scope/scope_id 에 해당하는 디렉토리에 설정을 serialize 해서 저장함.
  *
  * @param string $config_file 설정파일명 (주의! 반드시 .php 파일로 저장해야 경로를 알아도 브라우져로 확인할 수 없음)
  * @param mixed $config 설정변수
  * @param string $scope 플러그인 적용 범위 (SITE, GROUP, BOARD)
  * @param string $scope_id scope가 GROUP 이면 $gr_id, BOARD 면 $bo_table
  * @access public
  * @return mixed 쓴 bytes 수 또는 FALSE
  */
function gp_write_config($config_file, $config, $scope = '', $scope_id = '');

 /**
  * gp_read_config : 플러그인 설정 읽기
  *
  * @param string $config_file 설정파일명
  * @param mixed $default_data 설정내용이 없을 경우 반환할 기본값
  * @param string $scope 플러그인 적용 범위 (SITE, GROUP, BOARD)
  * @param string $scope_id scope가 GROUP 이면 $gr_id, BOARD 면 $bo_table
  * @access public
  * @return mixed 저장되어있던 설정 내용
  */
function gp_read_config($config_file, $default_data = null, $scope = '', $scope_id = '');

사용 예제를 보겠습니다.

// file:plugin.php

// 저장할 파일명(확장자를 .php로 합니다)
$my_config_file = 'cfg.my_plugin.php';

// 현재 스코프 (게시판)
$my_scope = GP_SCOPE_BOARD;

// 스코프 아이디
// 스코프가 BOARD 이므로, scope_id 에는 $bo_table 값이 들어가야 합니다
$my_scope_id = 'freeboard';

// 위와 같은 설정 일 때,
// 설정은 [g4]/data/gp/board/freeboard/cfg.my_plugin.php 파일에 serialize 되서 저장됩니다.
// 이때, 브라우져로 접근해도 내용이 보이지 않도록 처리되어있습니다.

// 저장할 설정 데이터 : 배열, 객체, 일반 변수 등
$config_data = array('id'=>'byfun', 'nick'=>'동하아빠');

// 저장, 반환값이 false 이면 저장이 실패했음을 의미
if(!gp_write_config($my_config_file, $config_data, $my_scope, $my_scope_id))
   die('설정 저장 실패');

// 저장된 값을 다시 읽어옴
$loaded_config = gp_read_config($my_config_file, $default_data=array(), $my_scope, $my_scope_id);

// 출력
var_dump($loaded_config);

이와 같은 방법으로 간단한 설정은 DB를 사용하지 않고 할 수 있습니다.

7. GPF 상수

GPF 의 상수는 [g4]/extend/gp.extend.php 파일에 정의되어있습니다. gp.extend.php 파일 내용중 일부와 주석을 첨부한 아래 코드 파일을 참고해주세요.

플러그인 개발시 G4와 G4S를 모두 고려한다면, 이곳에 선언된 상수들을 사용하실 것을 권장합니다. 특히, $g4['path']의 경우 경로 문제가 발생할 수 있으므로, js나 css 를 불러오는 경우나 다른 페이지로의 이동을 할 경우엔 G4_URL 을 사용하시고, 다른 php 파일을 include 할 경우엔 G4_PATH 상수를 사용하세요.

// 하단에 나오는 모든 PATH 변수는 '절대경로' 임

define('GP_VERSION', '2.0.3'); // GPF 버전
define('GP', 'Gnuboard Plugins'); // GP 임을 선언
define('GP_HOST', $_SERVER['HTTP_HOST']); // 서버 호스트

// G4인지 G4S 인지 설정
if(defined('G4_PATH'))
{
   define('GP_PLATFORM', 'GPF4S');
   define('GB_PLATFORM', 'G4S');
   define('IS_G4', false);
   define('IS_G4S', true);
 } else {
   define('GP_PLATFORM', 'GPF');
   define('GB_PLATFORM', 'G4');
   define('IS_G4', true);
   define('IS_G4S', false);
 }

// GPF 디렉토리
define('GP_DIR', 'gp');

// 디렉토리 구분자
define('DS', DIRECTORY_SEPARATOR);

// G4S 에 있는 상수들, G4 에도 사용할 수 있도록 함
if(!defined('G4_PATH'))
 {
   define('G4_PATH', realpath($g4['path'])); // G4 경로 (절대경로)
   define('G4_URL', $g4['url']); // G4 URL (config.php 파일에 명시적으로 정의하는게 좋음)

   define('G4_ADMIN_DIR', $g4['admin']); // 관리자 디렉토리명
   define('G4_BBS_DIR', $g4['bbs']); // bbs 디렉토리명
   define('G4_DATA_DIR', 'data'); // data 디렉토리명
   define('G4_EXTEND_DIR', 'extend'); // extend 디렉토리명
   define('G4_LIB_DIR', 'lib'); // lib 디렉토리명
   define('G4_SKIN_DIR', 'skin'); // skin 디렉토리명

   define('G4_SERVER_TIME', $g4['server_time']); // 서버 시간
   define('G4_TIME_YMDHIS', $g4['time_ymdhis']); // 서버 시간 YMDHIS
   define('G4_TIME_YMD', $g4['time_ymd']); // 서버 시간 YMD
   define('G4_TIME_HIS', $g4['time_his']); // 서버 시간 HIS

   define('G4_ADMIN_URL', G4_URL.'/'.G4_ADMIN_DIR); // G4 관리자 페이지 URL
   define('G4_BBS_URL', G4_URL.'/'.G4_BBS_DIR); // G4 BBS URL
   define('G4_DATA_URL', G4_URL.'/'.G4_DATA_DIR); // G4 데이터 URL
   define('G4_SKIN_URL', G4_URL.'/'.G4_SKIN_DIR); // G4 스킨 URL

   define('G4_ADMIN_PATH', G4_PATH.DS.G4_ADMIN_DIR); // G4 관리자 경로
   define('G4_BBS_PATH', G4_PATH.DS.G4_BBS_DIR); // G4 BBS 경로
   define('G4_DATA_PATH', G4_PATH.DS.G4_DATA_DIR); // G4 데이터 경로
   define('G4_LIB_PATH', G4_PATH.DS.G4_LIB_DIR); // G4 lib 경로
   define('G4_SKIN_PATH', G4_PATH.DS.G4_SKIN_DIR); // G4 스킨 경로

   define('G4_MYSQL_HOST', $mysql_host); // DB 호스트
   define('G4_MYSQL_USER', $mysql_user); // DB 유저
   define('G4_MYSQL_PASSWORD', $mysql_password); // DB 패스워드
   define('G4_MYSQL_DB', $mysql_db);

   define('G4_TABLE_PREFIX', $g4['table_prefix']); // G4 db 테이블 prefix
 }

 define('GP_INTERCEPT_SKIN', '.gp'); // member, search 스킨 인터셉트 스킨 디렉토리명
 // ajax 요청인지 아닌지
 define('GP_AJAXING', !empty($_SERVER['HTTP_X_REQUESTED_WITH']) 
        && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'); 
 // GPF 데이터 최상위 경로 (그누보드 데이터 경로에 gp 디렉토리)
 define('GP_DATA_ROOT_PATH', G4_PATH.DS.G4_DATA_DIR.DS.'gp'); 

 define('GP_SCOPE_BOARD', 'BOARD'); // 플러그인 scope : board
 define('GP_SCOPE_GROUP', 'GROUP'); // 플러그인 scope : group
 define('GP_SCOPE_SITE', 'SITE'); // 플러그인 scope : site

 define('GP_PATH', G4_PATH.DS.GP_DIR); // GPF 경로 ([g4]/gp)
 define('GP_URL', G4_URL.'/'.GP_DIR); // GPF URL (http://그누보드/gp)
 define('GP_ADMIN_PATH', G4_ADMIN_PATH.DS.GP_DIR); // GPF 관리자 페이지 경로 ([g4]/adm/gp)
 define('GP_ADMIN_URL', G4_ADMIN_URL.'/'.GP_DIR); // GPF 관리자 URL (http://그누보드/adm/gp)
 define('GP_PLUGIN_PATH', GP_PATH.DS.'plugins'); // GPF 플러그인 경로 ([g4]/gp/plugins)
 define('GP_PLUGIN_URL', GP_URL.'/plugins'); // GPF 플러그인 URL (http://그누보드/gp/plugins)

8. GPF 함수 API

API 는 이 문서를 참고해주세요.

이 글을 읽은 사람들 12314151sxs 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , coros 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 추모태황 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 실버크래프트 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 박태진 쪽지보내기 메일보내기 홈페이지 자기소개 아이디로 검색 전체게시물 , 노을 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 아스케키 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 태경 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 배성원 쪽지보내기 메일보내기 홈페이지 자기소개 아이디로 검색 전체게시물 , 딸기우유주까 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , silvia 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 천승재 쪽지보내기 메일보내기 홈페이지 자기소개 아이디로 검색 전체게시물 , 문정운 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 요요 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , princejey 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 비용러브 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 딩동2310 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 휴먼 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 모기씨 쪽지보내기 메일보내기 홈페이지 자기소개 아이디로 검색 전체게시물 , 이팀장 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , ch930701 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 나미에요 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , leyn 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , sdate 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 최진성 쪽지보내기 메일보내기 홈페이지 자기소개 아이디로 검색 전체게시물 , 고희정 쪽지보내기 메일보내기 홈페이지 자기소개 아이디로 검색 전체게시물 , 일반인 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 만만 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 북풍 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물 , 강강강 쪽지보내기 메일보내기 자기소개 아이디로 검색 전체게시물
이 글을 읽은 사람들이 본 다른 글들

댓글 보기

1.
3.3.1 필터 등록 방법 에서
gp_add_action 코드가 첨부되었네요. ^^;

근데 api 문서에서는, 첫번째 인자가 'name: 필터명'으로 되어 있네요?
위의 'data' 가 맞는것이겠죠?

2.
do.php 이용법에서 act 인자의 의미는?

1.
- copy&paste 의 폐해죠.. ㅎㅎ 고쳤습니다.
- 첫번째 파라미터가 name 이 맞습니다. 위에.. 'some_plugin_data' 라고 해놨던게 '필터명' 이었는데 혼란이 돼나봅니다. 'plugin_filter_event' 로 변경했습니다.

2. do.php 에.. act 가 넘어가면... do.php 에서 'px_'.$act 이벤트가 트리거됩니다. admin_do.php 에서는 'pxa_'.$act 이벤트가 트리거 됩니다... 설명을 조금 추가했습니다

왠지 논문 revision 하는 느낌 ㅎㅎ 어째뜬.. 전진님 밖에 없어요 T_T

아, 그렇네요..
add_filter와 do_filter 를 헷갈렸네요. ^^;

act인자로 이벤트 트리거군요.. (아마 나린위키도 그랬던것 같은... 가물가물..-_-)

지난번 나린위키는, 원래 사용하던 미디어위키에서 사용하던 추가기능을 만드는 것이라
뭘 만들지 고민을 하지 않았는데,
gpf는 뭘 만들지 고민부터 해야..
반응형 테마/스킨 이 좋을것 같은데.. 좀 들여다 봐야겠네요. ^^;

전에 만났을 때 보여드렸던.. 스키넬 스킨을 다운받아 보시면..
온통 gp_do_action(), gp_do_filter() 로 도배되어있어요.. 스킨을 GPF 플러그인으로 제어하기 위해서 ^^;
그리고 list, view, write 에 table 코딩을 배제해서 responsive 를 시도할 수 있게 했어요 ㅎㅎ
--------------
나린위키 때와 비슷하죠 ^^ GPF의 시작은 나린위키... ㅎㅎ

읽어보고 연구해 봐야 겠네요 좋네요^^