自制的简易PHP更新公网IP脚本,有需要的自取!

不要问我这个能干嘛,懂的自然懂,不懂得我也懒得解释那么多,存在一定是合理的;

Snipaste_2022-04-21_23-08-53.png

代码分享

<?php

/**
 * 激活后可以跨域调用
 */
function allowCors()
{
    if (isset($_SERVER['HTTP_ORIGIN'])) {
        header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
        header('Access-Control-Allow-Credentials: true');
        header('Access-Control-Max-Age: 86400');
    }

    if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {

        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
            header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
        }

        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
            header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
        }

        exit(0);
    }
}

// 允许跨域
allowCors();

/**
 * 返回数据
 * @param null $code
 * @param null $msg
 * @param null $data
 */
function returnJson($code = null, $msg = null, $data = null)
{
    header("Content-type: application/json");
    $result = ["code" => $code, "msg" => $msg, "data" => $data];
    foreach ($result as $key => $value) {
        if (empty($value)) unset($result[$key]);
    }
    echo json_encode($result,JSON_UNESCAPED_UNICODE);
    exit();
}

// 配置信息
$config = [
    "tokenFile" => "token.key",
    "tokenAlgo" => "sha256",
    "ipFile" => "ip.info",
    "ipFormat" => "Y年m月d日 H:i:s"
];

// 获取参数
$action = $_GET["action"];
$token = $_GET["token"];

// 判断操作
switch ($action) {
    case "install":
        // 如果秘钥文件已存在,则不会继续创建
        if (file_exists($config["tokenFile"])) {
            returnJson(500, "秘钥文件已存在!不可重复安装!");
        }
        // 生成秘钥
        $token = hash($config["tokenAlgo"], md5(microtime(true)));
        // 写秘钥文件
        file_put_contents($config["tokenFile"], $token);
        // 返回秘钥信息
        returnJson(200, "秘钥仅显示一次!请自行保存!", $token);
        break;
    case "update":
        // 检查是否传了令牌
        if (empty($token)) {
            returnJson(401, "更新IP信息需要携带令牌!您尚携带令牌信息!请检查!");
        }
        // 校验令牌是否可用
        if (file_get_contents($config["tokenFile"]) !== $token) {
            returnJson(401, "令牌校验不通过!请检查您的令牌是否与服务器上令牌一致");
        }
        // 组装IP信息
        $ipInfo = [
            "ip" => $_SERVER["REMOTE_ADDR"],
            "update_time" => time(),
            "format_update_time" => date($config["ipFormat"], time()),
        ];
        // 写本地文件
        file_put_contents($config["ipFile"], json_encode($ipInfo));
        // 返回结果
        returnJson("IP地址信息已更新!", $ipInfo);
        break;
    default:
        // 检查IP信息是否存在
        if (!file_exists($config["ipFile"])) returnJson(500, "IP地址信息尚未更新,请稍后再试!");
        // 返回结果
        returnJson(200, "获取IP信息成功", json_decode(file_get_contents($config["ipFile"]), true));
        break;
}

使用方式

  1. 实际操作中请将 https://example.ml 换成你自己的域名!
  2. 接口请求方式一律为 GET

安装

接口参数

  • action - 定值,填 install

示例调用

curl https://example.ml/index.php?action=install

返回内容

{
  "code": 200,
  "msg": "秘钥仅显示一次!请自行保存!",
  "data": "bd17cf2d3f14ae53bcd5c21a24cc5454f0f52d5a9591d2e0275debd8641765e3"
}

更新IP

接口参数

  • action - 定值,填 update
  • token - 填写 安装 中获取到的令牌

示例调用

curl https://example.ml/index.php?action=update&token=bd17cf2d3f14ae53bcd5c21a24cc5454f0f52d5a9591d2e0275debd8641765e3

返回预览

{
  "code": "IP地址信息已更新!",
  "msg": {
    "ip": "60.168.244.239",
    "update_time": 1650553426,
    "format_update_time": "2022年04月21日 23:03:46"
  }
}

获取地址

如需获取地址,则无需传入任何参数,直接访问脚本即可

