如何修改PHP代码实现CSV文件的多行数据添加功能?
实现多行客户信息收集并导出CSV的表单
下面是修改后的完整代码,已实现动态添加表单行、多行数据验证及CSV导出功能:
<?php // 初始化错误信息数组 $errors = array(); if (isset($_POST['submit'])) { // 获取公司名称 $Companyname = $_POST['Companyname']; // 验证公司名称 if (empty($Companyname)) { $errors[] = "公司名称为必填项。"; } // 获取多行表单数据 $firstnames = $_POST['FirstName'] ?? []; $lastnames = $_POST['LastName'] ?? []; $DateofBirths = $_POST['DateofBirth'] ?? []; $CDLs = $_POST['CDL'] ?? []; $Countries = $_POST['Country'] ?? []; $States = $_POST['State'] ?? []; // 逐行验证数据 foreach ($firstnames as $index => $firstname) { // 跳过空行(可选:若需强制所有添加行必须填写,可移除此判断) if (empty($firstname) && empty($lastnames[$index]) && empty($DateofBirths[$index]) && empty($CDLs[$index]) && empty($Countries[$index]) && empty($States[$index])) { continue; } // 验证名字 if (empty($firstname)) { $errors[] = "第 ".($index+1)." 行的名字为必填项。"; } // 验证姓氏 if (empty($lastnames[$index])) { $errors[] = "第 ".($index+1)." 行的姓氏为必填项。"; } // 验证出生日期 if (empty($DateofBirths[$index])) { $errors[] = "第 ".($index+1)." 行的出生日期为必填项。"; } // 验证CDL编号 if (empty($CDLs[$index])) { $errors[] = "第 ".($index+1)." 行的CDL编号为必填项。"; } // 验证国家 if (empty($Countries[$index])) { $errors[] = "第 ".($index+1)." 行的国家为必填项。"; } // 验证州/省 if (empty($States[$index])) { $errors[] = "第 ".($index+1)." 行的州/省为必填项。"; } } // 无错误时生成CSV if (empty($errors)) { // CSV表头 $Content = "firstname,lastname,DateofBirth,CDL,Country,State\n"; // 逐行添加数据到CSV foreach ($firstnames as $index => $firstname) { // 跳过空行 if (empty($firstname) && empty($lastnames[$index]) && empty($DateofBirths[$index]) && empty($CDLs[$index]) && empty($Countries[$index]) && empty($States[$index])) { continue; } // 转义特殊字符,避免CSV格式错乱 $fn = str_replace('"', '""', $firstname); $ln = str_replace('"', '""', $lastnames[$index]); $dob = str_replace('"', '""', $DateofBirths[$index]); $cdl = str_replace('"', '""', $CDLs[$index]); $country = str_replace('"', '""', $Countries[$index]); $state = str_replace('"', '""', $States[$index]); // 用双引号包裹字段,处理含逗号的数据 $Content .= "\"$fn\",\"$ln\",\"$dob\",\"$cdl\",\"$country\",\"$state\"\n"; } // 设置文件名并导出CSV $FileName = $Companyname . "-" . date("d-m-y-h:i:s") . ".csv"; header('Content-Type: application/csv'); header('Content-Disposition: attachment; filename="' . $FileName . '"'); echo $Content; exit(); } } // 显示错误信息 if (!empty($errors)) { foreach ($errors as $error) { echo '<p style="color:#ff0000">' . $error . '</p>'; } } ?> <!-- 带动态行功能的HTML表单 --> <form action="" method="post"> <label>公司名称</label> <input type="text" name="Companyname" required value=""> <br><br> <!-- 表单行容器 --> <div id="formRows"> <!-- 初始表单行 --> <div class="formRow"> <label>名字</label> <input type="text" name="FirstName[]" required value=""> <label>姓氏</label> <input type="text" name="LastName[]" required value=""> <label>出生日期</label> <input type="date" name="DateofBirth[]" required value=""> <label>CDL #</label> <input type="text" name="CDL[]" required value=""> <label>国家</label> <select name="Country[]" required> <option value="">选择国家</option> <option value="US">美国</option> <option value="CN">加拿大</option> <option value="MX">墨西哥</option> </select> <label>州/省:</label> <select name="State[]" required> <option value="">选择州/省</option> <option value="AL">阿拉巴马州</option> <option value="AK">阿拉斯加州</option> <option value="AZ">亚利桑那州</option> <option value="AR">阿肯色州</option> <option value="CA">加利福尼亚州</option> <option value="CO">科罗拉多州</option> <option value="CT">康涅狄格州</option> <option value="DE">特拉华州</option> <option value="FL">佛罗里达州</option> <option value="GA">佐治亚州</option> <option value="HI">夏威夷州</option> <option value="ID">爱达荷州</option> <option value="IL">伊利诺伊州</option> <option value="IN">印第安纳州</option> <option value="IA">爱荷华州</option> <option value="KS">堪萨斯州</option> <option value="KY">肯塔基州</option> <option value="LA">路易斯安那州</option> <option value="ME">缅因州</option> <option value="MD">马里兰州</option> <option value="MA">马萨诸塞州</option> <option value="MI">密歇根州</option> <option value="MN">明尼苏达州</option> <option value="MS">密西西比州</option> <option value="MT">蒙大拿州</option> <option value="NE">内布拉斯加州</option> <option value="NV">内华达州</option> <option value="NH">新罕布什尔州</option> <option value="NJ">新泽西州</option> <option value="NM">新墨西哥州</option> <option value="NY">纽约州</option> <option value="NC">北卡罗来纳州</option> <option value="ND">北达科他州</option> <option value="OH">俄亥俄州</option> <option value="OK">俄克拉荷马州</option> <option value="OR">俄勒冈州</option> <option value="PA">宾夕法尼亚州</option> <option value="RI">罗得岛州</option> <option value="SC">南卡罗来纳州</option> <option value="SD">南达科他州</option> <option value="TN">田纳西州</option> <option value="TX">德克萨斯州</option> <option value="UT">犹他州</option> <option value="VT">佛蒙特州</option> <option value="VA">弗吉尼亚州</option> <option value="WA">华盛顿州</option> <option value="WV">西弗吉尼亚州</option> <option value="WI">威斯康星州</option> <option value="WY">怀俄明州</option> </select> <!-- 删除行按钮(仅第一行隐藏) --> <button type="button" class="removeRow" style="display:none;">删除此行</button> </div> </div> <br><br> <button type="button" id="addLine">Add a line</button> <input type="submit" name="submit" value="导出CSV"> <input type="reset" name="reset" value="重置"> </form> <script> // 添加行功能 document.getElementById('addLine').addEventListener('click', function() { const formRows = document.getElementById('formRows'); const firstRow = formRows.querySelector('.formRow'); const newRow = firstRow.cloneNode(true); // 清空新行的输入值 const inputs = newRow.querySelectorAll('input, select'); inputs.forEach(input => { input.value = ''; if (input.tagName === 'SELECT') { input.selectedIndex = 0; } }); // 显示新行的删除按钮 newRow.querySelector('.removeRow').style.display = 'inline-block'; formRows.appendChild(newRow); }); // 删除行功能 document.getElementById('formRows').addEventListener('click', function(e) { if (e.target.classList.contains('removeRow')) { const rows = document.querySelectorAll('.formRow'); // 至少保留一行表单 if (rows.length > 1) { e.target.parentElement.remove(); } } }); </script>
核心改动说明
表单字段数组化
将原表单字段名改为FirstName[]、LastName[]格式,让PHP能接收多行数据为数组。动态行操作
- 点击「Add a line」克隆现有表单行,清空输入值并显示删除按钮。
- 删除按钮仅在表单行数大于1时可用,避免无表单行的情况。
多行数据处理
- PHP遍历数组逐行验证,给出带行号的错误提示。
- 生成CSV时转义特殊字符,用双引号包裹字段,确保Excel等工具能正确解析。
- 自动跳过空行,避免导出无效数据。
内容的提问来源于stack exchange,提问作者Poecifer
相关产品推荐
相关产品推荐

