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,17 @@
<?xml version="1.0" encoding="utf-8"?>
<module version="0.1">
<title xml:lang="ko">제로보드 데이터 이전</title>
<title xml:lang="en">Zeroboard data transferation</title>
<title xml:lang="zh-CN">数据导入</title>
<title xml:lang="jp">ZBデータ移転</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="jp">Zero</name>
<description xml:lang="ko">XML파일을 이용하여 회원정보 또는 게시판등의 데이터를 입력합니다. </description>
<description xml:lang="en">Inputting member information or board's data using XML file.</description>
<description xml:lang="zh-CN">利用XML文件导入会员信息或版面数据。</description>
<description xml:lang="jp">XMLファイルを用いて会員情報または掲示板などの情報を入力します。</description>
</author>
</module>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<module>
<actions>
<action name="dispImporterAdminContent" type="view" standalone="true" admin_index="true" />
<action name="procImporterAdminStep1" type="controller" standalone="true" />
<action name="procImporterAdminStep12" type="controller" standalone="true" />
<action name="procImporterAdminImport" type="controller" standalone="true" />
<action name="procImporterAdminSync" type="controller" standalone="true" />
</actions>
</module>

View file

@ -0,0 +1,498 @@
<?php
/**
* @class importerAdminController
* @author zero (zero@nzeo.com)
* @brief importer 모듈의 admin controller class
**/
class importerAdminController extends importer {
var $oXml = null;
var $oMemberController = null;
var $oMemberModel = null;
var $oDocumentController = null;
var $oFileController = null;
var $oCommentController = null;
var $oTrackbackController = null;
var $total_count = '';
var $start_position = 0;
var $position = 0;
var $limit_count = 50;
var $file_point = 0;
var $default_group_srl = 0;
var $module_srl = 0;
var $target_path = 0;
var $category_srl = 0;
var $category_list = array();
var $msg = null;
/**
* @brief 초기화
**/
function init() {
}
/**
* @brief import step1
* import하려는 대상에 따라 결과값을 구해서 return
* 회원정보 : next_step=2, module_list = null
* 모듈정보 : next_step=12, module_list = modules..
* 회원정보 동기화 : next_step=3
**/
function procImporterAdminStep1() {
$source_type = Context::get('source_type');
switch($source_type) {
case 'module' :
// 모듈 목록을 구함
$oModuleModel = &getModel('module');
$module_list = $oModuleModel->getMidList();
foreach($module_list as $key => $val) {
$module_list_arr[] = sprintf('%d,%s (%s)', $val->module_srl, $val->browser_title, $val->mid);
}
if(count($module_list_arr)) $module_list = implode("\n",$module_list_arr);
$next_step = 12;
break;
case 'member' :
$next_step = 2;
break;
case 'syncmember' :
$next_step = 3;
break;
}
$this->add('next_step', $next_step);
$this->add('module_list', $module_list);
}
/**
* @brief import step12
* module_srl을 이용하여 대상 모듈에 카테고리값이 있는지 확인하여
* 있으면 카테고리 정보를 return, 아니면 파일 업로드 단계로 이동
**/
function procImporterAdminStep12() {
$target_module= Context::get('target_module');
// 대상 모듈의 카테고리 목록을 구해옴
$oDocumentModel = &getModel('document');
$category_list = $oDocumentModel->getCategoryList($target_module);
if(count($category_list)) {
foreach($category_list as $key => $val) {
$category_list_arr[] = sprintf('%d,%s', $val->category_srl, $val->title);
}
if(count($category_list_arr)) {
$category_list = implode("\n",$category_list_arr);
$next_step = 13;
}
} else {
$category_list = null;
$next_step = 2;
}
$this->add('next_step', $next_step);
$this->add('category_list', $category_list);
}
/**
* @brief import 실행
**/
function procImporterAdminImport() {
// 실행시간 무한대로 설정
@set_time_limit(0);
// 변수 체크
$this->module_srl = Context::get('module_srl');
$this->target_path = Context::get('target_path');
if(substr($this->target_path,-1)!="/") $this->target_path .= "/";
$this->category_srl = Context::get('category_srl');
$xml_file = Context::get('xml_file');
$this->start_position = $this->position = (int)Context::get('position');
$this->total_count = (int)Context::get('total_count');
$this->file_point = (int)Context::get('file_point');
// 파일을 찾을 수 없으면 에러 표시
if(!file_exists($xml_file)) return new Object(-1,'msg_no_xml_file');
$this->oXml = new XmlParser();
$oDB = &DB::getInstance();
$oDB->begin();
// module_srl이 있으면 module데이터로 판단하여 처리, 아니면 회원정보로..
if($this->module_srl) {
$this->limit_count = 100;
$is_finished = $this->importDocument($xml_file);
} else {
$this->limit_count = 500;
$is_finished = $this->importMember($xml_file);
}
$oDB->commit();
if($is_finished) {
$this->add('is_finished', 'Y');
$this->add('position', $this->total_count);
$this->add('total_count', $this->total_count);
$this->setMessage( sprintf(Context::getLang('msg_import_finished'), $this->position) );
} else {
$this->add('position', $this->position);
$this->add('total_count', $this->total_count);
$this->add('file_point', $this->file_point);
$this->add('is_finished', 'N');
$this->setMessage( $this->msg );
}
}
/**
* @brief 회원정보 import
**/
function importMember($xml_file) {
$filesize = filesize($xml_file);
if($filesize<1) return true;
$this->oMemberController = &getController('member');
$this->oMemberModel = &getModel('member');
$default_group = $this->oMemberModel->getDefaultGroup();
$this->default_group_srl = $default_group->group_srl;
$is_finished = true;
$fp = @fopen($xml_file, "r");
if($this->file_point) fseek($fp, $this->file_point, SEEK_SET);
if($fp) {
$buff = '';
while(!feof($fp)) {
$str = fgets($fp,1024);
$buff .= $str;
$buff = preg_replace_callback("!<root([^>]*)>!is", array($this, '_parseRootInfo'), $buff);
$buff = preg_replace_callback("!<member user_id=\"([^\"]*)\">(.*?)<\/member>!is", array($this, '_importMember'), $buff);
if($this->start_position+$this->limit_count <= $this->position) {
$is_finished = false;
$this->file_point = ftell($fp) - strlen($buff);;
break;
}
}
fclose($fp);
}
return $is_finished;
}
function _importMember($matches) {
$user_id = $matches[1];
$xml_doc = $this->oXml->parse($matches[0]);
$args->user_id = strtolower($xml_doc->member->user_id->body);
$args->user_name = $xml_doc->member->user_name->body;
$args->nick_name = $xml_doc->member->nick_name->body;
$args->homepage = $xml_doc->member->homepage->body;
$args->blog = $xml_doc->member->blog->body;
if($args->homepage && !eregi("^http:\/\/",$args->homepage)) $args->homepage = 'http://'.$args->homepage;
if($args->blog && !eregi("^http:\/\/",$args->blog)) $args->blog = 'http://'.$args->blog;
$args->birthday = $xml_doc->member->birthday->body;
$args->email_address = $xml_doc->member->email_address->body;
list($args->email_id, $args->email_host) = explode('@', $args->email_address);
if(!$args->email_host) $args->email_host = $args->email_id;
$args->password = $xml_doc->member->password->body;
$args->regdate = $xml_doc->member->regdate->body;
$args->allow_mailing = $xml_doc->member->allow_mailing->body;
if($args->allow_mailing!='Y') $args->allow_mailing = 'N';
$args->allow_message = 'Y';
if(!in_array($args->allow_message, array('Y','N','F'))) $args->allow_message= 'Y';
$args->member_srl = getNextSequence();
$output = executeQuery('member.insertMember', $args);
if(!$output->toBool()) {
// 닉네임이 같으면 닉네임을 변경후 재 입력
$member_srl = $this->oMemberModel->getMemberSrlByNickName($args->nick_name);
if($member_srl) {
$args->nick_name .= rand(111,999);
$output = executeQuery('member.insertMember', $args);
}
}
if($output->toBool()) {
// 기본 그룹 가입 시킴
$member_srl = $args->member_srl;
$args->group_srl = $this->default_group_srl;
executeQuery('member.addMemberToGroup',$args);
// 이미지네임
if($xml_doc->member->image_nickname->body) {
$image_nickname = base64_decode($xml_doc->member->image_nickname->body);
$target_path = sprintf('files/member_extra_info/image_name/%s/', getNumberingPath($args->member_extra_info));
$target_filename = sprintf('%s%d.gif', $target_path, $args->member_srl);
FileHandler::makeDir($target_path);
FileHandler::writeFile($target_filename, $image_nickname);
}
// 이미지 마크
if($xml_doc->member->image_mark->body) {
$image_mark = base64_decode($xml_doc->member->image_mark->body);
$target_path = sprintf('files/member_extra_info/image_mark/%s/', getNumberingPath($args->member_srl));
$target_filename = sprintf('%s%d.gif', $target_path, $args->member_srl);
FileHandler::makeDir($target_path);
FileHandler::writeFile($target_filename, $image_mark);
}
// 서명
if(trim($xml_doc->member->signature->body)) {
$signature = removeHackTag(base64_decode($xml_doc->member->signature->body));
$signature_buff = sprintf('<?php if(!defined("__ZBXE__")) exit();?>%s', $signature);
$target_path = sprintf('files/member_extra_info/signature/%s/', getNumberingPath($args->member_srl));
$target_filename = sprintf('%s%d.signature.php', $target_path, $args->member_srl);
FileHandler::makeDir($target_path);
FileHandler::writeFile($target_filename, $signature_buff);
}
} else {
$this->msg .= $args->user_id." : ".$output->getMessage()."<br />";
}
$this->position++;
return '';
}
/**
* @brief 게시물정보 import
**/
function importDocument($xml_file) {
$filesize = filesize($xml_file);
if($filesize<1) return;
$this->oDocumentController = &getController('document');
$this->oFileController = &getController('file');
$this->oCommentController = &getController('comment');
$this->oTrackbackController = &getController('trackback');
$oDocumentModel = &getModel('document');
$tmp_category_list = $oDocumentModel->getCategoryList($this->module_srl);
if(count($tmp_category_list)) {
foreach($tmp_category_list as $key => $val) $this->category_list[$val->title] = $key;
} else {
$this->category_list = array();
}
$is_finished = true;
$fp = @fopen($xml_file, "r");
if($this->file_point) fseek($fp, $this->file_point, SEEK_SET);
if($fp) {
$buff = '';
while(!feof($fp)) {
$str = fread($fp,1024);
$buff .= $str;
$buff = preg_replace_callback("!<root([^>]*)>!is", array($this, '_parseRootInfo'), $buff);
if(!$this->category_srl) $buff = preg_replace_callback("!<categories>(.*?)</categories>!is", array($this, '_parseCategoryInfo'), $buff);
$buff = preg_replace_callback("!<document sequence=\"([^\"]*)\">(.*?)<\/document>!is", array($this, '_importDocument'), $buff);
if($this->start_position+$this->limit_count <= $this->position) {
$is_finished = false;
$this->file_point = ftell($fp) - strlen($buff);;
break;
}
}
fclose($fp);
}
return $is_finished;
}
function _importDocument($matches) {
$sequence = $matches[1];
$matches[0] = str_replace(array('',''),'',$matches[0]);
$xml_doc = $this->oXml->parse($matches[0]);
// 문서 번호와 내용 미리 구해 놓기
$args->document_srl = getNextSequence();
$args->content = $xml_doc->document->content->body;
// 첨부파일 미리 등록
$files = $xml_doc->document->files->file;
if($files && !is_array($files)) $files = array($files);
if(count($files)) {
foreach($files as $key => $val) {
$filename = $val->filename->body;
$path = $val->path->body;
$download_count = (int)$val->download_count->body;
$tmp_filename = './files/cache/tmp_uploaded_file';
$path = $this->target_path.$path;
if(!eregi("^http",$path)) {
if(preg_match('/[\xEA-\xED][\x80-\xFF]{2}/', $path)&&function_exists('iconv')) {
$tmp_path = iconv("UTF-8","EUC-KR",$path);
if(file_exists($tmp_path)) $path = $tmp_path;
}
if(file_exists($path)) @copy($path, $tmp_filename);
} else FileHandler::getRemoteFile($path, $tmp_filename);
if(file_exists($tmp_filename)) {
$file_info['tmp_name'] = $tmp_filename;
$file_info['name'] = $filename;
$this->oFileController->insertFile($file_info, $this->module_srl, $args->document_srl, $download_count, true);
// 컨텐츠의 내용 수정 (이미지 첨부파일 관련)
if(eregi("\.(jpg|gif|jpeg|png)$", $filename)) $args->content = str_replace($filename, sprintf('./files/attach/images/%s/%s/%s', $this->module_srl, $args->document_srl, $filename), $args->content);
}
@unlink($tmp_filename);
}
}
// 문서 입력
$args->module_srl = $this->module_srl;
if($this->category_srl) $args->category_srl = $this->category_srl;
elseif($xml_doc->document->category->body) $args->category_srl = $this->category_list[$xml_doc->document->category->body];
$args->is_notice = $xml_doc->document->is_notice->body;
$args->is_secret = $xml_doc->document->is_secret->body;
$args->title = $xml_doc->document->title->body;
$args->readed_count = $xml_doc->document->readed_count->body;
$args->voted_count = $xml_doc->document->voted_count->body;
$args->comment_count = $xml_doc->document->comment_count->body;
$args->trackback_count = $xml_doc->document->trackback_count->body;
$args->uploaded_count = $xml_doc->document->uploaded_count->body;
$args->password = $xml_doc->document->password->body;
$args->nick_name = $xml_doc->document->nick_name->body;
$args->member_srl = 0;
$args->user_id = $xml_doc->document->user_id->body;
$args->user_name = $xml_doc->document->user_name->body;
$args->email_address = $xml_doc->document->email_address->body;
$args->homepage = $xml_doc->document->homepage->body;
$args->tags = $xml_doc->document->tags->body;
$args->regdate = $xml_doc->document->regdate->body;
$args->ipaddress = $xml_doc->document->ipaddress->body;
$args->allow_comment = $xml_doc->document->allow_comment->body;
$args->lock_comment = $xml_doc->document->lock_comment->body;
$args->allow_trackback = $xml_doc->document->allow_trackback->body;
$args->extra_vars1 = $xml_doc->document->extra_vars1->body;
$args->extra_vars2 = $xml_doc->document->extra_vars2->body;
$args->extra_vars3 = $xml_doc->document->extra_vars3->body;
$args->extra_vars4 = $xml_doc->document->extra_vars4->body;
$args->extra_vars5 = $xml_doc->document->extra_vars5->body;
$args->extra_vars6 = $xml_doc->document->extra_vars6->body;
$args->extra_vars7 = $xml_doc->document->extra_vars7->body;
$args->extra_vars8 = $xml_doc->document->extra_vars8->body;
$args->extra_vars9 = $xml_doc->document->extra_vars9->body;
$args->extra_vars10 = $xml_doc->document->extra_vars10->body;
$args->extra_vars11 = $xml_doc->document->extra_vars11->body;
$args->extra_vars12 = $xml_doc->document->extra_vars12->body;
$args->extra_vars13 = $xml_doc->document->extra_vars13->body;
$args->extra_vars14 = $xml_doc->document->extra_vars14->body;
$args->extra_vars15 = $xml_doc->document->extra_vars15->body;
$args->extra_vars16 = $xml_doc->document->extra_vars16->body;
$args->extra_vars17 = $xml_doc->document->extra_vars17->body;
$args->extra_vars18 = $xml_doc->document->extra_vars18->body;
$args->extra_vars19 = $xml_doc->document->extra_vars19->body;
$args->extra_vars20 = $xml_doc->document->extra_vars20->body;
$output = $this->oDocumentController->insertDocument($args, true);
if($output->toBool()) {
// 코멘트 입력
$comments = $xml_doc->document->comments->comment;
if($comments && !is_array($comments)) $comments = array($comments);
if(count($comments)) {
foreach($comments as $key => $val) {
$comment_args->document_srl = $args->document_srl;
$comment_args->comment_srl = getNextSequence();
$comment_args->module_srl = $this->module_srl;
//$comment_args->parent_srl = $val->parent_srl->body;
$comment_args->parent_srl = 0;
$comment_args->content = $val->content->body;
$comment_args->password = $val->password->body;
$comment_args->nick_name = $val->nick_name->body;
$comment_args->user_id = $val->user_id->body;
$comment_args->user_name = $val->user_name->body;
$comment_args->member_srl = 0;
$comment_args->email_address = $val->email_address->body;
$comment_args->regdate = $val->regdate->body;
$comment_args->ipaddress = $val->ipaddress->body;
$this->oCommentController->insertComment($comment_args, true);
}
}
// 트랙백 입력
$trackbacks = $xml_doc->document->trackbacks->trackback;
if($trackbacks && !is_array($trackbacks)) $trackbacks = array($trackbacks);
if(count($trackbacks)) {
foreach($trackbacks as $key => $val) {
$trackback_args->document_srl = $args->document_srl;
$trackback_args->module_srl = $this->module_srl;
$trackback_args->url = $val->url->body;
$trackback_args->title = $val->title->body;
$trackback_args->blog_name = $val->blog_name->body;
$trackback_args->excerpt = $val->excerpt->body;
$trackback_args->regdate = $val->regdate->body;
$trackback_args->ipaddress = $val->ipaddress->body;
$this->oTrackbackController->insertTrackback($trackback_args, true);
}
}
} else {
$this->msg .= $sequence." : ".$output->getMessage()."<br />";
}
$this->position++;
return '';
}
/**
* @brief 회원정보와 게시물 정보를 싱크
**/
function procImporterAdminSync() {
// 게시물정보 싱크
$output = executeQuery('importer.updateDocumentSync');
// 댓글정보 싱크
$output = executeQuery('importer.updateCommentSync');
$this->setMessage('msg_sync_completed');
}
/**
* @brief <root>정보를 읽어서 정보를 구함
**/
function _parseRootInfo($matches) {
$root = $matches[0].'</root>';
$xml_doc = $this->oXml->parse($root);
$this->total_count = $xml_doc->root->attrs->count;
}
/**
* @brief <categories>정보를 읽어서 정보를 구함
**/
function _parseCategoryInfo($matches) {
$xml_doc = $this->oXml->parse($matches[0]);
$category_list = $xml_doc->categories->category;
if(!$category_list) return;
if(!is_array($category_list)) $category_list = array($category_list);
$oDocumentController = &getAdminController('document');
foreach($category_list as $key => $val) {
$title = $val->body;
if($this->category_list[$title]) continue;
$output = $oDocumentController->insertCategory($this->module_srl, $title);
$this->category_list[$title] = $output->get('category_srl');
}
}
}
?>

