<?php
/**
 * Project: Catfish Blog.
 * Author: A.J <804644245@qq.com>
 * Copyright: http://www.catfish-cms.com All rights reserved.
 * Date: 2016/10/1
 */
namespace app\login\controller;

use app\model\Users;
use app\model\Options;
use think\Controller;
use think\Request;
use think\Validate;
use think\Session;
use think\Cookie;
use think\Cache;
use think\Db;
use think\Url;
use think\Lang;
use think\Config;
use think\Hook;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

class Index extends Controller
{
    protected $session_prefix;
    private $lang;
    private $ccc;
    protected $params = [];
    protected $plugins = [];
    public function _initialize()
    {
        $this->session_prefix = 'catfish'.str_replace(['/','.',' ','-'],['','?','*','|'],Url::build('/'));
        $this->lang = Lang::detect();
        $this->lang = $this->filterLanguages($this->lang);
        Lang::load(APP_PATH . 'login/lang/'.$this->lang.'.php');
        $this->ccc = 'Catfish CMS Copyright';
    }
    public function index()
    {
        $captcha = Db::name('options')->where('option_name','captcha')->field('option_value')->find();
        if(Request::instance()->has('user','post'))
        {
            if(Request::instance()->has('captcha','post'))
            {
                $rule = [
                    'user' => 'require',
                    'pwd' => 'require',
                    'captcha|'.Lang::get('Captcha')=>'require|captcha'
                ];
            }
            else
            {
                $rule = [
                    'user' => 'require',
                    'pwd' => 'require'
                ];
            }
            $msg = [
                'user.require' => Lang::get('The user name must be filled in'),
                'pwd.require' => Lang::get('Password must be filled in')
            ];
            if($captcha['option_value'] == 1)
            {
                $data = [
                    'user' => Request::instance()->post('user'),
                    'pwd' => Request::instance()->post('pwd'),
                    'captcha' => Request::instance()->post('captcha')
                ];
            }
            else
            {
                $data = [
                    'user' => Request::instance()->post('user'),
                    'pwd' => Request::instance()->post('pwd')
                ];
            }
            $validate = new Validate($rule, $msg);
            if(!$validate->check($data))
            {
                $this->error($validate->getError());
                return false;
            }
            $users = new Users();
            $user = $users->where('user_login', htmlspecialchars(Request::instance()->post('user')))
                ->find();
            if(empty($user))
            {
                $this->error(Lang::get('Username error'));
                return false;
            }
            if($user['user_pass'] != md5(Request::instance()->post('pwd')))
            {
                $this->error(Lang::get('Password error'));
                return false;
            }
            if($user['user_status'] == 0)
            {
                $this->error(Lang::get('Account has been disabled, please contact the administrator'));
                return false;
            }
            $this->getPlugins();
            $getparam = [
                'user' => Request::instance()->post('user'),
                'pwd' => Request::instance()->post('pwd'),
                'error' => 0,
                'message' => ''
            ];
            Hook::add('login_check',$this->plugins);
            Hook::listen('login_check',$getparam);
            if($getparam['error'] != 0)
            {
                $this->error($getparam['message']);
                return false;
            }
            $ip = get_client_ip(0,true);
            $users->save([
                'last_login_ip' => $ip,
                'last_login_time' => date("Y-m-d H:i:s")
            ],['id' => $user['id']]);
            Session::set($this->session_prefix.'user_id',$user['id']);
            Session::set($this->session_prefix.'user',$user['user_login']);
            Session::set($this->session_prefix.'user_type',$user['user_type']);
            Session::set($this->session_prefix.'up',md5($user['user_login'].$ip));
            if(Request::instance()->post('remember'))
            {
                Cookie::set($this->session_prefix.'user_id',$user['id'],604800);
                Cookie::set($this->session_prefix.'user',$user['user_login'],604800);
                $cookie_user_p = Cache::get('cookie_user_p');
                if($cookie_user_p == false)
                {
                    $cookie_user_p = md5(time());
                    Cache::set('cookie_user_p',$cookie_user_p,604800);
                }
                Cookie::set($this->session_prefix.'user_p',md5($cookie_user_p.$user['user_pass']),604800);
            }
        }
        if(!Session::has($this->session_prefix.'user_id'))
        {
            $this->assign('yanzheng', $captcha['option_value']);
            $this->getPlugins();
            Hook::add('login_background',$this->plugins);
            Hook::listen('login_background',$this->params);
            if(isset($this->params['login_background']))
            {
                $this->assign('login_background', $this->params['login_background']);
            }
            Hook::add('login_annex',$this->plugins);
            Hook::listen('login_annex',$this->params);
            if(isset($this->params['login_annex']))
            {
                $this->assign('login_annex', $this->params['login_annex']);
            }
            $param = '';
            Hook::add('login_annex_post',$this->plugins);
            Hook::listen('login_annex_post',$param);
            $this->url();
            $options_spare = $this->optionsSpare();
            if(isset($options_spare['retpwd']) && $options_spare['retpwd'] == 1)
            {
                $this->assign('retpwd', 1);
            }
            else{
                $this->assign('retpwd', 0);
            }
            $template = $this->options();
            $this->domain();
            if(Request::instance()->isMobile() && is_file(APP_PATH.'../public/'.$template.'/mobile/login.html'))
            {
                $view = $this->fetch(APP_PATH.'../public/'.$template.'/mobile/login.html');
            }
            elseif(is_file(APP_PATH.'../public/'.$template.'/login.html'))
            {
                $view = $this->fetch(APP_PATH.'../public/'.$template.'/login.html');
            }
            else{
                $view = $this->fetch();
            }
            return $view;
        }
        else
        {
            $this->redirect(Url::build('/admin'));
        }
    }
    public function denglu()
    {
        if(Request::instance()->post('user') == '')
        {
            return Lang::get('The user name must be filled in');
        }
        if(Request::instance()->post('pwd') == '')
        {
            return Lang::get('Password must be filled in');
        }
        $users = new Users();
        $user = $users->where('user_login', htmlspecialchars(Request::instance()->post('user')))
            ->find();
        if(empty($user))
        {
            return Lang::get('Username error');
        }
        if($user['user_pass'] != md5(Request::instance()->post('pwd')))
        {
            return Lang::get('Password error');
        }
        if($user['user_status'] == 0)
        {
            return Lang::get('Account has been disabled, please contact the administrator');
        }
        $this->getPlugins();
        $getparam = [
            'user' => Request::instance()->post('user'),
            'pwd' => Request::instance()->post('pwd'),
            'error' => 0,
            'message' => ''
        ];
        Hook::add('login_check',$this->plugins);
        Hook::listen('login_check',$getparam);
        if($getparam['error'] != 0)
        {
            return $getparam['message'];
        }
        $ip = get_client_ip(0,true);
        $users->save([
            'last_login_ip' => $ip,
            'last_login_time' => date("Y-m-d H:i:s")
        ],['id' => $user['id']]);
        Session::set($this->session_prefix.'user_id',$user['id']);
        Session::set($this->session_prefix.'user',$user['user_login']);
        Session::set($this->session_prefix.'user_type',$user['user_type']);
        Session::set($this->session_prefix.'up',md5($user['user_login'].$ip));
        return 'ok';
    }
    public function register()
    {
        $options_spare = $this->optionsSpare();
        if(isset($options_spare['notAllowLogin']) && $options_spare['notAllowLogin'] == 1)
        {
            $this->redirect(Url::build('/index'));
            exit();
        }
        if(Request::instance()->has('user','post'))
        {
            $rule = [
                'user' => 'require|regex:^[A-Za-z][A-Za-z0-9_\-]+$',
                'pwd' => 'require',
                'repeat' => 'require',
                'email' => 'require|email'
            ];
            $msg = [
                'user.require' => Lang::get('The user name must be filled in'),
                'user.regex' => Lang::get('Username can only use letters, numbers and connecting lines, and start with a letter'),
                'pwd.require' => Lang::get('Password must be filled in'),
                'repeat.require' => Lang::get('Confirm password is required'),
                'email.require' => Lang::get('E-mail address is required'),
                'email.email' => Lang::get('The e-mail format is incorrect')
            ];
            $data = [
                'user' => Request::instance()->post('user'),
                'pwd' => Request::instance()->post('pwd'),
                'repeat' => Request::instance()->post('repeat'),
                'email' => Request::instance()->post('email')
            ];
            $validate = new Validate($rule, $msg);
            if(!$validate->check($data))
            {
                $this->error($validate->getError());
                return false;
            }
            if(Request::instance()->post('pwd') != Request::instance()->post('repeat'))
            {
                $this->error(Lang::get('Confirm the password must be the same as the password'));
                return false;
            }
            $guolv = Options::get(['option_name' => 'filter']);
            $jinyg = $guolv->option_value;
            if(!empty($jinyg))
            {
                $jinyg = str_replace('，',',',$jinyg);
                $jinygArr = explode(',', $jinyg);
                foreach($jinygArr as $key => $val)
                {
                    $val = trim($val);
                    if(!empty($val)){
                        if(strpos(Request::instance()->post('user'),$val) !== false)
                        {
                            $this->error(Lang::get('Please use a different username'));
                            return false;
                        }
                    }
                }
            }
            $users = new Users;
            $user = $users->where('user_login', Request::instance()->post('user'))
                ->find();
            if(!empty($user))
            {
                $this->error(Lang::get('User name has been registered'));
                return false;
            }
            $this->getPlugins();
            $getparam = [
                'user' => $data['user'],
                'pwd' => $data['pwd'],
                'repeat' => $data['repeat'],
                'email' => $data['email'],
                'error' => 0,
                'message' => ''
            ];
            Hook::add('register_check',$this->plugins);
            Hook::listen('register_check',$getparam);
            if($getparam['error'] != 0)
            {
                $this->error($getparam['message']);
                return false;
            }
            $users->data([
                'user_login' => htmlspecialchars(Request::instance()->post('user')),
                'user_pass' => md5(Request::instance()->post('pwd')),
                'user_nicename' => htmlspecialchars(Request::instance()->post('user')),
                'user_email' => Request::instance()->post('email'),
                'last_login_ip' => get_client_ip(0,true),
                'create_time' => date("Y-m-d H:i:s"),
                'user_type' => 7
            ]);
            $users->save();
            $this->success(Lang::get('User registration is successful'), Url::build('/login'));
        }
        $template = $this->options();
        $this->getPlugins();
        Hook::add('registration_background',$this->plugins);
        Hook::listen('registration_background',$this->params);
        if(isset($this->params['registration_background']))
        {
            $this->assign('registration_background', $this->params['registration_background']);
        }
        $this->url();
        $this->domain();
        if(Request::instance()->isMobile() && is_file(APP_PATH.'../public/'.$template.'/mobile/register.html'))
        {
            $view = $this->fetch(APP_PATH.'../public/'.$template.'/mobile/register.html');
        }
        elseif(is_file(APP_PATH.'../public/'.$template.'/register.html'))
        {
            $view = $this->fetch(APP_PATH.'../public/'.$template.'/register.html');
        }
        else{
            $view = $this->fetch();
        }
        return $view;
    }
    public function zhuce()
    {
        $options_spare = $this->optionsSpare();
        if(isset($options_spare['notAllowLogin']) && $options_spare['notAllowLogin'] == 1)
        {
            return Lang::get('Registration is not allowed');
        }
        $user = trim(Request::instance()->post('user'));
        $pwd = Request::instance()->post('pwd');
        $repeat = Request::instance()->post('repeat');
        $email = trim(Request::instance()->post('email'));
        if($user == '')
        {
            return Lang::get('The user name must be filled in');
        }
        if(!preg_match('/^[A-Za-z][A-Za-z0-9_\-]+$', $user))
        {
            return Lang::get('Username can only use letters, numbers and connecting lines, and start with a letter');
        }
        if($pwd == '')
        {
            return Lang::get('Password must be filled in');
        }
        if($repeat == '')
        {
            return Lang::get('Confirm password is required');
        }
        if($email == '')
        {
            return Lang::get('Password must be filled in');
        }
        $rule = [
            'email' => 'email'
        ];
        $msg = [
            'email.email' => Lang::get('The e-mail format is incorrect')
        ];
        $data = [
            'email' => $email
        ];
        $validate = new Validate($rule, $msg);
        if(!$validate->check($data))
        {
            return $validate->getError();
        }
        if($pwd != $repeat)
        {
            return Lang::get('Confirm the password must be the same as the password');
        }
        $guolv = Options::get(['option_name' => 'filter']);
        $jinyg = $guolv->option_value;
        if(!empty($jinyg))
        {
            $jinyg = str_replace('，',',',$jinyg);
            $jinygArr = explode(',', $jinyg);
            foreach($jinygArr as $key => $val)
            {
                $val = trim($val);
                if(!empty($val)){
                    if(strpos($user,$val) !== false)
                    {
                        return Lang::get('Please use a different username');
                    }
                }
            }
        }
        $users = new Users;
        $hasuser = $users->where('user_login', $user)
            ->find();
        if(!empty($hasuser))
        {
            return Lang::get('User name has been registered');
        }
        $this->getPlugins();
        $getparam = [
            'user' => $user,
            'pwd' => $pwd,
            'repeat' => $repeat,
            'email' => $email,
            'error' => 0,
            'message' => ''
        ];
        Hook::add('register_check',$this->plugins);
        Hook::listen('register_check',$getparam);
        if($getparam['error'] != 0)
        {
            return $getparam['message'];
        }
        $users->data([
            'user_login' => htmlspecialchars($user),
            'user_pass' => md5($pwd),
            'user_nicename' => htmlspecialchars($user),
            'user_email' => $email,
            'last_login_ip' => get_client_ip(0,true),
            'create_time' => date("Y-m-d H:i:s"),
            'user_type' => 7
        ]);
        $users->save();
        echo 'ok';
        exit();
    }
    public function retpwd()
    {
        if(Request::instance()->has('user','post'))
        {
            $rule = [
                'user' => 'require',
                'email' => 'require|email',
                'captcha|'.Lang::get('Captcha')=>'require|captcha'
            ];
            $msg = [
                'user.require' => Lang::get('The user name must be filled in'),
                'email.require' => Lang::get('E-mail address is required'),
                'email.email' => Lang::get('The e-mail format is incorrect')
            ];
            $data = [
                'user' => Request::instance()->post('user'),
                'email' => Request::instance()->post('email'),
                'captcha' => Request::instance()->post('captcha')
            ];
            $validate = new Validate($rule, $msg);
            if(!$validate->check($data))
            {
                $this->error($validate->getError());
                return false;
            }
            $data['user'] = htmlspecialchars($data['user']);
            $users = new Users();
            $user = $users->where('user_login', $data['user'])->field('id,user_email')
                ->find();
            if(empty($user))
            {
                $this->error(Lang::get('Username error'));
                return false;
            }
            elseif($user['user_email'] != $data['email'])
            {
                $this->error(Lang::get('Email error'));
                return false;
            }
            $newpwd = uniqid();
            $users->where('id', $user['id'])->update([
                'user_pass' => md5($newpwd)
            ]);
            $this->sendmail($data['email'], $data['user'], Lang::get('Retrieve password'), Lang::get('This is your new password, please change your password immediately after login.'). '<br><br>'.Lang::get('Password').': '.$newpwd);
            $this->success(Lang::get('The new password has been sent to your email address'), Url::build('/login'));
        }
        $template = $this->options();
        $this->domain();
        if(Request::instance()->isMobile() && is_file(APP_PATH.'../public/'.$template.'/mobile/retpwd.html'))
        {
            $view = $this->fetch(APP_PATH.'../public/'.$template.'/mobile/retpwd.html');
        }
        elseif(is_file(APP_PATH.'../public/'.$template.'/retpwd.html'))
        {
            $view = $this->fetch(APP_PATH.'../public/'.$template.'/retpwd.html');
        }
        else{
            $view = $this->fetch();
        }
        return $view;
    }
    private function domain()
    {
        $domain = Cache::get('domain');
        if($domain == false)
        {
            $domain = Options::get(['option_name' => 'domain'])->option_value;
            Cache::set('domain',$domain,3600);
        }
        $this->assign('domain', $domain);
    }
    private function filterLanguages($parameter)
    {
        $param = strtolower($parameter);
        if($param == 'zh' || strpos($param,'zh-hans') !== false || strpos($param,'zh-chs') !== false)
        {
            Lang::range('zh-cn');
            return 'zh-cn';
        }
        else if($param == 'zh-tw' || strpos($param,'zh-hant') !== false || strpos($param,'zh-cht') !== false){
            Lang::range('zh-tw');
            return 'zh-tw';
        }
        else if(stripos($param,'zh') === false)
        {
            $paramsub = substr($param,0,2);
            switch($paramsub)
            {
                case 'de':
                    Lang::range('de-de');
                    return 'de-de';
                    break;
                case 'fr':
                    Lang::range('fr-fr');
                    return 'fr-fr';
                    break;
                case 'ja':
                    Lang::range('ja-jp');
                    return 'ja-jp';
                    break;
                case 'ko':
                    Lang::range('ko-kr');
                    return 'ko-kr';
                    break;
                case 'ru':
                    Lang::range('ru-ru');
                    return 'ru-ru';
                    break;
                default:
                    return $param;
            }
        }
        else
        {
            return $param;
        }
    }
    protected function optionsSpare()
    {
        $options_spare = Cache::get('options_spare');
        if($options_spare == false)
        {
            $options_spare = Db::name('options')->where('option_name','spare')->field('option_value')->find();
            $options_spare = $options_spare['option_value'];
            if(!empty($options_spare))
            {
                $options_spare = unserialize($options_spare);
            }
            Cache::set('options_spare',$options_spare,3600);
        }
        return $options_spare;
    }
    private function options()
    {
        $data_options = Cache::get('options');
        if($data_options == false)
        {
            $data_options = Db::name('options')->where('autoload',1)->field('option_name,option_value')->select();
            Cache::set('options',$data_options,3600);
        }
        $yc = '';
        if($this->aut())
        {
            $yc = base64_decode('IHN0eWxlPSJkaXNwbGF5OiBub25lOyI=');
        }
        $version = Config::get('version');
        $this->assign('catfish', '<a href="http://www.'.$version['official'].'/" target="_blank" id="catfish"'.$yc.'>'.$version['name'].' '.$version['description'].'</a>&nbsp;&nbsp;');
        $template = '';
        foreach($data_options as $key => $val)
        {
            if($val['option_name'] == 'copyright' || $val['option_name'] == 'statistics')
            {
                $this->assign($val['option_name'], unserialize($val['option_value']));
            }
            elseif($val['option_name'] == 'template')
            {
                $template = $val['option_value'];
            }
            elseif($val['option_name'] == 'pageSettings')
            {
                ;
            }
            else
            {
                $this->assign($val['option_name'], $val['option_value']);
            }
        }
        return $template;
    }
    private function getPlugins()
    {
        $plugins = Cache::get('plugins');
        if($plugins == false)
        {
            $plugins = Db::name('options')->where('option_name','plugins')->field('option_value')->find();
            if(!empty($plugins))
            {
                $plugins = unserialize($plugins['option_value']);
            }
            else
            {
                $plugins = [];
            }
            Cache::set('plugins',$plugins,3600);
        }
        if(!empty($plugins))
        {
            foreach($plugins as $key => $val)
            {
                $pluginFile = APP_PATH.'plugins/'.$val.'/'.ucfirst($val).'.php';
                if(is_file($pluginFile))
                {
                    $plugins[$key] = 'app\\plugins\\'.$val.'\\'.ucfirst($val);
                    Lang::load(APP_PATH . 'plugins/'.$val.'/lang/'.$this->lang.'.php');
                }
                else
                {
                    unset($plugins[$key]);
                }
            }
            $this->plugins = $plugins;
        }
    }
    private function getb($key)
    {
        $re = Db::name('options')->where('option_name','b_'.$key)->field('option_value')->find();
        if(isset($re['option_value']))
        {
            return $re['option_value'];
        }
        else
        {
            return '';
        }
    }
    private function aut()
    {
        $aut = Cache::get('aut');
        if($aut == false)
        {
            $author = $this->getb('author');
            if(!empty($author))
            {
                $aut = unserialize($author);
            }
            else
            {
                $aut = '';
            }
            Cache::set('aut',$aut,3600);
        }
        if(empty($aut))
        {
            return false;
        }
        else
        {
            if(isset($aut['open']) && isset($aut['veri']) && isset($aut['rm']) && isset($aut['sq']) && isset($aut['ck']))
            {
                if($aut['ck'] == md5($aut['rm'].$aut['sq']))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
    }
    private function url()
    {
        $url = [
            'href' => Url::build('/index'),
            'register' => Url::build('/login/index/register'),
            'login' => Url::build('/login')
        ];
        $this->assign('url', $url);
    }
    private function sendmail($to, $toname, $subject, $body, $altbody = '', $from = '', $fromname = '', $host = '', $port = 25, $user = '', $password = '', $secure = 'tls', $auth = true)
    {
        if(empty($host)){
            $estis = unserialize($this->getb('emailsettings'));
            if($estis == false){
                return false;
            }
            $host = trim($estis['host']);
            $port = intval(trim($estis['port']));
            $user = trim($estis['user']);
            $password = $estis['password'];
            $secure = trim($estis['secure']);
            $auth = (bool)$estis['auth'];
        }
        if(empty($from)){
            $from = $user;
        }
        if(empty($fromname)){
            $fromname = $this->getb('title');
        }
        if(empty($altbody)){
            $altbody = strip_tags($body);
        }
        $mail = new PHPMailer();
        try {
            $mail->CharSet = 'utf-8';
            $mail->isSMTP();
            $mail->Host = $host;
            $mail->SMTPAuth = $auth;
            $mail->Username = $user;
            $mail->Password = $password;
            $mail->SMTPSecure = $secure;
            $mail->Port = $port;
            $mail->setFrom($from, $fromname);
            $mail->addAddress($to, $toname);
            $mail->addReplyTo($from, $fromname);
            $mail->isHTML(true);
            $mail->Subject = $subject;
            $mail->Body = $body;
            $mail->AltBody = $altbody;
            $mail->send();
            return true;
        } catch (Exception $e) {
            return false;
        }
    }
}