PHP表单验证不起作用 - 几个问题

时间:2012-01-13 20:56:11

标签: php validation

目前我正在尝试使用PHP验证表单。问题是,即使输入错误,PHP也会将其解释为正确。显然我现在不知道为什么,虽然我有一个假设。 这是代码:

if(isset($_GET['contact'])){

    // Validation functions

    // Name
    function validate_name(){
        $name       =   $_POST['customer'];
        if(strlen($name) > 0){
            trim(mysql_real_escape_string($name));
            return true;
        }else {
            return false;
        }
    } 

    // Mail
    function validate_mail(){
        $mail       =   $_POST['mail'];
        if(preg_match('/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/', $mail) && strlen($mail) > 0){
            return true;
        }else {
            return false;
        }
    }

    // Message
    function validate_message(){
        $message    =   $_POST['message'];
        if(strlen($message) > 0){
            trim(mysql_real_escape_string($message));
            return true;
        }else {
            return false;
        }
    }

    validate_name();
    validate_mail();
    validate_message();

    if(validate_name == true && validate_mail == true && validate_message == true){
        echo "Ok!";
    }else{
        echo "Error!";
    }
}

我知道的一件事是坏事:if(validate_name == true && validate_mail == true && validate_message == true){}。 但是,如果我没有弄错,这仍然有效,因为PHP可以处理这样的事情(PHP只给出通知,而不是错误)。但如果做得对,必须有更好的方法?

我发现的第二个问题是,PHP基本上调用函数是正确的,但在函数内部,if-else不起作用。为什么?我不明白这个......

7 个答案:

答案 0 :(得分:3)

