git-svn-id: http://xe-core.googlecode.com/svn/sandbox@2327 201d5d3c-b55e-5fd7-737f-ddc643e51545
This commit is contained in:
zero 2007-08-12 03:59:52 +00:00
commit 8326004cb2
2773 changed files with 91485 additions and 0 deletions

View file

@ -0,0 +1,394 @@
<?php
if(!defined("__ZBXE__")) exit();
/**
* @file blogapicounter.addon.php
* @author zero (zero@nzeo.com)
* @brief blogAPI 애드온
*
* ms live writer, 파이어폭스의 performancing, zoundry 등의 외부 툴을 이용하여 글을 입력할 있게 합니다.
* 모듈 실행 이전(before_module_proc) 호출이 되어야 하며 정상동작후에는 강제 종료를 한다.
**/
// called_position가 after_module_proc일때 rsd 태그 삽입
if($called_position == 'after_module_proc') {
// 현재 모듈의 rsd주소를 만듬
$rsd_url = sprintf('%s%s/api', Context::getRequestUri(), $this->mid);
// 헤더에 rsd태그 삽입
Context::addHtmlHeader(" ".'<link rel="EditURI" type="application/rsd+xml" title="RSD" href="'.$rsd_url.'" />');
}
// act가 api가 아니면 그냥 리턴~
if($_REQUEST['act']!='api') return;
/**
* blogapi의 경우 GET argument와 XML Content가 같이 오기에 제로보드XE의 경우 XML Content가 오면 이것만 처리하기에
* GET argument중에 mid값을 강제 설정해야 모듈을 정상적으로 찾는다
**/
if($called_position == 'before_module_init') {
$mid = $_REQUEST['mid'];
Context::set('mid', $mid, true);
$this->mid = $mid;
}
// 관련 func 파일 읽음
require_once('./addons/blogapi/blogapi.func.php');
// xmlprc 파싱
// 요청된 xmlrpc를 파싱
$oXmlParser = new XmlParser();
$xmlDoc = $oXmlParser->parse();
$method_name = $xmlDoc->methodcall->methodname->body;
$params = $xmlDoc->methodcall->params->param;
if($params && !is_array($params)) $params = array($params);
// blogger.deletePost일 경우 첫번째 인자 값 삭제
if($method_name == 'blogger.deletePost') array_shift($params);
// user_id, password를 구해서 로그인 시도
$user_id = trim($params[1]->value->string->body);
$password = trim($params[2]->value->string->body);
// 모듈 실행전이라면 인증을 처리한다.
if($called_position == 'before_module_init') {
// member controller을 이용해서 로그인 시도
if($user_id && $password) {
$oMemberController = &getController('member');
$output = $oMemberController->doLogin($user_id, $password);
// 로그인 실패시 에러 메시지 출력
if(!$output->toBool()) {
$content = getXmlRpcFailure(1, $output->getMessage());
printContent($content);
}
} else {
$content = getXmlRpcFailure(1, 'not logged');
printContent($content);
}
}
// 모듈에서 무언가 작업을 하기 전에 blogapi tool의 요청에 대한 처리를 하고 강제 종료한다.
if($called_position == 'before_module_proc') {
// 글쓰기 권한 체크 (권한명의 경우 약속이 필요할듯..)
if(!$this->grant->write_document) {
printContent( getXmlRpcFailure(1, 'no permission') );
}
// 카테고리의 정보를 구해옴
$oDocumentModel = &getModel('document');
$category_list = $oDocumentModel->getCategoryList($this->module_srl);
// 임시 파일 저장 장소 지정
$tmp_uploaded_path = sprintf('./files/cache/blogapi/%s/%s/', $this->mid, $user_id);
$uploaded_target_path = sprintf('/files/cache/blogapi/%s/%s/', $this->mid, $user_id);
switch($method_name) {
// 블로그 정보
case 'blogger.getUsersBlogs' :
$obj->url = Context::getRequestUri().$this->mid;
$obj->blogid = $this->mid;
$obj->blogName = $this->module_info->browser_title;
$blog_list = array($obj);
$content = getXmlRpcResponse($blog_list);
printContent($content);
break;
// 카테고리 목록 return
case 'metaWeblog.getCategories' :
$category_obj_list = array();
if($category_list) {
foreach($category_list as $category_srl => $category_info) {
unset($obj);
$obj->description = $category_info->title;
//$obj->htmlUrl = Context::getRequestUri().$this->mid.'/1';
//$obj->rssUrl= Context::getRequestUri().'rss/'.$this->mid.'/1';
$obj->title = $category_info->title;
$obj->categoryid = $category_srl;
$category_obj_list[] = $obj;
}
}
$content = getXmlRpcResponse($category_obj_list);
printContent($content);
break;
// 파일 업로드
case 'metaWeblog.newMediaObject' :
// 파일 업로드 권한 체크
if(!$this->grant->fileupload) {
printContent( getXmlRpcFailure(1, 'no permission') );
}
$fileinfo = $params[3]->value->struct->member;
foreach($fileinfo as $key => $val) {
$nodename = $val->name->body;
if($nodename == 'bits') $filedata = base64_decode($val->value->base64->body);
elseif($nodename == 'name') $filename = $val->value->string->body;
}
$tmp_arr = explode('/',$filename);
$filename = array_pop($tmp_arr);
if(!is_dir($tmp_uploaded_path)) FileHandler::makeDir($tmp_uploaded_path);
$target_filename = sprintf('%s%s', $tmp_uploaded_path, $filename);
FileHandler::writeFile($target_filename, $filedata);
$obj->url = Context::getRequestUri().$target_filename;
$content = getXmlRpcResponse($obj);
printContent($content);
break;
// 글작성
case 'metaWeblog.newPost' :
unset($obj);
$info = $params[3];
// 글, 제목, 카테고리 정보 구함
for($i=0;$i<count($info->value->struct->member);$i++) {
$val = $info->value->struct->member[$i];
switch($val->name->body) {
case 'title' :
$obj->title = $val->value->string->body;
break;
case 'description' :
$obj->content = $val->value->string->body;
break;
case 'categories' :
$categories = $val->value->array->data->value;
if(!is_array($categories)) $categories = array($categories);
$category = $categories[0]->string->body;
if($category && $category_list) {
foreach($category_list as $category_srl => $category_info) {
if($category_info->title == $category) $obj->category_srl = $category_srl;
}
}
break;
case 'tagwords' :
$tags = $val->value->array->data->value;
if(!is_array($tags)) $tags = array($tags);
for($j=0;$j<count($tags);$j++) {
$tag_list[] = $tags[$j]->string->body;
}
if(count($tag_list)) $obj->tags = implode(',',$tag_list);
break;
}
}
// 문서 번호 설정
$document_srl = getNextSequence();
$obj->document_srl = $document_srl;
$obj->module_srl = $this->module_srl;
// 첨부파일 정리
if(is_dir($tmp_uploaded_path)) {
$file_list = FileHandler::readDir($tmp_uploaded_path);
$file_count = count($file_list);
if($file_count) {
$oFileController = &getController('file');
for($i=0;$i<$file_count;$i++) {
$file_info['tmp_name'] = sprintf('%s%s', $tmp_uploaded_path, $file_list[$i]);
$file_info['name'] = $file_list[$i];
$oFileController->insertFile($file_info, $this->module_srl, $document_srl, 0, true);
}
$obj->uploaded_count = $file_count;
}
}
$obj->content = str_replace($uploaded_target_path,sprintf('/files/attach/images/%s/%s/%s', $this->module_srl, $document_srl, $filename), $obj->content);
$oDocumentController = &getController('document');
$obj->allow_comment = 'Y';
$obj->allow_trackback = 'Y';
$output = $oDocumentController->insertDocument($obj);
if(!$output->toBool()) {
$content = getXmlRpcFailure(1, $output->getMessage());
} else {
//$content = getXmlRpcResponse(Context::getRequestUri().$this->mid.'/'.$document_srl);
$content = getXmlRpcResponse(''.$document_srl);
}
FileHandler::removeDir($tmp_uploaded_path);
printContent($content);
break;
// 글 수정
case 'metaWeblog.editPost' :
$tmp_val = $params[0]->value->string->body;
$tmp_arr = explode('/', $tmp_val);
$document_srl = array_pop($tmp_arr);
$oDocumentModel = &getModel('document');
$oDocument = $oDocumentModel->getDocument($document_srl);
// 글 수정 권한 체크
if(!$oDocument->isGranted()) {
$content = getXmlRpcFailure(1, 'no permission');
break;
}
$obj = $oDocument->getObjectVars();
$info = $params[3];
// 글, 제목, 카테고리 정보 구함
for($i=0;$i<count($info->value->struct->member);$i++) {
$val = $info->value->struct->member[$i];
switch($val->name->body) {
case 'title' :
$obj->title = $val->value->string->body;
break;
case 'description' :
$obj->content = $val->value->string->body;
break;
case 'categories' :
$categories = $val->value->array->data->value;
if(!is_array($categories)) $categories = array($categories);
$category = $categories[0]->string->body;
if($category && $category_list) {
foreach($category_list as $category_srl => $category_info) {
if($category_info->title == $category) $obj->category_srl = $category_srl;
}
}
break;
case 'tagwords' :
$tags = $val->value->array->data->value;
if(!is_array($tags)) $tags = array($tags);
for($j=0;$j<count($tags);$j++) {
$tag_list[] = $tags[$j]->string->body;
}
if(count($tag_list)) $obj->tags = implode(',',$tag_list);
break;
}
}
// 문서 번호 설정
$obj->document_srl = $document_srl;
$obj->module_srl = $this->module_srl;
// 첨부파일 정리
if(is_dir($tmp_uploaded_path)) {
$file_list = FileHandler::readDir($tmp_uploaded_path);
$file_count = count($file_list);
if($file_count) {
$oFileController = &getController('file');
for($i=0;$i<$file_count;$i++) {
$file_info['tmp_name'] = sprintf('%s%s', $tmp_uploaded_path, $file_list[$i]);
$file_info['name'] = $file_list[$i];
$moved_filename = sprintf('./files/attach/images/%s/%s/%s', $this->module_srl, $document_srl, $file_info['name']);
if(file_exists($moved_filename)) continue;
$oFileController->insertFile($file_info, $this->module_srl, $document_srl, 0, true);
}
$obj->uploaded_count += $file_count;
}
}
$obj->content = str_replace($uploaded_target_path,sprintf('/files/attach/images/%s/%s/%s', $this->module_srl, $document_srl, $filename), $obj->content);
$oDocumentController = &getController('document');
$output = $oDocumentController->updateDocument($oDocument,$obj);
if(!$output->toBool()) {
$content = getXmlRpcFailure(1, $output->getMessage());
} else {
$content = getXmlRpcResponse(Context::getRequestUri().$this->mid.'/'.$document_srl);
FileHandler::removeDir($tmp_uploaded_path);
}
printContent($content);
break;
// 글삭제
case 'blogger.deletePost' :
$tmp_val = $params[0]->value->string->body;
$tmp_arr = explode('/', $tmp_val);
$document_srl = array_pop($tmp_arr);
// 글 받아오기
$oDocumentModel = &getModel('document');
$oDocument = $oDocumentModel->getDocument($document_srl);
// 글 삭제 권한 체크
if(!$oDocument->isGranted()) {
$content = getXmlRpcFailure(1, 'no permission');
break;
}
$oDocumentController = &getController('document');
$output = $oDocumentController->deleteDocument($document_srl);
if(!$output->toBool()) $content = getXmlRpcFailure(1, $output->getMessage());
else $content = getXmlRpcResponse(true);
printContent($content);
break;
// 최신글 받기
case 'metaWeblog.getRecentPosts' :
// 목록을 구하기 위한 옵션
$args->module_srl = $this->module_srl; ///< 현재 모듈의 module_srl
$args->page = 1;
$args->list_count = 20;
$args->sort_index = 'list_order'; ///< 소팅 값
$output = $oDocumentModel->getDocumentList($args);
if(!$output->toBool() || !$output->data) {
$content = getXmlRpcFailure(1, 'post not founded');
printContent($content);
} else {
$oContext = &Context::getInstance();
$posts = array();
foreach($output->data as $key => $oDocument) {
$post = null;
$post->link = $post->permaLink = getUrl('','mid',$this->mid,'document_srl',$oDocument->document_srl);
$post->userid = $oDocument->get('user_id');
$post->mt_allow_pings = 0;
$post->mt_allow_comments = $oDocument->allowComment()=='Y'?1:0;
$post->description = htmlspecialchars($oContext->transContent($oDocument->get('content')));
$post->postid = $oDocument->document_srl;
$post->title = htmlspecialchars($oDocument->get('title'));
$year = substr($oDocument->get('regdate'),0,4);
$month = substr($oDocument->get('regdate'),4,2);
$day = substr($oDocument->get('regdate'),6,2);
$hour = substr($oDocument->get('regdate'),8,2);
$min = substr($oDocument->get('regdate'),10,2);
$sec = substr($oDocument->get('regdate'),12,2);
$time = mktime($hour,$min,$sec,$month,$day,$year);
$post->dateCreated = gmdate("D, d M Y H:i:s", $time);
$posts[] = $post;
}
$content = getXmlRpcResponse($posts);
printContent($content);
}
break;
// 아무런 요청이 없을 경우 RSD 출력
default :
$homepagelink = getUrl('','mid',$this->mid);
$api_url = sprintf('%s%s/api', Context::getRequestUri(), $this->mid);
$content = <<<RSDContent
<?xml version="1.0" ?>
<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd" >
<service>
<engineName>zeroboardXE</engineName>
<engineLink>http://www.zeroboard.com/ </engineLink>
<homePageLink>{$homepagelink}</homePageLink>
<apis>
<api name="MetaWeblog" preferred="true" apiLink="{$api_url}" blogID="" />
</apis>
</service>
</rsd>
RSDContent;
printContent($content);
break;
}
}
?>

