使用PHP对接宝塔面板Web API完整指南

前言

宝塔面板是一款强大的服务器管理软件,提供了丰富的Web API接口供开发者调用。本文将详细介绍如何使用PHP对接宝塔API,并封装成可复用的公共方法。无论您是需要自动化部署、批量管理站点,还是监控服务器状态,这些方法都能大大提高效率。

环境准备

1. 获取宝塔API配置信息

登录宝塔面板 → 面板设置 → API接口,开启API并获取以下信息:

  • API密钥(API Key)

  • API地址(通常为面板地址 + /api)

2. PHP环境要求

  • PHP 7.0及以上

  • 开启cURL扩展

完整的PHP宝塔API封装类

<?php
/**
 * 宝塔面板API接口封装类
 * 作者:技术分享 | 来源:uudwc.com
 * 创建时间:2026年
 * 版本:1.2
 */

class BtApiClient
{
    // API基础配置
    private $bt_url;      // 宝塔面板地址
    private $bt_key;      // API密钥
    private $debug;       // 调试模式
    private $timeout;     // 请求超时时间
    
    /**
     * 构造函数
     * @param string $bt_url  宝塔面板地址
     * @param string $bt_key  API密钥
     * @param bool   $debug   是否开启调试模式
     */
    public function __construct($bt_url, $bt_key, $debug = false)
    {
        $this->bt_url = rtrim($bt_url, '/');
        $this->bt_key = $bt_key;
        $this->debug = $debug;
        $this->timeout = 30;
        
        // 验证参数
        if (empty($this->bt_url) || empty($this->bt_key)) {
            throw new Exception('宝塔API配置参数不能为空');
        }
    }
    
    /**
     * 通用API请求方法
     * @param string $api_path API路径
     * @param array  $data     请求参数
     * @param string $method   请求方法 (GET/POST)
     * @return array
     */
    public function request($api_path, $data = [], $method = 'POST')
    {
        // 准备请求URL
        $url = $this->bt_url . '/' . ltrim($api_path, '/');
        
        // 生成签名
        $request_time = time();
        $request_token = $this->generateToken($request_time);
        
        // 构建请求数据
        $post_data = array_merge($data, [
            'request_token' => $request_token,
            'request_time' => $request_time
        ]);
        
        // 初始化cURL
        $ch = curl_init();
        
        // 设置cURL选项
        $options = [
            CURLOPT_URL            => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HEADER         => false,
            CURLOPT_TIMEOUT        => $this->timeout,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_HTTPHEADER     => [
                'Content-Type: application/x-www-form-urlencoded',
                'User-Agent: BT-API-PHP-Client/1.0'
            ]
        ];
        
        // 根据请求方法设置参数
        if (strtoupper($method) === 'POST') {
            $options[CURLOPT_POST] = true;
            $options[CURLOPT_POSTFIELDS] = http_build_query($post_data);
        } else {
            // GET请求将参数附加到URL
            $url .= '?' . http_build_query($post_data);
            $options[CURLOPT_URL] = $url;
        }
        
        curl_setopt_array($ch, $options);
        
        // 执行请求
        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        
        curl_close($ch);
        
        // 调试信息
        if ($this->debug) {
            $this->logDebug([
                'url' => $url,
                'method' => $method,
                'request_data' => $post_data,
                'response' => $response,
                'http_code' => $http_code,
                'error' => $error
            ]);
        }
        
        // 处理错误
        if ($error) {
            return $this->formatResponse(false, "cURL请求失败: {$error}");
        }
        
        // 解析响应
        $result = json_decode($response, true);
        
        if (json_last_error() !== JSON_ERROR_NONE) {
            return $this->formatResponse(false, "JSON解析失败: " . json_last_error_msg());
        }
        
        // 检查HTTP状态码
        if ($http_code !== 200) {
            return $this->formatResponse(false, "HTTP请求失败,状态码: {$http_code}");
        }
        
        return $this->formatResponse(true, "请求成功", $result);
    }
    
    /**
     * 生成请求令牌
     * @param int $request_time 请求时间戳
     * @return string
     */
    private function generateToken($request_time)
    {
        // 宝塔API签名算法
        $md5_key = md5($request_time . $this->bt_key);
        $token = md5(substr($md5_key, 0, 8) . $request_time);
        
        return $token;
    }
    
    /**
     * 格式化响应数据
     * @param bool   $status  状态
     * @param string $message 消息
     * @param mixed  $data    数据
     * @return array
     */
    private function formatResponse($status, $message, $data = null)
    {
        return [
            'status'  => $status,
            'message' => $message,
            'data'    => $data,
            'timestamp' => time()
        ];
    }
    