View file

@ -0,0 +1,27 @@
<?php
/**
* @class importerAdminView
* @author zero (zero@nzeo.com)
* @brief importer 모듈의 admin view class
**/
class importerAdminView extends importer {
/**
* @brief 초기화
*
* importer 모듈은 일반 사용과 관리자용으로 나누어진다.\n
**/
function init() {
}
/**
* @brief XML 파일을 업로드하는 form 출력
**/
function dispImporterAdminContent() {
$this->setTemplatePath($this->module_path.'tpl');
$this->setTemplateFile('index');
}
}
?>

View file

@ -0,0 +1,36 @@
<?php
/**
* @class importer
* @author zero (zero@nzeo.com)
* @brief importer 모듈의 high class
**/
class importer extends ModuleObject {
/**
* @brief 설치시 추가 작업이 필요할시 구현
**/
function moduleInstall() {
// action forward에 등록 (관리자 모드에서 사용하기 위함)
$oModuleController = &getController('module');
$oModuleController->insertActionForward('importer', 'view', 'dispImporterAdminContent');
return new Object();
}
/**
* @brief 설치가 이상이 없는지 체크하는 method
**/
function checkUpdate() {
return false;
}
/**
* @brief 업데이트 실행
**/
function moduleUpdate() {
return new Object();
}
}
?>

