AI摘要

在Typecho博客中添加服务器状态栏的详细步骤和代码示例。

功能

  • 实时监控服务器CPU、内存、磁盘使用率
  • 显示服务器运行时间、IO和网络状态
  • 准确获取访客IP、地理位置、设备和浏览器信息
  • 全面支持电信、联通、移动等各类网络环境
  • 兼容Linux系统(CentOS Stream 9、Ubuntu 22.04、Debian 10.2等)
  • 环境是Linux系统,PHP8.0(7.4以上即可),typecho1.2.1

演示环境

我的系统是Ubuntu22.04
Typecho是1.2
PHP是8.0
主题是Handsome主题
别的主题代码段可能不一样

实现步骤

安装必要的系统工具

一定要安装啊,不然到时候没有数据qwq

apt-get update
apt-get install -y procps net-tools sysstat

修改 headnav.php 文件

文件的位置为你的主题/component/headnav.php
在以下代码段位置

<!-- statitic info-->
<?php
if (@Utils::getExpertValue("show_static",true) !== false): ?>
<ul class="nav navbar-nav hidden-sm">

    <!-- 在此追加代码 -->

    <li class="dropdown pos-stc">

添加以下的代码即可

展开查看代码

<!-- 引入Font Awesome图标库 -->
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
        <li class="dropdown pos-stc" id="StateDataPos">
            <a id="StateData" href="#" data-toggle="dropdown" class="dropdown-toggle feathericons dropdown-toggle">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-activity">
                    <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline>
                </svg>
                <span class="caret"></span>
            </a>
            <div class="dropdown-menu wrapper w-full bg-white">
                <div class="row">
                    <div class="col-sm-4 b-l b-light">
                        <div class="m-t-xs m-b-xs font-bold">运行状态</div>
                        <div class="">
                            <span class="pull-right text-danger" id="cpu">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-microchip fa-fw" aria-hidden="true"></i> CPU占用
                                <span class="badge badge-sm bg-dark">8核心</span>
                            </span>
                        </div>
                        <div class="progress progress-xs m-t-sm bg-default">
                            <div id="cpu_css" class="progress-bar bg-danger" data-toggle="tooltip" style="width: 100%"></div>
                        </div>
                        <div class="">
                            <span class="pull-right text-danger" id="memory">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-memory fa-fw" aria-hidden="true"></i> 占用内存
                                <span class="badge badge-sm bg-dark" id="memory_data">
                                    <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                                </span>
                            </span>
                        </div>
                        <div class="progress progress-xs m-t-sm bg-default">
                            <div id="memory_css" class="progress-bar bg-danger" data-toggle="tooltip" style="width: 100%"></div>
                        </div>
                        <div class="">
                            <span class="pull-right text-danger" id="disk">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-hdd fa-fw" aria-hidden="true"></i> 磁盘占用
                                <span class="badge badge-sm bg-dark" id="disk_data">
                                    <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                                </span>
                            </span>
                        </div>
                        <div class="progress progress-xs m-t-sm bg-default">
                            <div id="disk_css" class="progress-bar bg-danger" data-toggle="tooltip" style="width: 100%"></div>
                        </div>
                        <div class="">
                            <span class="pull-right text-danger" id="memCached">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-database fa-fw" aria-hidden="true"></i> 内存缓存
                                <span class="badge badge-sm bg-dark" id="memCached_data">
                                    <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                                </span>
                            </span>
                        </div>
                        <div class="progress progress-xs m-t-sm bg-default">
                            <div id="memCached_css" class="progress-bar bg-danger" data-toggle="tooltip" style="width: 100%"></div>
                        </div>
                        <div class="">
                            <span class="pull-right text-danger" id="memBuffers">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-layer-group fa-fw" aria-hidden="true"></i> 内存缓冲
                                <span class="badge badge-sm bg-dark" id="memBuffers_data">
                                    <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                                </span>
                            </span>
                        </div>
                        <div class="progress progress-xs m-t-sm bg-default">
                            <div id="memBuffers_css" class="progress-bar bg-danger" data-toggle="tooltip" style="width: 100%"></div>
                        </div>
                        <div class="">
                            <span class="pull-right text-danger" id="state_s">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-tachometer-alt fa-fw" aria-hidden="true"></i> 系统负载
                                <span id="state">
                                    <span class="badge badge-sm bg-dark">
                                        <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                                    </span>
                                </span>
                            </span>
                        </div>
                        <div class="progress progress-xs m-t-sm bg-default">
                            <div id="state_css" class="progress-bar bg-danger" data-toggle="tooltip" style="width: 100%"></div>
                        </div>
                        <div class="">
                            <span class="pull-right text-danger" id="cacheHitRate">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-bolt fa-fw" aria-hidden="true"></i> 缓存命中率</span>
                        </div>
                        <div class="progress progress-xs m-t-sm bg-default">
                            <div id="cacheHitRate_css" class="progress-bar bg-info" data-toggle="tooltip" style="width: 0%"></div>
                        </div>
                    </div>
                    <div class="col-sm-4 b-l b-light visible-lg visible-md">
                        <div class="m-t-xs m-b-xs font-bold">网络状态</div>
                        <div class="">
                            <span class="pull-right text-default" id="io">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-exchange-alt fa-fw" aria-hidden="true"></i> IO</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default" id="io1">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-random fa-fw" aria-hidden="true"></i> 实时IO</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default" id="eth">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-globe fa-fw" aria-hidden="true"></i> 网络</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default" id="eth1">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-wifi fa-fw" aria-hidden="true"></i> 实时网络</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default" id="time">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="far fa-clock fa-fw" aria-hidden="true"></i> 服务器时间</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default">
                                <span class="badge badge-sm bg-dark"><?php echo $_SERVER['SERVER_SOFTWARE']; ?></span></span>
                            <span><i class="fas fa-server fa-fw" aria-hidden="true"></i> WEB服务器</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default">
                                <span class="badge badge-sm bg-dark"><?php echo $_SERVER['SERVER_PROTOCOL']; ?></span>
                            </span>
                            <span><i class="fas fa-route fa-fw" aria-hidden="true"></i> 通信协议</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default">
                                <span class="badge badge-sm bg-dark"><?php echo PHP_VERSION; ?></span>
                            </span>
                            <span><i class="fas fa-code fa-fw" aria-hidden="true"></i> PHP版本</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default" id="sys_info_badge">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-cogs fa-fw" aria-hidden="true"></i> 系统信息</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default" id="os_info_badge">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-server fa-fw" aria-hidden="true"></i> 操作系统</span>
                        </div>
                        <br />
                    </div>
                    <div class="col-sm-4 b-l b-light visible-lg visible-md">
                        <div class="m-t-xs m-b-sm font-bold">访客信息</div>
                        <div class="">
                            <span class="pull-right text-default" id="u_time">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-hourglass-half fa-fw" aria-hidden="true"></i> 持续运行</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default" id="ip">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-map-marker-alt fa-fw" aria-hidden="true"></i> 您的IP</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default" id="address">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-location-arrow fa-fw" aria-hidden="true"></i> 网络地址</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default" id="b">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fab fa-chrome fa-fw" aria-hidden="true"></i> 浏览器信息</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default" id="sys">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="fas fa-laptop fa-fw" aria-hidden="true"></i> 您的设备</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default">
                                <span class="badge badge-sm bg-dark"><?php echo $_SERVER['REQUEST_METHOD']; ?></span></span>
                            <span><i class="fas fa-paper-plane fa-fw" aria-hidden="true"></i> 请求方法</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default">
                                <span class="badge badge-sm bg-dark"><?php echo $_SERVER['HTTP_ACCEPT_LANGUAGE']; ?></span></span>
                            <span><i class="fas fa-language fa-fw" aria-hidden="true"></i> 服务语言</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default">
                                <span class="badge badge-sm bg-dark"><?php echo (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ? "HTTPS" : "HTTP"; ?></span>
                            </span>
                            <span><i class="fas fa-lock fa-fw" aria-hidden="true"></i> 连接类型</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default">
                                <span class="badge badge-sm bg-dark"><?php echo $_SERVER['HTTP_HOST']; ?></span>
                            </span>
                            <span><i class="fas fa-globe fa-fw" aria-hidden="true"></i> 当前域名</span>
                        </div>
                        <br />
                        <div class="">
                            <span class="pull-right text-default" id="sys_times">
                                <i class="fas fa-spinner fa-spin" aria-hidden="true"></i>
                            </span>
                            <span><i class="far fa-calendar-alt fa-fw" aria-hidden="true"></i> 您的设备时间</span>
                        </div>
                    </div>
                </div>
            </div>
        </li>

修改 footer.php 文件

文件在你的主题文件/component/footer.php
找到以下代码片段

<?php $this->options->bottomHtml(); ?>

   <!-- 在此追加代码 -->

</body>
</html><!--html end-->

添加以下代码即可

展开查看代码

新建文件

之后返回到你的网站根目录
新建一个名为serverInfo.php的文件
以下是该文件的代码

展开查看代码

<?php

header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');

/**
 * Tries to get file contents, using file_get_contents and falling back to shell_exec('cat').
 * This can help in environments with restrictions like open_basedir.
 * @param string $file The path to the file.
 * @return string|false The file contents or false on failure.
 */
function GetContents($file)
{
    if (!@is_readable($file)) {
        return false;
    }
    $content = @file_get_contents($file);
    if ($content !== false) {
        return $content;
    }
    if (function_exists('shell_exec') && false === strpos(ini_get('disable_functions'), 'shell_exec')) {
        $output = shell_exec('cat ' . escapeshellarg($file));
        if ($output) {
            return $output;
        }
    }
    return false;
}

function size_format($bytes, $decimals = 2)
{
    $size = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
    $factor = floor((strlen($bytes) - 1) / 3);
    return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . $size[$factor];
}

function netSize($bytes)
{
    if ($bytes < 1024) return $bytes . ' B';
    if ($bytes < 1048576) return round($bytes / 1024, 2) . ' KB';
    if ($bytes < 1073741824) return round($bytes / 1048576, 2) . ' MB';
    return round($bytes / 1073741824, 2) . ' GB';
}

/**
 * 获取当前Unix时间戳
 * */
$unixTimestamp = time();
/**
 * 获取服务器总的运行时长
 * */
$serverUptime =  getUpTime();
/**
 * 获取服务器负载 以及CPU使用信息
 * */
$serverLoad = GetLoad();
$cpuUsage = GetCPUInfo();
/**
 * 获取服务器内存信息
 * */
$memoryInfo = GetMem();

// 处理IP信息请求
if (isset($_GET['action']) && $_GET['action'] == 'getip') {
    // 获取用户真实IP地址
    $ip = '';
    // 检查各种可能的代理头部
    $headers = [
        'HTTP_CF_CONNECTING_IP', // Cloudflare
        'HTTP_X_FORWARDED_FOR',  // 通用代理和CDN
        'HTTP_X_REAL_IP',        // Nginx代理
        'HTTP_CLIENT_IP',        // 客户端代理
        'HTTP_X_FORWARDED',      // 通用
        'HTTP_FORWARDED_FOR',    // 通用
        'HTTP_FORWARDED',        // 通用
        'HTTP_X_CLUSTER_CLIENT_IP', // 集群
        'HTTP_TRUE_CLIENT_IP',   // Akamai和Cloudflare
        'HTTP_X_CHAITIN_IP',     // 长亭雷池可能使用的头部
        'REMOTE_ADDR'            // 直接连接
    ];

    // 记录所有可能的IP来源(调试用)
    $debug_headers = [];
    foreach ($headers as $header) {
        if (!empty($_SERVER[$header])) {
            $debug_headers[$header] = $_SERVER[$header];
        }
    }

    // 尝试获取真实IP
    foreach ($headers as $header) {
        if (!empty($_SERVER[$header])) {
            $ip_array = explode(',', $_SERVER[$header]);
            $ip = trim($ip_array[0]); // 第一个IP通常是客户端真实IP
            break;
        }
    }

    // 简单过滤掉非法IP
    $ip = filter_var($ip, FILTER_VALIDATE_IP) ? $ip : '未知';

    // 获取地理位置信息(只对公网IP有效)
    $location = '';
    // 检查是否是内网IP
    if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
        $location = '内网IP: ' . $ip; // 显示具体的内网IP地址
    } else {
        // 方法1:使用太平洋IP库(覆盖较全面,国内外都支持)
        $url = "http://whois.pconline.com.cn/ipJson.jsp?ip={$ip}&json=true";
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 3);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36');
        curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate');
        $response = curl_exec($ch);
        $errno = curl_errno($ch);
        curl_close($ch);

        if ($response && !$errno) {
            // 太平洋的接口返回的是GB2312编码,需要转换
            $response = mb_convert_encoding($response, 'UTF-8', 'GBK');
            $data = json_decode($response, true);
            if ($data && isset($data['pro']) && isset($data['city'])) {
                $region = '';
                if (!empty($data['pro'])) {
                    $region .= $data['pro'];
                }
                if (!empty($data['city']) && $data['city'] != $data['pro']) {
                    $region .= ' ' . $data['city'];
                }
                // 根据IP段判断运营商
                $carrier = judgeCarrier($ip);
                if ($carrier) {
                    $region .= ' ' . $carrier;
                }
                $location = $region ? $region : '未知区域';
            }
        }

        // 方法2:使用IpInfo API(国外IP支持较好)
        if (empty($location)) {
            $url = "https://ipinfo.io/{$ip}/json";
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_TIMEOUT, 3);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36');
            $response = curl_exec($ch);
            curl_close($ch);

            if ($response) {
                $data = json_decode($response, true);
                if ($data && isset($data['region']) && isset($data['city'])) {
                    $region = '';
                    if (!empty($data['country'])) {
                        $region .= getCountryName($data['country']);
                    }
                    if (!empty($data['region'])) {
                        $region .= ' ' . $data['region'];
                    }
                    if (!empty($data['city'])) {
                        $region .= ' ' . $data['city'];
                    }
                    if (!empty($data['org'])) {
                        $region .= ' ' . preg_replace('/^AS\d+\s+/', '', $data['org']);
                    } else {
                        // 补充运营商信息
                        $carrier = judgeCarrier($ip);
                        if ($carrier) {
                            $region .= ' ' . $carrier;
                        }
                    }
                    $location = $region ? $region : '未知区域';
                }
            }
        }

        // 方法3:使用IPIP.net的免费接口(国内移动网络支持较好)
        if (empty($location)) {
            $url = "https://freeapi.ipip.net/{$ip}";
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_TIMEOUT, 3);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36');
            $response = curl_exec($ch);
            curl_close($ch);

            if ($response && $response != '{}') {
                $data = json_decode($response, true);
                if (is_array($data) && count($data) >= 4) {
                    // IPIP.net返回格式:["中国","福建","厦门","","移动"]
                    $region = '';
                    if (!empty($data[1])) {
                        $region .= $data[1]; // 省份
                    }
                    if (!empty($data[2]) && $data[2] != $data[1]) {
                        $region .= ' ' . $data[2]; // 城市
                    }
                    if (!empty($data[4])) {
                        $region .= ' ' . $data[4]; // 运营商
                    } else {
                        // 补充运营商信息
                        $carrier = judgeCarrier($ip);
                        if ($carrier) {
                            $region .= ' ' . $carrier;
                        }
                    }
                    $location = $region ? $region : '未知区域';
                }
            }
        }

        // 方法4:使用淘宝IP库(作为备用)
        if (empty($location)) {
            $url = "https://ip.taobao.com/outGetIpInfo?ip=" . $ip . "&accessKey=alibaba-inc";
            $opts = array(
                'http' => array(
                    'method' => "GET",
                    'timeout' => 3,
                )
            );
            $context = stream_context_create($opts);
            $response = @file_get_contents($url, false, $context);

            if ($response !== false) {
                $data = json_decode($response, true);
                if (isset($data['data']) && $data['data']) {
                    $result = $data['data'];
                    $region = '';
                    if (!empty($result['region'])) {
                        $region .= $result['region'];
                    }
                    if (!empty($result['city']) && $result['city'] != $result['region']) {
                        $region .= ' ' . $result['city'];
                    }
                    if (!empty($result['isp'])) {
                        $region .= ' ' . $result['isp'];
                    } else {
                        // 补充运营商信息
                        $carrier = judgeCarrier($ip);
                        if ($carrier) {
                            $region .= ' ' . $carrier;
                        }
                    }
                    $location = $region ? $region : '未知区域';
                }
            }
        }

        // 方法5:极速数据网络IP库(移动网络特别友好)
        if (empty($location)) {
            $url = "http://ip.jisuapi.com/api/ip/geo?ip={$ip}";
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_TIMEOUT, 3);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            $response = curl_exec($ch);
            curl_close($ch);

            if ($response) {
                $data = json_decode($response, true);
                if (isset($data['result']) && $data['result']) {
                    $result = $data['result'];
                    $region = '';
                    if (!empty($result['province'])) {
                        $region .= $result['province'];
                    }
                    if (!empty($result['city']) && $result['city'] != $result['province']) {
                        $region .= ' ' . $result['city'];
                    }
                    if (!empty($result['isp'])) {
                        $region .= ' ' . $result['isp'];
                    } else {
                        // 补充运营商信息
                        $carrier = judgeCarrier($ip);
                        if ($carrier) {
                            $region .= ' ' . $carrier;
                        }
                    }
                    $location = $region ? $region : '未知区域';
                }
            }
        }

        // 方法6:仅使用IP段进行精准匹配(最后保障)
        if (empty($location)) {
            // 根据IP段匹配位置信息
            $ipLocation = getIpLocation($ip);
            if ($ipLocation) {
                $location = $ipLocation;
            } else {
                // 至少返回运营商信息
                $carrier = judgeCarrier($ip);
                if ($carrier) {
                    $location = $carrier;
                } else {
                    $location = "公网IP";
                }
            }
        }
    }

    // 返回IP信息
    echo json_encode([
        'ip' => $ip,
        'location' => $location,
        'debug' => $debug_headers // 添加调试信息
    ]);
    exit;
}

