cfmgrv4 init...2

This commit is contained in:
최준흠 2024-10-10 20:23:32 +09:00
parent f44a82b46f
commit 7aae21010a
13 changed files with 286 additions and 175 deletions

View File

@ -68,7 +68,7 @@ abstract class CloudflareController extends AdminController
//Transaction Rollback
$this->getModel()->transRollback();
log_message("error", $e->getMessage());
return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
return redirect()->back()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
}
}
@ -88,7 +88,7 @@ abstract class CloudflareController extends AdminController
//Transaction Rollback
$this->getModel()->transRollback();
log_message("error", $e->getMessage());
return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
return redirect()->back()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
}
}
}

View File

@ -217,7 +217,7 @@ abstract class MVController extends CommonController
//Transaction Rollback
$this->getModel()->transRollback();
log_message("error", $e->getMessage());
return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
return redirect()->back()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
}
}
//단일필드작업
@ -238,7 +238,7 @@ abstract class MVController extends CommonController
//Transaction Rollback
$this->getModel()->transRollback();
log_message("error", $e->getMessage());
return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
return redirect()->back()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
}
}
//삭제
@ -266,7 +266,7 @@ abstract class MVController extends CommonController
//Transaction Rollback
$this->getModel()->transRollback();
log_message("error", $e->getMessage());
return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
return redirect()->back()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage());
}
}
// 리스트
@ -346,7 +346,7 @@ abstract class MVController extends CommonController
log_message("debug", $this->getModel()->getLastQuery());
return $entitys;
}
final protected function list_procedure(): RedirectResponse|string
final protected function list_procedure(): string
{
try {
helper(['form']);
@ -358,17 +358,15 @@ abstract class MVController extends CommonController
$this->pagination = $this->list_pagination_process();
//모델 처리
$this->entitys = $this->list_entitys_process();
// 현재 URL을 스택에 저장
$this->pushCurrentUrl();
return view(
$this->view_path . "index",
['viewDatas' => $this->getViewDatas()]
);
} catch (\Exception $e) {
log_message("error", $e->getMessage());
return redirect()->back()->with('error', $e->getMessage());
return $this->helper->alert($e->getMessage());
}
}
@ -440,7 +438,7 @@ abstract class MVController extends CommonController
return $this->response->download($full_path, null)->setFileName($file_name);
} catch (\Exception $e) {
log_message("error", $e->getMessage());
return redirect()->back()->with('error', $e->getMessage());
return $this->helper->alert($e->getMessage());
}
}
}

View File

@ -5,7 +5,7 @@ namespace App\Controllers;
use App\Helpers\UserHelper;
use App\Libraries\MyAuth\GoogleAuth;
use App\Libraries\MyAuth\LocalAuth;
use App\Libraries\MySocket\GoogleSocket;
use App\Libraries\MySocket\GoogleSocket\API as GoogleSocket;
use App\Models\UserModel;
use CodeIgniter\HTTP\RedirectResponse;
@ -83,8 +83,6 @@ class UserController extends FrontController
$this->init('login');
try {
helper(['form']);
$this->create_form_process();
//구글 로그인 BUTTON용
$google_socket = new GoogleSocket();
$this->google_url = $google_socket->createAuthUrl();
@ -131,8 +129,8 @@ class UserController extends FrontController
if (!$access_code) {
throw new \Exception("구글 로그인 실패");
}
$auth = new GoogleAuth($access_code);
$auth->login($auth->checkUser());
$auth = new GoogleAuth();
$auth->login($auth->checkUser($access_code));
$this->message = "로그인 성공";
$this->getModel()->transCommit();
log_message("notice", __FUNCTION__ . $this->message);

View File

@ -25,8 +25,16 @@ class UserSNSEntity extends CommonEntity
{
return $this->attributes[UserSNSModel::PK];
}
public function getSite(): string
{
return $this->attributes['site'];
}
public function getID(): string
{
return $this->attributes['id'];
}
public function getEmail(): string
{
return $this->attributes['email'];
}
}

