
在web开发中,处理用户上传的csv文件是常见的需求。通常,csv文件包含结构化数据,但有时某些字段的值可能需要进一步处理和转换才能满足应用的需求。例如,一个字段可能包含复杂的url,而我们只关心url中的某个特定查询参数值。本教程将以一个具体的例子,展示如何上传csv文件,将其内容解析为php数组,并对数组中特定键(例如query字段)的url值进行批量处理,从中提取出keywords参数的实际值。
首先,我们需要一个HTML表单来允许用户上传CSV文件,并编写PHP代码来接收文件并将其内容初步解析为关联数组。
<form enctype='multipart/form-data' action='' method='post'>
<label>上传 CSV 文件</label><br>
<input size='50' type='file' name='filename'>
<br>
<input type='submit' name='submit' value='上传文件'>
</form>当表单提交后,PHP脚本会接收上传的文件。$_FILES全局变量用于访问上传文件的信息。我们使用fgetcsv函数逐行读取CSV内容,并利用array_combine将CSV的标题行作为键,每行数据作为值,构建成一个易于操作的关联数组。
<?php
if (isset($_POST['submit'])) {
// 检查文件是否成功上传且没有错误
if (isset($_FILES['filename']) && $_FILES['filename']['error'] === UPLOAD_ERR_OK) {
$file = fopen($_FILES['filename']['tmp_name'], "r");
$all_rows = array();
// 读取CSV头部作为数组的键
$header = fgetcsv($file);
// 逐行读取CSV数据并与头部结合
while (($row = fgetcsv($file)) !== FALSE) {
// 确保行数据和头部长度匹配,避免array_combine报错
if (count($header) === count($row)) {
$all_rows[] = array_combine($header, $row);
} else {
// 处理行数据与头部不匹配的情况,例如跳过或记录错误
error_log("CSV行数据与头部不匹配,已跳过此行: " . implode(",", $row));
}
}
fclose($file); // 关闭文件句柄
echo "<pre>";
print_r($all_rows); // 打印原始解析结果
echo "</pre>";
// 接下来的数据转换逻辑将放在这里
// ...
} else {
echo "文件上传失败或未选择文件。错误码: " . $_FILES['filename']['error'];
}
}
?>此时,$all_rows数组将包含CSV文件的所有数据,每行作为一个子数组,键是CSV的列名。例如:
Array
(
[0] => Array
(
[query] => https://www.example.com/search/output/person/?loc=%5B%22105490917%22%2C%22101452733%22%5D&keywords=Computational%20Biologist&origin=host
[firstName] => John
[lastName] => Smith
[] =>
)
// ... 其他行
)我们的目标是将query键中的复杂URL转换为只包含keywords参数解码后的值,例如将https://...&keywords=Computational%20Biologist&origin=host变为Computational Biologist。这需要对数组中的每个query值进行迭代处理。
立即学习“PHP免费学习笔记(深入)”;
由于我们需要修改数组中的每个子元素的特定键值,最直接的方法是使用foreach循环遍历$all_rows数组。
// ... (接续上面的PHP代码)
if (isset($_POST['submit'])) {
// ... (文件上传和初步解析代码)
// 对$all_rows数组中的每个元素进行处理
foreach($all_rows as $key => $value) {
// 确保 'query' 键存在且为字符串
if (isset($all_rows[$key]['query']) && is_string($all_rows[$key]['query'])) {
$queryString = $all_rows[$key]['query'];
// 1. 查找 'keywords=' 出现的位置及之后的所有内容
// strstr() 返回从 needle 开始到字符串结尾的部分,如果未找到则返回 false
$tempQuery = strstr($queryString, 'keywords=');
if ($tempQuery !== false) {
// 2. 移除 'keywords=' 前缀
$tempQuery = str_replace('keywords=', '', $tempQuery);
// 3. 查找下一个 '&' 符号,并截取到该位置之前的内容
// strpos() 返回 needle 在 haystack 中第一次出现的位置
$ampersandPos = strpos($tempQuery, "&");
if ($ampersandPos !== false) {
$tempQuery = substr($tempQuery, 0, $ampersandPos);
}
// 如果没有 '&',说明 keywords 是最后一个参数,无需截取
// 4. 对URL编码的字符串进行解码
$all_rows[$key]['query'] = urldecode($tempQuery);
} else {
// 如果没有找到 'keywords=',可以将 'query' 设为空或保持原样
$all_rows[$key]['query'] = '';
}
}
}
echo "<h3>转换后的数据:</h3>";
echo "<pre>";
print_r($all_rows); // 打印转换后的结果
echo "</pre>";
}
?>将上述所有部分组合起来,形成一个完整的PHP脚本:
<?php
// error_reporting(E_ALL); // 开启所有错误报告,方便调试
// ini_set('display_errors', 1);
if (isset($_POST['submit'])) {
// 检查文件是否成功上传且没有错误
if (isset($_FILES['filename']) && $_FILES['filename']['error'] === UPLOAD_ERR_OK) {
$file = fopen($_FILES['filename']['tmp_name'], "r");
$all_rows = array();
// 读取CSV头部作为数组的键
$header = fgetcsv($file);
// 检查头部是否有效
if ($header === false || empty($header)) {
echo "错误:无法读取CSV头部或头部为空。";
fclose($file);
exit;
}
// 逐行读取CSV数据并与头部结合
while (($row = fgetcsv($file)) !== FALSE) {
// 确保行数据和头部长度匹配,避免array_combine报错
if (count($header) === count($row)) {
$all_rows[] = array_combine($header, $row);
} else {
error_log("CSV行数据与头部不匹配,已跳过此行: " . implode(",", $row));
}
}
fclose($file); // 关闭文件句柄
echo "<h3>原始解析结果:</h3>";
echo "<pre>";
print_r($all_rows);
echo "</pre>";
// 对$all_rows数组中的每个元素进行处理
foreach($all_rows as $key => $value) {
// 确保 'query' 键存在且为字符串
if (isset($all_rows[$key]['query']) && is_string($all_rows[$key]['query'])) {
$queryString = $all_rows[$key]['query'];
// 1. 查找 'keywords=' 出现的位置及之后的所有内容
$tempQuery = strstr($queryString, 'keywords=');
if ($tempQuery !== false) {
// 2. 移除 'keywords=' 前缀
$tempQuery = str_replace('keywords=', '', $tempQuery);
// 3. 查找下一个 '&' 符号,并截取到该位置之前的内容
$ampersandPos = strpos($tempQuery, "&");
if ($ampersandPos !== false) {
$tempQuery = substr($tempQuery, 0, $ampersandPos);
}
// 如果没有 '&',说明 keywords 是最后一个参数,无需截取
// 4. 对URL编码的字符串进行解码
$all_rows[$key]['query'] = urldecode($tempQuery);
} else {
// 如果没有找到 'keywords=',可以将 'query' 设为空字符串
$all_rows[$key]['query'] = '';
}
} else {
// 如果 'query' 键不存在或不是字符串,也将其设为空或保持原样
$all_rows[$key]['query'] = '';
}
}
echo "<h3>转换后的数据:</h3>";
echo "<pre>";
print_r($all_rows);
echo "</pre>";
} else {
// 根据 $_FILES['filename']['error'] 提供更详细的错误信息
$error_messages = [
UPLOAD_ERR_INI_SIZE => '上传文件大小超过php.ini中upload_max_filesize选项限制。',
UPLOAD_ERR_FORM_SIZE => '上传文件大小超过HTML表单中MAX_FILE_SIZE选项限制。',
UPLOAD_ERR_PARTIAL => '文件只有部分被上传。',
UPLOAD_ERR_NO_FILE => '没有文件被上传。',
UPLOAD_ERR_NO_TMP_DIR => '找不到临时文件夹。',
UPLOAD_ERR_CANT_WRITE => '文件写入失败。',
UPLOAD_ERR_EXTENSION => 'PHP扩展阻止了文件上传。',
];
$error_code = $_FILES['filename']['error'] ?? UPLOAD_ERR_NO_FILE;
echo "文件上传失败或未选择文件。错误详情: " . ($error_messages[$error_code] ?? '未知错误');
}
}
?>
<form enctype='multipart/form-data' action='' method='post'>
<label>上传 CSV 文件</label><br>
<input size='50' type='file' name='filename'>
<br>
<input type='submit' name='submit' value='上传文件'>
</form>$url = "https://www.example.com/search/?loc=...&keywords=Computational%20Biologist&origin=host"; $query_components = parse_url($url, PHP_URL_QUERY); // 获取查询字符串 $params = []; parse_str($query_components, $params); // 解析查询字符串到关联数组 $keyword = $params['keywords'] ?? ''; // 获取 'keywords' 参数
这种方法在URL结构多变时更为可靠。然而,对于本教程中这种特定且一致的模式,直接的字符串函数组合是高效且易于理解的。
本教程演示了如何在PHP中实现一个实用的CSV文件上传和数据处理流程。通过结合fgetcsv进行文件解析,foreach循环进行数组迭代,以及strstr、str_replace、substr和urldecode等字符串函数进行精确的数据提取和转换,我们成功地将复杂的URL查询字符串清洗为所需的简洁关键词信息。这种方法对于数据清洗、报告生成或将外部数据导入系统等场景都非常有用。
以上就是PHP CSV文件处理与URL查询参数提取:实现数组中特定键值的批量转换的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号