From 551b79d8c2cf93f17e7fbf591fde52ec9b35dfd8 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sun, 29 Apr 2018 04:02:23 +0900 Subject: [PATCH 001/101] =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20=ED=8C=A8?= =?UTF-8?q?=EB=84=90=20=EC=A0=91=EC=86=8D=20=ED=97=88=EC=9A=A9,=20?= =?UTF-8?q?=EC=A0=91=EC=86=8D=20=EC=A0=9C=ED=95=9C=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/_admin2_submit.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hwe/_admin2_submit.php b/hwe/_admin2_submit.php index a14bab7f..f6fa480b 100644 --- a/hwe/_admin2_submit.php +++ b/hwe/_admin2_submit.php @@ -191,12 +191,12 @@ switch($btn) { ], '`no` IN %li', $genlist); break; case "접속 허용": - $db->update('genera',[ + $db->update('general',[ 'con'=>0 ], '`no` IN %li', $genlist); break; case "접속 제한": - $db->update('genera',[ + $db->update('general',[ 'con'=>1000 ], '`no` IN %li', $genlist); break; From d5be6e3e083a57ceb33e2773b167d250f0c68ebb Mon Sep 17 00:00:00 2001 From: hide_d Date: Sun, 29 Apr 2018 04:29:46 +0900 Subject: [PATCH 002/101] =?UTF-8?q?=EB=82=B4=20=EC=A0=95=EB=B3=B4=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=88=99=EB=A0=A8=EB=8F=84=EB=A5=BC=20=EC=88=98?= =?UTF-8?q?=EC=B9=98=EB=A1=9C=20=ED=91=9C=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/func.php | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/hwe/func.php b/hwe/func.php index c96998ca..33e1e3c9 100644 --- a/hwe/func.php +++ b/hwe/func.php @@ -1002,11 +1002,17 @@ function generalInfo2($no) { if($dex30 > 100) { $dex30 = 100; } if($dex40 > 100) { $dex40 = 100; } - $general['dex0'] = getDexCall($general['dex0']); - $general['dex10'] = getDexCall($general['dex10']); - $general['dex20'] = getDexCall($general['dex20']); - $general['dex30'] = getDexCall($general['dex30']); - $general['dex40'] = getDexCall($general['dex40']); + $general['dex0_text'] = getDexCall($general['dex0']); + $general['dex10_text'] = getDexCall($general['dex10']); + $general['dex20_text'] = getDexCall($general['dex20']); + $general['dex30_text'] = getDexCall($general['dex30']); + $general['dex40_text'] = getDexCall($general['dex40']); + + $general['dex0_short'] = sprintf('%.1fK', $general['dex0']/1000); + $general['dex10_short'] = sprintf('%.1fK', $general['dex10']/1000); + $general['dex20_short'] = sprintf('%.1fK', $general['dex20']/1000); + $general['dex30_short'] = sprintf('%.1fK', $general['dex30']/1000); + $general['dex40_short'] = sprintf('%.1fK', $general['dex40']/1000); echo " @@ -1042,30 +1048,35 @@ function generalInfo2($no) {
추 가 정 보
- + - - + + + - + + - + + - + + - + +
숙 련 도
숙 련 도
보병  {$general['dex0']}".bar($dex0, 16)." {$general['dex0_text']}{$general['dex0_short']} ".bar($dex0, 16)."
궁병  {$general['dex10']} {$general['dex10_text']}{$general['dex10_short']}  ".bar($dex10, 16)."
기병  {$general['dex20']} {$general['dex20_text']}{$general['dex20_short']}  ".bar($dex20, 16)."
귀병  {$general['dex30']} {$general['dex30_text']}{$general['dex30_short']}  ".bar($dex30, 16)."
차병  {$general['dex40']} {$general['dex40_text']}{$general['dex40_short']}  ".bar($dex40, 16)."
"; From 953196ec78289d0ede78e95428264f7922388f57 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sun, 29 Apr 2018 12:55:16 +0900 Subject: [PATCH 003/101] =?UTF-8?q?=EC=98=88=EC=95=BD=20=EC=98=A4=ED=94=88?= =?UTF-8?q?=20=EC=8B=9C=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=A5=BC=20=EB=B0=94?= =?UTF-8?q?=EB=A1=9C=20=EB=82=A0=EB=A6=AC=EC=A7=84=20=EC=95=8A=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/j_autoreset.php | 62 +++++++++++++++++++++++++++++++++++++++++---- hwe/j_install.php | 15 ++++++++--- 2 files changed, 69 insertions(+), 8 deletions(-) diff --git a/hwe/j_autoreset.php b/hwe/j_autoreset.php index 36e6360f..a18f8588 100644 --- a/hwe/j_autoreset.php +++ b/hwe/j_autoreset.php @@ -6,15 +6,67 @@ include "func.php"; $db = DB::db(); -$reserved = $db->queryFirstRow( - 'SELECT * FROM reserved_open WHERE `date` <= %s LIMIT 1', - (new \DateTime())->format('Y-m-d H:i:s') -); +$reserved = $db->queryFirstRow('SELECT `date`, options FROM reserved_open ORDER BY `date` ASC LIMIT 1'); if(!$reserved){ Json::die([ 'result'=>true, - 'affected'=>0 + 'affected'=>0, + 'status'=>'no_reserved' + ]); +} + +$reservedDate = new \DateTime($reserved['date']); +$now = new \DateTime(); + + +$status = 'not_yet'; + +if ($db->queryFirstField("SHOW TABLES LIKE 'game'")) { + list($isUnited, $lastTurn) = $db->queryFirstList('SELECT isUnited, turntime FROM game LIMIT 1'); +} +else{ + $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 ]); } diff --git a/hwe/j_install.php b/hwe/j_install.php index 4b535e53..f4cc8af0 100644 --- a/hwe/j_install.php +++ b/hwe/j_install.php @@ -52,9 +52,18 @@ if($reserve_open){ $reserve_open = new \DateTime($reserve_open); $db = DB::db(); - $clearResult = ResetHelper::clearDB(); - if(!$clearResult['result']){ - Json::die($clearResult); + if (!$db->queryFirstField("SHOW TABLES LIKE 'game'")) { + $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); From a19661199e97b4ec27d664872d952165359c27c7 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sun, 29 Apr 2018 23:13:49 +0900 Subject: [PATCH 004/101] =?UTF-8?q?Date=EC=9D=98=20=EB=B9=84=EA=B5=90=20?= =?UTF-8?q?=EB=8C=80=EC=83=81=20lhs,=20rhs=EA=B0=80=20=EB=B0=94=EB=80=90?= =?UTF-8?q?=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/sammo/Event/Condition/Date.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hwe/sammo/Event/Condition/Date.php b/hwe/sammo/Event/Condition/Date.php index 23acff06..d34261d3 100644 --- a/hwe/sammo/Event/Condition/Date.php +++ b/hwe/sammo/Event/Condition/Date.php @@ -50,13 +50,15 @@ class Date extends \sammo\Event\Condition{ } $lhs = [ - $this->year, - $this->month - ]; - $rhs = [ $this->year!==null?(int)$env['year']:null, $this->month!==null?(int)$env['month']:null ]; + + $rhs = [ + $this->year, + $this->month + ]; + $value = false; switch($this->cmp){ From 7db3675e71f3b1c2df456cf00cd10b2abd00bf1f Mon Sep 17 00:00:00 2001 From: hide_d Date: Sun, 29 Apr 2018 23:31:21 +0900 Subject: [PATCH 005/101] =?UTF-8?q?=EC=84=B1=EC=9D=B8=20=EB=93=B1=EC=9E=A5?= =?UTF-8?q?=EC=9D=B4=20=EA=BC=AD=201=EC=9B=94=EC=9D=B4=20=EC=95=84?= =?UTF-8?q?=EB=8B=88=EC=96=B4=EB=8F=84=20=EB=90=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/sammo/Scenario/NPC.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hwe/sammo/Scenario/NPC.php b/hwe/sammo/Scenario/NPC.php index 2508bd9a..b2d2278a 100644 --- a/hwe/sammo/Scenario/NPC.php +++ b/hwe/sammo/Scenario/NPC.php @@ -107,8 +107,8 @@ class NPC{ $db = DB::db(); - if($age == \sammo\GameConst::$adultAge && $month == 1){ - \sammo\pushWorldHistory(["●1월:$name(이)가 성인이 되어 등장했습니다."], $year, $month); + if($age == \sammo\GameConst::$adultAge){ + \sammo\pushWorldHistory(["●$month월:$name(이)가 성인이 되어 등장했습니다."], $year, $month); } if($this->ego == null || $isFictionMode){ From 45fd06c195a5abe880a654188849770c938275e2 Mon Sep 17 00:00:00 2001 From: hide_d Date: Mon, 30 Apr 2018 00:01:11 +0900 Subject: [PATCH 006/101] =?UTF-8?q?=EC=84=B1=EC=9D=B8=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=93=B1=EC=9E=A5=EC=8B=9C=20=EC=9B=94=EC=9D=B4=20=EC=A0=9C?= =?UTF-8?q?=EB=8C=80=EB=A1=9C=20=EB=A1=9C=EA=B7=B8=EB=A1=9C=20=EB=82=A8?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/sammo/Scenario/NPC.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hwe/sammo/Scenario/NPC.php b/hwe/sammo/Scenario/NPC.php index b2d2278a..54b13f87 100644 --- a/hwe/sammo/Scenario/NPC.php +++ b/hwe/sammo/Scenario/NPC.php @@ -108,7 +108,7 @@ class NPC{ $db = DB::db(); if($age == \sammo\GameConst::$adultAge){ - \sammo\pushWorldHistory(["●$month월:$name(이)가 성인이 되어 등장했습니다."], $year, $month); + \sammo\pushWorldHistory(["●{$month}월:{$name}(이)가 성인이 되어 등장했습니다."], $year, $month); } if($this->ego == null || $isFictionMode){ From ebf9b4b75d0986973a8ef8e2280923c8de6c7ed3 Mon Sep 17 00:00:00 2001 From: hide_d Date: Mon, 30 Apr 2018 00:15:43 +0900 Subject: [PATCH 007/101] =?UTF-8?q?=EA=B0=80=EC=83=81=20=EC=83=81=EC=84=B1?= =?UTF-8?q?=EC=9D=B8=20=EA=B2=BD=EC=9A=B0=20=EC=83=88=20=EC=9E=A5=EC=88=98?= =?UTF-8?q?=EB=8A=94=20=EC=9E=AC=EC=95=BC=EC=9E=84.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/sammo/Scenario/NPC.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/hwe/sammo/Scenario/NPC.php b/hwe/sammo/Scenario/NPC.php index 54b13f87..80000859 100644 --- a/hwe/sammo/Scenario/NPC.php +++ b/hwe/sammo/Scenario/NPC.php @@ -86,10 +86,6 @@ class NPC{ public function build($env=[]){ //scenario에 life==1인 경우 수명 제한이 없어지는 모양. - $nationID = $this->nationID; - if(!\sammo\getNationStaticInfo($nationID)){ - $nationID = 0; - }; $isFictionMode = (Util::array_get($env['fiction'], 0)!=0); @@ -105,9 +101,21 @@ class NPC{ return false; //예약. } + $isNewGeneral = ($age == \sammo\GameConst::$adultAge); + + $nationID = $this->nationID; + if($isFictionMode && $isNewGeneral){ + $nationID = 0; + } + + if(!\sammo\getNationStaticInfo($nationID)){ + $nationID = 0; + }; + + $db = DB::db(); - if($age == \sammo\GameConst::$adultAge){ + if($isNewGeneral){ \sammo\pushWorldHistory(["●{$month}월:{$name}(이)가 성인이 되어 등장했습니다."], $year, $month); } From 063b3d37a6a36af14476e9010cbd3fd4442c1c05 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 19:44:22 +0900 Subject: [PATCH 008/101] =?UTF-8?q?exception=EC=9D=B4=20trace=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- f_config/config.php | 1 + 1 file changed, 1 insertion(+) diff --git a/f_config/config.php b/f_config/config.php index 217c995b..04a18445 100644 --- a/f_config/config.php +++ b/f_config/config.php @@ -82,6 +82,7 @@ function logExceptionByCustomHandler(\Throwable $e){ ], Json::PRETTY); file_put_contents(ROOT.'/d_log/err_log.txt',"$data\n", FILE_APPEND); + echo $e->getTraceAsString(); throw $e; } set_exception_handler('\\sammo\\logExceptionByCustomHandler'); \ No newline at end of file From 69af23b60a2fbc557de4ef19c87ecf790f9c38c5 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 19:45:10 +0900 Subject: [PATCH 009/101] =?UTF-8?q?Session=EC=97=90=EC=84=9C=20requireLogi?= =?UTF-8?q?n=20=EC=9D=B8=EC=9E=90=20=EC=9D=B4=EB=A6=84=EC=9D=84=20?= =?UTF-8?q?=EC=A7=81=EA=B4=80=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sammo/Session.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sammo/Session.php b/src/sammo/Session.php index 6bd6de08..fdfe52f6 100644 --- a/src/sammo/Session.php +++ b/src/sammo/Session.php @@ -72,25 +72,25 @@ class Session Json::die($result + $jsonResult); } - public static function requireLogin($result = '..'): Session + public static function requireLogin($actionOnError = '..'): Session { $session = Session::getInstance(); if ($session->isLoggedIn()) { return $session; } - static::die($result); + static::die($actionOnError); } - public static function requireGameLogin($result = '..'): Session + public static function requireGameLogin($actionOnError = '..'): Session { - $session = Session::requireLogin($result)->loginGame(); + $session = Session::requireLogin($actionOnError)->loginGame(); if ($session->generalID) { return $session; } - static::die($result); + static::die($actionOnError); } public function __construct() From a1392652ae586cdc84282c4d0f0209bb4a41dca8 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 19:48:38 +0900 Subject: [PATCH 010/101] =?UTF-8?q?config.css=EC=97=90=EC=84=9C=20div,=20b?= =?UTF-8?q?utton=EC=97=90=20=EC=A0=81=EC=9A=A9=EB=90=98=EB=8D=98=20?= =?UTF-8?q?=EC=A0=84=EC=97=AD=20style=20=EC=A0=9C=EA=B1=B0=20=EB=AA=A8?= =?UTF-8?q?=EB=B0=94=EC=9D=BC=20=ED=99=94=EB=A9=B4=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=9E=85=EA=B5=AC=20=ED=96=84=EB=B2=84=EA=B1=B0=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EB=8F=99=EC=9E=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- css/config.css | 34 ++++++++++------------------------ css/user_info.css | 14 ++++++-------- i_entrance/entrance.php | 2 +- i_entrance/user_info.html | 3 ++- js/admin_server.js | 20 ++++++++++---------- 5 files changed, 29 insertions(+), 44 deletions(-) diff --git a/css/config.css b/css/config.css index d09bdb69..34b9b848 100644 --- a/css/config.css +++ b/css/config.css @@ -1,8 +1,9 @@ @charset "utf-8"; -* { margin: 0px; padding: 0px; } -body { color:white; background-color:black; border-width:1px; border-color:gray; } -table { +body { + color:white; background-color:black; font-family: '맑은 고딕'; +} +table { border: solid 1px; border-spacing: 0px; border-collapse: separate; border-top-color: gray; border-left-color: gray; border-right-color: black; border-bottom-color: black; padding: 0px; font-size: 13px; @@ -23,13 +24,6 @@ a.just_link { text-decoration: none; } -div { - margin:0px; - padding: 0px; - word-break: break-all; - font-family: '맑은 고딕'; -} - .with_border{ border: solid 1px; border-spacing: 0px; @@ -58,8 +52,6 @@ div { font-family: '맑은 고딕';; } -font { font-family: '맑은 고딕';} - .obj_fill{ display:block; width:100%; @@ -72,24 +64,18 @@ button.with_skin { font-size: 13px; } +button.with_skin:disabled { + background-color:#333333; +} + input.with_skin { background-color: black; color: white; font-family: '맑은 고딕'; font-size: 13px; } -select { - width: 100px; height: 18px; - background-color: black; color: white; - font-family: '맑은 고딕'; - font-size: 13px; -} -button { - width: 100px; height: 20px; - background-color: black; color: white; - font-family: '맑은 고딕'; - font-size: 13px; - line-height:1.3; +input.with_skin:disabled { + background-color: #333333; } .font0 { font-size: 10px; } diff --git a/css/user_info.css b/css/user_info.css index 92665087..3b9ed297 100644 --- a/css/user_info.css +++ b/css/user_info.css @@ -21,6 +21,7 @@ right: 6px; margin:6px; height:40px; + line-height:40px; } #btn_delete_me{ @@ -37,15 +38,15 @@ #image_upload_filename{ position:absolute; - height:16px; + height:20px; left:10px; width:130px; - top:16px; + top:12px; } #image_upload_fake_btn{ - top:16px; - height:20px; + top:12px; + height:22px; right:10px; position:absolute; } @@ -53,8 +54,7 @@ #image_upload{ opacity: 0; position:absolute; - top:16px; - height:22px; + top:12px; left:0; height:20px; width:100%; @@ -70,7 +70,6 @@ bottom:0; left:0; width:50%; - height:20px; } #btn_remove_icon{ @@ -78,7 +77,6 @@ bottom:0; right:0; width:50%; - height:20px; } #third_use_disallow{ diff --git a/i_entrance/entrance.php b/i_entrance/entrance.php index e7d026c1..2a944abe 100644 --- a/i_entrance/entrance.php +++ b/i_entrance/entrance.php @@ -23,12 +23,12 @@ $userGrade = $session->userGrade; - + diff --git a/i_entrance/user_info.html b/i_entrance/user_info.html index c741f1f1..fb207a06 100644 --- a/i_entrance/user_info.html +++ b/i_entrance/user_info.html @@ -15,6 +15,7 @@ + @@ -36,7 +37,7 @@ diff --git a/js/admin_server.js b/js/admin_server.js index e8ab64cc..bd157e95 100644 --- a/js/admin_server.js +++ b/js/admin_server.js @@ -4,13 +4,13 @@ var serverAdminTemplate = '\ \ \ \ - \ - \ - \ - \ - \ - \ - \ + \ + \ + \ + \ + \ + \ + \ \ '; @@ -77,14 +77,14 @@ function drawServerAdminList(serverList){ var $tr = $(TemplateEngine(serverAdminTemplate, server)); $table.append($tr); if(!server.valid){ - $tr.find('.valid_if_set').css('background','#333333').prop('disabled', true); + $tr.find('.valid_if_set').prop('disabled', true); } if(!server.installed){ - $tr.find('.valid_if_installed').css('background','#333333').prop('disabled', true); + $tr.find('.valid_if_installed').prop('disabled', true); } }); if(serverList.grade == 5){ - $table.find('.only_admin').css('background','#333333').prop('disabled', true); + $table.find('.only_admin').prop('disabled', true); } } From cb2fbf1a32bf724f045bcd99e238d844e033f48e Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 19:49:07 +0900 Subject: [PATCH 011/101] =?UTF-8?q?common.js=EC=97=90=20iconpath=20?= =?UTF-8?q?=EC=97=B0=EC=82=B0=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/js/common.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hwe/js/common.js b/hwe/js/common.js index 142575e0..0ac528d6 100644 --- a/hwe/js/common.js +++ b/hwe/js/common.js @@ -118,4 +118,14 @@ var TemplateEngine = function (html, options) { try { result = new Function('obj', code).apply(options, [options]); } catch (err) { console.error("'" + err.message + "'", " in \n\nCode:\n", code, "\n"); } return result; +} + +function getIconPath(imgsvr, picture){ + // ../d_shared/common_path.js 필요 + if(!imgsvr){ + return pathConfig.sharedIcon+'/'+picture; + } + else{ + return pathConfig.root+'/d_pic/'+picture; + } } \ No newline at end of file From a534b8f8128c9020e7cde94d6f2f7747405ddd30 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 19:49:22 +0900 Subject: [PATCH 012/101] =?UTF-8?q?=EC=8B=9C=EB=82=98=EB=A6=AC=EC=98=A4=20?= =?UTF-8?q?30=EB=B2=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/scenario/scenario_30.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hwe/scenario/scenario_30.json b/hwe/scenario/scenario_30.json index 7060459b..1f433d76 100644 --- a/hwe/scenario/scenario_30.json +++ b/hwe/scenario/scenario_30.json @@ -47,7 +47,7 @@ [0, "강영식", -1, 0, null, 63, 69, 60, 0, 160, 300, null, null], [0, "김사율", -1, 0, null, 74, 66, 67, 0, 160, 300, null, null], [0, "배장호", -1, 0, null, 62, 48, 60, 0, 160, 300, null, null], - [0, "손민한", -1, 0, null, 85, 84, 94, 0, 160, 300, null, null, "팝콘이 먹고싶다"], + [0, "손민한", -1, 0, null, 85, 84, 94, 0, 160, 300, null, "환술", "팝콘이 먹고싶다"], [0, "송승준", -1, 0, null, 65, 84, 67, 0, 160, 300, null, null], [0, "이용훈", -1, 0, null, 48, 58, 63, 0, 160, 300, null, null], [0, "임경완", -1, 0, null, 68, 57, 39, 0, 160, 300, null, null], @@ -70,7 +70,7 @@ [0, "정보명", -1, 0, null, 69, 31, 39, 0, 160, 300, null, null], [0, "이재곤", -1, 0, null, 40, 41, 39, 0, 160, 300, null, null], [0, "염종석", -1, 0, null, 83, 90, 93, 0, 160, 300, null, null], - [0, "황재균", -1, 0, null, 79, 77, 83, 0, 160, 300, null, null, "안녕하세요 섹머입니다"], + [0, "황재균", -1, 0, null, 79, 77, 83, 0, 160, 300, null, "집중", "안녕하세요 섹머입니다"], [0, "윤학길", -1, 0, null, 81, 76, 82, 0, 160, 300, null, null], [0, "가득염", -1, 0, null, 60, 67, 61, 0, 160, 300, null, null], [0, "조경환", -1, 0, null, 57, 78, 20, 0, 160, 300, null, null], @@ -84,7 +84,7 @@ [0, "금광옥", -1, 0, null, 31, 30, 39, 0, 160, 300, null, null], [0, "김무관", -1, 0, null, 20, 7, 43, 0, 160, 300, null, null], [0, "양승관", -1, 0, null, 46, 44, 22, 0, 160, 300, null, null], - [0, "박철순", -1, 0, null, 89, 82, 80, 0, 160, 300, null, "무쌍"], + [0, "박철순", -1, 0, null, 89, 82, 80, 0, 160, 300, null, "필살"], [0, "하기룡", -1, 0, null, 82, 58, 64, 0, 160, 300, null, null], [0, "황규봉", -1, 0, null, 83, 48, 72, 0, 160, 300, null, null], [0, "계형철", -1, 0, null, 74, 75, 70, 0, 160, 300, null, null], @@ -133,8 +133,8 @@ [0, "최정", -1, 0, null, 89, 91, 88, 0, 160, 300, null, "무쌍"], [0, "조동화", -1, 0, null, 48, 11, 83, 0, 160, 300, null, null], [0, "김강민", -1, 0, null, 77, 77, 82, 0, 160, 300, null, null], - [0, "박용택", -1, 0, null, 92, 90, 92, 0, 160, 300, null, "신중", "팬 여러분 올해는 유광잠바 준비하셔야 될 겁니다"], - [0, "이병규", -1, 0, null, 93, 90, 89, 0, 160, 300, null, "필살"], + [0, "박용택", -1, 0, null, 92, 90, 92, 0, 160, 300, null, "환술", "팬 여러분 올해는 유광잠바 준비하셔야 될 겁니다"], + [0, "이병규", -1, 0, null, 93, 90, 89, 0, 160, 300, null, "위압"], [0, "조인성", -1, 0, null, 49, 86, 25, 0, 160, 300, null, null], [0, "김동수", -1, 0, null, 65, 86, 65, 0, 160, 300, null, null], [0, "유지현", -1, 0, null, 76, 57, 87, 0, 160, 300, null, null], From 5974028c4d3651d492b0c09f543e7001be989ea0 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 19:51:56 +0900 Subject: [PATCH 013/101] =?UTF-8?q?=EB=B9=99=EC=9D=98=20=EC=9E=A5=EC=88=98?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80(=EC=84=A0=ED=83=9D?= =?UTF-8?q?=EC=9D=80=20=EB=AF=B8=EC=99=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- css/config.css | 2 + hwe/css/select_npc.css | 26 +++++ hwe/j_get_select_npc_token.php | 172 +++++++++++++++++++++++++++++++++ hwe/js/select_npc.js | 76 +++++++++++++++ hwe/new_select_npc.php | 103 ++++++++++++++++++++ 5 files changed, 379 insertions(+) create mode 100644 hwe/css/select_npc.css create mode 100644 hwe/j_get_select_npc_token.php create mode 100644 hwe/js/select_npc.js create mode 100644 hwe/new_select_npc.php diff --git a/css/config.css b/css/config.css index 34b9b848..53b22574 100644 --- a/css/config.css +++ b/css/config.css @@ -3,6 +3,7 @@ body { color:white; background-color:black; font-family: '맑은 고딕'; } + table { border: solid 1px; border-spacing: 0px; border-collapse: separate; border-top-color: gray; border-left-color: gray; border-right-color: black; border-bottom-color: black; padding: 0px; @@ -25,6 +26,7 @@ a.just_link { } .with_border{ + margin:0; border: solid 1px; border-spacing: 0px; border-collapse: separate; diff --git a/hwe/css/select_npc.css b/hwe/css/select_npc.css new file mode 100644 index 00000000..d86b3365 --- /dev/null +++ b/hwe/css/select_npc.css @@ -0,0 +1,26 @@ +.card_holder{ + text-align:center; +} +.general_card{ + width:100px; + display:inline-block; +} + + +.general_card label { + display: block; + padding-left: 15px; + text-indent: -15px; + } + +.general_card input { + width: 13px; + height: 13px; + padding: 0; + margin:0; + vertical-align: bottom; + position: relative; + top: -1px; + *overflow: hidden; + } + \ No newline at end of file diff --git a/hwe/j_get_select_npc_token.php b/hwe/j_get_select_npc_token.php new file mode 100644 index 00000000..e924cb8f --- /dev/null +++ b/hwe/j_get_select_npc_token.php @@ -0,0 +1,172 @@ +setReadOnly(); +$userID = Session::getUserID(); + + +$oNow = new \DateTimeImmutable(); + +$now = $oNow->format('Y-m-d H:i:s'); + +$db = DB::db(); + +$oldGeneral = $db->queryFirstField('SELECT `no` FROM general WHERE `owner`=%i', $userID); +if($oldGeneral !== null){ + Json::die([ + 'result'=>false, + 'reason'=>'이미 장수가 생성되었습니다' + ]); +} + +list( + $year, + $month, + $maxgeneral, + $turnterm, + $genius, + $npcmode +) = $db->queryFirstList('SELECT year,month,maxgeneral,turnterm,genius,npcmode from game limit 1'); + +if(!$npcmode){ + Json::die([ + 'result'=>false, + 'reason'=>'빙의 가능한 서버가 아닙니다' + ]); +} + + +$token = $db->queryFirstRow('SELECT * FROM select_npc_token WHERE `owner`=%i AND `valid_until`>=%s', $userID, $now); +$pickResult = []; + + +if($token && $refresh){ + $pickMoreFrom = (new \DateTime($token['pick_more_from']))->getTimestamp(); + $nowT = $oNow->getTimestamp(); + + if($nowT >= $pickMoreFrom){ + $oldPickResult = Json::decode($token['pick_result']); + + foreach($keepResult as $keepId){ + if(\key_exists($keepId, $oldPickResult) && $oldPickResult[$keepId]['keepCnt'] > 0){ + $pickResult[$keepId] = $oldPickResult[$keepId]; + $pickResult[$keepId]['keepCnt']-=1; + } + } + + if(count($pickResult) == count($oldPickResult)){ + $refresh = false; + } + } + else{ + Json::die([ + 'result'=>false, + 'reason'=>'아직 다시 뽑을 수 없습니다', + ]); + } +} + +if($token && !$refresh){ + Json::die([ + 'result'=>true, + 'pick'=>Json::decode($token['pick_result']), + 'pickMoreFrom'=>$token['pick_more_from'], + 'validUntil'=>$token['valid_until'] + ]); +} + +$candidates = []; + +$weight = []; +foreach($db->query('SELECT `no`, `name`, leader, power, intel, imgsvr, picture, special, special2 FROM general WHERE npc=2') as $general){ + $general['special'] = \sammo\SpecialityConst::DOMESTIC[$general['special']][0]??'-'; + $general['special2'] = \sammo\SpecialityConst::WAR[$general['special2']][0]??'-'; + $candidates[$general['no']] = $general + ['keepCnt'=>KEEP_CNT]; + $allStat = $general['leader'] + $general['power'] + $general['intel']; + $weight[$general['no']] = pow($allStat, 1.7); +} + +foreach($db->queryFirstColumn('SELECT pick_result FROM select_npc_token WHERE `owner`!=%i AND valid_until >=%s', $userID, $now) as $reserved){ + $reserved = Json::decode($reserved); + foreach(array_keys($reserved) as $reservedNPC){ + if(key_exists($reservedNPC, $weight)){ + unset($candidates[$reservedNPC]); + unset($weight[$reservedNPC]); + } + } +} + +$pickLimit = min(count($candidates), 5); + +while(count($pickResult) < $pickLimit){ + $generalID = Util::choiceRandomUsingWeight($weight); + if(!key_exists($generalID, $pickResult)){ + $pickResult[$generalID] = $candidates[$generalID]; + } +} + +$newNonce = mt_rand(0, 0xfffffff); + +$validMinute = max(VALID_MINUTE, intdiv($turnterm, 2)); +$pickMoreMinute = max(PICK_MORE_MINUTE, intdiv($turnterm, 5)); + +$validUntil = $oNow->add(new \DateInterval(sprintf('PT%dM', $validMinute))); +$pickMoreFrom = $oNow->add(new \DateInterval(sprintf('PT%dM', $pickMoreMinute))); + +$db->query('LOCK TABLES select_npc_token WRITE'); + +$db->delete('select_npc_token', 'valid_until < %s', $now); + +$inserted = 0; + +if($token){ + $db->update('select_npc_token', [ + 'valid_until'=>$validUntil->format('Y-m-d H:i:s'), + 'pick_more_from'=>$pickMoreFrom->format('Y-m-d H:i:s'), + 'pick_result'=>Json::encode($pickResult), + 'nonce'=>$newNonce + ], 'owner = %i AND nonce = %i', $userID, $token['nonce']); + if($db->affectedRows()){ + $inserted = -1; + } +} +else{ + $db->insertIgnore('select_npc_token', [ + 'owner'=>$userID, + 'valid_until'=>$validUntil->format('Y-m-d H:i:s'), + 'pick_more_from'=>'2000-01-01 01:00:00', + 'pick_result'=>Json::encode($pickResult), + 'nonce'=>$newNonce + ]); + + if($db->affectedRows()){ + $inserted = 1; + } +} + +$db->query('UNLOCK TABLES'); + +if($inserted === 0){ + Json::die([ + 'result'=>false, + 'reason'=>'중복 요청, 다시 랜덤 토큰을 확인해주세요' + ]); +} + +Json::die([ + 'result'=>true, + 'pick'=>$pickResult, + 'pickMoreFrom'=>($inserted===-1)?$pickMoreFrom->format('Y-m-d H:i:s'):'2000-01-01 01:00:00', + 'validUntil'=>$validUntil->format('Y-m-d H:i:s') +]); \ No newline at end of file diff --git a/hwe/js/select_npc.js b/hwe/js/select_npc.js new file mode 100644 index 00000000..8229d686 --- /dev/null +++ b/hwe/js/select_npc.js @@ -0,0 +1,76 @@ +var templateGeneralCard = +'
\ +

<%name%>

\ +

\ +

<%leader%> / <%power%> / <%intel%>
\ + <%special%> / <%special2%>

\ + \ + \ +
'; + +function updatePickMoreTimer(){ + var $btn = $('#btn_pick_more'); + var now = Date.now(); + var remain = ($btn.data('available') - now) / 1000; + if(remain <= 0){ + $btn.prop('disabled', false) + $btn.html('다른 장수 보기'); + return; + } + + $btn.html('다른 장수 보기({0}초)'.format(Math.ceil(remain))); + + setTimeout(updatePickMoreTimer, 250); +} + +function printGenerals(value){ + $('.card_holder').empty(); + $('#valid_until_text').html(value.validUntil); + $('#btn_pick_more').data('available', new Date(value.pickMoreFrom).getTime()).prop('disabled',true); + $.each(value.pick, function(idx, cardData){ + cardData.iconPath = getIconPath(cardData.imgsvr, cardData.picture); + console.log(cardData); + + var $card = $(TemplateEngine(templateGeneralCard, cardData)); + console.log($card); + + $('.card_holder').append($card); + }); + + updatePickMoreTimer(); +} + +jQuery(function($){ + +$.post('j_get_select_npc_token.php').then(function(value){ + if(!value.result){ + alert(value.reason); + return; + } + + console.log(value); + printGenerals(value); +}); + +$('#btn_pick_more').click(function(){ + var generals = $.map($('.keep_select:checked'), function(value){ + return $(value).val(); + }); + console.log(generals); + $.post({ + url:'j_get_select_npc_token.php', + dataType:'json', + data:{ + refresh:true, + keep:generals + } + }).then(function(result){ + if(!result.result){ + alert(result.reason); + location.refresh(); + } + printGenerals(result); + }); +}); + +}); \ No newline at end of file diff --git a/hwe/new_select_npc.php b/hwe/new_select_npc.php new file mode 100644 index 00000000..d5e18c35 --- /dev/null +++ b/hwe/new_select_npc.php @@ -0,0 +1,103 @@ +setReadOnly(); +$userID = Session::getUserID(); +$rootDB = RootDB::db(); +$db = DB::db(); + +//회원 테이블에서 정보확인 +$member = $rootDB->queryFirstRow('select no,name,picture,grade from member where no=%i', $userID); + +if(!$member) { + $session->logout(); + header('location:..'); + die(); +} + +list($npcmode, $maxgeneral) = $db->queryFirstList('SELECT npcmode,maxgeneral FROM game LIMIT 1'); + +if(!$npcmode) { + header('location:..'); + die(); +} + +$gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2'); + +$nations = $db->queryAllLists('SELECT `name`, scoutmsg, color FROM nation'); +?> + + + +<?=UniqueConst::$serverName?>: NPC빙의 + + + + + + + + + + + + + + += $maxgeneral) { +?> + + + + + + + +
+
장 수 선 택
+
계 정 관 리 - +
<%korName%>(<%name%>)<%status%><%version%>
+ +
+ + + + + + + + + + + + + + + +
임관 권유 메세지
+ +
+
장수 빙의
+
+( 까지 유효)
+
+
+
+
+
+
+
+
+
+ + + From 3c1c33949896d0d422f0e0979f1e0bdd5a6e42e2 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 21:20:15 +0900 Subject: [PATCH 014/101] =?UTF-8?q?=EC=9E=A5=EC=88=98=20=EB=B9=99=EC=9D=98?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/css/common.css | 3 +- hwe/css/select_npc.css | 17 ++++ hwe/j_get_select_npc_token.php | 12 +-- hwe/j_select_npc.php | 109 ++++++++++++++++++++ hwe/js/select_npc.js | 25 ++++- hwe/new_select_npc.php | 103 ------------------- hwe/select_npc.php | 179 ++++++++++++--------------------- hwe/select_npc_post.php | 144 -------------------------- js/common.js | 10 ++ 9 files changed, 226 insertions(+), 376 deletions(-) create mode 100644 hwe/j_select_npc.php delete mode 100644 hwe/new_select_npc.php delete mode 100644 hwe/select_npc_post.php diff --git a/hwe/css/common.css b/hwe/css/common.css index 488dad05..eecb5928 100644 --- a/hwe/css/common.css +++ b/hwe/css/common.css @@ -3,11 +3,12 @@ html, body{ background-color:black; color:white; + line-height:1.3; } table { font-family:'맑은 고딕'; } font { font-family:'맑은 고딕'; } -input { font-family:'맑은 고딕'; height:20px } +input { font-family:'맑은 고딕'; font-size:13px; } select { font-family:'굴림'; line-height:100%; } /* */ diff --git a/hwe/css/select_npc.css b/hwe/css/select_npc.css index d86b3365..d6935563 100644 --- a/hwe/css/select_npc.css +++ b/hwe/css/select_npc.css @@ -1,3 +1,8 @@ +.container{ + width:1000px; + margin:0 auto; +} + .card_holder{ text-align:center; } @@ -6,6 +11,18 @@ display:inline-block; } +.general_card h4 { + margin:0; +} + +.general_card p { + margin:0; +} + + +.general_card .select_btn { + width:100%; +} .general_card label { display: block; diff --git a/hwe/j_get_select_npc_token.php b/hwe/j_get_select_npc_token.php index e924cb8f..915b2f30 100644 --- a/hwe/j_get_select_npc_token.php +++ b/hwe/j_get_select_npc_token.php @@ -31,13 +31,10 @@ if($oldGeneral !== null){ } list( - $year, - $month, $maxgeneral, $turnterm, - $genius, $npcmode -) = $db->queryFirstList('SELECT year,month,maxgeneral,turnterm,genius,npcmode from game limit 1'); +) = $db->queryFirstList('SELECT maxgeneral,turnterm,npcmode from game limit 1'); if(!$npcmode){ Json::die([ @@ -46,7 +43,6 @@ if(!$npcmode){ ]); } - $token = $db->queryFirstRow('SELECT * FROM select_npc_token WHERE `owner`=%i AND `valid_until`>=%s', $userID, $now); $pickResult = []; @@ -94,7 +90,7 @@ foreach($db->query('SELECT `no`, `name`, leader, power, intel, imgsvr, picture, $general['special2'] = \sammo\SpecialityConst::WAR[$general['special2']][0]??'-'; $candidates[$general['no']] = $general + ['keepCnt'=>KEEP_CNT]; $allStat = $general['leader'] + $general['power'] + $general['intel']; - $weight[$general['no']] = pow($allStat, 1.7); + $weight[$general['no']] = pow($allStat, 1.5); } foreach($db->queryFirstColumn('SELECT pick_result FROM select_npc_token WHERE `owner`!=%i AND valid_until >=%s', $userID, $now) as $reserved){ @@ -124,8 +120,6 @@ $pickMoreMinute = max(PICK_MORE_MINUTE, intdiv($turnterm, 5)); $validUntil = $oNow->add(new \DateInterval(sprintf('PT%dM', $validMinute))); $pickMoreFrom = $oNow->add(new \DateInterval(sprintf('PT%dM', $pickMoreMinute))); -$db->query('LOCK TABLES select_npc_token WRITE'); - $db->delete('select_npc_token', 'valid_until < %s', $now); $inserted = 0; @@ -155,8 +149,6 @@ else{ } } -$db->query('UNLOCK TABLES'); - if($inserted === 0){ Json::die([ 'result'=>false, diff --git a/hwe/j_select_npc.php b/hwe/j_select_npc.php new file mode 100644 index 00000000..51fb91e9 --- /dev/null +++ b/hwe/j_select_npc.php @@ -0,0 +1,109 @@ +false, + 'reason'=>'장수를 선택하지 않았습니다' + ]); +} + +$session = Session::requireLogin()->setReadOnly(); +$userID = Session::getUserID(); +$db = DB::db(); +$rootDB = RootDB::db(); + +$oNow = new \DateTimeImmutable(); +$now = $oNow->format('Y-m-d H:i:s'); + +$userNick = RootDB::db()->queryFirstField('SELECT `NAME` FROM member WHERE `NO`=%i',$userID); +if(!$userNick){ + Json::die([ + 'result'=>false, + 'reason'=>'멤버 정보를 가져오지 못했습니다.' + ]); +} + +$pickResult = $db->queryFirstField('SELECT pick_result FROM select_npc_token WHERE `owner`=%i AND `valid_until`>=%s', $userID, $now); +if(!$pickResult){ + Json::die([ + 'result'=>false, + 'reason'=>'유효한 장수 목록이 없습니다.' + ]); +} + + +$pickResult = Json::decode($pickResult); +if(!key_exists($pick, $pickResult)){ + Json::die([ + 'result'=>false, + 'reason'=>'선택한 장수가 목록에 없습니다.' + ]); +} +$pickedNPC = $pickResult[$pick]; + + +$gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2'); +list( + $year, + $month, + $maxgeneral, + $npcmode +) = $db->queryFirstList('SELECT year,month,maxgeneral,npcmode from game limit 1'); + +if(!$npcmode){ + Json::die([ + 'result'=>false, + 'reason'=>'빙의 가능한 서버가 아닙니다' + ]); +} + +if ($gencount >= $maxgeneral) { + Json::die([ + 'result'=>false, + 'reason'=>'더 이상 등록 할 수 없습니다.' + ]); +} + +//등록 시작 +$db->update('general', [ + 'owner'=>$userID, + 'npc'=>1 +], 'owner <= 0 AND npc = 2 AND no = %i', $pick); + +if(!$db->affectedRows()){ + Json::die([ + 'result'=>false, + 'reason'=>'장수 등록에 실패했습니다.' + ]); +} + +$db->delete('select_npc_token', 'owner=%i', $userID); + +pushGeneralHistory($pickedNPC, "●{$year}년 {$month}월:{$pickedNPC['name']}의 육체에 {$userNick}(이)가 빙의되다."); +//pushGenLog($me, $mylog); +pushGeneralPublicRecord(["●{$month}월:{$pickedNPC['name']}의 육체에 {$userNick}(이)가 빙의됩니다!"], $year, $month); + +pushAdminLog(["가입 : {$userID} // {$session->userName} // {$pick} // ".getenv("REMOTE_ADDR")]); + +$rootDB->insert('member_log', [ + 'member_no' => $userID, + 'date'=>date('Y-m-d H:i:s'), + 'action_type'=>'make_general', + 'action'=>Json::encode([ + 'server'=>DB::prefix(), + 'type'=>'npc', + 'generalID'=>$npc['no'], + 'generalName'=>$npc['name'] + ]) +]); + +Json::die([ + 'result'=>true, + 'reason'=>'success' +]); \ No newline at end of file diff --git a/hwe/js/select_npc.js b/hwe/js/select_npc.js index 8229d686..5170d58d 100644 --- a/hwe/js/select_npc.js +++ b/hwe/js/select_npc.js @@ -8,6 +8,27 @@ var templateGeneralCard = \ '; +function pickGeneral(){ + $btn = $(this); + + $.post({ + url:'j_select_npc.php', + dataType:'json', + data:{ + pick:$btn.val() + } + }).then(function(result){ + if(!result.result){ + alert(result.reason); + location.refresh(); + } + + alert('빙의에 성공했습니다.'); + location.href = './'; + }); + return false; +} + function updatePickMoreTimer(){ var $btn = $('#btn_pick_more'); var now = Date.now(); @@ -29,18 +50,18 @@ function printGenerals(value){ $('#btn_pick_more').data('available', new Date(value.pickMoreFrom).getTime()).prop('disabled',true); $.each(value.pick, function(idx, cardData){ cardData.iconPath = getIconPath(cardData.imgsvr, cardData.picture); - console.log(cardData); var $card = $(TemplateEngine(templateGeneralCard, cardData)); console.log($card); $('.card_holder').append($card); + $card.find('.select_btn').click(pickGeneral); }); updatePickMoreTimer(); } -jQuery(function($){ +$(function($){ $.post('j_get_select_npc_token.php').then(function(value){ if(!value.result){ diff --git a/hwe/new_select_npc.php b/hwe/new_select_npc.php deleted file mode 100644 index d5e18c35..00000000 --- a/hwe/new_select_npc.php +++ /dev/null @@ -1,103 +0,0 @@ -setReadOnly(); -$userID = Session::getUserID(); -$rootDB = RootDB::db(); -$db = DB::db(); - -//회원 테이블에서 정보확인 -$member = $rootDB->queryFirstRow('select no,name,picture,grade from member where no=%i', $userID); - -if(!$member) { - $session->logout(); - header('location:..'); - die(); -} - -list($npcmode, $maxgeneral) = $db->queryFirstList('SELECT npcmode,maxgeneral FROM game LIMIT 1'); - -if(!$npcmode) { - header('location:..'); - die(); -} - -$gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2'); - -$nations = $db->queryAllLists('SELECT `name`, scoutmsg, color FROM nation'); -?> - - - -<?=UniqueConst::$serverName?>: NPC빙의 - - - - - - - - - - - - - - -= $maxgeneral) { -?> - - - - - - - -
-
장 수 선 택
- - -
- - - - - - - - - - - - - - - -
임관 권유 메세지
- -
-
장수 빙의
-
-( 까지 유효)
-
-
-
-
-
-
-
-
-
-
- - diff --git a/hwe/select_npc.php b/hwe/select_npc.php index 868318b9..99e4890d 100644 --- a/hwe/select_npc.php +++ b/hwe/select_npc.php @@ -6,141 +6,88 @@ include "func.php"; $session = Session::requireLogin()->setReadOnly(); $userID = Session::getUserID(); -$rootDB = RootDB::db(); $db = DB::db(); -//회원 테이블에서 정보확인 -$member = $rootDB->queryFirstRow('select no,name,picture,grade from member where no=%i', $userID); +list($npcmode, $maxgeneral) = $db->queryFirstList('SELECT npcmode,maxgeneral FROM game LIMIT 1'); -if(!$member) { - MessageBox("잘못된 접근입니다!!!"); - echo ""; - exit(1); -} - -$admin = $db->queryFirstRow('select npcmode,maxgeneral,show_img_level from game limit 1'); - -if($admin['npcmode'] != 1) { - header('Location:join.php'); +if(!$npcmode) { + header('location:..'); die(); } +$gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2'); -$connect=$db->get(); - +$nations = $db->queryAllLists('SELECT `name`, scoutmsg, color FROM nation'); ?> -<?=UniqueConst::$serverName?>: NPC선택 +<?=UniqueConst::$serverName?>: NPC빙의 + + + + + + + - - - -
장 수 선 택
- - -
-= $admin['maxgeneral']) { - echo ""; - echo ""; - exit(); -} += $maxgeneral) { ?> - - -"; - } else { - echo " - "; - } -} -?> -
임관 권유 메세지
{$nation['name']}-
{$nation['name']}{$nation['scoutmsg']}
- -
- - - - -= 3) { -?> - - - - - - - - - - - - - - -
장수 선택
장수/1001.jpg border=0 name=picture width=64 height=64>
- -
- 컴퓨터가 조작중이던 NPC장수를 조종하게 됩니다.
- 80시간동안 휴식을 취하면 다시 컴퓨터가 조종하게 되고 장수의 소유권을 잃습니다. -
-
- - - -
- - + + + + +
+
장 수 선 택
+ + +
+ + + + + + + + + + + + + + + +
임관 권유 메세지
+ +
+
장수 빙의
+
+( 까지 유효)
+
+
+
+
+
+
+
+
+
+
+ diff --git a/hwe/select_npc_post.php b/hwe/select_npc_post.php deleted file mode 100644 index 4387baf7..00000000 --- a/hwe/select_npc_post.php +++ /dev/null @@ -1,144 +0,0 @@ -rule('required', 'face') -->rule('integer', 'face'); -if(!$v->validate()){ - MessageBox($v->errorStr()); - echo ""; - exit(1); -} - -$session = Session::requireLogin()->setReadOnly(); -$userID = Session::getUserID(); - -$face = (int)$_POST['face']; -$rootDB = RootDB::db(); - -//회원 테이블에서 정보확인 -$member = $rootDB->queryFirstRow('SELECT `no`, id, picture, grade, `name` FROM member WHERE no=%i', $userID); - -if(!$member) { - MessageBox("잘못된 접근입니다!!!"); - echo ""; - exit(1); -} - -$db = DB::db(); - -$npc = $db->queryFirstRow('SELECT `no`, `name`, `npc`, `level` FROM general WHERE `no`=%i', $face); -if(!$npc){ - echo ""; - echo ""; - exit(); -} - - -########## 동일 정보 존재여부 확인. ########## - -list( - $year, - $month, - $maxgeneral, - $turnterm, - $genius, - $npcmode -) = $db->queryFirstList('SELECT year,month,maxgeneral,turnterm,genius,npcmode from game limit 1'); - -$gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2'); -$oldGeneral = $db->queryFirstField('SELECT `no` FROM general WHERE `owner`=%i', $userID); - -if($npcmode != 1) { - echo ""; - echo ""; - exit(); -} -if($oldGeneral) { - echo(""); - exit; -} -if($maxgeneral <= $gencount) { - echo(""); - exit; -} -if($npc['npc'] < 2) { - echo(""); - exit; -} -if($npc['npc'] != 2) { - echo(""); - exit; -} -/*if($npc['level'] >= 5) { - echo(""); - exit; - -} */ - -$userNick = RootDB::db()->queryFirstField('SELECT `NAME` FROM member WHERE `NO`=%i',Session::getUserID()); - -$npcID = $npc['no']; -$db->update('general', [ - 'name2'=>$userNick, - 'npc'=>1, - 'killturn'=>6, - 'mode'=>2, - 'owner'=>$userID -], 'no=%i and npc=2', $npcID); -$affected = $db->affectedRows(); -if(!$affected){ - echo(""); - exit; -} - -$me = [ - 'no'=>$npcID -]; - -pushGeneralHistory($me, "●{$year}년 {$month}월:{$npc['name']}의 육체에 {$userNick}(이)가 빙의되다."); -//pushGenLog($me, $mylog); -pushGeneralPublicRecord(["●{$month}월:{$npc['name']}의 육체에 {$userNick}(이)가 빙의됩니다!"], $year, $month); - -pushAdminLog(["가입 : {$userID} // {$session->userName} // {$npcID} // ".getenv("REMOTE_ADDR")]); - -$rootDB->insert('member_log', [ - 'member_no' => $userID, - 'date'=>date('Y-m-d H:i:s'), - 'action_type'=>'make_general', - 'action'=>Json::encode([ - 'server'=>DB::prefix(), - 'type'=>'npc', - 'generalID'=>$npc['no'], - 'generalName'=>$npc['name'] - ]) -]); - -?> - diff --git a/js/common.js b/js/common.js index 142575e0..0ac528d6 100644 --- a/js/common.js +++ b/js/common.js @@ -118,4 +118,14 @@ var TemplateEngine = function (html, options) { try { result = new Function('obj', code).apply(options, [options]); } catch (err) { console.error("'" + err.message + "'", " in \n\nCode:\n", code, "\n"); } return result; +} + +function getIconPath(imgsvr, picture){ + // ../d_shared/common_path.js 필요 + if(!imgsvr){ + return pathConfig.sharedIcon+'/'+picture; + } + else{ + return pathConfig.root+'/d_pic/'+picture; + } } \ No newline at end of file From 20f991a20571c66994dc2503e47ad5833cb01e7f Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 21:22:38 +0900 Subject: [PATCH 015/101] =?UTF-8?q?=EB=B9=99=EC=9D=98=EC=8B=9C=20=EC=98=A4?= =?UTF-8?q?=EB=9E=98=EB=90=9C=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/j_select_npc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hwe/j_select_npc.php b/hwe/j_select_npc.php index 51fb91e9..e4ff95a4 100644 --- a/hwe/j_select_npc.php +++ b/hwe/j_select_npc.php @@ -83,7 +83,7 @@ if(!$db->affectedRows()){ ]); } -$db->delete('select_npc_token', 'owner=%i', $userID); +$db->delete('select_npc_token', 'owner=%i or valid_until < %s', $userID, $now); pushGeneralHistory($pickedNPC, "●{$year}년 {$month}월:{$pickedNPC['name']}의 육체에 {$userNick}(이)가 빙의되다."); //pushGenLog($me, $mylog); From 5dfb844c7eadf994ed4d3b1f201ff92a522c5add Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 21:40:59 +0900 Subject: [PATCH 016/101] =?UTF-8?q?=EB=B9=99=EC=9D=98=20=EC=9E=AC=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=EC=8B=9C=EA=B0=84=EC=9D=84=20=EB=B9=A0=EB=A5=B4?= =?UTF-8?q?=EA=B2=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/j_get_select_npc_token.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hwe/j_get_select_npc_token.php b/hwe/j_get_select_npc_token.php index 915b2f30..53863ade 100644 --- a/hwe/j_get_select_npc_token.php +++ b/hwe/j_get_select_npc_token.php @@ -4,8 +4,8 @@ namespace sammo; include "lib.php"; include "func.php"; -const VALID_MINUTE = 5; -const PICK_MORE_MINUTE = 2; +const VALID_SECOND = 25; +const PICK_MORE_SECOND = 10; const KEEP_CNT = 3; @@ -114,11 +114,11 @@ while(count($pickResult) < $pickLimit){ $newNonce = mt_rand(0, 0xfffffff); -$validMinute = max(VALID_MINUTE, intdiv($turnterm, 2)); -$pickMoreMinute = max(PICK_MORE_MINUTE, intdiv($turnterm, 5)); +$validSecond = max(VALID_SECOND, $turnterm*25); +$pickMoreSecond = max(PICK_MORE_SECOND, $turnterm*10); -$validUntil = $oNow->add(new \DateInterval(sprintf('PT%dM', $validMinute))); -$pickMoreFrom = $oNow->add(new \DateInterval(sprintf('PT%dM', $pickMoreMinute))); +$validUntil = $oNow->add(new \DateInterval(sprintf('PT%dS', $validSecond))); +$pickMoreFrom = $oNow->add(new \DateInterval(sprintf('PT%dS', $pickMoreSecond))); $db->delete('select_npc_token', 'valid_until < %s', $now); From a75eb5b74e853756ed2c8f3644018d577a6ba056 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 21:44:15 +0900 Subject: [PATCH 017/101] =?UTF-8?q?=EC=9E=A5=EC=88=98=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=20=ED=85=8C=EC=9D=B4=EB=B8=94=EC=9D=84=20schema=EC=97=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/sql/reset.sql | 4 +++- hwe/sql/schema.sql | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/hwe/sql/reset.sql b/hwe/sql/reset.sql index ef31cd89..f2ecae16 100644 --- a/hwe/sql/reset.sql +++ b/hwe/sql/reset.sql @@ -46,4 +46,6 @@ DROP TABLE IF EXISTS world_history; # 전체 이벤트 테이블 삭제(연감 대체?) DROP TABLE IF EXISTS general_public_record; -DROP TABLE IF EXISTS reserved_open; \ No newline at end of file +DROP TABLE IF EXISTS reserved_open; + +DROP TABLE IF EXISTS select_npc_token; \ No newline at end of file diff --git a/hwe/sql/schema.sql b/hwe/sql/schema.sql index 7ecd0e54..911c594f 100644 --- a/hwe/sql/schema.sql +++ b/hwe/sql/schema.sql @@ -656,3 +656,19 @@ CREATE TABLE `reserved_open` ( ) DEFAULT CHARSET=utf8mb4 ENGINE=MyISAM; + +###### +# 장수 선택 토큰 +CREATE TABLE `select_npc_token` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `owner` INT(11) NOT NULL, + `valid_until` DATETIME NOT NULL, + `pick_more_from` DATETIME NOT NULL, + `pick_result` TEXT NOT NULL COMMENT 'json', + `nonce` INT(11) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `owner` (`owner`), + INDEX `valid_until` (`valid_until`) +) +DEFAULT CHARSET=utf8mb4 +ENGINE=MyISAM; From 683a844a086d3f7d966763444b73a5cc3baa328e Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 22:39:21 +0900 Subject: [PATCH 018/101] =?UTF-8?q?=EB=B9=99=EC=9D=98=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EA=B0=9C=EC=84=A0=20-=20=EC=9C=A0=ED=9A=A8=20=EA=B8=B0?= =?UTF-8?q?=EA=B0=84=20=EA=B4=80=EB=A0=A8=20=EB=8A=98=EB=A6=BC.=20-=20?= =?UTF-8?q?=EC=9C=A0=ED=9A=A8=20=EA=B8=B0=EA=B0=84=20=EA=B0=80=EA=B9=8C?= =?UTF-8?q?=EC=9B=8C=EC=A7=80=EB=A9=B4=20=EC=83=89=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=ED=91=9C=EC=8B=9C.=20=EB=A7=8C=EB=A3=8C=20=ED=91=9C=EA=B8=B0?= =?UTF-8?q?=EB=8F=84=20=EC=B6=94=EA=B0=80=20-=20=EB=8B=A4=EB=A5=B8=20?= =?UTF-8?q?=EC=9E=A5=EC=88=98=20=EB=B3=B4=EA=B8=B0=EB=A5=BC=20=EB=82=A8?= =?UTF-8?q?=EC=9D=80=20=EC=B4=88=20=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/css/select_npc.css | 9 +++++++-- hwe/j_get_select_npc_token.php | 9 +++++++-- hwe/js/select_npc.js | 29 +++++++++++++++++++++++++++-- hwe/select_npc.php | 16 ++++++++-------- 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/hwe/css/select_npc.css b/hwe/css/select_npc.css index d6935563..8d345056 100644 --- a/hwe/css/select_npc.css +++ b/hwe/css/select_npc.css @@ -39,5 +39,10 @@ position: relative; top: -1px; *overflow: hidden; - } - \ No newline at end of file +} + + +#outdate_token{ + color:red; + display:none; +} \ No newline at end of file diff --git a/hwe/j_get_select_npc_token.php b/hwe/j_get_select_npc_token.php index 53863ade..613eff5d 100644 --- a/hwe/j_get_select_npc_token.php +++ b/hwe/j_get_select_npc_token.php @@ -4,7 +4,7 @@ namespace sammo; include "lib.php"; include "func.php"; -const VALID_SECOND = 25; +const VALID_SECOND = 90; const PICK_MORE_SECOND = 10; const KEEP_CNT = 3; @@ -74,10 +74,14 @@ if($token && $refresh){ } if($token && !$refresh){ + $pickMoreFrom = (new \DateTime($token['pick_more_from']))->getTimestamp(); + $nowT = $oNow->getTimestamp(); + Json::die([ 'result'=>true, 'pick'=>Json::decode($token['pick_result']), 'pickMoreFrom'=>$token['pick_more_from'], + 'pickMoreSeconds'=>$pickMoreFrom-$nowT, 'validUntil'=>$token['valid_until'] ]); } @@ -114,7 +118,7 @@ while(count($pickResult) < $pickLimit){ $newNonce = mt_rand(0, 0xfffffff); -$validSecond = max(VALID_SECOND, $turnterm*25); +$validSecond = max(VALID_SECOND, $turnterm*40); $pickMoreSecond = max(PICK_MORE_SECOND, $turnterm*10); $validUntil = $oNow->add(new \DateInterval(sprintf('PT%dS', $validSecond))); @@ -160,5 +164,6 @@ Json::die([ 'result'=>true, 'pick'=>$pickResult, 'pickMoreFrom'=>($inserted===-1)?$pickMoreFrom->format('Y-m-d H:i:s'):'2000-01-01 01:00:00', + 'pickMoreSeconds'=>($inserted===-1)?$pickMoreSecond:0, 'validUntil'=>$validUntil->format('Y-m-d H:i:s') ]); \ No newline at end of file diff --git a/hwe/js/select_npc.js b/hwe/js/select_npc.js index 5170d58d..eae34bc7 100644 --- a/hwe/js/select_npc.js +++ b/hwe/js/select_npc.js @@ -29,8 +29,29 @@ function pickGeneral(){ return false; } +function updateOutdateTimer(){ + var $validUntilText = $('#valid_until_text'); + var now = Date.now(); + var validUntil = $validUntilText.data('until'); + if(validUntil <= 0){ + return; + } + else if(validUntil < now){ + $validUntilText.data('until',0); + $('#valid_until').hide(); + $('#outdate_token').show(); + return; + } + else if(validUntil - now <= 30000){ + $validUntilText.css('color', "rgb(255, {0}, {0})".format(255*(validUntil - now)/30000)); + } + + setTimeout(updateOutdateTimer, 1000); +} + function updatePickMoreTimer(){ var $btn = $('#btn_pick_more'); + var now = Date.now(); var remain = ($btn.data('available') - now) / 1000; if(remain <= 0){ @@ -46,8 +67,10 @@ function updatePickMoreTimer(){ function printGenerals(value){ $('.card_holder').empty(); - $('#valid_until_text').html(value.validUntil); - $('#btn_pick_more').data('available', new Date(value.pickMoreFrom).getTime()).prop('disabled',true); + $('#valid_until_text').html(value.validUntil).data('until', (new Date(value.validUntil)).getTime()).show().css('color','white'); + $('#outdate_token').hide(); + var time = Date.now() + value.pickMoreSeconds*1000; + $('#btn_pick_more').data('available', time).prop('disabled',true); $.each(value.pick, function(idx, cardData){ cardData.iconPath = getIconPath(cardData.imgsvr, cardData.picture); @@ -59,6 +82,7 @@ function printGenerals(value){ }); updatePickMoreTimer(); + updateOutdateTimer(); } $(function($){ @@ -90,6 +114,7 @@ $('#btn_pick_more').click(function(){ alert(result.reason); location.refresh(); } + console.log(result); printGenerals(result); }); }); diff --git a/hwe/select_npc.php b/hwe/select_npc.php index 99e4890d..ee13d4f8 100644 --- a/hwe/select_npc.php +++ b/hwe/select_npc.php @@ -24,15 +24,15 @@ $nations = $db->queryAllLists('SELECT `name`, scoutmsg, color FROM nation'); <?=UniqueConst::$serverName?>: NPC빙의 - - - - - + + + + + - - + + @@ -78,7 +78,7 @@ history.go(-1);
장수 빙의
-( 까지 유효)
+( 까지 유효)- 만료 -
From 95445d8f8af94835b6384c239b19caca2d0adb00 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 22:46:56 +0900 Subject: [PATCH 019/101] =?UTF-8?q?=EB=B9=99=EC=9D=98=EC=B0=BD=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=A7=8C=EB=A3=8C=20=ED=9B=84=20=EB=8B=A4=EB=A5=B8?= =?UTF-8?q?=20=EC=9E=A5=EC=88=98=20=EB=B3=B4=EA=B8=B0=20=EC=8B=9C=20?= =?UTF-8?q?=EC=95=88=EB=B3=B4=EC=9D=B4=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/js/select_npc.js | 3 ++- hwe/select_npc.php | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hwe/js/select_npc.js b/hwe/js/select_npc.js index eae34bc7..31646829 100644 --- a/hwe/js/select_npc.js +++ b/hwe/js/select_npc.js @@ -67,7 +67,8 @@ function updatePickMoreTimer(){ function printGenerals(value){ $('.card_holder').empty(); - $('#valid_until_text').html(value.validUntil).data('until', (new Date(value.validUntil)).getTime()).show().css('color','white'); + $('#valid_until').show(); + $('#valid_until_text').html(value.validUntil).data('until', (new Date(value.validUntil)).getTime()).css('color','white'); $('#outdate_token').hide(); var time = Date.now() + value.pickMoreSeconds*1000; $('#btn_pick_more').data('available', time).prop('disabled',true); diff --git a/hwe/select_npc.php b/hwe/select_npc.php index ee13d4f8..f6808847 100644 --- a/hwe/select_npc.php +++ b/hwe/select_npc.php @@ -32,7 +32,7 @@ $nations = $db->queryAllLists('SELECT `name`, scoutmsg, color FROM nation'); - + @@ -78,7 +78,7 @@ history.go(-1);
장수 빙의
-( 까지 유효)- 만료 -
+(까지 유효)- 만료 -
From dec24e09cfa35a7a225d256199b2149a9c326b90 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 22:52:53 +0900 Subject: [PATCH 020/101] =?UTF-8?q?=EB=B9=99=EC=9D=98=EC=8B=9C=20=EC=9E=A5?= =?UTF-8?q?=EC=88=98=EB=AA=85=20=EB=B9=BC=EB=A8=B9=EB=8A=94=20=EB=B2=84?= =?UTF-8?q?=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/j_select_npc.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hwe/j_select_npc.php b/hwe/j_select_npc.php index e4ff95a4..4cde200b 100644 --- a/hwe/j_select_npc.php +++ b/hwe/j_select_npc.php @@ -72,8 +72,11 @@ if ($gencount >= $maxgeneral) { //등록 시작 $db->update('general', [ + 'name2'=>$userNick, + 'npc'=>1, + 'killturn'=>6, + 'mode'=>2, 'owner'=>$userID, - 'npc'=>1 ], 'owner <= 0 AND npc = 2 AND no = %i', $pick); if(!$db->affectedRows()){ From 5e4493b49a56b19203e18cb6901e0778fc147147 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 23:03:10 +0900 Subject: [PATCH 021/101] =?UTF-8?q?=EB=B9=99=EC=9D=98=20=EB=AA=A9=EB=A1=9D?= =?UTF-8?q?=EC=9D=84=20=EC=A2=85=EB=8A=A5=20=EC=88=9C=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A0=AC=ED=95=B4=EC=84=9C=20=ED=91=9C=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/js/select_npc.js | 13 ++++++++++++- hwe/select_npc.php | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/hwe/js/select_npc.js b/hwe/js/select_npc.js index 31646829..b41713ff 100644 --- a/hwe/js/select_npc.js +++ b/hwe/js/select_npc.js @@ -72,7 +72,18 @@ function printGenerals(value){ $('#outdate_token').hide(); var time = Date.now() + value.pickMoreSeconds*1000; $('#btn_pick_more').data('available', time).prop('disabled',true); - $.each(value.pick, function(idx, cardData){ + + var pick = $.map(value.pick, function(value, key) { + return value; + }); + + pick.sort(function(lhs, rhs){ + var lsum = lhs.leader+lhs.power+lhs.intel; + var rsum = rhs.leader+rhs.power+rhs.intel; + return lsum - rsum; + }); + + $.each(pick, function(idx, cardData){ cardData.iconPath = getIconPath(cardData.imgsvr, cardData.picture); var $card = $(TemplateEngine(templateGeneralCard, cardData)); diff --git a/hwe/select_npc.php b/hwe/select_npc.php index f6808847..6de57857 100644 --- a/hwe/select_npc.php +++ b/hwe/select_npc.php @@ -32,7 +32,7 @@ $nations = $db->queryAllLists('SELECT `name`, scoutmsg, color FROM nation'); - + From 70b1f23a491dfaec625dc1dc0b93aa090d0af7d5 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sat, 5 May 2018 23:25:21 +0900 Subject: [PATCH 022/101] =?UTF-8?q?=EB=B9=99=EC=9D=98=20=ED=95=B4=EC=A0=9C?= =?UTF-8?q?=EC=9A=A9=20=EC=82=AD=ED=84=B4=20=EC=84=B8=ED=8C=85.=20-=2010?= =?UTF-8?q?=EB=B6=84=20=EB=AF=B8=EB=A7=8C=EC=9D=80=2030=EB=B6=84=20-=2010?= =?UTF-8?q?=EB=B6=84=20=EC=9D=B4=ED=95=98=EB=8A=94=2060=EB=B6=84=20?= =?UTF-8?q?=EB=8C=80=EA=B8=B0=20=ED=95=84=EC=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/b_myPage.php | 53 +++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/hwe/b_myPage.php b/hwe/b_myPage.php index 4e83baca..449e5ede 100644 --- a/hwe/b_myPage.php +++ b/hwe/b_myPage.php @@ -7,6 +7,7 @@ include "func.php"; $btn = Util::getReq('btn'); $mode = Util::getReq('mode', 'int', 2); $tnmt = Util::getReq('tnmt', 'int', 1); +$detachNPC = Util::getReq('detachNPC', 'bool'); extractMissingPostToGlobals(); @@ -27,33 +28,48 @@ $connect=$db->get(); increaseRefresh("내정보", 1); -$query = "select myset from general where owner='{$userID}'"; +$query = "select no,npc,mode,tnmt,myset from general where owner='{$userID}'"; $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect), ""); $me = MYDB_fetch_array($result); + if ($me['myset'] > 0) { $submit = 'submit'; } else { $submit = 'hidden'; } -if ($btn == "설정저장" && $me['myset'] > 0) { +if (($btn == "설정저장" || $detachNPC) && $me['myset'] > 0) { if ($me['myset'] > 1) { $submit = 'submit'; } else { $submit = 'hidden'; } + $me['myset'] -= 1; + $db->update('general', [ 'myset'=>$db->sqleval('myset-1'), 'mode'=>$mode, 'tnmt'=>$tnmt ], 'owner=%i', $userID); -} -$query = "select no,mode,tnmt,myset from general where owner='{$userID}'"; -$result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect), ""); -$me = MYDB_fetch_array($result); + if($me['npc'] == 1 && $detachNPC){ + $turnterm = $db->queryFirstField('SELECT turnterm FROM game LIMIT 1'); + + if($turnterm < 10){ + $targetKillTurn = 30 / $turnterm; + } + else{ + $targetKillTurn = 60 / $turnterm; + } + $db->update('general', [ + 'killturn'=>$targetKillTurn + ], 'owner=%i AND npc=1', $userID); + + $me['killturn']=$targetKillTurn; + } +} ?> @@ -63,13 +79,6 @@ $me = MYDB_fetch_array($result); <?=UniqueConst::$serverName?>: 내정보 - @@ -83,23 +92,25 @@ function go(type) { - +
-     토너먼트 【 + 토너먼트 【 >수동참여 >자동참여 】
-     ∞개막직전 남는자리가 있을경우 랜덤하게 참여합니다.

-     수비 【 + ∞개막직전 남는자리가 있을경우 랜덤하게 참여합니다.

+ 수비 【 >◎(훈사80) >○(훈사60) >× 】

-      name=btn style=background-color:;color:white;width:160px;height:30px;font-size:13px; value=설정저장>
-     ∞설정저장은 이달중 회 남았습니다.

+ name=btn style=background-color:;color:white;width:160px;height:30px;font-size:13px; value=설정저장>
+ ∞설정저장은 이달중 회 남았습니다.

-     휴 가 신 청
-     ;color:white;width:160px;height:30px;font-size:13px; value=휴가신청 onclick='go(0)'> + 휴 가 신 청
+

+ 빙의 해제용 삭턴 조절
+ From 776e16b58b8ad43873770fe71758b5a3b79bcfdf Mon Sep 17 00:00:00 2001 From: hide_d Date: Mon, 7 May 2018 12:39:03 +0900 Subject: [PATCH 023/101] =?UTF-8?q?=EB=B9=99=EC=9D=98=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=20=EB=8C=80=EA=B8=B0=20=EC=8B=9C=EA=B0=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/j_get_select_npc_token.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hwe/j_get_select_npc_token.php b/hwe/j_get_select_npc_token.php index 613eff5d..93de3b31 100644 --- a/hwe/j_get_select_npc_token.php +++ b/hwe/j_get_select_npc_token.php @@ -119,7 +119,7 @@ while(count($pickResult) < $pickLimit){ $newNonce = mt_rand(0, 0xfffffff); $validSecond = max(VALID_SECOND, $turnterm*40); -$pickMoreSecond = max(PICK_MORE_SECOND, $turnterm*10); +$pickMoreSecond = max(PICK_MORE_SECOND, Util::round(pow($turnterm, 0.672)*8)); $validUntil = $oNow->add(new \DateInterval(sprintf('PT%dS', $validSecond))); $pickMoreFrom = $oNow->add(new \DateInterval(sprintf('PT%dS', $pickMoreSecond))); From 330853c98d8c2d6dddc03d117986ffa018654f4a Mon Sep 17 00:00:00 2001 From: hide_d Date: Mon, 7 May 2018 19:34:56 +0900 Subject: [PATCH 024/101] =?UTF-8?q?30=EB=B2=88=20=EC=8B=9C=EB=82=98?= =?UTF-8?q?=EB=A6=AC=EC=98=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/scenario/scenario_30.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hwe/scenario/scenario_30.json b/hwe/scenario/scenario_30.json index 1f433d76..c0f7056b 100644 --- a/hwe/scenario/scenario_30.json +++ b/hwe/scenario/scenario_30.json @@ -70,8 +70,8 @@ [0, "정보명", -1, 0, null, 69, 31, 39, 0, 160, 300, null, null], [0, "이재곤", -1, 0, null, 40, 41, 39, 0, 160, 300, null, null], [0, "염종석", -1, 0, null, 83, 90, 93, 0, 160, 300, null, null], - [0, "황재균", -1, 0, null, 79, 77, 83, 0, 160, 300, null, "집중", "안녕하세요 섹머입니다"], - [0, "윤학길", -1, 0, null, 81, 76, 82, 0, 160, 300, null, null], + [0, "황재균", -1, 0, null, 79, 77, 83, 0, 160, 300, null, null, "안녕하세요 섹머입니다"], + [0, "윤학길", -1, 0, null, 81, 76, 82, 0, 160, 300, null, "집중"], [0, "가득염", -1, 0, null, 60, 67, 61, 0, 160, 300, null, null], [0, "조경환", -1, 0, null, 57, 78, 20, 0, 160, 300, null, null], [0, "강상수", -1, 0, null, 65, 66, 58, 0, 160, 300, null, null], From a3f6a8e8abedbf34dc316f900ee1527ce726aed2 Mon Sep 17 00:00:00 2001 From: hide_d Date: Tue, 8 May 2018 00:38:29 +0900 Subject: [PATCH 025/101] =?UTF-8?q?symfony/lock=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 3 +- composer.lock | 171 ++++++++- vendor/composer/autoload_classmap.php | 7 + vendor/composer/autoload_files.php | 2 + vendor/composer/autoload_psr4.php | 2 + vendor/composer/autoload_static.php | 22 ++ vendor/composer/installed.json | 175 +++++++++ vendor/paragonie/random_compat/LICENSE | 22 ++ vendor/paragonie/random_compat/build-phar.sh | 5 + vendor/paragonie/random_compat/composer.json | 37 ++ .../dist/random_compat.phar.pubkey | 5 + .../dist/random_compat.phar.pubkey.asc | 11 + .../random_compat/lib/byte_safe_strings.php | 181 +++++++++ .../random_compat/lib/cast_to_int.php | 75 ++++ .../random_compat/lib/error_polyfill.php | 49 +++ vendor/paragonie/random_compat/lib/random.php | 225 +++++++++++ .../lib/random_bytes_com_dotnet.php | 88 +++++ .../lib/random_bytes_dev_urandom.php | 167 ++++++++ .../lib/random_bytes_libsodium.php | 88 +++++ .../lib/random_bytes_libsodium_legacy.php | 92 +++++ .../random_compat/lib/random_bytes_mcrypt.php | 77 ++++ .../random_compat/lib/random_int.php | 190 ++++++++++ .../random_compat/other/build_phar.php | 57 +++ .../random_compat/psalm-autoload.php | 9 + vendor/paragonie/random_compat/psalm.xml | 18 + vendor/symfony/lock/.gitignore | 3 + vendor/symfony/lock/CHANGELOG.md | 7 + .../lock/Exception/ExceptionInterface.php | 21 ++ .../Exception/InvalidArgumentException.php | 19 + .../lock/Exception/LockAcquiringException.php | 21 ++ .../Exception/LockConflictedException.php | 21 ++ .../lock/Exception/LockExpiredException.php | 21 ++ .../lock/Exception/LockReleasingException.php | 21 ++ .../lock/Exception/LockStorageException.php | 21 ++ .../lock/Exception/NotSupportedException.php | 21 ++ vendor/symfony/lock/Factory.php | 52 +++ vendor/symfony/lock/Key.php | 109 ++++++ vendor/symfony/lock/LICENSE | 19 + vendor/symfony/lock/Lock.php | 173 +++++++++ vendor/symfony/lock/LockInterface.php | 59 +++ vendor/symfony/lock/README.md | 11 + vendor/symfony/lock/Store/CombinedStore.php | 186 +++++++++ vendor/symfony/lock/Store/FlockStore.php | 141 +++++++ vendor/symfony/lock/Store/MemcachedStore.php | 187 +++++++++ vendor/symfony/lock/Store/RedisStore.php | 166 ++++++++ .../symfony/lock/Store/RetryTillSaveStore.php | 102 +++++ vendor/symfony/lock/Store/SemaphoreStore.php | 129 +++++++ vendor/symfony/lock/Store/StoreFactory.php | 40 ++ vendor/symfony/lock/StoreInterface.php | 64 ++++ .../lock/Strategy/ConsensusStrategy.php | 36 ++ .../lock/Strategy/StrategyInterface.php | 43 +++ .../lock/Strategy/UnanimousStrategy.php | 36 ++ vendor/symfony/lock/Tests/FactoryTest.php | 36 ++ vendor/symfony/lock/Tests/LockTest.php | 254 +++++++++++++ .../Tests/Store/AbstractRedisStoreTest.php | 45 +++ .../lock/Tests/Store/AbstractStoreTest.php | 115 ++++++ .../Tests/Store/BlockingStoreTestTrait.php | 97 +++++ .../lock/Tests/Store/CombinedStoreTest.php | 356 ++++++++++++++++++ .../Tests/Store/ExpiringStoreTestTrait.php | 107 ++++++ .../lock/Tests/Store/FlockStoreTest.php | 78 ++++ .../lock/Tests/Store/MemcachedStoreTest.php | 60 +++ .../lock/Tests/Store/PredisStoreTest.php | 36 ++ .../lock/Tests/Store/RedisArrayStoreTest.php | 38 ++ .../lock/Tests/Store/RedisStoreTest.php | 36 ++ .../Tests/Store/RetryTillSaveStoreTest.php | 35 ++ .../lock/Tests/Store/SemaphoreStoreTest.php | 36 ++ .../Tests/Strategy/ConsensusStrategyTest.php | 89 +++++ .../Tests/Strategy/UnanimousStrategyTest.php | 89 +++++ vendor/symfony/lock/composer.json | 38 ++ vendor/symfony/lock/phpunit.xml.dist | 32 ++ vendor/symfony/polyfill-php70/LICENSE | 19 + vendor/symfony/polyfill-php70/Php70.php | 74 ++++ vendor/symfony/polyfill-php70/README.md | 28 ++ .../Resources/stubs/ArithmeticError.php | 5 + .../Resources/stubs/AssertionError.php | 5 + .../Resources/stubs/DivisionByZeroError.php | 5 + .../polyfill-php70/Resources/stubs/Error.php | 5 + .../Resources/stubs/ParseError.php | 5 + ...SessionUpdateTimestampHandlerInterface.php | 23 ++ .../Resources/stubs/TypeError.php | 5 + vendor/symfony/polyfill-php70/bootstrap.php | 27 ++ vendor/symfony/polyfill-php70/composer.json | 33 ++ 82 files changed, 5316 insertions(+), 2 deletions(-) create mode 100644 vendor/paragonie/random_compat/LICENSE create mode 100644 vendor/paragonie/random_compat/build-phar.sh create mode 100644 vendor/paragonie/random_compat/composer.json create mode 100644 vendor/paragonie/random_compat/dist/random_compat.phar.pubkey create mode 100644 vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc create mode 100644 vendor/paragonie/random_compat/lib/byte_safe_strings.php create mode 100644 vendor/paragonie/random_compat/lib/cast_to_int.php create mode 100644 vendor/paragonie/random_compat/lib/error_polyfill.php create mode 100644 vendor/paragonie/random_compat/lib/random.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_libsodium.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php create mode 100644 vendor/paragonie/random_compat/lib/random_int.php create mode 100644 vendor/paragonie/random_compat/other/build_phar.php create mode 100644 vendor/paragonie/random_compat/psalm-autoload.php create mode 100644 vendor/paragonie/random_compat/psalm.xml create mode 100644 vendor/symfony/lock/.gitignore create mode 100644 vendor/symfony/lock/CHANGELOG.md create mode 100644 vendor/symfony/lock/Exception/ExceptionInterface.php create mode 100644 vendor/symfony/lock/Exception/InvalidArgumentException.php create mode 100644 vendor/symfony/lock/Exception/LockAcquiringException.php create mode 100644 vendor/symfony/lock/Exception/LockConflictedException.php create mode 100644 vendor/symfony/lock/Exception/LockExpiredException.php create mode 100644 vendor/symfony/lock/Exception/LockReleasingException.php create mode 100644 vendor/symfony/lock/Exception/LockStorageException.php create mode 100644 vendor/symfony/lock/Exception/NotSupportedException.php create mode 100644 vendor/symfony/lock/Factory.php create mode 100644 vendor/symfony/lock/Key.php create mode 100644 vendor/symfony/lock/LICENSE create mode 100644 vendor/symfony/lock/Lock.php create mode 100644 vendor/symfony/lock/LockInterface.php create mode 100644 vendor/symfony/lock/README.md create mode 100644 vendor/symfony/lock/Store/CombinedStore.php create mode 100644 vendor/symfony/lock/Store/FlockStore.php create mode 100644 vendor/symfony/lock/Store/MemcachedStore.php create mode 100644 vendor/symfony/lock/Store/RedisStore.php create mode 100644 vendor/symfony/lock/Store/RetryTillSaveStore.php create mode 100644 vendor/symfony/lock/Store/SemaphoreStore.php create mode 100644 vendor/symfony/lock/Store/StoreFactory.php create mode 100644 vendor/symfony/lock/StoreInterface.php create mode 100644 vendor/symfony/lock/Strategy/ConsensusStrategy.php create mode 100644 vendor/symfony/lock/Strategy/StrategyInterface.php create mode 100644 vendor/symfony/lock/Strategy/UnanimousStrategy.php create mode 100644 vendor/symfony/lock/Tests/FactoryTest.php create mode 100644 vendor/symfony/lock/Tests/LockTest.php create mode 100644 vendor/symfony/lock/Tests/Store/AbstractRedisStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/AbstractStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/BlockingStoreTestTrait.php create mode 100644 vendor/symfony/lock/Tests/Store/CombinedStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/ExpiringStoreTestTrait.php create mode 100644 vendor/symfony/lock/Tests/Store/FlockStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/MemcachedStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/PredisStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/RedisArrayStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/RedisStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/RetryTillSaveStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Store/SemaphoreStoreTest.php create mode 100644 vendor/symfony/lock/Tests/Strategy/ConsensusStrategyTest.php create mode 100644 vendor/symfony/lock/Tests/Strategy/UnanimousStrategyTest.php create mode 100644 vendor/symfony/lock/composer.json create mode 100644 vendor/symfony/lock/phpunit.xml.dist create mode 100644 vendor/symfony/polyfill-php70/LICENSE create mode 100644 vendor/symfony/polyfill-php70/Php70.php create mode 100644 vendor/symfony/polyfill-php70/README.md create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/AssertionError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/Error.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/ParseError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/TypeError.php create mode 100644 vendor/symfony/polyfill-php70/bootstrap.php create mode 100644 vendor/symfony/polyfill-php70/composer.json diff --git a/composer.json b/composer.json index c8b0e570..ea4ebc53 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,8 @@ "firephp/firephp-core": "^0.4.0", "vlucas/valitron": "^1.4", "php-extended/php-tail": "^2.1", - "pguardiario/phpuri": "^1.0" + "pguardiario/phpuri": "^1.0", + "symfony/lock": "^3.4" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 43411eaf..5ce4f436 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "1753c2c2ad9fe40ecc5c6ae541dd2e78", + "content-hash": "a329d39be5161c87438d41f9adf4417b", "packages": [ { "name": "brandonwamboldt/utilphp", @@ -454,6 +454,54 @@ ], "time": "2017-06-19T01:22:40+00:00" }, + { + "name": "paragonie/random_compat", + "version": "v2.0.12", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb", + "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "pseudorandom", + "random" + ], + "time": "2018-04-04T21:24:14+00:00" + }, { "name": "pguardiario/phpuri", "version": "1.0", @@ -702,6 +750,127 @@ ], "time": "2014-06-16T22:40:22+00:00" }, + { + "name": "symfony/lock", + "version": "v3.4.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/lock.git", + "reference": "3a707193326d31603824706e34a95af899a59788" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/lock/zipball/3a707193326d31603824706e34a95af899a59788", + "reference": "3a707193326d31603824706e34a95af899a59788", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "psr/log": "~1.0", + "symfony/polyfill-php70": "~1.0" + }, + "require-dev": { + "predis/predis": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Lock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + }, + { + "name": "Jérémy Derussé", + "email": "jeremy@derusse.com" + } + ], + "description": "Symfony Lock Component", + "homepage": "https://symfony.com", + "keywords": [ + "cas", + "flock", + "locking", + "mutex", + "redlock", + "semaphore" + ], + "time": "2018-04-29T14:44:26+00:00" + }, + { + "name": "symfony/polyfill-php70", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php70.git", + "reference": "77454693d8f10dd23bb24955cffd2d82db1007a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/77454693d8f10dd23bb24955cffd2d82db1007a6", + "reference": "77454693d8f10dd23bb24955cffd2d82db1007a6", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "~1.0|~2.0", + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php70\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2018-04-26T10:06:28+00:00" + }, { "name": "vlucas/valitron", "version": "v1.4.2", diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 0f375530..e8398d99 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -6,14 +6,21 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( + 'ArithmeticError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php', + 'AssertionError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php', 'DB' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'DBHelper' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'DBTransaction' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', + 'DivisionByZeroError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php', + 'Error' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/Error.php', 'FB' => $vendorDir . '/firephp/firephp-core/lib/FirePHPCore/fb.php', 'FirePHP' => $vendorDir . '/firephp/firephp-core/lib/FirePHPCore/FirePHP.class.php', 'MeekroDB' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'MeekroDBEval' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'MeekroDBException' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', + 'ParseError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ParseError.php', + 'SessionUpdateTimestampHandlerInterface' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php', + 'TypeError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/TypeError.php', 'WhereClause' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'kakao\\KakaoKey' => $baseDir . '/d_setting/KakaoKey.php', 'sammo\\RootDB' => $baseDir . '/d_setting/RootDB.php', diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index 325499f6..350100b3 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -6,8 +6,10 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( + '5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php', 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php', + '023d27dca8066ef29e6739335ea73bad' => $vendorDir . '/symfony/polyfill-php70/bootstrap.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', '5b154887902198b16314243c6e0e3e19' => $vendorDir . '/pguardiario/phpuri/phpuri.php', '870dc64919afa8b0f700701bb2c6a783' => $baseDir . '/f_config/config.php', diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index a422d325..c11d2d90 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -8,6 +8,8 @@ $baseDir = dirname($vendorDir); return array( 'sammo\\' => array($baseDir . '/src/sammo'), 'kakao\\' => array($baseDir . '/src/kakao'), + 'Symfony\\Polyfill\\Php70\\' => array($vendorDir . '/symfony/polyfill-php70'), + 'Symfony\\Component\\Lock\\' => array($vendorDir . '/symfony/lock'), 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'), 'PhpExtended\\Tail\\' => array($vendorDir . '/php-extended/php-tail/src'), diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 78b46bcf..0811ecbf 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -7,8 +7,10 @@ namespace Composer\Autoload; class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a { public static $files = array ( + '5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php', 'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php', + '023d27dca8066ef29e6739335ea73bad' => __DIR__ . '/..' . '/symfony/polyfill-php70/bootstrap.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', '5b154887902198b16314243c6e0e3e19' => __DIR__ . '/..' . '/pguardiario/phpuri/phpuri.php', '870dc64919afa8b0f700701bb2c6a783' => __DIR__ . '/../..' . '/f_config/config.php', @@ -23,6 +25,11 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a array ( 'kakao\\' => 6, ), + 'S' => + array ( + 'Symfony\\Polyfill\\Php70\\' => 23, + 'Symfony\\Component\\Lock\\' => 23, + ), 'P' => array ( 'Psr\\Log\\' => 8, @@ -56,6 +63,14 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a array ( 0 => __DIR__ . '/../..' . '/src/kakao', ), + 'Symfony\\Polyfill\\Php70\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php70', + ), + 'Symfony\\Component\\Lock\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/lock', + ), 'Psr\\Log\\' => array ( 0 => __DIR__ . '/..' . '/psr/log/Psr/Log', @@ -116,14 +131,21 @@ class ComposerStaticInit67b09c83b85c3bc0027caefe5bba171a ); public static $classMap = array ( + 'ArithmeticError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php', + 'AssertionError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php', 'DB' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'DBHelper' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'DBTransaction' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', + 'DivisionByZeroError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php', + 'Error' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/Error.php', 'FB' => __DIR__ . '/..' . '/firephp/firephp-core/lib/FirePHPCore/fb.php', 'FirePHP' => __DIR__ . '/..' . '/firephp/firephp-core/lib/FirePHPCore/FirePHP.class.php', 'MeekroDB' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'MeekroDBEval' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'MeekroDBException' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', + 'ParseError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ParseError.php', + 'SessionUpdateTimestampHandlerInterface' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php', + 'TypeError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/TypeError.php', 'WhereClause' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'kakao\\KakaoKey' => __DIR__ . '/../..' . '/d_setting/KakaoKey.php', 'sammo\\RootDB' => __DIR__ . '/../..' . '/d_setting/RootDB.php', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index c2931551..5c44110b 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -463,6 +463,56 @@ "psr-3" ] }, + { + "name": "paragonie/random_compat", + "version": "v2.0.12", + "version_normalized": "2.0.12.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb", + "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "time": "2018-04-04T21:24:14+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "pseudorandom", + "random" + ] + }, { "name": "pguardiario/phpuri", "version": "1.0", @@ -723,6 +773,131 @@ "pdo" ] }, + { + "name": "symfony/lock", + "version": "v3.4.9", + "version_normalized": "3.4.9.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/lock.git", + "reference": "3a707193326d31603824706e34a95af899a59788" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/lock/zipball/3a707193326d31603824706e34a95af899a59788", + "reference": "3a707193326d31603824706e34a95af899a59788", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "psr/log": "~1.0", + "symfony/polyfill-php70": "~1.0" + }, + "require-dev": { + "predis/predis": "~1.0" + }, + "time": "2018-04-29T14:44:26+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Lock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + }, + { + "name": "Jérémy Derussé", + "email": "jeremy@derusse.com" + } + ], + "description": "Symfony Lock Component", + "homepage": "https://symfony.com", + "keywords": [ + "cas", + "flock", + "locking", + "mutex", + "redlock", + "semaphore" + ] + }, + { + "name": "symfony/polyfill-php70", + "version": "v1.8.0", + "version_normalized": "1.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php70.git", + "reference": "77454693d8f10dd23bb24955cffd2d82db1007a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/77454693d8f10dd23bb24955cffd2d82db1007a6", + "reference": "77454693d8f10dd23bb24955cffd2d82db1007a6", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "~1.0|~2.0", + "php": ">=5.3.3" + }, + "time": "2018-04-26T10:06:28+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php70\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ] + }, { "name": "vlucas/valitron", "version": "v1.4.2", diff --git a/vendor/paragonie/random_compat/LICENSE b/vendor/paragonie/random_compat/LICENSE new file mode 100644 index 00000000..45c7017d --- /dev/null +++ b/vendor/paragonie/random_compat/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Paragon Initiative Enterprises + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/paragonie/random_compat/build-phar.sh b/vendor/paragonie/random_compat/build-phar.sh new file mode 100644 index 00000000..b4a5ba31 --- /dev/null +++ b/vendor/paragonie/random_compat/build-phar.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +basedir=$( dirname $( readlink -f ${BASH_SOURCE[0]} ) ) + +php -dphar.readonly=0 "$basedir/other/build_phar.php" $* \ No newline at end of file diff --git a/vendor/paragonie/random_compat/composer.json b/vendor/paragonie/random_compat/composer.json new file mode 100644 index 00000000..1c5978c6 --- /dev/null +++ b/vendor/paragonie/random_compat/composer.json @@ -0,0 +1,37 @@ +{ + "name": "paragonie/random_compat", + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "random", + "pseudorandom" + ], + "license": "MIT", + "type": "library", + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "support": { + "issues": "https://github.com/paragonie/random_compat/issues", + "email": "info@paragonie.com", + "source": "https://github.com/paragonie/random_compat" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "autoload": { + "files": [ + "lib/random.php" + ] + } +} diff --git a/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey new file mode 100644 index 00000000..eb50ebfc --- /dev/null +++ b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey @@ -0,0 +1,5 @@ +-----BEGIN PUBLIC KEY----- +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm +pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p ++h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc +-----END PUBLIC KEY----- diff --git a/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc new file mode 100644 index 00000000..6a1d7f30 --- /dev/null +++ b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2.0.22 (MingW32) + +iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip +QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg +1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW +NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA +NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV +JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74= +=B6+8 +-----END PGP SIGNATURE----- diff --git a/vendor/paragonie/random_compat/lib/byte_safe_strings.php b/vendor/paragonie/random_compat/lib/byte_safe_strings.php new file mode 100644 index 00000000..3de86b22 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/byte_safe_strings.php @@ -0,0 +1,181 @@ + RandomCompat_strlen($binary_string)) { + return ''; + } + + return (string) mb_substr($binary_string, $start, $length, '8bit'); + } + + } else { + + /** + * substr() implementation that isn't brittle to mbstring.func_overload + * + * This version just uses the default substr() + * + * @param string $binary_string + * @param int $start + * @param int $length (optional) + * + * @throws TypeError + * + * @return string + */ + function RandomCompat_substr($binary_string, $start, $length = null) + { + if (!is_string($binary_string)) { + throw new TypeError( + 'RandomCompat_substr(): First argument should be a string' + ); + } + + if (!is_int($start)) { + throw new TypeError( + 'RandomCompat_substr(): Second argument should be an integer' + ); + } + + if ($length !== null) { + if (!is_int($length)) { + throw new TypeError( + 'RandomCompat_substr(): Third argument should be an integer, or omitted' + ); + } + + return (string) substr($binary_string, $start, $length); + } + + return (string) substr($binary_string, $start); + } + } +} diff --git a/vendor/paragonie/random_compat/lib/cast_to_int.php b/vendor/paragonie/random_compat/lib/cast_to_int.php new file mode 100644 index 00000000..9a4fab99 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/cast_to_int.php @@ -0,0 +1,75 @@ + operators might accidentally let a float + * through. + * + * @param int|float $number The number we want to convert to an int + * @param bool $fail_open Set to true to not throw an exception + * + * @return float|int + * @psalm-suppress InvalidReturnType + * + * @throws TypeError + */ + function RandomCompat_intval($number, $fail_open = false) + { + if (is_int($number) || is_float($number)) { + $number += 0; + } elseif (is_numeric($number)) { + $number += 0; + } + + if ( + is_float($number) + && + $number > ~PHP_INT_MAX + && + $number < PHP_INT_MAX + ) { + $number = (int) $number; + } + + if (is_int($number)) { + return (int) $number; + } elseif (!$fail_open) { + throw new TypeError( + 'Expected an integer.' + ); + } + return $number; + } +} diff --git a/vendor/paragonie/random_compat/lib/error_polyfill.php b/vendor/paragonie/random_compat/lib/error_polyfill.php new file mode 100644 index 00000000..6a91990c --- /dev/null +++ b/vendor/paragonie/random_compat/lib/error_polyfill.php @@ -0,0 +1,49 @@ += 70000) { + return; +} + +if (!defined('RANDOM_COMPAT_READ_BUFFER')) { + define('RANDOM_COMPAT_READ_BUFFER', 8); +} + +$RandomCompatDIR = dirname(__FILE__); + +require_once $RandomCompatDIR . '/byte_safe_strings.php'; +require_once $RandomCompatDIR . '/cast_to_int.php'; +require_once $RandomCompatDIR . '/error_polyfill.php'; + +if (!is_callable('random_bytes')) { + /** + * PHP 5.2.0 - 5.6.x way to implement random_bytes() + * + * We use conditional statements here to define the function in accordance + * to the operating environment. It's a micro-optimization. + * + * In order of preference: + * 1. Use libsodium if available. + * 2. fread() /dev/urandom if available (never on Windows) + * 3. mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM) + * 4. COM('CAPICOM.Utilities.1')->GetRandom() + * + * See RATIONALE.md for our reasoning behind this particular order + */ + if (extension_loaded('libsodium')) { + // See random_bytes_libsodium.php + if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) { + require_once $RandomCompatDIR . '/random_bytes_libsodium.php'; + } elseif (method_exists('Sodium', 'randombytes_buf')) { + require_once $RandomCompatDIR . '/random_bytes_libsodium_legacy.php'; + } + } + + /** + * Reading directly from /dev/urandom: + */ + if (DIRECTORY_SEPARATOR === '/') { + // DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast + // way to exclude Windows. + $RandomCompatUrandom = true; + $RandomCompat_basedir = ini_get('open_basedir'); + + if (!empty($RandomCompat_basedir)) { + $RandomCompat_open_basedir = explode( + PATH_SEPARATOR, + strtolower($RandomCompat_basedir) + ); + $RandomCompatUrandom = (array() !== array_intersect( + array('/dev', '/dev/', '/dev/urandom'), + $RandomCompat_open_basedir + )); + $RandomCompat_open_basedir = null; + } + + if ( + !is_callable('random_bytes') + && + $RandomCompatUrandom + && + @is_readable('/dev/urandom') + ) { + // Error suppression on is_readable() in case of an open_basedir + // or safe_mode failure. All we care about is whether or not we + // can read it at this point. If the PHP environment is going to + // panic over trying to see if the file can be read in the first + // place, that is not helpful to us here. + + // See random_bytes_dev_urandom.php + require_once $RandomCompatDIR . '/random_bytes_dev_urandom.php'; + } + // Unset variables after use + $RandomCompat_basedir = null; + } else { + $RandomCompatUrandom = false; + } + + /** + * mcrypt_create_iv() + * + * We only want to use mcypt_create_iv() if: + * + * - random_bytes() hasn't already been defined + * - the mcrypt extensions is loaded + * - One of these two conditions is true: + * - We're on Windows (DIRECTORY_SEPARATOR !== '/') + * - We're not on Windows and /dev/urandom is readabale + * (i.e. we're not in a chroot jail) + * - Special case: + * - If we're not on Windows, but the PHP version is between + * 5.6.10 and 5.6.12, we don't want to use mcrypt. It will + * hang indefinitely. This is bad. + * - If we're on Windows, we want to use PHP >= 5.3.7 or else + * we get insufficient entropy errors. + */ + if ( + !is_callable('random_bytes') + && + // Windows on PHP < 5.3.7 is broken, but non-Windows is not known to be. + (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307) + && + // Prevent this code from hanging indefinitely on non-Windows; + // see https://bugs.php.net/bug.php?id=69833 + ( + DIRECTORY_SEPARATOR !== '/' || + (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613) + ) + && + extension_loaded('mcrypt') + ) { + // See random_bytes_mcrypt.php + require_once $RandomCompatDIR . '/random_bytes_mcrypt.php'; + } + $RandomCompatUrandom = null; + + /** + * This is a Windows-specific fallback, for when the mcrypt extension + * isn't loaded. + */ + if ( + !is_callable('random_bytes') + && + extension_loaded('com_dotnet') + && + class_exists('COM') + ) { + $RandomCompat_disabled_classes = preg_split( + '#\s*,\s*#', + strtolower(ini_get('disable_classes')) + ); + + if (!in_array('com', $RandomCompat_disabled_classes)) { + try { + $RandomCompatCOMtest = new COM('CAPICOM.Utilities.1'); + if (method_exists($RandomCompatCOMtest, 'GetRandom')) { + // See random_bytes_com_dotnet.php + require_once $RandomCompatDIR . '/random_bytes_com_dotnet.php'; + } + } catch (com_exception $e) { + // Don't try to use it. + } + } + $RandomCompat_disabled_classes = null; + $RandomCompatCOMtest = null; + } + + /** + * throw new Exception + */ + if (!is_callable('random_bytes')) { + /** + * We don't have any more options, so let's throw an exception right now + * and hope the developer won't let it fail silently. + * + * @param mixed $length + * @psalm-suppress MissingReturnType + * @throws Exception + * @return string + */ + function random_bytes($length) + { + unset($length); // Suppress "variable not used" warnings. + throw new Exception( + 'There is no suitable CSPRNG installed on your system' + ); + return ''; + } + } +} + +if (!is_callable('random_int')) { + require_once $RandomCompatDIR . '/random_int.php'; +} + +$RandomCompatDIR = null; diff --git a/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php b/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php new file mode 100644 index 00000000..fc1926e5 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php @@ -0,0 +1,88 @@ +GetRandom($bytes, 0)); + if (RandomCompat_strlen($buf) >= $bytes) { + /** + * Return our random entropy buffer here: + */ + return RandomCompat_substr($buf, 0, $bytes); + } + ++$execCount; + } while ($execCount < $bytes); + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} \ No newline at end of file diff --git a/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php b/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php new file mode 100644 index 00000000..df5b9152 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php @@ -0,0 +1,167 @@ + 0); + + /** + * Is our result valid? + */ + if (is_string($buf)) { + if (RandomCompat_strlen($buf) === $bytes) { + /** + * Return our random entropy buffer here: + */ + return $buf; + } + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Error reading from source device' + ); + } +} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php new file mode 100644 index 00000000..4af1a242 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php @@ -0,0 +1,88 @@ + 2147483647) { + $buf = ''; + for ($i = 0; $i < $bytes; $i += 1073741824) { + $n = ($bytes - $i) > 1073741824 + ? 1073741824 + : $bytes - $i; + $buf .= \Sodium\randombytes_buf($n); + } + } else { + $buf = \Sodium\randombytes_buf($bytes); + } + + if ($buf !== false) { + if (RandomCompat_strlen($buf) === $bytes) { + return $buf; + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php new file mode 100644 index 00000000..705af526 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php @@ -0,0 +1,92 @@ + 2147483647) { + for ($i = 0; $i < $bytes; $i += 1073741824) { + $n = ($bytes - $i) > 1073741824 + ? 1073741824 + : $bytes - $i; + $buf .= Sodium::randombytes_buf((int) $n); + } + } else { + $buf .= Sodium::randombytes_buf((int) $bytes); + } + + if (is_string($buf)) { + if (RandomCompat_strlen($buf) === $bytes) { + return $buf; + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php b/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php new file mode 100644 index 00000000..aac9c013 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php @@ -0,0 +1,77 @@ + operators might accidentally let a float + * through. + */ + + try { + $min = RandomCompat_intval($min); + } catch (TypeError $ex) { + throw new TypeError( + 'random_int(): $min must be an integer' + ); + } + + try { + $max = RandomCompat_intval($max); + } catch (TypeError $ex) { + throw new TypeError( + 'random_int(): $max must be an integer' + ); + } + + /** + * Now that we've verified our weak typing system has given us an integer, + * let's validate the logic then we can move forward with generating random + * integers along a given range. + */ + if ($min > $max) { + throw new Error( + 'Minimum value must be less than or equal to the maximum value' + ); + } + + if ($max === $min) { + return (int) $min; + } + + /** + * Initialize variables to 0 + * + * We want to store: + * $bytes => the number of random bytes we need + * $mask => an integer bitmask (for use with the &) operator + * so we can minimize the number of discards + */ + $attempts = $bits = $bytes = $mask = $valueShift = 0; + + /** + * At this point, $range is a positive number greater than 0. It might + * overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to + * a float and we will lose some precision. + */ + $range = $max - $min; + + /** + * Test for integer overflow: + */ + if (!is_int($range)) { + + /** + * Still safely calculate wider ranges. + * Provided by @CodesInChaos, @oittaa + * + * @ref https://gist.github.com/CodesInChaos/03f9ea0b58e8b2b8d435 + * + * We use ~0 as a mask in this case because it generates all 1s + * + * @ref https://eval.in/400356 (32-bit) + * @ref http://3v4l.org/XX9r5 (64-bit) + */ + $bytes = PHP_INT_SIZE; + $mask = ~0; + + } else { + + /** + * $bits is effectively ceil(log($range, 2)) without dealing with + * type juggling + */ + while ($range > 0) { + if ($bits % 8 === 0) { + ++$bytes; + } + ++$bits; + $range >>= 1; + $mask = $mask << 1 | 1; + } + $valueShift = $min; + } + + $val = 0; + /** + * Now that we have our parameters set up, let's begin generating + * random integers until one falls between $min and $max + */ + do { + /** + * The rejection probability is at most 0.5, so this corresponds + * to a failure probability of 2^-128 for a working RNG + */ + if ($attempts > 128) { + throw new Exception( + 'random_int: RNG is broken - too many rejections' + ); + } + + /** + * Let's grab the necessary number of random bytes + */ + $randomByteString = random_bytes($bytes); + + /** + * Let's turn $randomByteString into an integer + * + * This uses bitwise operators (<< and |) to build an integer + * out of the values extracted from ord() + * + * Example: [9F] | [6D] | [32] | [0C] => + * 159 + 27904 + 3276800 + 201326592 => + * 204631455 + */ + $val &= 0; + for ($i = 0; $i < $bytes; ++$i) { + $val |= ord($randomByteString[$i]) << ($i * 8); + } + + /** + * Apply mask + */ + $val &= $mask; + $val += $valueShift; + + ++$attempts; + /** + * If $val overflows to a floating point number, + * ... or is larger than $max, + * ... or smaller than $min, + * then try again. + */ + } while (!is_int($val) || $val > $max || $val < $min); + + return (int) $val; + } +} diff --git a/vendor/paragonie/random_compat/other/build_phar.php b/vendor/paragonie/random_compat/other/build_phar.php new file mode 100644 index 00000000..70ef4b2e --- /dev/null +++ b/vendor/paragonie/random_compat/other/build_phar.php @@ -0,0 +1,57 @@ +buildFromDirectory(dirname(__DIR__).'/lib'); +rename( + dirname(__DIR__).'/lib/index.php', + dirname(__DIR__).'/lib/random.php' +); + +/** + * If we pass an (optional) path to a private key as a second argument, we will + * sign the Phar with OpenSSL. + * + * If you leave this out, it will produce an unsigned .phar! + */ +if ($argc > 1) { + if (!@is_readable($argv[1])) { + echo 'Could not read the private key file:', $argv[1], "\n"; + exit(255); + } + $pkeyFile = file_get_contents($argv[1]); + + $private = openssl_get_privatekey($pkeyFile); + if ($private !== false) { + $pkey = ''; + openssl_pkey_export($private, $pkey); + $phar->setSignatureAlgorithm(Phar::OPENSSL, $pkey); + + /** + * Save the corresponding public key to the file + */ + if (!@is_readable($dist.'/random_compat.phar.pubkey')) { + $details = openssl_pkey_get_details($private); + file_put_contents( + $dist.'/random_compat.phar.pubkey', + $details['key'] + ); + } + } else { + echo 'An error occurred reading the private key from OpenSSL.', "\n"; + exit(255); + } +} diff --git a/vendor/paragonie/random_compat/psalm-autoload.php b/vendor/paragonie/random_compat/psalm-autoload.php new file mode 100644 index 00000000..d71d1b81 --- /dev/null +++ b/vendor/paragonie/random_compat/psalm-autoload.php @@ -0,0 +1,9 @@ + + + + + + + + + + + + + + diff --git a/vendor/symfony/lock/.gitignore b/vendor/symfony/lock/.gitignore new file mode 100644 index 00000000..5414c2c6 --- /dev/null +++ b/vendor/symfony/lock/.gitignore @@ -0,0 +1,3 @@ +composer.lock +phpunit.xml +vendor/ diff --git a/vendor/symfony/lock/CHANGELOG.md b/vendor/symfony/lock/CHANGELOG.md new file mode 100644 index 00000000..8e992b98 --- /dev/null +++ b/vendor/symfony/lock/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +3.4.0 +----- + + * added the component diff --git a/vendor/symfony/lock/Exception/ExceptionInterface.php b/vendor/symfony/lock/Exception/ExceptionInterface.php new file mode 100644 index 00000000..0d419584 --- /dev/null +++ b/vendor/symfony/lock/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * Base ExceptionInterface for the Lock Component. + * + * @author Jérémy Derussé + */ +interface ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Exception/InvalidArgumentException.php b/vendor/symfony/lock/Exception/InvalidArgumentException.php new file mode 100644 index 00000000..f2f74b37 --- /dev/null +++ b/vendor/symfony/lock/Exception/InvalidArgumentException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * @author Jérémy Derussé + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Exception/LockAcquiringException.php b/vendor/symfony/lock/Exception/LockAcquiringException.php new file mode 100644 index 00000000..e6756aec --- /dev/null +++ b/vendor/symfony/lock/Exception/LockAcquiringException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * LockAcquiringException is thrown when an issue happens during the acquisition of a lock. + * + * @author Jérémy Derussé + */ +class LockAcquiringException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Exception/LockConflictedException.php b/vendor/symfony/lock/Exception/LockConflictedException.php new file mode 100644 index 00000000..8fcd6a83 --- /dev/null +++ b/vendor/symfony/lock/Exception/LockConflictedException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * LockConflictedException is thrown when a lock is acquired by someone else. + * + * @author Jérémy Derussé + */ +class LockConflictedException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Exception/LockExpiredException.php b/vendor/symfony/lock/Exception/LockExpiredException.php new file mode 100644 index 00000000..9b712ae0 --- /dev/null +++ b/vendor/symfony/lock/Exception/LockExpiredException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * LockExpiredException is thrown when a lock may conflict due to a TTL expiration. + * + * @author Jérémy Derussé + */ +class LockExpiredException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Exception/LockReleasingException.php b/vendor/symfony/lock/Exception/LockReleasingException.php new file mode 100644 index 00000000..56eedde7 --- /dev/null +++ b/vendor/symfony/lock/Exception/LockReleasingException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * LockReleasingException is thrown when an issue happens during the release of a lock. + * + * @author Jérémy Derussé + */ +class LockReleasingException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Exception/LockStorageException.php b/vendor/symfony/lock/Exception/LockStorageException.php new file mode 100644 index 00000000..8c393fc1 --- /dev/null +++ b/vendor/symfony/lock/Exception/LockStorageException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * LockStorageException is thrown when an issue happens during the manipulation of a lock in a store. + * + * @author Jérémy Derussé + */ +class LockStorageException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Exception/NotSupportedException.php b/vendor/symfony/lock/Exception/NotSupportedException.php new file mode 100644 index 00000000..c9a7f013 --- /dev/null +++ b/vendor/symfony/lock/Exception/NotSupportedException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Exception; + +/** + * NotSupportedException is thrown when an unsupported method is called. + * + * @author Jérémy Derussé + */ +class NotSupportedException extends \LogicException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/lock/Factory.php b/vendor/symfony/lock/Factory.php new file mode 100644 index 00000000..e9fdde97 --- /dev/null +++ b/vendor/symfony/lock/Factory.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Psr\Log\NullLogger; + +/** + * Factory provides method to create locks. + * + * @author Jérémy Derussé + */ +class Factory implements LoggerAwareInterface +{ + use LoggerAwareTrait; + + private $store; + + public function __construct(StoreInterface $store) + { + $this->store = $store; + + $this->logger = new NullLogger(); + } + + /** + * Creates a lock for the given resource. + * + * @param string $resource The resource to lock + * @param float $ttl Maximum expected lock duration in seconds + * @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed + * + * @return Lock + */ + public function createLock($resource, $ttl = 300.0, $autoRelease = true) + { + $lock = new Lock(new Key($resource), $this->store, $ttl, $autoRelease); + $lock->setLogger($this->logger); + + return $lock; + } +} diff --git a/vendor/symfony/lock/Key.php b/vendor/symfony/lock/Key.php new file mode 100644 index 00000000..8be4f3a2 --- /dev/null +++ b/vendor/symfony/lock/Key.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock; + +/** + * Key is a container for the state of the locks in stores. + * + * @author Jérémy Derussé + */ +final class Key +{ + private $resource; + private $expiringTime; + private $state = array(); + + /** + * @param string $resource + */ + public function __construct($resource) + { + $this->resource = (string) $resource; + } + + public function __toString() + { + return $this->resource; + } + + /** + * @param string $stateKey + * + * @return bool + */ + public function hasState($stateKey) + { + return isset($this->state[$stateKey]); + } + + /** + * @param string $stateKey + * @param mixed $state + */ + public function setState($stateKey, $state) + { + $this->state[$stateKey] = $state; + } + + /** + * @param string $stateKey + */ + public function removeState($stateKey) + { + unset($this->state[$stateKey]); + } + + /** + * @param $stateKey + * + * @return mixed + */ + public function getState($stateKey) + { + return $this->state[$stateKey]; + } + + public function resetLifetime() + { + $this->expiringTime = null; + } + + /** + * @param float $ttl the expiration delay of locks in seconds + */ + public function reduceLifetime($ttl) + { + $newTime = microtime(true) + $ttl; + + if (null === $this->expiringTime || $this->expiringTime > $newTime) { + $this->expiringTime = $newTime; + } + } + + /** + * Returns the remaining lifetime. + * + * @return float|null Remaining lifetime in seconds. Null when the key won't expire. + */ + public function getRemainingLifetime() + { + return null === $this->expiringTime ? null : $this->expiringTime - microtime(true); + } + + /** + * @return bool + */ + public function isExpired() + { + return null !== $this->expiringTime && $this->expiringTime <= microtime(true); + } +} diff --git a/vendor/symfony/lock/LICENSE b/vendor/symfony/lock/LICENSE new file mode 100644 index 00000000..fcd3fa76 --- /dev/null +++ b/vendor/symfony/lock/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2016-2018 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/lock/Lock.php b/vendor/symfony/lock/Lock.php new file mode 100644 index 00000000..77fd032b --- /dev/null +++ b/vendor/symfony/lock/Lock.php @@ -0,0 +1,173 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Psr\Log\NullLogger; +use Symfony\Component\Lock\Exception\InvalidArgumentException; +use Symfony\Component\Lock\Exception\LockAcquiringException; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\LockExpiredException; +use Symfony\Component\Lock\Exception\LockReleasingException; + +/** + * Lock is the default implementation of the LockInterface. + * + * @author Jérémy Derussé + */ +final class Lock implements LockInterface, LoggerAwareInterface +{ + use LoggerAwareTrait; + + private $store; + private $key; + private $ttl; + private $autoRelease; + private $dirty = false; + + /** + * @param Key $key Resource to lock + * @param StoreInterface $store Store used to handle lock persistence + * @param float|null $ttl Maximum expected lock duration in seconds + * @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed + */ + public function __construct(Key $key, StoreInterface $store, $ttl = null, $autoRelease = true) + { + $this->store = $store; + $this->key = $key; + $this->ttl = $ttl; + $this->autoRelease = (bool) $autoRelease; + + $this->logger = new NullLogger(); + } + + /** + * Automatically releases the underlying lock when the object is destructed. + */ + public function __destruct() + { + if (!$this->autoRelease || !$this->dirty || !$this->isAcquired()) { + return; + } + + $this->release(); + } + + /** + * {@inheritdoc} + */ + public function acquire($blocking = false) + { + try { + if (!$blocking) { + $this->store->save($this->key); + } else { + $this->store->waitAndSave($this->key); + } + + $this->dirty = true; + $this->logger->info('Successfully acquired the "{resource}" lock.', array('resource' => $this->key)); + + if ($this->ttl) { + $this->refresh(); + } + + if ($this->key->isExpired()) { + throw new LockExpiredException(sprintf('Failed to store the "%s" lock.', $this->key)); + } + + return true; + } catch (LockConflictedException $e) { + $this->dirty = false; + $this->logger->notice('Failed to acquire the "{resource}" lock. Someone else already acquired the lock.', array('resource' => $this->key)); + + if ($blocking) { + throw $e; + } + + return false; + } catch (\Exception $e) { + $this->logger->notice('Failed to acquire the "{resource}" lock.', array('resource' => $this->key, 'exception' => $e)); + throw new LockAcquiringException(sprintf('Failed to acquire the "%s" lock.', $this->key), 0, $e); + } + } + + /** + * {@inheritdoc} + */ + public function refresh() + { + if (!$this->ttl) { + throw new InvalidArgumentException('You have to define an expiration duration.'); + } + + try { + $this->key->resetLifetime(); + $this->store->putOffExpiration($this->key, $this->ttl); + $this->dirty = true; + + if ($this->key->isExpired()) { + throw new LockExpiredException(sprintf('Failed to put off the expiration of the "%s" lock within the specified time.', $this->key)); + } + + $this->logger->info('Expiration defined for "{resource}" lock for "{ttl}" seconds.', array('resource' => $this->key, 'ttl' => $this->ttl)); + } catch (LockConflictedException $e) { + $this->dirty = false; + $this->logger->notice('Failed to define an expiration for the "{resource}" lock, someone else acquired the lock.', array('resource' => $this->key)); + throw $e; + } catch (\Exception $e) { + $this->logger->notice('Failed to define an expiration for the "{resource}" lock.', array('resource' => $this->key, 'exception' => $e)); + throw new LockAcquiringException(sprintf('Failed to define an expiration for the "%s" lock.', $this->key), 0, $e); + } + } + + /** + * {@inheritdoc} + */ + public function isAcquired() + { + return $this->dirty = $this->store->exists($this->key); + } + + /** + * {@inheritdoc} + */ + public function release() + { + $this->store->delete($this->key); + $this->dirty = false; + + if ($this->store->exists($this->key)) { + $this->logger->notice('Failed to release the "{resource}" lock.', array('resource' => $this->key)); + throw new LockReleasingException(sprintf('Failed to release the "%s" lock.', $this->key)); + } + } + + /** + * @return bool + */ + public function isExpired() + { + return $this->key->isExpired(); + } + + /** + * Returns the remaining lifetime. + * + * @return float|null Remaining lifetime in seconds. Null when the lock won't expire. + */ + public function getRemainingLifetime() + { + return $this->key->getRemainingLifetime(); + } +} diff --git a/vendor/symfony/lock/LockInterface.php b/vendor/symfony/lock/LockInterface.php new file mode 100644 index 00000000..437a4cc2 --- /dev/null +++ b/vendor/symfony/lock/LockInterface.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock; + +use Symfony\Component\Lock\Exception\LockAcquiringException; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\LockReleasingException; + +/** + * LockInterface defines an interface to manipulate the status of a lock. + * + * @author Jérémy Derussé + */ +interface LockInterface +{ + /** + * Acquires the lock. If the lock is acquired by someone else, the parameter `blocking` determines whether or not + * the the call should block until the release of the lock. + * + * @param bool $blocking Whether or not the Lock should wait for the release of someone else + * + * @return bool whether or not the lock had been acquired + * + * @throws LockConflictedException If the lock is acquired by someone else in blocking mode + * @throws LockAcquiringException If the lock can not be acquired + */ + public function acquire($blocking = false); + + /** + * Increase the duration of an acquired lock. + * + * @throws LockConflictedException If the lock is acquired by someone else + * @throws LockAcquiringException If the lock can not be refreshed + */ + public function refresh(); + + /** + * Returns whether or not the lock is acquired. + * + * @return bool + */ + public function isAcquired(); + + /** + * Release the lock. + * + * @throws LockReleasingException If the lock can not be released + */ + public function release(); +} diff --git a/vendor/symfony/lock/README.md b/vendor/symfony/lock/README.md new file mode 100644 index 00000000..0be0bfd4 --- /dev/null +++ b/vendor/symfony/lock/README.md @@ -0,0 +1,11 @@ +Lock Component +============== + +Resources +--------- + + * [Documentation](https://symfony.com/doc/master/components/lock.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/lock/Store/CombinedStore.php b/vendor/symfony/lock/Store/CombinedStore.php new file mode 100644 index 00000000..50258fe6 --- /dev/null +++ b/vendor/symfony/lock/Store/CombinedStore.php @@ -0,0 +1,186 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Store; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Psr\Log\NullLogger; +use Symfony\Component\Lock\Exception\InvalidArgumentException; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\LockExpiredException; +use Symfony\Component\Lock\Exception\NotSupportedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\Strategy\StrategyInterface; +use Symfony\Component\Lock\StoreInterface; + +/** + * CombinedStore is a StoreInterface implementation able to manage and synchronize several StoreInterfaces. + * + * @author Jérémy Derussé + */ +class CombinedStore implements StoreInterface, LoggerAwareInterface +{ + use LoggerAwareTrait; + + /** @var StoreInterface[] */ + private $stores; + /** @var StrategyInterface */ + private $strategy; + + /** + * @param StoreInterface[] $stores The list of synchronized stores + * @param StrategyInterface $strategy + * + * @throws InvalidArgumentException + */ + public function __construct(array $stores, StrategyInterface $strategy) + { + foreach ($stores as $store) { + if (!$store instanceof StoreInterface) { + throw new InvalidArgumentException(sprintf('The store must implement "%s". Got "%s".', StoreInterface::class, get_class($store))); + } + } + + $this->stores = $stores; + $this->strategy = $strategy; + $this->logger = new NullLogger(); + } + + /** + * {@inheritdoc} + */ + public function save(Key $key) + { + $successCount = 0; + $failureCount = 0; + $storesCount = count($this->stores); + + foreach ($this->stores as $store) { + try { + $store->save($key); + ++$successCount; + } catch (\Exception $e) { + $this->logger->warning('One store failed to save the "{resource}" lock.', array('resource' => $key, 'store' => $store, 'exception' => $e)); + ++$failureCount; + } + + if (!$this->strategy->canBeMet($failureCount, $storesCount)) { + break; + } + } + + if ($this->strategy->isMet($successCount, $storesCount)) { + return; + } + + $this->logger->warning('Failed to store the "{resource}" lock. Quorum has not been met.', array('resource' => $key, 'success' => $successCount, 'failure' => $failureCount)); + + // clean up potential locks + $this->delete($key); + + throw new LockConflictedException(); + } + + public function waitAndSave(Key $key) + { + throw new NotSupportedException(sprintf('The store "%s" does not supports blocking locks.', get_class($this))); + } + + /** + * {@inheritdoc} + */ + public function putOffExpiration(Key $key, $ttl) + { + $successCount = 0; + $failureCount = 0; + $storesCount = count($this->stores); + $expireAt = microtime(true) + $ttl; + + foreach ($this->stores as $store) { + try { + if (0.0 >= $adjustedTtl = $expireAt - microtime(true)) { + $this->logger->warning('Stores took to long to put off the expiration of the "{resource}" lock.', array('resource' => $key, 'store' => $store, 'ttl' => $ttl)); + $key->reduceLifetime(0); + break; + } + + $store->putOffExpiration($key, $adjustedTtl); + ++$successCount; + } catch (\Exception $e) { + $this->logger->warning('One store failed to put off the expiration of the "{resource}" lock.', array('resource' => $key, 'store' => $store, 'exception' => $e)); + ++$failureCount; + } + + if (!$this->strategy->canBeMet($failureCount, $storesCount)) { + break; + } + } + + if ($key->isExpired()) { + throw new LockExpiredException(sprintf('Failed to put off the expiration of the "%s" lock within the specified time.', $key)); + } + + if ($this->strategy->isMet($successCount, $storesCount)) { + return; + } + + $this->logger->warning('Failed to define the expiration for the "{resource}" lock. Quorum has not been met.', array('resource' => $key, 'success' => $successCount, 'failure' => $failureCount)); + + // clean up potential locks + $this->delete($key); + + throw new LockConflictedException(); + } + + /** + * {@inheritdoc} + */ + public function delete(Key $key) + { + foreach ($this->stores as $store) { + try { + $store->delete($key); + } catch (\Exception $e) { + $this->logger->notice('One store failed to delete the "{resource}" lock.', array('resource' => $key, 'store' => $store, 'exception' => $e)); + } catch (\Throwable $e) { + $this->logger->notice('One store failed to delete the "{resource}" lock.', array('resource' => $key, 'store' => $store, 'exception' => $e)); + } + } + } + + /** + * {@inheritdoc} + */ + public function exists(Key $key) + { + $successCount = 0; + $failureCount = 0; + $storesCount = count($this->stores); + + foreach ($this->stores as $store) { + if ($store->exists($key)) { + ++$successCount; + } else { + ++$failureCount; + } + + if ($this->strategy->isMet($successCount, $storesCount)) { + return true; + } + if (!$this->strategy->canBeMet($failureCount, $storesCount)) { + return false; + } + } + + return false; + } +} diff --git a/vendor/symfony/lock/Store/FlockStore.php b/vendor/symfony/lock/Store/FlockStore.php new file mode 100644 index 00000000..287d6fb5 --- /dev/null +++ b/vendor/symfony/lock/Store/FlockStore.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Store; + +use Symfony\Component\Lock\Exception\InvalidArgumentException; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\LockStorageException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * FlockStore is a StoreInterface implementation using the FileSystem flock. + * + * Original implementation in \Symfony\Component\Filesystem\LockHandler. + * + * @author Jérémy Derussé + * @author Grégoire Pineau + * @author Romain Neutron + * @author Nicolas Grekas + */ +class FlockStore implements StoreInterface +{ + private $lockPath; + + /** + * @param string|null $lockPath the directory to store the lock, defaults to the system's temporary directory + * + * @throws LockStorageException If the lock directory doesn’t exist or is not writable + */ + public function __construct($lockPath = null) + { + if (null === $lockPath) { + $lockPath = sys_get_temp_dir(); + } + if (!is_dir($lockPath) || !is_writable($lockPath)) { + throw new InvalidArgumentException(sprintf('The directory "%s" is not writable.', $lockPath)); + } + + $this->lockPath = $lockPath; + } + + /** + * {@inheritdoc} + */ + public function save(Key $key) + { + $this->lock($key, false); + } + + /** + * {@inheritdoc} + */ + public function waitAndSave(Key $key) + { + $this->lock($key, true); + } + + private function lock(Key $key, $blocking) + { + // The lock is maybe already acquired. + if ($key->hasState(__CLASS__)) { + return; + } + + $fileName = sprintf('%s/sf.%s.%s.lock', + $this->lockPath, + preg_replace('/[^a-z0-9\._-]+/i', '-', $key), + strtr(substr(base64_encode(hash('sha256', $key, true)), 0, 7), '/', '_') + ); + + // Silence error reporting + set_error_handler(function () { + }); + if (!$handle = fopen($fileName, 'r')) { + if ($handle = fopen($fileName, 'x')) { + chmod($fileName, 0444); + } elseif (!$handle = fopen($fileName, 'r')) { + usleep(100); // Give some time for chmod() to complete + $handle = fopen($fileName, 'r'); + } + } + restore_error_handler(); + + if (!$handle) { + $error = error_get_last(); + throw new LockStorageException($error['message'], 0, null); + } + + // On Windows, even if PHP doc says the contrary, LOCK_NB works, see + // https://bugs.php.net/54129 + if (!flock($handle, LOCK_EX | ($blocking ? 0 : LOCK_NB))) { + fclose($handle); + throw new LockConflictedException(); + } + + $key->setState(__CLASS__, $handle); + } + + /** + * {@inheritdoc} + */ + public function putOffExpiration(Key $key, $ttl) + { + // do nothing, the flock locks forever. + } + + /** + * {@inheritdoc} + */ + public function delete(Key $key) + { + // The lock is maybe not acquired. + if (!$key->hasState(__CLASS__)) { + return; + } + + $handle = $key->getState(__CLASS__); + + flock($handle, LOCK_UN | LOCK_NB); + fclose($handle); + + $key->removeState(__CLASS__); + } + + /** + * {@inheritdoc} + */ + public function exists(Key $key) + { + return $key->hasState(__CLASS__); + } +} diff --git a/vendor/symfony/lock/Store/MemcachedStore.php b/vendor/symfony/lock/Store/MemcachedStore.php new file mode 100644 index 00000000..8e9db10c --- /dev/null +++ b/vendor/symfony/lock/Store/MemcachedStore.php @@ -0,0 +1,187 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Store; + +use Symfony\Component\Lock\Exception\InvalidArgumentException; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\LockExpiredException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * MemcachedStore is a StoreInterface implementation using Memcached as store engine. + * + * @author Jérémy Derussé + */ +class MemcachedStore implements StoreInterface +{ + private $memcached; + private $initialTtl; + /** @var bool */ + private $useExtendedReturn; + + public static function isSupported() + { + return extension_loaded('memcached'); + } + + /** + * @param \Memcached $memcached + * @param int $initialTtl the expiration delay of locks in seconds + */ + public function __construct(\Memcached $memcached, $initialTtl = 300) + { + if (!static::isSupported()) { + throw new InvalidArgumentException('Memcached extension is required'); + } + + if ($initialTtl < 1) { + throw new InvalidArgumentException(sprintf('%s() expects a strictly positive TTL. Got %d.', __METHOD__, $initialTtl)); + } + + $this->memcached = $memcached; + $this->initialTtl = $initialTtl; + } + + /** + * {@inheritdoc} + */ + public function save(Key $key) + { + $token = $this->getToken($key); + $key->reduceLifetime($this->initialTtl); + if (!$this->memcached->add((string) $key, $token, (int) ceil($this->initialTtl))) { + // the lock is already acquired. It could be us. Let's try to put off. + $this->putOffExpiration($key, $this->initialTtl); + } + + if ($key->isExpired()) { + throw new LockExpiredException(sprintf('Failed to store the "%s" lock.', $key)); + } + } + + public function waitAndSave(Key $key) + { + throw new InvalidArgumentException(sprintf('The store "%s" does not supports blocking locks.', get_class($this))); + } + + /** + * {@inheritdoc} + */ + public function putOffExpiration(Key $key, $ttl) + { + if ($ttl < 1) { + throw new InvalidArgumentException(sprintf('%s() expects a TTL greater or equals to 1. Got %s.', __METHOD__, $ttl)); + } + + // Interface defines a float value but Store required an integer. + $ttl = (int) ceil($ttl); + + $token = $this->getToken($key); + + list($value, $cas) = $this->getValueAndCas($key); + + $key->reduceLifetime($ttl); + // Could happens when we ask a putOff after a timeout but in luck nobody steal the lock + if (\Memcached::RES_NOTFOUND === $this->memcached->getResultCode()) { + if ($this->memcached->add((string) $key, $token, $ttl)) { + return; + } + + // no luck, with concurrency, someone else acquire the lock + throw new LockConflictedException(); + } + + // Someone else steal the lock + if ($value !== $token) { + throw new LockConflictedException(); + } + + if (!$this->memcached->cas($cas, (string) $key, $token, $ttl)) { + throw new LockConflictedException(); + } + + if ($key->isExpired()) { + throw new LockExpiredException(sprintf('Failed to put off the expiration of the "%s" lock within the specified time.', $key)); + } + } + + /** + * {@inheritdoc} + */ + public function delete(Key $key) + { + $token = $this->getToken($key); + + list($value, $cas) = $this->getValueAndCas($key); + + if ($value !== $token) { + // we are not the owner of the lock. Nothing to do. + return; + } + + // To avoid concurrency in deletion, the trick is to extends the TTL then deleting the key + if (!$this->memcached->cas($cas, (string) $key, $token, 2)) { + // Someone steal our lock. It does not belongs to us anymore. Nothing to do. + return; + } + + // Now, we are the owner of the lock for 2 more seconds, we can delete it. + $this->memcached->delete((string) $key); + } + + /** + * {@inheritdoc} + */ + public function exists(Key $key) + { + return $this->memcached->get((string) $key) === $this->getToken($key); + } + + /** + * Retrieve an unique token for the given key. + * + * @param Key $key + * + * @return string + */ + private function getToken(Key $key) + { + if (!$key->hasState(__CLASS__)) { + $token = base64_encode(random_bytes(32)); + $key->setState(__CLASS__, $token); + } + + return $key->getState(__CLASS__); + } + + private function getValueAndCas(Key $key) + { + if (null === $this->useExtendedReturn) { + $this->useExtendedReturn = version_compare(phpversion('memcached'), '2.9.9', '>'); + } + + if ($this->useExtendedReturn) { + $extendedReturn = $this->memcached->get((string) $key, null, \Memcached::GET_EXTENDED); + if (\Memcached::GET_ERROR_RETURN_VALUE === $extendedReturn) { + return array($extendedReturn, 0.0); + } + + return array($extendedReturn['value'], $extendedReturn['cas']); + } + + $cas = 0.0; + $value = $this->memcached->get((string) $key, null, $cas); + + return array($value, $cas); + } +} diff --git a/vendor/symfony/lock/Store/RedisStore.php b/vendor/symfony/lock/Store/RedisStore.php new file mode 100644 index 00000000..4d057337 --- /dev/null +++ b/vendor/symfony/lock/Store/RedisStore.php @@ -0,0 +1,166 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Store; + +use Symfony\Component\Cache\Traits\RedisProxy; +use Symfony\Component\Lock\Exception\InvalidArgumentException; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\LockExpiredException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * RedisStore is a StoreInterface implementation using Redis as store engine. + * + * @author Jérémy Derussé + */ +class RedisStore implements StoreInterface +{ + private $redis; + private $initialTtl; + + /** + * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient + * @param float $initialTtl the expiration delay of locks in seconds + */ + public function __construct($redisClient, $initialTtl = 300.0) + { + if (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \RedisCluster && !$redisClient instanceof \Predis\Client && !$redisClient instanceof RedisProxy) { + throw new InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, is_object($redisClient) ? get_class($redisClient) : gettype($redisClient))); + } + + if ($initialTtl <= 0) { + throw new InvalidArgumentException(sprintf('%s() expects a strictly positive TTL. Got %d.', __METHOD__, $initialTtl)); + } + + $this->redis = $redisClient; + $this->initialTtl = $initialTtl; + } + + /** + * {@inheritdoc} + */ + public function save(Key $key) + { + $script = ' + if redis.call("GET", KEYS[1]) == ARGV[1] then + return redis.call("PEXPIRE", KEYS[1], ARGV[2]) + else + return redis.call("set", KEYS[1], ARGV[1], "NX", "PX", ARGV[2]) + end + '; + + $key->reduceLifetime($this->initialTtl); + if (!$this->evaluate($script, (string) $key, array($this->getToken($key), (int) ceil($this->initialTtl * 1000)))) { + throw new LockConflictedException(); + } + + if ($key->isExpired()) { + throw new LockExpiredException(sprintf('Failed to store the "%s" lock.', $key)); + } + } + + public function waitAndSave(Key $key) + { + throw new InvalidArgumentException(sprintf('The store "%s" does not supports blocking locks.', get_class($this))); + } + + /** + * {@inheritdoc} + */ + public function putOffExpiration(Key $key, $ttl) + { + $script = ' + if redis.call("GET", KEYS[1]) == ARGV[1] then + return redis.call("PEXPIRE", KEYS[1], ARGV[2]) + else + return 0 + end + '; + + $key->reduceLifetime($ttl); + if (!$this->evaluate($script, (string) $key, array($this->getToken($key), (int) ceil($ttl * 1000)))) { + throw new LockConflictedException(); + } + + if ($key->isExpired()) { + throw new LockExpiredException(sprintf('Failed to put off the expiration of the "%s" lock within the specified time.', $key)); + } + } + + /** + * {@inheritdoc} + */ + public function delete(Key $key) + { + $script = ' + if redis.call("GET", KEYS[1]) == ARGV[1] then + return redis.call("DEL", KEYS[1]) + else + return 0 + end + '; + + $this->evaluate($script, (string) $key, array($this->getToken($key))); + } + + /** + * {@inheritdoc} + */ + public function exists(Key $key) + { + return $this->redis->get((string) $key) === $this->getToken($key); + } + + /** + * Evaluates a script in the corresponding redis client. + * + * @param string $script + * @param string $resource + * @param array $args + * + * @return mixed + */ + private function evaluate($script, $resource, array $args) + { + if ($this->redis instanceof \Redis || $this->redis instanceof \RedisCluster || $this->redis instanceof RedisProxy) { + return $this->redis->eval($script, array_merge(array($resource), $args), 1); + } + + if ($this->redis instanceof \RedisArray) { + return $this->redis->_instance($this->redis->_target($resource))->eval($script, array_merge(array($resource), $args), 1); + } + + if ($this->redis instanceof \Predis\Client) { + return call_user_func_array(array($this->redis, 'eval'), array_merge(array($script, 1, $resource), $args)); + } + + throw new InvalidArgumentException(sprintf('%s() expects been initialized with a Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, is_object($this->redis) ? get_class($this->redis) : gettype($this->redis))); + } + + /** + * Retrieves an unique token for the given key. + * + * @param Key $key + * + * @return string + */ + private function getToken(Key $key) + { + if (!$key->hasState(__CLASS__)) { + $token = base64_encode(random_bytes(32)); + $key->setState(__CLASS__, $token); + } + + return $key->getState(__CLASS__); + } +} diff --git a/vendor/symfony/lock/Store/RetryTillSaveStore.php b/vendor/symfony/lock/Store/RetryTillSaveStore.php new file mode 100644 index 00000000..dfc3b266 --- /dev/null +++ b/vendor/symfony/lock/Store/RetryTillSaveStore.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Store; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Psr\Log\NullLogger; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * RetryTillSaveStore is a StoreInterface implementation which decorate a non blocking StoreInterface to provide a + * blocking storage. + * + * @author Jérémy Derussé + */ +class RetryTillSaveStore implements StoreInterface, LoggerAwareInterface +{ + use LoggerAwareTrait; + + private $decorated; + private $retrySleep; + private $retryCount; + + /** + * @param StoreInterface $decorated The decorated StoreInterface + * @param int $retrySleep Duration in ms between 2 retry + * @param int $retryCount Maximum amount of retry + */ + public function __construct(StoreInterface $decorated, $retrySleep = 100, $retryCount = PHP_INT_MAX) + { + $this->decorated = $decorated; + $this->retrySleep = $retrySleep; + $this->retryCount = $retryCount; + + $this->logger = new NullLogger(); + } + + /** + * {@inheritdoc} + */ + public function save(Key $key) + { + $this->decorated->save($key); + } + + /** + * {@inheritdoc} + */ + public function waitAndSave(Key $key) + { + $retry = 0; + $sleepRandomness = (int) ($this->retrySleep / 10); + do { + try { + $this->decorated->save($key); + + return; + } catch (LockConflictedException $e) { + usleep(($this->retrySleep + random_int(-$sleepRandomness, $sleepRandomness)) * 1000); + } + } while (++$retry < $this->retryCount); + + $this->logger->warning('Failed to store the "{resource}" lock. Abort after {retry} retry.', array('resource' => $key, 'retry' => $retry)); + + throw new LockConflictedException(); + } + + /** + * {@inheritdoc} + */ + public function putOffExpiration(Key $key, $ttl) + { + $this->decorated->putOffExpiration($key, $ttl); + } + + /** + * {@inheritdoc} + */ + public function delete(Key $key) + { + $this->decorated->delete($key); + } + + /** + * {@inheritdoc} + */ + public function exists(Key $key) + { + return $this->decorated->exists($key); + } +} diff --git a/vendor/symfony/lock/Store/SemaphoreStore.php b/vendor/symfony/lock/Store/SemaphoreStore.php new file mode 100644 index 00000000..a6cc9ea8 --- /dev/null +++ b/vendor/symfony/lock/Store/SemaphoreStore.php @@ -0,0 +1,129 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Store; + +use Symfony\Component\Lock\Exception\InvalidArgumentException; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\NotSupportedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * SemaphoreStore is a StoreInterface implementation using Semaphore as store engine. + * + * @author Jérémy Derussé + */ +class SemaphoreStore implements StoreInterface +{ + /** + * Returns whether or not the store is supported. + * + * @param bool|null $blocking when not null, checked again the blocking mode + * + * @return bool + * + * @internal + */ + public static function isSupported($blocking = null) + { + if (!extension_loaded('sysvsem')) { + return false; + } + + if (false === $blocking && \PHP_VERSION_ID < 50601) { + return false; + } + + return true; + } + + public function __construct() + { + if (!static::isSupported()) { + throw new InvalidArgumentException('Semaphore extension (sysvsem) is required'); + } + } + + /** + * {@inheritdoc} + */ + public function save(Key $key) + { + $this->lock($key, false); + } + + /** + * {@inheritdoc} + */ + public function waitAndSave(Key $key) + { + $this->lock($key, true); + } + + private function lock(Key $key, $blocking) + { + if ($key->hasState(__CLASS__)) { + return; + } + + $resource = sem_get(crc32($key)); + + if (\PHP_VERSION_ID < 50601) { + if (!$blocking) { + throw new NotSupportedException(sprintf('The store "%s" does not supports non blocking locks.', get_class($this))); + } + + $acquired = sem_acquire($resource); + } else { + $acquired = sem_acquire($resource, !$blocking); + } + + if (!$acquired) { + throw new LockConflictedException(); + } + + $key->setState(__CLASS__, $resource); + } + + /** + * {@inheritdoc} + */ + public function delete(Key $key) + { + // The lock is maybe not acquired. + if (!$key->hasState(__CLASS__)) { + return; + } + + $resource = $key->getState(__CLASS__); + + sem_release($resource); + + $key->removeState(__CLASS__); + } + + /** + * {@inheritdoc} + */ + public function putOffExpiration(Key $key, $ttl) + { + // do nothing, the semaphore locks forever. + } + + /** + * {@inheritdoc} + */ + public function exists(Key $key) + { + return $key->hasState(__CLASS__); + } +} diff --git a/vendor/symfony/lock/Store/StoreFactory.php b/vendor/symfony/lock/Store/StoreFactory.php new file mode 100644 index 00000000..a768d197 --- /dev/null +++ b/vendor/symfony/lock/Store/StoreFactory.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Store; + +use Symfony\Component\Cache\Traits\RedisProxy; +use Symfony\Component\Lock\Exception\InvalidArgumentException; + +/** + * StoreFactory create stores and connections. + * + * @author Jérémy Derussé + */ +class StoreFactory +{ + /** + * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client|\Memcached $connection + * + * @return RedisStore|MemcachedStore + */ + public static function createStore($connection) + { + if ($connection instanceof \Redis || $connection instanceof \RedisArray || $connection instanceof \RedisCluster || $connection instanceof \Predis\Client || $connection instanceof RedisProxy) { + return new RedisStore($connection); + } + if ($connection instanceof \Memcached) { + return new MemcachedStore($connection); + } + + throw new InvalidArgumentException(sprintf('Unsupported Connection: %s.', get_class($connection))); + } +} diff --git a/vendor/symfony/lock/StoreInterface.php b/vendor/symfony/lock/StoreInterface.php new file mode 100644 index 00000000..985c4476 --- /dev/null +++ b/vendor/symfony/lock/StoreInterface.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock; + +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Exception\NotSupportedException; + +/** + * StoreInterface defines an interface to manipulate a lock store. + * + * @author Jérémy Derussé + */ +interface StoreInterface +{ + /** + * Stores the resource if it's not locked by someone else. + * + * @throws LockConflictedException + */ + public function save(Key $key); + + /** + * Waits until a key becomes free, then stores the resource. + * + * If the store does not support this feature it should throw a NotSupportedException. + * + * @throws LockConflictedException + * @throws NotSupportedException + */ + public function waitAndSave(Key $key); + + /** + * Extends the ttl of a resource. + * + * If the store does not support this feature it should throw a NotSupportedException. + * + * @param float $ttl amount of second to keep the lock in the store + * + * @throws LockConflictedException + * @throws NotSupportedException + */ + public function putOffExpiration(Key $key, $ttl); + + /** + * Removes a resource from the storage. + */ + public function delete(Key $key); + + /** + * Returns whether or not the resource exists in the storage. + * + * @return bool + */ + public function exists(Key $key); +} diff --git a/vendor/symfony/lock/Strategy/ConsensusStrategy.php b/vendor/symfony/lock/Strategy/ConsensusStrategy.php new file mode 100644 index 00000000..047820a4 --- /dev/null +++ b/vendor/symfony/lock/Strategy/ConsensusStrategy.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Strategy; + +/** + * ConsensusStrategy is a StrategyInterface implementation where strictly more than 50% items should be successful. + * + * @author Jérémy Derussé + */ +class ConsensusStrategy implements StrategyInterface +{ + /** + * {@inheritdoc} + */ + public function isMet($numberOfSuccess, $numberOfItems) + { + return $numberOfSuccess > ($numberOfItems / 2); + } + + /** + * {@inheritdoc} + */ + public function canBeMet($numberOfFailure, $numberOfItems) + { + return $numberOfFailure < ($numberOfItems / 2); + } +} diff --git a/vendor/symfony/lock/Strategy/StrategyInterface.php b/vendor/symfony/lock/Strategy/StrategyInterface.php new file mode 100644 index 00000000..beaa7280 --- /dev/null +++ b/vendor/symfony/lock/Strategy/StrategyInterface.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Strategy; + +/** + * StrategyInterface defines an interface to indicate when a quorum is met and can be met. + * + * @author Jérémy Derussé + */ +interface StrategyInterface +{ + /** + * Returns whether or not the quorum is met. + * + * @param int $numberOfSuccess + * @param int $numberOfItems + * + * @return bool + */ + public function isMet($numberOfSuccess, $numberOfItems); + + /** + * Returns whether or not the quorum *could* be met. + * + * This method does not mean the quorum *would* be met for sure, but can be useful to stop a process early when you + * known there is no chance to meet the quorum. + * + * @param int $numberOfFailure + * @param int $numberOfItems + * + * @return bool + */ + public function canBeMet($numberOfFailure, $numberOfItems); +} diff --git a/vendor/symfony/lock/Strategy/UnanimousStrategy.php b/vendor/symfony/lock/Strategy/UnanimousStrategy.php new file mode 100644 index 00000000..27404f3e --- /dev/null +++ b/vendor/symfony/lock/Strategy/UnanimousStrategy.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Strategy; + +/** + * UnanimousStrategy is a StrategyInterface implementation where 100% of elements should be successful. + * + * @author Jérémy Derussé + */ +class UnanimousStrategy implements StrategyInterface +{ + /** + * {@inheritdoc} + */ + public function isMet($numberOfSuccess, $numberOfItems) + { + return $numberOfSuccess === $numberOfItems; + } + + /** + * {@inheritdoc} + */ + public function canBeMet($numberOfFailure, $numberOfItems) + { + return 0 === $numberOfFailure; + } +} diff --git a/vendor/symfony/lock/Tests/FactoryTest.php b/vendor/symfony/lock/Tests/FactoryTest.php new file mode 100644 index 00000000..d6794909 --- /dev/null +++ b/vendor/symfony/lock/Tests/FactoryTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests; + +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Symfony\Component\Lock\Factory; +use Symfony\Component\Lock\LockInterface; +use Symfony\Component\Lock\StoreInterface; + +/** + * @author Jérémy Derussé + */ +class FactoryTest extends TestCase +{ + public function testCreateLock() + { + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); + $factory = new Factory($store); + $factory->setLogger($logger); + + $lock = $factory->createLock('foo'); + + $this->assertInstanceOf(LockInterface::class, $lock); + } +} diff --git a/vendor/symfony/lock/Tests/LockTest.php b/vendor/symfony/lock/Tests/LockTest.php new file mode 100644 index 00000000..7913644b --- /dev/null +++ b/vendor/symfony/lock/Tests/LockTest.php @@ -0,0 +1,254 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests; + +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\Lock; +use Symfony\Component\Lock\StoreInterface; + +/** + * @author Jérémy Derussé + */ +class LockTest extends TestCase +{ + public function testAcquireNoBlocking() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store); + + $store + ->expects($this->once()) + ->method('save'); + + $this->assertTrue($lock->acquire(false)); + } + + public function testAcquireReturnsFalse() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store); + + $store + ->expects($this->once()) + ->method('save') + ->willThrowException(new LockConflictedException()); + + $this->assertFalse($lock->acquire(false)); + } + + public function testAcquireBlocking() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store); + + $store + ->expects($this->never()) + ->method('save'); + $store + ->expects($this->once()) + ->method('waitAndSave'); + + $this->assertTrue($lock->acquire(true)); + } + + public function testAcquireSetsTtl() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10); + + $store + ->expects($this->once()) + ->method('save'); + $store + ->expects($this->once()) + ->method('putOffExpiration') + ->with($key, 10); + + $lock->acquire(); + } + + public function testRefresh() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10); + + $store + ->expects($this->once()) + ->method('putOffExpiration') + ->with($key, 10); + + $lock->refresh(); + } + + public function testIsAquired() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10); + + $store + ->expects($this->any()) + ->method('exists') + ->with($key) + ->will($this->onConsecutiveCalls(true, false)); + + $this->assertTrue($lock->isAcquired()); + } + + public function testRelease() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10); + + $store + ->expects($this->once()) + ->method('delete') + ->with($key); + + $store + ->expects($this->once()) + ->method('exists') + ->with($key) + ->willReturn(false); + + $lock->release(); + } + + public function testReleaseOnDestruction() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10); + + $store + ->method('exists') + ->willReturnOnConsecutiveCalls(array(true, false)) + ; + $store + ->expects($this->once()) + ->method('delete') + ; + + $lock->acquire(false); + unset($lock); + } + + public function testNoAutoReleaseWhenNotConfigured() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10, false); + + $store + ->method('exists') + ->willReturnOnConsecutiveCalls(array(true, false)) + ; + $store + ->expects($this->never()) + ->method('delete') + ; + + $lock->acquire(false); + unset($lock); + } + + /** + * @expectedException \Symfony\Component\Lock\Exception\LockReleasingException + */ + public function testReleaseThrowsExceptionIfNotWellDeleted() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10); + + $store + ->expects($this->once()) + ->method('delete') + ->with($key); + + $store + ->expects($this->once()) + ->method('exists') + ->with($key) + ->willReturn(true); + + $lock->release(); + } + + /** + * @expectedException \Symfony\Component\Lock\Exception\LockReleasingException + */ + public function testReleaseThrowsAndLog() + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); + $lock = new Lock($key, $store, 10, true); + $lock->setLogger($logger); + + $logger->expects($this->atLeastOnce()) + ->method('notice') + ->with('Failed to release the "{resource}" lock.', array('resource' => $key)); + + $store + ->expects($this->once()) + ->method('delete') + ->with($key); + + $store + ->expects($this->once()) + ->method('exists') + ->with($key) + ->willReturn(true); + + $lock->release(); + } + + /** + * @dataProvider provideExpiredDates + */ + public function testExpiration($ttls, $expected) + { + $key = new Key(uniqid(__METHOD__, true)); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); + $lock = new Lock($key, $store, 10); + + foreach ($ttls as $ttl) { + if (null === $ttl) { + $key->resetLifetime(); + } else { + $key->reduceLifetime($ttl); + } + } + $this->assertSame($expected, $lock->isExpired()); + } + + public function provideExpiredDates() + { + yield array(array(-0.1), true); + yield array(array(0.1, -0.1), true); + yield array(array(-0.1, 0.1), true); + + yield array(array(), false); + yield array(array(0.1), false); + yield array(array(-0.1, null), false); + } +} diff --git a/vendor/symfony/lock/Tests/Store/AbstractRedisStoreTest.php b/vendor/symfony/lock/Tests/Store/AbstractRedisStoreTest.php new file mode 100644 index 00000000..4b9c81bd --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/AbstractRedisStoreTest.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Store\RedisStore; + +/** + * @author Jérémy Derussé + */ +abstract class AbstractRedisStoreTest extends AbstractStoreTest +{ + use ExpiringStoreTestTrait; + + /** + * {@inheritdoc} + */ + protected function getClockDelay() + { + return 250000; + } + + /** + * Return a RedisConnection. + * + * @return \Redis|\RedisArray|\RedisCluster|\Predis\Client + */ + abstract protected function getRedisConnection(); + + /** + * {@inheritdoc} + */ + public function getStore() + { + return new RedisStore($this->getRedisConnection()); + } +} diff --git a/vendor/symfony/lock/Tests/Store/AbstractStoreTest.php b/vendor/symfony/lock/Tests/Store/AbstractStoreTest.php new file mode 100644 index 00000000..2ab030b2 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/AbstractStoreTest.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * @author Jérémy Derussé + */ +abstract class AbstractStoreTest extends TestCase +{ + /** + * @return StoreInterface + */ + abstract protected function getStore(); + + public function testSave() + { + $store = $this->getStore(); + + $key = new Key(uniqid(__METHOD__, true)); + + $this->assertFalse($store->exists($key)); + $store->save($key); + $this->assertTrue($store->exists($key)); + $store->delete($key); + $this->assertFalse($store->exists($key)); + } + + public function testSaveWithDifferentResources() + { + $store = $this->getStore(); + + $key1 = new Key(uniqid(__METHOD__, true)); + $key2 = new Key(uniqid(__METHOD__, true)); + + $store->save($key1); + $this->assertTrue($store->exists($key1)); + $this->assertFalse($store->exists($key2)); + + $store->save($key2); + $this->assertTrue($store->exists($key1)); + $this->assertTrue($store->exists($key2)); + + $store->delete($key1); + $this->assertFalse($store->exists($key1)); + $this->assertTrue($store->exists($key2)); + + $store->delete($key2); + $this->assertFalse($store->exists($key1)); + $this->assertFalse($store->exists($key2)); + } + + public function testSaveWithDifferentKeysOnSameResources() + { + $store = $this->getStore(); + + $resource = uniqid(__METHOD__, true); + $key1 = new Key($resource); + $key2 = new Key($resource); + + $store->save($key1); + $this->assertTrue($store->exists($key1)); + $this->assertFalse($store->exists($key2)); + + try { + $store->save($key2); + $this->fail('The store shouldn\'t save the second key'); + } catch (LockConflictedException $e) { + } + + // The failure of previous attempt should not impact the state of current locks + $this->assertTrue($store->exists($key1)); + $this->assertFalse($store->exists($key2)); + + $store->delete($key1); + $this->assertFalse($store->exists($key1)); + $this->assertFalse($store->exists($key2)); + + $store->save($key2); + $this->assertFalse($store->exists($key1)); + $this->assertTrue($store->exists($key2)); + + $store->delete($key2); + $this->assertFalse($store->exists($key1)); + $this->assertFalse($store->exists($key2)); + } + + public function testSaveTwice() + { + $store = $this->getStore(); + + $resource = uniqid(__METHOD__, true); + $key = new Key($resource); + + $store->save($key); + $store->save($key); + // just asserts it don't throw an exception + $this->addToAssertionCount(1); + + $store->delete($key); + } +} diff --git a/vendor/symfony/lock/Tests/Store/BlockingStoreTestTrait.php b/vendor/symfony/lock/Tests/Store/BlockingStoreTestTrait.php new file mode 100644 index 00000000..93e5a547 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/BlockingStoreTestTrait.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * @author Jérémy Derussé + */ +trait BlockingStoreTestTrait +{ + /** + * @see AbstractStoreTest::getStore() + */ + abstract protected function getStore(); + + /** + * Tests blocking locks thanks to pcntl. + * + * This test is time sensible: the $clockDelay could be adjust. + * + * @requires extension pcntl + * @requires function pcntl_sigwaitinfo + */ + public function testBlockingLocks() + { + // Amount a microsecond used to order async actions + $clockDelay = 50000; + + if (\PHP_VERSION_ID < 50600 || defined('HHVM_VERSION_ID')) { + $this->markTestSkipped('The PHP engine does not keep resource in child forks'); + + return; + } + + /** @var StoreInterface $store */ + $store = $this->getStore(); + $key = new Key(uniqid(__METHOD__, true)); + $parentPID = posix_getpid(); + + // Block SIGHUP signal + pcntl_sigprocmask(SIG_BLOCK, array(SIGHUP)); + + if ($childPID = pcntl_fork()) { + // Wait the start of the child + pcntl_sigwaitinfo(array(SIGHUP), $info); + + try { + // This call should failed given the lock should already by acquired by the child + $store->save($key); + $this->fail('The store saves a locked key.'); + } catch (LockConflictedException $e) { + } + + // send the ready signal to the child + posix_kill($childPID, SIGHUP); + + // This call should be blocked by the child #1 + $store->waitAndSave($key); + $this->assertTrue($store->exists($key)); + $store->delete($key); + + // Now, assert the child process worked well + pcntl_waitpid($childPID, $status1); + $this->assertSame(0, pcntl_wexitstatus($status1), 'The child process couldn\'t lock the resource'); + } else { + // Block SIGHUP signal + pcntl_sigprocmask(SIG_BLOCK, array(SIGHUP)); + try { + $store->save($key); + // send the ready signal to the parent + posix_kill($parentPID, SIGHUP); + + // Wait for the parent to be ready + pcntl_sigwaitinfo(array(SIGHUP), $info); + + // Wait ClockDelay to let parent assert to finish + usleep($clockDelay); + $store->delete($key); + exit(0); + } catch (\Exception $e) { + exit(1); + } + } + } +} diff --git a/vendor/symfony/lock/Tests/Store/CombinedStoreTest.php b/vendor/symfony/lock/Tests/Store/CombinedStoreTest.php new file mode 100644 index 00000000..c7232d40 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/CombinedStoreTest.php @@ -0,0 +1,356 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\Strategy\UnanimousStrategy; +use Symfony\Component\Lock\Strategy\StrategyInterface; +use Symfony\Component\Lock\Store\CombinedStore; +use Symfony\Component\Lock\Store\RedisStore; +use Symfony\Component\Lock\StoreInterface; + +/** + * @author Jérémy Derussé + */ +class CombinedStoreTest extends AbstractStoreTest +{ + use ExpiringStoreTestTrait; + + /** + * {@inheritdoc} + */ + protected function getClockDelay() + { + return 250000; + } + + /** + * {@inheritdoc} + */ + public function getStore() + { + $redis = new \Predis\Client('tcp://'.getenv('REDIS_HOST').':6379'); + try { + $redis->connect(); + } catch (\Exception $e) { + self::markTestSkipped($e->getMessage()); + } + + return new CombinedStore(array(new RedisStore($redis)), new UnanimousStrategy()); + } + + /** @var \PHPUnit_Framework_MockObject_MockObject */ + private $strategy; + /** @var \PHPUnit_Framework_MockObject_MockObject */ + private $store1; + /** @var \PHPUnit_Framework_MockObject_MockObject */ + private $store2; + /** @var CombinedStore */ + private $store; + + public function setup() + { + $this->strategy = $this->getMockBuilder(StrategyInterface::class)->getMock(); + $this->store1 = $this->getMockBuilder(StoreInterface::class)->getMock(); + $this->store2 = $this->getMockBuilder(StoreInterface::class)->getMock(); + + $this->store = new CombinedStore(array($this->store1, $this->store2), $this->strategy); + } + + /** + * @expectedException \Symfony\Component\Lock\Exception\LockConflictedException + */ + public function testSaveThrowsExceptionOnFailure() + { + $key = new Key(uniqid(__METHOD__, true)); + + $this->store1 + ->expects($this->once()) + ->method('save') + ->with($key) + ->willThrowException(new LockConflictedException()); + $this->store2 + ->expects($this->once()) + ->method('save') + ->with($key) + ->willThrowException(new LockConflictedException()); + + $this->strategy + ->expects($this->any()) + ->method('canBeMet') + ->willReturn(true); + $this->strategy + ->expects($this->any()) + ->method('isMet') + ->willReturn(false); + + $this->store->save($key); + } + + public function testSaveCleanupOnFailure() + { + $key = new Key(uniqid(__METHOD__, true)); + + $this->store1 + ->expects($this->once()) + ->method('save') + ->with($key) + ->willThrowException(new LockConflictedException()); + $this->store2 + ->expects($this->once()) + ->method('save') + ->with($key) + ->willThrowException(new LockConflictedException()); + + $this->store1 + ->expects($this->once()) + ->method('delete'); + $this->store2 + ->expects($this->once()) + ->method('delete'); + + $this->strategy + ->expects($this->any()) + ->method('canBeMet') + ->willReturn(true); + $this->strategy + ->expects($this->any()) + ->method('isMet') + ->willReturn(false); + + try { + $this->store->save($key); + } catch (LockConflictedException $e) { + // Catch the exception given this is not what we want to assert in this tests + } + } + + public function testSaveAbortWhenStrategyCantBeMet() + { + $key = new Key(uniqid(__METHOD__, true)); + + $this->store1 + ->expects($this->once()) + ->method('save') + ->with($key) + ->willThrowException(new LockConflictedException()); + $this->store2 + ->expects($this->never()) + ->method('save'); + + $this->strategy + ->expects($this->once()) + ->method('canBeMet') + ->willReturn(false); + $this->strategy + ->expects($this->any()) + ->method('isMet') + ->willReturn(false); + + try { + $this->store->save($key); + } catch (LockConflictedException $e) { + // Catch the exception given this is not what we want to assert in this tests + } + } + + /** + * @expectedException \Symfony\Component\Lock\Exception\LockConflictedException + */ + public function testputOffExpirationThrowsExceptionOnFailure() + { + $key = new Key(uniqid(__METHOD__, true)); + $ttl = random_int(1, 10); + + $this->store1 + ->expects($this->once()) + ->method('putOffExpiration') + ->with($key, $this->lessThanOrEqual($ttl)) + ->willThrowException(new LockConflictedException()); + $this->store2 + ->expects($this->once()) + ->method('putOffExpiration') + ->with($key, $this->lessThanOrEqual($ttl)) + ->willThrowException(new LockConflictedException()); + + $this->strategy + ->expects($this->any()) + ->method('canBeMet') + ->willReturn(true); + $this->strategy + ->expects($this->any()) + ->method('isMet') + ->willReturn(false); + + $this->store->putOffExpiration($key, $ttl); + } + + public function testputOffExpirationCleanupOnFailure() + { + $key = new Key(uniqid(__METHOD__, true)); + $ttl = random_int(1, 10); + + $this->store1 + ->expects($this->once()) + ->method('putOffExpiration') + ->with($key, $this->lessThanOrEqual($ttl)) + ->willThrowException(new LockConflictedException()); + $this->store2 + ->expects($this->once()) + ->method('putOffExpiration') + ->with($key, $this->lessThanOrEqual($ttl)) + ->willThrowException(new LockConflictedException()); + + $this->store1 + ->expects($this->once()) + ->method('delete'); + $this->store2 + ->expects($this->once()) + ->method('delete'); + + $this->strategy + ->expects($this->any()) + ->method('canBeMet') + ->willReturn(true); + $this->strategy + ->expects($this->any()) + ->method('isMet') + ->willReturn(false); + + try { + $this->store->putOffExpiration($key, $ttl); + } catch (LockConflictedException $e) { + // Catch the exception given this is not what we want to assert in this tests + } + } + + public function testputOffExpirationAbortWhenStrategyCantBeMet() + { + $key = new Key(uniqid(__METHOD__, true)); + $ttl = random_int(1, 10); + + $this->store1 + ->expects($this->once()) + ->method('putOffExpiration') + ->with($key, $this->lessThanOrEqual($ttl)) + ->willThrowException(new LockConflictedException()); + $this->store2 + ->expects($this->never()) + ->method('putOffExpiration'); + + $this->strategy + ->expects($this->once()) + ->method('canBeMet') + ->willReturn(false); + $this->strategy + ->expects($this->any()) + ->method('isMet') + ->willReturn(false); + + try { + $this->store->putOffExpiration($key, $ttl); + } catch (LockConflictedException $e) { + // Catch the exception given this is not what we want to assert in this tests + } + } + + public function testPutOffExpirationIgnoreNonExpiringStorage() + { + $store1 = $this->getMockBuilder(StoreInterface::class)->getMock(); + $store2 = $this->getMockBuilder(StoreInterface::class)->getMock(); + + $store = new CombinedStore(array($store1, $store2), $this->strategy); + + $key = new Key(uniqid(__METHOD__, true)); + $ttl = random_int(1, 10); + + $this->strategy + ->expects($this->any()) + ->method('canBeMet') + ->willReturn(true); + $this->strategy + ->expects($this->once()) + ->method('isMet') + ->with(2, 2) + ->willReturn(true); + + $store->putOffExpiration($key, $ttl); + } + + public function testExistsDontAskToEveryBody() + { + $key = new Key(uniqid(__METHOD__, true)); + + $this->store1 + ->expects($this->any()) + ->method('exists') + ->with($key) + ->willReturn(false); + $this->store2 + ->expects($this->never()) + ->method('exists'); + + $this->strategy + ->expects($this->any()) + ->method('canBeMet') + ->willReturn(true); + $this->strategy + ->expects($this->once()) + ->method('isMet') + ->willReturn(true); + + $this->assertTrue($this->store->exists($key)); + } + + public function testExistsAbortWhenStrategyCantBeMet() + { + $key = new Key(uniqid(__METHOD__, true)); + + $this->store1 + ->expects($this->any()) + ->method('exists') + ->with($key) + ->willReturn(false); + $this->store2 + ->expects($this->never()) + ->method('exists'); + + $this->strategy + ->expects($this->once()) + ->method('canBeMet') + ->willReturn(false); + $this->strategy + ->expects($this->once()) + ->method('isMet') + ->willReturn(false); + + $this->assertFalse($this->store->exists($key)); + } + + public function testDeleteDontStopOnFailure() + { + $key = new Key(uniqid(__METHOD__, true)); + + $this->store1 + ->expects($this->once()) + ->method('delete') + ->with($key) + ->willThrowException(new \Exception()); + $this->store2 + ->expects($this->once()) + ->method('delete') + ->with($key); + + $this->store->delete($key); + } +} diff --git a/vendor/symfony/lock/Tests/Store/ExpiringStoreTestTrait.php b/vendor/symfony/lock/Tests/Store/ExpiringStoreTestTrait.php new file mode 100644 index 00000000..10b13273 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/ExpiringStoreTestTrait.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\StoreInterface; + +/** + * @author Jérémy Derussé + */ +trait ExpiringStoreTestTrait +{ + /** + * Amount a microsecond used to order async actions. + * + * @return int + */ + abstract protected function getClockDelay(); + + /** + * @see AbstractStoreTest::getStore() + */ + abstract protected function getStore(); + + /** + * Tests the store automatically delete the key when it expire. + * + * This test is time sensible: the $clockDelay could be adjust. + */ + public function testExpiration() + { + $key = new Key(uniqid(__METHOD__, true)); + $clockDelay = $this->getClockDelay(); + + /** @var StoreInterface $store */ + $store = $this->getStore(); + + $store->save($key); + $store->putOffExpiration($key, $clockDelay / 1000000); + $this->assertTrue($store->exists($key)); + + usleep(2 * $clockDelay); + $this->assertFalse($store->exists($key)); + } + + /** + * Tests the store thrown exception when TTL expires. + * + * @expectedException \Symfony\Component\Lock\Exception\LockExpiredException + */ + public function testAbortAfterExpiration() + { + $key = new Key(uniqid(__METHOD__, true)); + + /** @var StoreInterface $store */ + $store = $this->getStore(); + + $store->save($key); + $store->putOffExpiration($key, 1 / 1000000); + } + + /** + * Tests the refresh can push the limits to the expiration. + * + * This test is time sensible: the $clockDelay could be adjust. + */ + public function testRefreshLock() + { + // Amount a microsecond used to order async actions + $clockDelay = $this->getClockDelay(); + + // Amount a microsecond used to order async actions + $key = new Key(uniqid(__METHOD__, true)); + + /** @var StoreInterface $store */ + $store = $this->getStore(); + + $store->save($key); + $store->putOffExpiration($key, $clockDelay / 1000000); + $this->assertTrue($store->exists($key)); + + usleep(2 * $clockDelay); + $this->assertFalse($store->exists($key)); + } + + public function testSetExpiration() + { + $key = new Key(uniqid(__METHOD__, true)); + + /** @var StoreInterface $store */ + $store = $this->getStore(); + + $store->save($key); + $store->putOffExpiration($key, 1); + $this->assertGreaterThanOrEqual(0, $key->getRemainingLifetime()); + $this->assertLessThanOrEqual(1, $key->getRemainingLifetime()); + } +} diff --git a/vendor/symfony/lock/Tests/Store/FlockStoreTest.php b/vendor/symfony/lock/Tests/Store/FlockStoreTest.php new file mode 100644 index 00000000..ef3650c3 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/FlockStoreTest.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\Store\FlockStore; + +/** + * @author Jérémy Derussé + */ +class FlockStoreTest extends AbstractStoreTest +{ + use BlockingStoreTestTrait; + + /** + * {@inheritdoc} + */ + protected function getStore() + { + return new FlockStore(); + } + + /** + * @expectedException \Symfony\Component\Lock\Exception\InvalidArgumentException + * @expectedExceptionMessage The directory "/a/b/c/d/e" is not writable. + */ + public function testConstructWhenRepositoryDoesNotExist() + { + if (!getenv('USER') || 'root' === getenv('USER')) { + $this->markTestSkipped('This test will fail if run under superuser'); + } + + new FlockStore('/a/b/c/d/e'); + } + + /** + * @expectedException \Symfony\Component\Lock\Exception\InvalidArgumentException + * @expectedExceptionMessage The directory "/" is not writable. + */ + public function testConstructWhenRepositoryIsNotWriteable() + { + if (!getenv('USER') || 'root' === getenv('USER')) { + $this->markTestSkipped('This test will fail if run under superuser'); + } + + new FlockStore('/'); + } + + public function testSaveSanitizeName() + { + $store = $this->getStore(); + + $key = new Key(''); + + $file = sprintf( + '%s/sf.-php-echo-hello-word-.%s.lock', + sys_get_temp_dir(), + strtr(substr(base64_encode(hash('sha256', $key, true)), 0, 7), '/', '_') + ); + // ensure the file does not exist before the store + @unlink($file); + + $store->save($key); + + $this->assertFileExists($file); + + $store->delete($key); + } +} diff --git a/vendor/symfony/lock/Tests/Store/MemcachedStoreTest.php b/vendor/symfony/lock/Tests/Store/MemcachedStoreTest.php new file mode 100644 index 00000000..f4ab571f --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/MemcachedStoreTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Store\MemcachedStore; + +/** + * @author Jérémy Derussé + * + * @requires extension memcached + */ +class MemcachedStoreTest extends AbstractStoreTest +{ + use ExpiringStoreTestTrait; + + public static function setupBeforeClass() + { + $memcached = new \Memcached(); + $memcached->addServer(getenv('MEMCACHED_HOST'), 11211); + $memcached->get('foo'); + $code = $memcached->getResultCode(); + + if (\Memcached::RES_SUCCESS !== $code && \Memcached::RES_NOTFOUND !== $code) { + self::markTestSkipped('Unable to connect to the memcache host'); + } + } + + /** + * {@inheritdoc} + */ + protected function getClockDelay() + { + return 1000000; + } + + /** + * {@inheritdoc} + */ + public function getStore() + { + $memcached = new \Memcached(); + $memcached->addServer(getenv('MEMCACHED_HOST'), 11211); + + return new MemcachedStore($memcached); + } + + public function testAbortAfterExpiration() + { + $this->markTestSkipped('Memcached expects a TTL greater than 1 sec. Simulating a slow network is too hard'); + } +} diff --git a/vendor/symfony/lock/Tests/Store/PredisStoreTest.php b/vendor/symfony/lock/Tests/Store/PredisStoreTest.php new file mode 100644 index 00000000..621affec --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/PredisStoreTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +/** + * @author Jérémy Derussé + */ +class PredisStoreTest extends AbstractRedisStoreTest +{ + public static function setupBeforeClass() + { + $redis = new \Predis\Client('tcp://'.getenv('REDIS_HOST').':6379'); + try { + $redis->connect(); + } catch (\Exception $e) { + self::markTestSkipped($e->getMessage()); + } + } + + protected function getRedisConnection() + { + $redis = new \Predis\Client('tcp://'.getenv('REDIS_HOST').':6379'); + $redis->connect(); + + return $redis; + } +} diff --git a/vendor/symfony/lock/Tests/Store/RedisArrayStoreTest.php b/vendor/symfony/lock/Tests/Store/RedisArrayStoreTest.php new file mode 100644 index 00000000..180da461 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/RedisArrayStoreTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +/** + * @author Jérémy Derussé + * + * @requires extension redis + */ +class RedisArrayStoreTest extends AbstractRedisStoreTest +{ + public static function setupBeforeClass() + { + if (!class_exists('RedisArray')) { + self::markTestSkipped('The RedisArray class is required.'); + } + if (!@((new \Redis())->connect(getenv('REDIS_HOST')))) { + $e = error_get_last(); + self::markTestSkipped($e['message']); + } + } + + protected function getRedisConnection() + { + $redis = new \RedisArray(array(getenv('REDIS_HOST'))); + + return $redis; + } +} diff --git a/vendor/symfony/lock/Tests/Store/RedisStoreTest.php b/vendor/symfony/lock/Tests/Store/RedisStoreTest.php new file mode 100644 index 00000000..6c7d2441 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/RedisStoreTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +/** + * @author Jérémy Derussé + * + * @requires extension redis + */ +class RedisStoreTest extends AbstractRedisStoreTest +{ + public static function setupBeforeClass() + { + if (!@((new \Redis())->connect(getenv('REDIS_HOST')))) { + $e = error_get_last(); + self::markTestSkipped($e['message']); + } + } + + protected function getRedisConnection() + { + $redis = new \Redis(); + $redis->connect(getenv('REDIS_HOST')); + + return $redis; + } +} diff --git a/vendor/symfony/lock/Tests/Store/RetryTillSaveStoreTest.php b/vendor/symfony/lock/Tests/Store/RetryTillSaveStoreTest.php new file mode 100644 index 00000000..febd48f2 --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/RetryTillSaveStoreTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Store\RedisStore; +use Symfony\Component\Lock\Store\RetryTillSaveStore; + +/** + * @author Jérémy Derussé + */ +class RetryTillSaveStoreTest extends AbstractStoreTest +{ + use BlockingStoreTestTrait; + + public function getStore() + { + $redis = new \Predis\Client('tcp://'.getenv('REDIS_HOST').':6379'); + try { + $redis->connect(); + } catch (\Exception $e) { + self::markTestSkipped($e->getMessage()); + } + + return new RetryTillSaveStore(new RedisStore($redis), 100, 100); + } +} diff --git a/vendor/symfony/lock/Tests/Store/SemaphoreStoreTest.php b/vendor/symfony/lock/Tests/Store/SemaphoreStoreTest.php new file mode 100644 index 00000000..bb37ec1f --- /dev/null +++ b/vendor/symfony/lock/Tests/Store/SemaphoreStoreTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Store; + +use Symfony\Component\Lock\Store\SemaphoreStore; + +/** + * @author Jérémy Derussé + * + * @requires extension sysvsem + */ +class SemaphoreStoreTest extends AbstractStoreTest +{ + use BlockingStoreTestTrait; + + /** + * {@inheritdoc} + */ + protected function getStore() + { + if (\PHP_VERSION_ID < 50601) { + $this->markTestSkipped('Non blocking semaphore are supported by PHP version greater or equals than 5.6.1'); + } + + return new SemaphoreStore(); + } +} diff --git a/vendor/symfony/lock/Tests/Strategy/ConsensusStrategyTest.php b/vendor/symfony/lock/Tests/Strategy/ConsensusStrategyTest.php new file mode 100644 index 00000000..87e83a99 --- /dev/null +++ b/vendor/symfony/lock/Tests/Strategy/ConsensusStrategyTest.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Strategy; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Lock\Strategy\ConsensusStrategy; + +/** + * @author Jérémy Derussé + */ +class ConsensusStrategyTest extends TestCase +{ + /** @var ConsensusStrategy */ + private $strategy; + + public function setup() + { + $this->strategy = new ConsensusStrategy(); + } + + public function provideMetResults() + { + // success, failure, total, isMet + yield array(3, 0, 3, true); + yield array(2, 1, 3, true); + yield array(2, 0, 3, true); + yield array(1, 2, 3, false); + yield array(1, 1, 3, false); + yield array(1, 0, 3, false); + yield array(0, 3, 3, false); + yield array(0, 2, 3, false); + yield array(0, 1, 3, false); + yield array(0, 0, 3, false); + + yield array(2, 0, 2, true); + yield array(1, 1, 2, false); + yield array(1, 0, 2, false); + yield array(0, 2, 2, false); + yield array(0, 1, 2, false); + yield array(0, 0, 2, false); + } + + public function provideIndeterminate() + { + // success, failure, total, canBeMet + yield array(3, 0, 3, true); + yield array(2, 1, 3, true); + yield array(2, 0, 3, true); + yield array(1, 2, 3, false); + yield array(1, 1, 3, true); + yield array(1, 0, 3, true); + yield array(0, 3, 3, false); + yield array(0, 2, 3, false); + yield array(0, 1, 3, true); + yield array(0, 0, 3, true); + + yield array(2, 0, 2, true); + yield array(1, 1, 2, false); + yield array(1, 0, 2, true); + yield array(0, 2, 2, false); + yield array(0, 1, 2, false); + yield array(0, 0, 2, true); + } + + /** + * @dataProvider provideMetResults + */ + public function testMet($success, $failure, $total, $isMet) + { + $this->assertSame($isMet, $this->strategy->isMet($success, $total)); + } + + /** + * @dataProvider provideIndeterminate + */ + public function testCanBeMet($success, $failure, $total, $isMet) + { + $this->assertSame($isMet, $this->strategy->canBeMet($failure, $total)); + } +} diff --git a/vendor/symfony/lock/Tests/Strategy/UnanimousStrategyTest.php b/vendor/symfony/lock/Tests/Strategy/UnanimousStrategyTest.php new file mode 100644 index 00000000..beff54a6 --- /dev/null +++ b/vendor/symfony/lock/Tests/Strategy/UnanimousStrategyTest.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Tests\Strategy; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Lock\Strategy\UnanimousStrategy; + +/** + * @author Jérémy Derussé + */ +class UnanimousStrategyTest extends TestCase +{ + /** @var UnanimousStrategy */ + private $strategy; + + public function setup() + { + $this->strategy = new UnanimousStrategy(); + } + + public function provideMetResults() + { + // success, failure, total, isMet + yield array(3, 0, 3, true); + yield array(2, 1, 3, false); + yield array(2, 0, 3, false); + yield array(1, 2, 3, false); + yield array(1, 1, 3, false); + yield array(1, 0, 3, false); + yield array(0, 3, 3, false); + yield array(0, 2, 3, false); + yield array(0, 1, 3, false); + yield array(0, 0, 3, false); + + yield array(2, 0, 2, true); + yield array(1, 1, 2, false); + yield array(1, 0, 2, false); + yield array(0, 2, 2, false); + yield array(0, 1, 2, false); + yield array(0, 0, 2, false); + } + + public function provideIndeterminate() + { + // success, failure, total, canBeMet + yield array(3, 0, 3, true); + yield array(2, 1, 3, false); + yield array(2, 0, 3, true); + yield array(1, 2, 3, false); + yield array(1, 1, 3, false); + yield array(1, 0, 3, true); + yield array(0, 3, 3, false); + yield array(0, 2, 3, false); + yield array(0, 1, 3, false); + yield array(0, 0, 3, true); + + yield array(2, 0, 2, true); + yield array(1, 1, 2, false); + yield array(1, 0, 2, true); + yield array(0, 2, 2, false); + yield array(0, 1, 2, false); + yield array(0, 0, 2, true); + } + + /** + * @dataProvider provideMetResults + */ + public function testMet($success, $failure, $total, $isMet) + { + $this->assertSame($isMet, $this->strategy->isMet($success, $total)); + } + + /** + * @dataProvider provideIndeterminate + */ + public function testCanBeMet($success, $failure, $total, $isMet) + { + $this->assertSame($isMet, $this->strategy->canBeMet($failure, $total)); + } +} diff --git a/vendor/symfony/lock/composer.json b/vendor/symfony/lock/composer.json new file mode 100644 index 00000000..9a6e7687 --- /dev/null +++ b/vendor/symfony/lock/composer.json @@ -0,0 +1,38 @@ +{ + "name": "symfony/lock", + "type": "library", + "description": "Symfony Lock Component", + "keywords": ["locking", "redlock", "mutex", "semaphore", "flock", "cas"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Jérémy Derussé", + "email": "jeremy@derusse.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-php70": "~1.0", + "psr/log": "~1.0" + }, + "require-dev": { + "predis/predis": "~1.0" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Lock\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + } +} diff --git a/vendor/symfony/lock/phpunit.xml.dist b/vendor/symfony/lock/phpunit.xml.dist new file mode 100644 index 00000000..be3ca215 --- /dev/null +++ b/vendor/symfony/lock/phpunit.xml.dist @@ -0,0 +1,32 @@ + + + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Tests + ./vendor + + + + diff --git a/vendor/symfony/polyfill-php70/LICENSE b/vendor/symfony/polyfill-php70/LICENSE new file mode 100644 index 00000000..24fa32c2 --- /dev/null +++ b/vendor/symfony/polyfill-php70/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-2018 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/polyfill-php70/Php70.php b/vendor/symfony/polyfill-php70/Php70.php new file mode 100644 index 00000000..39e66450 --- /dev/null +++ b/vendor/symfony/polyfill-php70/Php70.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php70; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class Php70 +{ + public static function intdiv($dividend, $divisor) + { + $dividend = self::intArg($dividend, __FUNCTION__, 1); + $divisor = self::intArg($divisor, __FUNCTION__, 2); + + if (0 === $divisor) { + throw new \DivisionByZeroError('Division by zero'); + } + if (-1 === $divisor && ~PHP_INT_MAX === $dividend) { + throw new \ArithmeticError('Division of PHP_INT_MIN by -1 is not an integer'); + } + + return ($dividend - ($dividend % $divisor)) / $divisor; + } + + public static function preg_replace_callback_array(array $patterns, $subject, $limit = -1, &$count = 0) + { + $count = 0; + $result = (string) $subject; + if (0 === $limit = self::intArg($limit, __FUNCTION__, 3)) { + return $result; + } + + foreach ($patterns as $pattern => $callback) { + $result = preg_replace_callback($pattern, $callback, $result, $limit, $c); + $count += $c; + } + + return $result; + } + + public static function error_clear_last() + { + static $handler; + if (!$handler) { + $handler = function() { return false; }; + } + set_error_handler($handler); + @trigger_error(''); + restore_error_handler(); + } + + private static function intArg($value, $caller, $pos) + { + if (\is_int($value)) { + return $value; + } + if (!\is_numeric($value) || PHP_INT_MAX <= ($value += 0) || ~PHP_INT_MAX >= $value) { + throw new \TypeError(sprintf('%s() expects parameter %d to be integer, %s given', $caller, $pos, gettype($value))); + } + + return (int) $value; + } +} diff --git a/vendor/symfony/polyfill-php70/README.md b/vendor/symfony/polyfill-php70/README.md new file mode 100644 index 00000000..04988c6f --- /dev/null +++ b/vendor/symfony/polyfill-php70/README.md @@ -0,0 +1,28 @@ +Symfony Polyfill / Php70 +======================== + +This component provides features unavailable in releases prior to PHP 7.0: + +- [`intdiv`](http://php.net/intdiv) +- [`preg_replace_callback_array`](http://php.net/preg_replace_callback_array) +- [`error_clear_last`](http://php.net/error_clear_last) +- `random_bytes` and `random_int` (from [paragonie/random_compat](https://github.com/paragonie/random_compat)) +- [`*Error` throwable classes](http://php.net/Error) +- [`PHP_INT_MIN`](http://php.net/manual/en/reserved.constants.php#constant.php-int-min) +- `SessionUpdateTimestampHandlerInterface` + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). + +Compatibility notes +=================== + +To write portable code between PHP5 and PHP7, some care must be taken: +- `\*Error` exceptions must be caught before `\Exception`; +- after calling `error_clear_last()`, the result of `$e = error_get_last()` must be + verified using `isset($e['message'][0])` instead of `null !== $e`. + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php b/vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php new file mode 100644 index 00000000..68191244 --- /dev/null +++ b/vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php @@ -0,0 +1,5 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php70 as p; + +if (PHP_VERSION_ID < 70000) { + if (!defined('PHP_INT_MIN')) { + define('PHP_INT_MIN', ~PHP_INT_MAX); + } + if (!function_exists('intdiv')) { + function intdiv($dividend, $divisor) { return p\Php70::intdiv($dividend, $divisor); } + } + if (!function_exists('preg_replace_callback_array')) { + function preg_replace_callback_array(array $patterns, $subject, $limit = -1, &$count = 0) { return p\Php70::preg_replace_callback_array($patterns, $subject, $limit, $count); } + } + if (!function_exists('error_clear_last')) { + function error_clear_last() { return p\Php70::error_clear_last(); } + } +} diff --git a/vendor/symfony/polyfill-php70/composer.json b/vendor/symfony/polyfill-php70/composer.json new file mode 100644 index 00000000..871045d2 --- /dev/null +++ b/vendor/symfony/polyfill-php70/composer.json @@ -0,0 +1,33 @@ +{ + "name": "symfony/polyfill-php70", + "type": "library", + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3", + "paragonie/random_compat": "~1.0|~2.0" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php70\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + } +} From 64e279d8597f9582830fc13dda76b1fd3dea1830 Mon Sep 17 00:00:00 2001 From: hide_d Date: Tue, 8 May 2018 23:39:48 +0900 Subject: [PATCH 026/101] =?UTF-8?q?=EB=B9=99=EC=9D=98=EC=8B=9C=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EA=B0=80=20=EC=9E=98=EB=AA=BB=20=EB=82=A8=EB=8A=94=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/j_select_npc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hwe/j_select_npc.php b/hwe/j_select_npc.php index 4cde200b..ffa83201 100644 --- a/hwe/j_select_npc.php +++ b/hwe/j_select_npc.php @@ -101,8 +101,8 @@ $rootDB->insert('member_log', [ 'action'=>Json::encode([ 'server'=>DB::prefix(), 'type'=>'npc', - 'generalID'=>$npc['no'], - 'generalName'=>$npc['name'] + 'generalID'=>$pickedNPC['no'], + 'generalName'=>$pickedNPC['name'] ]) ]); From 766d0b3ad59ed23c35135ee8c6a73f4e51fa52dd Mon Sep 17 00:00:00 2001 From: hide_d Date: Tue, 8 May 2018 23:40:35 +0900 Subject: [PATCH 027/101] =?UTF-8?q?=EB=B9=99=EC=9D=98=20=ED=83=88=EC=B6=9C?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EC=9E=84=EC=8B=9C=20=EC=A0=9C=ED=95=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/b_myPage.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hwe/b_myPage.php b/hwe/b_myPage.php index 449e5ede..2be84cc8 100644 --- a/hwe/b_myPage.php +++ b/hwe/b_myPage.php @@ -7,7 +7,8 @@ include "func.php"; $btn = Util::getReq('btn'); $mode = Util::getReq('mode', 'int', 2); $tnmt = Util::getReq('tnmt', 'int', 1); -$detachNPC = Util::getReq('detachNPC', 'bool'); +//$detachNPC = Util::getReq('detachNPC', 'bool'); +$detachNPC = false; extractMissingPostToGlobals(); @@ -109,8 +110,8 @@ if (($btn == "설정저장" || $detachNPC) && $me['myset'] > 0) { 휴 가 신 청


- 빙의 해제용 삭턴 조절
- + From beea13ff4b443d30bc66d5dd33c549407dcbc58f Mon Sep 17 00:00:00 2001 From: hide_d Date: Wed, 9 May 2018 01:44:22 +0900 Subject: [PATCH 028/101] =?UTF-8?q?checkSupply()=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EA=B5=AD=EA=B0=80=20select=20=EC=BF=BC=EB=A6=AC=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/func_gamerule.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hwe/func_gamerule.php b/hwe/func_gamerule.php index e3006343..51baa14e 100644 --- a/hwe/func_gamerule.php +++ b/hwe/func_gamerule.php @@ -257,12 +257,15 @@ function checkSupply() { } $queue = new \SplQueue(); - foreach(getAllNationStaticInfo() as $nation){ + foreach($db->query('SELECT capital, nation FROM nation WHERE `level` > 0') as $nation){ $capitalID = $nation['capital']; if(!$capitalID){ continue; } $city = &$cities[$capitalID]; + if($nation['nation'] != $city['nation']){ + continue; + } $city['supply'] = true; $queue->enqueue($city['id']); } From aa46fc9668df0793aece06742b027d978b969cc4 Mon Sep 17 00:00:00 2001 From: hide_d Date: Fri, 11 May 2018 03:16:24 +0900 Subject: [PATCH 029/101] =?UTF-8?q?html5=20=EB=B9=84=ED=98=B8=ED=99=98=20b?= =?UTF-8?q?order=3D1,=20border=3D0=20=EC=A0=9C=EA=B1=B0.=20bar=20=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=EB=A5=BC=20div=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/_119.php | 4 +- hwe/_admin1.php | 10 +- hwe/_admin2.php | 12 +- hwe/_admin4.php | 12 +- hwe/_admin5.php | 14 +- hwe/_admin6.php | 10 +- hwe/_admin7.php | 10 +- hwe/_admin8.php | 10 +- hwe/_simul.php | 6 +- hwe/a_bestGeneral.php | 12 +- hwe/a_emperior.php | 10 +- hwe/a_emperior2.php | 10 +- hwe/a_genList.php | 8 +- hwe/a_hallOfFame.php | 8 +- hwe/a_history.php | 8 +- hwe/a_kingdomList.php | 10 +- hwe/a_npcList.php | 8 +- hwe/a_status.php | 8 +- hwe/a_traffic.php | 228 +++++++++----------------- hwe/a_vote.php | 70 ++++---- hwe/b_auction.php | 10 +- hwe/b_battleCenter.php | 8 +- hwe/b_betting.php | 27 +-- hwe/b_chiefboard.php | 6 +- hwe/b_chiefcenter.php | 8 +- hwe/b_currentCity.php | 14 +- hwe/b_dipcenter.php | 12 +- hwe/b_diplomacy.php | 32 +--- hwe/b_genList.php | 8 +- hwe/b_myBossInfo.php | 14 +- hwe/b_myCityInfo.php | 8 +- hwe/b_myGenInfo.php | 8 +- hwe/b_myKingdomInfo.php | 8 +- hwe/b_myPage.php | 8 +- hwe/b_nationboard.php | 6 +- hwe/b_nationrule.php | 4 +- hwe/b_tournament.php | 25 +-- hwe/b_troop.php | 20 +-- hwe/commandlist.php | 4 +- hwe/css/common.css | 52 ++++++ hwe/css/main.css | 4 + hwe/css/msg.css | 10 +- hwe/func.php | 316 ++++++++++++++++++------------------ hwe/func_legacy.php | 16 +- hwe/index.php | 111 +++++++------ hwe/join.php | 14 +- hwe/processing.php | 10 +- hwe/select_npc.php | 2 +- hwe/templates/msg_plate.php | 53 ------ i_other/help.php | 32 ++-- i_other/screenshot.php | 13 +- tmp_map/map.html | 2 +- tmp_msg/msg.html | 2 +- 53 files changed, 612 insertions(+), 723 deletions(-) delete mode 100644 hwe/templates/msg_plate.php diff --git a/hwe/_119.php b/hwe/_119.php index 9ac164fc..82875fef 100644 --- a/hwe/_119.php +++ b/hwe/_119.php @@ -13,7 +13,7 @@ if($session->userGrade < 4) { 관리메뉴 - + 관리자가 아닙니다.
@@ -41,7 +41,7 @@ $plock = MYDB_fetch_array($result); 삼국지 모의전투 HiDCHe - +
diff --git a/hwe/_admin1.php b/hwe/_admin1.php index 1855a5a4..3adebcba 100644 --- a/hwe/_admin1.php +++ b/hwe/_admin1.php @@ -13,7 +13,7 @@ if($session->userGrade < 5) { 관리메뉴 - + 관리자가 아닙니다.
@@ -37,14 +37,14 @@ $admin = getAdmin(); 게임관리 - + - +
게 임 관 리
- +
@@ -81,7 +81,7 @@ $admin = getAdmin();
운영자메세지 '>
- +
diff --git a/hwe/_admin2.php b/hwe/_admin2.php index ee68de3e..d0f2602b 100644 --- a/hwe/_admin2.php +++ b/hwe/_admin2.php @@ -13,7 +13,7 @@ if($session->userGrade < 5) { 관리메뉴 - + 관리자가 아닙니다.
@@ -39,20 +39,20 @@ $admin = MYDB_fetch_array($result); 회원관리 - + - +
회 원 관 리
- +
접속제한
- +
회원선택

NPC
NPC유저
접속제한
블럭회원
@@ -131,7 +131,7 @@ for($i=0; $i < 27; $i++) {
- +
diff --git a/hwe/_admin4.php b/hwe/_admin4.php index d000476a..8c07ac13 100644 --- a/hwe/_admin4.php +++ b/hwe/_admin4.php @@ -13,7 +13,7 @@ if($session->userGrade < 5) { 관리메뉴 - + 관리자가 아닙니다.
@@ -39,14 +39,14 @@ $admin = MYDB_fetch_array($result); 멀티관리 - + - +
멀 티 관 리
- +
회원선택

NPC
NPC유저
접속제한
블럭회원
@@ -90,7 +90,7 @@ echo "
- +
@@ -137,7 +137,7 @@ echo " //NOTE: password의 md5 해시가 같은지 확인하는 방식으로는 앞으로 잡아낼 수 없다. 폐기 ?> -
장수명 최근로그인
+
diff --git a/hwe/_admin5.php b/hwe/_admin5.php index e460fbc4..7ccaa8c9 100644 --- a/hwe/_admin5.php +++ b/hwe/_admin5.php @@ -26,7 +26,7 @@ if($session->userGrade < 5) { 관리메뉴 - + 관리자가 아닙니다.
@@ -57,10 +57,10 @@ $admin = MYDB_fetch_array($result); 일제정보 - + - +
일 제 정 보
정렬순서 : @@ -115,7 +115,7 @@ for($i=1; $i <= $count; $i++) {
- +
@@ -262,11 +262,11 @@ for($i=0; $i < $nationCount; $i++) { ?>
국명 접률
- +
- +
@@ -317,7 +317,7 @@ for($i=0; $i < $count; $i++) { ?>
- +
diff --git a/hwe/_admin6.php b/hwe/_admin6.php index 8ad66ef1..3a1226f8 100644 --- a/hwe/_admin6.php +++ b/hwe/_admin6.php @@ -20,7 +20,7 @@ if($session->userGrade < 5) { 관리메뉴 - + 관리자가 아닙니다.
@@ -45,10 +45,10 @@ $sel[$type] = "selected"; 접속정보 - + - +
접 속 정 보
정렬순서 :
- +
@@ -100,7 +100,7 @@ for($i=0; $i < $gencount; $i++) { ?>
장수명 접속률
- +
diff --git a/hwe/_admin7.php b/hwe/_admin7.php index 8be7c7ff..f7049853 100644 --- a/hwe/_admin7.php +++ b/hwe/_admin7.php @@ -24,7 +24,7 @@ if($session->userGrade < 5) { 관리메뉴 - + 관리자가 아닙니다.
@@ -52,10 +52,10 @@ $sel[$type] = "selected"; 로그정보 - + - +
로 그 정 보
@@ -99,7 +99,7 @@ for($i=0; $i < $gencount; $i++) {
- +
@@ -136,7 +136,7 @@ for($i=0; $i < $gencount; $i++) {
장 수 정 보 -
- +
diff --git a/hwe/_admin8.php b/hwe/_admin8.php index cff5f832..c9bfcfef 100644 --- a/hwe/_admin8.php +++ b/hwe/_admin8.php @@ -20,7 +20,7 @@ if ($session->userGrade < 5) { 관리메뉴 - + 관리자가 아닙니다.
@@ -48,10 +48,10 @@ $sel[$type] = "selected"; 외교정보 - + - +
외 교 정 보
@@ -63,7 +63,7 @@ $sel[$type] = "selected";
- +
@@ -155,7 +155,7 @@ for ($i=0; $i < $dipcount; $i++) { } ?>
외 교 관 계
국 가 명
- +
diff --git a/hwe/_simul.php b/hwe/_simul.php index fe992f6f..034cf629 100644 --- a/hwe/_simul.php +++ b/hwe/_simul.php @@ -1141,7 +1141,7 @@ switch($dex240) { 전투시뮬레이션 - + - +
트 래 픽 정 보

- +
- +
$value){ - $w = round($refresh[$i] / $game['maxrefresh'] * 100, 1); - if ($w >= 100) { - $w -= 0.1; - } - if ($refresh[$i] < 10 && $w < 3) { - $w = 3; - } elseif ($refresh[$i] < 100 && $w < 6) { - $w = 6; - } elseif ($refresh[$i] < 1000 && $w < 9) { - $w = 9; - } - $w2 = round(100 - $w, 1); +$refresh[] = $game['refresh']; +foreach($refresh as $i=>$value){ + $w = round($value / $game['maxrefresh'] * 100, 1); $color = getTrafficColor($w); $dt = substr($date[$i], 11, 5); ?> - = 100) { - $w -= 0.1; -} -if ($game['refresh'] < 10 && $w < 3) { - $w = 3; -} elseif ($game['refresh'] < 100 && $w < 6) { - $w = 6; -} elseif ($game['refresh'] < 1000 && $w < 9) { - $w = 9; -} -$w2 = round(100 - $w, 1); -$color = getTrafficColor($w); -$dt = date('H:i'); ?> - - - - - - @@ -130,137 +122,71 @@ $dt = date('H:i');
접 속 량
- - - - - -
% bgcolor= align=right> % id=bg0> 
+
+ + + +
+ +
+ +
- - - - - -
% bgcolor= align=right> % id=bg0> 
-
최고기록:
- +
$value){ - $w = round($online[$i] / $game['maxonline'] * 100, 1); - if ($w >= 100) { - $w -= 0.1; - } - if ($online[$i] < 10 && $w < 3) { - $w = 3; - } elseif ($online[$i] < 100 && $w < 6) { - $w = 6; - } elseif ($online[$i] < 1000 && $w < 9) { - $w = 9; - } - $w2 = round(100 - $w, 1); +$online[] = $curonline; +foreach($online as $i=>$value){ + $w = round($value / $game['maxonline'] * 100, 1); $color = getTrafficColor($w); $dt = substr($date[$i], 11, 5); ?> - = 100) { - $w -= 0.1; -} -if ($curonline < 10 && $w < 3) { - $w = 3; -} elseif ($curonline < 100 && $w < 6) { - $w = 6; -} elseif ($curonline < 1000 && $w < 9) { - $w = 9; -} -$w2 = round(100 - $w, 1); -$color = getTrafficColor($w); -$dt = date('H:i'); -echo " - - - - - - +?> - + -"; -?>
접 속 자
- - - - - -
% bgcolor= align=right> % id=bg0> 
+
+ + + +
+ +
+ +
{$game['year']}년 {$game['month']}월{$dt} - - - - - -
{$curonline}  
-
최고기록: {$game['maxonline']}최고기록:

- +
queryFirstRow('SELECT sum(refresh) as refresh, sum(`connect`) as `connect` from general'); +$max_refresh['name'] = '접속자 총합'; -$w = round($maxrefresh / $maxrefresh * 100, 1); -$w2 = round(100 - $w, 1); -$color = getTrafficColor($w); -echo " - - - - - - - - - - -"; +$refresh_result = array_merge([$max_refresh], $db->query('SELECT `name`,refresh,`connect` FROM general ORDER BY refresh DESC LIMIT 5')); -$query = "select name,refresh,connect from general order by refresh desc limit 0,5"; -$result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect), ""); -$count = MYDB_num_rows($result); -for ($i=0; $i < $count; $i++) { - $user = MYDB_fetch_array($result); - - $w = round($user['refresh'] / $maxrefresh * 100, 1); +foreach ($refresh_result as $i=>$user) { + $w = round($user['refresh'] / $max_refresh['refresh'] * 100, 1); $w2 = round(100 - $w, 1); $color = getTrafficColor($w); - echo " +?> - - - + + - "; +
주 의 대 상 자 (순간과도갱신)
주의대상자벌점(순간갱신)전체 대비
접속자 총합{$user['connect']}({$maxrefresh}) - - - - - -
  
-
{$user['name']}{$user['connect']}({$user['refresh']}) - - - - - -
  
+
() + + +
+ +
+

- +
@@ -273,7 +199,7 @@ function getTrafficColor($per) $r = getHex($per); $b = getHex(100 - $per); $color = $r . "00" . $b; - return $color; + return '#'.$color; } function getHex($dec) diff --git a/hwe/a_vote.php b/hwe/a_vote.php index 4b6c08d3..771cdc42 100644 --- a/hwe/a_vote.php +++ b/hwe/a_vote.php @@ -31,7 +31,16 @@ if ($vote[0] == "") { <?=UniqueConst::$serverName?>: 설문조사 - + + - + - +
중 원 정 보

- +

-
align=center bgcolor=blue>외 교 현 황
+
분 쟁 현 황
- +

- +
@@ -244,7 +226,7 @@ for($i=0; $i < $nationcount; $i++) {
중 원 지 도

- +
diff --git a/hwe/b_genList.php b/hwe/b_genList.php index a38ba92d..3dc2f811 100644 --- a/hwe/b_genList.php +++ b/hwe/b_genList.php @@ -56,12 +56,12 @@ $sel[$type] = "selected"; <?=UniqueConst::$serverName?>: 암행부 - + - +
암 행 부
정렬순서 : +
@@ -206,7 +206,7 @@ echo " ?> -
이 름 통무지
+
diff --git a/hwe/b_myBossInfo.php b/hwe/b_myBossInfo.php index 89ecd255..c0b30db2 100644 --- a/hwe/b_myBossInfo.php +++ b/hwe/b_myBossInfo.php @@ -32,7 +32,7 @@ if($meLevel == 0) { <?=UniqueConst::$serverName?>: 인사부 - + - - + + - + @@ -93,50 +115,27 @@ $(function(){
- +
- - - - - - "; -} -?> + + + + + + - - - - + + + + - "; ?> - - - - + + + + userGrade >= 5) { echo " @@ -227,7 +226,7 @@ else if($session->userGrade == 4){ ?>
삼국지 모의전투 HiDCHe ()
{$scenario}NPC수 : {$extend}NPC상성 : {$fiction}NPC선택 : {$npcmode}
>>NPC수 : >NPC상성 : >NPC선택 :
전체 접속자 수 : 턴당 갱신횟수 : 전체 접속자 수 : 턴당 갱신횟수 :
+ 서버 가동중"; @@ -195,10 +194,10 @@ echo "
접속중인 국가:
【 국가방침 】
【 접속자 】
접속중인 국가:
【 국가방침 】
【 접속자 】
- +
- + -
@@ -237,7 +236,7 @@ else if($session->userGrade == 4){
@@ -259,31 +258,31 @@ else if($session->userGrade == 4){
+ ;color:white;width:110px;font-size:13px; value='실 행' onclick='refreshing(this, 3,form2)'>;color:white;width:110px;font-size:13px; value='갱 신' onclick='refreshing(this, 0,0)'>;color:white;width:160px;font-size:13px; value='로비로' onclick=location.replace('../')>
- +
- - + +
- +
- - + + - - + + - - + +
장수 동향개인 기록장수 동향개인 기록
중원 정세
중원 정세
+
장 수 생 성
- +
= $admin['maxgeneral']) { } ?> - +
-
임관 권유 메세지
+
@@ -98,7 +98,7 @@ if ($admin['show_img_level'] >= 1 && $member['grade'] >= 1 && $member['picture']
장수 생성
전콘 사용 여부 - + 사용 @@ -172,7 +172,7 @@ if ($admin['show_img_level'] >= 1 && $member['grade'] >= 1 && $member['picture']
- +
diff --git a/hwe/processing.php b/hwe/processing.php index c2ed4bc1..f085741f 100644 --- a/hwe/processing.php +++ b/hwe/processing.php @@ -145,14 +145,14 @@ $(function(){ - + '; echo ' - +
'.$name.'
'; @@ -279,7 +279,7 @@ function calc(cost, formnum) { form.cost.value = Math.round(crew * cost); } - +
현재 기술력 : @@ -487,7 +487,7 @@ function calc(cost, formnum) { form.cost.value = Math.round(crew * cost * 2); } - +
모병은 가격 2배의 자금이 소요됩니다.
@@ -1031,7 +1031,7 @@ function command_25($turn, $command) { echo " - +
{$scoutStr}
임관 권유 메세지
"; diff --git a/hwe/select_npc.php b/hwe/select_npc.php index 6de57857..8e5a32f2 100644 --- a/hwe/select_npc.php +++ b/hwe/select_npc.php @@ -27,7 +27,7 @@ $nations = $db->queryAllLists('SELECT `name`, scoutmsg, color FROM nation'); - + diff --git a/hwe/templates/msg_plate.php b/hwe/templates/msg_plate.php deleted file mode 100644 index a2272296..00000000 --- a/hwe/templates/msg_plate.php +++ /dev/null @@ -1,53 +0,0 @@ - - - bgcolor="#CC6600" - - bgcolor="#336600" - - bgcolor="#000055" - - style="font-size:13px;table-layout:fixed;word-break:break-all;" - data-id="" -> - - - - -
- - - - - - - - [ - e($src['name'])?>:e($src['nation'])?> - ▶ - e($dest['name'])?>:e($dest['nation'])?> - ] - - [ - e($src['name'])?>:e($src['nation'])?> - ▶ - e($dest['nation'])?> - ] - - [ - e($src['name'])?>:e($src['nation'])?> - ] - - <> -
- e($message)?> -
\ No newline at end of file diff --git a/i_other/help.php b/i_other/help.php index 68ca000e..1245a04a 100644 --- a/i_other/help.php +++ b/i_other/help.php @@ -13,16 +13,10 @@ $category = Util::getReq('category', 'int', 0); 튜토리얼 - + +