View file

@ -0,0 +1,67 @@
<?php
if(!defined("__ZBXE__")) exit();
/**
* @file ./addons/blogapi/blogapi.func.php
* @author zero (zero@nzeo.com)
* @brief blogapi구현을 위한 함수 모음집
**/
// 오류 표시
function getXmlRpcFailure($error, $message) {
return
sprintf(
"<methodResponse>\n<fault><value><struct>\n<member>\n<name>faultCode</name>\n<value><int>%d</int></value>\n</member>\n<member>\n<name>faultString</name>\n<value><string>%s</string></value>\n</member>\n</struct></value></fault>\n</methodResponse>\n",
$error,
htmlspecialchars($message)
);
}
// 결과 표시
function getXmlRpcResponse($params) {
$buff = '<?xml version="1.0" encoding="utf-8"?>'."\n<methodResponse><params>";
$buff .= _getEncodedVal($params);
$buff .= "</params>\n</methodResponse>\n";
return $buff;
}
// 인코딩 처리
function _getEncodedVal($val, $is_sub_set = false) {
if(is_int($val)) $buff = sprintf("<value><i4>%d</i4></value>", $val);
elseif(is_double($val)) $buff = sprintf("<value><double>%f</double></value>", $val);
elseif(is_bool($val)) $buff = sprintf("<value><boolean>%d</boolean></value>", $val?1:0);
elseif(is_object($val)) {
$values = get_object_vars($val);
$val_count = count($values);
$buff = "<value><struct>";
foreach($values as $k => $v) {
$buff .= sprintf("<member>\n<name>%s</name>\n%s</member>\n", htmlspecialchars($k), _getEncodedVal($v, true));
}
$buff .= "</struct></value>\n";
} elseif(is_array($val)) {
$val_count = count($val);
$buff = "<value><array>\n<data>";
for($i=0;$i<$val_count;$i++) {
$buff .= _getEncodedVal($val[$i], true);
}
$buff .= "</data>\n</array></value>";
} else {
$buff = sprintf("<value><string>%s</string></value>\n", $val);
}
if(!$is_sub_set) return sprintf("<param>\n%s</param>", $buff);
return $buff;
}
// 결과 출력
function printContent($content) {
header("Content-Type: text/xml; charset=UTF-8");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
print $content;
exit();
}
?>

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<addon version="0.1">
<title xml:lang="ko">BlogAPI 애드온</title>
<title xml:lang="jp">BlogAPI </title>
<title xml:lang="zh-CN">BlogAPI</title>
<title xml:lang="en">Addon for BlogAPI</title>
<title xml:lang="es">BlogAPI Adicionales</title>
<author email_address="zero@zeroboard.com" link="http://www.zeroboard.com" date="2007. 2. 28">
<name xml:lang="ko">제로</name>
<name xml:lang="jp">Zero</name>
<name xml:lang="zh-CN">zero</name>
<name xml:lang="en">zero</name>
<name xml:lang="es">zero</name>
<description xml:lang="ko">
metaWeblog를 지원하는 blogApi애드온입니다.
사용으로 설정하시면 각 모듈마다 RSD 태그를 노출합니다.
api의 주소는 http://설치주소/모듈명/api 입니다.
사용으로 하셔야 RSD태그 및 api가 동작을 합니다.
</description>
<description xml:lang="jp">
MetaWeblogをサポートするBlogAPI アドオンです。「使用する」をクリックして設定すると各モジュールごとRSDのアドレスを表示します。API のアドレスは「http://インストールURL/モジュール名/api」です。 「使用する」に設定しておけば RSDのアドレスが表示され、 API が動作します。
</description>
<description xml:lang="zh-CN">
支持metaWeblog的 blogApi插件。
设置为"启用"时,会使每个模块都会显示RSD标签。
api地址为http://安装地址/模块名/api。
把状态设置为"使用"时才会激活RSD标签及api。
</description>
<description xml:lang="en">
This blogApi addon supports metaWeblog.
Toggling this with use option lets RSD tag be exposed for each module.
URL to the api is http://setup_path/module_name/api.
Only selecting use option enables RSD tag and api to behave.
</description>
<description xml:lang="es">
Es adicionales para soporte de metaWeblog.
Si marcar en uso, cada modulas van a exponer RSD etiqueta.
dirección de es, http://dirección de instalación/nombre de modula/api.
Para funcionar RSD etiqueta y API, es nesesario marcar USAR.
</description>
</author>
</addon>

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<addon version="0.1">
<title xml:lang="ko">기본 카운터 애드온</title>
<title xml:lang="jp">接続カウンター</title>
<title xml:lang="zh-CN">网站访问统计</title>
<title xml:lang="en">Addon for basic counter</title>
<title xml:lang="es">Adición Taquilla Predeterminado</title>
<author email_address="zero@zeroboard.com" link="http://www.zeroboard.com" date="2007. 2. 28">
<name xml:lang="ko">제로</name>
<name xml:lang="jp">Zero</name>
<name xml:lang="zh-CN">zero</name>
<name xml:lang="en">zero</name>
<name xml:lang="es">zero</name>
<description xml:lang="ko">
제로보드XE의 기본 카운터 모듈을 이용하여 접속 정보를 기록합니다.
이 애드온을 켜셔야 접속 정보 수집이 됩니다.
</description>
<description xml:lang="jp">
セロボードXEの接続カウンターモジュールは、接続情報を記録します。このアドオンを「使用」に設定しておくと接続情報が記録されます。
</description>
<description xml:lang="zh-CN">
利用ZeroboardXE的网站访问统计模块记录网站访问信息。
把状态设置为"使用"时,才会记录网站访问信息.
</description>
<description xml:lang="en">
This addon logs access information based on the basic counter module within Zeroboard XE.
It is necessary for aggregation of access information to turn on this addon.
</description>
<description xml:lang="es">
Contar los visitantes con la taquilla predeterminado de ZeroBoardXE. Es necesario aprender esta adición para acumular las información de visitos.
</description>
</author>
</addon>