View file

@ -0,0 +1,52 @@
<?php
/**
* @file en.lang.php
* @author zero (zero@nzeo.com)
* @brief Importer module's basic language pack
**/
// words for button
$lang->cmd_sync_member = 'Synchronize';
$lang->cmd_continue = 'Continue';
// items
$lang->importer = 'Transfer zeroboard datas';
$lang->source_type = 'Previous target';
$lang->type_member = 'Member data';
$lang->type_module = 'Articles data';
$lang->type_syncmember = 'Synchronize member data';
$lang->target_module = 'Target module';
$lang->xml_file = 'XML file';
$lang->import_step_title = array(
1 => 'Step 1. Select previous target',
12 => 'Step 1-2. Select target module',
13 => 'Step 1-3. Select target category',
2 => 'Step 2. Upload XML file',
3 => 'Step 2. Synchronize member data and article data',
);
$lang->import_step_desc = array(
1 => 'Please select the XML file\'s type you wish to transfer.',
12 => 'Please select the module you wish to transfer datas.',
13 => 'Please select the target category you wish to tranfer datas.',
2 => "Please input the XML file's location you wish to tranfer datas.\nIf it is located in the same account, input absolute/relative path. If not, input the url starting with http://..",
3 => 'The member data and article data may not be correct after the transferation. If that is the case, synchronize to repair it based on user_id.',
);
// guide/alert
$lang->msg_sync_member = 'Member and article data synchronization will begin by clicking the synchronize button.';
$lang->msg_no_xml_file = 'Could not find XML file. Please check the path again';
$lang->msg_invalid_xml_file = 'Invalid type of XML file.';
$lang->msg_importing = 'Writing %d datas of %d. (If it keeps being frozen, click the button "Continue")';
$lang->msg_import_finished = '%d datas were inputted completely. Depending on the situation, there might be some datas which couldn\'t be inputted.';
$lang->msg_sync_completed = 'Completed synchronzing member article and comments.';
// blah blah..
$lang->about_type_member = 'If you are transfering the member information, select this option';
$lang->about_type_module = 'If you are transfering the board or articles information, select this option';
$lang->about_type_syncmember = 'If you are trying to synchronize the member information after transfering member and article information, select this option';
$lang->about_importer = "You can transfer Zeroboard4, Zeroboard5 Beta or other program's data into ZeroboardXE's data.\nIn order to tranfer, you have to use <a href=\"#\" onclick=\"winopen('');return false;\">XML Exporter</a> to convert the data you want into XML File then upload it.";
$lang->about_target_path = "첨부파일을 받기 위해 제로보드4가 설치된 위치를 입력해주세요.\n같은 서버에 있을 경우 /home/아이디/public_html/bbs 등과 같이 제로보드4의 위치를 입력하시고\n다른 서버일 경우 http://도메인/bbs 처럼 제로보드가 설치된 곳의 url을 입력해주세요";
?>

