PHP表单提交跳转错误页 邮件未发送问题排查
问题描述
- 查阅过站内大量同类问题的修复方案后,表单提交功能仍异常:提交后直接跳转错误页面,无邮件发出。代码中已隐藏个人邮箱信息,实际
$webmaster_email参数配置的是hotmail.com后缀的有效可接收邮箱。 - 因表单代码过长未完整附出,该表单包含大量脚本逻辑,可根据单选框、下拉菜单的选项动态显示/隐藏对应表单区块,目前前端交互效果完全符合预期。
- 表单前端脚本已针对部分输入项配置了required必填校验,暂不确定是否需要在发送邮件的PHP文件中补充相同的校验逻辑。
关联代码:landformsend_mail.php 完整代码
<?php /* This first bit sets the email address that you want the form to be submitted to. You will need to change this value to a valid email address that you can access. */ $webmaster_email = "email@hotmail.com"; /* This bit sets the URLs of the supporting pages. If you change the names of any of the pages, you will need to change the values here. */ $feedback_page = "landformtest.php"; $error_page = "landform_not_sent.html"; $thankyou_page = "landform_thank_you.html"; /* This next bit loads the form field data into variables. If you add a form field, you will need to add it here. */ $Name = $_REQUEST['Name'] ; $ifowner = $_REQUEST['ifowner'] ; $actualowner = $_REQUEST['actualowner'] ; $Email = $_REQUEST['Email'] ; $Phone = $_REQUEST['Phone'] ; $timezone = $_REQUEST['timezone'] ; $callafter = $_REQUEST['callafter'] ; $callbefore = $_REQUEST['callbefore'] ; $street = $_REQUEST['street'] ; $city = $_REQUEST['city'] ; $county = $_REQUEST['county'] ; $state = $_REQUEST['state'] ; $zipcode = $_REQUEST['zipcode'] ; $apn = $_REQUEST['apn'] ; $parcelsize = $_REQUEST['$parcelsize'] ; $landunits = $_REQUEST['$landunits'] ; $access = $_REQUEST['access'] ; $roadowner = $_REQUEST['roadowner'] ; $roadtype = $_REQUEST['roadtype'] ; $othersurfacedetails = $_REQUEST['othersurfacedetails'] ; $easedescr = $_REQUEST['easedescr'] ; $tempaccess = $_REQUEST['tempaccess'] ; $tempaccessdetails = $_REQUEST['tempaccessdetails'] ; $ifsurvey = $_REQUEST['ifsurvey'] ; $datesurvey = $_REQUEST['datesurvey'] ; $ifperc = $_REQUEST['ifperc'] ; $dateperc = $_REQUEST['dateperc'] ; $septicpermit = $_REQUEST['septicpermit'] ; $ifflood = $_REQUEST['ifflood'] ; $ifelectric = $_REQUEST['ifelectric'] ; $offgridelectric = $_REQUEST['offgridelectric'] ; $altelecticdetails = $_REQUEST['altelectricdetails'] ; $ifwater = $_REQUEST['ifwater'] ; $datewell = $_REQUEST['datewell'] ; $potablewellwater = $_REQUEST['potablewellwater'] ; $ifsewer = $_REQUEST['ifsewer'] ; $dateseptic = $_REQUEST['dateseptic'] ; $currentzoning = $_REQUEST['currentzoning'] ; $futurezoning = $_REQUEST['futurezoning'] ; $futurezoningdetails = $_REQUEST['futurezoningdetails'] ; $restrictions = $_REQUEST['restrictions'] ; $restrictiondetails = $_REQUEST['restrictiondetails'] ; $farming = $_REQUEST['farming'] ; $somefarmingdetails = $_REQUEST['somefarmingdetails'] ; $landuse = $_REQUEST['landuse'] ; $description = $_REQUEST['description'] ; $msg = "Name: " . $Name . "\r\n" . "If owner: " . $ifowner . "\r\n" . "Actual owner: " . $actualowner . "\r\n" . "Email: " . $Email . "\r\n" . "Phone: " . $Phone . "\r\n" . "Time zone: " . $timezone . "\r\n" . "Call after: " . $callafter . "\r\n" . "But before: " . $callbefore . "\r\n" . "Property street address: " . $street . "\r\n" . "Property city: " . $city . "\r\n" . "Propety county: " . $county . "\r\n" . "Property state: " . $state . "\r\n" . "Property zipcode: " . $zipcode . "\r\n" . "APN: " . $apn . "\r\n" . "Parcel size: " . $parcelsize . "\r\n" . "Land units: " . $landunits . "\r\n" . "Access to land: " . $access . "\r\n" . "Road owner: " . $roadowner . "\r\n" . "Road surface type: " . $roadtype . "\r\n" . "Other surface type: " . $othersurfacedetails . "\r\n" . "Details of easement: " . $easedescr . "\r\n" . "Is temporary access available?: " . $tempaccess . "\r\n" . "Temporary access details: " . $tempaccessdetails . "\r\n" . "Has a survey been done? : " . $ifsurvey . "\r\n" . "Date of survey: " . $datesurvey . "\r\n" . "Has a perc test been done? : " . $ifperc . "\r\n" . "Date of perc test: " . $dateperc . "\r\n" . "Is there a septic permit? : " . $septicpermit . "\r\n" . "Is the land within a flood zone? : " . $ifflood . "\r\n" . "Is there electric? : " . $ifelectric . "\r\n" . "Is there an alternate source of electricity? : " . $offgridelectric . "\r\n" . "Details of the alt electric source: " . $altelecticdetails . "\r\n" . "Is there water? : " . $ifwater . "\r\n" . "Date well drilled: " . $datewell . "\r\n" . "Is the water drinkable? : " . $potablewellwater . "\r\n" . "Is there a sewer system? : " . $ifsewer . "\r\n" . "Date septic system was installed: " . $dateseptic . "\r\n" . "Current land zoning: " . $currentzoning . "\r\n" . "Are there plans to change the zoning?: " . $futurezoning . "\r\n" . "Details of future zoning: " . $futurezoningdetails . "\r\n" . "Are there any Use restrictions? : " . $restrictions . "\r\n" . "Details of any restrictions: " . $restrictiondetails . "\r\n" . "Is farming permitted? : " . $farming . "\r\n" . "Details of any farming restrictions: " . $somefarmingdetails . "\r\n" . "What is the land being used for at this time? : " . $landuse . "\r\n" . "Description of land: " . $description ; /* The following function checks for email injection. Specifically, it checks for carriage returns - typically used by spammers to inject a CC list. */ function isInjected($str) { $injections = array('(\n+)', '(\r+)', '(\t+)', '(%0A+)', '(%0D+)', '(%08+)', '(%09+)' ); $inject = join('|', $injections); $inject = "/$inject/i"; if(preg_match($inject,$str)) { return true; } else { return false; } } // If the user tries to access this script directly, redirect them to the feedback form, if (!isset($_REQUEST['Email'])) { header( "Location: $error_page" ); } // If the form fields are empty, redirect to the error page. elseif (empty($Name) || empty($Email) || empty($city) || empty($county) || empty($state)) { header( "Location: $error_page" ); } /* If email injection is detected, redirect to the error page. If you add a form field, you should add it here. */ elseif ( isInjected($Email) || isInjected($Name) || isInjected($ifowner) || isInjected($actualowner) || isInjected($Phone) || isInjected($timezone) || isInjected($callafter) || isInjected($callbefore) || isInjected($street) || isInjected($city) || isInjected($county) || isInjected($state) || isInjected($zipcode) || isInjected($apn) || isInjected($parcelsize) || isInjected($landunits) || isInjected($access) || isInjected($roadowner) || isInjected($roadtype) || isInjected($othersurfacedetails) || isInjected($easedescr) || isInjected($tempaccess) || isInjected($tempaccessdetails) || isInjected($ifsurvey) || isInjected($datesurvey) || isInjected($ifperc) || isInjected($dateperc) || isInjected($septicpermit) || isInjected($ifflood) || isInjected($ifelectric) || isInjected($offgridelectric) || isInjected($altelecticdetails) || isInjected($ifwater) || isInjected($datewell) || isInjected($potablewellwater) || isInjected($ifsewer) || isInjected($dateseptic) || isInjected($currentzoning) || isInjected($futurezoning) || isInjected($futurezoningdetails) || isInjected($restrictions) || isInjected($restrictiondetails) || isInjected($farming) || isInjected($somefarmingdetails) || isInjected($landuse) || isInjected($description) ) { header( "Location: $error_page" ); } // If we passed all previous tests, send the email then redirect to the thank you page. else { mail( "$webmaster_email", "Landform Results", $msg ); header( "Location: $thankyou_page" ); } ?>
问题排查结果&修复方案
- 核心触发原因:接收表单参数时,
parcelsize和landunits两个字段的键名多写了多余的$符号,和前端实际传的字段名不匹配,导致两个变量取值为空,直接触发空值校验逻辑跳转错误页。将这两行的键名去掉$即可:// 修正前 $parcelsize = $_REQUEST['$parcelsize'] ; $landunits = $_REQUEST['$landunits'] ; // 修正后 $parcelsize = $_REQUEST['parcelsize'] ; $landunits = $_REQUEST['landunits'] ; - 后端校验必须补充:前端的required校验仅对正常操作的用户生效,恶意用户可以直接通过浏览器控制台绕过前端校验提交非法请求,后端必须配置和前端一致的必填校验、格式校验规则,不能依赖前端校验结果。
- 邮件发送逻辑优化:PHP原生
mail()函数默认无SMTP认证配置,向hotmail这类有严格反垃圾规则的邮箱发信时,大概率会被直接拦截拒收,即使校验通过也可能收不到邮件。建议替换为带SMTP认证的发信方式,配置正确的发件服务器地址、账号、密码、加密端口。 - 代码逻辑补全:所有
header()跳转语句后必须加exit;终止后续代码执行,避免出现逻辑漏洞。 - 细节修正:拼接邮件正文时将
Propety county的拼写错误修正为Property county,避免收到的邮件内容出现错别字。
内容的提问来源于stack exchange,提问作者Dragonwalker
相关产品推荐
相关产品推荐