View file

@ -0,0 +1,20 @@
<?php
if(!defined("__ZBXE__")) exit();
/**
* @file counter.addon.php
* @author zero (zero@nzeo.com)
* @brief 카운터 애드온
*
* 카운터 애드온은 제로보드XE의 기본 카운터(counter)모듈을 이용하여 로그를 남깁니다.
* 검색 로봇이나 기타 툴의 접속을 방지하고 부하를 줄이기 위해서 페이지가 로드된 후에 javascript로 다시 로그를 남기도록 합니다.
* 따라서 카운터 애드온은 카운터를 수집하게 하는 javascript 파일을 추가하는 동작만 하며 기본 카운터 모듈의 호출은 해당 javascript
* 파일내에서 이루어집니다.
**/
// called_position가 before_module_init 이고 module이 admin이 아닐 경우
if($called_position == 'before_module_init' && !$GLOBALS['__counter_addon_called__']) {
if($this->module != 'admin') Context::addJsFile('./modules/counter/tpl/js/counter.js');
$GLOBALS['__counter_addon_called__'] = true;
}
?>

View file

@ -0,0 +1,194 @@
<?xml version="1.0" encoding="utf-8"?>
<addon version="0.1">
<title xml:lang="ko">게시글 구글 애드센스 연동</title>
<title xml:lang="jp">グーグル・アドセンス</title>
<title xml:lang="zh-CN">Google AdSense</title>
<title xml:lang="en">Linkage of Articles and Google Adsense</title>
<author email_address="zero@zeroboard.com" link="http://www.zeroboard.com" date="2007. 2. 28">
<name xml:lang="ko">제로</name>
<name xml:lang="jp">Zero</name>
<name xml:lang="zh-CN">zero</name>
<name xml:lang="en">zero</name>
<description xml:lang="ko">
게시글의 상/하단에 구글 애드센스를 추가할 수 있습니다.
추가확장폼에서 사용자에게 구글애드센스 코드를 받게 하여 글쓴이와 연동되는 애드센스 출력이 가능합니다.
이 기능을 사용하지 않거나 사용자가 애드센스 코드를 입력하지 않았다면 기본으로 설정된 애드센스 코드가 사용됩니다.
색상을 입력할때는 # 을 제외한 나머지 6자리의 색상코드를 입력해주세요.
위치를 top 또는 bottom을 입력하시면 게시글 상단 또는 하단에 광고를 출력할 수 있습니다.
</description>
<description xml:lang="jp">
コンテンツ書き込みの上・下段にグーグル・アドセンスGoogle AdSenseを追加することができます。追加拡張フォームに、グーグル・アドセンスGoogle AdSenseコードを入力すると、書き込みにユーザ自身のグーグル・アドセンスGoogle AdSenseが挿入できます。
この機能を使わない、またはユーザがグーグル・アドセンスGoogle AdSenseコードを入力しない場合は、デフォルトで設定されたアドセンス適用されます。文字列などに色を使用する場合は、「 #」を除く6ケタのカラーコードを入力してください。
「top」または「bottom」を入力すると書き込みの上段または下段に広告を出力することができます。
</description>
<description xml:lang="zh-CN">
可以把Google AdSense添加到文章的上/下端。
可以让用户在扩展表单里获得Google AdSense代码从而也可以显示与作者相关联的AdSense。
不使用此功能或用户没有输入Google AdSense代码时使用默认的AdSense代码。
输入颜色时,输入除#以外的 6位颜色代码。
指定显示位置时输入top或bottom即可把AdSense显示在内容的上端或下端。
</description>
<description xml:lang="en">
Google Adsense can be added at top/bottom of article.
An adsense linked with writer can be displayed by Google adsense code input by user in additional form.
If this isn't used or user hasn't input the adsense code, the default adsense code will be used.
To use color, input 6 color code except '#'.
You can display the ad at the top or the bottom of article by input Position as top or bottom.
</description>
</author>
<extra_vars>
<var name="position">
<title xml:lang="ko">위치</title>
<title xml:lang="jp">位置</title>
<title xml:lang="zh-CN">位置</title>
<title xml:lang="en">Position</title>
<description xml:lang="ko">top : 게시글 상단, bottom : 게시글 하단 을 지정하실 수 있습니다.</description>
<description xml:lang="jp">top : 本文の上段, bottom : 本文の下段</description>
<description xml:lang="zh-CN">可以指定显示位置。(top : 内容上端, bottom : 内容下端)</description>
<description xml:lang="en">You can set top : top of article, bottom : bottom of article.</description>
</var>
<var name="ad_client">
<title xml:lang="ko">구글 애드센스 키</title>
<title xml:lang="jp">アドセンスキー</title>
<title xml:lang="zh-CN">Google Adsense Key</title>
<title xml:lang="en">Google Adsense Key</title>
<description xml:lang="ko">기본으로 사용될 구글 애드센스 키를 입력해주세요.</description>
<description xml:lang="ko">デフォルトで使用するグーグルアドセンスキーを入力してください。</description>
<description xml:lang="zh-CN">请输入要使用的默认Google Adsense Key。</description>
<description xml:lang="en">Please input Google Adsense key to use as default.</description>
</var>
<var name="user_ad_client">
<title xml:lang="ko">회원 키 항목 이름</title>
<title xml:lang="jp">キー項目名</title>
<title xml:lang="zh-CN">会员Key项目名</title>
<title xml:lang="en">Name of Member Key Item</title>
<description xml:lang="ko">회원의 구글 애드센스를 허락하시려면 가입항목중 구글 키 입력 항목 이름을 입력해주세요.</description>
<description xml:lang="jp">グーグル・アドセンスが使用できるようするにためには、加入項目でグーグルキー入力項目名を入力してください。
</description>
<description xml:lang="zh-CN">允许会员使用个人Google AdSense时请输入要在会员注册项目中显示的Google Key项目名。</description>
<description xml:lang="en">To permit members' Google Adsense, please input name of Google key item in join items.</description>
</var>
<var name="ad_width">
<title xml:lang="ko">가로 길이</title>
<title xml:lang="jp">横幅</title>
<title xml:lang="zh-CN">宽度</title>
<title xml:lang="en">Width</title>
<description xml:lang="ko">애드센스의 가로길이를 입력해주세요.</description>
<description xml:lang="jp">アドセンスの横幅のサイズを入力してください</description>
<description xml:lang="zh-CN">请输入AdSense的宽度大小。</description>
<description xml:lang="en">Please input width of Adsense.</description>
</var>
<var name="ad_height">
<title xml:lang="ko">세로 길이</title>
<title xml:lang="jp">縦幅</title>
<title xml:lang="zh-CN">高度</title>
<title xml:lang="en">Height</title>
<description xml:lang="ko">애드센스의 세로길이를 입력해주세요.</description>
<description xml:lang="jp">アドセンスの立幅のサイズを入力してください。</description>
<description xml:lang="zh-CN">请输入高度大小。</description>
<description xml:lang="en">Please input height of Adsense.</description>
</var>
<var name="ad_format">
<title xml:lang="ko">포맷</title>
<title xml:lang="jp">フォーマット</title>
<title xml:lang="zh-CN">格式</title>
<title xml:lang="en">Format</title>
<description xml:lang="ko">애드센스 포맷을 입력해주세요.</description>
<description xml:lang="jp">アドセンスのフォーマットを入力してください。</description>
<description xml:lang="zh-CN">请输入广告格式</description>
<description xml:lang="en">Please input format of Adsense.</description>
</var>
<var name="ad_type">
<title xml:lang="ko">타입</title>
<title xml:lang="jp">タイプ</title>
<title xml:lang="zh-CN">样式</title>
<title xml:lang="en">Type</title>
<description xml:lang="ko">애드센스의 타입을 입력해주세요.</description>
<description xml:lang="jp">アドセンスのタイプを入力してください。</description>
<description xml:lang="zh-CN">请输入AdSense样式。</description>
<description xml:lang="en">Please input type of Adsense.</description>
</var>
<var name="ad_channel">
<title xml:lang="ko">채널</title>
<title xml:lang="jp">チャンネル</title>
<title xml:lang="zh-CN">频道</title>
<title xml:lang="en">Channel</title>
<description xml:lang="ko">채널을 입력해주세요. (사용자 정의 구글 애드센스일 경우 사용되지 않습니다)</description>
<description xml:lang="jp">チャンネルを入力してください(カスタマイズ・グーグル・アドセンスには使用されません)。</description>
<description xml:lang="zh-CN">请输入频道。 (用户自定义Google AdSense不使用频道)</description>
<description xml:lang="en">Please input channel. (It will not be used for custom Google Adsense)</description>
</var>
<var name="color_border">
<title xml:lang="ko">외곽선 색상</title>
<title xml:lang="jp">ボーダカラー</title>
<title xml:lang="zh-CN">边框颜色</title>
<title xml:lang="en">Border Color</title>
<description xml:lang="ko">외곽선 색상을 입력해주세요.</description>
<description xml:lang="jp">ボーダーカラーを入力してください。.</description>
<description xml:lang="zh-CN">请输入边框颜色。</description>
<description xml:lang="en">Please input color of border.</description>
</var>
<var name="color_bg">
<title xml:lang="ko">배경색</title>
<title xml:lang="jp">背景色</title>
<title xml:lang="zh-CN">背景色</title>
<title xml:lang="en">Background Color</title>
<description xml:lang="ko">배경색상을 입력해주세요.</description>
<description xml:lang="jp">背景色を入力してください</description>
<description xml:lang="zh-CN">请输入背景颜色。</description>
<description xml:lang="en">Please input color of background.</description>
</var>
<var name="link_color">
<title xml:lang="ko">링크 글자색</title>
<title xml:lang="jp">リンク色</title>
<title xml:lang="zh-CN">链接颜色</title>
<title xml:lang="en">Link Color</title>
<description xml:lang="ko">링크가 걸린 글자의 색상을 입력해주세요.</description>
<description xml:lang="jp">リンクの文字列の色を入力してください。</description>
<description xml:lang="zh-CN">请输入链接颜色。</description>
<description xml:lang="en">Please input color of linked text.</description>
</var>
<var name="text_color">
<title xml:lang="ko">글자 색 </title>
<title xml:lang="jp">文字列色</title>
<title xml:lang="zh-CN">字体颜色 </title>
<title xml:lang="en">Text Color </title>
<description xml:lang="ko">링크가 걸리지 않은 글자의 색을 입력해주세요</description>
<description xml:lang="jp">文字列の色を入力してください。</description>
<description xml:lang="zh-CN">请输入没有链接字体颜色。</description>
<description xml:lang="en">Please input color of text.</description>
</var>
<var name="url_color">
<title xml:lang="ko">URL 색</title>
<title xml:lang="jp">URL色</title>
<title xml:lang="zh-CN">URL 颜色</title>
<title xml:lang="en">URL Color</title>
<description xml:lang="ko">URL의 글자색을 입력해주세요.</description>
<description xml:lang="ko">URLの色を入力してください。</description>
<description xml:lang="zh-CN">请输入URL的颜色。</description>
<description xml:lang="en">Please input color of URL.</description>
</var>
<var name="ui_features">
<title xml:lang="ko">테두리 형태</title>
<title xml:lang="jp">ボーダスタイル</title>
<title xml:lang="zh-CN">边框样式</title>
<title xml:lang="en">Border Style</title>
<description xml:lang="ko">테두리 형태를 입력해주세요.</description>
<description xml:lang="jp">ボーダースタイルを入力してください。</description>
<description xml:lang="zh-CN">请输入边框样式。</description>
<description xml:lang="en">Please input style of border.</description>
</var>
<var name="background_image">
<title xml:lang="ko">배경 이미지를 입력해주세요.</title>
<title xml:lang="jp">背景イメージ</title>
<title xml:lang="zh-CN">请输入背景图片。</title>
<title xml:lang="en">Please input image of background.</title>
<description xml:lang="ko">접근가능한 웹서버에 올린 배경 이미지의 URL을 입력해주세요.</description>
<description xml:lang="jp">アクセス可能なサーバにアップロードされている背景イメージのURLを入力してください。</description>
<description xml:lang="zh-CN">请输入有效的图片URL。</description>
<description xml:lang="en">Please input URL of background image which is uploaded on accessible web server.</description>
</var>
</extra_vars>
</addon>

