PHP动态图片失效主因是三层缓存未清:浏览器需设no-store响应头,OPcache需手动重置,Web服务器须禁用fastcgi_cache/mod_cache,框架还需清除路由与模板缓存。

PHP文生图样式失效,不是CSS写错了,是缓存把图片“锁死”在旧状态——浏览器、OPcache、Web服务器三者同时缓存响应内容,漏清一层,imagepng() 生成的新图就永远出不来。
浏览器缓存让 <img src="gen.php"> 永远不更新
即使你用 imagestring() 改了文字、imagecolorallocate() 换了颜色,只要 HTTP 响应头没禁用缓存,浏览器大概率直接从本地加载旧二进制数据。
- 必须在输出图片前加三行头(顺序不能错,且不能有任何前置输出):
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");header("Pragma: no-cache");header("Expires: 0"); - 只写
Cache-Control: no-cache不够——它允许协商缓存(如 ETag),而no-store才真正禁止存储 - URL 加时间戳是临时补救:
<img src="gen.php?t=<?php echo time(); ?>">,但不能替代响应头,否则 CDN 或代理仍可能缓存
OPcache 缓存了旧字节码,imagepng() 根本没执行
PHP 8.0+ 默认启用 OPcache,它把 gen.php 编译后的 opcode 存在内存里。你改了文件,但 OPcache 不刷新,Web 服务器仍在跑旧逻辑——可能连 header() 都没发,直接返回空白或 500。
- 检查是否启用:
php -i | grep opcache.enable→ 输出opcache.enable => On就要处理 - 开发中别依赖
opcache.validate_timestamps=0;设为1并配opcache.revalidate_freq=2也不保险,手动重置最稳 - 建一个
clear_opcache.php,内容仅:<?php opcache_reset(); ?>,访问一次再删掉 - 重启 PHP-FPM 通常无效:OPcache 是进程内缓存,重启不一定清空全部共享内存段
Nginx/Apache 把 Content-Type: image/* 当静态资源缓存了
某些 Web 服务器配置会识别到响应头是图片类型,自动启用 fastcgi_cache 或 mod_cache,导致整个 HTTP 响应(含状态码和二进制 body)被缓存下来——你删了 gen.php 文件,页面照样显示旧图。
立即学习“PHP免费学习笔记(深入)”;
- 查 Nginx 配置是否有
fastcgi_cache、fastcgi_cache_valid块;Apache 查mod_cache相关指令 - 临时注释掉相关配置,运行
nginx -s reload或apachectl graceful - 更稳妥的做法:给图片脚本加专属 location 块,显式关闭缓存:
location ~ \.php$ {fastcgi_cache off;add_header Cache-Control "no-store";}
框架路由/模板缓存干扰了图片脚本入口
如果你的图片生成逻辑放在 Laravel 的控制器、ThinkPHP 的操作方法里,而不是独立 PHP 文件,那框架自身的路由缓存、视图编译缓存也会生效——比如 php artisan route:clear 没执行,请求根本没进到你的图片逻辑里。
- Laravel:必须按顺序跑四条命令(缺一不可):
php artisan route:clearphp artisan view:clearphp artisan config:clearphp artisan cache:clear - ThinkPHP:执行
php think clear --all后,**必须额外补上**:php think clear:templatephp think route:clear,否则模板层或路由层仍走旧路径 - 别手动删
runtime/下的某个子目录——runtime/view/和runtime/route.php可能残留,问题照旧
最常被忽略的是:动态图片不该做条件响应(304 Not Modified)。一旦代码里写了 header("HTTP/1.1 304 Not Modified") 却没 exit,后续 imagepng() 就不会执行,用户看到的永远是上次成功生成的缓存图。



