View file

@ -0,0 +1,52 @@
<?php
/**
* @file jp.lang.php
* @author zero (zero@nzeo.com) 翻訳RisaPapa
* @brief Importer(importer) モジュールの基本言語パッケージ
**/
// ボタンに使用する用語
$lang->cmd_sync_member = '同期化';
$lang->cmd_continue = '続ける';
// 項目
$lang->importer = 'ZBデータ変換';
$lang->source_type = 'データ変換の対象';
$lang->type_member = '会員情報';
$lang->type_module = '書き込みデータ情報';
$lang->type_syncmember = '会員情報同期化';
$lang->target_module = '対象モジュール';
$lang->xml_file = 'XMLファイル';
$lang->import_step_title = array(
1 => 'Step 1. 以前対象選択',
12 => 'Step 1-2. 対象モジュール選択',
13 => 'Step 1-3. 対象カテゴリ選択',
2 => 'Step 2. XMLファイルアップロード',
3 => 'Step 2. 会員情報と書き込みデータの同期化',
);
$lang->import_step_desc = array(
1 => '変換するXMLファイルの種類を選択してください。',
12 => 'データ変換を行う対象モジュールを選択してください。',
13 => 'データ変換を行う対象カテゴリを選択してください。',
2 => "データ変換を行うXMLファイルパスを入力してください。同じアカウントのサーバ上では、相対または絶対パスを、異なるサーバにアップロードされている場合は、「http://アドレス..」を入力してください。",
3 => '会員情報と書き込みデータの情報の変換を行った後、データが合わない場合があります。この時に同期化を行うと「user_id」をもとに正しく動作するようにします。',
);
// 案内/警告
$lang->msg_sync_member = '同期化ボタンをクリックすると会員情報と書き込みデータの情報の同期化が始まります。';
$lang->msg_no_xml_file = 'XMLファイルが見つかりません。パスをもう一度確認してください。';
$lang->msg_invalid_xml_file = 'XMLファイルのフォーマットが正しくありません。';
$lang->msg_importing = '%d個のデータの内、%d個を変換中です止まったままの場合は「続ける」ボタンをクリックしてください。';
$lang->msg_import_finished = '%d個のデータ変換が完了しました。場合によって変換されていないデータがあることもあります。';
$lang->msg_sync_completed = '会員情報、書き込みデータ、コメントのデータの同期化(変換)が完了しました。';
// Bla, Blah..
$lang->about_type_member = 'データ変換の対象が会員情報の場合は選択してください。';
$lang->about_type_module = 'データ変換の対象が書き込みデータである場合は選択してください。';
$lang->about_type_syncmember = '会員情報と書き込みデータなどの変換を行った後、会員情報を同期化する必要がある場合は、選択してください。';
$lang->about_importer = "ゼロボード4、zb5betaまたは他のプログラムの書き込みデータをゼロボードXEのデータに変換することができます。\n変換するためには、<a href=\"#\" onclick=\"winopen('');return false;\">XML Exporter</a>を利用して変換したい書き込みデータをXMLファイルで作成してアップロードしてください。";
$lang->about_target_path = "첨부파일을 받기 위해 제로보드4가 설치된 위치를 입력해주세요.\n같은 서버에 있을 경우 /home/아이디/public_html/bbs 등과 같이 제로보드4의 위치를 입력하시고\n다른 서버일 경우 http://도메인/bbs 처럼 제로보드가 설치된 곳의 url을 입력해주세요";
?>