View file

@ -0,0 +1,23 @@
<?php
if(!defined("__ZBXE__")) exit();
/**
* @file google_adsense.addon.php
* @author zero (zero@nzeo.com)
* @brief google_adsense를 게시글의 /하단에 출력할 있도록 한다.
*
* 모든 출력이 끝난후에 사용이 .
**/
// called_position이 before_module_init일때만 실행
if($called_position != 'before_display_content' || Context::getResponseMethod()=="XMLRPC") return;
require_once("./addons/google_adsense/google_adsense.lib.php");
if($addon_info->position == "top") $pos_regx = "!<\!--BeforeDocument\(([0-9]+),([0-9]+)\)-->!is";
else $pos_regx = "!<\!--AfterDocument\(([0-9]+),([0-9]+)\)-->!is";
$GLOBALS['__g_addon_info__'] = $addon_info;
$output = preg_replace_callback($pos_regx, matchDocument, $output);
?>

View file

@ -0,0 +1,53 @@
<?php
function matchDocument($matches) {
$addon_info = $GLOBALS['__g_addon_info__'];
$source_code = $matches[0];
$document_srl = $matches[1];
$member_srl = $matches[2];
// 사용자 입력을 지원하면 해당 회원의 정보에서 구글 키를 가져옴
if($member_srl && $addon_info->user_ad_client) {
$oMemberModel = &getModel('member');
$member_info = $oMemberModel->getMemberInfoByMemberSrl($member_srl);
$key = $member_info->{$addon_info->user_ad_client};
if($key) {
$addon_info->ad_client = $key;
$addAdSense->ad_type = '';
}
}
$adsense_code = addAdSense($addon_info);
return $source_code.$adsense_code;
}
function addAdSense($addon_info) {
$script_code = <<<EndOfScript
<script type="text/javascript"><!--
google_ad_client = "{$addon_info->ad_client}";
google_ad_width = "{$addon_info->ad_width}";
google_ad_height = "{$addon_info->ad_height}";
google_ad_format = "{$addon_info->ad_format}";
google_ad_type = "{$addon_info->ad_type}";
google_ad_channel = "{$addon_info->ad_channel}";
google_color_border = "{$addon_info->color_border}";
google_color_bg = "{$addon_info->color_bg}";
google_color_link = "{$addon_info->link_color}";
google_color_text = "{$addon_info->text_color}";
google_color_url = "{$addon_info->url_color}";
google_ui_features = "{$addon_info->ui_features}";
//-->
</script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
EndOfScript;
if($addon_info->background_image) $backgroundStyle = sprintf('background-image:url(%s)', $addon_info->background_image);
$script_code = sprintf('<div style="width:%dpx;height:%dpx;%s;margin:10px 0 10px 0px;">%s</div>',$addon_info->ad_width, $addon_info->ad_height, $backgroundStyle, $script_code);
return $script_code;
}
?>

View file

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<addon version="0.1">
<title xml:lang="ko">사용자 추가 정보 및 커뮤니케이션 기능 활성화</title>
<title xml:lang="jp">会員情報・コミュニティ</title>
<title xml:lang="zh-CN">用户扩展信息</title>
<title xml:lang="en">Addon for enabling facilities for providing additional information about users and communicating</title>
<title xml:lang="es">Informaciónes addciónales del usuario y actualzación del función communicación.</title>
<author email_address="zero@zeroboard.com" link="http://www.zeroboard.com" date="2007. 2. 28">
<name xml:lang="ko">제로</name>
<name xml:lang="jp">Zero</name>
<name xml:lang="zh-CN">zero</name>
<name xml:lang="en">zero</name>
<name xml:lang="es">zero</name>
<description xml:lang="ko">
사용자의 정보중 이미지이름, 이미지마크, 서명등을 화면에 출력해주는 애드온입니다.
이런 정보들을 사용하지 않을 경우를 대비하여 별도의 애드온으로 빼어서 실행시간을 줄여줍니다.
이미지이름, 이미지마크, 서명등을 노출하고 싶다면 이 애드온을 활성화 시키세요.
1. 출력되기 직전 &amp;lt;div class="member_회원번호"&amp;gt;....&amp;lt;/div&amp;gt; 로 정의가 된 부분을 찾아 회원번호를 구해서 이미지이름, 이미지마크가 있는지를 확인하여 있으면 내용을 변경해버립니다.
2. 출력되기 직전 &amp;lt;div class="document_번호"&amp;gt;...&amp;lt;/div&amp;gt;로 정의된 곳을 찾아 글의 내용이라 판단, 하단에 서명을 추가합니다.
3. 새로운 쪽지가 왔을 경우 팝업으로 띄움
4. MemberModel::getMemberMenu 호출시 대상이 회원일 경우 쪽지 보내기 기능 추가합니다.
5. MemberModel::getMemberMenu 호출시 친구 등록 메뉴를 추가합니다.
</description>
<description xml:lang="jp">
会員情報のイメージ名、イメージマーク、署名などを画面に表示するアドオンです。このような情報を使用しない場合、アドオンを「使用」に設定すれば、実行時間を少なくします。イメージ名、イメージマーク、署名などを表示させたい時は、このアドオンを「使用」に設定して下さい。
1. 出力の直前 &lt;div class="member_会員番号"&gt;....&lt;/div&gt; に定義された部分を探し、会員番号をチェックしてイメージ名、イメージマークがあるかを確認します。あった場合は内容を変更します
2. 出力の直前 &lt;div class="document_番号"&gt;...&lt;/div&gt;に定義された部分を探し、書込みの内容だと判断して、下段に署名を追加します
3. 新しいメッセージが来た場合ポップアップで表示します
4. MemberModel::getMemberMenu を呼出す時、相手が会員の場合はメッセージ送信の機能を追加します
5. MemberModel::getMemberMenu を呼出す時、友達登録メニュを追加します
</description>
<description xml:lang="zh-CN">
此插件将把用户信息中的昵称图片,用户图标,签名等信息显示到页面当中。
因部分用户不使用此项功能或为了考虑页面载入速度,以插件形式提供此项功能。
要想使用会员扩展信息请激活此插件。
1. 显示之前先查找定义为 &amp;lt;div class="member_会员编号"&amp;gt;....&amp;lt;/div&amp;gt; 的部分获得会员编号后,再以会员编号确认有没有昵称图片/用户图标,有的话即可更新相关内容。
2. 显示之前先查找定义为 &amp;lt;div class="document_编号"&amp;gt;...&amp;lt;/div&amp;gt;的部分判断此处为主题内容后,在此处下方添加个人签名。
3. 收到新消息时,用弹出窗口显示。
4. 呼出MemberModel::getMemberMenu时如对方是会员就添加[发送短消息]功能。
5. 呼出MemberModel::getMemberMenu时添加[加为好友]菜单。
</description>
<description xml:lang="en">
Among other information about users, this addon displays image name, image mark, and signature.
In case of you not use this information, this stands apart from basic information so runtime should be reduced.
To expose image name, image mark, and signature, please turn on this addon.
1. Just before displaying user information, this will figure out unique key of member from the definition of "&amp;lt;div class="member_{unique key of member}"&amp;gt;....&amp;lt;/div&amp;gt;" and replace image name and/or image mark if they exsist.
2. Just before displaying, this is gonna locate the definition of "&amp;lt;div class="document_{unique key of document}"&amp;gt;...&amp;lt;/div&amp;gt;" and insert the signature below it.
3. When arrived a new slip, this will popup it.
4. This makes available to send a slip if the target is a member when MemberModel::getMemberMenu is called.
5. This adds a menu for registering as a friend when MemberModel::getMemberMenu is called.
</description>
<description xml:lang="es">
Se muestra nombre de imagén, marcador de imagén, firma del usuario.
para cortar la ejecución de programa, si no es necessario, puede apagar la function adicionales.
Necesita actualizar este funcion, por favor haga clic en ´usar´.
1. Este adición busca &lt;div class="member_Num. usuario"&gt;....&lt;/div&gt; en los documentos, y calcula numero de usuario. Y si hay nombre de imagen, marcador de imagen, se cambia el contenido.
2. Este adicion busca &lt;div class="document_Num. documentos"&gt;...&lt;/div&gt; en los documentos, coloca la firma donde interpreta el termino de contenido.
3. Si llega nota, se muestra en pop up.
4. Si llama MemberModel::getMemberMenu, si es miembro, funcion de "mandar nota" se actualiza.
5. Si llama MemberModel::getMemberMenu, el addiciona menú ¨agregar contacto¨.
</description>
</author>
</addon>