/**
 * 根据IP地址判断归属运营商
 * @param string $ip IP地址
 * @return string 运营商名称
 */
function judgeCarrier($ip)
{
    // 特殊IP段映射
    $special_ip_carriers = [
        // 移动特殊段
        '39.128.' => '中国移动',
        '39.129.' => '中国移动',
        '39.130.' => '中国移动',
        '39.131.' => '中国移动',
        '39.132.' => '中国移动',
        '39.133.' => '中国移动',
        '39.134.' => '中国移动',
        '39.135.' => '中国移动',
        '39.136.' => '中国移动',
        '39.137.' => '中国移动',
        '39.138.' => '中国移动',
        '39.139.' => '中国移动',
        '39.140.' => '中国移动',
        '39.141.' => '中国移动',
        '39.142.' => '中国移动',
        '39.143.' => '中国移动',
        '39.144.' => '中国移动',
        '39.145.' => '中国移动',
        '39.146.' => '中国移动',
        '39.147.' => '中国移动',
        '39.148.' => '中国移动',
        '39.149.' => '中国移动',
        '39.150.' => '中国移动',
        '39.151.' => '中国移动',
        '39.152.' => '中国移动',
        '39.153.' => '中国移动',
        '39.154.' => '中国移动',
        '39.155.' => '中国移动',
        '39.156.' => '中国移动',
        '39.157.' => '中国移动',
        '39.158.' => '中国移动',
        '39.159.' => '中国移动',
        '39.176.' => '中国移动',
        '40.128.' => '中国移动',
        '40.129.' => '中国移动',
        '40.130.' => '中国移动',
        '41.128.' => '中国移动',
        '42.128.' => '中国移动',
        '43.128.' => '中国移动',

        // 联通特殊段
        '44.128.' => '中国联通',
        '45.128.' => '中国联通',
        '46.128.' => '中国联通',

        // 电信特殊段
        '48.128.' => '中国电信',
        '49.128.' => '中国电信',
        '50.128.' => '中国电信',
        '51.128.' => '中国电信',
    ];

    // 检查特殊IP段映射
    foreach ($special_ip_carriers as $prefix => $carrier) {
        if (strpos($ip, $prefix) === 0) {
            return $carrier;
        }
    }

    // 移动
    $china_mobile = [
        '39',
        '40',
        '41',
        '42',
        '43', // 新的移动段
        '47.0',
        '47.1',
        '47.2',
        '47.3', // 兼容部分联通和移动混用
        '178.',
        '180.',
        '182.',
        '183.',
        '184.',
        '157.',
        '158.',
        '159.',
        '165.',
        '172.',
        '120.204.',
        '120.205.',
        '120.206.',
        '120.207.',
        '120.208.',
        '120.209.',
        '120.210.',
        '120.211.',
        '120.212.',
        '120.213.',
        '120.214.',
        '120.215.',
        '221.130.',
        '221.131.',
        '221.132.',
        '221.133.',
        '221.134.',
        '221.135.',
        '221.136.',
        '221.137.',
        '221.138.',
        '221.139.',
        '211.103.',
        '211.137.',
    ];

    // 联通
    $china_unicom = [
        '44',
        '45',
        '46', // 新的联通段
        '47.4',
        '47.5',
        '47.6',
        '47.7',
        '47.8',
        '47.9', // 兼容部分联通和移动混用
        '130.',
        '131.',
        '132.',
        '155.',
        '156.',
        '186.',
        '145.',
        '146.',
        '166.',
        '175.',
        '171.',
        '175.',
        '176.',
        '185.',
        '186.',
        '166.',
        '120.64.',
        '120.65.',
        '120.66.',
        '120.67.',
        '120.68.',
        '120.69.',
        '120.70.',
        '120.71.',
        '120.72.',
        '120.73.',
        '120.74.',
        '120.75.',
        '120.76.',
        '120.77.',
        '120.78.',
        '120.79.',
        '120.80.',
        '120.81.',
        '121.76.',
        '121.77.',
        '121.78.',
        '121.79.',
        '121.80.',
        '121.81.',
        '218.100.',
        '218.104.',
        '218.108.',
        '211.90.',
        '211.91.',
        '211.92.',
        '211.93.',
        '211.94.',
        '211.95.',
        '211.96.',
        '211.97.',
        '211.98.',
        '211.99.',
        '211.100.',
        '211.101.',
        '211.102.',
    ];

    // 电信
    $china_telecom = [
        '48',
        '49',
        '50',
        '51', // 新的电信段
        '133.',
        '153.',
        '173.',
        '177.',
        '180.',
        '181.',
        '189.',
        '199.',
        '120.128.',
        '120.129.',
        '120.130.',
        '120.131.',
        '120.132.',
        '120.133.',
        '120.134.',
        '120.135.',
        '120.136.',
        '120.137.',
        '120.138.',
        '120.139.',
        '120.140.',
        '120.141.',
        '120.142.',
        '120.143.',
        '120.144.',
        '120.145.',
        '113.64.',
        '113.65.',
        '113.66.',
        '113.67.',
        '113.68.',
        '113.69.',
        '113.70.',
        '113.71.',
        '113.72.',
        '113.73.',
        '113.74.',
        '113.75.',
        '125.64.',
        '125.65.',
        '125.66.',
        '125.67.',
        '125.68.',
        '125.69.',
        '125.70.',
        '125.71.',
        '125.72.',
        '125.73.',
        '125.74.',
        '125.75.',
        '210.5.',
        '210.12.',
        '210.14.',
        '210.21.',
        '210.32.',
        '210.51.',
        '210.52.',
        '210.77.',
        '210.192.',
    ];

    // 铁通/广电/其他
    $china_other = [
        '36',
        '37',
        '38', // 其他杂段
        '1700',
        '1705',
        '1709', // 虚拟运营商
    ];

    // 特定省份IP段
    $province_ip_map = [
        // 河南移动IP段范围
        '39.144.25' => '河南 南阳 中国移动',
        '39.144.26' => '河南 南阳 中国移动',
        '39.144.27' => '河南 南阳 中国移动',

        // 福建电信IP段范围
        '120.32.2' => '福建 厦门 中国电信',
        '120.32.3' => '福建 厦门 中国电信',
        '120.32.4' => '福建 厦门 中国电信',
    ];

    // 检查特定省份IP段映射
    foreach ($province_ip_map as $prefix => $location) {
        if (strpos($ip, $prefix) === 0) {
            return $location;
        }
    }

    foreach ($china_mobile as $prefix) {
        if (strpos($ip, $prefix) === 0) {
            return '中国移动';
        }
    }

    foreach ($china_unicom as $prefix) {
        if (strpos($ip, $prefix) === 0) {
            return '中国联通';
        }
    }

    foreach ($china_telecom as $prefix) {
        if (strpos($ip, $prefix) === 0) {
            return '中国电信';
        }
    }

    foreach ($china_other as $prefix) {
        if (strpos($ip, $prefix) === 0) {
            return '其他运营商';
        }
    }

    return '';
}

