<?php
/**
 * Created by PhpStorm.
 * User: zhl
 * Date: 2023/09/02
 * Time: 10:36
 */

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\SyncSubmitTask\SyncSubmitTask;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Validator;
use ZipArchive;

/**
 * Class NoticeController
 * @package App\Http\Controllers\Api
 */
class NoticeController extends Controller
{
    const SUCCESS = 200;
    const ERROR = 400;
    const SERVERERROR = 500;
    const  TYPEVISIT = "visit";
    const TYPEINQUIRY = "inquiry";
    const TRAFFICZERO = 0;
    const TRAFFICONE = 1;
    const DEVICE_PORT_ONE = 1;
    const DEVICE_PORT_TWO = 2;
    protected $header = [];//设置请求头参数

    /**
     * @param array $data
     * @param string $message
     * @param int $status
     * @return string
     */
    protected function success($data = [], $message = 'success', $status = 200)
    {
        $array = compact('status', 'message', 'data');
        return json_encode($array, JSON_UNESCAPED_UNICODE);
    }

    /**
     * @param int $status
     * @param string $message
     * @param array $data
     * @return string
     */
    protected function error($message = 'error', $status = 400, $data = [])
    {
        $array = compact('status', 'message', 'data');
        return json_encode($array, JSON_UNESCAPED_UNICODE);
    }

    /**
     * 响应
     * @param null $msg
     * @param int $code
     * @param array $data
     * @param int $result_code
     * @param string $type
     * @return void
     */
    public function response($msg = null, $code = self::SUCCESS, $data = [], $result_code = 200, $type = 'application/json')
    {
        $result = [
            'msg' => $msg,
            'code' => $code,
            'data' => $data,
        ];
        $this->header['Content-Type'] = $type;
        $response = response($result, $result_code, $this->header);
        throw new HttpResponseException($response);
    }

    /**
     * GET请求
     * @param $url
     * @return mixed
     */
    public function curlGet($url)
    {
        $ch1 = curl_init();
        $timeout = 0;
        curl_setopt($ch1, CURLOPT_URL, $url);
        curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch1, CURLOPT_ENCODING, '');
        curl_setopt($ch1, CURLOPT_MAXREDIRS, 10);
        curl_setopt($ch1, CURLOPT_HTTPHEADER, array());
        curl_setopt($ch1, CURLOPT_CONNECTTIMEOUT, $timeout);
        curl_setopt($ch1, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch1, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch1, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch1, CURLOPT_CUSTOMREQUEST, "GET");
        curl_setopt($ch1, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
        $access_txt = curl_exec($ch1);
        curl_close($ch1);
        return json_decode($access_txt, true);
    }