View file

@ -0,0 +1,3 @@
<?php
$lang->alert_new_message_arrived = 'You got a new message. Do you want to check now?';
?>

View file

@ -0,0 +1,3 @@
<?php
$lang->alert_new_message_arrived = '新しいメッセージが届きました。確認しますか。';
?>

View file

@ -0,0 +1,3 @@
<?php
$lang->alert_new_message_arrived = '새로운 메세지가 도착하였습니다. 확인하시겠습니까?';
?>

View file

@ -0,0 +1,3 @@
<?php
$lang->alert_new_message_arrived = '您有新消息。要确认吗?';
?>

View file

@ -0,0 +1,111 @@
<?php
if(!defined("__ZBXE__")) exit();
/**
* @file image_name.addon.php
* @author zero (zero@nzeo.com)
* @brief 사용자의 이미지이름/ 이미지마크나 커뮤니케이션 기능을 추가시킴
*
* 1. 출력되기 직전 <div class="member_회원번호">....</div> 정의가 부분을 찾아 회원번호를 구해서
* 이미지이름, 이미지마크가 있는지를 확인하여 있으면 내용을 변경해버립니다.
*
* 2. 출력되기 직전 <div class="document_회원번호">...</div> 정의된 곳을 찾아 글의 내용이라 판단,
* 하단에 서명을 추가합니다.
*
* 3. 새로운 쪽지가 왔을 경우 팝업으로 띄움
*
* 4. MemberModel::getMemberMenu 호출시 대상이 회원일 경우 쪽지 보내기 기능 추가합니다.
*
* 5. MemberModel::getMemberMenu 호출시 친구 등록 메뉴를 추가합니다.
*
**/
/**
* 1,2 기능 수행 : 출력되기 바로 직전일 경우에 이미지이름/이미지마크등을 변경
* 조건 : called_position == 'before_display_content'
**/
if($called_position == "before_display_content") {
// 기본적인 기능이라 MemberController 에 변경 코드가 있음
$oMemberController = &getController('member');
// 1. 출력문서중에서 <div class="member_번호">content</div>를 찾아 MemberController::transImageName() 를 이용하여 이미지이름/마크로 변경
$output = preg_replace_callback('!<(div|span)([^\>]*)member_([0-9]+)([^\>]*)>(.*?)\<\/(div|span)\>!is', array($oMemberController, 'transImageName'), $output);
// 2. 출력문서중에 <!--AfterDocument(문서번호,회원번호)--> 를 찾아서 member_controller::transSignature()를 이용해서 서명을 추가
$output = preg_replace_callback('/<!--AfterDocument\(([0-9]+),([0-9]+)\)-->/i', array($oMemberController, 'transSignature'), $output);
/**
* 3 기능 수행 : 시작할때 새쪽지가 왔는지 검사
* 조건 : called_position = 'before_module_init', module != 'member'
**/
} elseif($called_position == 'before_module_init' && $this->module != 'member' && Context::get('is_logged') ) {
// 로그인된 사용자 정보를 구함
$logged_info = Context::get('logged_info');
$flag_path = './files/member_extra_info/new_message_flags/'.getNumberingPath($logged_info->member_srl);
$flag_file = sprintf('%s%s', $flag_path, $logged_info->member_srl);
// 새로운 쪽지에 대한 플래그가 있으면 쪽지 보기 팝업 띄움
if(file_exists($flag_file)) {
@unlink($flag_file);
Context::loadLang('./addons/member_extra_info/lang');
$script = sprintf('<script type="text/javascript"> xAddEventListener(window,"load", function() {if(confirm("%s")) { popopen("%s"); }}); </script>', Context::getLang('alert_new_message_arrived'), Context::getRequestUri().'?module=member&act=dispMemberNewMessage');
Context::addHtmlHeader( $script );
}
/**
* 4,5 기능 수행 : 사용자 이름을 클릭시 요청되는 MemberModel::getMemberMenu 후에 $menu_list에 쪽지 발송, 친구추가등의 링크 추가
* 조건 : called_position == 'after_module_proc', module = 'member', act = 'getMemberMenu'
**/
} elseif($called_position == 'after_module_proc' && $this->module == 'member' && $this->act == 'getMemberMenu') {
// 비로그인 사용자라면 패스
if(!Context::get('is_logged')) return;
// 로그인된 사용자 정보를 구함
$logged_info = Context::get('logged_info');
$member_srl = Context::get('member_srl');
// 템플릿에서 사용되기 전의 menu_list를 가져옴
$menu_list = $this->get('menu_list');
// 자신이라면 쪽지함 보기 기능 추가
if($logged_info->member_srl == $member_srl) {
// 4. 자신의 쪽지함 보기 기능 추가
$menu_str = Context::getLang('cmd_view_message_box');
$menu_link = "current_url.setQuery('act','dispMemberMessages')";
$menu_list .= sprintf("\n%s,%s,move_url(%s,'Y')", Context::getRequestUri().'/modules/member/tpl/images/icon_message_box.gif', $menu_str, $menu_link);
// 5. 친구 목록 보기
$menu_str = Context::getLang('cmd_view_friend');
$menu_link = "current_url.setQuery('act','dispMemberFriend')";
$menu_list .= sprintf("\n%s,%s,move_url(%s,'Y')", Context::getRequestUri().'/modules/member/tpl/images/icon_friend_box.gif',$menu_str, $menu_link);
// 아니라면 쪽지 발송, 친구 등록 추가
} else {
// 대상 회원의 정보를 가져옴
$target_member_info = $this->getMemberInfoByMemberSrl($member_srl);
// 4. 쪽지 발송 메뉴를 만듬
if( $target_member_info->allow_message =='Y' || ($target_member_info->allow_message == 'F' && $this->isFriend($member_srl))) {
$menu_str = Context::getLang('cmd_send_message');
$menu_link = sprintf('%s?module=member&amp;act=dispMemberSendMessage&amp;receiver_srl=%s',Context::getRequestUri(),$member_srl);
$menu_list .= sprintf("\n%s,%s,popopen('%s','sendMessage')", Context::getRequestUri().'/modules/member/tpl/images/icon_write_message.gif', $menu_str, $menu_link);
}
// 5. 친구 등록 메뉴를 만듬 (이미 등록된 친구가 아닐 경우)
if(!$this->isAddedFriend($member_srl)) {
$menu_str = Context::getLang('cmd_add_friend');
$menu_link = sprintf('%s?module=member&amp;act=dispMemberAddFriend&amp;target_srl=%s',Context::getRequestUri(),$member_srl);
$menu_list .= sprintf("\n%s,%s,popopen('%s','addFriend')", Context::getRequestUri().'/modules/member/tpl/images/icon_add_friend.gif', $menu_str, $menu_link);
}
}
// 템플릿에 적용되게 하기 위해 module의 variables에 재등록
$this->add('menu_list', $menu_list);
}
?>

View file

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<addon version="0.1">
<title xml:lang="ko">OpenID delegation ID</title>
<title xml:lang="zh-CN">OpenID</title>
<title xml:lang="en">Addon for delegating domain name to OpenID</title>
<title xml:lang="es">delegación ID para OpenID</title>
<title xml:lang="jp">OpenID</title>
<author email_address="zero@zeroboard.com" link="http://www.zeroboard.com" date="2007. 2. 28">
<name xml:lang="ko">제로</name>
<name xml:lang="zh-CN">zero</name>
<name xml:lang="en">zero</name>
<name xml:lang="es">zero</name>
<name xml:lang="jp">Zero</name>
<description xml:lang="ko">
본인의 도메인을 사용하여 오픈아이디로 활용할 수 있도록 합니다.
꼭 설정을 통해서 openid provider관련 값을 입력후 사용해주세요.
</description>
<description xml:lang="zh-CN">
可以把本人的域名当分散式身份验证系统(OpenID)来使用。
必须在设置中输入openid provider相关值后再使用。
</description>
<description xml:lang="en">
This addon enables you to use your own domian name as an OpenID.
Just be sure to set the values related with openid provider before using.
</description>
<description xml:lang="es">
Utliza su dominio para usar OpenID.
La configuración es necesario.
</description>
<description xml:lang="jp">
保有するドメインをオープンとして活用することができます。必ず設定で、OpenIDのプロバイダー関連の情報を入力してから使用してください。
</description>
</author>
<extra_vars>
<var name="server">
<title xml:lang="ko">server</title>
<title xml:lang="zh-CN">server</title>
<title xml:lang="en">server</title>
<title xml:lang="es">Servidor</title>
<title xml:lang="jp">server</title>
<description xml:lang="ko">openid.server 값을 입력해 주세요.</description>
<description xml:lang="zh-CN">请输入 openid.server 值。</description>
<description xml:lang="en">Please input your openid.server value.</description>
<description xml:lang="es">Servidor de OpenID.</description>
<description xml:lang="jp">openid.server の値を入力してください。</description>
</var>
<var name="delegate">
<title xml:lang="ko">delegate</title>
<title xml:lang="en">delegate</title>
<title xml:lang="zh-CN">delegate</title>
<title xml:lang="es">Delegador</title>
<title xml:lang="jp">delegate</title>
<description xml:lang="ko">openid.delegate값을 입력해주세요.</description>
<description xml:lang="zh-CN">请输入 openid.delegate 值。</description>
<description xml:lang="en">Please input your openid.delegate value.</description>
<description xml:lang="en">Delegador de OpenID</description>
<description xml:lang="jp">openid.delegate の値を入力してください。</description>
</var>
<var name="xrds">
<title xml:lang="ko">xrds</title>
<title xml:lang="zh-CN">xrds</title>
<title xml:lang="en">xrds</title>
<title xml:lang="es">xrds</title>
<title xml:lang="jp">xrds</title>
<description xml:lang="ko">X-XRDS-Location값을 입력해주세요.</description>
<description xml:lang="zh-CN">请输入 X-XRDS-Location 值。</description>
<description xml:lang="en">Please input your X-XRDS-Location value.</description>
<description xml:lang="es">ubicación de X-XRDS</description>
<description xml:lang="jp">X-XRDS-Location の値を入力してください。</description>
</var>
</extra_vars>
</addon>

