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