/**
 * 根据IP前缀识别地理位置
 * @param string $ip IP地址
 * @return string 地理位置
 */
function getIpLocation($ip)
{
    // 特定地区IP段映射表
    $ip_location_map = [
        // 河南移动
        '39.144.2' => '河南 中国移动',
        '39.144.25' => '河南 南阳 中国移动',
        '39.144.26' => '河南 南阳 中国移动',

        // 福建电信
        '120.32.2' => '福建 厦门 中国电信',
        '120.32.3' => '福建 厦门 中国电信',

        // 北京联通
        '111.200.' => '北京 中国联通',
        '111.201.' => '北京 中国联通',

        // 上海电信
        '180.166.' => '上海 中国电信',
        '180.167.' => '上海 中国电信',

        // 广东移动
        '120.231.' => '广东 中国移动',
        '120.232.' => '广东 中国移动',

        // 浙江电信
        '115.192.' => '浙江 杭州 中国电信',
        '115.193.' => '浙江 杭州 中国电信',
    ];

    // 逐段检查,从最长前缀到最短
    $segments = explode('.', $ip);

    // 检查前三段 (如 192.168.1)
    if (count($segments) >= 3) {
        $prefix3 = $segments[0] . '.' . $segments[1] . '.' . $segments[2];
        if (isset($ip_location_map[$prefix3])) {
            return $ip_location_map[$prefix3];
        }
    }

    // 检查前两段 (如 192.168)
    if (count($segments) >= 2) {
        $prefix2 = $segments[0] . '.' . $segments[1];
        if (isset($ip_location_map[$prefix2])) {
            return $ip_location_map[$prefix2];
        }
    }

    // 检查第一段 (如 192)
    if (count($segments) >= 1) {
        $prefix1 = $segments[0];
        if (isset($ip_location_map[$prefix1])) {
            return $ip_location_map[$prefix1];
        }
    }

    return '';
}

