서버 커스터마이징 가능

This commit is contained in:
2020-06-21 17:03:32 +09:00
parent 929d2db5a5
commit 0ec99d8ba1
16 changed files with 2815 additions and 2792 deletions
+313 -305
View File
@@ -1,305 +1,313 @@
<?php <?php
namespace sammo; namespace sammo;
require(__DIR__ . '/../vendor/autoload.php'); require(__DIR__ . '/../vendor/autoload.php');
$host = Util::getPost('db_host'); $host = Util::getPost('db_host');
$port = Util::getPost('db_port', 'int'); $port = Util::getPost('db_port', 'int');
$username = Util::getPost('db_id'); $username = Util::getPost('db_id');
$password = Util::getPost('db_pw'); $password = Util::getPost('db_pw');
$dbName = Util::getPost('db_name'); $dbName = Util::getPost('db_name');
$servHost = Util::getPost('serv_host'); $servHost = Util::getPost('serv_host');
$sharedIconPath = Util::getPost('shared_icon_path'); $sharedIconPath = Util::getPost('shared_icon_path');
$gameImagePath = Util::getPost('game_image_path'); $gameImagePath = Util::getPost('game_image_path');
$imageRequestKey = Util::getPost('image_request_key'); $imageRequestKey = Util::getPost('image_request_key');
$kakaoRESTKey = Util::getPost('kakao_rest_key', 'string', ''); $kakaoRESTKey = Util::getPost('kakao_rest_key', 'string', '');
$kakaoAdminKey = Util::getPost('kakao_admin_key', 'string', ''); $kakaoAdminKey = Util::getPost('kakao_admin_key', 'string', '');
if (!$host || !$port || !$username || !$password || !$dbName || !$servHost || !$sharedIconPath || !$gameImagePath) { if (!$host || !$port || !$username || !$password || !$dbName || !$servHost || !$sharedIconPath || !$gameImagePath) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => '입력 값이 올바르지 않습니다' 'reason' => '입력 값이 올바르지 않습니다'
]); ]);
} }
if (!filter_var($servHost, FILTER_VALIDATE_URL)) { if (!filter_var($servHost, FILTER_VALIDATE_URL)) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => '접속 경로가 올바르지 않습니다.' 'reason' => '접속 경로가 올바르지 않습니다.'
]); ]);
} }
if (file_exists(ROOT . '/d_setting/RootDB.php') && is_dir(ROOT . '/d_setting/RootDB.php')) { if (file_exists(ROOT . '/d_setting/RootDB.php') && is_dir(ROOT . '/d_setting/RootDB.php')) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => 'd_setting/RootDB.php 가 디렉토리입니다' 'reason' => 'd_setting/RootDB.php 가 디렉토리입니다'
]); ]);
} }
if (class_exists('\\sammo\\RootDB')) { if (class_exists('\\sammo\\RootDB')) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => '이미 RootDB.php 파일이 있습니다' 'reason' => '이미 RootDB.php 파일이 있습니다'
]); ]);
} }
//파일 권한 검사 //파일 권한 검사
if (file_exists(AppConf::getUserIconPathFS()) && !is_dir(AppConf::getUserIconPathFS())) { if (file_exists(AppConf::getUserIconPathFS()) && !is_dir(AppConf::getUserIconPathFS())) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => AppConf::$userIconPath . ' 이 디렉토리가 아닙니다' 'reason' => AppConf::$userIconPath . ' 이 디렉토리가 아닙니다'
]); ]);
} }
if (file_exists(ROOT . '/d_log') && !is_dir(ROOT . '/d_log')) { if (file_exists(ROOT . '/d_log') && !is_dir(ROOT . '/d_log')) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => 'd_log 가 디렉토리가 아닙니다' 'reason' => 'd_log 가 디렉토리가 아닙니다'
]); ]);
} }
if (file_exists(ROOT . '/d_shared') && !is_dir(ROOT . '/d_shared')) { if (file_exists(ROOT . '/d_shared') && !is_dir(ROOT . '/d_shared')) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => 'd_shared 가 디렉토리가 아닙니다' 'reason' => 'd_shared 가 디렉토리가 아닙니다'
]); ]);
} }
if (file_exists(ROOT . '/d_setting') && !is_dir(ROOT . '/d_setting')) { if (file_exists(ROOT . '/d_setting') && !is_dir(ROOT . '/d_setting')) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => 'd_shared 가 디렉토리가 아닙니다' 'reason' => 'd_shared 가 디렉토리가 아닙니다'
]); ]);
} }
if ( if (
!file_exists(ROOT . '/d_log') !file_exists(ROOT . '/d_log')
|| !file_exists(ROOT . '/d_shared') || !file_exists(ROOT . '/d_shared')
|| !file_exists(ROOT . '/d_setting') || !file_exists(ROOT . '/d_setting')
|| !file_exists(AppConf::getUserIconPathFS()) || !file_exists(AppConf::getUserIconPathFS())
) { ) {
if (!is_writable(ROOT)) { if (!is_writable(ROOT)) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => '하위 디렉토리 생성 권한이 없습니다' 'reason' => '하위 디렉토리 생성 권한이 없습니다'
]); ]);
} }
//기본 파일 생성 //기본 파일 생성
if (!file_exists(AppConf::getUserIconPathFS())) { if (!file_exists(AppConf::getUserIconPathFS())) {
mkdir(AppConf::getUserIconPathFS()); mkdir(AppConf::getUserIconPathFS());
} }
if (!file_exists(ROOT . '/d_log')) { if (!file_exists(ROOT . '/d_log')) {
mkdir(ROOT . '/d_log'); mkdir(ROOT . '/d_log');
} }
if (!file_exists(ROOT . '/d_setting')) { if (!file_exists(ROOT . '/d_setting')) {
mkdir(ROOT . '/d_setting'); mkdir(ROOT . '/d_setting');
} }
if (!file_exists(ROOT . '/d_shared')) { if (!file_exists(ROOT . '/d_shared')) {
mkdir(ROOT . '/d_shared'); mkdir(ROOT . '/d_shared');
} }
} }
if (!is_writable(AppConf::getUserIconPathFS())) { if (!is_writable(AppConf::getUserIconPathFS())) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => AppConf::$userIconPath . ' 디렉토리의 쓰기 권한이 없습니다' 'reason' => AppConf::$userIconPath . ' 디렉토리의 쓰기 권한이 없습니다'
]); ]);
} }
if (!is_writable(ROOT . '/d_log')) { if (!is_writable(ROOT . '/d_log')) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => 'd_log 디렉토리의 쓰기 권한이 없습니다' 'reason' => 'd_log 디렉토리의 쓰기 권한이 없습니다'
]); ]);
} }
if (!is_writable(ROOT . '/d_shared')) { if (!is_writable(ROOT . '/d_shared')) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => 'd_shared 디렉토리의 쓰기 권한이 없습니다' 'reason' => 'd_shared 디렉토리의 쓰기 권한이 없습니다'
]); ]);
} }
if (!is_writable(ROOT . '/d_setting')) { if (!is_writable(ROOT . '/d_setting')) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => 'd_setting 디렉토리의 쓰기 권한이 없습니다.' 'reason' => 'd_setting 디렉토리의 쓰기 권한이 없습니다.'
]); ]);
} }
if (!file_exists(ROOT . '/d_log/.htaccess')) { if (!file_exists(ROOT . '/d_log/.htaccess')) {
@file_put_contents(ROOT . '/d_log/.htaccess', 'Deny from all'); @file_put_contents(ROOT . '/d_log/.htaccess', 'Deny from all');
} }
if (!file_exists(ROOT . '/d_setting/.htaccess')) { if (!file_exists(ROOT . '/d_setting/.htaccess')) {
@file_put_contents(ROOT . '/d_setting/.htaccess', 'Deny from all'); @file_put_contents(ROOT . '/d_setting/.htaccess', 'Deny from all');
} }
//DB 접근 권한 검사 //DB 접근 권한 검사
$rootDB = new \MeekroDB($host, $username, $password, $dbName, $port, 'utf8mb4'); $rootDB = new \MeekroDB($host, $username, $password, $dbName, $port, 'utf8mb4');
$rootDB->connect_options[MYSQLI_OPT_INT_AND_FLOAT_NATIVE] = true; $rootDB->connect_options[MYSQLI_OPT_INT_AND_FLOAT_NATIVE] = true;
$rootDB->throw_exception_on_nonsql_error = false; $rootDB->throw_exception_on_nonsql_error = false;
$rootDB->nonsql_error_handler = function ($params) { $rootDB->nonsql_error_handler = function ($params) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => 'DB 접속에 실패했습니다.' 'reason' => 'DB 접속에 실패했습니다.'
]); ]);
}; };
$rootDB->error_handler = function ($params) { $rootDB->error_handler = function ($params) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => 'SQL을 제대로 실행하지 못했습니다. DB상태를 확인해 주세요.' 'reason' => 'SQL을 제대로 실행하지 못했습니다. DB상태를 확인해 주세요.'
]); ]);
}; };
$mysqli_obj = $rootDB->get(); //로그인에 실패할 경우 자동으로 dbConnFail()이 실행됨. $mysqli_obj = $rootDB->get(); //로그인에 실패할 경우 자동으로 dbConnFail()이 실행됨.
if ($mysqli_obj->multi_query(file_get_contents(__DIR__ . '/sql/common_schema.sql'))) { if ($mysqli_obj->multi_query(file_get_contents(__DIR__ . '/sql/common_schema.sql'))) {
while (true) { while (true) {
if (!$mysqli_obj->more_results()) { if (!$mysqli_obj->more_results()) {
break; break;
} }
if (!$mysqli_obj->next_result()) { if (!$mysqli_obj->next_result()) {
break; break;
} }
} }
} }
$rootDB->insert('system', array( $rootDB->insert('system', array(
'REG' => 'N', 'REG' => 'N',
'LOGIN' => 'N', 'LOGIN' => 'N',
'CRT_DATE' => TimeUtil::now(), 'CRT_DATE' => TimeUtil::now(),
'MDF_DATE' => TimeUtil::now() 'MDF_DATE' => TimeUtil::now()
)); ));
$globalSalt = bin2hex(random_bytes(16)); $globalSalt = bin2hex(random_bytes(16));
'@phan-var-force string $servHost'; '@phan-var-force string $servHost';
'@phan-var-force string $sharedIconPath'; '@phan-var-force string $sharedIconPath';
'@phan-var-force string $gameImagePath'; '@phan-var-force string $gameImagePath';
$sharedIconPath = WebUtil::resolveRelativePath($sharedIconPath, $servHost); $sharedIconPath = WebUtil::resolveRelativePath($sharedIconPath, $servHost);
$gameImagePath = WebUtil::resolveRelativePath($gameImagePath, $servHost); $gameImagePath = WebUtil::resolveRelativePath($gameImagePath, $servHost);
$imageRequestPath = WebUtil::resolveRelativePath($gameImagePath . '/../hook/git_pull.php', $servHost); $imageRequestPath = WebUtil::resolveRelativePath($gameImagePath . '/../hook/git_pull.php', $servHost);
$imageKeyInstallPath = WebUtil::resolveRelativePath($gameImagePath . '/../hook/InstallKey.php', $servHost); $imageKeyInstallPath = WebUtil::resolveRelativePath($gameImagePath . '/../hook/InstallKey.php', $servHost);
$result = Util::generateFileUsingSimpleTemplate( $result = Util::generateFileUsingSimpleTemplate(
__DIR__ . '/templates/ServConfig.orig.php', __DIR__ . '/templates/ServConfig.orig.php',
ROOT . '/d_setting/ServConfig.php', ROOT . '/d_setting/ServConfig.php',
[ [
'serverBasePath' => $servHost, 'serverBasePath' => $servHost,
'sharedIconPath' => $sharedIconPath, 'sharedIconPath' => $sharedIconPath,
'gameImagePath' => $gameImagePath, 'gameImagePath' => $gameImagePath,
'imageRequestPath' => $imageRequestPath, 'imageRequestPath' => $imageRequestPath,
'imageRequestKey' => $imageRequestKey 'imageRequestKey' => $imageRequestKey,
], 'serverList' => [
true ['che', '체', 'white'],
); ['kwe', '퀘', 'yellow'],
['pwe', '풰', 'orange'],
if ($imageRequestKey) { ['twe', '퉤', 'magenta'],
@file_get_contents($imageKeyInstallPath . '?key=' . $imageRequestKey); ['nya', '냐', '#e67e22'],
} ['pya', '퍄', '#9b59b6']
]
if ($result !== true) { ],
Json::die([ true
'result' => false, );
'reason' => $result
]); if ($imageRequestKey) {
} @file_get_contents($imageKeyInstallPath . '?key=' . $imageRequestKey);
}
$result = Util::generateFileUsingSimpleTemplate(
__DIR__ . '/templates/common_path.orig.js', if ($result !== true) {
ROOT . '/d_shared/common_path.js', Json::die([
[ 'result' => false,
'serverBasePath' => $servHost, 'reason' => $result
'sharedIconPath' => $sharedIconPath, ]);
'gameImagePath' => $gameImagePath }
],
true $result = Util::generateFileUsingSimpleTemplate(
); __DIR__ . '/templates/common_path.orig.js',
ROOT . '/d_shared/common_path.js',
$result = Util::generateFileUsingSimpleTemplate( [
__DIR__ . '/templates/menu.orig.json', 'serverBasePath' => $servHost,
ROOT . '/d_shared/menu.json', 'sharedIconPath' => $sharedIconPath,
[], 'gameImagePath' => $gameImagePath
true ],
); true
);
if ($result !== true) {
Json::die([ $result = Util::generateFileUsingSimpleTemplate(
'result' => false, __DIR__ . '/templates/menu.orig.json',
'reason' => $result ROOT . '/d_shared/menu.json',
]); [],
} true
);
$result = Util::generateFileUsingSimpleTemplate( if ($result !== true) {
__DIR__ . '/templates/common.orig.css', Json::die([
ROOT . '/d_shared/common.css', 'result' => false,
[ 'reason' => $result
'serverBasePath' => $servHost, ]);
'sharedIconPath' => $sharedIconPath, }
'gameImagePath' => $gameImagePath
],
true $result = Util::generateFileUsingSimpleTemplate(
); __DIR__ . '/templates/common.orig.css',
ROOT . '/d_shared/common.css',
if ($result !== true) { [
Json::die([ 'serverBasePath' => $servHost,
'result' => false, 'sharedIconPath' => $sharedIconPath,
'reason' => $result 'gameImagePath' => $gameImagePath
]); ],
} true
);
$result = Util::generateFileUsingSimpleTemplate( if ($result !== true) {
__DIR__ . '/templates/RootDB.orig.php', Json::die([
ROOT . '/d_setting/RootDB.php', 'result' => false,
[ 'reason' => $result
'host' => $host, ]);
'user' => $username, }
'password' => $password,
'dbName' => $dbName,
'port' => $port, $result = Util::generateFileUsingSimpleTemplate(
'globalSalt' => $globalSalt, __DIR__ . '/templates/RootDB.orig.php',
] ROOT . '/d_setting/RootDB.php',
); [
'host' => $host,
$kakaoRedirectURI = WebUtil::resolveRelativePath('oauth_kakao/oauth.php', $servHost . '/'); 'user' => $username,
'password' => $password,
Util::generateFileUsingSimpleTemplate( 'dbName' => $dbName,
__DIR__ . '/templates/KakaoKey.orig.php', 'port' => $port,
ROOT . '/d_setting/KakaoKey.php', 'globalSalt' => $globalSalt,
[ ]
'REST_API_KEY' => $kakaoRESTKey, );
'ADMIN_KEY' => $kakaoAdminKey,
'REDIRECT_URI' => $kakaoRedirectURI $kakaoRedirectURI = WebUtil::resolveRelativePath('oauth_kakao/oauth.php', $servHost . '/');
],
true Util::generateFileUsingSimpleTemplate(
); __DIR__ . '/templates/KakaoKey.orig.php',
ROOT . '/d_setting/KakaoKey.php',
if ($result !== true) { [
Json::die([ 'REST_API_KEY' => $kakaoRESTKey,
'result' => false, 'ADMIN_KEY' => $kakaoAdminKey,
'reason' => $result 'REDIRECT_URI' => $kakaoRedirectURI
]); ],
} true
);
Json::die([
'result' => true, if ($result !== true) {
'reason' => 'success', Json::die([
'globalSalt' => $globalSalt 'result' => false,
]); 'reason' => $result
]);
}
Json::die([
'result' => true,
'reason' => 'success',
'globalSalt' => $globalSalt
]);
+74 -55
View File
@@ -1,55 +1,74 @@
<?php <?php
namespace sammo; namespace sammo;
class ServConfig class ServConfig
{ {
private function __construct() private function __construct()
{ {
} }
public static $serverWebPath = '_tK_serverBasePath_'; public static $serverWebPath = '_tK_serverBasePath_';
public static $sharedIconPath = '_tK_sharedIconPath_'; public static $sharedIconPath = '_tK_sharedIconPath_';
public static $gameImagePath = "_tK_gameImagePath_"; public static $gameImagePath = "_tK_gameImagePath_";
public static $imageRequestPath = "_tK_imageRequestPath_"; public static $imageRequestPath = "_tK_imageRequestPath_";
public static $imageRequestKey = '_tK_imageRequestKey_'; public static $imageRequestKey = '_tK_imageRequestKey_';
private static $serverList = null;
public static function getSharedIconPath(string $filepath = ''): string
{ public static function getSharedIconPath(string $filepath = ''): string
if ($filepath) { {
return static::$sharedIconPath . "/{$filepath}"; if ($filepath) {
} return static::$sharedIconPath . "/{$filepath}";
return static::$sharedIconPath; }
} return static::$sharedIconPath;
}
public static function getUserIconPath(string $filepath = ''): string
{ public static function getUserIconPath(string $filepath = ''): string
return AppConf::getUserIconPathWeb($filepath); {
} return AppConf::getUserIconPathWeb($filepath);
}
public static function getGameImagePath(string $filepath = ''): string
{ public static function getGameImagePath(string $filepath = ''): string
if ($filepath) { {
return static::$gameImagePath . "/{$filepath}"; if ($filepath) {
} return static::$gameImagePath . "/{$filepath}";
return static::$gameImagePath; }
} return static::$gameImagePath;
}
public static function getImagePullURI(): string
{ public static function getImagePullURI(): string
$now = time(); {
$req_hash = Util::hashPassword(sprintf("%016x", $now), static::$imageRequestKey); $now = time();
return static::$imageRequestPath . "?req={$req_hash}&time={$now}"; $req_hash = Util::hashPassword(sprintf("%016x", $now), static::$imageRequestKey);
} return static::$imageRequestPath . "?req={$req_hash}&time={$now}";
}
/** /**
* 서버 주소 반환. 서버의 경로가 하부 디렉토리인 경우에 하부 디렉토리까지 포함 * 서버 설정 반환
* *
* @return string * @return \sammo\Setting[]
*/ */
public static function getServerBasepath(): string public static function getServerList(): array{
{ $servKeyList = [/*_tK_serverList_*/];
return self::$serverWebPath; $servKeyList[] = ['hwe', '훼', 'red'];
}
} if (self::$serverList === null) {
self::$serverList = [];
foreach($servKeyList as [$servKey, $servNick, $servColor]){
self::$serverList[] = new Setting(ROOT.'/'.$servKey, $servNick, $servColor);
}
}
return self::$serverList;
}
/**
* 서버 주소 반환. 서버의 경로가 하부 디렉토리인 경우에 하부 디렉토리까지 포함
*
* @return string
*/
public static function getServerBasepath(): string
{
return self::$serverWebPath;
}
}
+100 -100
View File
@@ -1,101 +1,101 @@
<?php <?php
namespace sammo; namespace sammo;
include 'lib.php'; include 'lib.php';
include "func.php"; include "func.php";
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
if (!$db->queryFirstField("SHOW TABLES LIKE 'reserved_open'")) { if (!$db->queryFirstField("SHOW TABLES LIKE 'reserved_open'")) {
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'affected'=>0, 'affected'=>0,
'status'=>'no_reserved_table' 'status'=>'no_reserved_table'
]); ]);
} }
$reserved = $db->queryFirstRow('SELECT `date`, options FROM reserved_open ORDER BY `date` ASC LIMIT 1'); $reserved = $db->queryFirstRow('SELECT `date`, options FROM reserved_open ORDER BY `date` ASC LIMIT 1');
if(!$reserved){ if(!$reserved){
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'affected'=>0, 'affected'=>0,
'status'=>'no_reserved' 'status'=>'no_reserved'
]); ]);
} }
$reservedDate = new \DateTime($reserved['date']); $reservedDate = new \DateTime($reserved['date']);
$now = new \DateTime(); $now = new \DateTime();
$status = 'not_yet'; $status = 'not_yet';
list($isUnited, $lastTurn) = $gameStor->getValuesAsArray(['isunited', 'turntime']); list($isUnited, $lastTurn) = $gameStor->getValuesAsArray(['isunited', 'turntime']);
if($isUnited === null || $lastTurn === null){ if($isUnited === null || $lastTurn === null){
$isUnited = 2; $isUnited = 2;
$lastTurn = '2000-01-01'; $lastTurn = '2000-01-01';
} }
if($lastTurn !== null){ if($lastTurn !== null){
$lastTurn = new \DateTime($lastTurn); $lastTurn = new \DateTime($lastTurn);
} }
if($lastTurn === null){ if($lastTurn === null){
//이미 리셋된 상태임 //이미 리셋된 상태임
} }
else if(file_exists(__DIR__.'/.htaccess')){ else if(file_exists(__DIR__.'/.htaccess')){
//일단 서버는 닫혀 있음 //일단 서버는 닫혀 있음
} }
else if( else if(
$isUnited == 2 && $isUnited == 2 &&
$now->getTimestamp() - $lastTurn->getTimestamp() > $reservedDate->getTimestamp() - $now->getTimestamp() $now->getTimestamp() - $lastTurn->getTimestamp() > $reservedDate->getTimestamp() - $now->getTimestamp()
){ ){
//정지 상태 & 중간 넘음 //정지 상태 & 중간 넘음
AppConf::getList()[DB::prefix()]->closeServer(); ServConfig::getServerList()[DB::prefix()]->closeServer();
$status = 'closed'; $status = 'closed';
} }
else if( else if(
$isUnited > 0 && $isUnited > 0 &&
$now->getTimestamp() - $lastTurn->getTimestamp() > ($reservedDate->getTimestamp() - $now->getTimestamp()) * 2 $now->getTimestamp() - $lastTurn->getTimestamp() > ($reservedDate->getTimestamp() - $now->getTimestamp()) * 2
){ ){
//천통 & 비정지 상태 & 2/3 넘음 //천통 & 비정지 상태 & 2/3 넘음
AppConf::getList()[DB::prefix()]->closeServer(); ServConfig::getServerList()[DB::prefix()]->closeServer();
$status = 'closed'; $status = 'closed';
} }
else if($reservedDate->getTimestamp() - $now->getTimestamp() <= 60*10){ else if($reservedDate->getTimestamp() - $now->getTimestamp() <= 60*10){
//어쨌든 간에 10분 남았다면. //어쨌든 간에 10분 남았다면.
AppConf::getList()[DB::prefix()]->closeServer(); ServConfig::getServerList()[DB::prefix()]->closeServer();
$status = 'closed'; $status = 'closed';
} }
if($now < $reservedDate){ if($now < $reservedDate){
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'affected'=>0, 'affected'=>0,
'status'=>$status 'status'=>$status
]); ]);
} }
$options = Json::decode($reserved['options']); $options = Json::decode($reserved['options']);
$result = ResetHelper::buildScenario( $result = ResetHelper::buildScenario(
$options['turnterm'], $options['turnterm'],
$options['sync'], $options['sync'],
$options['scenario'], $options['scenario'],
$options['fiction'], $options['fiction'],
$options['extend'], $options['extend'],
$options['npcmode'], $options['npcmode'],
$options['show_img_level'], $options['show_img_level'],
$options['tournament_trig'], $options['tournament_trig'],
$options['join_mode'], $options['join_mode'],
$options['starttime'], $options['starttime'],
$options['autorun_user']?:null $options['autorun_user']?:null
); );
$result['affected']=1; $result['affected']=1;
$prefix = DB::prefix(); $prefix = DB::prefix();
AppConf::getList()[$prefix]->openServer(); ServConfig::getServerList()[$prefix]->openServer();
Json::die($result); Json::die($result);
+208 -208
View File
@@ -1,209 +1,209 @@
<?php <?php
namespace sammo; namespace sammo;
include "lib.php"; include "lib.php";
include "func.php"; include "func.php";
WebUtil::requireAJAX(); WebUtil::requireAJAX();
$session = Session::requireLogin([])->setReadOnly(); $session = Session::requireLogin([])->setReadOnly();
if(!class_exists('\\sammo\\DB')){ if(!class_exists('\\sammo\\DB')){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'DB리셋 필요' 'reason'=>'DB리셋 필요'
]); ]);
} }
$serverName = DB::prefix(); $serverName = DB::prefix();
$serverAcl = $session->acl[$serverName]??[]; $serverAcl = $session->acl[$serverName]??[];
$allowReset = in_array('reset', $serverAcl); $allowReset = in_array('reset', $serverAcl);
$allowFullReset = in_array('fullReset',$serverAcl); $allowFullReset = in_array('fullReset',$serverAcl);
$allowReset |= $allowFullReset; $allowReset |= $allowFullReset;
$reserve_open = Util::getPost('reserve_open'); $reserve_open = Util::getPost('reserve_open');
if($reserve_open && $reserve_open < date('Y-m-d H:i')){ if($reserve_open && $reserve_open < date('Y-m-d H:i')){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'현재 시간보다 이전 시간대를 예약 시간으로 지정했습니다.' 'reason'=>'현재 시간보다 이전 시간대를 예약 시간으로 지정했습니다.'
]); ]);
} }
$pre_reserve_open = Util::getPost('pre_reserve_open'); $pre_reserve_open = Util::getPost('pre_reserve_open');
if($pre_reserve_open && !$reserve_open){ if($pre_reserve_open && !$reserve_open){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'가오픈 예약을 위해선 오픈 예약을 지정해야합니다.' 'reason'=>'가오픈 예약을 위해선 오픈 예약을 지정해야합니다.'
]); ]);
} }
if($pre_reserve_open && $pre_reserve_open >= $reserve_open){ if($pre_reserve_open && $pre_reserve_open >= $reserve_open){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'가오픈 시간이 오픈 예약 시점보다 이전이어야 합니다.' 'reason'=>'가오픈 시간이 오픈 예약 시점보다 이전이어야 합니다.'
]); ]);
} }
if($session->userGrade < 5 && !$allowReset){ if($session->userGrade < 5 && !$allowReset){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'관리자 아님' 'reason'=>'관리자 아님'
]); ]);
} }
$v = new Validator($_POST); $v = new Validator($_POST);
$v->rule('required', [ $v->rule('required', [
'turnterm', 'turnterm',
'sync', 'sync',
'scenario', 'scenario',
'fiction', 'fiction',
'extend', 'extend',
'join_mode', 'join_mode',
'npcmode', 'npcmode',
'show_img_level', 'show_img_level',
'autorun_user_minutes' 'autorun_user_minutes'
])->rule('integer', [ ])->rule('integer', [
'turnterm', 'turnterm',
'sync', 'sync',
'scenario', 'scenario',
'fiction', 'fiction',
'extend', 'extend',
'npcmode', 'npcmode',
'show_img_level', 'show_img_level',
'tournament_trig', 'tournament_trig',
'autorun_user_minutes' 'autorun_user_minutes'
])->rule('in', 'join_mode', ['onlyRandom', 'full']); ])->rule('in', 'join_mode', ['onlyRandom', 'full']);
if(!$v->validate()){ if(!$v->validate()){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>$v->errorStr() 'reason'=>$v->errorStr()
]); ]);
} }
$allowReset = true; $allowReset = true;
if($session->userGrade < 5 && !$allowFullReset){ if($session->userGrade < 5 && !$allowFullReset){
//리셋 가능한 조건인지 테스트 //리셋 가능한 조건인지 테스트
$allowReset = false; $allowReset = false;
if(file_exists(__DIR__.'/.htaccess')){ if(file_exists(__DIR__.'/.htaccess')){
$allowReset = true; $allowReset = true;
} }
else{ else{
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
if($gameStor->isunited){ if($gameStor->isunited){
$allowReset = true; $allowReset = true;
} }
} }
} }
if(!$allowReset){ if(!$allowReset){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'부족한 권한: 서버가 닫혀있거나, 천통되어 있을 경우에만 리셋 가능합니다.' 'reason'=>'부족한 권한: 서버가 닫혀있거나, 천통되어 있을 경우에만 리셋 가능합니다.'
]); ]);
} }
$turnterm = (int)$_POST['turnterm']; $turnterm = (int)$_POST['turnterm'];
$sync = (int)$_POST['sync']; $sync = (int)$_POST['sync'];
$scenario = (int)$_POST['scenario']; $scenario = (int)$_POST['scenario'];
$fiction = (int)$_POST['fiction']; $fiction = (int)$_POST['fiction'];
$extend = (int)$_POST['extend']; $extend = (int)$_POST['extend'];
$npcmode = (int)$_POST['npcmode']; $npcmode = (int)$_POST['npcmode'];
$show_img_level = (int)$_POST['show_img_level']; $show_img_level = (int)$_POST['show_img_level'];
$tournament_trig = (int)$_POST['tournament_trig']; $tournament_trig = (int)$_POST['tournament_trig'];
$join_mode = $_POST['join_mode']; $join_mode = $_POST['join_mode'];
$autorun_user_minutes = (int)$_POST['autorun_user_minutes']; $autorun_user_minutes = (int)$_POST['autorun_user_minutes'];
$autorun_user_options = []; $autorun_user_options = [];
foreach(Util::getPost('autorun_user', 'array_string', []) as $autorun_option){ foreach(Util::getPost('autorun_user', 'array_string', []) as $autorun_option){
$autorun_user_options[$autorun_option] = 1; $autorun_user_options[$autorun_option] = 1;
} }
if($autorun_user_minutes > 0 && !$autorun_user_options){ if($autorun_user_minutes > 0 && !$autorun_user_options){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'적어도 자동 행동 중 하나는 선택을 해야합니다.' 'reason'=>'적어도 자동 행동 중 하나는 선택을 해야합니다.'
]); ]);
} }
if($autorun_user_minutes < 0){ if($autorun_user_minutes < 0){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'자동 행동 기한이 0보다 작을 수 없습니다.' 'reason'=>'자동 행동 기한이 0보다 작을 수 없습니다.'
]); ]);
} }
$autorun_user = $autorun_user_minutes?[ $autorun_user = $autorun_user_minutes?[
'limit_minutes'=>$autorun_user_minutes, 'limit_minutes'=>$autorun_user_minutes,
'options'=>$autorun_user_options 'options'=>$autorun_user_options
]:null; ]:null;
if($reserve_open){ if($reserve_open){
$reserve_open = new \DateTime($reserve_open); $reserve_open = new \DateTime($reserve_open);
$db = DB::db(); $db = DB::db();
if (!$db->queryFirstField("SHOW TABLES LIKE 'storage'")) { if (!$db->queryFirstField("SHOW TABLES LIKE 'storage'")) {
$clearResult = ResetHelper::clearDB(); $clearResult = ResetHelper::clearDB();
if(!$clearResult['result']){ if(!$clearResult['result']){
Json::die($clearResult); Json::die($clearResult);
} }
} }
if (!$db->queryFirstField("SHOW TABLES LIKE 'reserved_open'")) { if (!$db->queryFirstField("SHOW TABLES LIKE 'reserved_open'")) {
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'예약 테이블이 없음!' 'reason'=>'예약 테이블이 없음!'
]); ]);
} }
$scenarioObj = new Scenario($scenario, true); $scenarioObj = new Scenario($scenario, true);
$open_date = $reserve_open->format('Y-m-d H:i:s'); $open_date = $reserve_open->format('Y-m-d H:i:s');
$reserveInfo = [ $reserveInfo = [
'turnterm'=>$turnterm, 'turnterm'=>$turnterm,
'sync'=>$sync, 'sync'=>$sync,
'scenario'=>$scenario, 'scenario'=>$scenario,
'scenarioName'=>$scenarioObj->getTitle(), 'scenarioName'=>$scenarioObj->getTitle(),
'fiction'=>$fiction, 'fiction'=>$fiction,
'extend'=>$extend, 'extend'=>$extend,
'npcmode'=>$npcmode, 'npcmode'=>$npcmode,
'show_img_level'=>$show_img_level, 'show_img_level'=>$show_img_level,
'tournament_trig'=>$tournament_trig, 'tournament_trig'=>$tournament_trig,
'gameConf'=>$scenarioObj->getGameConf(), 'gameConf'=>$scenarioObj->getGameConf(),
'join_mode'=>$join_mode, 'join_mode'=>$join_mode,
'starttime'=>$open_date, 'starttime'=>$open_date,
'autorun_user'=>$autorun_user 'autorun_user'=>$autorun_user
]; ];
if($pre_reserve_open){ if($pre_reserve_open){
$pre_reserve_open = new \DateTime($pre_reserve_open); $pre_reserve_open = new \DateTime($pre_reserve_open);
$open_date = $pre_reserve_open->format('Y-m-d H:i:s'); $open_date = $pre_reserve_open->format('Y-m-d H:i:s');
} }
$db->delete('reserved_open', true); $db->delete('reserved_open', true);
$db->insert('reserved_open', [ $db->insert('reserved_open', [
'options'=>Json::encode($reserveInfo), 'options'=>Json::encode($reserveInfo),
'date'=>$open_date 'date'=>$open_date
]); ]);
AppConf::getList()[DB::prefix()]->closeServer(); ServConfig::getServerList()[DB::prefix()]->closeServer();
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'reason'=>'예약' 'reason'=>'예약'
]); ]);
} }
Json::die(ResetHelper::buildScenario( Json::die(ResetHelper::buildScenario(
$turnterm, $turnterm,
$sync, $sync,
$scenario, $scenario,
$fiction, $fiction,
$extend, $extend,
$npcmode, $npcmode,
$show_img_level, $show_img_level,
$tournament_trig, $tournament_trig,
$join_mode, $join_mode,
TimeUtil::now(), TimeUtil::now(),
$autorun_user $autorun_user
)); ));
+102 -102
View File
@@ -1,103 +1,103 @@
<?php <?php
namespace sammo; namespace sammo;
include "lib.php"; include "lib.php";
include "func.php"; include "func.php";
WebUtil::requireAJAX(); WebUtil::requireAJAX();
$session = Session::requireLogin([])->setReadOnly(); $session = Session::requireLogin([])->setReadOnly();
if($session->userGrade < 6){ if($session->userGrade < 6){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'관리자 아님' 'reason'=>'관리자 아님'
]); ]);
} }
$fullReset = Util::getPost('full_reset', 'bool', false); $fullReset = Util::getPost('full_reset', 'bool', false);
$host = Util::getPost('db_host'); $host = Util::getPost('db_host');
$port = Util::getPost('db_port', 'int'); $port = Util::getPost('db_port', 'int');
$username = Util::getPost('db_id'); $username = Util::getPost('db_id');
$password = Util::getPost('db_pw'); $password = Util::getPost('db_pw');
$dbName = Util::getPost('db_name'); $dbName = Util::getPost('db_name');
if(!$host || !$port || !$username || !$password || !$dbName){ if(!$host || !$port || !$username || !$password || !$dbName){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'입력 값이 올바르지 않습니다' 'reason'=>'입력 값이 올바르지 않습니다'
]); ]);
} }
if($fullReset && class_exists('\\sammo\\DB')){ if($fullReset && class_exists('\\sammo\\DB')){
$mysqli_obj = DB::db()->get(); $mysqli_obj = DB::db()->get();
if($mysqli_obj->multi_query(file_get_contents(__DIR__.'/sql/reset.sql'))){ if($mysqli_obj->multi_query(file_get_contents(__DIR__.'/sql/reset.sql'))){
while(true){ while(true){
if (!$mysqli_obj->more_results()) { if (!$mysqli_obj->more_results()) {
break; break;
} }
if(!$mysqli_obj->next_result()){ if(!$mysqli_obj->next_result()){
break; break;
} }
} }
} }
} }
if($fullReset){ if($fullReset){
FileUtil::delInDir(__DIR__."/logs"); FileUtil::delInDir(__DIR__."/logs");
FileUtil::delInDir(__DIR__."/data"); FileUtil::delInDir(__DIR__."/data");
if(file_exists(__DIR__.'/d_setting/DB.php')){ if(file_exists(__DIR__.'/d_setting/DB.php')){
@unlink(__DIR__.'/d_setting/DB.php'); @unlink(__DIR__.'/d_setting/DB.php');
} }
if(file_exists(__DIR__.'/d_setting/UniqueConst.php')){ if(file_exists(__DIR__.'/d_setting/UniqueConst.php')){
@unlink(__DIR__.'/d_setting/UniqueConst.php'); @unlink(__DIR__.'/d_setting/UniqueConst.php');
} }
} }
function dbConnFail($params){ function dbConnFail($params){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'DB 접속에 실패했습니다.' 'reason'=>'DB 접속에 실패했습니다.'
]); ]);
} }
$db = new \MeekroDB($host,$username,$password,$dbName,$port,'utf8mb4'); $db = new \MeekroDB($host,$username,$password,$dbName,$port,'utf8mb4');
$db->connect_options[MYSQLI_OPT_INT_AND_FLOAT_NATIVE] = true; $db->connect_options[MYSQLI_OPT_INT_AND_FLOAT_NATIVE] = true;
$db->throw_exception_on_nonsql_error = false; $db->throw_exception_on_nonsql_error = false;
$db->nonsql_error_handler = 'dbConnFail'; $db->nonsql_error_handler = 'dbConnFail';
$mysqli_obj = $db->get(); //로그인에 실패할 경우 자동으로 dbConnFail()이 실행됨. $mysqli_obj = $db->get(); //로그인에 실패할 경우 자동으로 dbConnFail()이 실행됨.
$prefix = basename(__DIR__); $prefix = basename(__DIR__);
$result = Util::generateFileUsingSimpleTemplate( $result = Util::generateFileUsingSimpleTemplate(
__DIR__.'/d_setting/DB.orig.php', __DIR__.'/d_setting/DB.orig.php',
__DIR__.'/d_setting/DB.php',[ __DIR__.'/d_setting/DB.php',[
'host'=>$host, 'host'=>$host,
'user'=>$username, 'user'=>$username,
'password'=>$password, 'password'=>$password,
'dbName'=>$dbName, 'dbName'=>$dbName,
'port'=>$port, 'port'=>$port,
'prefix'=>$prefix 'prefix'=>$prefix
], true ], true
); );
if($result !== true){ if($result !== true){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>$result 'reason'=>$result
]); ]);
} }
ResetHelper::clearDB(); ResetHelper::clearDB();
AppConf::getList()[$prefix]->closeServer(); ServConfig::getServerList()[$prefix]->closeServer();
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'reason'=>'success' 'reason'=>'success'
]); ]);
+357 -357
View File
@@ -1,358 +1,358 @@
<?php <?php
namespace sammo; namespace sammo;
class ResetHelper{ class ResetHelper{
private function __construct(){ private function __construct(){
} }
static public function clearDB(){ static public function clearDB(){
$servRoot = realpath(__DIR__.'/../'); $servRoot = realpath(__DIR__.'/../');
if(!file_exists($servRoot.'/logs') || !file_exists($servRoot.'/data')){ if(!file_exists($servRoot.'/logs') || !file_exists($servRoot.'/data')){
if(!is_writable($servRoot)){ if(!is_writable($servRoot)){
return [ return [
'result'=>false, 'result'=>false,
'reason'=>'logs, data 디렉토리를 생성할 권한이 없습니다.' 'reason'=>'logs, data 디렉토리를 생성할 권한이 없습니다.'
]; ];
} }
mkdir($servRoot.'/logs', 0755); mkdir($servRoot.'/logs', 0755);
mkdir($servRoot.'/data', 0755); mkdir($servRoot.'/data', 0755);
} }
if(!is_writable($servRoot.'/logs')){ if(!is_writable($servRoot.'/logs')){
return [ return [
'result'=>false, 'result'=>false,
'reason'=>'logs 디렉토리의 쓰기 권한이 없습니다' 'reason'=>'logs 디렉토리의 쓰기 권한이 없습니다'
]; ];
} }
if(!is_writable($servRoot.'/data')){ if(!is_writable($servRoot.'/data')){
return [ return [
'result'=>false, 'result'=>false,
'reason'=>'data 디렉토리의 쓰기 권한이 없습니다' 'reason'=>'data 디렉토리의 쓰기 권한이 없습니다'
]; ];
} }
if(!is_writable($servRoot.'/d_setting')){ if(!is_writable($servRoot.'/d_setting')){
return [ return [
'result'=>false, 'result'=>false,
'reason'=>'d_setting 디렉토리의 쓰기 권한이 없습니다' 'reason'=>'d_setting 디렉토리의 쓰기 권한이 없습니다'
]; ];
} }
if(!file_exists($servRoot.'/logs/preserved')){ if(!file_exists($servRoot.'/logs/preserved')){
mkdir($servRoot.'/logs/preserved', 0755); mkdir($servRoot.'/logs/preserved', 0755);
} }
if(!file_exists($servRoot.'/logs/.htaccess')){ if(!file_exists($servRoot.'/logs/.htaccess')){
@file_put_contents($servRoot.'/logs/.htaccess', 'Deny from all'); @file_put_contents($servRoot.'/logs/.htaccess', 'Deny from all');
} }
if(!file_exists($servRoot.'/data/.htaccess')){ if(!file_exists($servRoot.'/data/.htaccess')){
@file_put_contents($servRoot.'/data/.htaccess', 'Deny from all'); @file_put_contents($servRoot.'/data/.htaccess', 'Deny from all');
} }
$dir = new \DirectoryIterator($servRoot.'/logs'); $dir = new \DirectoryIterator($servRoot.'/logs');
foreach ($dir as $fileinfo) { foreach ($dir as $fileinfo) {
/** @var \DirectoryIterator $fileinfo */ /** @var \DirectoryIterator $fileinfo */
if (!$fileinfo->isDir() || $fileinfo->isDot()) { if (!$fileinfo->isDir() || $fileinfo->isDot()) {
continue; continue;
} }
$basename = $fileinfo->getFilename(); $basename = $fileinfo->getFilename();
if($basename == 'preserved'){ if($basename == 'preserved'){
continue; continue;
} }
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
exec("move ".escapeshellarg($servRoot.'/logs/'.$basename)." ".escapeshellarg($servRoot.'/logs/preserved/'.$basename)); exec("move ".escapeshellarg($servRoot.'/logs/'.$basename)." ".escapeshellarg($servRoot.'/logs/preserved/'.$basename));
} else { } else {
exec("mv ".escapeshellarg($servRoot.'/logs/'.$basename)." ".escapeshellarg($servRoot.'/logs/preserved/'.$basename)); exec("mv ".escapeshellarg($servRoot.'/logs/'.$basename)." ".escapeshellarg($servRoot.'/logs/preserved/'.$basename));
} }
} }
$prefix = DB::prefix(); $prefix = DB::prefix();
AppConf::getList()[$prefix]->closeServer(); ServConfig::getServerList()[$prefix]->closeServer();
$db = DB::db(); $db = DB::db();
$mysqli_obj = $db->get(); $mysqli_obj = $db->get();
$serverID = DB::prefix().'_'.date("ymd").'_'.Util::randomStr(4); $serverID = DB::prefix().'_'.date("ymd").'_'.Util::randomStr(4);
mkdir($servRoot.'/logs/'.$serverID, 0755); mkdir($servRoot.'/logs/'.$serverID, 0755);
mkdir($servRoot.'/data/'.$serverID, 0755); mkdir($servRoot.'/data/'.$serverID, 0755);
$seasonIdx = 1; $seasonIdx = 1;
if($db->queryFirstField('SHOW TABLES LIKE %s', 'storage') !== null){ if($db->queryFirstField('SHOW TABLES LIKE %s', 'storage') !== null){
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$nextSeasonIdx = $gameStor->next_season_idx; $nextSeasonIdx = $gameStor->next_season_idx;
if($nextSeasonIdx !== null){ if($nextSeasonIdx !== null){
$seasonIdx = $nextSeasonIdx; $seasonIdx = $nextSeasonIdx;
} }
$gameStor->resetCache(); $gameStor->resetCache();
} }
$result = Util::generateFileUsingSimpleTemplate( $result = Util::generateFileUsingSimpleTemplate(
$servRoot.'/d_setting/UniqueConst.orig.php', $servRoot.'/d_setting/UniqueConst.orig.php',
$servRoot.'/d_setting/UniqueConst.php',[ $servRoot.'/d_setting/UniqueConst.php',[
'serverID'=>$serverID, 'serverID'=>$serverID,
'serverName'=>AppConf::getList()[$prefix]->getKorName(), 'serverName'=>ServConfig::getServerList()[$prefix]->getKorName(),
'seasonIdx'=>$seasonIdx, 'seasonIdx'=>$seasonIdx,
], true ], true
); );
copy( copy(
$servRoot.'/d_setting/GameConst.orig.php', $servRoot.'/d_setting/GameConst.orig.php',
$servRoot.'/d_setting/GameConst.php', $servRoot.'/d_setting/GameConst.php',
); );
if($mysqli_obj->multi_query(file_get_contents($servRoot.'/sql/reset.sql'))){ if($mysqli_obj->multi_query(file_get_contents($servRoot.'/sql/reset.sql'))){
while(true){ while(true){
if (!$mysqli_obj->more_results()) { if (!$mysqli_obj->more_results()) {
break; break;
} }
if(!$mysqli_obj->next_result()){ if(!$mysqli_obj->next_result()){
break; break;
} }
} }
} }
if($mysqli_obj->multi_query(file_get_contents($servRoot.'/sql/schema.sql'))){ if($mysqli_obj->multi_query(file_get_contents($servRoot.'/sql/schema.sql'))){
while(true){ while(true){
if (!$mysqli_obj->more_results()) { if (!$mysqli_obj->more_results()) {
break; break;
} }
if(!$mysqli_obj->next_result()){ if(!$mysqli_obj->next_result()){
break; break;
} }
} }
} }
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->resetValues(); $gameStor->resetValues();
$gameStor->next_season_idx = $seasonIdx; $gameStor->next_season_idx = $seasonIdx;
return [ return [
'result'=>true, 'result'=>true,
'serverID'=>$serverID, 'serverID'=>$serverID,
'seasonIdx'=>$seasonIdx 'seasonIdx'=>$seasonIdx
]; ];
} }
static public function buildScenario( static public function buildScenario(
int $turnterm, int $turnterm,
int $sync, int $sync,
int $scenario, int $scenario,
int $fiction, int $fiction,
int $extend, int $extend,
int $npcmode, int $npcmode,
int $show_img_level, int $show_img_level,
int $tournament_trig, int $tournament_trig,
string $join_mode, string $join_mode,
string $turntime, string $turntime,
?array $autorun_user ?array $autorun_user
):array{ ):array{
//FIXME: 분리할 것 //FIXME: 분리할 것
if(120 % $turnterm != 0){ if(120 % $turnterm != 0){
return [ return [
'result'=>false, 'result'=>false,
'reason'=>'turnterm은 120의 약수여야 합니다.' 'reason'=>'turnterm은 120의 약수여야 합니다.'
]; ];
} }
if($tournament_trig < 0 || $tournament_trig > 7){ if($tournament_trig < 0 || $tournament_trig > 7){
return [ return [
'result'=>false, 'result'=>false,
'reason'=>'올바르지 않은 토너먼트 주기입니다.' 'reason'=>'올바르지 않은 토너먼트 주기입니다.'
]; ];
} }
$clearResult = self::clearDB(); $clearResult = self::clearDB();
if(!$clearResult['result']){ if(!$clearResult['result']){
return $clearResult; return $clearResult;
} }
$serverID = $clearResult['serverID']; $serverID = $clearResult['serverID'];
$seasonIdx = $clearResult['seasonIdx']; $seasonIdx = $clearResult['seasonIdx'];
$scenarioObj = new Scenario($scenario, false); $scenarioObj = new Scenario($scenario, false);
$scenarioObj->buildConf(); $scenarioObj->buildConf();
$startyear = $scenarioObj->getYear()??GameConst::$defaultStartYear; $startyear = $scenarioObj->getYear()??GameConst::$defaultStartYear;
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$db->insert('plock', [ $db->insert('plock', [
'plock'=>1, 'plock'=>1,
'locktime'=>TimeUtil::now(true) 'locktime'=>TimeUtil::now(true)
]); ]);
$prevWinner = $db->queryFirstField('SELECT l12name FROM emperior ORDER BY `no` DESC LIMIT 1'); $prevWinner = $db->queryFirstField('SELECT l12name FROM emperior ORDER BY `no` DESC LIMIT 1');
$serverCnt = $db->queryFirstField('SELECT count(*) FROM ng_games') + 1; $serverCnt = $db->queryFirstField('SELECT count(*) FROM ng_games') + 1;
CityConst::build(); CityConst::build();
$cityPositions = []; $cityPositions = [];
foreach(CityConst::all() as $city){ foreach(CityConst::all() as $city){
$cityPositions[$city->id] = [ $cityPositions[$city->id] = [
$city->name, $city->name,
$city->posX, $city->posX,
$city->posY $city->posY
]; ];
} }
Util::generateFileUsingSimpleTemplate( Util::generateFileUsingSimpleTemplate(
__DIR__.'/../templates/base_map.orig.js', __DIR__.'/../templates/base_map.orig.js',
__DIR__.'/../d_shared/base_map.js', __DIR__.'/../d_shared/base_map.js',
[ [
'cityPosition'=>Json::encode($cityPositions), 'cityPosition'=>Json::encode($cityPositions),
'regionMap'=>Json::encode(CityConst::$regionMap), 'regionMap'=>Json::encode(CityConst::$regionMap),
'levelMap'=>Json::encode(CityConst::$levelMap), 'levelMap'=>Json::encode(CityConst::$levelMap),
], ],
true true
); );
if($sync == 0) { if($sync == 0) {
// 현재 시간을 1월로 맞춤 // 현재 시간을 1월로 맞춤
$starttime = cutTurn($turntime, $turnterm); $starttime = cutTurn($turntime, $turnterm);
$month = 1; $month = 1;
$year = $startyear; $year = $startyear;
} else { } else {
// 현재 시간과 동기화 // 현재 시간과 동기화
[$starttime, $yearPulled, $month] = cutDay($turntime, $turnterm); [$starttime, $yearPulled, $month] = cutDay($turntime, $turnterm);
if($yearPulled){ if($yearPulled){
$year = $startyear-1; $year = $startyear-1;
} }
else{ else{
$year = $startyear; $year = $startyear;
} }
} }
$killturn = 4800 / $turnterm; $killturn = 4800 / $turnterm;
if($npcmode == 1) { $killturn = intdiv($killturn, 3); } if($npcmode == 1) { $killturn = intdiv($killturn, 3); }
$develcost = ($year - $startyear + 10) * 2; $develcost = ($year - $startyear + 10) * 2;
$env = [ $env = [
'scenario'=>$scenario, 'scenario'=>$scenario,
'scenario_text'=>$scenarioObj->getTitle(), 'scenario_text'=>$scenarioObj->getTitle(),
'icon_path'=>$scenarioObj->getIconPath(), 'icon_path'=>$scenarioObj->getIconPath(),
'startyear'=>$startyear, 'startyear'=>$startyear,
'year'=> $year, 'year'=> $year,
'month'=> $month, 'month'=> $month,
'init_year'=> $year, 'init_year'=> $year,
'init_month'=>$month, 'init_month'=>$month,
'map_theme' => $scenarioObj->getMapTheme(), 'map_theme' => $scenarioObj->getMapTheme(),
'season'=>$seasonIdx, 'season'=>$seasonIdx,
'msg'=>'공지사항',//TODO:공지사항 'msg'=>'공지사항',//TODO:공지사항
'maxgeneral'=>GameConst::$defaultMaxGeneral, 'maxgeneral'=>GameConst::$defaultMaxGeneral,
'maxnation'=>GameConst::$defaultMaxNation, 'maxnation'=>GameConst::$defaultMaxNation,
'conlimit'=>30000, 'conlimit'=>30000,
'develcost'=>$develcost, 'develcost'=>$develcost,
'turntime'=>$turntime, 'turntime'=>$turntime,
'starttime'=>$starttime, 'starttime'=>$starttime,
'opentime'=>$turntime, 'opentime'=>$turntime,
'turnterm'=>$turnterm, 'turnterm'=>$turnterm,
'killturn'=>$killturn, 'killturn'=>$killturn,
'genius'=>GameConst::$defaultMaxGenius, 'genius'=>GameConst::$defaultMaxGenius,
'show_img_level'=>$show_img_level, 'show_img_level'=>$show_img_level,
'join_mode'=>$join_mode, 'join_mode'=>$join_mode,
'npcmode'=>$npcmode, 'npcmode'=>$npcmode,
'extended_general'=>$extend, 'extended_general'=>$extend,
'fiction'=>$fiction, 'fiction'=>$fiction,
'tnmt_trig'=>$tournament_trig, 'tnmt_trig'=>$tournament_trig,
'prev_winner'=>$prevWinner, 'prev_winner'=>$prevWinner,
'autorun_user'=>$autorun_user, 'autorun_user'=>$autorun_user,
'tournament'=>0, 'tournament'=>0,
'server_cnt'=>$serverCnt, 'server_cnt'=>$serverCnt,
]; ];
$db->insert('betting', [ $db->insert('betting', [
'general_id'=>0, 'general_id'=>0,
'bet0'=>0, 'bet0'=>0,
'bet1'=>0, 'bet1'=>0,
'bet2'=>0, 'bet2'=>0,
'bet3'=>0, 'bet3'=>0,
'bet4'=>0, 'bet4'=>0,
'bet5'=>0, 'bet5'=>0,
'bet6'=>0, 'bet6'=>0,
'bet7'=>0, 'bet7'=>0,
'bet8'=>0, 'bet8'=>0,
'bet9'=>0, 'bet9'=>0,
'bet10'=>0, 'bet10'=>0,
'bet11'=>0, 'bet11'=>0,
'bet12'=>0, 'bet12'=>0,
'bet13'=>0, 'bet13'=>0,
'bet14'=>0, 'bet14'=>0,
'bet15'=>0, 'bet15'=>0,
]); ]);
foreach(RootDB::db()->query('SELECT `no`, `name`, `picture`, `imgsvr` FROM member WHERE grade >= 5') as $admin){ foreach(RootDB::db()->query('SELECT `no`, `name`, `picture`, `imgsvr` FROM member WHERE grade >= 5') as $admin){
$db->insert('general', [ $db->insert('general', [
'owner'=>$admin['no'], 'owner'=>$admin['no'],
'name'=>$admin['name'], 'name'=>$admin['name'],
'picture'=>$admin['picture'], 'picture'=>$admin['picture'],
'imgsvr'=>$admin['imgsvr'], 'imgsvr'=>$admin['imgsvr'],
'turntime'=>$turntime, 'turntime'=>$turntime,
'killturn'=>9999, 'killturn'=>9999,
'crewtype'=>GameUnitConst::DEFAULT_CREWTYPE 'crewtype'=>GameUnitConst::DEFAULT_CREWTYPE
]); ]);
$generalID = $db->insertId(); $generalID = $db->insertId();
$turnRows = []; $turnRows = [];
foreach(Util::range(GameConst::$maxTurn) as $turnIdx){ foreach(Util::range(GameConst::$maxTurn) as $turnIdx){
$turnRows[] = [ $turnRows[] = [
'general_id'=>$generalID, 'general_id'=>$generalID,
'turn_idx'=>$turnIdx, 'turn_idx'=>$turnIdx,
'action'=>'휴식', 'action'=>'휴식',
'arg'=>null, 'arg'=>null,
'brief'=>'휴식' 'brief'=>'휴식'
]; ];
} }
$db->insert('general_turn', $turnRows); $db->insert('general_turn', $turnRows);
$rank_data = []; $rank_data = [];
foreach(array_keys(General::RANK_COLUMN) as $rankColumn){ foreach(array_keys(General::RANK_COLUMN) as $rankColumn){
$rank_data[] = [ $rank_data[] = [
'general_id'=>$generalID, 'general_id'=>$generalID,
'nation_id'=>0, 'nation_id'=>0,
'type'=>$rankColumn, 'type'=>$rankColumn,
'value'=>0 'value'=>0
]; ];
} }
$db->insert('rank_data', $rank_data); $db->insert('rank_data', $rank_data);
$db->insert('betting', [ $db->insert('betting', [
'general_id'=>$generalID, 'general_id'=>$generalID,
]); ]);
} }
foreach($env as $key=>$value){ foreach($env as $key=>$value){
$gameStor->$key = $value; $gameStor->$key = $value;
} }
$db->insert('ng_games', [ $db->insert('ng_games', [
'server_id'=>$serverID, 'server_id'=>$serverID,
'date'=>$turntime, 'date'=>$turntime,
'winner_nation'=>null, 'winner_nation'=>null,
'map'=>$scenarioObj->getMapTheme(), 'map'=>$scenarioObj->getMapTheme(),
'season'=>$seasonIdx, 'season'=>$seasonIdx,
'scenario'=>$scenario, 'scenario'=>$scenario,
'scenario_name'=>$scenarioObj->getTitle(), 'scenario_name'=>$scenarioObj->getTitle(),
'env'=>Json::encode($env) 'env'=>Json::encode($env)
]); ]);
$scenarioObj->build($env); $scenarioObj->build($env);
$db->update('plock', [ $db->update('plock', [
'plock'=>0 'plock'=>0
], true); ], true);
LogHistory(1); LogHistory(1);
$prefix = DB::prefix(); $prefix = DB::prefix();
AppConf::getList()[$prefix]->closeServer(); ServConfig::getServerList()[$prefix]->closeServer();
opcache_reset(); opcache_reset();
return [ return [
'result'=>true 'result'=>true
]; ];
} }
} }
+90 -90
View File
@@ -1,90 +1,90 @@
<?php <?php
namespace sammo; namespace sammo;
require(__DIR__.'/../vendor/autoload.php'); require(__DIR__.'/../vendor/autoload.php');
$session = Session::requireLogin([])->setReadOnly(); $session = Session::requireLogin([])->setReadOnly();
$userID = Session::getUserID(); $userID = Session::getUserID();
// 외부 파라미터 // 외부 파라미터
$db = RootDB::db(); $db = RootDB::db();
$member = $db->queryFirstRow('SELECT `id`, `name`, `grade`, `picture`, reg_date, third_use, acl, oauth_type, token_valid_until FROM `member` WHERE `NO` = %i', $userID); $member = $db->queryFirstRow('SELECT `id`, `name`, `grade`, `picture`, reg_date, third_use, acl, oauth_type, token_valid_until FROM `member` WHERE `NO` = %i', $userID);
if(!$member['picture']){ if(!$member['picture']){
$picture = ServConfig::getSharedIconPath().'/default.jpg'; $picture = ServConfig::getSharedIconPath().'/default.jpg';
} }
else{ else{
$picture = $member['picture']; $picture = $member['picture'];
if(strlen($picture) > 11){ if(strlen($picture) > 11){
$picture = substr($picture, 0, -10); $picture = substr($picture, 0, -10);
} }
$pictureFSPath = AppConf::getUserIconPathFS().'/'.$picture; $pictureFSPath = AppConf::getUserIconPathFS().'/'.$picture;
if(file_exists($pictureFSPath)){ if(file_exists($pictureFSPath)){
$picture = AppConf::getUserIconPathWeb().'/'.$picture; $picture = AppConf::getUserIconPathWeb().'/'.$picture;
} }
else{ else{
$picture = ServConfig::getSharedIconPath().'/'.$picture; $picture = ServConfig::getSharedIconPath().'/'.$picture;
} }
} }
$tokenValidUntil = $member['token_valid_until']; $tokenValidUntil = $member['token_valid_until'];
if($member['grade'] == 6) { if($member['grade'] == 6) {
$grade = '운영자'; $grade = '운영자';
} elseif($member['grade'] == 5) { } elseif($member['grade'] == 5) {
$grade = '부운영자'; $grade = '부운영자';
} elseif($member['grade'] > 1) { } elseif($member['grade'] > 1) {
$grade = '특별회원'; $grade = '특별회원';
} elseif($member['grade'] == 1) { } elseif($member['grade'] == 1) {
$grade = '일반회원'; $grade = '일반회원';
} elseif($member['grade'] == 0) { } elseif($member['grade'] == 0) {
$grade = '블럭회원'; $grade = '블럭회원';
} }
$acl = []; $acl = [];
//TODO: Acl을 관리하기 위한 별도의 객체 필요 //TODO: Acl을 관리하기 위한 별도의 객체 필요
foreach(Json::decode($member['acl']??'{}') as $serverName=>$aclList){ foreach(Json::decode($member['acl']??'{}') as $serverName=>$aclList){
$serverKorName = AppConf::getList()[$serverName]->getKorName(); $serverKorName = ServConfig::getServerList()[$serverName]->getKorName();
$aclTextList = array_map(function($aclName){ $aclTextList = array_map(function($aclName){
$aclText = "알수없음[{$aclName}]"; $aclText = "알수없음[{$aclName}]";
switch($aclName){ switch($aclName){
case 'openClose':$aclText='서버여닫기';break; case 'openClose':$aclText='서버여닫기';break;
case 'reset':$aclText='서버리셋';break; case 'reset':$aclText='서버리셋';break;
case 'update':$aclText='업데이트';break; case 'update':$aclText='업데이트';break;
case 'fullUpdate':$aclText='임의업데이트';break; case 'fullUpdate':$aclText='임의업데이트';break;
case 'vote':$aclText='설문조사';break; case 'vote':$aclText='설문조사';break;
case 'globalNotice':$aclText='전역공지';break; case 'globalNotice':$aclText='전역공지';break;
case 'notice':$aclText='공지';break; case 'notice':$aclText='공지';break;
case 'blockGeneral':$aclText='장수징계';break; case 'blockGeneral':$aclText='장수징계';break;
} }
return $aclText; return $aclText;
}, $aclList); }, $aclList);
$acl[] = sprintf("%s(%s)", $serverKorName, join(",", $aclTextList)); $acl[] = sprintf("%s(%s)", $serverKorName, join(",", $aclTextList));
} }
if($acl){ if($acl){
$acl = join(",<br>", $acl); $acl = join(",<br>", $acl);
} }
else{ else{
$acl = "-"; $acl = "-";
} }
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'reason'=>'success', 'reason'=>'success',
'id'=>$member['id'], 'id'=>$member['id'],
'name'=>$member['name'], 'name'=>$member['name'],
'grade'=>$grade, 'grade'=>$grade,
'picture'=>$picture, 'picture'=>$picture,
'global_salt'=>RootDB::getGlobalSalt(), 'global_salt'=>RootDB::getGlobalSalt(),
'join_date'=>$member['reg_date'], 'join_date'=>$member['reg_date'],
'third_use'=>($member['third_use']!=0), 'third_use'=>($member['third_use']!=0),
'acl'=>$acl, 'acl'=>$acl,
'oauth_type'=>$member['oauth_type'], 'oauth_type'=>$member['oauth_type'],
'token_valid_until'=>$tokenValidUntil 'token_valid_until'=>$tokenValidUntil
]); ]);
+57 -57
View File
@@ -1,58 +1,58 @@
<?php <?php
namespace sammo; namespace sammo;
require(__DIR__.'/../vendor/autoload.php'); require(__DIR__.'/../vendor/autoload.php');
$session = Session::requireLogin([])->setReadOnly(); $session = Session::requireLogin([])->setReadOnly();
$db = RootDB::db(); $db = RootDB::db();
if($session->userGrade < 5){ if($session->userGrade < 5){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'권한이 부족합니다' 'reason'=>'권한이 부족합니다'
]); ]);
} }
$userList = []; $userList = [];
foreach($db->query('SELECT member.*, max(member_log.date) as loginDate from member foreach($db->query('SELECT member.*, max(member_log.date) as loginDate from member
left join member_log on member.`NO` = member_log.member_no and member_log.action_type="login" left join member_log on member.`NO` = member_log.member_no and member_log.action_type="login"
group by member.no order by member.no asc') as $member){ group by member.no order by member.no asc') as $member){
if($member['IMGSVR']){ if($member['IMGSVR']){
$icon = AppConf::getUserIconPathWeb().'/'.$member['PICTURE']; $icon = AppConf::getUserIconPathWeb().'/'.$member['PICTURE'];
} }
else{ else{
$icon = ServConfig::getSharedIconPath().'/'.$member['PICTURE']; $icon = ServConfig::getSharedIconPath().'/'.$member['PICTURE'];
} }
$userList[] = [ $userList[] = [
'userID'=>$member['NO'], 'userID'=>$member['NO'],
'userName'=>$member['ID'], 'userName'=>$member['ID'],
'email'=>$member['EMAIL'], 'email'=>$member['EMAIL'],
'authType'=>$member['oauth_type'], 'authType'=>$member['oauth_type'],
'userGrade'=>$member['GRADE'], 'userGrade'=>$member['GRADE'],
'blockUntil'=>$member['BLOCK_DATE'], 'blockUntil'=>$member['BLOCK_DATE'],
'nickname'=>$member['NAME'], 'nickname'=>$member['NAME'],
'icon'=>$icon, 'icon'=>$icon,
'joinDate'=>$member['REG_DATE'], 'joinDate'=>$member['REG_DATE'],
'loginDate'=>$member['loginDate'], 'loginDate'=>$member['loginDate'],
'deleteAfter'=>$member['delete_after'] 'deleteAfter'=>$member['delete_after']
]; ];
} }
$serverList = []; $serverList = [];
foreach(AppConf::getList() as $serverName => $setting){ foreach(ServConfig::getServerList() as $serverName => $setting){
if($setting->isRunning()){ if($setting->isRunning()){
$serverList[] = $serverName; $serverList[] = $serverName;
} }
} }
$system = $db->queryFirstRow('SELECT `REG`, `LOGIN` FROM `system` limit 1'); $system = $db->queryFirstRow('SELECT `REG`, `LOGIN` FROM `system` limit 1');
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'users'=>$userList, 'users'=>$userList,
'servers'=>$serverList, 'servers'=>$serverList,
'allowJoin'=>$system['REG']=='Y', 'allowJoin'=>$system['REG']=='Y',
'allowLogin'=>$system['LOGIN']=='Y' 'allowLogin'=>$system['LOGIN']=='Y'
]); ]);
+106 -106
View File
@@ -1,107 +1,107 @@
<?php <?php
namespace sammo; namespace sammo;
require(__DIR__.'/../vendor/autoload.php'); require(__DIR__.'/../vendor/autoload.php');
WebUtil::requireAJAX(); WebUtil::requireAJAX();
$session = Session::requireLogin([])->setReadOnly(); $session = Session::requireLogin([])->setReadOnly();
$userID = Session::getUserID(); $userID = Session::getUserID();
// 외부 파라미터 // 외부 파라미터
// $_FILES['image_upload'] : 사진파일 // $_FILES['image_upload'] : 사진파일
$defaultImg = 'default.jpg'; $defaultImg = 'default.jpg';
$image = $_FILES['image_upload']; $image = $_FILES['image_upload'];
$ext = strrchr($image['name'], "."); $ext = strrchr($image['name'], ".");
$size = getImageSize($image['tmp_name']); $size = getImageSize($image['tmp_name']);
$imageType = $size[2]; $imageType = $size[2];
$availableImageType = array('.jpg'=>IMAGETYPE_JPEG, '.png'=>IMAGETYPE_PNG, '.gif'=>IMAGETYPE_GIF); $availableImageType = array('.jpg'=>IMAGETYPE_JPEG, '.png'=>IMAGETYPE_PNG, '.gif'=>IMAGETYPE_GIF);
$db = RootDB::db(); $db = RootDB::db();
$member = $db->queryFirstRow('SELECT `ID`, `PICTURE` FROM `member` WHERE `NO` = %i', $userID); $member = $db->queryFirstRow('SELECT `ID`, `PICTURE` FROM `member` WHERE `NO` = %i', $userID);
$picName = $member['PICTURE']; $picName = $member['PICTURE'];
$newExt = array_search($imageType, $availableImageType, true); $newExt = array_search($imageType, $availableImageType, true);
if($picName && strlen($picName) > 11){ if($picName && strlen($picName) > 11){
$dt = substr($picName, -8); $dt = substr($picName, -8);
$picName = substr($picName, 0, -10); $picName = substr($picName, 0, -10);
} }
else{ else{
$dt = '00000000'; $dt = '00000000';
} }
$rf = date('Ymd'); $rf = date('Ymd');
$response['result'] = false; $response['result'] = false;
$response['reason'] = '요청이 올바르지 않습니다!'; $response['reason'] = '요청이 올바르지 않습니다!';
if(!is_uploaded_file($image['tmp_name'])) { if(!is_uploaded_file($image['tmp_name'])) {
//진짜 전송된 파일인지 검증 //진짜 전송된 파일인지 검증
$response['reason'] = '업로드가 되지 않았습니다!'; $response['reason'] = '업로드가 되지 않았습니다!';
$response['result'] = false; $response['result'] = false;
} elseif(!$newExt) { } elseif(!$newExt) {
//확장자 검사 //확장자 검사
$response['reason'] = 'jpg, gif, png 파일이 아닙니다!'; $response['reason'] = 'jpg, gif, png 파일이 아닙니다!';
$response['result'] = false; $response['result'] = false;
} elseif($image['size'] > 30720) { } elseif($image['size'] > 30720) {
//파일크기 검사 //파일크기 검사
$response['reason'] = '30kb 이하로 올려주세요!'; $response['reason'] = '30kb 이하로 올려주세요!';
$response['result'] = false; $response['result'] = false;
} elseif($size[0] < 64 || 128 < $size[0]) { } elseif($size[0] < 64 || 128 < $size[0]) {
//이미지크기 검사 //이미지크기 검사
$response['reason'] = '64x64 ~ 128x128 사이여야 합니다.'; $response['reason'] = '64x64 ~ 128x128 사이여야 합니다.';
$response['result'] = false; $response['result'] = false;
} elseif($size[0] != $size[1]) { } elseif($size[0] != $size[1]) {
//이미지크기 검사 //이미지크기 검사
$response['reason'] = '1:1 비율 이미지여야 합니다.'; $response['reason'] = '1:1 비율 이미지여야 합니다.';
$response['result'] = false; $response['result'] = false;
}elseif($dt == $rf) { }elseif($dt == $rf) {
//갱신날짜 검사 //갱신날짜 검사
$response['reason'] = '1일 1회 변경 가능합니다!'; $response['reason'] = '1일 1회 변경 가능합니다!';
$response['result'] = false; $response['result'] = false;
} else { } else {
//이미지 저장 //이미지 저장
while(true){ while(true){
$newPicName = dechex(rand(0x000000f,0xfffffff)).$newExt; $newPicName = dechex(rand(0x000000f,0xfffffff)).$newExt;
$dest = AppConf::getUserIconPathFS().'/'.$newPicName; $dest = AppConf::getUserIconPathFS().'/'.$newPicName;
if(file_exists($dest)){ if(file_exists($dest)){
continue; continue;
} }
break; break;
} }
if(!move_uploaded_file($image['tmp_name'], $dest)) { if(!move_uploaded_file($image['tmp_name'], $dest)) {
$response['reason'] = '업로드에 실패했습니다!'; $response['reason'] = '업로드에 실패했습니다!';
$response['result'] = false; $response['result'] = false;
} else { } else {
$pic = "{$newPicName}?={$rf}"; $pic = "{$newPicName}?={$rf}";
RootDB::db()->update('member',[ RootDB::db()->update('member',[
'PICTURE' => $pic, 'PICTURE' => $pic,
'IMGSVR' => 1 'IMGSVR' => 1
], 'NO=%i', $userID); ], 'NO=%i', $userID);
$servers = []; $servers = [];
foreach(AppConf::getList() as $key=>$setting){ foreach(ServConfig::getServerList() as $key=>$setting){
if($setting->isRunning()){ if($setting->isRunning()){
$servers[] = [$key, $setting->getKorName()]; $servers[] = [$key, $setting->getKorName()];
} }
} }
$response['servers'] = $servers; $response['servers'] = $servers;
$response['reason'] = '업로드에 성공했습니다!'; $response['reason'] = '업로드에 성공했습니다!';
$response['result'] = true; $response['result'] = true;
} }
} }
Json::die($response); Json::die($response);
+55 -55
View File
@@ -1,56 +1,56 @@
<?php <?php
namespace sammo; namespace sammo;
require(__DIR__.'/../vendor/autoload.php'); require(__DIR__.'/../vendor/autoload.php');
WebUtil::requireAJAX(); WebUtil::requireAJAX();
$session = Session::requireLogin([])->setReadOnly(); $session = Session::requireLogin([])->setReadOnly();
$userID = Session::getUserID(); $userID = Session::getUserID();
// 외부 파라미터 // 외부 파라미터
$respone = []; $respone = [];
$db = RootDB::db(); $db = RootDB::db();
$picName = $db->queryFirstField('SELECT picture FROM `member` WHERE `NO` = %i', $userID); $picName = $db->queryFirstField('SELECT picture FROM `member` WHERE `NO` = %i', $userID);
if($picName && strlen($picName) > 11){ if($picName && strlen($picName) > 11){
$dt = substr($picName, -8); $dt = substr($picName, -8);
$picName = substr($picName, 0, -10); $picName = substr($picName, 0, -10);
} }
else{ else{
$dt = '00000000'; $dt = '00000000';
} }
$dest = AppConf::getUserIconPathFS().'/'.$picName; $dest = AppConf::getUserIconPathFS().'/'.$picName;
$rf = date('Ymd'); $rf = date('Ymd');
$response['result'] = false; $response['result'] = false;
$response['reason'] = '요청이 올바르지 않습니다!'; $response['reason'] = '요청이 올바르지 않습니다!';
if($dt == $rf) { if($dt == $rf) {
//갱신날짜 검사 //갱신날짜 검사
$response['reason'] = '1일 1회 변경 가능합니다!'; $response['reason'] = '1일 1회 변경 가능합니다!';
$response['result'] = false; $response['result'] = false;
} else { } else {
$db->update('member', [ $db->update('member', [
'PICTURE'=>'default.jpg', 'PICTURE'=>'default.jpg',
'IMGSVR'=>0, 'IMGSVR'=>0,
], 'NO=%i', $userID); ], 'NO=%i', $userID);
$servers = []; $servers = [];
foreach(AppConf::getList() as $key=>$setting){ foreach(ServConfig::getServerList() as $key=>$setting){
if($setting->isRunning()){ if($setting->isRunning()){
$servers[] = [$key, $setting->getKorName()]; $servers[] = [$key, $setting->getKorName()];
} }
} }
$response['servers'] = $servers; $response['servers'] = $servers;
$response['reason'] = '제거에 성공했습니다!'; $response['reason'] = '제거에 성공했습니다!';
$response['result'] = true; $response['result'] = true;
} }
Json::die($response); Json::die($response);
+117 -117
View File
@@ -1,117 +1,117 @@
<?php <?php
namespace sammo; namespace sammo;
require(__DIR__.'/../vendor/autoload.php'); require(__DIR__.'/../vendor/autoload.php');
WebUtil::requireAJAX(); WebUtil::requireAJAX();
$session = Session::requireLogin(null); $session = Session::requireLogin(null);
// 외부 파라미터 // 외부 파라미터
// $_POST['action'] : 'notice', 'open', 'close', 'reset', 'reset_full' // $_POST['action'] : 'notice', 'open', 'close', 'reset', 'reset_full'
// $_POST['notice'] : 공지 // $_POST['notice'] : 공지
// $_POST['server'] : 서버 인덱스 // $_POST['server'] : 서버 인덱스
$action = Util::getPost('action', 'string', ''); $action = Util::getPost('action', 'string', '');
$notice = Util::getPost('notice', 'string', ''); $notice = Util::getPost('notice', 'string', '');
$server = Util::getPost('server', 'string', ''); $server = Util::getPost('server', 'string', '');
$db = RootDB::db(); $db = RootDB::db();
$userGrade = $session->userGrade; $userGrade = $session->userGrade;
$acl = $session->acl; $acl = $session->acl;
$session->setReadOnly(); $session->setReadOnly();
if($userGrade < 5 && !$acl) { if($userGrade < 5 && !$acl) {
Json::die([ Json::die([
'result'=>'FAIL', 'result'=>'FAIL',
'msg'=>'운영자 권한이 없습니다.' 'msg'=>'운영자 권한이 없습니다.'
]); ]);
} }
function doServerModeSet($server, $action, &$response, $session){ function doServerModeSet($server, $action, &$response, $session){
$serverList = AppConf::getList(); $serverList = ServConfig::getServerList();
$settingObj = $serverList[$server]; $settingObj = $serverList[$server];
$serverAcl = $session->acl[$server]??[]; $serverAcl = $session->acl[$server]??[];
$userGrade = $session->userGrade; $userGrade = $session->userGrade;
$serverDir = $settingObj->getShortName(); $serverDir = $settingObj->getShortName();
$serverPath = $settingObj->getBasePath(); $serverPath = $settingObj->getBasePath();
$realServerPath = realpath(dirname(__FILE__)).'/'.$serverPath; $realServerPath = realpath(dirname(__FILE__)).'/'.$serverPath;
if($action == 'close') { //폐쇄 if($action == 'close') { //폐쇄
$doClose = false; $doClose = false;
if($userGrade >= 5){ if($userGrade >= 5){
$doClose = true; $doClose = true;
} }
else if(in_array('openClose', $serverAcl)){ else if(in_array('openClose', $serverAcl)){
$doClose = true; $doClose = true;
} }
if(!$doClose && in_array('reset', $serverAcl) && file_exists($serverPath.'/d_setting/DB.php')){ if(!$doClose && in_array('reset', $serverAcl) && file_exists($serverPath.'/d_setting/DB.php')){
require($serverPath.'/lib.php'); require($serverPath.'/lib.php');
$localGameStorage = KVStorage::getStorage(DB::db(), 'game_env'); $localGameStorage = KVStorage::getStorage(DB::db(), 'game_env');
//천통 이후, 오픈 직후는 닫을 수 있음 //천통 이후, 오픈 직후는 닫을 수 있음
$localGameStorage->cacheValues(['isunited', 'startyear', 'year']); $localGameStorage->cacheValues(['isunited', 'startyear', 'year']);
if($localGameStorage->isunited){ if($localGameStorage->isunited){
$doClose = true; $doClose = true;
} }
else if($localGameStorage->year < $localGameStorage->startyear + 2){ else if($localGameStorage->year < $localGameStorage->startyear + 2){
$doClose = true; $doClose = true;
} }
} }
if(!$doClose){ if(!$doClose){
if(in_array('reset', $serverAcl)){ if(in_array('reset', $serverAcl)){
$response['msg'] = '서버 시작 직후, 또는 천하통일 이후에만 닫을 수 있습니다.'; $response['msg'] = '서버 시작 직후, 또는 천하통일 이후에만 닫을 수 있습니다.';
} }
else{ else{
$response['msg'] = '서버 닫기 권한이 부족합니다.'; $response['msg'] = '서버 닫기 권한이 부족합니다.';
} }
return false; return false;
} }
return $settingObj->closeServer(); return $settingObj->closeServer();
} elseif($action == 'reset' && $userGrade >= 6) {//리셋 } elseif($action == 'reset' && $userGrade >= 6) {//리셋
//FIXME: reset, reset_full 구현 //FIXME: reset, reset_full 구현
if(file_exists($serverPath.'/d_setting/DB.php')){ if(file_exists($serverPath.'/d_setting/DB.php')){
@unlink($serverPath.'/d_setting/DB.php'); @unlink($serverPath.'/d_setting/DB.php');
} }
$response['installURL'] = $serverDir."/install.php"; $response['installURL'] = $serverDir."/install.php";
} elseif($action == 'open' && ($userGrade >= 5 || in_array('openClose', $serverAcl))) {//오픈 } elseif($action == 'open' && ($userGrade >= 5 || in_array('openClose', $serverAcl))) {//오픈
return $settingObj->openServer(); return $settingObj->openServer();
} else{ } else{
$response['msg'] = '올바르지 않은 요청입니다'; $response['msg'] = '올바르지 않은 요청입니다';
return false; return false;
} }
return true; return true;
} }
function doAdminPost($action, $notice, $server, $session){ function doAdminPost($action, $notice, $server, $session){
$response = ['result' => 'FAIL']; $response = ['result' => 'FAIL'];
$globalAcl = $session->acl['global']??[]; $globalAcl = $session->acl['global']??[];
$userGrade = $session->userGrade; $userGrade = $session->userGrade;
if($action == 'notice' && ($userGrade >= 5 || in_array('notice', $globalAcl))) { if($action == 'notice' && ($userGrade >= 5 || in_array('notice', $globalAcl))) {
RootDB::db()->update('system', ['NOTICE'=>$notice], true); RootDB::db()->update('system', ['NOTICE'=>$notice], true);
$response['result'] = 'SUCCESS'; $response['result'] = 'SUCCESS';
return $response; return $response;
} }
if(doServerModeSet($server, $action, $response, $session)){ if(doServerModeSet($server, $action, $response, $session)){
$response['result'] = 'SUCCESS'; $response['result'] = 'SUCCESS';
return $response; return $response;
} }
return $response; return $response;
} }
$response = doAdminPost($action, $notice, $server, $session); $response = doAdminPost($action, $notice, $server, $session);
Json::die($response); Json::die($response);
+89 -89
View File
@@ -1,90 +1,90 @@
<?php <?php
namespace sammo; namespace sammo;
require(__DIR__.'/../vendor/autoload.php'); require(__DIR__.'/../vendor/autoload.php');
WebUtil::requireAJAX(); WebUtil::requireAJAX();
$session = Session::requireLogin([])->setReadOnly(); $session = Session::requireLogin([])->setReadOnly();
if($session->userGrade < 5 && !$session->acl){ if($session->userGrade < 5 && !$session->acl){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'권한이 부족합니다.' 'reason'=>'권한이 부족합니다.'
]); ]);
} }
$result = []; $result = [];
$server = []; $server = [];
$storage = new \sammo\KVStorage(RootDB::db(), 'git_path'); $storage = new \sammo\KVStorage(RootDB::db(), 'git_path');
$serverGitPath = $storage->getAll(); $serverGitPath = $storage->getAll();
$rootServer = Util::array_last(AppConf::getList())->getShortName(); $rootServer = Util::array_last(ServConfig::getServerList())->getShortName();
foreach (AppConf::getList() as $setting) { foreach (ServConfig::getServerList() as $setting) {
$serverColor = $setting->getColor(); $serverColor = $setting->getColor();
$serverKorName = $setting->getKorName(); $serverKorName = $setting->getKorName();
$serverPath = $setting->getBasePath(); $serverPath = $setting->getBasePath();
$serverDir = $setting->getShortName(); $serverDir = $setting->getShortName();
//TODO: .htaccess가 서버 오픈에도 사용될 수 있으니 별도의 방법이 필요함 //TODO: .htaccess가 서버 오픈에도 사용될 수 있으니 별도의 방법이 필요함
if (!is_dir($serverPath)) { if (!is_dir($serverPath)) {
$state = [ $state = [
'valid'=>false, 'valid'=>false,
'run'=>false, 'run'=>false,
'installed'=>false, 'installed'=>false,
'version'=>$setting->getVersion(), 'version'=>$setting->getVersion(),
'reason'=>'디렉토리 없음' 'reason'=>'디렉토리 없음'
]; ];
} elseif (!file_exists($serverPath.'/index.php')) { } elseif (!file_exists($serverPath.'/index.php')) {
$state = [ $state = [
'valid'=>false, 'valid'=>false,
'run'=>false, 'run'=>false,
'installed'=>false, 'installed'=>false,
'version'=>$setting->getVersion(), 'version'=>$setting->getVersion(),
'reason'=>'index.php 없음' 'reason'=>'index.php 없음'
]; ];
} elseif (!$setting->isExists()) { } elseif (!$setting->isExists()) {
$state = [ $state = [
'valid'=>false, 'valid'=>false,
'run'=>false, 'run'=>false,
'installed'=>true, 'installed'=>true,
'version'=>$setting->getVersion(), 'version'=>$setting->getVersion(),
'reason'=>'설정 파일 없음' 'reason'=>'설정 파일 없음'
]; ];
} elseif (!$setting->isRunning()) { } elseif (!$setting->isRunning()) {
// 폐쇄중 // 폐쇄중
$state = [ $state = [
'valid'=>true, 'valid'=>true,
'run'=>false, 'run'=>false,
'installed'=>true, 'installed'=>true,
'version'=>$setting->getVersion(), 'version'=>$setting->getVersion(),
'reason'=>'폐쇄됨' 'reason'=>'폐쇄됨'
]; ];
} else { } else {
// 오픈중 // 오픈중
$state = [ $state = [
'valid'=>true, 'valid'=>true,
'run'=>true, 'run'=>true,
'installed'=>true, 'installed'=>true,
'version'=>$setting->getVersion(), 'version'=>$setting->getVersion(),
'reason'=>'운영중' 'reason'=>'운영중'
]; ];
} }
$state += [ $state += [
'name' => $serverDir, 'name' => $serverDir,
'korName' => $serverKorName, 'korName' => $serverKorName,
'color' => $serverColor, 'color' => $serverColor,
'isRoot' => $serverDir == $rootServer, 'isRoot' => $serverDir == $rootServer,
'lastGitPath' => ($serverGitPath[$serverDir][0])??($serverDir == $rootServer?'devel':'origin/devel') 'lastGitPath' => ($serverGitPath[$serverDir][0])??($serverDir == $rootServer?'devel':'origin/devel')
]; ];
$server[] = $state; $server[] = $state;
} }
Json::die([ Json::die([
'acl' => $session->acl, 'acl' => $session->acl,
'server' => $server, 'server' => $server,
'grade' => $session->userGrade 'grade' => $session->userGrade
]); ]);
+25 -25
View File
@@ -1,25 +1,25 @@
<?php <?php
namespace sammo; namespace sammo;
require(__DIR__.'/../vendor/autoload.php'); require(__DIR__.'/../vendor/autoload.php');
// 외부 파라미터 // 외부 파라미터
$response['server'] = []; $response['server'] = [];
foreach(AppConf::getList() as $setting){ foreach(ServConfig::getServerList() as $setting){
$serverObj = [ $serverObj = [
'color'=>$setting->getColor(), 'color'=>$setting->getColor(),
'korName'=>$setting->getKorName(), 'korName'=>$setting->getKorName(),
'name'=>$setting->getShortName(), 'name'=>$setting->getShortName(),
'exists'=>$setting->isExists(), 'exists'=>$setting->isExists(),
'enable'=>$setting->isRunning() 'enable'=>$setting->isRunning()
]; ];
$response['server'][] = $serverObj; $response['server'][] = $serverObj;
} }
$response['result'] = 'SUCCESS'; $response['result'] = 'SUCCESS';
Json::die($response); Json::die($response);
+240 -240
View File
@@ -1,240 +1,240 @@
<?php <?php
namespace sammo; namespace sammo;
require(__DIR__ . '/vendor/autoload.php'); require(__DIR__ . '/vendor/autoload.php');
WebUtil::requireAJAX(); WebUtil::requireAJAX();
function getVersion($target = null) function getVersion($target = null)
{ {
if ($target) { if ($target) {
$command = sprintf('git describe %s --long --tags', escapeshellarg($target)); $command = sprintf('git describe %s --long --tags', escapeshellarg($target));
} else { } else {
$command = 'git describe --long --tags'; $command = 'git describe --long --tags';
} }
exec($command, $output); exec($command, $output);
if (is_array($output)) { if (is_array($output)) {
$output = join('', $output); $output = join('', $output);
} }
return trim($output); return trim($output);
} }
$session = Session::requireLogin(null)->setReadOnly(); $session = Session::requireLogin(null)->setReadOnly();
$request = $_POST + $_GET; $request = $_POST + $_GET;
$rootDB = RootDB::db(); $rootDB = RootDB::db();
$storage = new \sammo\KVStorage($rootDB, 'git_path'); $storage = new \sammo\KVStorage($rootDB, 'git_path');
$tmpFile = 'd_log/arc.zip'; $tmpFile = 'd_log/arc.zip';
$v = new Validator($request); $v = new Validator($request);
$v->rule('required', [ $v->rule('required', [
'server' 'server'
])->rule('regex', 'target', '/^[0-9a-zA-Z^{}\\/\-_,.@]+$/'); ])->rule('regex', 'target', '/^[0-9a-zA-Z^{}\\/\-_,.@]+$/');
if (!$v->validate()) { if (!$v->validate()) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => $v->errorStr() 'reason' => $v->errorStr()
]); ]);
} }
$target = Util::getPost('target'); $target = Util::getPost('target');
$server = basename($request['server']); $server = basename($request['server']);
$allowFullUpdate = in_array('fullUpdate', $session->acl[$server] ?? []); $allowFullUpdate = in_array('fullUpdate', $session->acl[$server] ?? []);
$allowFullUpdate |= $session->userGrade >= 6; $allowFullUpdate |= $session->userGrade >= 6;
$allowUpdate = in_array('update', $session->acl[$server] ?? []); $allowUpdate = in_array('update', $session->acl[$server] ?? []);
$allowUpdate |= $session->userGrade >= 5; $allowUpdate |= $session->userGrade >= 5;
$allowUpdate |= $allowFullUpdate; $allowUpdate |= $allowFullUpdate;
if (!$allowUpdate) { if (!$allowUpdate) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => '권한이 충분하지 않습니다' 'reason' => '권한이 충분하지 않습니다'
]); ]);
} }
$src_target = $storage->$server; $src_target = $storage->$server;
if ($src_target) { if ($src_target) {
$src_target = $src_target[0]; $src_target = $src_target[0];
} }
if (!$allowFullUpdate || !$target) { if (!$allowFullUpdate || !$target) {
$target = $src_target; $target = $src_target;
} else { } else {
$target = $request['target']; $target = $request['target'];
} }
$baseServerName = Util::array_last_key(AppConf::getList()); $baseServerName = Util::array_last_key(ServConfig::getServerList());
if (!$target && $server != $baseServerName) { if (!$target && $server != $baseServerName) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => 'git -ish target이 제대로 지정되지 않았습니다.' 'reason' => 'git -ish target이 제대로 지정되지 않았습니다.'
]); ]);
} }
$targetDir = $target . ':' . $baseServerName; $targetDir = $target . ':' . $baseServerName;
if (!key_exists($server, AppConf::getList())) { if (!key_exists($server, ServConfig::getServerList())) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => '불가능한 서버 이름입니다.' 'reason' => '불가능한 서버 이름입니다.'
]); ]);
} }
if (\file_exists($server) && !is_dir($server)) { if (\file_exists($server) && !is_dir($server)) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => '같은 이름을 가진 파일이 있습니다.' 'reason' => '같은 이름을 가진 파일이 있습니다.'
]); ]);
} }
if (file_exists($server) && !is_writable($server)) { if (file_exists($server) && !is_writable($server)) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => $server . ' 디렉토리 쓰기 권한이 없습니다.' 'reason' => $server . ' 디렉토리 쓰기 권한이 없습니다.'
]); ]);
} }
if (!file_exists($server)) { if (!file_exists($server)) {
if (!is_writable('.')) { if (!is_writable('.')) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => $server . ' 디렉토리가 없지만 생성할 권한이 없습니다.' 'reason' => $server . ' 디렉토리가 없지만 생성할 권한이 없습니다.'
]); ]);
} }
mkdir($server, 0755); mkdir($server, 0755);
} }
if ($server == $baseServerName) { if ($server == $baseServerName) {
exec("git fetch -q 2>&1", $output); exec("git fetch -q 2>&1", $output);
if ($output) { if ($output) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => 'git pull 작업 : ' . join(', ', $output) 'reason' => 'git pull 작업 : ' . join(', ', $output)
]); ]);
} }
if ($target != $src_target) { if ($target != $src_target) {
$command = sprintf('git checkout %s -q 2>&1', $target); $command = sprintf('git checkout %s -q 2>&1', $target);
exec($command, $output); exec($command, $output);
if ($output) { if ($output) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => join(', ', $output) 'reason' => join(', ', $output)
]); ]);
} }
} }
exec("git pull -q 2>&1", $output); exec("git pull -q 2>&1", $output);
if ($output && $output[0] != 'Already up-to-date.') { if ($output && $output[0] != 'Already up-to-date.') {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => 'git pull 작업 : ' . join(', ', $output) 'reason' => 'git pull 작업 : ' . join(', ', $output)
]); ]);
} }
$version = getVersion(); $version = getVersion();
$result = Util::generateFileUsingSimpleTemplate( $result = Util::generateFileUsingSimpleTemplate(
__DIR__ . '/' . $server . '/d_setting/VersionGit.orig.php', __DIR__ . '/' . $server . '/d_setting/VersionGit.orig.php',
__DIR__ . '/' . $server . '/d_setting/VersionGit.php', __DIR__ . '/' . $server . '/d_setting/VersionGit.php',
[ [
'verionGit' => $version 'verionGit' => $version
], ],
true true
); );
if (ServConfig::$imageRequestKey) { if (ServConfig::$imageRequestKey) {
try { try {
$imagePullPath = ServConfig::getImagePullURI(); $imagePullPath = ServConfig::getImagePullURI();
$pullResult = @file_get_contents($imagePullPath); $pullResult = @file_get_contents($imagePullPath);
if ($pullResult === false) { if ($pullResult === false) {
throw new \ErrorException('Invalid URI'); throw new \ErrorException('Invalid URI');
} }
$pullResult = Json::decode($pullResult); $pullResult = Json::decode($pullResult);
if ($pullResult['result']) { if ($pullResult['result']) {
$imgResult = true; $imgResult = true;
$imgDetail = $pullResult['version']; $imgDetail = $pullResult['version'];
} else { } else {
$imgResult = false; $imgResult = false;
$imgDetail = $pullResult['reason']; $imgDetail = $pullResult['reason'];
} }
} catch (\Exception $e) { } catch (\Exception $e) {
$imgResult = false; $imgResult = false;
$imgDetail = $e->getMessage(); $imgDetail = $e->getMessage();
} }
} else { } else {
$imgResult = true; $imgResult = true;
$imgDetail = 'No key'; $imgDetail = 'No key';
} }
$storage->$server = [$target, $version]; $storage->$server = [$target, $version];
opcache_reset(); opcache_reset();
Json::die([ Json::die([
'server' => $server, 'server' => $server,
'result' => true, 'result' => true,
'version' => $version, 'version' => $version,
'imgResult' => $imgResult, 'imgResult' => $imgResult,
'imgDetail' => $imgDetail, 'imgDetail' => $imgDetail,
]); ]);
} }
$command = sprintf('git archive --format=zip -o %s %s', escapeshellarg($tmpFile), escapeshellarg($targetDir)); $command = sprintf('git archive --format=zip -o %s %s', escapeshellarg($tmpFile), escapeshellarg($targetDir));
exec("$command 2>&1", $output); exec("$command 2>&1", $output);
if ($output) { if ($output) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => join(', ', $output) 'reason' => join(', ', $output)
]); ]);
} }
$zip = new \ZipArchive; $zip = new \ZipArchive;
if ($zip->open($tmpFile) !== true) { if ($zip->open($tmpFile) !== true) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => 'archive가 생성되지 않았습니다.' 'reason' => 'archive가 생성되지 않았습니다.'
]); ]);
} }
if (!$zip->extractTo($server)) { if (!$zip->extractTo($server)) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => '생성한 archive를 제대로 옮기지 못했습니다.' 'reason' => '생성한 archive를 제대로 옮기지 못했습니다.'
]); ]);
} }
$zip->close(); $zip->close();
@unlink($tmpFile); @unlink($tmpFile);
$version = getVersion($target); $version = getVersion($target);
$result = Util::generateFileUsingSimpleTemplate( $result = Util::generateFileUsingSimpleTemplate(
__DIR__ . '/' . $server . '/d_setting/VersionGit.orig.php', __DIR__ . '/' . $server . '/d_setting/VersionGit.orig.php',
__DIR__ . '/' . $server . '/d_setting/VersionGit.php', __DIR__ . '/' . $server . '/d_setting/VersionGit.php',
[ [
'verionGit' => $version 'verionGit' => $version
], ],
true true
); );
$storage->$server = [$target, $version]; $storage->$server = [$target, $version];
//AppConf::getList()[$server]->closeServer(); //ServConfig::getServerList()[$server]->closeServer();
opcache_reset(); opcache_reset();
Json::die([ Json::die([
'server' => $server, 'server' => $server,
'result' => true, 'result' => true,
'version' => $version 'version' => $version
]); ]);
+69 -79
View File
@@ -1,79 +1,69 @@
<?php <?php
namespace sammo; namespace sammo;
class AppConf class AppConf
{ {
private static $serverList = null; private static $serverList = null;
/** @var string 전용 아이콘 경로 */ /** @var string 전용 아이콘 경로 */
public static $userIconPath = 'd_pic'; public static $userIconPath = 'd_pic';
/** /**
* 서버 설정 반환 * 서버 설정 반환
* *
* @return \sammo\Setting[] * @deprecated
*/ * @return \sammo\Setting[]
public static function getList() */
{ public static function getList()
if (self::$serverList === null) { {
self::$serverList = [ return ServConfig::getServerList();
'che'=>new Setting(ROOT.'/che', '체', 'white'), }
'kwe'=>new Setting(ROOT.'/kwe', '퀘', 'yellow'),
'pwe'=>new Setting(ROOT.'/pwe', '풰', 'orange'), /**
'twe'=>new Setting(ROOT.'/twe', '퉤', 'magenta'), * DB 객체 생성
'nya'=>new Setting(ROOT.'/nya', '냐', '#e67e22'), *
'pya'=>new Setting(ROOT.'/pya', '퍄', '#9b59b6'), * @return \MeekroDB
'hwe'=>new Setting(ROOT.'/hwe', '훼', 'red') */
]; public static function requireRootDB()
} {
return self::$serverList; if (!class_exists('\\sammo\\RootDB')) {
} if(!trigger_error('RootDB.php가 설정되지 않았습니다.', E_USER_ERROR)){
die();
/** }
* DB 객체 생성
* }
* @return \MeekroDB return RootDB::db();
*/ }
public static function requireRootDB()
{ /**
if (!class_exists('\\sammo\\RootDB')) { * DB 객체 생성
if(!trigger_error('RootDB.php가 설정되지 않았습니다.', E_USER_ERROR)){ *
die(); * @return \MeekroDB
} */
public static function requireDB()
} {
return RootDB::db(); if (!class_exists('\\sammo\\DB')) {
} if(!trigger_error('DB.php가 설정되지 않았습니다.', E_USER_ERROR)){
die();
/** }
* DB 객체 생성
* }
* @return \MeekroDB return DB::db();
*/ }
public static function requireDB()
{ public static function getUserIconPathFS(string $filepath='') : string{
if (!class_exists('\\sammo\\DB')) { $path = ROOT.'/'.static::$userIconPath;
if(!trigger_error('DB.php가 설정되지 않았습니다.', E_USER_ERROR)){ if($filepath){
die(); $path .= '/'.$filepath;
} }
return $path;
} }
return DB::db();
} public static function getUserIconPathWeb(string $filepath='') : string{
$path = ServConfig::$serverWebPath.'/'.static::$userIconPath;
public static function getUserIconPathFS(string $filepath='') : string{ if($filepath){
$path = ROOT.'/'.static::$userIconPath; $path .= '/'.$filepath;
if($filepath){ }
$path .= '/'.$filepath; return $path;
} }
return $path; }
}
public static function getUserIconPathWeb(string $filepath='') : string{
$path = ServConfig::$serverWebPath.'/'.static::$userIconPath;
if($filepath){
$path .= '/'.$filepath;
}
return $path;
}
}
+813 -807
View File
@@ -1,807 +1,813 @@
<?php <?php
namespace sammo; namespace sammo;
class Util extends \utilphp\util class Util extends \utilphp\util
{ {
/** /**
* int 값 반환을 강제하는 부동소수점 반올림 * int 값 반환을 강제하는 부동소수점 반올림
* @param int|float $value * @param int|float $value
* @param int $pos 반올림 자리수, 0 이하의 '음수만' * @param int $pos 반올림 자리수, 0 이하의 '음수만'
*/ */
public static function round($value, $pos=0) : int{ public static function round($value, $pos=0) : int{
assert($pos <= 0, 'Util::round는 음수만 입력 가능'); assert($pos <= 0, 'Util::round는 음수만 입력 가능');
return intval(round($value, $pos)); return intval(round($value, $pos));
} }
/** /**
* int 값으로 강제로 설정하는 부동소수점 반올림 * int 값으로 강제로 설정하는 부동소수점 반올림
* @param int|float $value * @param int|float $value
* @param int $pos 반올림 자리수, 0 이하의 '음수만' * @param int $pos 반올림 자리수, 0 이하의 '음수만'
*/ */
public static function setRound(&$value, $pos=0) : void{ public static function setRound(&$value, $pos=0) : void{
$value = static::round($value, $pos); $value = static::round($value, $pos);
} }
private static function _parseReq($value, string $type) private static function _parseReq($value, string $type)
{ {
if (is_array($value)) { if (is_array($value)) {
if ($type === 'array_int') { if ($type === 'array_int') {
return array_map('intval', $value); return array_map('intval', $value);
} }
if ($type === 'array_string') { if ($type === 'array_string') {
return array_map(function ($item) { return array_map(function ($item) {
return (string)$item; return (string)$item;
}, $value); }, $value);
} }
if ($type === 'array') { if ($type === 'array') {
return $value; return $value;
} }
throw new \InvalidArgumentException('지원할 수 없는 type 지정. array 가 붙은 type이어야 합니다'); throw new \InvalidArgumentException('지원할 수 없는 type 지정. array 가 붙은 type이어야 합니다');
} }
if ($type === 'bool') { if ($type === 'bool') {
$value = strtolower($value); $value = strtolower($value);
if ($value === null || $value === '' || $value === 'off' || $value === 'false' || $value === 'no' || $value === 'n' || $value === 'x' || $value === 'null') { if ($value === null || $value === '' || $value === 'off' || $value === 'false' || $value === 'no' || $value === 'n' || $value === 'x' || $value === 'null') {
return false; return false;
} }
return !!$value; return !!$value;
} }
if ($type === 'int') { if ($type === 'int') {
return (int)$value; return (int)$value;
} }
if ($type === 'float') { if ($type === 'float') {
return (float)$value; return (float)$value;
} }
if ($type === 'string') { if ($type === 'string') {
return (string)$value; return (string)$value;
} }
throw new \InvalidArgumentException('올바르지 않은 type 지정'); throw new \InvalidArgumentException('올바르지 않은 type 지정');
} }
public static function zip(\Generator ...$iterators){ public static function zip(\Generator ...$iterators){
while(true){ while(true){
$hasValue = false; $hasValue = false;
$values = []; $values = [];
foreach($iterators as $iter){ foreach($iterators as $iter){
if($iter->valid()){ if($iter->valid()){
$values[] = $iter->send(NULL); $values[] = $iter->send(NULL);
$hasValue = true; $hasValue = true;
} }
} }
yield $values; yield $values;
if(!$hasValue){ if(!$hasValue){
break; break;
} }
} }
} }
/** /**
* $_POST, $_GET에서 값을 가져오는 함수. Util::array_get($_POST[$name])을 축약 가능. * $_POST, $_GET에서 값을 가져오는 함수. Util::array_get($_POST[$name])을 축약 가능.
* 타입이 복잡해질 경우 이 함수를 통하지 않고 json으로 요청할 것을 권장. * 타입이 복잡해질 경우 이 함수를 통하지 않고 json으로 요청할 것을 권장.
* *
* @param string $name 가져오고자 하는 key 이름. * @param string $name 가져오고자 하는 key 이름.
* @param string $type 가져오고자 하는 type. [string, int, float, bool, array, array_string, array_int] * @param string $type 가져오고자 하는 type. [string, int, float, bool, array, array_string, array_int]
* @param mixed $ifNotExists 만약 $_POST와 $_GET에 값이 없을 경우 반환하는 변수. 이 값은 $type을 검사하지 않음. * @param mixed $ifNotExists 만약 $_POST와 $_GET에 값이 없을 경우 반환하는 변수. 이 값은 $type을 검사하지 않음.
* @return int|float|string|array|null * @return int|float|string|array|null
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
public static function getReq(string $name, string $type = 'string', $ifNotExists = null) public static function getReq(string $name, string $type = 'string', $ifNotExists = null)
{ {
if (isset($_POST[$name])) { if (isset($_POST[$name])) {
$value = $_POST[$name]; $value = $_POST[$name];
} elseif (isset($_GET[$name])) { } elseif (isset($_GET[$name])) {
$value = $_GET[$name]; $value = $_GET[$name];
} else { } else {
return $ifNotExists; return $ifNotExists;
} }
return static::_parseReq($value, $type); return static::_parseReq($value, $type);
} }
/** /**
* $_POST에서 값을 가져오는 함수. Util::array_get($_POST[$name])을 축약 가능. $_GET에서도 가져올 수 있다면 getReq 사용. * $_POST에서 값을 가져오는 함수. Util::array_get($_POST[$name])을 축약 가능. $_GET에서도 가져올 수 있다면 getReq 사용.
* 타입이 복잡해질 경우 이 함수를 통하지 않고 json으로 요청할 것을 권장. * 타입이 복잡해질 경우 이 함수를 통하지 않고 json으로 요청할 것을 권장.
* *
* @param string $name 가져오고자 하는 key 이름. * @param string $name 가져오고자 하는 key 이름.
* @param string $type 가져오고자 하는 type. [string, int, float, bool, array, array_string, array_int] * @param string $type 가져오고자 하는 type. [string, int, float, bool, array, array_string, array_int]
* @param mixed $ifNotExists 만약 $_GET과 $_POST에 값이 없을 경우 반환하는 변수. 이 값은 $type을 검사하지 않음. * @param mixed $ifNotExists 만약 $_GET과 $_POST에 값이 없을 경우 반환하는 변수. 이 값은 $type을 검사하지 않음.
* @return int|float|string|array|null * @return int|float|string|array|null
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
public static function getPost(string $name, string $type = 'string', $ifNotExists = null) public static function getPost(string $name, string $type = 'string', $ifNotExists = null)
{ {
if (isset($_POST[$name])) { if (isset($_POST[$name])) {
$value = $_POST[$name]; $value = $_POST[$name];
} else { } else {
return $ifNotExists; return $ifNotExists;
} }
return static::_parseReq($value, $type); return static::_parseReq($value, $type);
} }
public static function hashPassword($salt, $password) public static function hashPassword($salt, $password)
{ {
return hash('sha512', $salt.$password.$salt); return hash('sha512', $salt.$password.$salt);
} }
/** /**
* 변환할 내용이 _tK_$key_ 형태로 작성된 단순한 템플릿 파일을 이용하여 결과물을 생성해주는 함수. * 변환할 내용이 _tK_$key_ 형태로 작성된 단순한 템플릿 파일을 이용하여 결과물을 생성해주는 함수.
*/ */
public static function generateFileUsingSimpleTemplate(string $srcFilePath, string $destFilePath, array $params, bool $canOverwrite=false) public static function generateFileUsingSimpleTemplate(string $srcFilePath, string $destFilePath, array $params, bool $canOverwrite=false)
{ {
if ($destFilePath === $srcFilePath) { if ($destFilePath === $srcFilePath) {
return 'invalid destFilePath'; return 'invalid destFilePath';
} }
if (!file_exists($srcFilePath)) { if (!file_exists($srcFilePath)) {
return 'srcFilePath is not exists'; return 'srcFilePath is not exists';
} }
if (file_exists($destFilePath) && !$canOverwrite) { if (file_exists($destFilePath) && !$canOverwrite) {
return 'destFilePath is already exists'; return 'destFilePath is already exists';
} }
if (!is_writable(dirname($destFilePath))) { if (!is_writable(dirname($destFilePath))) {
return 'destFilePath is not writable'; return 'destFilePath is not writable';
} }
$text = file_get_contents($srcFilePath); $text = file_get_contents($srcFilePath);
foreach ($params as $key => $value) { foreach ($params as $key => $value) {
$text = str_replace("_tK_{$key}_", $value, $text); if(is_array($value)){
} $text = str_replace("[/*_tK_{$key}_*/]", var_export($value, true), $text);
file_put_contents($destFilePath, $text); }
else{
return true; $text = str_replace("_tK_{$key}_", $value, $text);
} }
/** }
* params에 맞도록 class를 생성해주는 함수 file_put_contents($destFilePath, $text);
*/
public static function generatePHPClassFile(string $destFilePath, array $params, ?string $srcClassName=null, string $namespace='sammo'){ return true;
if (!is_writable(dirname($destFilePath))) { }
return 'destFilePath is not writable';
} /**
* params에 맞도록 class를 생성해주는 함수
$newClassName = basename($destFilePath, '.php'); */
$newClassName = basename($newClassName, '.orig'); public static function generatePHPClassFile(string $destFilePath, array $params, ?string $srcClassName=null, string $namespace='sammo'){
$head = []; if (!is_writable(dirname($destFilePath))) {
$head[] = '<?php'; return 'destFilePath is not writable';
$head[] = "namespace $namespace;"; }
if($srcClassName === null){
$head[] = "class $newClassName"; $newClassName = basename($destFilePath, '.php');
} $newClassName = basename($newClassName, '.orig');
else{ $head = [];
$head[] = "class $newClassName extends $srcClassName"; $head[] = '<?php';
} $head[] = "namespace $namespace;";
if($srcClassName === null){
$head[] = '{'; $head[] = "class $newClassName";
$head[] = ''; }
$head = join("\n", $head); else{
$head[] = "class $newClassName extends $srcClassName";
$body = []; }
foreach($params as $key=>$value){
$head[] = '{';
if(!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/',$key)){ $head[] = '';
return "$key is not valid variable name"; $head = join("\n", $head);
}
$body = [];
$body[] = ' public static $'.$key.' = '.var_export($value, true).';'; foreach($params as $key=>$value){
}
$tail = "\n}"; if(!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/',$key)){
return "$key is not valid variable name";
if(file_exists($destFilePath)){ }
unlink($destFilePath);
} $body[] = ' public static $'.$key.' = '.var_export($value, true).';';
$result = file_put_contents($destFilePath, $head.join("\n", $body).$tail, LOCK_EX); }
assert($result); $tail = "\n}";
return true; if(file_exists($destFilePath)){
} unlink($destFilePath);
}
/** $result = file_put_contents($destFilePath, $head.join("\n", $body).$tail, LOCK_EX);
* '비교적' 안전한 int 변환 assert($result);
* null -> null
* int -> int return true;
* float -> int }
* numeric(int, float) 포함 -> int
* 기타 -> 예외처리 /**
* * '비교적' 안전한 int 변환
* @return int|null * null -> null
*/ * int -> int
public static function toInt($val, $silent=false) * float -> int
{ * numeric(int, float) 포함 -> int
if (!isset($val)) { * 기타 -> 예외처리
return null; *
} * @return int|null
if ($val === null) { */
return null; public static function toInt($val, $silent=false)
} {
if (is_int($val)) { if (!isset($val)) {
return $val; return null;
} }
if (is_numeric($val)) { if ($val === null) {
return intval($val);// return null;
} }
if (strtolower($val) === 'null') { if (is_int($val)) {
return null; return $val;
} }
if (is_numeric($val)) {
if ($silent) { return intval($val);//
if ($val == null) { }
return null; if (strtolower($val) === 'null') {
} return null;
if ($val == ''){ }
return null;
} if ($silent) {
return intval($val); if ($val == null) {
} return null;
throw new \InvalidArgumentException('올바르지 않은 타입형 :'.$val); }
} if ($val == ''){
return null;
/** }
* Generate a random string, using a cryptographically secure return intval($val);
* pseudorandom number generator (random_int) }
* throw new \InvalidArgumentException('올바르지 않은 타입형 :'.$val);
* For PHP 7, random_int is a PHP core function }
* For PHP 5.x, depends on https://github.com/paragonie/random_compat
* /**
* @param int $length How many characters do we want? * Generate a random string, using a cryptographically secure
* @param string $keyspace A string of all possible characters * pseudorandom number generator (random_int)
* to select from *
* @return string * For PHP 7, random_int is a PHP core function
*/ * For PHP 5.x, depends on https://github.com/paragonie/random_compat
public static function randomStr($length, $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') *
{ * @param int $length How many characters do we want?
$str = ''; * @param string $keyspace A string of all possible characters
$max = mb_strlen($keyspace, '8bit') - 1; * to select from
for ($i = 0; $i < $length; ++$i) { * @return string
$str .= $keyspace[random_int(0, $max)]; */
} public static function randomStr($length, $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
return $str; {
} $str = '';
$max = mb_strlen($keyspace, '8bit') - 1;
public static function mapWithKey($callback, $dict) for ($i = 0; $i < $length; ++$i) {
{ $str .= $keyspace[random_int(0, $max)];
$result = []; }
foreach ($dict as $key=>$value) { return $str;
$result[$key] = ($callback)($key, $value); }
}
return $result; public static function mapWithKey($callback, $dict)
} {
$result = [];
public static function convertArrayToDict($arr, $keyName) foreach ($dict as $key=>$value) {
{ $result[$key] = ($callback)($key, $value);
$result = []; }
return $result;
foreach ($arr as $obj) { }
$key = $obj[$keyName];
$result[$key] = $obj; public static function convertArrayToDict($arr, $keyName)
} {
$result = [];
return $result;
} foreach ($arr as $obj) {
$key = $obj[$keyName];
public static function convertArrayToSetLike($arr, $valueIsKey=true){ $result[$key] = $obj;
$result = []; }
foreach($arr as $datum){
$result[$datum] = $valueIsKey?$datum:1; return $result;
} }
return $result;
} public static function convertArrayToSetLike($arr, $valueIsKey=true){
$result = [];
public static function convertPairArrayToDict($arr){ foreach($arr as $datum){
$result = []; $result[$datum] = $valueIsKey?$datum:1;
foreach($arr as [$key, $val]){ }
$result[$key] = $val; return $result;
} }
return $result;
} public static function convertPairArrayToDict($arr){
$result = [];
public static function convertDictToArray($dict, bool $withKey=true) foreach($arr as [$key, $val]){
{ $result[$key] = $val;
$result = []; }
return $result;
foreach($dict as $key=>$value){ }
if($withKey){
$result[] = [$key, $value]; public static function convertDictToArray($dict, bool $withKey=true)
} {
else{ $result = [];
$result[] = $value;
} foreach($dict as $key=>$value){
} if($withKey){
$result[] = [$key, $value];
return $result; }
} else{
$result[] = $value;
public static function squeezeFromArray(array $dict, $key){ }
$result = []; }
foreach($dict as $dictKey=>$value){
$result[$dictKey] = $value[$key]; return $result;
} }
return $result; public static function squeezeFromArray(array $dict, $key){
} $result = [];
foreach($dict as $dictKey=>$value){
public static function isDict($array) $result[$dictKey] = $value[$key];
{ }
if($array === null){
return false; return $result;
} }
if (!is_array($array)) {
//배열이 아니면 dictionary 조차 아님. public static function isDict($array)
return false; {
} if($array === null){
if(count($array) === 0){ return false;
return true; }
} if (!is_array($array)) {
//배열이 아니면 dictionary 조차 아님.
$idx = 0; return false;
foreach (array_keys($array) as $key) { }
if (is_string($key)) { if(count($array) === 0){
return true; return true;
} }
if($idx !== $key){
return true; $idx = 0;
} foreach (array_keys($array) as $key) {
$idx = $key + 1; if (is_string($key)) {
} return true;
}
return false; if($idx !== $key){
} return true;
}
/** $idx = $key + 1;
* @param null|mixed|mixed[] $dict }
* @return null|mixed|mixed[]
*/ return false;
public static function eraseNullValue($dict, int $depth=512) }
{
//TODO:Test 추가 /**
if ($dict === null) { * @param null|mixed|mixed[] $dict
return null; * @return null|mixed|mixed[]
} */
public static function eraseNullValue($dict, int $depth=512)
if (is_array($dict) && empty($dict)) { {
return null; //TODO:Test 추가
} if ($dict === null) {
return null;
if ($depth <= 0) { }
return $dict;
} if (is_array($dict) && empty($dict)) {
return null;
foreach ($dict as $key=>$value) { }
if ($value === null) {
unset($dict[$key]); if ($depth <= 0) {
continue; return $dict;
} }
if (!Util::isDict($value)) {
continue; foreach ($dict as $key=>$value) {
} if ($value === null) {
unset($dict[$key]);
$newValue = Util::eraseNullValue($value, $depth - 1); continue;
if ($newValue === null) { }
unset($dict[$key]); if (!Util::isDict($value)) {
} else { continue;
$dict[$key] = $newValue; }
}
} $newValue = Util::eraseNullValue($value, $depth - 1);
if ($newValue === null) {
return $dict; unset($dict[$key]);
} } else {
$dict[$key] = $newValue;
/** }
* key=>value pair를 보존한 섞기 }
*/
public static function shuffle_assoc(&$array) { return $dict;
$keys = array_keys($array); }
shuffle($keys); /**
* key=>value pair를 보존한 섞기
$new = []; */
public static function shuffle_assoc(&$array) {
foreach($keys as $key) { $keys = array_keys($array);
$new[$key] = $array[$key];
} shuffle($keys);
$array = $new; $new = [];
return true; foreach($keys as $key) {
} $new[$key] = $array[$key];
}
/** $array = $new;
* [0.0, 1.0] 사이의 선형 랜덤 float
* @return float return true;
*/ }
public static function randF()
{
return mt_rand() / mt_getrandmax(); /**
} * [0.0, 1.0] 사이의 선형 랜덤 float
* @return float
/** */
* [min, max] 사이의 선형 랜덤 float public static function randF()
* @return float {
*/ return mt_rand() / mt_getrandmax();
public static function randRange(float $min, float $max) }
{
return static::randF()*($max - $min) + $min; /**
} * [min, max] 사이의 선형 랜덤 float
* @return float
/** */
* [min, max] 사이의 선형 랜덤 int public static function randRange(float $min, float $max)
* 현재는 rand(min, max)와 동일 {
* @return int return static::randF()*($max - $min) + $min;
*/ }
public static function randRangeInt(int $min, int $max){
return mt_rand($min, $max); /**
} * [min, max] 사이의 선형 랜덤 int
* 현재는 rand(min, max)와 동일
/** * @return int
* $prob의 확률로 true를 반환 */
* @return boolean public static function randRangeInt(int $min, int $max){
*/ return mt_rand($min, $max);
public static function randBool($prob = 0.5) }
{
return self::randF() < $prob; /**
} * $prob의 확률로 true를 반환
* @return boolean
/** */
* aaa(.bbb)?% 의 텍스트를 float으로 변환. 100% = 1.0 public static function randBool($prob = 0.5)
* @return float|null {
*/ return self::randF() < $prob;
public static function convPercentStrToFloat(string $text):?float{ }
preg_match('/^(\d+(\.\d+)?)\%$/', $text, $matches);
if($matches === null){ /**
return null; * aaa(.bbb)?% 의 텍스트를 float으로 변환. 100% = 1.0
} * @return float|null
*/
return (float)$matches[1] / 100; public static function convPercentStrToFloat(string $text):?float{
} preg_match('/^(\d+(\.\d+)?)\%$/', $text, $matches);
if($matches === null){
return null;
/** }
* $min과 $max 사이의 값으로 교정
*/ return (float)$matches[1] / 100;
public static function valueFit($value, $min = null, $max = null) }
{
if($max !== null && $min !== null && $max < $min){
return $min; /**
} * $min과 $max 사이의 값으로 교정
if ($min !== null && $value < $min) { */
return $min; public static function valueFit($value, $min = null, $max = null)
} {
if ($max !== null && $value > $max) { if($max !== null && $min !== null && $max < $min){
return $max; return $min;
} }
return $value; if ($min !== null && $value < $min) {
} return $min;
}
/** if ($max !== null && $value > $max) {
* 각 값의 비중에 따라 랜덤한 값을 선택 return $max;
* }
* @param array $items 각 수치의 비중 return $value;
* }
* @return int|string 선택된 랜덤 값의 key값. 단순 배열인 경우에는 index
*/ /**
public static function choiceRandomUsingWeight(array $items) * 각 값의 비중에 따라 랜덤한 값을 선택
{ *
$sum = 0; * @param array $items 각 수치의 비중
foreach ($items as $value) { *
if($value <= 0){ * @return int|string 선택된 랜덤 값의 key값. 단순 배열인 경우에는 index
continue; */
} public static function choiceRandomUsingWeight(array $items)
$sum += $value; {
} $sum = 0;
foreach ($items as $value) {
$rd = self::randF()*$sum; if($value <= 0){
foreach ($items as $key=>$value) { continue;
if($value <= 0){ }
$value = 0; $sum += $value;
} }
if ($rd <= $value) {
return $key; $rd = self::randF()*$sum;
} foreach ($items as $key=>$value) {
$rd -= $value; if($value <= 0){
} $value = 0;
}
//fallback. 이곳으로 빠지지 않음 if ($rd <= $value) {
end($items); return $key;
return key($items); }
} $rd -= $value;
}
/**
* 각 값의 비중에 따라 랜덤한 값을 선택. //fallback. 이곳으로 빠지지 않음
* end($items);
* @param array $items 각 수치와 비중. [값, weight] 으로 보관 return key($items);
* }
* @return object 선택된 랜덤 값의 첫번째 값
*/ /**
public static function choiceRandomUsingWeightPair(array $items) * 각 값의 비중에 따라 랜덤한 값을 선택.
{ *
$sum = 0; * @param array $items 각 수치와 비중. [값, weight] 으로 보관
foreach ($items as [$item, $value]) { *
if($value <= 0){ * @return object 선택된 랜덤 값의 첫번째 값
continue; */
} public static function choiceRandomUsingWeightPair(array $items)
$sum += $value; {
} $sum = 0;
foreach ($items as [$item, $value]) {
$rd = self::randF()*$sum; if($value <= 0){
foreach ($items as [$item, $value]) { continue;
if($value <= 0){ }
$value = 0; $sum += $value;
} }
if ($rd <= $value) {
return $item; $rd = self::randF()*$sum;
} foreach ($items as [$item, $value]) {
$rd -= $value; if($value <= 0){
} $value = 0;
}
//fallback. 이곳으로 빠지지 않음 if ($rd <= $value) {
end($items); return $item;
return $items[key($items)][0]; }
} $rd -= $value;
}
/**
* 2중 배열에서 특정 키의 합 //fallback. 이곳으로 빠지지 않음
* end($items);
* @param array $array 배열. 1차원 배열 또는 2차원 배열 return $items[key($items)][0];
* @param int|string|null $key 2차원 배열에서 참조할 키. }
* @return int|float 합계
*/ /**
public static function arraySum(array $array, $key = null){ * 2중 배열에서 특정 키의 합
if($key === null){ *
return array_sum($array); * @param array $array 배열. 1차원 배열 또는 2차원 배열
} * @param int|string|null $key 2차원 배열에서 참조할 키.
$sum = 0; * @return int|float 합계
foreach($array as $val){ */
$sum += $val[$key]; public static function arraySum(array $array, $key = null){
} if($key === null){
return $sum; return array_sum($array);
} }
$sum = 0;
/** foreach($array as $val){
* 특정 키를 가진 값으로 묶음 $sum += $val[$key];
* }
* @param array $array 배열. 1차원 배열 또는 2차원 배열 return $sum;
* @param int|string|null $key 2차원 배열에서 참조할 키. }
* @return array
*/ /**
public static function arrayGroupBy(array $array, $key, bool $preserveRowKey=false) { * 특정 키를 가진 값으로 묶음
$result = array(); *
* @param array $array 배열. 1차원 배열 또는 2차원 배열
if($preserveRowKey){ * @param int|string|null $key 2차원 배열에서 참조할 키.
foreach($array as $rowKey=>$val) { * @return array
if(key_exists($key, $val)){ */
$result[$val[$key]][$rowKey] = $val; public static function arrayGroupBy(array $array, $key, bool $preserveRowKey=false) {
}else{ $result = array();
$result[""][$rowKey] = $val;
} if($preserveRowKey){
} foreach($array as $rowKey=>$val) {
} if(key_exists($key, $val)){
else{ $result[$val[$key]][$rowKey] = $val;
foreach($array as $val) { }else{
if(key_exists($key, $val)){ $result[""][$rowKey] = $val;
$result[$val[$key]][] = $val; }
}else{ }
$result[""][] = $val; }
} else{
} foreach($array as $val) {
} if(key_exists($key, $val)){
$result[$val[$key]][] = $val;
return $result; }else{
} $result[""][] = $val;
}
public static function getKeyOfMaxValue(array $array){ }
$max = null; }
$result = null;
foreach ($array as $key => $value) { return $result;
if ($max === null || $value > $max) { }
$result = $key;
$max = $value; public static function getKeyOfMaxValue(array $array){
} $max = null;
} $result = null;
foreach ($array as $key => $value) {
return $result; if ($max === null || $value > $max) {
} $result = $key;
$max = $value;
/** }
* 배열의 아무거나 고름. Python의 random.choice() }
*
* @param array $items 선택하고자 하는 배열 return $result;
* }
* @return int|float|string|object 선택된 value값.
*/ /**
public static function choiceRandom(array $items) * 배열의 아무거나 고름. Python의 random.choice()
{ *
return $items[array_rand($items)]; * @param array $items 선택하고자 하는 배열
} *
* @return int|float|string|object 선택된 value값.
/** */
* fqn 클래스 경로에서 클래스 이름을 받아옴 public static function choiceRandom(array $items)
*/ {
public static function getClassName(string $classpath) return $items[array_rand($items)];
{ }
if ($pos = strrpos($classpath, '\\')) return substr($classpath, $pos + 1);
return $pos; /**
} * fqn 클래스 경로에서 클래스 이름을 받아옴
*/
public static function getClassNameFromObj($object){ public static function getClassName(string $classpath)
$reflect = new \ReflectionClass($object); {
return $reflect->getShortName(); if ($pos = strrpos($classpath, '\\')) return substr($classpath, $pos + 1);
} return $pos;
}
/**
* 배열의 원소에 대해서 테스트를 수행하고 모두 true인지 확인 public static function getClassNameFromObj($object){
*/ $reflect = new \ReflectionClass($object);
public static function testArrayValues(array $array, ?callable $callback):bool{ return $reflect->getShortName();
if($callback === null){ }
foreach($array as $value){
if(!$value){ /**
return false; * 배열의 원소에 대해서 테스트를 수행하고 모두 true인지 확인
} */
} public static function testArrayValues(array $array, ?callable $callback):bool{
return true; if($callback === null){
} foreach($array as $value){
if(!$value){
foreach($array as $value){ return false;
if(!($callback)($value)){ }
return false; }
} return true;
} }
return true;
} foreach($array as $value){
if(!($callback)($value)){
/** return false;
* MeekroDB에서 %lb의 처리가 이상하여 따로 만든 코드 }
*/ }
public static function formatListOfBackticks(array $array):string{ return true;
if(!$array){ }
throw new MustNotBeReachedException('backtick 목록에 없음');
} /**
//.이 들어간 경우에는 분리해서 묶어야함. * MeekroDB에서 %lb의 처리가 이상하여 따로 만든 코드
return join(',', array_map(function($value){ */
$value = preg_replace('/\s/', '', $value); public static function formatListOfBackticks(array $array):string{
if(strpos($value, '.') !== false){ if(!$array){
$value = explode('.', $value); throw new MustNotBeReachedException('backtick 목록에 없음');
$value = join('`.`', $value); }
} //.이 들어간 경우에는 분리해서 묶어야함.
return "`{$value}`"; return join(',', array_map(function($value){
}, $array)); $value = preg_replace('/\s/', '', $value);
} if(strpos($value, '.') !== false){
$value = explode('.', $value);
public static function joinYearMonth(int $year, int $month):int{ $value = join('`.`', $value);
return $year * 12 + $month - 1; }
} return "`{$value}`";
}, $array));
public static function parseYearMonth(int $yearMonth):array{ }
return [intdiv($yearMonth, 12), $yearMonth%12 + 1];
} public static function joinYearMonth(int $year, int $month):int{
return $year * 12 + $month - 1;
/** }
* 변수의 값을 첫번째 값부터 비교해서 대소를 반환
* 길이가 다른 경우, 앞의 결과를 먼저 비교한 뒤, 짧은쪽의 값을 null으로 가정하여 길이 처리 public static function parseYearMonth(int $yearMonth):array{
*/ return [intdiv($yearMonth, 12), $yearMonth%12 + 1];
public static function arrayCompare(iterable $lhs, iterable $rhs, ?callable $comp=null){ }
if($lhs instanceof \Traversable){
$lhsIter = new \IteratorIterator($lhs); /**
} * 변수의 값을 첫번째 값부터 비교해서 대소를 반환
else if(is_array($lhs)){ * 길이가 다른 경우, 앞의 결과를 먼저 비교한 뒤, 짧은쪽의 값을 null으로 가정하여 길이 처리
$lhsIter = new \ArrayIterator($lhs); */
} public static function arrayCompare(iterable $lhs, iterable $rhs, ?callable $comp=null){
else{ if($lhs instanceof \Traversable){
throw new \InvalidArgumentException('$lhs is not Traversable'); $lhsIter = new \IteratorIterator($lhs);
} }
else if(is_array($lhs)){
if($rhs instanceof \Traversable){ $lhsIter = new \ArrayIterator($lhs);
$rhsIter = new \IteratorIterator($rhs); }
} else{
else if(is_array($rhs)){ throw new \InvalidArgumentException('$lhs is not Traversable');
$rhsIter = new \ArrayIterator($rhs); }
}
else{ if($rhs instanceof \Traversable){
throw new \InvalidArgumentException('$rhs is not Traversable'); $rhsIter = new \IteratorIterator($rhs);
} }
else if(is_array($rhs)){
while($lhsIter->valid() && $rhsIter->valid()){ $rhsIter = new \ArrayIterator($rhs);
$lhsVal = $lhsIter->current(); }
$rhsVal = $rhsIter->current(); else{
throw new \InvalidArgumentException('$rhs is not Traversable');
if($comp !== null){ }
$compResult = $comp($lhsVal, $rhsVal);
} while($lhsIter->valid() && $rhsIter->valid()){
else{ $lhsVal = $lhsIter->current();
$compResult = $lhsVal <=> $rhsVal; $rhsVal = $rhsIter->current();
}
if($comp !== null){
if($compResult !== 0){ $compResult = $comp($lhsVal, $rhsVal);
return $compResult; }
} else{
$compResult = $lhsVal <=> $rhsVal;
$lhsIter->next(); }
$rhsIter->next();
} if($compResult !== 0){
return $compResult;
$rhsVal = null; }
while($lhsIter->valid()){
$lhsVal = $lhsIter->current(); $lhsIter->next();
$rhsIter->next();
if($comp !== null){ }
$compResult = $comp($lhsVal, $rhsVal);
} $rhsVal = null;
else{ while($lhsIter->valid()){
$compResult = $lhsVal <=> $rhsVal; $lhsVal = $lhsIter->current();
}
if($comp !== null){
if($compResult !== 0){ $compResult = $comp($lhsVal, $rhsVal);
return $compResult; }
} else{
$compResult = $lhsVal <=> $rhsVal;
$lhsIter->next(); }
}
if($compResult !== 0){
$lhsVal = null; return $compResult;
while($rhsIter->valid()){ }
$rhsVal = $rhsIter->current();
$lhsIter->next();
if($comp !== null){ }
$compResult = $comp($lhsVal, $rhsVal);
} $lhsVal = null;
else{ while($rhsIter->valid()){
$compResult = $lhsVal <=> $rhsVal; $rhsVal = $rhsIter->current();
}
if($comp !== null){
if($compResult !== 0){ $compResult = $comp($lhsVal, $rhsVal);
return $compResult; }
} else{
$compResult = $lhsVal <=> $rhsVal;
$rhsIter->next(); }
}
if($compResult !== 0){
return 0; return $compResult;
} }
public static function isPowerOfTwo(int $number):bool{ $rhsIter->next();
if($number <= 0){ }
return false;
} return 0;
return ($number & ($number - 1)) == 0; }
}
public static function isPowerOfTwo(int $number):bool{
/** if($number <= 0){
* Python 3의 range와 동일 return false;
* @param int $from }
* @param null|int $to return ($number & ($number - 1)) == 0;
* @param null|int $step }
* @return \Traversable
* @throws \InvalidArgumentException /**
*/ * Python 3의 range와 동일
public static function range(int $from, ?int $to=null, ?int $step=null):\Traversable{ * @param int $from
if($to === null){ * @param null|int $to
$to = $from; * @param null|int $step
$from = 0; * @return \Traversable
} * @throws \InvalidArgumentException
if($step === null){ */
$step = 1; public static function range(int $from, ?int $to=null, ?int $step=null):\Traversable{
} if($to === null){
else if($step === 0){ $to = $from;
throw new \InvalidArgumentException('xrange() arg 3 must not be zero'); $from = 0;
} }
if($step === null){
if($step > 0){ $step = 1;
while($from < $to){ }
yield $from; else if($step === 0){
$from += $step; throw new \InvalidArgumentException('xrange() arg 3 must not be zero');
} }
}
else{ if($step > 0){
while($from > $to){ while($from < $to){
yield $from; yield $from;
$from += $step; $from += $step;
} }
} }
} else{
while($from > $to){
}; yield $from;
$from += $step;
}
}
}
};