示例调用

curl https://example.ml/index.php

返回预览

{
  "code": 200,
  "msg": "获取IP信息成功",
  "data": {
    "ip": "60.168.244.239",
    "update_time": 1650553426,
    "format_update_time": "2022年04月21日 23:03:46"
  }
}

附赠前端模板

预览地址见:https://example.ml

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
    <script src="https://unpkg.com/vue-clipboard2@0.3.3/dist/vue-clipboard.min.js"></script>
    <script src="https://unpkg.com/axios@0.26.1/dist/axios.min.js"></script>
    <script src="https://unpkg.com/element-ui@2.15.8/lib/index.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/element-ui@2.15.8/lib/theme-chalk/index.css">
    <style type="text/css">
        html {
            font-size: 15px;
        }

        body {
            margin: 0;
            background: #232526; /* fallback for old browsers */
            background: -webkit-linear-gradient(to top, #414345, #232526); /* Chrome 10-25, Safari 5.1-6 */
            background: linear-gradient(to top, #414345, #232526); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */

        }

        @media screen and (min-width: 768px) {
            html {
                font-size: 20px;
            }
        }

        @media screen and (min-width: 992px) {
            html {
                font-size: 25px;
            }
        }

        @media screen and (min-width: 1200px) {
            html {
                font-size: 40px;
            }
        }

        #app {
            height: 100vh;
            width: 100vw;
            overflow: hidden;
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: column;
            color: #fff;
        }

        h1.title {
            font-size: 2rem;
            margin: 0;
            font-weight: normal;
        }

        button.ip {
            color: #fff;
            font-weight: bolder;
            cursor: pointer;
            outline: none;
            line-height: 1em;
            height: 1em;
            font-size: 3rem;
            background-color: transparent;
            margin: 2rem 0;
            border-width: 0 0 1px 0;
            border-style: solid;
            border-color: transparent;
        }

        button.ip:hover {
            border-color: #ffffff;
        }

        p.info {
            margin: 0;
            font-size: 1rem;
            font-weight: lighter;
        }

        .el-message {
            font-size: 16px;
            min-width: auto;
        }
    </style>
    <title>获取最新公网IP地址</title>
</head>
<body>
<div id="app" v-cloak>
    <h1 class="title">最新公网IP</h1>
    <button class="ip"
            v-clipboard:copy="ajaxReturn.ip"
            v-clipboard:success="handleCopySuccess"
            v-clipboard:error="handleCopyError">{{ ajaxReturn.ip || "-" }}
    </button>
    <p class="info">同步时间:{{ ajaxReturn.format_update_time || "-" }}</p>
</div>

<script>
    const app = new Vue({
        el: "#app",
        data() {
            return {
                ajaxReturn: {}
            }
        },
        created() {
            this.init();
        },
        methods: {
            /**
             * 初始化数据
             * @returns {Promise<void>}
             */
            async init() {
                const loading = this.$loading({
                    lock: true,
                    text: '同步中,请稍后'
                });
                const ajaxReturn = await this.syncIpAddress();
                this.ajaxReturn = ajaxReturn;
                loading.close();
                this.$notify({
                    title: "同步成功",
                    message: "最新IP地址为:" + ajaxReturn.ip,
                    type: "success"
                });
            },
            /**
             * 同步IP地址数据
             * @returns {Promise<unknown>}
             */
            syncIpAddress() {
                return new Promise((resolve, reject) => {
                    axios.get("api.php").then((xhr) => {
                        resolve(xhr.data.data);
                    }).catch(reject)
                })
            },
            /**
             * 复制成功
             */
            handleCopySuccess() {
                this.$notify({
                    title: "复制成功",
                    message: "IP地址已复制!快去使用吧!",
                    type: "success"
                });
            },
            /**
             * 复制失败
             */
            handleCopyError() {
                this.$notify({
                    title: "复制失败",
                    message: "当前浏览器不支持复制!建议更换主流浏览器或手动复制所需内容!",
                    type: "error"
                });
            }
        }
    })
</script>
</body>
</html>