从 PHP 函数中删除 eval [关闭]

Posted

技术标签:

【中文标题】从 PHP 函数中删除 eval [关闭]【英文标题】:Removing eval from PHP function [closed] 【发布时间】:2020-12-03 12:07:22 【问题描述】:

我想知道是否有办法从我的代码中删除 eval()

在此函数中,我通过 POST 加载一些变量,以根据管理员在表单中插入的内容在我的数据库中更新或插入新用户。

public function alterUser()

    
    $name = $_POST['name']; //required field 
    $contact = $_POST['contact']; //required field 
    $password = $_POST['password']; //required field 
    
    $string = "DB::table('users')";
    
    if(isset($_POST['id']))
        $string = $string."-> where ('id', \$_POST['id']) ->update([";
    else
        $string = $string."-> insert([";
    
    
    $string = $string."'name' => \$_POST['name'],";
            
    if (isset($_POST['email'])) 
        $string = $string."'email' => \$_POST['email'],";
    
    $string = $string."'password' => Hash::make(\$password),'contacto' => \$contact,";
    
    if (isset($_POST['nif'])) 
        $string = "$string.'nif' => \$nif,";
    
    $string = $string."]);";

    eval($string);
    return redirect('/user');

由于这会打开一些安全漏洞,还有其他替代方法可以使其正常工作吗?

【问题讨论】:

良好的代码缩进将帮助我们阅读代码,更重要的是,它将帮助您调试代码Take a quick look at a coding standard 为您自己的利益。您可能会被要求在几周/几个月内修改此代码,最后您会感谢我的。 谢谢! @RiggsFolly。 每当您有使用eval() 的冲动时,就狠狠地打自己一巴掌,然后尝试另一种方式。特别是这里完全不需要 这里绝对没有理由使用eval()。您可以轻松地将每个字符串的值分配给变量以构建查询构建器对象。哎呀,建立一个值数组,然后决定如何处理它 我还应该提到,*** 并不是真正发布要求代码清理和类似问题的网站。请为此使用 CodeReview:codereview.stackexchange.com。您在此处获得答案的原因是您的问题包含在不必要的情况下使用 eval() 的不安全做法,但通常,这类问题被否决并关闭。 【参考方案1】:

如前所述,这里绝对没有理由使用 eval。你需要做的是建立一个你想要传入的值数组,然后决定它是需要新用户还是更新。

public function alterUser()


    $name = $_POST['name']; //required field
    $contact = $_POST['contact']; //required field
    $password = $_POST['password']; //required field

    $values = [
        'name' => $name,
        'password' => Hash::make($password),
        'contacto' => $contact
    ];

    if (isset($_POST['email'])) 
        $values['email'] = $_POST['email'];
    

    if (isset($_POST['nif'])) 
        $values['nif'] = $_POST['nif'];
    

    if(!empty($_POST['id'])) 
        DB::table('users')->insert($values);
     else 
        DB::table('users')->where('id', $_POST['id'])->update($values);
    
    
    return redirect('/user');

【讨论】:

通过查看文档回答了我自己的问题。使用insert($values) 的工作方式,为什么不直接删除包含数据库调用的 IF 块之前的所有内容,并生成$values = $_POST?当然,在那之后你可以像$values['password'] = Hash::make($values['password']); 那样做任何需要直接改变的事情?这将使代码更干净IMO 我理解你的意思,但是我的 eval 参数是在函数中创建的,怎么会被利用或不安全? @davidsi02 因为您使用用户输入来创建要传递给eval() 的字符串。任何人都可以在该输入框中输入任何内容,这与 SQL 注入类似。 eval 也使代码变得非常混乱和复杂。除非绝对必要,否则不需要它。即便如此,看看是否还有其他方法可以这样做。 @GrumpyCrouton 您可以这样做,但有时 $_POST 包含您可能想要验证但不传递的内容。例如验证密码字段。最后,归结为意图和偏好。【参考方案2】:

您似乎可以大大简化代码,并消除对 eval() 的需求,除非是万不得已,否则您不应该使用它。

您的代码中不需要所有 IF 块,因为如果未设置该值,它也不会添加到 $values 数组中。

只需将您的 $_POST 变量分配给 $values 变量,Laravel 就会为您完成大部分繁重的工作。

public function alterUser()


    $values = $_POST;

    //remove _token variable created by Laravel in all POST requests
    unset($values['_token']); 

    //perform any actions needed on values before being send to database
    $values['password'] = Hash::make($values['password']);

    if(!empty($values['id'])) 
        DB::table('users')->insert($values);
     else 
        DB::table('users')->where('id', $values['id'])->update($values);
    
    
    return redirect('/user');

我在您的代码中看到您将contact 变量重命名为contacto。我建议更改您的表单以匹配此变量名称,但如果这不可能,您仍然可以在设置 $values = $_POST 后重命名它,如下所示:

$values['contacto'] = $values['contact'];
unset($values['contact']);

另外,如果您的表单发送任何您不想发送到数据库的变量,例如“密码验证”字段或类似的东西,那么您可以在设置 $values = $_POST 后取消设置它们,如下所示:

unset($values['VALUE_TO_REMOVE']);

【讨论】:

我试过你的代码,但它返回错误:SQLSTATE[42S22]: Column not found: 1054 Unknown column '_token' in 'field list' 您的$_POST 是否包含名为_token 的密钥?如果是这样,请阅读我的答案中关于删除您不想发送到数据库的变量的部分。 Laravel 中的所有 POST 请求应该包含一个 _token 字段。这是一个 CSRF 令牌,除非明确配置,否则它是必需的并包含在内。 @TimLewis 很好,我建议 OP 将其从 $values 数组中删除,而不是直接从 $_POST 中删除。将其添加到我的答案中,因为 Laravel 会发送此值。 @GrumpyCrouton 是的!我只是澄清_token 字段是什么,因为OP 可能知道也可能不知道它的存在:)【参考方案3】:

@aynber 的一个非常有力的回答 只是为了补充他的答案,我会将逻辑分解为更小的部分以使其更易于阅读。

public function alterUser()

    $values = $this->readPostValues();
    $this->performUpsert($values);

    return redirect('/user');



private function performUpsert(array $values): void

    if (!empty($_POST['id'])) 
        DB::table('users')->insert($values);

        return;
    

    DB::table('users')->where('id', $_POST['id'])->update($values);


private function readPostValues(): array

    $values = [
        'name' => $_POST['name'],
        'password' => $_POST['password'],
        'contacto' => $_POST['contact'],
    ];

    if (isset($_POST['email'])) 
        $values['email'] = $_POST['email'];
    

    if (isset($_POST['nif'])) 
        $values['nif'] = $_POST['nif'];
    

    return $values;

【讨论】:

不错的方法,但你也可以使用 Laravel 的 updateOrInsert() 方法:laravel.com/docs/7.x/queries#updates。您的方法名称 performUpsert() 表明您正在这样做,但需要一些额外的步骤:) 几年没用过laravel,忘记了,谢谢:)

以上是关于从 PHP 函数中删除 eval [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

php - 从json对象中按值删除[关闭]

如何从 Laravel 中的响应 JSON 中删除 HTML 标签 [关闭]

从字符串中删除所有反斜杠 - php - 正则表达式 [关闭]

如何在php中删除从json “x”:“y”到x:y的双引号[关闭]

php.webshell.eval有啥用?

如何从 symfony 中删除树枝? [关闭]