View file

@ -0,0 +1,29 @@
<?php
if(!defined("__ZBXE__")) exit();
/**
* @file openid_delegation_id.addon.php
* @author zero (zero@nzeo.com)
* @brief OpenID Delegation ID 애드온
*
* 오픈아이디를 자신의 홈페이지나 블로그 주소로 이용할 있도록 해줍니다.
* 설정을 통해서 사용하시는 오픈아이디 서비스에 해당하는 정보를 입력해주세요.
**/
// called_position이 before_module_init일때만 실행
if($called_position != 'before_module_init') return;
// openid_delegation_id 애드온 설정 정보를 가져옴
if(!$addon_info->server||!$addon_info->delegate||!$addon_info->xrds) return;
$header_script = sprintf(
'<link rel="openid.server" href="%s" />'."\n".
'<link rel="openid.delegate" href="%s" />'."\n".
'<meta http-equiv="X-XRDS-Location" content="%s" />',
$addon_info->server,
$addon_info->delegate,
$addon_info->xrds
);
Context::addHtmlHeader($header_script);
?>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<addon version="0.1">
<title xml:lang="ko">포인트 활성화 애드온</title>
<title xml:lang="zh-CN">积分插件</title>
<title xml:lang="jp">ポイントシステム</title>
<title xml:lang="en">Addon for activating point</title>
<author email_address="zero@zeroboard.com" link="http://www.zeroboard.com" date="2007. 7. 26">
<name xml:lang="ko">제로</name>
<name xml:lang="zh-CN">Zero</name>
<name xml:lang="jp">Zero</name>
<name xml:lang="en">zero</name>
<description xml:lang="ko">
포인트시스템 모듈에 설정된 내용을 바탕으로 글작성/삭제/댓글작성/삭제/파일업로드/삭제/다운로드등의 행동에 대해서 포인트를 기록합니다.
</description>
<description xml:lang="zh-CN">
以积分系统模块中设置的内容为基础,对发表/删除新帖,发表/删除评论,上传/下载/删除/文件等动作记录为积分。
</description>
<description xml:lang="jp">
ポイントシステムモジュールで設定された内容を基に、書き込み作成・削除/コメント作成・削除/ファイルアップロード・削除/ダウンロードなどのユーザの活動に対してポイントを記録します。
</description>
<description xml:lang="en">
This addon records point on writing/deleting/adding comments/deleting comments/uploading/downloading following to point system module.
</description>
</author>
</addon>

View file

@ -0,0 +1,221 @@
<?php
if(!defined("__ZBXE__")) exit();
/**
* @file point.addon.php
* @author zero (zero@nzeo.com)
* @brief 포인트 애드온
*
* 포인트 시스템 모듈에 설정된 내용을 토대로 하여 포인트를 부여/차감하고,
* 다운로드를 금지시키고,
* 회원 이름 앞에 레벨 아이콘을 표시한다.
**/
// 관리자 모듈이면 패스~
if(Context::get('module')=='admin') return;
// 로그인 상태일때만 실행
$logged_info = Context::get('logged_info');
if(!$logged_info->member_srl) return;
// point action cache file을 가져와서 현재 속한 캐시파일인지 확인
$act_cache_file = "./files/cache/point.act.cache";
$buff = FileHandler::readFile($act_cache_file);
if(strpos($buff,$this->act)===false) return;
// point 모듈 정보 가져옴
$oModuleModel = &getModel('module');
$config = $oModuleModel->getModuleConfig('point');
// 현재 로그인 사용자의 포인트를 가져옴
$member_srl = $logged_info->member_srl;
$oPointModel = &getModel('point');
$cur_point = $oPointModel->getPoint($member_srl, true);
// 파일다운로드를 제외한 action은 called_position가 before_module_proc일때 실행
if($called_position == 'after_module_proc') {
// 게시글 작성
if(strpos($config->insert_document_act,$this->act)!==false) {
$document_srl = Context::get('document_srl');
$oDocumentModel = &getModel('document');
$oDocument = $oDocumentModel->getDocument($document_srl);
// 신규 글인지 체크
if($oDocument->get('regdate')!=$oDocument->get('last_update')) return;
$module_srl = $oDocument->get('module_srl');
// 포인트를 구해옴
$point = $config->module_point[$module_srl]['insert_document'];
if(!$point) $point = $config->insert_document;
// 포인트 증감
$cur_point += $point;
$oPointController = &getController('point');
$oPointController->setPoint($member_srl,$cur_point);
// 게시글 삭제
} elseif(strpos($config->delete_document_act,$this->act)!==false) {
if(!$this->toBool()) return;
$target_member_srl = Context::get('_point_target_member_srl');
if(!$target_member_srl) return;
$module_srl = $this->module_srl;
// 포인트를 구해옴
$point = $config->module_point[$module_srl]['insert_document'];
if(!$point) $point = $config->insert_document;
// 포인트 차감
$cur_point = $oPointModel->getPoint($target_member_srl, true);
$cur_point -= $point;
$oPointController = &getController('point');
$oPointController->setPoint($target_member_srl,$cur_point);
// 댓글 작성
} elseif(strpos($config->insert_comment_act,$this->act)!==false) {
$comment_srl = Context::get('comment_srl');
$oCommentModel = &getModel('comment');
$comment = $oCommentModel->getComment($comment_srl);
// 이미 존재하는 댓글인지 체크
if($comment->last_update) return;
// 포인트를 구해옴
$module_srl = $comment->module_srl;
// 포인트를 구해옴
$point = $config->module_point[$module_srl]['insert_comment'];
if(!$point) $point = $config->insert_comment;
// 포인트 증감
$cur_point += $point;
$oPointController = &getController('point');
$oPointController->setPoint($member_srl,$cur_point);
// 댓글 삭제
} elseif(strpos($config->delete_comment_act,$this->act)!==false) {
if(!$this->toBool()) return;
$target_member_srl = Context::get('_point_target_member_srl');
if(!$target_member_srl) return;
// 포인트를 구해옴
$module_srl = $this->module_srl;
// 포인트를 구해옴
$point = $config->module_point[$module_srl]['insert_comment'];
if(!$point) $point = $config->insert_comment;
// 포인트 증감
$cur_point = $oPointModel->getPoint($target_member_srl, true);
$cur_point -= $point;
$oPointController = &getController('point');
$oPointController->setPoint($target_member_srl,$cur_point);
// 파일업로드
} elseif(strpos($config->upload_file_act,$this->act)!==false) {
if(!$output->toBool()||!$output->get('file_srl')) return;
$file_srl = $output->get('file_srl');
$oFileModel = &getModel('file');
$file_info = $oFileModel->getFile($file_srl);
$module_srl = $this->module_srl;
// 포인트를 구해옴
$point = $config->module_point[$module_srl]['upload_file'];
if(!$point) $point = $config->upload_file;
// 포인트 증감
$cur_point += $point;
$oPointController = &getController('point');
$oPointController->setPoint($member_srl,$cur_point);
// 파일삭제
} elseif(strpos($config->delete_file_act,$this->act)!==false) {
// 파일 정보를 구해옴
$file_srl = Context::get('file_srl');
if(!$file_srl) return;
$target_member_srl = Context::get('_point_target_member_srl');
if(!$target_member_srl) return;
$module_srl = $this->module_srl;
$target_member_srl = Context::get('_point_target_member_srl');
if(!$target_member_srl) return;
// 포인트를 구해옴
$point = $config->module_point[$module_srl]['upload_file'];
if(!$point) $point = $config->upload_file;
// 포인트 차감
$cur_point = $oPointModel->getPoint($target_member_srl, true);
$cur_point -= $point;
$oPointController = &getController('point');
$oPointController->setPoint($target_member_srl,$cur_point);
}
// 파일다운로드는 before_module_proc 일때 체크
} else if($called_position == "before_module_proc") {
// 파일다운로드
if(strpos($config->download_file_act,$this->act)!==false) {
// 파일 정보를 구해옴
$file_srl = Context::get('file_srl');
if(!$file_srl) return;
$oFileModel = &getModel('file');
$file_info = $oFileModel->getFile($file_srl);
if($file_info->file_srl != $file_srl) return;
$module_srl = $file_info->module_srl;
// 포인트를 구해옴
$point = $config->module_point[$module_srl]['download_file'];
if(!$point) $point = $config->download_file;
// 포인트가 0보다 작고 포인트가 없으면 파일 다운로드가 안되도록 했다면 오류
if($cur_point + $point < 0 && $config->disable_download == 'Y') {
$this->stop('msg_cannot_download');
}
// 포인트 차감
$cur_point += $point;
$oPointController = &getController('point');
$oPointController->setPoint($member_srl,$cur_point);
// 글 삭제일 경우 대상 글의 사용자 번호 저장
} elseif(strpos($config->delete_document_act,$this->act)!==false) {
$document_srl = Context::get('document_srl');
$oDocumentModel = &getModel('document');
$oDocument = $oDocumentModel->getDocument($document_srl);
$target_member_srl = $oDocument->get('member_srl');
if($target_member_srl) Context::set('_point_target_member_srl', $target_member_srl);
// 댓글 삭제일 경우 대상 댓글의 사용자 번호 저장
} elseif(strpos($config->delete_comment_act,$this->act)!==false) {
$comment_srl = Context::get('comment_srl');
$oCommentModel = &getModel('comment');
$comment = $oCommentModel->getComment($comment_srl);
$target_member_srl = $comment->member_srl;
if($target_member_srl) Context::set('_point_target_member_srl', $target_member_srl);
// 파일삭제일 경우 대상 파일의 정보에서 사용자 번호 저장
} elseif(strpos($config->delete_file_act,$this->act)!==false) {
// 파일 정보를 구해옴
$file_srl = Context::get('file_srl');
if(!$file_srl) return;
$oFileModel = &getModel('file');
$file_info = $oFileModel->getFile($file_srl);
if($file_info->file_srl != $file_srl) return;
$target_member_srl = $file_info->member_srl;
if($target_member_srl) Context::set('_point_target_member_srl', $target_member_srl);
}
}
?>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<addon version="0.1">
<title xml:lang="ko">포인트 레벨 아이콘 표시 애드온</title>
<title xml:lang="zh-CN">积分级别图标</title>
<title xml:lang="jp">ポイントレベルアイコン</title>
<title xml:lang="en">Addon for displaying level icon</title>
<author email_address="zero@zeroboard.com" link="http://www.zeroboard.com" date="2007. 7. 26">
<name xml:lang="ko">제로</name>
<name xml:lang="zh-CN">Zero</name>
<name xml:lang="jp">Zero</name>
<name xml:lang="en">zero</name>
<description xml:lang="ko">
포인트 시스템을 사용중일 경우 사용자 이름 앞에 레벨 아이콘을 표시하도록 합니다.
레벨 아이콘은 모듈 &gt; 포인트시스템에서 선택 가능합니다.
</description>
<description xml:lang="zh-CN">
使用积分系统时,可以在用户名前显示级别图标。
级别图标可以在模块 &gt; 积分系统中进行选择。
</description>
<description xml:lang="jp">
ポイントシステムを使用している場合、ユーザ名の前にレベルアイコンを表示させます。レベルアイコンは、「モジュール&gt;ポイントシステム」で選択できます。
</description>
<description xml:lang="en">
This addon displays level icon in front of user name when point system is using.
You can choose level icon on Module &gt; Point System.
</description>
</author>
</addon>