/**
 * 获取国家名称(将ISO代码转为中文名称)
 * @param string $code 国家代码
 * @return string 国家名称
 */
function getCountryName($code)
{
    $countries = [
        'CN' => '中国',
        'US' => '美国',
        'JP' => '日本',
        'KR' => '韩国',
        'GB' => '英国',
        'DE' => '德国',
        'FR' => '法国',
        'RU' => '俄罗斯',
        'CA' => '加拿大',
        'AU' => '澳大利亚',
        'HK' => '香港',
        'TW' => '台湾',
    ];

    return isset($countries[$code]) ? $countries[$code] : $code;
}

/**
 * 获取详细的操作系统信息
 * @return string
 */
function getDetailedOsInfo()
{
    if (stristr(PHP_OS, 'WIN')) {
        return php_uname('s') . ' ' . php_uname('r');
    }
    if (@is_readable('/etc/os-release')) {
        $vars = parse_ini_file('/etc/os-release');
        if (!empty($vars['PRETTY_NAME'])) return $vars['PRETTY_NAME'];
        if (!empty($vars['NAME'])) return $vars['NAME'] . (isset($vars['VERSION']) ? ' ' . $vars['VERSION'] : '');
    }
    return php_uname('s') . ' ' . php_uname('r');
}

// 定义要输出的内容  
$serverInfo = array(
    'serverTime' => date('Y-m-d H:i:s', $unixTimestamp),
    'serverUptime' => array(
        'days' => $serverUptime['days'],
        'hours' => $serverUptime['hours'],
        'mins' => $serverUptime['mins'],
        'secs' => $serverUptime['secs']
    ),
    'serverUtcTime' => date('Y/m/d H:i:s', $unixTimestamp),
    'diskUsage' => array(
        'value' => disk_total_space(__FILE__) - disk_free_space(__FILE__),
        'max' => disk_total_space(__FILE__)
    ),
    'sysInfo' => php_uname('s') . ' ' . php_uname('r'),
    'osInfo' => getDetailedOsInfo(), // This is new
);

