从零搭建高性能按分类随机图片 API 系统

AI摘要

本文介绍了如何使用PHP和MySQL从零搭建一个高性能的随机图片API系统。系统的核心亮点包括:使用HTTP 302 Location重定向以减少服务器压力、支持多目录分类以及自带调用统计功能。文章详细介绍了目录架构规划、核心后端部署、数据库统计表的创建、全局配置文件的编写、调用数据接口的编写以及核心分发引擎的编写。最后,还提供了Nginx配置文件中的规则以保护数据库配置信息。

在折腾个人博客或做前端开发时,我们经常需要用到“随机图片 API”来做头图或背景。网上虽然有很多免费接口,但稳定性和图片质量往往无法保证。今天,我将分享如何使用 PHP + MySQL 从零搭建一个属于你自己的高性能随机图片 API 系统。预览地址:https://api.weirain.com

一、这套系统的核心亮点在于:

1.彻底告别 readfile:抛弃了极其消耗服务器内存和带宽的传统输出方式,改用 HTTP 302 Location 重定向,将压力转移给 Nginx 静态处理,响应极快。

2.支持多目录分类:如二次元、风景、电脑壁纸等,结构清晰。

3.自带调用统计:内置 MySQL 计数器,精确记录 API 被调用的总次数。

二、📁 目录架构规划

api.yourdomain.com/ (网站根目录)
 ├── config.php      # 核心:数据库连接与统计算法
 ├── stats.php       # 核心:对外提供总调用次数的 JSON 接口
 ├── index.html      # 留空:你的自定义前端主页
 ├── acg/            # 分类 A:例如二次元
 │   ├── index.php   # 负责该分类下的随机重定向
 │   └── img/        # 存放具体的图片文件 (1.jpg, 2.png...)
 ├── fj/             # 分类 B:例如风景
 │   ├── index.php   
 │   └── img/        
 └── pc/、sj/ 等以此类推...

三、核心后端部署

1.创建数据库统计表

我们需要一张极简的表来记录全局调用次数。在你的 MySQL 中执行以下 SQL 语句:

CREATE TABLE IF NOT EXISTS `api_stats` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `total_calls` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 必须插入一条初始数据作为计数器基准
INSERT INTO `api_stats` (`id`, `total_calls`) VALUES (1, 0);

2.编写全局配置文件 (config.php)

在网站根目录创建 config.php。这里封装了 PDO 数据库连接,并定义了一个通用的计数器函数。

<?php
// 数据库配置信息 (请修改为你自己的)
$db_host = 'localhost';
$db_name = '你的数据库名';
$db_user = '你的数据库用户名';
$db_pass = '你的数据库密码';

try {
    // 核心优化:增加1秒超时熔断,长连接保持并发性能
    $options = [
        PDO::ATTR_TIMEOUT => 1, 
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_PERSISTENT => true, // 开启长连接
        PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"
    ];
    
    $pdo = new PDO("mysql:host={$db_host};dbname={$db_name};charset=utf8mb4", $db_user, $db_pass, $options);
} catch (PDOException $e) {
    // 连不上直接将 $pdo 置空,绝不卡顿前端图片展示
    $pdo = null; 
}

// 增加调用次数的通用函数
function addApiCallCount() {
    global $pdo;
    if ($pdo) {
        try {
            // 核心优化:防呆设计。如果没有记录会自动插入一条并设为1,有记录则+1
            // 确保你数据库里有一个叫 api_stats 的表,且 id 是主键
            $pdo->exec("INSERT INTO api_stats (id, total_calls) VALUES (1, 1) ON DUPLICATE KEY UPDATE total_calls = total_calls + 1");
        } catch (Exception $e) {
            // 忽略报错,保证业务不中断
        }
    }
}
?>

3.编写调用数据接口 (stats.php)

在网站根目录创建 stats.php。这个接口的作用是给你的前端主页(index.html)提供一个无刷新的数据源,用来展示“本站已累计服务 XXX 次”。

<?php
header('Content-Type: application/json; charset=utf-8');
require_once 'config.php';

$count = 0;
if ($pdo) {
    $stmt = $pdo->query("SELECT total_calls FROM api_stats WHERE id = 1");
    $result = $stmt->fetch(PDO::FETCH_ASSOC);
    if ($result) {
        $count = $result['total_calls'];
    }
}

echo json_encode(['code' => 200, 'total' => $count]);
?>

4.编写核心分发引擎 (index.php)

进入你的分类目录(比如 /acg/),创建 index.php

<?php
// 引入上一级(根目录)的数据库配置
require_once '../config.php';

// 触发统计次数 +1
addApiCallCount();

// 定义目录和缓存参数
$imgDir = 'img/';
$cacheFile = 'cache_images.json'; // 缓存文件名
$cacheTime = 3600; // 缓存有效期,3600秒 = 1小时

$images = [];

// 核心优化:如果有缓存且未过期,直接从本地读取,不再暴力扫盘
if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $cacheTime) {
    $cacheData = file_get_contents($cacheFile);
    if ($cacheData !== false) {
        $images = json_decode($cacheData, true);
    }
}

// 如果没有缓存、缓存过期、或缓存读取失败,则重新扫描硬盘并生成缓存
if (empty($images)) {
    $images = glob($imgDir . '*.{jpg,jpeg,png,gif,webp}', GLOB_BRACE);
    if (!empty($images)) {
        // 将结果写入缓存文件
        file_put_contents($cacheFile, json_encode($images), LOCK_EX);
    }
}

if (!empty($images)) {
    // 随机选择一张图片
    $randomImage = $images[array_rand($images)];
    
    // 清除缓存头,防止浏览器缓存同一张图
    header("Cache-Control: no-cache, must-revalidate");
    header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
    
    // 使用 302 重定向输出图片
    header("Location: " . $randomImage);
    exit;
} else {
    header('HTTP/1.1 404 Not Found');
    echo '目录下未找到图片,或者 img 文件夹权限错误。';
}
?>

本篇教程没有提供 index.html 的源码。由于我们把数据库账号密码明文写在了根目录的 config.php 里。虽然正常访问只会显示白屏,但如果服务器环境出现异常(比如 PHP 停止解析),该文件会被当作纯文本下载,从而导致密码泄露。所以需要在 Nginx 伪静态/配置文件中加入以下规则:

location = /config.php {
    deny all;
    return 404;
}

搭建随机图片api的教程就结束了。

评论区
头像
    头像
    一叶竹
      

    我正打算给openlist加个背景。

本站已运行: