【问题标题】:PHP script allowing empty (blank) fields to databasePHP脚本允许空(空白)字段到数据库
【发布时间】:2017-09-01 15:58:22
【问题描述】:

编辑:修改代码以包含 $errors 变量。请让我知道这是否可行,谢谢。

我是 PHP 和 MySQL 的新手。我的 Web 表单中有以下 php 代码,当任何 Web 字段为空白或格式不正确时,我在将新记录插入数据库时​​遇到问题。

我进行了错误检查,在按下提交按钮后会以红色显示错误消息,并且数据为空白或格式不正确。这部分工作正常,问题是当存在空白/格式不正确的值时,它仍然允许记录发布到数据库。我想添加一些脚本来检查是否有任何必填字段为空白或格式不正确,如果是,请不要继续执行 SQL 插入。如果有人可以帮助我添加我应该添加的脚本,我将不胜感激。下面是我正在使用的代码,谢谢!

<!DOCTYPE HTML>  
<html>
<head>
<style>
.error {color: #FF0000;}
</style>
</head>
<body>  

<?php
<?php

 $errors = "false";
// define variables and set to empty values
$nameErr = $emailErr = $genderErr = $websiteErr = $subErr = "";
$name = $email = $gender = $comment = $website = $sub = $newrecord = "";

if ($_SERVER["REQUEST_METHOD"] == "POST") {
  if (empty($_POST["Name"])) {
    $nameErr = "Name is required";
    $errors = "true";
  } else {
    $name = test_input($_POST["Name"]);
    // check if name only contains letters and whitespace
    if (!preg_match("/^[a-zA-Z ]*$/",$name)) {
      $nameErr = "Only letters and white space allowed";
      $errors = "true"; 
    }
  }

  if (empty($_POST["Email"])) {
    $emailErr = "Email is required";
    $errors = "true";
  } else {
    $email = test_input($_POST["Email"]);
    // check if e-mail address is well-formed
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
      $emailErr = "Invalid email format";
      $errors = "true"; 
    }
  }

  if (empty($_POST["Website"])) {
    $website = "";
  } else {
    $website = test_input($_POST["Website"]);
    // check if URL address syntax is valid (this regular expression also allows dashes in the URL)
    if (!preg_match("/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i",$website)) {
      $websiteErr = "Invalid URL";
      $errors = "true"; 
    }
  }

  if (empty($_POST["Comment"])) {
    $comment = "";
  } else {
    $comment = test_input($_POST["Comment"]);
  }

  if (empty($_POST["gender"])) {
    $genderErr = "Gender is required";
    $errors = "true";
  } else {
    $gender = test_input($_POST["gender"]);
  }

if (empty($_POST["Subscription"])) {
    $subErr = "Subscription is required";
    $errors = "true"; }
 else {
    $sub = test_input($_POST["Subscription"]);
    }
}

function test_input($data) {
  $data = trim($data);
  $data = stripslashes($data);
  $data = htmlspecialchars($data);
  return $data;
}
?>

<h2>Southern Tier Daily News</h2>
<form method="post" action="Newspaper3.php">
<input type="hidden" name="submitted" value="true"/>

<img src="https://bloximages.newyork1.vip.townnews.com/dnews.com/content/tncms/custom/image/5eec4204-483e-11e6-93c8-97ef236dc6c5.jpg?_dc=1468334339" alt="HTML5 Icon" style="width:128px;height:128px;">
    <p><span class="error">* required field.</span></p>
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
<fieldset>
 <legend>Newspaper Subscription Request</legend>  
  Name: <input type="text" name="Name" value="<?php echo $name;?>">
  <span class="error">* <?php echo $nameErr;?></span>
  <br><br>
  E-mail: <input type="text" name="Email" value="<?php echo $email;?>">
  <span class="error">* <?php echo $emailErr;?></span>
  <br><br>
  Website: <input type="text" name="Website" value="<?php echo $website;?>">
  <span class="error"><?php echo $websiteErr;?></span>
  <br><br>
  Comment: <textarea name="Comment" rows="5" cols="40"><?php echo $comment;?></textarea>
  <br><br>
  Gender:
  <input type="radio" name="gender" <?php if (isset($gender) && $gender=="female") echo "checked";?> value="female">Female
  <input type="radio" name="gender" <?php if (isset($gender) && $gender=="male") echo "checked";?> value="male">Male
  <span class="error">* <?php echo $genderErr;?></span>
    <br><br>
  Subscription:
   <select name="Subscription">
       <option value=""></option>
   <option value="Daily">Daily</option>
   <option value="Evening">Evening</option>
   <option value="Weekly">Weekly</option>
   <option value="Monthly">Monthly</option>