$serverStatus = array(
    'sysLoad' => array($serverLoad['1m'], $serverLoad['5m'], $serverLoad['15m']),
    'cpuUsage' => array(
        'user' => $cpuUsage['user'],
        'nice' => $cpuUsage['nice'],
        'sys' => $cpuUsage['sys'],
        'idle' => $cpuUsage['idle']
    ),
    'memRealUsage' => array(
        'value' => $memoryInfo['mRealUsed'],
        'max' => $memoryInfo['mTotal']
    ),
    'memBuffers' => array(
        'value' => $memoryInfo['mBuffers'],
        'max' => $memoryInfo['mTotal']
    ),
    'memCached' => array(
        'value' => $memoryInfo['mCached'],
        'max' => $memoryInfo['mTotal']
    ),
    'swapUsage' => array(
        'value' => $memoryInfo['swapUsed'],
        'max' => $memoryInfo['swapTotal']
    ),
    'swapCached' => array(
        'value' => $memoryInfo['swapCached'],
        'max' => $memoryInfo['swapTotal']
    )
);

$networkStats = array(
    'networks' => GetNetwork()
);
// 将以上内容合并为一个数组  
$output = array(
    'serverInfo' => $serverInfo,
    'serverStatus' => $serverStatus,
    'networkStats' => $networkStats
);