View file

@ -0,0 +1,52 @@
<?php
/**
* @file ko.lang.php
* @author zero (zero@nzeo.com)
* @brief Importer(importer) 모듈의 기본 언어팩
**/
// 버튼에 사용되는 언어
$lang->cmd_sync_member = '동기화';
$lang->cmd_continue = '계속진행';
// 항목
$lang->importer = '제로보드 데이터 이전';
$lang->source_type = '이전 대상';
$lang->type_member = '회원 정보';
$lang->type_module = '게시물 정보';
$lang->type_syncmember = '회원정보 동기화';
$lang->target_module = '대상 모듈';
$lang->xml_file = 'XML 파일';
$lang->import_step_title = array(
1 => 'Step 1. 이전 대상 선택',
12 => 'Step 1-2. 대상 모듈 선택',
13 => 'Step 1-3. 대상 분류 선택',
2 => 'Step 2. XML파일 지정',
3 => 'Step 2. 회원정보와 게시물의 정보 동기화',
);
$lang->import_step_desc = array(
1 => '이전을 하려는 XML파일의 종류를 선택해주세요.',
12 => '데이터 이전을 할 대상 모듈을 선택해주세요.',
13 => '데이터 이전을 할 대상 분류를 선택해주세요.',
2 => "데이터 이전을 할 XML파일의 경로를 입력해주세요.\n상대 또는 절대 경로를 입력하시면 됩니다",
3 => '회원정보와 게시물의 정보가 이전후에 맞지 않을 수 있습니다. 이 때 동기화를 하시면 user_id를 기반으로 올바르게 동작하도록 합니다.',
);
// 안내/경고
$lang->msg_sync_member = '동기화 버튼을 클릭하시면 회원정보와 게시물정보의 동기화를 시작합니다.';
$lang->msg_no_xml_file = 'XML파일을 찾을 수 없습니다. 경로를 다시 확인해주세요';
$lang->msg_invalid_xml_file = '잘못된 형식의 XML파일입니다';
$lang->msg_importing = '%d개의 데이터중 %d개를 입력중입니다. (계속 멈추어 있으면 "계속진행" 버튼을 클릭해주세요)';
$lang->msg_import_finished = '%d개의 데이터 입력이 완료되었습니다. 상황에 따라 입력되지 못한 데이터가 있을 수 있습니다.';
$lang->msg_sync_completed = '회원과 게시물, 댓글의 동기화가 완료되었습니다.';
// 주절 주절..
$lang->about_type_member = '데이터 이전 대상이 회원정보일 경우 선택해주세요';
$lang->about_type_module = '데이터 이전 대상이 게시판등의 게시물 정보일 경우 선택해주세요';
$lang->about_type_syncmember = '회원정보와 게시물정보등을 이전후 회원정보 동기화 해야 할때 선택해주세요';
$lang->about_importer = "제로보드4, zb5beta 또는 다른 프로그램의 데이터를 제로보드XE 데이터로 이전할 수 있습니다.\n이전을 위해서는 <a href=\"#\" onclick=\"winopen('');return false;\">XML Exporter</a>를 이용해서 원하는 데이터를 XML파일로 생성후 업로드해주셔야 합니다.";
$lang->about_target_path = "첨부파일을 받기 위해 제로보드4가 설치된 위치를 입력해주세요.\n같은 서버에 있을 경우 /home/아이디/public_html/bbs 등과 같이 제로보드4의 위치를 입력하시고\n다른 서버일 경우 http://도메인/bbs 처럼 제로보드가 설치된 곳의 url을 입력해주세요";
?>