    /**
     * 发送http post请求
     * @param $url
     * @param $data
     * @param array $header
     * @param bool $is_json
     * @return mixed|string
     */
    function httpPost($url, $data, $header = [], $is_json = true)
    {
        if (empty($header)) {
            $header = array(
                "Accept: application/json",
                "Content-Type:application/json;charset=utf-8",
                "token:" . env("SECRET_TOKEN"),
                "pid:" . env("MERCHANT_NUMBER")
            );
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $res = curl_exec($ch);
        if (curl_errno($ch)) {
            $error_message = curl_error($ch);
            @file_put_contents(storage_path('logs/error.log'), var_export($error_message, true) . PHP_EOL, FILE_APPEND);
        }
        curl_close($ch);
        if ($is_json) {
            return json_decode($res, true);
        }
        return trim($res);
    }

    /**
     * A端上传验证代码
     * @param Request $request
     * @return string
     */
    public function uploadVerifyFile(Request $request)
    {
        $domain = $request->getHost();
        $files = $request->allFiles();
        $file_name = '';
        foreach ($files as $file) {
            $destinationPath = public_path($domain);
            $file->move($destinationPath, $file->getClientOriginalName());
            $filePath = $destinationPath . '/' . $file->getClientOriginalName();
            @file_put_contents(storage_path('logs/upload_file.log'), date('Y-m-d H:i:s') . " " . $filePath . PHP_EOL, FILE_APPEND);
            $file_name = $file->getClientOriginalName();
        }
        if ($file_name) {
            $transmitUrl = env("TRANSMIT_URL");
            $this->httpPost($transmitUrl . "api/selfSiteVerify/", json_encode(['file_name' => $file_name, 'type' => 1]));
        }
        return $this->success();
    }

    /**
     * A端上传amp站验证代码
     * @param Request $request
     * @return string
     */
    public function uploadAmpVerifyFile(Request $request)
    {
        $domain = $request->getHost();

        $domain_array = parse_url($domain);
        $host = $domain_array['host'] ? $domain_array['path'] : "";
        $host_array = explode('.', $host);
        if (count($host_array) <= 2) {
            array_unshift($host_array, 'm');
        } else {
            $host_array[0] = 'm';
        }
        $amp_domain = implode('.', $host_array);

        $files = $request->allFiles();
        $file_name = '';
        foreach ($files as $file) {
            $destinationPath = public_path($amp_domain);
            $file->move($destinationPath, $file->getClientOriginalName());
            $filePath = $destinationPath . '/' . $file->getClientOriginalName();
            @file_put_contents(storage_path('logs/upload_file.log'), date('Y-m-d H:i:s') . " " . $filePath . PHP_EOL, FILE_APPEND);
            $file_name = $file->getClientOriginalName();
        }
        if ($file_name) {
            $transmitUrl = env("TRANSMIT_URL");
            $this->httpPost($transmitUrl . "api/selfSiteVerify/", json_encode(['file_name' => $file_name, 'type' => 2]));
        }
        return $this->success();
    }


    /**
     * 获取需要下载的文件url
     * @param Request $request
     * @return string
     */
    public function websiteHtml(Request $request)
    {
        $domain = $request->getHost();
        $site_token = $request->input('site_token');
        $zip_count = $request->input('zip_count');
        $token = env("SECRET_TOKEN");
        $pid = env("MERCHANT_NUMBER");
        $apiUrl = env("API_URL");

        if (empty($site_token)) {
            return $this->error('请求无效');
        }

        if ($site_token != $token) {
            return $this->error('请求无效');
        }

        $requestUrl = $apiUrl . "api/get_url_verify_token/?pid=" . $pid . "&token=" . $token . "&domain=" . $domain;
        @file_put_contents(storage_path('logs/notify_get_url.log'), date('Y-m-d H:i:s') . "接收到通知:" . $requestUrl . PHP_EOL, FILE_APPEND);

        try {
            $res = $this->curlGet($requestUrl);
            if ($res["status"] != self::SUCCESS) {
                $msg = isset($res["message"]) && !empty($res["message"]) ? $res["message"] : "请求失败!";
                return $this->error($msg);
            }
        } catch (\Exception $e) {
            return $this->error($e->getMessage());
        }

        $info = [
            "domain" => $domain,
            "zip_count" => $zip_count
        ];
        $info = json_encode($info);
        Redis::set('handle_html', $info);
        return $this->success();
    }

    /**
     * 网站html解压
     * @param $zip_count
     * @param $domain
     */
    public function websiteHtmlHandle($zip_count, $domain)
    {
        $api_url = env('API_URL');

        for ($i = 0; $i <= $zip_count; $i++) {
            $targetFile = $this->downLoadFile($api_url . $domain . '_part' . $i . '.zip');
            if ($targetFile == "") {
                $this->output('文件 ' . $targetFile . ' 不存在');
                continue;
            }
            $zip = new ZipArchive();
            if ($zip->open($targetFile) === TRUE) {
                $outputFolder = public_path($domain);
                if (!is_dir($outputFolder)) {
                    mkdir($outputFolder, 0777, true);
                }
                // 解压缩文件,保留原文件结构
                $zip->extractTo($outputFolder);
                $zip->close();
                $this->deleteDirectory($targetFile);
            } else {
                // 处理打开压缩文件失败的情况
                $this->output('解压文件 ' . $targetFile . ' 失败');
                continue;
            }
        }

        $transmitUrl = env("TRANSMIT_URL");
        $this->httpPost($transmitUrl . "api/selfSiteNotify/", json_encode(['domain' => $domain]));
    }

    /**
     * 下载文件(下载到public目录下)
     * @param $url
     * @return string
     */
    public function downLoadFile($url)
    {
        $savePath = public_path();
        if (!file_exists($savePath)) {
            mkdir($savePath, 0777, true);
        }
        $targetFile = $savePath . '/' . basename($url);
        if (!file_exists($targetFile)) {
            $file = fopen($targetFile, 'w');
            fclose($file);
            chmod($targetFile, 0755);
        }

        $remoteFile = fopen($url, 'rb');
        $localFile = fopen($targetFile, 'wb');
        if ($remoteFile && $localFile) {
            while (!feof($remoteFile)) {
                fwrite($localFile, fread($remoteFile, 1024 * 8), 1024 * 8);
            }
            fclose($remoteFile);
            fclose($localFile);
            return $targetFile;
        } else {
            return "";
        }


//        $context = stream_context_create([
//            'http' => [
//                'header' => "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",
//            ],
//        ]);
//        $fileContent = @file_get_contents($url, false, $context);
//        if ($fileContent !== false) {
//            file_put_contents($targetFile, $fileContent);
//            return $targetFile;
//        } else {
//            return "";
//        }
    }


    /**
     * 删除文件
     * @param $path
     * @return bool
     */
    public function deleteDirectory($path)
    {
        if (!is_dir($path)) {
            try {
                unlink($path);
            } catch (\Exception $e) {
                return true;
            }
            return true;
        }
        $files = array_diff(scandir($path), array('.', '..'));
        foreach ($files as $file) {
            $filePath = $path . '/' . $file;
            if (is_dir($filePath)) {
                $this->deleteDirectory($filePath);
            } else {
                try {
                    unlink($filePath);
                } catch (\Exception $e) {
                    return true;
                }
            }
        }
        rmdir($path);
        return true;
    }

    /**
     * 提交
     * @param $request
     * @param string $type
     * @param int $traffic
     * @return string
     */
    public function transmit($request, $type = self::TYPEVISIT, $traffic = self::TRAFFICZERO)
    {
        if ($request->getClientIp() == "127.0.0.1") {
            return $this->success();
        }
        //判断是否是爬虫
        $isReptile = $this->isReptile($request);
        if ($isReptile) {
            return $this->success();
        }

        $data = $request->all();
        if (empty($data)) {
            return $this->success();
        }
        $data["device_port"] = $this->userAgentHandle($request->userAgent(), $data["device_port"] ?? self::DEVICE_PORT_ONE);
        $req["data"] = $data;
        $referrer_url = $data["referrer_url"] ?? $request->header('Referer');
        if ($type == self::TYPEVISIT) {
            $referrer_url = $this->visitInfoHandle($referrer_url);
        }
        $req["referer"] = $referrer_url;
        $req["domain"] = $request->getHost();
        $req["ip"] = $request->getClientIp();
        $req["user_agent"] = $request->userAgent();
        $req["files"] = isset($data["files"]) ? $data["files"] : null;
        $req["type"] = $type;
        $req["traffic"] = $traffic;
        $req["timestamp"] = time();

        //转发接口
        $transmitUrl = env("TRANSMIT_URL");
        $resp = $this->httpPost($transmitUrl . "api/selfSiteApi/", json_encode($req));
        if ($resp["status"] != self::SUCCESS) {
            $dataJson = json_encode($req);
            if (!file_exists(storage_path('logs/fail_req'))) {
                mkdir(storage_path('logs/fail_req', 0777, true));
            }
            @file_put_contents(storage_path('logs/fail_req/' . date('Y-m-d') . '.log'), var_export($dataJson, true) . PHP_EOL, FILE_APPEND);
        }
        return $this->success();
    }

    /**
     * 处理user_agent
     * @param $user_agent
     * @param $device_port
     * @return int
     */
    public function userAgentHandle($user_agent, $device_port)
    {
        if (!in_array($device_port, [self::DEVICE_PORT_ONE, self::DEVICE_PORT_TWO])) {
            $device_port = self::DEVICE_PORT_ONE;
        }
        // 头信息中带有这些信息, 代表是手机端, 重置设备类型
        if (preg_match('/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|wap|windowsce|ucweb/', $user_agent)) {
            $device_port = self::DEVICE_PORT_TWO;
        }
        return $device_port;
    }

    /**
     * 客户访问埋点接口
     * @param Request $request
     * @return string
     */
    public function customerVisit(Request $request)
    {
        return $this->transmit($request);
    }

    /**
     * 埋点信息处理
     * @param $referrerUrl
     * @return string
     */
    public function visitInfoHandle($referrerUrl)
    {
        if (preg_match('/google|facebook|bing|yahoo|youtobe|linkedin|messefrankfurt|yandex|tiktok|twitter|instagram|reddit|telegram|pinterest|tumblr/', $referrerUrl)) {
        } else if ($referrerUrl == null) {
            //直访用户
            $referrerUrl = "";
        } else {
            $referrerUrl = "https://www.google.com/";
        }
        return $referrerUrl;
    }

    /**
     * 是否是爬虫访问
     * @param $request
     * @return bool
     */
    public function isReptile($request)
    {
        $agent = $request->header('User-Agent');
        if (!empty($agent)) {
            $spiderSite = array(
                "TencentTraveler",
                "Baiduspider+",
                "BaiduGame",
                "Googlebot",
                "msnbot",
                "Sosospider+",
                "Sogou web spider",
                "ia_archiver",
                "Yahoo! Slurp",
                "YoudaoBot",
                "Yahoo Slurp",
                "MSNBot",
                "Java (Often spam bot)",
                "BaiDuSpider",
                "Voila",
                "Yandex bot",
                "BSpider",
                "twiceler",
                "Sogou Spider",
                "Speedy Spider",
                "Google AdSense",
                "Heritrix",
                "Python-urllib",
                "Alexa (IA Archiver)",
                "Ask",
                "Exabot",
                "Custo",
                "OutfoxBot/YodaoBot",
                "yacy",
                "SurveyBot",
                "legs",
                "lwp-trivial",
                "Nutch",
                "StackRambler",
                "The web archive (IA Archiver)",
                "Perl tool",
                "MJ12bot",
                "Netcraft",
                "MSIECrawler",
                "WGet tools",
                "larbin",
                "Fish search",
                "yandex.com/bots",
                "google.com/bot",
                "bingbot",
                "YandexMobileBot",
                "BingPreview",
                "AhrefsBot",
                "bot"
            );
            $flag = 0;
            foreach ($spiderSite as $val) {
                $str = strtolower($val);
                if (strpos($agent, $str) !== false) {
                    $flag = 1;
                }
            }
            if ($flag == 1) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 接口
     * @param Request $request
     * @return string
     */
    public function trafficVisit(Request $request)
    {
        return $this->transmit($request, self::TYPEVISIT, self::TRAFFICONE);
    }

    /**
     * C端表单提交 询盘信息
     * @param Request $request
     * @return string
     */
    public function inquiry(Request $request)
    {
        $data = $request->all();
        $black_ips = ['203.86.233.27', '37.19.221.202'];
        if (in_array(request()->getClientIp(), $black_ips)) {
            $this->success();
        }

        //同一ip 5秒内超过5次 限制1小时
        $ip = $request->ip();
        $lock_key = 'lock_ip_' . $ip;
        $rate_key = 'rate_limit:' . $ip;
        if (Cache::has($lock_key)) {
            $this->success();
        }
        if (Cache::has($rate_key)) {
            $count = Cache::get($rate_key);
            if ($count >= 5) {
                Cache::put($lock_key, 1, 3600);
                $this->success();
            }
            Cache::increment($rate_key);
        } else {
            Cache::put($rate_key, 1, 5);
        }

        $data["files"] = $request->allFiles();
        return $this->transmit($request, self::TYPEINQUIRY, self::TRAFFICZERO);
    }

    /**
     * 收集邮箱或者手机号等其他信息
     * @param Request $request
     * @return string
     */
    public function inquiryOtherInfo(Request $request)
    {
        return $this->transmit($request, self::TYPEINQUIRY);
    }

    /**
     * 起点表单询盘
     * @param Request $request
     * @return string
     */
    public function inquiryQd(Request $request)
    {
        return $this->transmit($request, self::TYPEINQUIRY);
    }

    /**
     * 搜索
     * @param Request $request
     * @return mixed|string
     */
    public function search(Request $request)
    {
        $data = $request->all();

        //获取搜索参数
        $data["search_content"] = '';
        if (isset($data['s'])) {
            $req["search_content"] = $data['s'];
        }
        if (isset($data['search'])) {
            $req["search_content"] = $data['search'];
        }

        //分页
        $req["page"] = isset($data['page']) && (int)$data['page'] > 1 ? (int)$data['page'] : 1;
        $req["domain"] = $request->getHost();

        //转发data
        $transmitUrl = env("API_URL");
        $resp = $this->httpPost($transmitUrl . "api/get_search_content/", json_encode($req));
        return $resp["data"]["html"];
    }

    /**
     * 输出处理日志
     * @param $message
     * @return bool
     */
    public function output($message)
    {
        echo date('Y-m-d H:i:s') . ' | ' . $message . PHP_EOL;
        return true;
    }
}