// 将数组转换为JSON字符串并输出  
echo json_encode($output);

/**
 * 获取系统运行时长
 *
 * @return array
 */
function getUpTime()
{
    $uptime_str = GetContents("/proc/uptime");
    if (false === $uptime_str) {
        return array('days' => 0, 'hours' => 0, 'mins' => 0, 'secs' => 0);
    }
    $uptime = (float)$uptime_str;
    $days = floor($uptime / 86400);
    $hours = floor(($uptime % 86400) / 3600);
    $minutes = floor((($uptime % 86400) % 3600) / 60);
    $seconds = floor(($uptime % 3600) % 60);
    return array(
        'days' => $days,
        'hours' => $hours,
        'mins' => $minutes,
        'secs' => $seconds
    );
}

/**
 * 获取系统负载
 *
 * @return array|false|string[]
 */
function GetLoad()
{
    $str = GetContents("/proc/loadavg");
    if (false === $str) {
        return ['1m' => 0, '5m' => 0, '15m' => 0];
    }
    $loads = explode(' ', $str);
    if (count($loads) >= 3) {
        return [
            '1m'  => $loads[0],
            '5m'  => $loads[1],
            '15m' => $loads[2],
        ];
    }
    return ['1m' => 0, '5m' => 0, '15m' => 0];
}

