使用fgetcsv提取CSV中URL后,parse_url无法解析域名求助
问题分析与解决方案
核心原因
你的URL字符串被隐性破坏了——从var_dump输出能看到,parse_url返回的path中每个字符都被下划线分隔(比如_h_t_t_p_s_:_/_/_w_w_w_._h_4_d_._c_o_m_/_),这说明实际读取到的URL字符串里,每个有效字符之间插入了空字节(在输出中显示为下划线)。
这种情况90%是因为你的CSV文件是UTF-16编码(通常带BOM,常见于Excel导出的CSV),而你用fgetcsv默认的ASCII编码读取,把双字节的UTF-16字符拆成了单字节,导致空字节混入字符串,完全打乱了URL的结构,所以parse_url无法识别协议、主机等部分,只能把整个乱码内容当成path。
另外你的CSV读取逻辑存在混乱:先调用fgetcsv($file, 10000, ",")用逗号分隔读取表头,后续循环却用fgetcsv($file, 0, "\t")用制表符分隔读取数据,这会导致表头解析错误,甚至后续数据行错位。
修复步骤
1. 统一CSV分隔符读取逻辑
确保表头和数据行使用相同的分隔符(根据你的实际CSV文件选择逗号或制表符,这里假设是制表符)。
2. 处理UTF-16编码的CSV文件
下面提供两种可行的处理方式:
方式一:转换文件编码为UTF-8后读取
$tempPath = public_path('uploads/temp/tempcsv.csv'); $request->file('file')->move($tempPath); // 读取UTF-16编码的文件内容,转换为UTF-8 $content = file_get_contents($tempPath); $content = mb_convert_encoding($content, 'UTF-8', 'UTF-16'); file_put_contents($tempPath, $content); // 统一用制表符读取CSV $file = fopen($tempPath, "r"); $lines = []; // 跳过表头 fgetcsv($file, 0, "\t"); while (($data = fgetcsv($file, 0, "\t")) !== FALSE) { $lines[] = $data; } fclose($file); File::delete($tempPath); $urlsOfCsv = array_column($lines, 0);
方式二:直接用支持多字节的SplFileObject读取
$tempPath = public_path('uploads/temp/tempcsv.csv'); $request->file('file')->move($tempPath); $lines = []; $file = new SplFileObject($tempPath); $file->setFlags(SplFileObject::READ_CSV); // 设置CSV分隔符为制表符 $file->setCsvControl("\t"); // 指定文件编码为UTF-16 $file->setEncoding('UTF-16'); // 跳过表头行 $file->next(); foreach ($file as $data) { if (!empty($data)) { $lines[] = $data; } } File::delete($tempPath); $urlsOfCsv = array_column($lines, 0);
3. 验证修复效果
处理后再执行parse_url,就能正确识别URL的各个部分(包括host):
foreach($urlsOfCsv as $url){ var_dump($url); var_dump(parse_url($url)); }
额外提示
如果不确定CSV的编码,可以用mb_detect_encoding检测:
$content = file_get_contents($tempPath); var_dump(mb_detect_encoding($content));
内容的提问来源于stack exchange,提问作者Thomas Locatelli
相关产品推荐
相关产品推荐