到目前为止我看到了3个问题:

  1. 您的函数只返回true或false,而不是修改后的提供变量。此外,变量受功能范围限制,因此如果您只是在内部修改它们并且不返回它们,或者使用全局变量,则在函数外部不可用。 如果你没有返回值,那么,为什么要修剪和转义它们?
  2. mysql_real_escape_string()在连接处于活动状态时有效,否则返回FALSE。
  3. 在你的if()条件中,你正在使用“validate_name”但它的语法是错误的,如果你想把它作为一个变量或一个函数(缺少括号)
  4. 拿你的第一个功能,例如,你可以做(​​如果你有一个有效的连接):

    function validate_name($customer){
            if(strlen($customer) > 0){
                $customer = trim(mysql_real_escape_string($customer));
                return $customer;
            }else {
                return false;
            }
        } 
    

    以及后来:

    if(validate_name($_POST['customer'] AND ....)
    

    我看到的另一件事,因为validate_name()validate_message()正在执行相同的操作,为什么不将它作为单个函数(例如validate($postIndex)),将$ _POST索引作为参数?它更干一点。像:

    $name = validate($_POST['customer']);
    $message = validate($_POST['message']);
    $email = validate_email($_POST['email']);
    if($name AND $email AND $message){
    
    // now here you also have the trimmed/escaped values to work with.
    }
    

答案 1 :(得分:3)

第一个问题是,你的函数返回一个布尔结果,它们不会持久地表示一个值。你是否条件基本上只是检查是否定义了常量“validate_name”,“validate_mail”和“validate_message”。遇到未定义的常量时,PHP会将常量设置为等于自身。然后类型强制将字符串值“validate_name”,“validate_mail”和“validate_message”与true进行比较,这是通过将布尔值和字符串值都转换为1值来实现的。然后他们被认为是平等的。

你应该做的是:

$isNameOk = validate_name();
$isMessageOk = validate_message();
$isMailOk = validate_mail();

if($isNameOk && $isMessageOk && $isMailOk)
    echo "Ok!";
else
    echo "Error!";

第二个不相关的错误就是你正在做的功能。你在函数的范围内设置$ name,$ mail和$ message等变量(这很好),但是你也可以在它们上发出trim和mysql_escape,而实际上将值设置回变量。即它应该是:

$name = trim(mysql_escape_string($name));

最重要的是,您将这些值清理剂应用于您的变量,但您的函数实际上并未对这些变量执行任何操作。我假设您希望稍后在脚本中使用已清理的$ name,$ mail和$ message变量。但是因为它们在本地函数范围内定义,永远不会起作用。

快速解决方法是在全局范围内定义变量,并使用全局关键字在函数中引用它们,但这很难看。更好的解决方案是对代码进行客观化,并使这些值和函数成为类对象的成员。

class Validator {
    protected $name;
    protected $isNameOk;
    protected $mail;
    protected $isMailOk;
    protected $message;
    protected $isMessageOk;

    public function validate($data) {
         $this->isNameOk = $this->checkAndSanitizeName($data['name']);
         $this->isMessageOk = $this->checkAndSanitizeMessage($data['message']);
         $this->isMailOk = $this->checkAndSanitizeMail($data['mail']);
         if($this->isNameOk && $this->isMessageOk && $this->isMailOk)
             return true;
         return false;
    }

    protected function checkAndSanitizeName($name) {
        $this->name = trim(mysql_real_escape_string($name));
        if(strlen($name) > 0)
            return true;
        return false;
    }

    protected function checkAndSanitizeMail($mail) {
        $this->mail = trim(mysql_real_escape_string($mail));
        if(preg_match('/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/', $this->mail) && strlen($this->mail) > 0)
            return true;
        return false;
    }

    protected function checkAndSanitizeMessage($message) {
        $this->message = trim(mysql_real_escape($mail));
        if(strlen($this->message) > 0)
            return true;
        return false;
    }

    public function getName() { return $this->name; }
    public function getMail() { return $this->mail; }
    public function getMessage() { return $this->message; }
    public function isMailOk() { return $this->isMailOk; }
    public function isNameOk() { return $this->isNameOk; }
    public function isMessageOk(){ return $this->isMessageOk; }
}

用法是:

$validator = new Validator();
if($validator->validate($_POST))
{
    echo "Ok!";
    echo "Thanks " . $validator->getName() . " for posting your message.";
}
else
{
    echo "Error!";
    if(!$validator->isMailOk())
        echo "Mail was invalid";
    // etc.
}

我在回复框中输出了这个代码,所以请把它拿出来。可能需要一些拼写错误。

答案 2 :(得分:2)

行。由于是周末,我没有更好的事情要做,我将解决您的问题,并解释您的代码有什么问题。

首先回答您的原始问题:

  

PHP只发出通知

正如通知所述:

  

注意:使用未定义的常量validate_name - 在...中假定为'validate_name'

这是因为您所在的行:

if(validate_name == true ...

validate_name没什么。如果它是一个变量,如果它是一个函数调用它将是$validate_name,它应该是validate_name()。所以PHP认为它是一个常数。没有咆哮这是否是PHP试图“帮助”你的聪明举动它做它做的。因此,PHP基本上将其作为常量处理,其值为validate_name

PHP的作用如下:

if ('somestring' == true) // this will always be truthy.

现在进一步修复/改进您的代码:

我也不确定你对超全球的使用。您使用$_GET['contact']$_POST['customer']。因此,您要混合_POST_GET。不过这可能是不正确的。

如果您的表单的动作为“/file.php?contact=something”且表单方法设置为post,则表示完全没问题。


最好将params添加到函数中。所以改变:

function validate_name(){

function validate_name($name){

而不是依赖_POST值。这样您就可以在不需要任何后期数据的情况下测试代码。


在您的validate_namevalidate_message功能中,您正在执行此操作:

trim(mysql_real_escape_string($name));
trim(mysql_real_escape_string($message));

这有两个问题:

  1. 它仅在功能范围内可用,而您没有返回它(所以为什么要这样做)
  2. 函数名称表示它验证,而不是它执行其他操作。

  3. 在验证邮件功能中,您可以执行以下操作:

    if(preg_match('/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/', $mail) && strlen($mail) > 0){
    

    除了我确信正则表达式没有获得所有有效的电子邮件地址之外,最好首先检查字符串是否已填写。


    现在在以下代码中更正所有问题:

    if(isset($_GET['contact'])){
    
        function validate_name($name)
        {        
            if(strlen($name) === 0) {
                return false;
            }
    
            return true;
        } 
    
        function validate_mail($mail)
        {
            if (strlen($mail) === 0 || filter_var($mail, FILTER_VALIDATE_EMAIL)) {
                return false;
            }
    
            return true;
        }
    
        function validate_message($message)
        {
            if(strlen($message) === 0) {
                return false;
            }
    
            return true;
        }
    
        if(validate_name($_POST['customer']) && validate_mail($_POST['mail']) && validate_message($_POST['message'])) {
            echo "Ok!";
        } else {
            echo "Error!";
        }
    }
    

答案 3 :(得分:2)

  1. validate_name == true更改为validate_name()。这将调用该函数并返回布尔值。无需将已经是布尔值的东西与另一个布尔值进行比较以生成布尔值...只需使用返回的值即可。对其他两个函数做同样的事情。
  2. 在您的功能中,您正在调用函数trim()mysql_real_escape_string(),但您没有保存这些更改。这些不是通过引用传递的,因此您需要将更改保存回$_POST变量。
  3. 这是更新后的代码:

    if(isset($_GET['contact'])){ 
    
        // Validation functions 
    
        // Name 
        function validate_name(){ 
            $name       =   $_POST['customer']; 
            if(strlen($name) > 0){ 
                $_POST["customer"] = trim(mysql_real_escape_string($name)); 
                return true; 
            }else { 
                return false; 
            } 
        }  
    
        // Mail 
        function validate_mail(){ 
            $mail       =   $_POST['mail']; 
            if(preg_match('/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/', $mail) && strlen($mail) > 0){ 
                return true; 
            }else { 
                return false; 
            } 
        } 
    
        // Message 
        function validate_message(){ 
            $message    =   $_POST['message']; 
            if(strlen($message) > 0){ 
                $_POST["message"] = trim(mysql_real_escape_string($message)); 
                return true; 
            }else { 
                return false; 
            } 
        }
    
        if(validate_name() && validate_mail() && validate_message()){ 
            echo "Ok!"; 
        }else{ 
            echo "Error!"; 
        } 
    } 
    

答案 4 :(得分:1)

看起来好像你没有调用你在if-block中编写的函数。你也可以简写那句话。

if( validate_name() && validate_mail() && validate_message() ) {echo 'Ok!';}

因为所有这些都返回布尔结果,所以if语句不需要显式== true检查。此外,您还需要小心清理任何GET / POST变量。

答案 5 :(得分:1)

您需要稍微更改代码的最后一位。像这样:

if(validate_name() && validate_mail() && validate_message()){
    //do stuff with the info here
}else{
    echo "Error!";
    //display error information and show them the form again.
}

答案 6 :(得分:1)

你可以这样做:
它不是最好的解决方案,但没有显示通知或错误。快乐的编码。

if(isset($_GET['contact'])){
    // Validation functions
    // Name
    function validate_name(){
        if(!isset($_POST['customer'])) {
            return false;
        }
        if(strlen($_POST['customer']) > 0){
            $_POST['customer'] = trim($_POST['customer']);
            return true;
        }else {
            return false;
        }
    } 

    // Mail
    function validate_mail(){
        if(!isset($_POST['mail'])) {
            return false;
        }
        return preg_match('/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/', $_POST['mail']);

    }

    // Message
    function validate_message(){
        if(!isset($_POST['message'])) {
            return false;
        }
        if(strlen($_POST['message']) > 0){
            $_POST['message'] = trim($_POST['message']);
            return true;
        } else {
            return false;
        }
    }

    if(validate_name() == true && validate_mail() == true && validate_message() == true){
        echo "Ok!";
    }else{
        echo "Error!";
    }
}