function GetCPUInfo()
{
    $load = sys_getloadavg();
    $user = $load[0];
    $nice = $load[1];
    $sys = $load[2];
    $idle = 100 - ($user + $nice + $sys);
    return [
        'user' => $user,
        'nice' => $nice,
        'sys' => $sys,
        'idle' => $idle,
    ];
}

/**
 * 内存信息
 *
 * @param bool $bFormat 格式化
 *
 * @return array
 */
function GetMem(bool $bFormat = false)
{
    $defaults = [
        'mTotal' => 0,
        'mFree' => 0,
        'mBuffers' => 0,
        'mCached' => 0,
        'mUsed' => 0,
        'mPercent' => 0,
        'mRealUsed' => 0,
        'mRealFree' => 0,
        'mRealPercent' => 0,
        'mCachedPercent' => 0,
        'swapTotal' => 0,
        'swapFree' => 0,
        'swapUsed' => 0,
        'swapPercent' => 0,
        'swapCached' => 0
    ];

    $str = GetContents("/proc/meminfo");
    if (false === $str) {
        return $defaults;
    }

    preg_match_all("/MemTotal\s{0,}\:+\s{0,}([\d\.]+).+?MemFree\s{0,}\:+\s{0,}([\d\.]+).+?Cached\s{0,}\:+\s{0,}([\d\.]+).+?SwapTotal\s{0,}\:+\s{0,}([\d\.]+).+?SwapFree\s{0,}\:+\s{0,}([\d\.]+)/s", $str, $mems);
    preg_match_all("/Buffers\s{0,}\:+\s{0,}([\d\.]+)/s", $str, $buffers);
    preg_match("/SwapCached\s{0,}\:+\s{0,}([\d\.]+)/s", $str, $swap_cached_match);

    if (!isset($mems[1][0], $mems[2][0], $mems[3][0], $mems[4][0], $mems[5][0], $buffers[1][0])) {
        return $defaults;
    }

    $mtotal    = $mems[1][0] * 1024;
    $mfree     = $mems[2][0] * 1024;
    $mbuffers  = $buffers[1][0] * 1024;
    $mcached   = $mems[3][0] * 1024;
    $stotal    = $mems[4][0] * 1024;
    $sfree     = $mems[5][0] * 1024;
    $swap_cached = !empty($swap_cached_match[1]) ? $swap_cached_match[1] * 1024 : 0;

    $mused     = $mtotal - $mfree;
    $sused     = $stotal - $sfree;
    $mrealused = $mtotal - $mfree - $mcached - $mbuffers;

    $rtn['mTotal']         = !$bFormat ? $mtotal : size_format($mtotal, 1);
    $rtn['mFree']          = !$bFormat ? $mfree : size_format($mfree, 1);
    $rtn['mBuffers']       = !$bFormat ? $mbuffers : size_format($mbuffers, 1);
    $rtn['mCached']        = !$bFormat ? $mcached : size_format($mcached, 1);
    $rtn['mUsed']          = !$bFormat ? ($mtotal - $mfree) : size_format($mtotal - $mfree, 1);
    $rtn['mPercent']       = (floatval($mtotal) != 0) ? round($mused / $mtotal * 100, 1) : 0;
    $rtn['mRealUsed']      = !$bFormat ? $mrealused : size_format($mrealused, 1);
    $rtn['mRealFree']      = !$bFormat ? ($mtotal - $mrealused) : size_format($mtotal - $mrealused, 1);
    $rtn['mRealPercent']   = (floatval($mtotal) != 0) ? round($mrealused / $mtotal * 100, 1) : 0;
    $rtn['mCachedPercent'] = (floatval($mcached) != 0) ? round($mcached / $mtotal * 100, 1) : 0;
    $rtn['swapTotal']      = !$bFormat ? $stotal : size_format($stotal, 1);
    $rtn['swapFree']       = !$bFormat ? $sfree : size_format($sfree, 1);
    $rtn['swapUsed']       = !$bFormat ? $sused : size_format($sused, 1);
    $rtn['swapPercent']    = (floatval($stotal) != 0) ? round($sused / $stotal * 100, 1) : 0;
    $rtn['swapCached']     = !$bFormat ? $swap_cached : size_format($swap_cached, 1);
    return $rtn;
}

