PHP无需下载读取在线Excel及cURL下载xlsx异常解决方案咨询
问题解决方案
一、修复cURL下载文件损坏的问题
你当前代码的核心错误如下:
- 错误使用
CURLOPT_HEADER参数:该参数接收布尔值,用于控制是否将响应头写入输出流,自定义请求头需要使用CURLOPT_HTTPHEADER参数。 - 手动添加了HTTP/2伪头:
:authority、:method、:path、:scheme这类冒号开头的头是cURL发起HTTP/2请求时自动生成的,手动添加会导致请求格式错误。 - 未开启自动解压缩:你设置了
accept-encoding支持压缩格式,但没有配置cURL自动解码,返回的压缩内容直接保存会导致文件损坏。 - 固定写死Cookie:代码中的
__cf_bm是Cloudflare的反爬Cookie,有效期仅有几分钟,固定写死很快就会失效,请求会被拦截。
修正后的cURL下载代码如下:
function dfCurl($url, $saveToFile = true, $savePath = '../'){ $ch = curl_init($url); // 先请求一次referer页面获取最新Cookie,避免反爬拦截 curl_setopt($ch, CURLOPT_URL, 'https://www.idx.co.id/perusahaan-tercatat/laporan-keuangan-dan-tahunan/'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_COOKIEJAR, tmpfile()); // 临时存储Cookie curl_exec($ch); // 再请求目标文件 curl_setopt($ch, CURLOPT_URL, $url); $headers = [ 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'accept-language: en-AU,en;q=0.9,id-ID;q=0.8,id;q=0.7,zh-CN;q=0.6,zh;q=0.5,ja-JP;q=0.4,ja;q=0.3,en-GB;q=0.2,en-US;q=0.1', 'cache-control: no-cache', 'pragma: no-cache', 'referer: https://www.idx.co.id/perusahaan-tercatat/laporan-keuangan-dan-tahunan/', 'sec-ch-ua: "Google Chrome";v="95", "Chromium";v="95", ";Not A Brand";v="99"', 'sec-ch-ua-mobile: ?1', 'sec-ch-ua-platform: "Android"', 'sec-fetch-dest: document', 'sec-fetch-mode: navigate', 'sec-fetch-site: same-origin', 'sec-fetch-user: ?1', 'upgrade-insecure-requests: 1', 'user-agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Mobile Safari/537.36' ]; curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_ENCODING, ''); // 自动解码所有支持的压缩格式 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); if($saveToFile){ $fileName = basename($url); $saveFilePath = $savePath . $fileName; $fp = fopen($saveFilePath, 'wb'); curl_setopt($ch, CURLOPT_FILE, $fp); $result = curl_exec($ch); fclose($fp); }else{ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = curl_exec($ch); } $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return $httpCode == 200 ? $result : false; }
二、无需下载到本地直接读取Excel内容
使用PHPSpreadsheet可以直接读取内存中的Excel内容,无需写入本地磁盘,实现方案如下:
- 用cURL获取到Excel文件的二进制内容
- 将内容写入内存流,直接传给PHPSpreadsheet加载
- 读取指定工作表的全量数据
示例代码:
require 'vendor/autoload.php'; use PhpOffice\PhpSpreadsheet\IOFactory; public function readRemoteExcel() { $url = 'https://www.idx.co.id/Portals/0/StaticData/ListedCompanies/Corporate_Actions/New_Info_JSX/Jenis_Informasi/01_Laporan_Keuangan/02_Soft_Copy_Laporan_Keuangan//Laporan%20Keuangan%20Tahun%202021/TW1/AALI/FinancialStatement-2021-I-AALI.xlsx'; // 获取文件二进制内容,不保存到本地 $fileContent = dfCurl($url, false); if(!$fileContent){ die('文件获取失败'); } // 从内存流加载Excel $spreadsheet = IOFactory::load('data://application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,' . base64_encode($fileContent)); // 读取第一个工作表 $worksheet = $spreadsheet->getActiveSheet(); // 获取全量行列数据 $data = $worksheet->toArray(); // 后续处理$data即可 print_r($data); }
注:如果目标站点反爬策略升级,普通cURL请求被拦截,可以使用Guzzle配合中间件,或者使用无头浏览器获取文件内容。
内容的提问来源于stack exchange,提问作者Dennis Liu
相关产品推荐
相关产品推荐