View file

@ -0,0 +1,52 @@
<?php
/**
* @file zh-CN.lang.php
* @author zero (zero@nzeo.com)
* @brief Importer(importer) 模块语言包
**/
// 按钮上使用的语言
$lang->cmd_sync_member = '同步';
$lang->cmd_continue = '继续进行';
// 项目
$lang->importer = '数据导入';
$lang->source_type = '导入对象';
$lang->type_member = '会员信息';
$lang->type_module = '版面信息';
$lang->type_syncmember = '同步会员信息';
$lang->target_module = '模块对象';
$lang->xml_file = 'XML文件';
$lang->import_step_title = array(
1 => 'Step 1. 选择导入对象',
12 => 'Step 1-2. 选择模块对象',
13 => 'Step 1-3. 选择对象分类',
2 => 'Step 2. 上传XML文件',
3 => 'Step 2. 同步会员信息和文章信息',
);
$lang->import_step_desc = array(
1 => '请选择要导入的XML文件种类。',
12 => '请选择要导入的对象模块。',
13 => '请选择要导入的对象分类。',
2 => "请输入要导入的XML文件的位置。\n位于同一个服务器时可输入相对或绝对路径位于不同服务器时可输入http://地址。",
3 => '数据导入后可能会导致会员信息和文章内容信息的误差。这时以user_id进行同步即可解决问题。',
);
// 信息/提示
$lang->msg_sync_member = '按同步按钮即可开始对会员信息和文章信息进行同步。';
$lang->msg_no_xml_file = '找不到XML文件请重新确认路径。';
$lang->msg_invalid_xml_file = '错误形式的XML文件';
$lang->msg_importing = '%d个的数据中正在输入 %d个。 (长时间没有响应时请按“继续进行”按钮)';
$lang->msg_import_finished = '已完成输入%d个数据。根据情况的不同可能有没有被导入的数据。';
$lang->msg_sync_completed = '已完成会员和文章,评论的同步。';
// 说明
$lang->about_type_member = '数据导入对象为会员信息时请选择';
$lang->about_type_module = '数据导入对象是版面主题时请选择';
$lang->about_type_syncmember = '会员信息和文章信息导入后需要同步会员信息时请选择。';
$lang->about_importer = "不仅可以导入Zeroboard 4Zb5beta的数据,也可以把其他程序数据导入到Zeroboard XE当中。\n导入数据时请利用 <a href=\"#\" onclick=\"winopen('');return false;\">XML Exporter</a>生成XML文件后再上传。";
$lang->about_target_path = "为了下载附件请输入Zeroboard 4的安装位置。\n位置在同一个服务器时,请输入如 /home/id/public_html/bbs的路径,在不同服务器时,请输入如 http://域名/bbs的url地址。";
?>

View file

@ -0,0 +1,12 @@
<query id="updateCommentSync" action="update">
<tables>
<table name="comments" alias="comments" />
<table name="member" alias="member" />
</tables>
<columns>
<column name="comments.member_srl" default="member.member_srl" filter="number" />
</columns>
<conditions>
<condition operation="equal" column="comments.user_id" default="member.user_id" />
</conditions>
</query>

View file