/**
 * 获取网络数据
 *
 * @param bool $bFormat
 *
 * @return array
 */
function GetNetwork(bool $bFormat = false)
{
    $rtn     = [];
    $netstat = GetContents('/proc/net/dev');
    if (false === $netstat) {
        return [];
    }

    $bufe = preg_split("/\n/", $netstat, -1, PREG_SPLIT_NO_EMPTY);
    foreach ($bufe as $buf) {
        if (preg_match('/:/', $buf)) {
            list($dev_name, $stats_list) = preg_split('/:/', $buf, 2);
            $dev_name = trim($dev_name);

            $stats = preg_split('/\s+/', trim($stats_list));
            if (count($stats) < 10) {
                continue;
            }

            $rtn[$dev_name]['name']       = $dev_name;
            $rtn[$dev_name]['rx']    = !$bFormat ? $stats[0] : netSize($stats[0]);
            $rtn[$dev_name]['in_packets'] = $stats[1];
            $rtn[$dev_name]['in_errors']  = $stats[2];
            $rtn[$dev_name]['in_drop']    = $stats[3];

            $rtn[$dev_name]['tx'] = !$bFormat ? $stats[8] : netSize($stats[8]);
            $rtn[$dev_name]['out_packets'] = $stats[9];
            $rtn[$dev_name]['out_errors']  = $stats[10] ?? 0;
            $rtn[$dev_name]['out_drop']    = $stats[11] ?? 0;
        }
    }

    return $rtn;
}

使用宝塔面板配置说明

若使用宝塔面板环境,请修改网站根目录中的 .user.ini 文件,在 open_basedir 后面追加 :/proc/:
如下代码

open_basedir=/www/wwwroot/blog/:/tmp/:/proc/

如果你不加的话是没有数据的哦

最后修改:2025 年 11 月 23 日
如果觉得我的文章对你有用,请随意赞赏