    /**
     * 记录调试信息
     * @param array $data 调试数据
     */
    private function logDebug($data)
    {
        $log_file = dirname(__FILE__) . '/bt_api_debug.log';
        $log_content = "[" . date('Y-m-d H:i:s') . "] " . print_r($data, true) . "\n";
        file_put_contents($log_file, $log_content, FILE_APPEND);
    }
    
    /**
     * 设置超时时间
     * @param int $seconds 秒数
     */
    public function setTimeout($seconds)
    {
        $this->timeout = (int)$seconds;
    }
    
    // ==================== 常用API封装方法 ====================
    
    /**
     * 获取系统状态
     * @return array
     */
    public function getSystemStatus()
    {
        return $this->request('system?action=GetSystemTotal', [], 'GET');
    }
    
    /**
     * 获取网站列表
     * @param int $page     页码
     * @param int $page_size 每页数量
     * @return array
     */
    public function getWebsites($page = 1, $page_size = 100)
    {
        $data = [
            'p' => $page,
            'limit' => $page_size,
            'type' => -1,
            'order' => 'id desc'
        ];
        return $this->request('data?action=getData', $data);
    }
    
    /**
     * 创建网站
     * @param array $site_info 网站信息
     * @return array
     */
    public function createWebsite($site_info)
    {
        $required_fields = ['webname', 'path', 'type_id', 'port', 'ps'];
        
        foreach ($required_fields as $field) {
            if (!isset($site_info[$field])) {
                return $this->formatResponse(false, "缺少必要参数: {$field}");
            }
        }
        
        return $this->request('site?action=AddSite', $site_info);
    }
    
    /**
     * 删除网站
     * @param int    $id     网站ID
     * @param string $webname 网站名称
     * @return array
     */
    public function deleteWebsite($id, $webname)
    {
        $data = [
            'id' => $id,
            'webname' => $webname
        ];
        return $this->request('site?action=DeleteSite', $data);
    }
    
    /**
     * 获取SSL证书信息
     * @param string $site_name 网站名称
     * @return array
     */
    public function getSSLInfo($site_name)
    {
        $data = ['siteName' => $site_name];
        return $this->request('site?action=GetSiteSSL', $data);
    }
    
    /**
     * 设置SSL证书
     * @param string $site_name 网站名称
     * @param string $key       私钥内容
     * @param string $cert      证书内容
     * @return array
     */
    public function setSSL($site_name, $key, $cert)
    {
        $data = [
            'siteName' => $site_name,
            'key' => $key,
            'csr' => $cert
        ];
        return $this->request('site?action=SetSSL', $data);
    }
    
    /**
     * 获取防火墙状态
     * @return array
     */
    public function getFirewallStatus()
    {
        return $this->request('firewall?action=GetFirewallStatus', [], 'GET');
    }
    
    /**
     * 添加防火墙规则
     * @param string $port     端口
     * @param string $protocol 协议 (tcp/udp)
     * @param string $ps       备注
     * @return array
     */
    public function addFirewallRule($port, $protocol = 'tcp', $ps = '')
    {
        $data = [
            'port' => $port,
            'protocol' => $protocol,
            'ps' => $ps ?: "API添加 - " . date('Y-m-d H:i:s')
        ];
        return $this->request('firewall?action=AddFirewallRule', $data);
    }
    
    /**
     * 获取数据库列表
     * @param int $page     页码
     * @param int $page_size 每页数量
     * @return array
     */
    public function getDatabases($page = 1, $page_size = 100)
    {
        $data = [
            'p' => $page,
            'limit' => $page_size
        ];
        return $this->request('database?action=getData', $data);
    }
    
    /**
     * 创建数据库
     * @param string $name     数据库名
     * @param string $user     用户名
     * @param string $password 密码
     * @param string $ps       备注
     * @return array
     */
    public function createDatabase($name, $user, $password, $ps = '')
    {
        $data = [
            'name' => $name,
            'db_user' => $user,
            'password' => $password,
            'dtype' => 'mysql',
            'dataAccess' => '127.0.0.1',
            'address' => '%',
            'ps' => $ps ?: "API创建 - " . date('Y-m-d H:i:s')
        ];
        return $this->request('database?action=AddDatabase', $data);
    }
}

使用示例

基础使用方法