</select> 
  <span class="error">* <?php echo $subErr;?></span>

  <br><br>
  <input type="submit" name="submit" value="Submit"> 
<br><br>
<a href="https://www.google.com/">Visit Admin Page</a>
 </fieldset>
</form>



<?php

 if (isset($_POST['submitted'])) {
    and $errors = "False"
    include('connect-mysql.php');



$fname = $_POST['Name'];
$femail = $_POST['Email'];
$fcomment = $_POST['Comment'];
$fsubsciption = $_POST['Subscription'];
$sqlinsert = "INSERT INTO subscriptions (Name, Email, Comment, Subscription) VALUES ('$fname',
'$femail', '$fcomment', '$fsubsciption')";

      if (!mysqli_query($dbcon, $sqlinsert))  {
           die(mysqli_error($dbcon)); // and die('error inserting new record'); ;       

  }     // end of nested if statement

  // else
        $newrecord = "1 record added to the database";

}  // end of main if statement

?>

<?php

echo $newrecord

?>



</body>
</html>

【问题讨论】:

  • 将所有错误消息存储在一个数组中会更容易。如果数组为空,则插入数据库中,如果数组不为空,则显示错误消息。另请注意,您对 SQL 注入持开放态度
  • 您的代码容易受到 SQL 注入攻击。您应该使用参数化查询和准备好的语句来帮助防止攻击者通过使用恶意输入值来破坏您的数据库。 bobby-tables.com 给出了风险解释,以及一些如何使用 PHP / mysqli 安全地编写查询的示例。
  • 我认为您可以从更好的代码组织开始,使其更加清晰/简单。

标签: php mysql wamp


【解决方案1】:

尝试在您的 SQL 语句中使用经过验证的字段值,而不是再次使用 $_POST 变量 - 如果该字段不存在,请不要运行查询。

或者,如果在脚本开头发现任何错误,请不要运行 SQL 语句。为此,我会这样做:

  • 在脚本开始时将变量 $errors 设置为 false
  • 无论何时发现任何错误,将$errors 变量设置为true
  • 在脚本末尾,您有 if (isset($_POST['submitted'])),在实际运行插入之前还要检查 $errors 是否为 false。

希望对您有所帮助。