View file

@ -0,0 +1,17 @@
<?php
if(!defined("__ZBXE__")) exit();
/**
* @file point.addon.php
* @author zero (zero@nzeo.com)
* @brief 포인트 레벨 아이콘 표시 애드온
*
* 포인트 시스템 사용중일때 사용자 이름 앞에 포인트 레벨 아이콘을 표시합니다.
**/
// before_display_content 가 아니면 return
if($called_position != "before_display_content") return;
$oPointController = &getController('point');
$output = preg_replace_callback('!<(div|span)([^\>]*)member_([0-9\-]+)([^\>]*)>(.*?)\<\/(div|span)\>!is', array($oPointController, 'transLevelIcon'), $output);
?>

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<addon version="0.1">
<title xml:lang="ko">레인보우 링크 애드온</title>
<title xml:lang="zh-CN">Rainbow 链接</title>
<title xml:lang="en">Addon for rainbow links</title>
<title xml:lang="es">Adición Enlace Arco Iris</title>
<title xml:lang="jp">レインボーリンク</title>
<author email_address="webmaster@dynamicdrive.com" link="http://dynamicdrive.com" date="2007. 2. 28">
<name xml:lang="ko">dynamicdrive.com</name>
<name xml:lang="zh-CN">dynamicdrive.com</name>
<name xml:lang="en">dynamicdrive.com</name>
<name xml:lang="es">dynamicdrive.com</name>
<name xml:lang="jp">dynamicdrive.com</name>
<description xml:lang="ko">
rainbow.js를 header에 추가하여 링크가 걸린 글의 색을 무지개색으로 나타냅니다.
이 애드온의 rainbow.js는 &lt;a href=&quot;http://www.dynamicdrive.com&quot; target=&quot;_blank&quot;&gt;Dynamicdrive.com&lt;/a&gt;에 저작권이 있습니다.
</description>
<description xml:lang="zh-CN">
把rainbow.js添加到header区使链接显示为彩虹色。
此插件的rainbow.js文件版权属于 &lt;a href=&quot;http://www.dynamicdrive.com&quot; target=&quot;_blank&quot;&gt;Dynamicdrive.com&lt;/a&gt;
</description>
<description xml:lang="en">
This addon adds a file named &quot;rainbow.js&quot; to headers, then linked text will get chameleon(rainbow) color change effect.
&quot;rainbow.js&quot; Copyrightⓒ2007 &lt;a href=&quot;http://www.dynamicdrive.com&quot; target=&quot;_blank&quot;&gt;Dynamicdrive.com&lt;/a&gt;.
</description>
<description xml:lang="es">
incluye rainbow.js en header para mostrar enlaces en colores de arco iris.
&lt;a href=&quot;http://www.dynamicdrive.com&quot; target=&quot;_blank&quot;&gt;Dynamicdrive.com&lt;/a&gt; tiene derecho de autor sobre rainbow.js
</description>
<description xml:lang="jp">
「rainbow.js」をヘッダーに追加し、リンクされている文字列の色を虹色で表示します。この機能拡張の「 rainbow.js」は「&lt;a href=&quot;http://www.dynamicdrive.com&quot; target=&quot;_blank&quot;&gt;Dynamicdrive.com&lt;/a&gt;」に著作権があります。
</description>
</author>
</addon>

View file

@ -0,0 +1,245 @@
/************************************************************************/
/* Rainbow Links Version 1.03 (2003.9.20) */
/* Script updated by Dynamicdrive.com for IE6 */
/* Copyright (C) 1999-2001 TAKANASHI Mizuki */
/* takanasi@hamal.freemail.ne.jp */
/*----------------------------------------------------------------------*/
/* Read it somehow even if my English text is a little wrong! ;-) */
/* */
/* Usage: */
/* Insert '<script src="rainbow.js"></script>' into the BODY section, */
/* right after the BODY tag itself, before anything else. */
/* You don't need to add "onMouseover" and "onMouseout" attributes!! */
/* */
/* If you'd like to add effect to other texts(not link texts), then */
/* add 'onmouseover="doRainbow(this);"' and */
/* 'onmouseout="stopRainbow();"' to the target tags. */
/* */
/* This Script works with IE4,Netscape6,Mozilla browser and above only, */
/* but no error occurs on other browsers. */
/************************************************************************/
////////////////////////////////////////////////////////////////////
// Setting
var rate = 20; // Increase amount(The degree of the transmutation)
////////////////////////////////////////////////////////////////////
// Main routine
/*
if (document.getElementById)
window.onerror=new Function("return true")
*/
var objActive; // The object which event occured in
var act = 0; // Flag during the action
var elmH = 0; // Hue
var elmS = 128; // Saturation
var elmV = 255; // Value
var clrOrg; // A color before the change
var TimerID; // Timer ID
if(xIE4Up) {
xAddEventListener(document, 'mouseover', doRainbowAnchor);
xAddEventListener(document, 'mouseout', stopRainbowAnchor);
} else {
xAddEventListener(document, 'mouseover', Mozilla_doRainbowAnchor);
xAddEventListener(document, 'mouseout', Mozilla_stopRainbowAnchor);
}
/*
if (document.all) {
document.onmouseover = doRainbowAnchor;
document.onmouseout = stopRainbowAnchor;
}
else if (document.getElementById) {
document.captureEvents(Event.MOUSEOVER | Event.MOUSEOUT);
document.onmouseover = Mozilla_doRainbowAnchor;
document.onmouseout = Mozilla_stopRainbowAnchor;
}
*/
//=============================================================================
// doRainbow
// This function begins to change a color.
//=============================================================================
function doRainbow(obj)
{
if (act == 0) {
act = 1;
if (obj)
objActive = obj;
else
objActive = event.srcElement;
clrOrg = objActive.style.color;
TimerID = setInterval("ChangeColor()",100);
}
}
//=============================================================================
// stopRainbow
// This function stops to change a color.
//=============================================================================
function stopRainbow()
{
if (act) {
objActive.style.color = clrOrg;
clearInterval(TimerID);
act = 0;
}
}
//=============================================================================
// doRainbowAnchor
// This function begins to change a color. (of a anchor, automatically)
//=============================================================================
function doRainbowAnchor()
{
try {
if (act == 0) {
var obj = event.srcElement;
while (obj.tagName != 'A' && obj.tagName != 'BODY') {
obj = obj.parentElement;
if (obj.tagName == 'A' || obj.tagName == 'BODY')
break;
}
if (obj.tagName == 'A' && obj.href != '') {
objActive = obj;
act = 1;
clrOrg = objActive.style.color;
TimerID = setInterval("ChangeColor()",100);
}
}
} catch(e) {
}
}
//=============================================================================
// stopRainbowAnchor
// This function stops to change a color. (of a anchor, automatically)
//=============================================================================
function stopRainbowAnchor()
{
if (act) {
if (objActive.tagName == 'A') {
objActive.style.color = clrOrg;
clearInterval(TimerID);
act = 0;
}
}
}
//=============================================================================
// Mozilla_doRainbowAnchor(for Netscape6 and Mozilla browser)
// This function begins to change a color. (of a anchor, automatically)
//=============================================================================
function Mozilla_doRainbowAnchor(evt)
{
var e = new xEvent(evt);
if (act == 0) {
obj = e.target;
while (obj.nodeName != 'A' && obj.nodeName != 'BODY') {
obj = obj.parentNode;
if(typeof(obj)=='undefined'||!obj) return;
if (obj.nodeName == 'A' || obj.nodeName == 'BODY') break;
}
if (obj.nodeName == 'A' && obj.href != '') {
objActive = obj;
act = 1;
clrOrg = obj.style.color;
TimerID = setInterval("ChangeColor()",100);
}
}
}
//=============================================================================
// Mozilla_stopRainbowAnchor(for Netscape6 and Mozilla browser)
// This function stops to change a color. (of a anchor, automatically)
//=============================================================================
function Mozilla_stopRainbowAnchor(e)
{
if (act) {
if (objActive.nodeName == 'A') {
objActive.style.color = clrOrg;
clearInterval(TimerID);
act = 0;
}
}
}
//=============================================================================
// Change Color
// This function changes a color actually.
//=============================================================================
function ChangeColor()
{
objActive.style.color = makeColor();
}
//=============================================================================
// makeColor
// This function makes rainbow colors.
//=============================================================================
function makeColor()
{
// Don't you think Color Gamut to look like Rainbow?
// HSVtoRGB
if (elmS == 0) {
elmR = elmV; elmG = elmV; elmB = elmV;
}
else {
t1 = elmV;
t2 = (255 - elmS) * elmV / 255;
t3 = elmH % 60;
t3 = (t1 - t2) * t3 / 60;
if (elmH < 60) {
elmR = t1; elmB = t2; elmG = t2 + t3;
}
else if (elmH < 120) {
elmG = t1; elmB = t2; elmR = t1 - t3;
}
else if (elmH < 180) {
elmG = t1; elmR = t2; elmB = t2 + t3;
}
else if (elmH < 240) {
elmB = t1; elmR = t2; elmG = t1 - t3;
}
else if (elmH < 300) {
elmB = t1; elmG = t2; elmR = t2 + t3;
}
else if (elmH < 360) {
elmR = t1; elmG = t2; elmB = t1 - t3;
}
else {
elmR = 0; elmG = 0; elmB = 0;
}
}
elmR = Math.floor(elmR).toString(16);
elmG = Math.floor(elmG).toString(16);
elmB = Math.floor(elmB).toString(16);
if (elmR.length == 1) elmR = "0" + elmR;
if (elmG.length == 1) elmG = "0" + elmG;
if (elmB.length == 1) elmB = "0" + elmB;
elmH = elmH + rate;
if (elmH >= 360)
elmH = 0;
return '#' + elmR + elmG + elmB;
}

