/** * 생성자. */ public function __construct() { if (self::$config === null) { self::$config = $this->getConfig(); } if (self::$reqid === null) { $random_seed = $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] . $_SERVER['REQUEST_URI'] . mt_rand() . mt_rand(); self::$reqid = date('YmdHis', time() + zgap()) . '-' . substr(base64_encode(sha1($random_seed, true)), 0, 25); } }
/** * 일정 기간 이상 지난 에러 기록을 삭제하는 메소드. */ public function procErrorLoggerAdminClearList($threshold = null) { // 정리 설정을 가져온다. if ($threshold === null) { $request_vars = Context::getRequestVars(); $threshold = intval($request_vars->clear_threshold); } // 정리한다. if ($threshold >= 0) { $obj = new stdClass(); $obj->threshold = date('YmdHis', time() - $threshold * 86400 + zgap()); $output = executeQuery('errorlogger.deleteErrorLog', $obj); } // 목록 페이지로 돌려보낸다. $this->setRedirectUrl(getNotEncodedUrl('', 'module', 'admin', 'act', 'dispErrorloggerAdminList')); return; }
/** * 정리대상 회원 목록을 표시하는 메소드. */ public function dispMember_ExpireAdminListTargets() { // 현재 설정을 불러온다. $config = $this->getConfig(); Context::set('mex_config', $config); // 검색 조건을 불러온다. $search_target = Context::get('search_target'); $search_keyword = Context::get('search_keyword'); if (!in_array($search_target, array('email_address', 'user_id', 'user_name', 'nick_name')) || !$search_keyword) { Context::set('search_target', $search_target = null); Context::set('search_keyword', $search_keyword = null); } // 휴면계정 목록을 불러온다. $obj = new stdClass(); if ($search_target && $search_keyword) { $obj->{$search_target} = trim($search_keyword); } $obj->threshold = date('YmdHis', time() - $config->expire_threshold * 86400 + zgap()); $expired_members_count = executeQuery('member_expire.countExpiredMembers', $obj); $expired_members_count = $expired_members_count->toBool() ? $expired_members_count->data->count : 0; $obj->page = $page = Context::get('page') ? Context::get('page') : 1; $obj->orderby = 'desc'; $expired_members = executeQuery('member_expire.getExpiredMembers', $obj); $expired_members = $expired_members->toBool() ? $expired_members->data : array(); Context::set('expire_threshold', $this->translateThreshold($config->expire_threshold)); Context::set('expired_members_count', $expired_members_count); Context::set('expired_members', $expired_members); // 페이징을 처리한다. $paging = new Object(); $paging->total_count = $expired_members_count; $paging->total_page = max(1, ceil($expired_members_count / 10)); $paging->page = $page; $paging->page_navigation = new PageHandler($paging->total_count, $paging->total_page, $page, 10); Context::set('paging', $paging); Context::set('page', $page); // 템플릿을 지정한다. Context::setBrowserTitle('정리대상 회원 목록 - XE Admin'); $this->setTemplatePath($this->module_path . 'tpl'); $this->setTemplateFile('list_targets'); }
/** * Execute finding ID/Passoword * When clicking the link in the verification email, a method is called to change the old password and to authenticate it * * @return void|Object (void : success, Object : fail) */ function procMemberAuthAccount() { $oMemberModel = getModel('member'); // Test user_id and authkey $member_srl = Context::get('member_srl'); $auth_key = Context::get('auth_key'); if (!$member_srl || !$auth_key) { return $this->stop('msg_invalid_request'); } // Test logs for finding password by user_id and authkey $args = new stdClass(); $args->member_srl = $member_srl; $args->auth_key = $auth_key; $output = executeQuery('member.getAuthMail', $args); if (!$output->toBool() || $output->data->auth_key != $auth_key) { if (strlen($output->data->auth_key) !== strlen($auth_key)) { executeQuery('member.deleteAuthMail', $args); } return $this->stop('msg_invalid_auth_key'); } if (ztime($output->data->regdate) < $_SERVER['REQUEST_TIME'] + zgap() - 86400) { executeQuery('member.deleteAuthMail', $args); return $this->stop('msg_invalid_auth_key'); } $args->password = $output->data->new_password; // If credentials are correct, change the password to a new one if ($output->data->is_register == 'Y') { $args->denied = 'N'; } else { $args->password = $oMemberModel->hashPassword($args->password); } // Back up the value of $Output->data->is_register $is_register = $output->data->is_register; $output = executeQuery('member.updateMemberPassword', $args); if (!$output->toBool()) { return $this->stop($output->getMessage()); } // Remove all values having the member_srl from authentication table executeQuery('member.deleteAuthMail', $args); $this->_clearMemberCache($args->member_srl); // Notify the result Context::set('is_register', $is_register); $this->setTemplatePath($this->module_path . 'tpl'); $this->setTemplateFile('msg_success_authed'); }
/** * If the recent post within a day, output format of YmdHis is "min/hours ago from now". If not within a day, it return format string. * * @param string $date Time value in format of YYYYMMDDHHIISS * @param string $format If gap is within a day, returns this format. * @return string */ function getTimeGap($date, $format = 'Y.m.d') { $gap = $_SERVER['REQUEST_TIME'] + zgap() - ztime($date); $lang_time_gap = Context::getLang('time_gap'); if ($gap < 60) { $buff = sprintf($lang_time_gap['min'], (int) ($gap / 60) + 1); } elseif ($gap < 60 * 60) { $buff = sprintf($lang_time_gap['mins'], (int) ($gap / 60) + 1); } elseif ($gap < 60 * 60 * 2) { $buff = sprintf($lang_time_gap['hour'], (int) ($gap / 60 / 60) + 1); } elseif ($gap < 60 * 60 * 24) { $buff = sprintf($lang_time_gap['hours'], (int) ($gap / 60 / 60) + 1); } else { $buff = zdate($date, $format); } return $buff; }
/** * 개별 휴면계정 또는 주어진 갯수만큼의 휴면계정을 정리하는 메소드. */ public function procMember_ExpireAdminDoCleanup() { // 정리 설정을 가져온다. $config = $this->getConfig(); $request_vars = Context::getRequestVars(); $member_srl = $request_vars->member_srl ? $request_vars->member_srl : 0; $threshold = $request_vars->threshold ? $request_vars->threshold : $config->expire_threshold; $method = $request_vars->method ? $request_vars->method : $config->expire_method; $total_count = $request_vars->total_count ? $request_vars->total_count : 10; $batch_count = $request_vars->batch_count ? $request_vars->batch_count : 10; $done_count = 0; // 트랜잭션을 시작한다. $oDB = DB::getInstance(); $oDB->begin(); // 모델을 불러온다. $oModel = getModel('member_expire'); // 정리 방법에 따라 처리한다. switch ($method) { // 삭제. case 'delete': // 정리 대상 member_srl들을 불러온다. if ($member_srl) { $member_srls = array($member_srl); } else { $args = new stdClass(); $args->threshold = date('YmdHis', time() - $threshold * 86400 + zgap()); $args->list_count = $batch_count; $args->page = 1; $args->orderby = 'asc'; $member_srls_query = executeQuery('member_expire.getExpiredMemberSrlOnly', $args); if (!$member_srls_query->toBool()) { $oDB->rollback(); $this->add('count', -1); return; } $member_srls = array(); foreach ($member_srls_query->data as $member_srls_item) { $member_srls[] = $member_srls_item->member_srl; } } // 각각의 member_srl 및 관련정보를 삭제한다. foreach ($member_srls as $member_srl) { $result = $oModel->deleteMember($member_srl, true, false); if ($result < 0) { $oDB->rollback(); $this->add('count', $result); return; } $done_count++; } break; // 이동. // 이동. case 'move': // 정리 대상 회원정보 전체를 불러온다. if ($member_srl) { $args = new stdClass(); $args->member_srl = $member_srl; $members_query = executeQuery('member.getMemberInfoByMemberSrl', $args); if (!$members_query->toBool()) { $oDB->rollback(); $this->add('count', -5); return; } $members = $members_query->data ? $members_query->data : array(); if (is_object($members)) { $members = array($members); } } else { $args = new stdClass(); $args->threshold = date('YmdHis', time() - $threshold * 86400 + zgap()); $args->list_count = $batch_count; $args->page = 1; $args->orderby = 'asc'; $members_query = executeQuery('member_expire.getExpiredMembers', $args); if (!$members_query->toBool()) { $oDB->rollback(); $this->add('count', -6); return; } $members = $members_query->data ? $members_query->data : array(); } // 각 회원정보를 member_expired 테이블로 이동한다. foreach ($members as $member) { $result = $oModel->moveMember($member, true, false); if ($result < 0) { $oDB->rollback(); $this->add('count', $result); return; } $done_count++; } break; // 기타. // 기타. default: $done_count = -10; } // 트랜잭션을 커밋한다. $oDB->commit(); // 정리된 결과 수를 반환한다. $this->add('count', $done_count); return true; }
/** * 회원 로그인 및 로그아웃 트리거. * 실제 로그인 및 로그아웃과는 무관하고, 적당한 간격으로 자동 정리를 실행하는 데 쓰인다. * 이 트리거의 호출 빈도가 실제 회원수에 비례할 가능성이 높기 때문이다. */ public function triggerAutoExpire() { // 자동으로 처리할 일이 없다면 종료한다. $config = $this->getConfig(); $tasks = 0; if ($config->auto_expire !== 'Y' && $config->email_threshold <= 0) { return; } // 이번에 처리할 일을 결정한다. $expire_enabled = $config->auto_expire === 'Y' && time() > strtotime($config->auto_start) + zgap(); if ($expire_enabled && $config->email_threshold <= 0) { $task = 'expire'; } elseif (!$expire_enabled && $config->email_threshold > 0) { $task = 'notify'; } else { $task = mt_rand() % 2 ? 'expire' : 'notify'; } // 휴면계정을 자동 정리한다. if ($task === 'expire') { // 정리할 휴면계정이 있는지 확인한다. $obj = new stdClass(); $obj->threshold = date('YmdHis', time() - $config->expire_threshold * 86400 + zgap()); $obj->list_count = $obj->page_count = $obj->page = 1; $obj->orderby = 'asc'; $members_query = executeQuery('member_expire.getExpiredMembers', $obj); // 정리할 휴면계정이 있다면 지금 정리한다. if ($members_query->toBool() && count($members_query->data)) { $oDB = DB::getInstance(); $oDB->begin(); $oModel = getModel('member_expire'); foreach ($members_query->data as $member) { if ($config->expire_method === 'delete') { $oModel->deleteMember($member, true, false); } else { $oModel->moveMember($member, true, false); } } $oDB->commit(); } } // 휴면 안내메일을 자동 발송한다. if ($task === 'notify') { // 안내할 회원이 있는지 확인한다. $obj = new stdClass(); $obj->threshold = date('YmdHis', time() - $config->expire_threshold * 86400 + $config->email_threshold * 86400 + zgap()); $obj->list_count = $obj->page_count = $obj->page = 1; $obj->orderby = 'asc'; $members_query = executeQuery('member_expire.getUnnotifiedMembers', $obj); // 안내할 회원이 있다면 지금 안내메일을 발송한다. if ($members_query->toBool() && count($members_query->data)) { $oDB = DB::getInstance(); $oDB->begin(); $oModel = getModel('member_expire'); foreach ($members_query->data as $member) { $oModel->sendEmail($member, $config, false, false); } $oDB->commit(); } } }
/** * 휴면 안내메일을 발송하는 메소드. */ public function sendEmail($member_srl, $config = null, $resend = true, $use_transaction = true) { // 회원 오브젝트를 통째로 받은 경우 member_srl을 추출한다. if (is_object($member_srl) && isset($member_srl->member_srl)) { $member = $member_srl; $member_srl = $member_srl->member_srl; } else { $args = new stdClass(); $args->member_srl = $member_srl; $member_query = executeQuery('member.getMemberInfoByMemberSrl', $args); if (!$member_query->toBool() || !$member_query->data) { return -41; } $member = is_object($member_query->data) ? $member_query->data : reset($member_query->data); if (!$member) { return -42; } $member_srl = $member->member_srl; } // 모듈 설정이 로딩되지 않은 경우 지금 로딩한다. if (!$config) { $config = $this->getConfig(); } // 이미 발송한 경우, $resend = true가 아니라면 재발송하지 않는다. $args = new stdClass(); $args->member_srl = $member_srl; $output = executeQuery('member_expire.getNotifiedDates', $args); if (!$output->toBool()) { return -43; } if (count($output->data) && !$resend) { return 2; } // 정리 예정일을 계산한다. $start_date = strtotime($config->auto_start) + zgap(); $base_date = $member->last_login ? $member->last_login : $member->regdate; $base_date = $base_date ? ztime($base_date) : 0; $expire_date = $base_date + 86400 * $config->expire_threshold; if ($expire_date < $start_date) { $expire_date = $start_date; } $member->expire_date = date('YmdHis', $expire_date); // 매크로를 변환한다. $site_title = Context::getSiteTitle(); $macros = array('{SITE_NAME}' => htmlspecialchars($site_title, ENT_QUOTES, 'UTF-8', false), '{USER_ID}' => htmlspecialchars($member->user_id, ENT_QUOTES, 'UTF-8', false), '{USER_NAME}' => htmlspecialchars($member->user_name, ENT_QUOTES, 'UTF-8', false), '{NICK_NAME}' => htmlspecialchars($member->nick_name, ENT_QUOTES, 'UTF-8', false), '{EMAIL}' => htmlspecialchars($member->email_address, ENT_QUOTES, 'UTF-8', false), '{LOGIN_DATE}' => $base_date ? date('Y년 n월 j일', $base_date) : '(로그인 기록 없음)', '{EXPIRE_DATE}' => date('Y년 n월 j일', $expire_date), '{TIME_LIMIT}' => $this->translateThreshold($config->expire_threshold), '{CLEAN_METHOD}' => $config->expire_method === 'delete' ? '삭제' : '별도의 저장공간으로 이동'); // 메일을 작성하여 발송한다. $subject = htmlspecialchars_decode(str_replace(array_keys($macros), array_values($macros), $config->email_subject)); $content = str_replace(array_keys($macros), array_values($macros), $config->email_content); $recipient_name = $member->user_name ? $member->user_name : ($member->nick_name ? $member->nick_name : 'member'); static $sender_name = null; static $sender_email = null; if ($sender_name === null) { $member_config = getModel('module')->getModuleConfig('member'); $sender_name = $member_config->webmaster_name ? $member_config->webmaster_name : ($site_title ? $site_title : 'webmaster'); $sender_email = $member_config->webmaster_email; } $oMail = new Mail(); $oMail->setTitle($subject); $oMail->setContent($content); $oMail->setSender($sender_name, $sender_email); $oMail->setReceiptor($recipient_name, $member->email_address); $oMail->send(); // 트랜잭션을 시작한다. if ($use_transaction) { $this->oDB->begin(); } // 발송한 메일을 기록한다. $output = executeQuery('member_expire.deleteNotifiedDate', $member); if (!$output->toBool()) { if ($use_transaction) { $this->oDB->rollback(); } return -44; } $output = executeQuery('member_expire.insertNotifiedDate', $member); if (!$output->toBool()) { if ($use_transaction) { $this->oDB->rollback(); } return -45; } // 트랜잭션을 커밋한다. if ($use_transaction) { $this->oDB->commit(); } return 1; }
/** * @brief Reformatting date data from Lifepod API into data type compatible to Lifepod UI **/ function dateFormatChange($dates, $plus = 0) { $dates = sprintf("%s-%s-%s %s:%s:%s+0", substr($dates, 0, 4), substr($dates, 4, 2), substr($dates, 6, 2), substr($dates, 9, 2), substr($dates, 11, 2), substr($dates, 13, 2)); $dates = date("Y-m-d H:i:s", strtotime($dates) + $plus + zgap()); return $dates; }
/** * Clear old sending log. */ public function procAdvanced_mailerAdminClearSentMail() { $status = Context::get('status'); $clear_before_days = intval(Context::get('clear_before_days')); if (!in_array($status, array('success', 'error'))) { return new Object(-1, 'msg_invalid_request'); } if ($clear_before_days < 0) { return new Object(-1, 'msg_invalid_request'); } $obj = new stdClass(); $obj->status = $status; $obj->regdate = date('YmdHis', time() - $clear_before_days * 86400 + zgap()); $output = executeQuery('advanced_mailer.deleteLogs', $obj); if ($status === 'success') { $this->setRedirectUrl(getNotEncodedUrl('', 'module', 'admin', 'act', 'dispAdvanced_mailerAdminSentMail')); } else { $this->setRedirectUrl(getNotEncodedUrl('', 'module', 'admin', 'act', 'dispAdvanced_mailerAdminErrors')); } }
/** * @brief YYYYMMDDHHIISS 형식의 시간값을 unix time으로 변경 * @param str YYYYMMDDHHIISS 형식의 시간값 * @return int **/ function ztime($str) { if (!$str) { return; } $hour = (int) substr($str, 8, 2); $min = (int) substr($str, 10, 2); $sec = (int) substr($str, 12, 2); $year = (int) substr($str, 0, 4); $month = (int) substr($str, 4, 2); $day = (int) substr($str, 6, 2); if (strlen($str) <= 8) { $gap = 0; } else { $gap = zgap(); } return mktime($hour, $min, $sec, $month ? $month : 1, $day ? $day : 1, $year) + $gap; }