<?php
/**
 * 宝塔API使用示例
 * 更多示例请参考:https://www.uudwc.com/bt-api-examples
 */

// 引入类文件
require_once 'BtApiClient.php';

// 初始化客户端
try {
    // 替换为您的宝塔面板地址和API密钥
    $bt_url = 'https://your-bt-panel.com';
    $bt_key = 'your_api_key_here';
    
    $bt_client = new BtApiClient($bt_url, $bt_key, true); // 开启调试模式
    
    // 示例1:获取系统状态
    echo "=== 获取系统状态 ===\n";
    $system_status = $bt_client->getSystemStatus();
    if ($system_status['status']) {
        echo "系统负载: " . $system_status['data']['load'] . "\n";
        echo "内存使用: " . $system_status['data']['mem'] . "\n";
        echo "磁盘使用: " . $system_status['data']['disk'] . "\n";
    } else {
        echo "获取失败: " . $system_status['message'] . "\n";
    }
    
    // 示例2:获取网站列表
    echo "\n=== 获取网站列表 ===\n";
    $websites = $bt_client->getWebsites(1, 10);
    if ($websites['status']) {
        foreach ($websites['data']['data'] as $site) {
            echo "网站ID: {$site['id']}, 名称: {$site['name']}, 域名: {$site['domain']}\n";
        }
    }
    
    // 示例3:创建网站
    echo "\n=== 创建网站示例 ===\n";
    $site_info = [
        'webname' => 'test_site',
        'path' => '/www/wwwroot/test_site',
        'type_id' => 0,
        'port' => 80,
        'ps' => '测试网站 - API创建',
        'ftp' => false,
        'sql' => false
    ];
    // $result = $bt_client->createWebsite($site_info);
    // print_r($result);
    
    // 示例4:设置SSL证书
    echo "\n=== SSL证书管理 ===\n";
    $ssl_info = $bt_client->getSSLInfo('your_domain.com');
    print_r($ssl_info);
    
} catch (Exception $e) {
    echo "初始化失败: " . $e->getMessage() . "\n";
}

实战应用:批量创建网站

<?php
/**
 * 批量创建网站示例
 * 适用于批量部署环境
 */

require_once 'BtApiClient.php';

class BatchSiteManager
{
    private $bt_client;
    
    public function __construct($bt_url, $bt_key)
    {
        $this->bt_client = new BtApiClient($bt_url, $bt_key);
    }
    
    /**
     * 从CSV文件批量创建网站
     * @param string $csv_file CSV文件路径
     * @return array 创建结果
     */
    public function batchCreateFromCsv($csv_file)
    {
        if (!file_exists($csv_file)) {
            return ['status' => false, 'message' => 'CSV文件不存在'];
        }
        
        $results = [];
        $handle = fopen($csv_file, 'r');
        
        // 跳过标题行
        fgetc($handle);
        
        while (($data = fgetcsv($handle)) !== false) {
            $site_name = $data[0];
            $domain = $data[1];
            $path = $data[2];
            
            $site_info = [
                'webname' => "{$site_name}|{$domain}",
                'path' => "/www/wwwroot/{$path}",
                'type_id' => 0,
                'port' => 80,
                'ps' => "批量创建 - {$site_name}",
                'ftp' => false,
                'sql' => false
            ];
            
            $result = $this->bt_client->createWebsite($site_info);
            
            $results[] = [
                'site_name' => $site_name,
                'status' => $result['status'],
                'message' => $result['message']
            ];
            
            // 避免请求过于频繁
            sleep(1);
        }
        
        fclose($handle);
        
        return [
            'status' => true,
            'message' => '批量创建完成',
            'data' => $results
        ];
    }
}

// 使用示例
$manager = new BatchSiteManager('https://your-bt-panel.com', 'your_api_key');
$result = $manager->batchCreateFromCsv('sites.csv');
print_r($result);

错误处理与优化建议

1. 错误处理策略

<?php
/**
 * 增强的错误处理示例
 */

class BtApiEnhanced extends BtApiClient
{
    private $retry_count = 3;
    private $retry_delay = 2; // 秒
    
    /**
     * 带重试机制的请求
     */
    public function requestWithRetry($api_path, $data = [], $method = 'POST')
    {
        $attempt = 0;
        
        while ($attempt < $this->retry_count) {
            $result = parent::request($api_path, $data, $method);
            
            if ($result['status']) {
                return $result;
            }
            
            // 如果是网络错误,重试
            if (strpos($result['message'], 'cURL请求失败') !== false) {
                $attempt++;
                sleep($this->retry_delay);
                continue;
            }
            
            // 其他错误直接返回
            return $result;
        }
        
        return $this->formatResponse(false, "请求失败,已达到最大重试次数");
    }
    