View file

@ -0,0 +1,19 @@
<?php
if(!defined("__ZBXE__")) exit();
/**
* @file rainbow.addon.php
* @author zero (zero@nzeo.com)
* @brief Rainbow link addon
*
* 링크가 걸린 텍스트에 마우스 오버를 하면 무지개색으로 변하게 하는 애드온입니다.
* rainbow.js 파일만 추가하는 것으로 끝납니다.
* rainbow.js는 http://www.dynamicdrive.com에서 제작하였으며 저작권을 가지고 있습니다.
* before_display_content 에서만 요청이 됩니다.
**/
if(Context::get('module')=='admin' || $called_position != 'before_module_init') return;
// Context::addJsFile()을 이용하면 끝
Context::addJsFile($addon_path.'js/rainbow.js');
?>

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<addon version="0.1">
<title xml:lang="ko">스팸필터 애드온</title>
<title xml:lang="zh-CN">垃圾过滤</title>
<title xml:lang="en">Addon for filtering spam</title>
<title xml:lang="es">Adición Filtros para artículos no deseado</title>
<title xml:lang="jp">スパムフィルター</title>
<author email_address="zero@zeroboard.com" link="http://www.zeroboard.com" date="2007. 2. 28">
<name xml:lang="ko">제로</name>
<name xml:lang="en">zero</name>
<name xml:lang="zh-CN">zero</name>
<name xml:lang="es">zero</name>
<name xml:lang="jp">Zero</name>
<description xml:lang="ko">
SpamFilter 모듈을 이용하여 글/코멘트/트랙백 등록 이전에 스팸 필터링 및 도배 방지를 합니다.
자세한 설정은 &quot; 스팸필터 모듈&quot; 에서 해주세요.
</description>
<description xml:lang="zh-CN">
利用垃圾过滤模块在发表主题/评论/引用之前进行垃圾过滤。
请在&quot; 垃圾过滤模块&quot;中详细设置。
</description>
<description xml:lang="en">
This addon filters spam and prevents users from cluttering before saving entries, comments, or trackbacks to database by setting SpamFilter module.
You can set up more details on &quot;Spam Filter module&quot;.
</description>
<description xml:lang="es">
Utiliza SpamFilter para bloquear los artículos/ commentarios/ trackback no deseado.
Para configurar haga clic &quot; Configurar la modula SpamFilter.&quot;..º
</description>
<description xml:lang="jp">
SpamFilterモジュールを利用して書き込み・コメント・トラックバックが登録される前にフィルタリングを行います。更に連続書き込みやロボットによる自動書き込みなどを防ぐことができます。詳細な設定は &quot; スパムフィルターモジュール &quot; で行ってください。
</description>
</author>
</addon>

View file

@ -0,0 +1,133 @@
<?php
if(!defined("__ZBXE__")) exit();
/**
* @file spamfilter.addon.php
* @author zero (zero@nzeo.com)
* @brief 스팸필터링 애드온
*
* 스팸필터 애드온은 SpamFilter 모듈을 이용합니다.
* /코멘트/트랙백 등록 이전에만 실행이 됩니다.
**/
// called_position가 before_module_proc 일때만 실행
if($called_position != 'before_module_proc') return;
// 이 애드온이 동작할 대상 (이 부분은 특별히 정해진 규약이 없다)
$effecived_target_act = array(
'procBoardInsertDocument', 'procBoardInsertComment',
'procBlogInsertComment',
'trackback',
);
// spam filter모듈이 적용될 module+act를 체크
if(!in_array($this->act, $effecived_target_act)) return;
// 각 모듈별 act에 대해서도 피해갈 부분이 있으면 피해감
switch($this->act) {
// 게시물 작성시 신규 등록이 아니면 패스~
case 'procBoardInsertDocument' :
// document module의 model 객체 생성
$oDocumentModel = &getModel('document');
// 이미 존재하는 글인지 체크
$document_srl = Context::get('document_srl');
$oDocument = $oDocumentModel->getDocument($document_srl);
// 이미 존재하는 글이라면 return
if($oDocument->isExists()) return;
break;
// 댓글 작성시 신규 등록이 아니면 패스~
case 'procBoardInsertComment' :
case 'procBlogInsertComment' :
$comment_srl = Context::get('comment_srl');
$oCommentModel = &getModel('comment');
// 이미 존재하는 댓글인지 체크
$comment = $oCommentModel->getComment($comment_srl);
if($comment->comment_srl == $comment_srl) return;
break;
}
// 현재 모듈의 관리자이거나 그에 준하는 manager권한이면 그냥 패스
if($this->grant->is_admin || $this->grant->manager) return;
// 현 접속자의 ip address를 구함
$ipaddress = $_SERVER['REMOTE_ADDR'];
// spamfilter 모듈 객체 생성
$oSpamFilterController = &getController('spamfilter');
$oSpamFilterModel = &getModel('spamfilter');
// 스팸필터 기본 설정 출력
$config = $oSpamFilterModel->getConfig();
// 스팸 간격을 체크하는 변수
$interval = $config->interval?$config->interval:60;
// 스팸 간격내에 limit_count이상 작성을 시도하면 해당 ip를 금지 시킴
$limit_count = $config->limit_count?$config->limit_count:5;
// 트랙백의 경우 한 글에 하나의 ip에서만 트랙백을 허용함
$check_trackback = $config->check_trackback=='Y'?true:false;
// 스팸 IP에 등록되어 있는지 체크하여 등록되어 있으면 return
$is_denied = $oSpamFilterModel->isDeniedIP($ipaddress);
if($is_denied) {
$output = new Object(-1, 'msg_alert_registered_denied_ip');
$this->stop_proc = true;
return;
}
// act==procReceiveTrackback (트랙백)일때 check_trackback==true이면 검사
if($this->act=='procReceiveTrackback' && $check_trackback){
$oTrackbackModel = &getModel('trackback');
$document_srl = Context::get('document_srl');
$count = $oTrackbackModel->getTrackbackCountByIPAddress($document_srl, $ipaddress);
if($count>0) {
$output = Object(-1, 'msg_alert_trackback_denied');
$this->stop_proc = true;
return;
}
}
// 정해진 시간내에 글 작성 시도를 하였는지 체크
$count = $oSpamFilterModel->getLogCount($interval, $ipaddress);
// 정해진 시간내에 정해진 글의 수를 초과시 스팸 IP로 등록시킴
if($count>=$limit_count) {
$oSpamFilterController->insertIP($ipaddress);
$output = new Object(-1, 'msg_alert_registered_denied_ip');
$this->stop_proc = true;
return;
// 제한 글수까지는 아니지만 정해진 시간내에 글 작성을 계속 할때
} elseif($count) {
$message = sprintf(Context::getLang('msg_alert_limited_by_config'), $interval);
$output = new Object(-1, $message);
$this->stop_proc = true;
}
// 금지 단어 체크를 위해서 몇가지 지정된 변수들을 한데 묶음
$check_vars = implode("\n",get_object_vars(Context::getRequestVars()));
// 금지 단어를 이용하여 본문 내용을 체크
$denied_word_list = $oSpamFilterModel->getDeniedWordList();
$denied_word_count = count($denied_word_list);
if($denied_word_count>0) {
for($i=0;$i<$denied_word_count;$i++) {
$word = preg_quote($denied_word_list[$i]->word,'/');
if(preg_match('/'.$word.'/i', $check_vars)) {
$message = sprintf(Context::getLang('msg_alert_denied_word'), $word);
$output = new Object(-1, $message);
$this->stop_proc = true;
return;
}
}
}
// 로그를 남김
$oSpamFilterController->insertLog();
?>