View File

@ -27,6 +27,9 @@ class AuthFilter implements FilterInterface
{
// 로그인 않했으면
if (!session()->has(SESSION_NAMES['ISLOGIN'])) {
$urlStack = session()->get('url_stack', []) ?? [];
$urlStack[] = current_url() . ($request->getUri()->getQuery() ? "?" . $request->getUri()->getQuery() : "");;
session()->set('url_stack', $urlStack);
return redirect()->to(URLS['LOGIN'])->with('error', '로그인을하셔야합니다.');
}
//User Role 비교 // 회원 ROLES이 필요ROLE($arguments[0]) 목록에 존재하지 않으면(ACL)

View File

@ -3,72 +3,50 @@
namespace App\Libraries\MyAuth;
use App\Entities\UserEntity;
use App\Libraries\MySocket\GoogleSocket;
use App\Models\UserSNSModel;
use App\Libraries\MySocket\GoogleSocket\CURL;
use App\Libraries\MySocket\GoogleSocket\API as GoogleSocket;
use App\Models\UserModel;
use CodeIgniter\Exceptions\PageNotFoundException;
use Google\Service\Oauth2;
class GoogleAuth extends MyAuth
{
private ?GoogleSocket $_mySocket = null;
private string $_site = "GOOGLE";
private ?UserSNSModel $_model = null;
private string $access_code = "";
public function __construct(string $access_code)
private ?UserModel $_model = null;
private string $_access_code = "";
public function __construct()
{
parent::__construct();
$this->access_code = $access_code;
}
public function getMySocket(): GoogleSocket
{
if ($this->_mySocket === null) {
$this->_mySocket = new GoogleSocket();
$this->_mySocket->setToken($this->access_code);
}
$this->_mySocket->setToken($this->_access_code);
$this->_mySocket->setUserSNSEntity();
return $this->_mySocket;
}
final protected function getModel(): UserSNSModel
final protected function getModel(): UserModel
{
if ($this->_model === null) {
$this->_model = model(UserSNSModel::class);
$this->_model = model(UserModel::class);
}
return $this->_model;
}
public function checkUser(): UserEntity
public function checkUser(string $access_code): UserEntity
{
try {
$this->_access_code = $access_code;
// Google 서비스 설정
$userInfo = $this->getMySocket()->getUserInfo();
//기존 등록된 사용자가 있는지 검사
$this->getModel()->where(UserSNSModel::SITE, $this->_site);
$entity = $this->getModel()->getEntityByID($userInfo['id']);
if ($entity === null) {
//없다면 새로 등록
$formDatas = [
'site' => $this->_site,
'id' => $userInfo['id'],
'name' => $userInfo['name'],
'email' => $userInfo['email'],
'detail' => var_export($userInfo, true),
'status' => 'standby',
];
$entity = $this->getModel()->create($formDatas);
}
//상태가 use(승인완료)가 아니라면
if (
$entity->status !== DEFAULTS['STATUS']
) {
throw new PageNotFoundException("{$this->_site}}의{$userInfo['email']}:{$userInfo['name']}님은 " . $entity->status . "입니다");
}
$userSNS_entity = $this->getMySocket()->getUserSNSEntity();
//local db 사용와의 연결 확인
$userModel = model(UserModel::class);
$user_entity = $userModel->getEntityByID($entity->getID());
$user_entity = $userModel->getEntityByID($userSNS_entity->getID());
if ($user_entity === null) {
throw new PageNotFoundException("{$this->_site}{$userInfo['email']}:{$userInfo['name']}님은 아직 사용자 연결이 이루어지지 않았습니다. ");
throw new PageNotFoundException("{$userSNS_entity->getSite()}{$userSNS_entity->getEmail()}:{$userSNS_entity->getTitle()}님은 아직 사용자 연결이 이루어지지 않았습니다. ");
}
return $user_entity;
} catch (\Google_Service_Exception $e) {

View File

@ -0,0 +1,115 @@
<?php
namespace App\Libraries\MySocket\GoogleSocket;
use App\Entities\UserSNSEntity;
use CodeIgniter\Exceptions\ConfigException;
use CodeIgniter\Exceptions\PageNotFoundException;
use Google\Client;
use Google\Service\Oauth2;
class API extends GoogleSocket
{
public function __construct() {}
public function getClient(): Client
{
if ($this->_client === null) {
$this->_client = new Client();
$this->_client->setClientId(env('socket.google.client.id'));
$this->_client->setClientSecret(env('socket.google.client.key'));
$this->_client->setRedirectUri(base_url(env('socket.google.client.callback_url')));
$this->_client->addScope(Oauth2::USERINFO_EMAIL);
$this->_client->addScope(Oauth2::USERINFO_PROFILE);
// $this->setPrompt('select_account consent');
// $this->setAccessType('offline');
// SSL 검증 비활성화
$this->_client->setHttpClient(new \GuzzleHttp\Client(['verify' => false]));
// 사용자 정의 CA 번들 사용
// $this->setHttpClient(new \GuzzleHttp\Client(['verify' => '/path/to/cacert.pem']));
}
return $this->_client;
}
public function createAuthUrl(): string
{
return $this->getClient()->createAuthUrl();
}
//TokenInfo
// (object) array(
// 'access_token' => 'sdfsdfsdfsdf',
// 'expires_in' => 3599,
// 'refresh_token' => 'sdfsdf',
// 'scope' => 'https://www.googleapis.com/auth/userinfo.profile openid https://www.googleapis.com/auth/userinfo.email',
// 'token_type' => 'Bearer',
// 'id_token' => 'fadfasdfsadf.sdfsdf.sdfsd',
// )
// id_token(.을기준으로 base64_decode):
// DEBUG - 2024-10-10 07:25:01 --> array (
// 'alg' => 'RS256',
// 'kid' => 'a50f6e70ef4bsdfsdffb8f54dce9ee',
// 'typ' => 'JWT',
// )
// DEBUG - 2024-10-10 07:25:01 --> array (
// 'iss' => 'accounts.google.com',
// 'azp' => '105607sdfsdfsdfsdfogleusercontent.com',
// 'aud' => '1056073563687sdfsdfsdftent.com',
// 'sub' => '103667492342341096838',
// 'email' => 'sdfsdfsdf@gmail.com',
// 'email_verified' => true,
// 'at_hash' => 'RKDNDFSrkeZ_LWg',
// 'iat' => 1728df545102,
// 'exp' => 172854df8702,
// )
// DEBUG - 2024-10-10 07:25:01 --> NULL
public function setToken(string $access_code): void
{
// 토큰 정보 가져오기
$tokenInfo = $this->getClient()->fetchAccessTokenWithAuthCode($access_code);
if (isset($tokenInfo['error'])) {
throw new ConfigException($tokenInfo['error']);
}
log_message("debug", var_export($tokenInfo, true));
$this->_access_token = $tokenInfo[$this->_token_name];
// Google Service에 접근하기 위해 Access Token 설정
$this->getClient()->setAccessToken([
'access_token' => $this->_access_token,
'expires_in' => 3600,
'created' => time(),
]);
if ($this->getClient()->isAccessTokenExpired()) {
$this->getClient()->refreshToken($tokenInfo['refresh_token']);
}
// 세션에 Token 값 설정
$this->session->set($this->_token_name, $this->_access_token);
}
public function getUserSNSEntity(): UserSNSEntity
{
$this->getClient()->setAccessToken($this->getToken());
$oauth = new Oauth2($this->getClient());
$userInfo = $oauth->userinfo->get();
log_message("debug", var_export($userInfo, true));
// 사용자정보 설정하기
$this->getModel()->where($this->getModel()::SITE, $this->getSite());
$entity = $this->getModel()->getEntityByID($userInfo['id']);
if ($entity === null) {
//없다면 새로 등록
$formDatas = [
'site' => $this->getSite(),
'id' => $userInfo->id,
'name' => $userInfo->name,
'email' => $userInfo->email,
'detail' => var_export($userInfo, true),
'status' => 'standby',
];
$entity = $this->getModel()->create($formDatas);
}
//상태가 use(승인완료)가 아니라면
if ($entity->status !== DEFAULTS['STATUS']) {
throw new PageNotFoundException("{$entity->getSite()}{$entity->getEmail()}:{$entity->getTitle()}님은 {$entity->status}입니다 ");
}
return $entity;
}
}

View File

@ -1,20 +1,25 @@
<?php
namespace App\Libraries\MySocket;
namespace App\Libraries\MySocket\GoogleSocket;
use CodeIgniter\Config\Services;
use App\Entities\UserSNSEntity;
use App\Libraries\MySocket\MySocket as Client;
use App\Models\UserSNSModel;
use CodeIgniter\Exceptions\PageNotFoundException;
class GoogleSocket extends MySocket
class CURL extends GoogleSocket
{
private $session;
private string $_access_token = "";
private string $_token_name = "access_token";
private string $_token_type = "";
private string $_google_oauth_version = "v3";
public function __construct()
{
parent::__construct();
$this->session = Services::session();
}
public function getClient(): Client
{
if ($this->_client === null) {
$this->_client = new Client();
}
return $this->_client;
}
public function createAuthUrl(): string
@ -31,14 +36,34 @@ class GoogleSocket extends MySocket
return "https://accounts.google.com/o/oauth2/v2/auth?" . $options;
}
//TokenInfo
// (object) array(
// 'access_token' => 'sdfsdfsdfsdf',
// 'expires_in' => 3599,
// 'refresh_token' => 'sdfsdf',
// 'scope' => 'https://www.googleapis.com/auth/userinfo.profile openid https://www.googleapis.com/auth/userinfo.email',
// 'token_type' => 'Bearer',
// 'id_token' => 'fadfasdfsadf',
// 'id_token' => 'fadfasdfsadf.sdfsdf.sdfsd',
// )
// id_token(.을기준으로 base64_decode):
// DEBUG - 2024-10-10 07:25:01 --> array (
// 'alg' => 'RS256',
// 'kid' => 'a50f6e70ef4bsdfsdffb8f54dce9ee',
// 'typ' => 'JWT',
// )
// DEBUG - 2024-10-10 07:25:01 --> array (
// 'iss' => 'accounts.google.com',
// 'azp' => '105607sdfsdfsdfsdfogleusercontent.com',
// 'aud' => '1056073563687sdfsdfsdftent.com',
// 'sub' => '103667492342341096838',
// 'email' => 'sdfsdfsdf@gmail.com',
// 'email_verified' => true,
// 'at_hash' => 'RKDNDFSrkeZ_LWg',
// 'iat' => 1728df545102,
// 'exp' => 172854df8702,
// )
// DEBUG - 2024-10-10 07:25:01 --> NULL
public function setToken(string $access_code): void
{
$options = [
@ -49,10 +74,9 @@ class GoogleSocket extends MySocket
'grant_type' => 'authorization_code',
];
$response = $this->post("https://accounts.google.com/o/oauth2/token", $options);
$tokenInfo = json_decode($response->getBody(), true);
if (isset($tokenInfo['error'])) {
if ($response->getStatusCode() != 200) {
$message = sprintf(
"Google: %s에서 API 호출 실패: \n--request options--\n%s\n--response--\n%s\n",
"Google: %s에서 API 호출 실패: \n--request options--\n%s\n--response--\n%s\n",
__FUNCTION__,
var_export($options, true),
var_export($response, true)
@ -60,7 +84,9 @@ class GoogleSocket extends MySocket
log_message("error", $message);
throw new \Exception($message);
}
if (!isset($tokenInfo[$this->_token_name]) || empty($tokenInfo[$this->_token_name])) {
$tokenInfo = json_decode($response->getBody(), true);
// log_message("debug", var_export($tokenInfo, true));
if (isset($tokenInfo['error']) || !isset($tokenInfo[$this->_token_name]) || empty($tokenInfo[$this->_token_name])) {
$message = sprintf(
"Google: Token 정보가 없습니다.\n--tokenInfo--\n%s\n",
__FUNCTION__,
@ -69,19 +95,18 @@ class GoogleSocket extends MySocket
log_message("error", $message);
throw new \Exception($message);
}
//토큰 Type정보 가져오기 getUserInfo()에서 사용
$this->_token_type = $tokenInfo['token_type'];
//JWT값
// $jwts = explode('.', $tokenInfo['id_token']);
// foreach ($jwts as $jwt) {
// $info = json_decode(base64_decode($jwt), true);
// // log_message("debug", var_export($info, true));
// }
// 토큰 정보 가져오기
$this->_access_token = $tokenInfo[$this->_token_name];
// 세션에 Token 값 설정
$this->session->set($this->_token_name, $this->_access_token);
}
public function getToken(): string
{
return $this->session->get($this->_token_name);
}
// throw new \Exception(__METHOD__ . "에서 데이터 처리 필요");
// DEBUG - 2023-07-13 12:54:51 --> \Google\Service\Oauth2\Userinfo::__set_state(array(
// 'internal_gapi_mappings' =>
@ -110,12 +135,17 @@ class GoogleSocket extends MySocket
// 'picture' => 'https://lh3.googleusercontent.com/a/AAcHTteFSgefsdfsdRJBkJA2tBEmg4PQrvI1Ta_5IXu5=s96-c',
// 'verifiedEmail' => true,
// ))
public function getUserInfo(): array
public function getUserSNSEntity(): UserSNSEntity
{
$options = ["Authorization: {$this->_token_type} {$this->getToken()}"];
$response = $this->get("https://www.googleapis.com/oauth2/{$this->_google_oauth_version}/userinfo", $options);
$userInfo = json_decode($response->getBody(), true);
if (isset($userInfo['error'])) {
$options = [
"headers" => [
"Authorization" => "Bearer {$this->getToken()}",
"Accept" => "application/json",
'User-Agent' => $this->getUserAgent()
],
];
$response = $this->get("https://www.googleapis.com/oauth2/v3/userinfo", $options);
if ($response->getStatusCode() != 200) {
$message = sprintf(
"Google: %s에서 API 호출 실패: \n--request options--\n%s\n--response--\n%s\n",
__FUNCTION__,
@ -125,7 +155,9 @@ class GoogleSocket extends MySocket
log_message("error", $message);
throw new \Exception($message);
}
if (isset($userInfo['email']) || empty($tokenInfo['email'])) {
$userInfo = json_decode($response->getBody(), true);
log_message("debug", var_export($userInfo, true));
if (isset($userInfo['error']) || !isset($userInfo['email']) || empty($userInfo['email'])) {
$message = sprintf(
"Google: User 정보가 없습니다.\n--userInfo--\n%s\n",
__FUNCTION__,
@ -134,7 +166,25 @@ class GoogleSocket extends MySocket
log_message("error", $message);
throw new \Exception($message);
}
// 사용자정보 가져오기
return $userInfo;
// 사용자정보 설정하기
$this->getModel()->where(UserSNSModel::SITE, $this->getSite());
$entity = $this->getModel()->getEntityByID($userInfo['id']);
if ($entity === null) {
//없다면 새로 등록
$formDatas = [
'site' => $this->getSite(),
'id' => $userInfo['id'],
'name' => $userInfo['name'],
'email' => $userInfo['email'],
'detail' => var_export($userInfo, true),
'status' => 'standby',
];
$entity = $this->getModel()->create($formDatas);
}
//상태가 use(승인완료)가 아니라면
if ($entity->status !== DEFAULTS['STATUS']) {
throw new PageNotFoundException("{$entity->getSite()}{$entity->getEmail()}:{$entity->getTitle()}님은 {$entity->status}입니다 ");
}
return $entity;
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Libraries\MySocket\GoogleSocket;
use App\Entities\UserSNSEntity;
use App\Libraries\MySocket\MySocket;
use App\Models\UserSNSModel;
use Config\Services;
abstract class GoogleSocket extends MySocket
{
private string $_site = "GOOGLE";
private ?UserSNSModel $_model = null;
protected $_client = null;
protected $session;
protected string $_access_token = "";
protected string $_token_name = "access_token";
public function __construct()
{
$this->session = Services::session();
}
abstract public function getClient(): mixed;
abstract public function createAuthUrl(): string;
abstract public function setToken(string $access_code): void;
abstract public function getUserSNSEntity(): UserSNSEntity;
final public function getToken(): string
{
return $this->session->get($this->_token_name);
}
final public function getSite(): string
{
return $this->_site;
}
final protected function getModel(): UserSNSModel
{
if ($this->_model === null) {
$this->_model = model(UserSNSModel::class);
}
return $this->_model;
}
}

View File

@ -1,88 +0,0 @@
<?php
namespace App\Libraries\MySocket;
use CodeIgniter\Config\Services;
use CodeIgniter\Exceptions\ConfigException;
use Google\Client;
use Google\Service\Oauth2;
class GoogleSocketAPI extends Client
{
private $session;
private string $_access_token = "";
private string $_token_name = "access_token";
public function __construct()
{
parent::__construct();
$this->setClientId(env('socket.google.client.id'));
$this->setClientSecret(env('socket.google.client.key'));
$this->setRedirectUri(base_url(env('socket.google.client.callback_url')));
$this->addScope(Oauth2::USERINFO_EMAIL);
$this->addScope(Oauth2::USERINFO_PROFILE);
// $this->setPrompt('select_account consent');
// $this->setAccessType('offline');
// SSL 검증 비활성화
$this->setHttpClient(new \GuzzleHttp\Client(['verify' => false]));
// 사용자 정의 CA 번들 사용
// $this->setHttpClient(new \GuzzleHttp\Client(['verify' => '/path/to/cacert.pem']));
$this->session = Services::session();
}
public function setToken(string $access_code): void
{
// 토큰 정보 가져오기
$tokenInfo = $this->fetchAccessTokenWithAuthCode($access_code);
if (isset($tokenInfo['error'])) {
throw new ConfigException($tokenInfo['error']);
}
// dd($tokenInfo);
$this->_access_token = $tokenInfo[$this->_token_name];
// Google Service에 접근하기 위해 Access Token 설정
$this->setAccessToken([
'access_token' => $this->_access_token,
'expires_in' => 3600,
'created' => time(),
]);
// 세션에 Token 값 설정
$this->session->set($this->_token_name, $this->_access_token);
}
public function getToken(): string
{
return $this->session->get($this->_token_name);
}
public function isAccessTokenValid(): bool
{
// 액세스 토큰이 없으면 유효하지 않음
if (empty($this->getAccessToken())) {
return false;
}
// 토큰의 만료 시간 확인
$expirationTime = $this->getTokenExpirationTime();
if ($expirationTime === null) {
return false;
}
// 현재 시간과 비교하여 유효성 확인
return $expirationTime > time();
}
private function getTokenExpirationTime(): ?int
{
// 토큰 정보 디코딩
$tokenParts = explode('.', $this->getToken());
if (count($tokenParts) !== 3) {
return null;
}
$payload = json_decode(base64_decode($tokenParts[1]), true);
if (!isset($payload['exp'])) {
return null;
}
return $payload['exp'];
}
}

View File

@ -6,10 +6,10 @@ use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Client;
abstract class MySocket extends Client
class MySocket extends Client
{
private $_cookieJar = null;
protected function __construct(array $config = [])
public function __construct(array $config = [])
{
// SSL 인증서 검증을 비활성화
$config['verify'] = getenv("socket.web.ssl.verify") == "true" ? true : false;

View File

@ -27,7 +27,16 @@
<b><?= ICONS['LOGIN'] . $viewDatas['session']->get(SESSION_NAMES['AUTH'])['name'] ?></b>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li><?= anchor("/admin/user/modify/" . $viewDatas['session']->get(SESSION_NAMES['AUTH'])['uid'], ICONS['SETUP'] . "정보수정", ["class" => "dropdown-item"]) ?></li>
<li><?= form_label(
ICONS['SETUP'] . "정보수정",
"modify",
[
"class" => "dropdown-item",
"data-src" => "/admin/user/modify/" . $viewDatas['session']->get(SESSION_NAMES['AUTH'])['uid'],
"data-bs-toggle" => "modal",
"data-bs-target" => "#index_action_form"
]
) ?></li>
<li>
<hr class="dropdown-divider">
</li>

View File

@ -263,10 +263,10 @@ case 'http://19hey.com': window.location.href='http://1004eve.com'; break;
case 'http://19hun.com': window.location.href='http://1004eve.com'; break;
case 'http://19hunt.com': window.location.href='https://twitter.com/_19hunter'; break;
case 'http://19hunter.com': window.location.href='https://twitter.com/_19hunter'; break;
case 'http://19hunters.com': window.location.href='https://twitter.com/_19hunter333'; break;
case 'http://19hunts.com': window.location.href='https://twitter.com/_19hunter'; break;
case 'http://19kor.com': window.location.href='https://twitter.com/_19hunter'; break;
case 'http://19mini.com': window.location.href='https://twitter.com/_19hunter'; break;
case 'http://19nomo.com': window.location.href='https://twitter.com/_19hunter'; break;
case 'http://19sns.com': window.location.href='https://twitter.com/_19hunter'; break;
case 'http://19tab.com': window.location.href='https://twitter.com/_19hunter'; break;
case 'http://19wiz.com': window.location.href='https://twitter.com/_19hunter'; break;
@ -1416,6 +1416,7 @@ case 'http://tc-79.com': window.location.href='http://mgmg55.com'; break;
case 'http://te300ny.com': window.location.href='https://sam100kr.com'; break;
case 'http://telm247.com': window.location.href='http://shot88-k77.com'; break;
case 'http://tesdm.com': window.location.href='http://naver.com'; break;
case 'http://test.co.kr': window.location.href='https://test1.co.kr'; break;
case 'http://test1.co.kr': window.location.href='https://ttt.com'; break;
case 'http://test2.co.kr': window.location.href='https://ttt.com'; break;
case 'http://tf-24.com': window.location.href='http://nt-2424.com'; break;
@ -2527,7 +2528,6 @@ case 'https://te300ny.com': window.location.href='https://sam100kr.com'; break;
case 'https://to01mix.com': window.location.href='https://to02mix.com'; break;
case 'https://todal1.com': window.location.href='http://torrentdal1.net'; break;
case 'https://top88ml.com': window.location.href='https://man247y.net'; break;
case 'https://torrentdal.com': window.location.href='http://torrentdal1.net'; break;
case 'https://torrentdal1.com': window.location.href='http://torrentdal1.net'; break;
case 'https://tp2za.com': window.location.href='http://skyt-666.com'; break;
case 'https://tvu7.com': window.location.href='https://pay-111.com'; break;
@ -2618,7 +2618,6 @@ case 'https://www.sm-8282.com': window.location.href='https://www.sm-5252.com';
case 'https://www.ss-sss10.com': window.location.href='https://www.sss-sss100.com'; break;
case 'https://www.to01mix.com': window.location.href='https://www.to02mix.com'; break;
case 'https://www.todal1.com': window.location.href='http://torrentdal1.net'; break;
case 'https://www.torrentdal.com': window.location.href='http://torrentdal1.net'; break;
case 'https://www.torrentdal1.com': window.location.href='http://torrentdal1.net'; break;
case 'https://www.tp2za.com': window.location.href='http://skyt-666.com'; break;
case 'https://www.tvu7.com': window.location.href='https://www.pay-111.com'; break;