【讨论】:

  • 感谢 Lorna,我修改了上面的代码以包含 $errors 变量。你能告诉我这是否正确(语法,逻辑)吗?谢谢!
  • 我在代码部分遇到语法错误,其中 IF (isset($_POST['submitted'])) 我包含了一个 And 函数来检查 $errors 是否为假。不过我一定是语法错误...?
  • @Kevin if (isset($_POST['submitted'])) { and $errors = "False" 应该是 if (isset($_POST['submitted']) &amp;&amp; $errors == "false") {。您将第二位放在if 的括号外,它是&amp;&amp; 不是and,也是$errors = "False" 设置 变量,而是===== _compares变量到另一个值。 (我会把它留给你用谷歌搜索 == 和 === 之间的区别,它可能很有用)。此外,将 $errors 设置为布尔值 truefalse 比字符串 "True""False" 值更健壮。尤其是因为套管 - "false" != "False"!
  • @Kevin 也许值得花时间学习一些 PHP 语法的基础知识。此外,您上面的代码也不是很合乎逻辑,您用一些标记随机分解 PHP,这很奇怪,因为它并没有真正反映程序的流程。
  • @ADyson 感谢您提供正确的语法和附加信息。现在可以按预期工作了!
【解决方案2】:

在上面的代码中,您在插入之前没有检查无效数据。您只需检查错误并绕过它并存储在数据库中。所以修改了if条件如下。

if (isset($_POST['submitted']) && empty($err_array))

在 $err_array 中存储错误值而不是单个变量。

【讨论】:

  • 谢谢。您介意分享我应该在脚本中如何以及在何处定义数组以及在其中插入哪些值吗?这对我来说是新的,我还没有使用过数组。
  • if (isset($_POST['submitted'])) { 和 $errors = "False" 如下更新这一行。 if(isset($_POST['submitted'] ) && $errors == "False") 这也可以解决你的问题
【解决方案3】:

为了清楚起见,我将您的 php 从您的 html 中分离出来。首先也是最重要的,正如上面所指出的,您容易受到 SQL 注入攻击,请使用标记化参数和准备好的语句来帮助保护您免受此问题的影响(示例如下)。

关于您的问题,我建议您尝试在您的工作流程中添加一些异常处理。如果您刚刚开始,这可能看起来有点吓人,但只要您知道您的开发服务器的错误日志文件在哪里,它就提供了一种快速简洁的方法来查看发生了什么问题,最终也会为您服务生产环境。

就处理空表单字段而言,您可以在此处采用多通道方法,HTML5 forms 允许您根据需要指定字段并阻止执行无效表单。 Javascript validation 是客户端的另一个选项。不过,在服务器端验证和清理数据总是好的,对于这个 php 有一些有用的工具(filter_varfilter_input)来帮助完成这项任务,另外还有所有的请求/服务器超全局变量是可迭代的,因此您可以循环它们并避免重复代码,而不是设置条件链。

PHP

<?php
$newRecord = false;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    try {
        list($errors, $inputs) = cleanInputs($_POST);

        if (!$errors['valid']) {
            throw new Exception(json_encode($errors));
        }
        
        // using instantiation in the same file for the example.
        $mysqli = new mysqli('host', 'user', 'password', 'schema');
        if (!$mysqli) {
            throw new Exception("({$mysqli->connect_errno}) {$mysqli->connect_error}");
        }
        // why is your form asking for Gender and URL if you aren't using them?
        $insertQuery = "INSERT INTO subscriptions (Name, Email, Comment, Subscription) VALUES (?, ?, ?, ?)";
        $stmt = $mysqli->prepare($insertQuery);

        if (!$stmt) {
            throw new Exception("({$mysqli->errno}) {$mysqli->error}");
        }
        
        $stmt->bind_param('ssss', $inputs['Name'], $inputs['Email'], $inputs['Comment'], $inputs['Subscription']);
        $stmt->execute();

        $newRecord = ($stmt->affected_rows > 0) ? 'Record added to database' : 'Record failed to insert to database';
    } catch (Exception $e) {
        // Here is where you would set your error variables for the html form.
        error_log($e);
    }
}

function cleanInputs($inputs)
{
    $keys = ['Name', 'Email', 'Website', 'Comment', 'Subscription',];
    $clean = [];
    $errors = ['valid' => true];
    foreach ($keys as $key) {
        if (empty($inputs[$key])) {
            $errors[$key] = "{$key} is required";
            $errors['valid'] = false;
            continue;
        }
        if (in_array($key, ['Name', 'Comment', 'Subscription', 'Gender'])) {
            $clean[$key] = trim(filter_var($inputs[$key], FILTER_SANITIZE_STRING));
            continue;
        } else if ($key === 'Email') {
            $filter = filter_var($inputs[$key], FILTER_VALIDATE_EMAIL);
            if (!$filter) {
                $errors[$key] = 'Invalid email format';
                $errors['valid'] = false;
                continue;
            }
            $clean[$key] = trim($filter);
        } else if ($key === 'Website') {
            $filter = filter_var($inputs[$key], FILTER_VALIDATE_URL);
            if (!$filter) {
                $errors[$key] = 'Invalid URL Format';
                $errors['valid'] = false;
                continue;
            }
            $clean[$key] = trim($filter);
        }
    }
    return [$errors, $clean];
}
?>

编辑

展开以帮助回答以下问题。

cleanInputs() 方法将返回干净的键和任何错误,因此在您的 catch 中,您需要填写这些错误变量。我可能建议在处理之前在文件顶部设置默认输入值如果它们需要存在,则在错误处理程序中重置它们。

<?php 
$newRecord = false;
$name = ''; 
$email = ''; 
$website = ''; 
$comment = ''; 
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// ... back to original example

然后使用一些错误处理程序条件更新您的 HTML,使用 alternative syntax(个人意见,如果您必须将逻辑放入模板中,对我来说看起来更干净)

<label for="Name">Name: </label>
<input type="text" name="Name" value="<?= $name ?>">
<?php if (isset($nameErr) && $nameErr !== false) : ?>
  <span class="error">* <?= $nameErr ?></span>
<?php endif; ?>
<br><br>

并更新您的 catch 语句

} catch (Exception $e) {
  if (!$errors['valid']) {
    // repeat for errors.
     $nameErr = (isset($errors['Name'])) ? $errors['Name'] : false;
     if (!$nameErr) {
       $name .= $inputs['Name'];
     }
  }

  error_log($e);
}

【讨论】:

  • @D Lowther 感谢所有的洞察力。由于我是 php 新手,我仍在学习基础知识。我正在查看您的代码(答案),并想知道您是否在下面的评论中写了我是否需要修改表单上的 html 变量,以及我应该将它们称为什么? } catch (Exception $e) { // 您可以在此处为 html 表单设置错误变量。 error_log($e);
  • 在 cleanInputs 方法中,您会注意到它返回一个干净的输入数组和一个错误数组。如果你点击了 catch 块,你需要遍历错误数组(可能还有干净的值数组来设置可回显变量。你可以使用你现在拥有的东西,你只需要设置它。我会添加一个编辑举个例子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-26
相关资源
最近更新 更多