最直接方式是用 file_get_contents 获取远程图片二进制数据,但需 ensure allow_url_fopen=On;推荐配合 get_headers 验证状态码与 Content-Type,并用 exif_imagetype 校验图片真实性。
用
获取图片二进制数据最直接
PHP 里最常用的方式就是用
拉取远程图片内容,它返回的是原始
字节
流,适合直接存为文件。注意:目标网址必须是可公开访问的图片地址(如
),且 PHP 配置中
必须为
。
常见错误现象:
—— 就是这个配置被关了,得去
改或联系服务器管理员。
实操建议:
先用
检查 HTTP
状态码
是否为
,避免下载 404 或重定向页面
用
提取扩展名,但别全信——有些 URL 没后缀(如
),得靠
里的
字段判断,比如
对应
保存前用
,别用
或
输出二进制,否则会乱码甚至损坏图片
用
更可控,尤其要处理重定向或自定义 Header
当目标网站校验
、需要 Cookie、或强制跳转(302)时,
就不够用了,得上
。
立即学习
“
PHP免费学习笔记(深入)
”;
关键参数设置:
—— 必须设,否则直接输出到页面
—— 处理 301/302 跳转(但注意有些站点跳转后带临时 token,需手动跟进)
—— 防止被反爬返回空内容或 403
下载大图时加
,避免卡死
示例片段:
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
保存路径和文件名要注意权限与唯一性
写入失败不是代码问题,八成是目录没写权限,或者磁盘满了。Linux 下常见报错:
。
实操建议:
用
提前检查目录可写性,别等
报错才处理
文件名别直接用 URL 原样拼接,容易含非法字符(如
、
、
),推荐用
生成安全文件名
如果并发下载,用
先写临时文件,再
,避免多个请求同时写同一个文件导致损坏
注意
限制——有些虚拟主机禁了某些路径,
可能被拒绝
图片内容校验不能省,防止存一堆“HTML 错误页”
很多开发者只管下载不管验证,结果发现目录里全是
的 HTML 文本,还当图片打开了。
简单但有效的校验方式:
用
判断是否为真实图片(返回
等常量),非图片会返回
更轻量:读前 4 字节,用
看是否匹配 PNG/JPG 文件头(如
或
),但不如
稳定
如果用
,下载完立刻检查
是否以
开头,不匹配就删掉文件并报错
这步看似多此一举,实际线上环境里因网络抖动、CDN 缓存错误、防盗链失效导致存错内容的概率远高于预期。
file_get_contentsfile_get_contentshttps://example.com/logo.pngallow_url_fopenOnWarning: file_get_contents(): failed to open stream: no suitable wrapperphp.iniget_headers($url, 1)200pathinfo($url, PATHINFO_EXTENSION)https://api.example/img?id=123get_headersContent-Typeimage/jpeg.jpgfile_put_contents($filename, $data)echoprintcURLUser-Agentfile_get_contentscURLcurl_setopt($ch, CURLOPT_RETURNTRANSFER, true)curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true)curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0')curl_setopt($ch, CURLOPT_TIMEOUT, 60)if (false === $data = curl_exec($ch)) {
throw new Exception('cURL error: ' . curl_error($ch));
}
// 检查 HTTP 状态
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode !== 200) {
throw new Exception("HTTP $httpCode");
}failed to open stream: Permission deniedis_writable($dir)file_put_contents?&/md5($url) . '.' . $exttempnam()rename()open_basedirfile_put_contents('/tmp/xxx.jpg')502 Bad Gatewayexif_imagetype($filename)IMAGETYPE_JPEGfalsebindec(decbin(ord($data[0])) . decbin(ord($data[1])))\x89PNG\xff\xd8\xffexif_imagetypecURLCURLINFO_CONTENT_TYPEimage/