    /**
     * 验证API连接
     */
    public function validateConnection()
    {
        $test_result = $this->requestWithRetry('system?action=GetSystemTotal', [], 'GET');
        
        if (!$test_result['status']) {
            // 记录到监控系统
            $this->sendAlert("宝塔API连接失败: " . $test_result['message']);
        }
        
        return $test_result;
    }
    
    /**
     * 发送告警(示例)
     */
    private function sendAlert($message)
    {
        // 这里可以集成到您的监控系统
        error_log("宝塔API告警: " . $message);
        
        // 或者发送邮件/钉钉通知
        // mail('admin@example.com', '宝塔API异常', $message);
    }
}

2. 安全建议

<?php
/**
 * 安全增强的API客户端
 */

class SecureBtApiClient extends BtApiClient
{
    /**
     * 安全地存储和获取API密钥
     */
    public static function getSecureConfig()
    {
        // 建议从环境变量或加密存储中读取配置
        $config_file = dirname(__FILE__) . '/config/bt_api_config.enc';
        
        if (file_exists($config_file)) {
            // 解密配置(示例)
            $encrypted = file_get_contents($config_file);
            $config = json_decode($this->decrypt($encrypted), true);
            
            return [
                'url' => $config['url'],
                'key' => $config['key']
            ];
        }
        
        return null;
    }
    
    /**
     * 简单的加密示例(实际项目请使用更安全的加密方式)
     */
    private function decrypt($data)
    {
        // 这里使用简单的base64解码,实际项目请使用openssl等
        return base64_decode($data);
    }
    
    /**
     * 验证请求参数
     */
    private function validateRequestParams($api_path, $data)
    {
        // 检查API路径是否在白名单中
        $allowed_apis = [
            'system?action=GetSystemTotal',
            'data?action=getData',
            'site?action=AddSite'
            // ... 其他允许的API
        ];
        
        if (!in_array($api_path, $allowed_apis)) {
            throw new Exception("未授权的API访问: {$api_path}");
        }
        
        // 检查数据大小
        if (strlen(json_encode($data)) > 1024 * 1024) { // 1MB限制
            throw new Exception("请求数据过大");
        }
        
        return true;
    }
}

最佳实践

1. 配置文件管理

创建 config/bt_api_config.php

<?php
// 宝塔API配置文件
// 注意:不要将此文件提交到版本控制系统

return [
    // 开发环境
    'development' => [
        'url' => 'https://dev-bt.example.com',
        'key' => 'dev_api_key_here',
        'timeout' => 30
    ],
    
    // 生产环境
    'production' => [
        'url' => 'https://bt.example.com',
        'key' => 'prod_api_key_here',
        'timeout' => 60
    ]
];

2. 使用工厂模式创建客户端

<?php
/**
 * API客户端工厂
 */

class BtApiClientFactory
{
    private static $instances = [];
    
    public static function getClient($environment = 'production')
    {
        if (!isset(self::$instances[$environment])) {
            $config = require 'config/bt_api_config.php';
            
            if (!isset($config[$environment])) {
                throw new Exception("环境配置不存在: {$environment}");
            }
            
            $client = new BtApiClient(
                $config[$environment]['url'],
                $config[$environment]['key']
            );
            
            if (isset($config[$environment]['timeout'])) {
                $client->setTimeout($config[$environment]['timeout']);
            }
            
            self::$instances[$environment] = $client;
        }
        
        return self::$instances[$environment];
    }
}

// 使用工厂
$client = BtApiClientFactory::getClient('production');
$status = $client->getSystemStatus();

常见问题解答

Q1: API请求返回"权限不足"怎么办?

A: 检查宝塔面板的API接口是否已开启,API密钥是否正确,以及IP白名单设置。

Q2: 如何提高API请求的安全性?

A: 建议:

  1. 定期更换API密钥

  2. 设置IP白名单限制

  3. 使用HTTPS连接

  4. 将API密钥存储在环境变量中

Q3: 请求超时如何处理?

A: 可以增加超时时间:

$client->setTimeout(60); // 设置为60秒

Q4: 如何获取更多API接口信息?

A: 访问宝塔官方文档

技术分享之余,这个就是通过全接口生成的独立网站:uudwc.com

posted @ 2026-01-17 16:18  Daijn  阅读(4)  评论(0)    收藏  举报