@ -0,0 +1,12 @@
<query id="updateDocumentSync" action="update">
<tables>
<table name="documents" alias="documents" />
<table name="member" alias="member" />
</tables>
<columns>
<column name="documents.member_srl" default="member.member_srl" filter="number" />
</columns>
<conditions>
<condition operation="equal" column="documents.user_id" default="member.user_id" />
</conditions>
</query>

View file

@ -0,0 +1,3 @@
@charset "utf-8";
#step2_position { height:150px; overflow-y:scroll; border:2px solid #DDDDDD; }

View file

@ -0,0 +1,14 @@
<filter name="import_xml" module="importer" act="procImporterAdminImport">
<form>
<node target="xml_file" required="true" />
</form>
<parameter />
<response callback_func="completeImport">
<tag name="error" />
<tag name="message" />
<tag name="is_finished" />
<tag name="position" />
<tag name="file_point" />
<tag name="total_count" />
</response>
</filter>

View file

@ -0,0 +1,12 @@
<filter name="step1" module="importer" act="procImporterAdminStep1">
<form>
<node target="source_type" required="true" filter="alpha" />
</form>
<parameter />
<response callback_func="completeStep1">
<tag name="error" />
<tag name="message" />
<tag name="next_step" />
<tag name="module_list" />
</response>
</filter>

View file

@ -0,0 +1,13 @@
<filter name="step12" module="importer" act="procImporterAdminStep12">
<form>
<node target="target_module" required="true" />
<node target="target_path" required="true" />
</form>
<parameter />
<response callback_func="completeStep12">
<tag name="error" />
<tag name="message" />
<tag name="next_step" />
<tag name="category_list" />
</response>
</filter>

View file

@ -0,0 +1,136 @@
<!--%import("js/importer_admin.js")-->
<!--%import("css/importer.js")-->
<!--%import("filter/step1.xml")-->
<!--%import("filter/step12.xml")-->
<!--%import("filter/import_xml.xml")-->
<h3>{$lang->importer} <span class="gray">{$lang->cmd_management}</span></h3>
<!-- 설명 -->
<div class="infoText">{nl2br($lang->about_importer)}</div>
<!-- step 1. import하려는 XML파일의 성격 및 대상 모듈을 지정 -->
<div id="step1">
<form action="./" method="get" onsubmit="return procFilter(this, step1);">
<div class="title" >{$lang->import_step_title[1]}</div>
<div class="desc">{$lang->import_step_desc[1]}</div>
<table cellspacing="0" class="tableType3 gap1">
<tr>
<th scope="col"><label for="source_type_module">{$lang->type_module}</label></th>
<td class="left"><input type="radio" name="source_type" value="module" id="source_type_module" /> {$lang->about_type_module}</td>
</tr>
<tr>
<th scope="col"><label for="source_type_member">{$lang->type_member}</label></th>
<td class="left"><input type="radio" name="source_type" value="member" id="source_type_member" /> {$lang->about_type_member}</td>
</tr>
<tr>
<th scope="col"><label for="source_type_syncmember">{$lang->type_syncmember}</label></th>
<td class="left"><input type="radio" name="source_type" value="syncmember" id="source_type_syncmember" /> {$lang->about_type_syncmember}</td>
</tr>
</table>
<div class="tRight gap1">
<span class="button"><input type="submit" value="{$lang->cmd_next}" /></span>
</div>
</form>
</div>
<!-- step 1-2. 대상이 게시물 정보일 경우 대상 모듈 목록을 선택하도록 함 -->
<div id="step12" style="display:none">
<form action="./" method="get" onsubmit="return procFilter(this, step12);">
<div class="title">{$lang->import_step_title[12]}</div>
<div class="desc">{$lang->import_step_desc[12]}</div>
<div>
<select name="target_module" id="target_module">
</select>
</div>
<br />
<div class="desc">{nl2br($lang->about_target_path)}</div>
<div>
Path/URL : <input type="text" name="target_path" id="target_path" class="inputTypeText w400" />
</div>
<div class="tRight gap1">
<span class="button"><input type="submit" value="{$lang->cmd_next}" /></span>
</div>
</form>
</div>
<!-- step 1-3. 대상이 게시물 정보일 경우 모듈 선택후 분류가 있으면 분류 선택을 하도록 함 -->
<div id="step13" style="display:none">
<form action="./" method="get" onsubmit="return doStep13(this)">
<div class="title">{$lang->import_step_title[13]}</div>
<div class="desc">{$lang->import_step_desc[13]}</div>
<div>
<select name="target_category" id="target_category">
<option value=""></option>
</select>
</div>
<div class="tRight gap1">
<span class="button"><input type="submit" value="{$lang->cmd_next}" /></span>
</div>
</form>
</div>
<!-- step 2. XML 파일 지정 -->
<div id="step2" style="display:none">
<form action="./" method="get" onsubmit="return doStep2(this)" id="fo_step2">
<input type="hidden" name="module_srl" value="" />
<input type="hidden" name="target_path" value="" />
<input type="hidden" name="category_srl" value="" />
<input type="hidden" name="position" value="0" />
<input type="hidden" name="file_point" value="0" />
<input type="hidden" name="total_count" value="0" />
<div class="title">{$lang->import_step_title[2]}</div>
<div class="desc">{$lang->import_step_desc[2]}</div>
<table cellspacing="0" class="tableType4 gap1">
<tr>
<td class="left">
<input type="text" name="xml_file" value="./" class="inputTypeText w100" />
</td>
</tr>
</table>
<div class="tRight gap1">
<span class="button"><input type="submit" value="{$lang->cmd_next}" /></span>
</div>
<div id="step2_status" style="display:none;" class="gap1">
<table border="0" cellspacing="0" cellpadding="0" width="100%" style="margin-bottom:10px;">
<col />
<col width="120" />
<tr>
<td><div id="bar" style="width:1px;height:10px;background-color:#EFEFEF;border:1px solid #888888"></div></td>
<td class="tRight"><span id="bar_status"></span>
</tr>
</table>
<div id="step2_position" style="height:100px;overflow-y:scroll;border:2px solid #DDDDDD;padding:10px;" class="desc"></div>
<div class="tRight gap1">
<span class="button"><input type="button" value="{$lang->cmd_continue}" onclick="doManualProcess(); return false" /></span>
</div>
</div>
</form>
</div>
<!-- step 3. 회원 동기화 시작 버튼 -->
<div id="step3" style="display:none">
<form action="./" method="get" onsubmit="return doStep3(this)">
<div class="title">{$lang->import_step_title[3]}</div>
<div class="desc">{$lang->import_step_desc[3]}<br />{$lang->msg_sync_member}</div>
<div class="tRight gap1">
<span class="button"><input type="submit" value="{$lang->cmd_sync_member}" /></span>
</div>
</form>
</div>
<!-- final step. 진행 완료 또는 실패 메세지 -->
<div id="step_finish" style="display:none;"></div>

