Docker Compose部署随机图API

平时我们部署博客的时候,为了考虑美观会考虑使用随机图来作为文章的封面,现在有很多大佬愿意提供随机图API,通过API我们可以很方便地部署随机图,不必自己寻找图片,考虑带宽支出

不过很多时候一些公益API访问速度很慢,其中很多图片并不是我们所想要的,这时候我们就要考虑自建随机图API了,我参考了很多教程,他们中的很多都是基于宝塔来实现的,但其实我们不必要安装宝塔面板,完全可以在Docker内实现

前置准备

首先我们先建立一个文件夹来方式我们的docker-compose和其他的随机图文件,并且进入该文件夹内:

mkdir random-pic && cd random-pic

之后上传随机图的php文件,在这里有三个版本,其中一个版本我尝试过无法使用(可能是我没有正确使用?

原理介绍

随机图的基本实现是通过新建一个站点,通过向站点发送请求,站点文件将请求重定向(301)到随机图所在图链,从而实现随机图切换:

图片准备

获取到原始图片之后,我建议你对图片继续压缩处理,常见的诸如将图片转换成webp,这能有效减小文件体积,加快用户端的加载速度,如果你使用的是对象存储或者套了CDN的话,这能减小带宽和费用压力

在这里推荐一下来自GoogleSquoosh,是一个很全能的图片压缩程序,不用下载,直接在浏览器中就可以使用:网址

基本上支持了常见图片类型的转换和压缩:

版本1(不支持桌面与移动端切换

<?php
//存放api随机图链接的文件名img.txt
$filename = "img.txt";
if(!file_exists($filename)){
    die('文件不存在');
}
 
//从文本获取链接
$pics = [];
$fs = fopen($filename, "r");
while(!feof($fs)){
    $line=trim(fgets($fs));
    if($line!='' && substr($str , 0 , 1) != '#'){
        array_push($pics, $line);
    }
}
 
// 从数组随机获取链接
// $pic = $pics[array_rand($pics)];
$pic = $pics[random_int(0, count($pics) - 1)]; # 真随机
 
//返回指定格式
$type=$_GET['type'];
switch($type){
 
//JSON返回
case 'json':
    header('Content-type:text/json');
    die(json_encode(['pic'=>$pic]));
 
default:
    die(header("Location: $pic"));
}
 
?>

此时你要在该文件夹内新建一个img.txt文件,用来保存随机图的图链,这里的图链就决定了你图片加载的速度,请务必选择一些速度比较快的图床,这能够有效提高使用体验和加载速度:

此时你的文件结构应该如下,有img.txtrandom.php两个文件

.
├── img.txt
└── random.php

版本2(支持桌面与移动端切换

<?php
// 函数:访客设备
function is_mobile() {
    if (empty($_SERVER['HTTP_USER_AGENT']) || 
        strpos($_SERVER['HTTP_USER_AGENT'], 'iPad') !== false) {
        // 因为iPad有类似于PC的长宽比,所以我设置为电脑端
            $is_mobile = false;
        } elseif ( strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') !== false 
            || strpos($_SERVER['HTTP_USER_AGENT'], 'Android') !== false
            || strpos($_SERVER['HTTP_USER_AGENT'], 'Silk/') !== false
            || strpos($_SERVER['HTTP_USER_AGENT'], 'Kindle') !== false
            || strpos($_SERVER['HTTP_USER_AGENT'], 'BlackBerry') !== false
            || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') !== false
            || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mobi') !== false ) {
        $is_mobile = true;
    } else {
        $is_mobile = false;
    }
    return $is_mobile;
}
 
// 电脑与手机用不同的壁纸
if(is_mobile()){
   // 手机壁纸
   $filename = "img_mobile.txt";
}else{
   // 电脑壁纸
   $filename = "img.txt";
}
 
//存放api随机图链接的文件名img.txt
if(!file_exists($filename)){
    die('文件不存在');
}
 
//从文本获取链接
$pics = [];
$fs = fopen($filename, "r");
while(!feof($fs)){
    $line=trim(fgets($fs));
    if($line!='' && substr($str , 0 , 1) != '#'){
        array_push($pics, $line);
    }
}
 
//从数组随机获取链接
$pic = $pics[array_rand($pics)];
 
//返回指定格式
$type=$_GET['type'];
switch($type){
 
//JSON返回
case 'json':
    header('Content-type:text/json');
    die(json_encode(['pic'=>$pic]));
 
default:
    die(header("Location: $pic"));
}
 
?>

使用这种方法,你需要额外添加一个img_mobile.txt文件来放置用于移动端的图片,文件内容同img.txt

此时你的文件结构应该如下:

.
├── img_mobile.txt
├── img.txt
└── random.php

版本3(尚未成功

此版本需要引用Mobile_Detect.php,用于检测用户的设备类型(如手机、平板、桌面等),你需要自行去GitHub上下载源码,并且将它放置到此文件夹内:

  1. 访问 GitHub 仓库
  2. 下载 ZIP 文件
    • 在仓库页面上,点击绿色的 “Code” 按钮,然后选择 “Download ZIP” 以下载整个仓库的压缩包。
  3. 解压并找到 Mobile_Detect.php
    • 解压下载的 ZIP 文件,在解压后的目录中,找到 src/Mobile_Detect.php 文件。
  4. 将文件放到正确的位置
    • Mobile_Detect.php 文件放置到你的项目目录中,例如 /root/random-pic/

之后random.php的内容为:

<?php
/*
 * 函数:访客设备
 * 博客园:https://www.cnblogs.com/freephp/p/13979503.html
 * Github: https://github.com/serbanghita/Mobile-Detect
*/
function is_mobile(){
    require(__DIR__ . '/MobileDetect.php'); // 修正文件路径
    $MobileDetect = new Mobile_Detect();
 
    if ($MobileDetect->isTablet()) {
        // 平板定义为PC类
        return false;
    } elseif ($MobileDetect->isMobile()) {
        return true;
    } else {
        return false;
    }
}
 
// 电脑与手机用不同的壁纸
$filename = is_mobile() ? "img_mobile.txt" : "img.txt";
 
// 存放api随机图链接的文件名
if(!file_exists($filename)){
    die('文件不存在');
}
 
// 从文本获取链接
$pics = [];
$fs = fopen($filename, "r");
while(!feof($fs)){
    $line = trim(fgets($fs));
    if($line != '' && substr($line, 0, 1) != '#'){ // 修正变量名
        array_push($pics, $line);
    }
}
fclose($fs);
 
// 从数组随机获取链接
$pic = $pics[random_int(0, count($pics) - 1)]; // 真随机
 
// 返回指定格式
$type = $_GET['type'] ?? '';
switch($type){
 
// JSON 返回
case 'json':
    header('Content-type: application/json'); // 修正 Content-type
    die(json_encode(['pic' => $pic]));
 
default:
    die(header("Location: $pic"));
}
?>

此时还是需要添加img_mobile.txt,同版本2

此时文件结构如下:

.
├── img_mobile.txt
├── img.txt
├── MobileDetect.php
└── random.php

Docker Compose部署

为了部署这个站点,在这里我们直接使用Docker Compose进行操作:

version: '3.8'
services:
  web:
    image: nginx:latest
    ports:
      - "9000:80"
    volumes:
      - /root/random-pic:/usr/share/nginx/html
      - ./default.conf:/etc/nginx/conf.d/default.conf
    container_name: random-pic
    depends_on:
      - php-fpm
    networks:
      - mynetwork

  php-fpm:
    image: php:7.4-fpm
    volumes:
      - /root/random-pic:/usr/share/nginx/html
    networks:
      - mynetwork

networks:
  mynetwork:
    driver: bridge

这里为了方便测试我们不占用80端口,而是使用9000端口,之后使用Nginx或者其他工具进行反代即可

此时不要急着启动容器,我们还需要定制一下Nginx的配置文件:

此时新建一个default.conf

server {
    listen 80;
    server_name localhost;

    root /usr/share/nginx/html;
    index random.php;

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass php-fpm:9000;
        fastcgi_index random.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

写入后保存,你的文件结构应该是这样的:

.
├── default.conf
├── docker-compose.yaml
├── img_mobile.txt
├── img.txt
└── random.php

之后正式启动容器

docker compose up -d

之后访问域名+端口即可看到随机图效果

后语

个人感觉给随机图域名套上CDN还是有意义的,因为这个严格来说也算个静态网站,如果有CDN缓存的话随机图的切换速度会变快很多

参考文献:Docker系列 WordPress系列 自建随机图API之静态壁纸

小树,小树!