【问题标题】:Remove all array elements except what I want?删除除我想要的所有数组元素吗?
【发布时间】:2012-04-12 11:39:26
【问题描述】:

我有一个控制器,它从 HTML 表单中获取 post 参数,然后它将它们发送到模型,该模型将数组插入 Cassandra 数据库。

它是 SQLInjection 证明,因为它是 NoSQL,但我担心用户可以只模拟 100k 的 post 参数,或者只是添加一些我不需要的参数,它将被插入到数据库中。如何确保只有我需要的值会保留在我的数组中。

例子:

$post = ['parent_id', 'type', 'title', 'body', 'tags']; // Good
$post = ['parent_id', 'type', 'title', 'body', 'tags', 'one', 'two', 'three'] // Bad

如何确保我的数组将取消设置所有不在 good 示例中的元素?

【问题讨论】:

    标签: php arrays


    【解决方案1】:

    通过将您确实期望的条目列入白名单。

    <?php
    $post = array( 
        'parent_id' => 1,
        'type' => 'foo', 
        'title' => 'bar', 
        'body' => 'foo bar', 
        'tags' => 'foo, bar', 
        'one' => 'foo',
        'two' => 'bar',
        'three' => 'qux'
    );
    
    $whitelist = array(
        'parent_id',
        'type',
        'title',
        'body',
        'tags'
    );
    
    $filtered = array_intersect_key( $post, array_flip( $whitelist ) );
    
    var_dump( $filtered );
    

    无论如何,使用 Cassandra 作为数据存储当然不是不对您收到的数据进行验证的理由。

    【讨论】:

      【解决方案2】:

      您正在寻找array_intersect:

      $good = ['parent_id', 'type', 'title', 'body', 'tags'];
      $post = ['parent_id', 'type', 'title', 'body', 'tags', 'one', 'two', 'three'];
      
      print_r(array_intersect($good, $post));
      

      See it in action.

      当然这个具体的例子没有多大意义,因为它适用于数组values,但也有array_intersect_key基于键做同样的事情。

      【讨论】:

      • @Qmal: $good 有很好的名称作为,而$post 有它们作为。最简单的解决方法是传入array_flip($good) 而不是$good,以便两个输入都具有好名称作为键。
      • 答案和 cmets 中的键盘链接已恢复为默认的“hello world”脚本。 :-(
      【解决方案3】:

      多维数组呢?我为这个解决方案研究了几个小时,没有找到最佳解决方案。所以,我自己写的

      function allow_keys($arr, $keys)
          {
              $saved = [];
      
              foreach ($keys as $key => $value) {
                  if (is_int($key) || is_int($value)) {
                      $keysKey = $value;
                  } else {
                      $keysKey = $key;
                  }
                  if (isset($arr[$keysKey])) {
      
                      $saved[$keysKey] = $arr[$keysKey];
                      if (is_array($value)) {
      
                          $saved[$keysKey] = allow_keys($saved[$keysKey], $keys[$keysKey]);
                      }
                  }
              }
              return $saved;
          }
      

      使用:示例

      $array = [
              'key1' => 'kw',
              'loaa'=> ['looo'],
              'k'    => [
                  'prope' => [
                      'prop'  => ['proo', 'prot', 'loolooo', 'de'],
                      'prop2' => ['hun' => 'lu'],
                  ],
                  'prop1' => [
      
                  ],
              ],
          ];
      

      调用:示例

      allow_keys($array, ['key1', 'k' => ['prope' => ['prop' => [0, 1], 'prop2']]])
      

      输出:

      Array ( [key1] => kw [k] => Array ( [prope] => Array ( [prop] => Array ( [0] => proo [1] => prot ) [prop2] => Array ( [hun] => lu ) ) ) ) 
      

      所以你从多维数组中只得到需要的键。它不仅限于“多维”,您可以通过传递类似的数组来使用它

      ['key1', 'loaa']
      

      你得到的输出:

      Array ( [key1] => kw [loaa] => Array ( [0] => looo ) )
      

      干杯!

      【讨论】:

        【解决方案4】:

        这将输出与 $post_allowed 相同的内容。它所做的只是允许 $post_input 中的值也存在于 $post_allow 中。

        $post_allowed = ['parent_id', 'type', 'title', 'body', 'tags'];
        $post_input   = ['parent_id', 'type', 'title', 'body', 'tags', 'one', 'two', 'three'];
        $post = array_intersect($post_input, $post_allowed);
        

        【讨论】:

          【解决方案5】:

          这称为白名单,您的示例具有误导性,因为 $_POST 是一个关联数组。

          $post = [
              'parent_id' => 'val',
              'type' => 'val',
              'title' => 'val',
              'body' => 'val',
              'tags' => 'val',
              'one' => 'val',
              'two' => 'val',
              'three'=>'val',
          ];
          
          $whitelist = ['parent_id', 'type', 'title', 'body', 'tags'];
          
          $sanitized_post = array_whitelist_assoc($post, $whitelist);
          

          这是我为关联数组创建的白名单函数。

          if(!function_exists('array_whitelist_assoc')){
          
              /**
               * Returns an associative array containing all the entries of array1 which have keys that are present in all the arguments when using their values as keys.
               *
               * @param array $array The array with master keys to check.
               * @param array $array2 An array to compare keys against its values.
               * @return array $array2,... A variable list of arrays to compare.
               * 
               */
          
              function array_whitelist_assoc(Array $array1, Array $array2) {
          
                  if(func_num_args() > 2){
                      $args = func_get_args();
                      array_shift($args);
                      $array2 = call_user_func_array('array_merge', $args);
                  } 
                  return array_intersect_key($array1, array_flip($array2)); 
              }
          }
          

          【讨论】:

            【解决方案6】:

            如果您正在处理关联数组并且出于任何原因不想使用array_intersect_key(),您还可以使用更简单的方法使用旧数组中的值手动构建新数组。

            $post = array(
                'parent_id' => 1,
                'type' => "post",
                'title' => "Post title",
                'body' => "Post body",
                'tags' => "Post tags",
                'malicious' => "Robert'); DROP TABLE students;--"
            );
            $good = array(
                'parent_id' => $post['parent_id'],
                'type' => $post['type'],
                'title' => $post['title'],
                'body' => $post['body'],
                'tags' => $post['tags']
            );
            

            【讨论】:

              【解决方案7】:

              值得记住的是,虽然array_intersectarray_intersect_key 很好,但它们很可能是矫枉过正。在我的情况下,我只想要 1 个元素,因此最简单的选择就是根据我需要的键/值重建我想要的数组。我想知道 array_intersect 在什么时候变得不值得,而使用$new = array('whatI'=&gt;'want'); 会更好。我相信在 OP 中这是值得的,但在较小的情况下它可能是矫枉过正。

              作为对原始问题的另一种选择,仅使用 unset 可能是更便宜的选择 - unset($post['one'],$post['two'],$post['three'])。不过,这又与这变得效率太低和 array_intersect 函数更好的点有关。

              【讨论】:

              • 不敢相信我没想到那个lollllllllllllll
              • 过度杀伤的问题,你刚刚拯救了我的一天,+1
              【解决方案8】:

              使用数组交集。 array intersect,对你有帮助。

              【讨论】:

              • 这个仅链接的答案将更好地定位为评论,因为与其他完整答案相比,它的信息量明显较少。
              猜你喜欢
              • 1970-01-01
              • 2015-05-13
              • 2020-08-29
              • 2019-05-27
              • 1970-01-01
              • 2020-01-02
              • 2017-09-25
              • 2016-02-12
              • 2013-05-16
              相关资源
              最近更新 更多