View file

@ -0,0 +1,137 @@
/**
* @file modules/importer/js/importer_admin.js
* @author zero (zero@nzeo.com)
* @brief importer에서 사용하는 javascript
**/
/* Step 1 처리 */
function completeStep1(ret_obj) {
var error = ret_obj['error'];
var message = ret_obj['message'];
var next_step = ret_obj['next_step'];
var module_list = ret_obj['module_list'];
if(module_list) {
var sel = xGetElementById("target_module");
var module_list_arr = module_list.split("\n");
for(var i=0;i<module_list_arr.length;i++) {
var pos = module_list_arr[i].indexOf(',');
var value = module_list_arr[i].substr(0,pos);
var text = module_list_arr[i].substr(pos+1);
var opt_obj = new Option(text, value, true, true);
sel.options[sel.options.length] = opt_obj;
}
sel.selectedIndex = 0;
}
xGetElementById('step1').style.display = 'none';
xGetElementById('step'+next_step).style.display = 'block';
}
/* Step 1-2 모듈선택 처리 (카테고리 있으면 카테고리 선택으로, 아니면 바로 파일 업로드로) */
function completeStep12(ret_obj) {
var error = ret_obj['error'];
var message = ret_obj['message'];
var next_step = ret_obj['next_step'];
var category_list = ret_obj['category_list'];
if(category_list) {
var sel = xGetElementById("target_category");
var category_list_arr = category_list.split("\n");
for(var i=0;i<category_list_arr.length;i++) {
var pos = category_list_arr[i].indexOf(',');
var value = category_list_arr[i].substr(0,pos);
var text = category_list_arr[i].substr(pos+1);
var opt_obj = new Option(text, value, true, true);
sel.options[sel.options.length] = opt_obj;
}
sel.selectedIndex = 0;
}
xGetElementById('step12').style.display = 'none';
xGetElementById('step'+next_step).style.display = 'block';
}
/* Step 1-3 카테고리 선택후 파일 업로드 보여주기 */
function doStep13(fo_obj) {
xGetElementById('step13').style.display = 'none';
xGetElementById('step2').style.display = 'block';
return false;
}
/* Step 2 XML파일을 입력받아서 처리~ */
function doStep2(fo_obj) {
var sel_module = xGetElementById("target_module");
if(sel_module.options.length>0) {
var module_srl = sel_module.options[sel_module.selectedIndex].value;
fo_obj.module_srl.value = module_srl;
}
var sel_category = xGetElementById("target_category");
if(sel_category.options.length>1) {
var category_srl = sel_category.options[sel_category.selectedIndex].value;
fo_obj.category_srl.value = category_srl;
}
var target_path = xGetElementById("target_path").value;
fo_obj.target_path.value = target_path;
procFilter(fo_obj, import_xml);
xGetElementById('step2_status').style.display = 'block';
return false;
}
/* Step Complete Import */
function completeImport(ret_obj) {
var message = ret_obj['message'];
var is_finished = ret_obj['is_finished'];
var position = ret_obj['position'];
var file_point = ret_obj['file_point'];
var total_count = ret_obj['total_count'];
if(total_count>0) {
var bar = xGetElementById('bar');
var status = xGetElementById('bar_status');
var per = parseInt(position/total_count*100,10)
xInnerHtml(status, position+'/'+total_count+' ('+per+'%)');
bar.style.width = per+'%';
}
if(is_finished=='Y') {
alert(ret_obj["message"]);
location.href = location.href;
} else {
var fo_obj = xGetElementById('fo_step2');
fo_obj.position.value = position;
fo_obj.file_point.value = file_point;
fo_obj.total_count.value = total_count;
message = message.replace(/&lt;/g,"<").replace(/&gt;/g,">");
var obj = xGetElementById('step2_position');
var txt = xInnerHtml(obj);
if(txt.length > 1024*10) txt = '';
if(message != "success") xInnerHtml(obj, txt+message);
obj.scrollTop += xHeight(obj);
procFilter(fo_obj, import_xml);
}
}
function doManualProcess() {
var fo_obj = xGetElementById('fo_step2');
procFilter(fo_obj, import_xml);
}
/* 회원정보와 게시물의 싱크 */
function doStep3(fo_obj) {
exec_xml('importer','procImporterAdminSync', new Array(), completeStep3);
return false;
}
function completeStep3(ret_obj) {
alert(ret_obj['message']);
location.href=location.href;
}