PHP脚本无法创建XML文件问题排查求助
问题描述
我用PHP脚本实现两个功能:
- 根据HTML表单输入在
/usr/local/ezreplay/data/XML/目录创建并写入XML文件 - 上传表单中的PCAP文件
目前PCAP上传功能正常,能看到成功提示,但XML文件始终未生成。已将目录权限改为apache用户所有甚至设置chmod 777,PHP和Apache日志也无报错信息。
附上PHP代码:
<?php // Check if the 'expirydate' input is set if (isset($_POST['expirydate'])) { // Convert the input string to a timestamp using 'strtotime' $timestamp = strtotime($_POST['expirydate']); // Format the timestamp as a 'mm/dd/yyyy' string using 'date' $expirydate = date('m/d/Y', $timestamp); } // Check if all required POST variables are set if ( isset($_POST['destinationip']) && isset($_POST['destinationport']) && isset($expirydate) && isset($_POST['multiplier']) && isset($_POST['pcap']) ) { // Set the path for the XML file $path = '/usr/local/ezreplay/data/XML/' . trim($_POST['destinationip']) . ':' . trim($_POST['destinationport']) . ':' . $expirydate . ':' . trim($_POST['multiplier']) . ':' . trim($_POST['pcap']) . '.xml'; // Initialize the contents of the XML file $contents = ""; // Open the XML file in append mode if ( $fh = fopen($path,"a+") ) { // Add the opening 'config' tag to the XML file $contents .= '<config>'; // If the 'destinationip' and 'destinationport' POST variables are not empty, add a 'destination' tag to the XML file if ( trim( $_POST['destinationip'] ) != "" && trim( $_POST['destinationport'] ) != "" ) { $contents .= "\n" . '<destination>' . $_POST['destinationip'] . ':' . $_POST['destinationport'] . '</destination>'; } // If the 'multiplier' POST variable is not empty, add a 'multiplier' tag to the XML file if ( trim( $_POST['multiplier'] ) != "" ) { $contents .= "\n" . '<multiplier>' . $_POST['multiplier'] . '</multiplier>'; } // If the 'pcap' POST variable is not empty, add a 'pcap' tag to the XML file if ( trim( $_POST['pcap'] ) != "" ) { $contents .= "\n" . '<pcap>/usr/local/ezreplay/data/PCAP/' . $_POST['pcap'] . '</pcap>'; // Add default tags to XML config file to ensure the pcap does not fail and loops continuously until expiration date hits $contents .= "\n" . '<loop>0</loop>'; $contents .= "\n" . '<nofail>true</nofail>'; } // Add the closing 'config' tag to the XML file $contents .= "\n" . '</config>'; // Write the contents to the file if ( fwrite( $fh, $contents ) ) { // Success } else { echo "The XML config could not be created"; } // Close the file fclose($fh); } } // Set the target directory and file name $target_dir = "/usr/local/ezreplay/data/PCAP/"; $basename = basename($_FILES["pcap"]["name"]); $target_file = $target_dir . $basename; // Check if the file has a pcap extension $allowedExtensions = array('pcap'); $basenameWithoutExt = null; foreach ($allowedExtensions as $allowedExtension) { if (preg_match('#\.' . $allowedExtension . '$#',$basename)) { $basenameWithoutExt = substr($basename,0,-1 - strlen($allowedExtension)); break; } } // Accept only .pcap files if (is_null($basenameWithoutExt)) { echo "Sorry, only .pcap files are allowed. Please try creating your Packet Replay again using a .pcap file."; exit; } // Check if the file already exists if (file_exists($target_file)) { echo "The Packet Replay could not be started, the PCAP is already running."; exit; } // Try to upload the file if (move_uploaded_file($_FILES["pcap"]["tmp_name"], $target_file)) { // Success } else { echo "Sorry, there was an error uploading your file."; exit; } // Start the Packet Replay $command = '/usr/local/ezreplay/bin/startreplay.sh ' . $path; system($command); echo "The Packet Replay has been started."; ?>
排查分析
1. 核心条件判断完全不触发
生成XML的代码块被包裹在一个多条件判断里,其中isset($_POST['pcap'])是致命错误:表单上传的文件信息会被PHP存放在$_FILES数组中,而非$_POST,所以这个判断始终为false,导致整个XML生成逻辑完全不执行。
另外$expirydate的初始化存在隐患:如果strtotime($_POST['expirydate'])转换失败(比如日期格式不符合要求),$timestamp会返回false,date()会生成1970年的默认日期,虽然isset($expirydate)为true,但会导致后续XML内容不符合预期。
2. 变量作用域与流程逻辑漏洞
XML生成逻辑中定义的$path变量,后续被用于执行startreplay.sh脚本,但如果XML生成的条件判断不成立,$path未被定义,此时执行system($command)会触发未定义变量错误,但因为没有错误捕获机制,日志也未记录该错误,导致问题被隐藏。
同时,XML生成失败的提示会被后续PCAP上传的流程覆盖——即使XML生成失败,PCAP上传代码仍会继续执行,最终输出成功提示,误导判断。
3. 错误处理缺失
fopen如果失败没有任何错误提示或日志记录fwrite的成功分支无反馈,失败分支的提示会被后续流程覆盖- 未对
$expirydate的有效性做校验
修复方案
1. 修正表单字段判断逻辑
将isset($_POST['pcap'])替换为isset($_FILES['pcap']),同时增加文件上传有效性检查:
// 替换原有的条件判断 if ( isset($_POST['destinationip']) && isset($_POST['destinationport']) && isset($expirydate) && isset($_POST['multiplier']) && isset($_FILES['pcap']) && $_FILES['pcap']['error'] == UPLOAD_ERR_OK ) { // XML生成逻辑 }
2. 完善$expirydate初始化逻辑
增加日期转换有效性检查,避免无效日期进入流程:
if (isset($_POST['expirydate'])) { $timestamp = strtotime($_POST['expirydate']); // 校验日期转换是否成功 if ($timestamp !== false) { $expirydate = date('m/d/Y', $timestamp); } else { echo "Invalid expiration date format"; exit; } } else { echo "Expiration date is required"; exit; }
3. 调整代码执行顺序与错误终止逻辑
将PCAP上传逻辑移至XML生成逻辑之后,或者确保$path在所有分支都有定义;同时在XML生成失败时直接终止流程,避免后续错误执行:
// fwrite失败时终止流程 if (!fwrite( $fh, $contents )) { echo "The XML config could not be created"; fclose($fh); exit; }
4. 添加错误日志记录
在关键步骤添加错误日志,方便后续排查:
// fopen失败时记录日志 if (!($fh = fopen($path,"a+"))) { error_log("Failed to open XML file: " . $path); echo "The XML config could not be created"; exit; }
内容的提问来源于stack exchange,提问作者divad

