如何在PHP中“正确”处理$ _GET变量?

时间:2010-12-08 14:40:45

标签: php validation variables get

目前,我有以下代码:

if(isset($_GET['mid']) && !empty($_GET['mid'])) {
    $mid = $_GET['mid'];

    if(is_numeric($mid) && $mid > 0) {
        if(isset($_GET['op']) && !empty($_GET['op'])) {
            $op = $_GET['op'];

            if($op == 'info') {
            }

            if($op == 'cast') {
            }
        }
    }
}

但我觉得if语句中的if语句太复杂了......等等......

你会以不同的方式处理它吗?你会如何使它变得更简单?

[编辑]接受的答案:

好吧,我已经学到了一些我不知道的小细节和新的PHP函数。我认为没有一种正确的方式来完成我的要求。我显然以错误的方式使用了一些PHP函数,我将解决这个问题。

在我看来,像这样的输入应该使用PHP过滤器功能进行验证/清理,因此我将 Arkh的答案标记为已接受。

然而,对于一个特定的大学项目(PHP代码完全不相关),我将使用他的答案和 Tatu的帮助函数的想法。但是对于一个不同的项目,我会将他的答案与 Ignacio的类的想法混合使用,因为它看起来更好,更有条理。

10 个答案:

答案 0 :(得分:11)

我会将filter_input与FILTER_SANITIZE_NUMBER_FLOAT过滤器一起用于mid。这样的事情:

$mid = filter_input(INPUT_GET, 'mid', FILTER_SANITIZE_NUMBER_FLOAT);
$op = filter_input(INPUT_GET, 'op');
if($mid > 0){
  switch($op){
    case 'info':
      // Some code
      break;
    case 'cast':
      // Some more code
      break;
    default:
      break;
  }
}

答案 1 :(得分:5)

我会编写一个带有索引名称的函数,并返回$_GET中的值或抛出异常。

那,或将其封装在类似于以下的类中:

#$_GET = array('name' => 'Ignacio', 'foo' => '42');

class Get
{
  public static function string($name)
  {
    if (isset($_GET[$name]))
    {
      return $_GET[$name];
    }
    else
    {
      throw new Exception(sprintf('Unknown GET parameter "%s"', $name));
    }
  }

  public static function int($name)
  {
    $val = Get::string($name);
    $ret = filter_var($val, FILTER_VALIDATE_INT);
    if ($ret != $val)
    {
      throw new Exception(sprintf('Invalid int GET parameter "%s"', $name));
    }
    return $ret;
  }
}

echo Get::string('name') . "\n";
echo Get::int('foo') . "\n";
#echo Get::int('name') . "\n";
#echo Get::int('age') . "\n";

答案 2 :(得分:4)

  1. empty已检查变量isset
  2. is_numeric有点冗长,因为您还要检查0
  3. switch语句最适合根据多个字符串值检查变量
  4. 我会这样做:

    $mid = empty($_GET['mid']) ? 0 : (int)$_GET['mid'];
                                     // casting as an integer will
                                     // make undesirable strings = 0
    
    if ($mid > 0 && !empty($_GET['op'])) {
        switch($_GET['op']) {
            case 'info':
                break;
            case 'cast':
                break;
            default:
                break;
        }
    }
    

    如果您需要将$_GET['op']存储在变量中以供日后使用,您可以在切换块之前执行此操作,但除非需要,否则我不会这样做。

答案 3 :(得分:3)

我喜欢创建一个实现ArrayAccess的InputFilter类的想法。这是更面向对象和更可定制的,因为您可以随意添加方法进行自定义,并使用相同的主过滤对象。

$get = new InputFilter($_GET);
echo $get->value_integer('variable_name');

这也很好,它可以重复使用$ _POST等等。你只需要做$post = new InputFilter($_POST);之类的事情。而且,您也可以将它用于其他输入源。

或者,如果你有一个足够新的php版本,你可以稍后实现filter_input(),如@Arkh所建议的那样。 IMO,拥有自己的课程,感觉更可重复和耐用。

<?php

// empty for now, fill in later if desired
class InputFilterException extends Exception {}

/*
 * Use the ArrayAccess interface as a template.
 *
 * Usage examples:
 *    $controller->get = InputFilter($_GET);
 *    echo $controller->get->value_string_html('variable');
 *    $controller->post = InputFilter($_POST);
 *    echo $controller->get->value_integer('variable');
 */
class InputFilter implements ArrayAccess {

    protected $data;

    function __construct( $data ) {
        if( !is_array($data) ) {
            throw new InputFilterException ("Only arrays are allowed here");
        }
        $this->data = $data;
    }

    // do not actually use these
    function __get( $offset ) {
        throw new InputFilterException( "Don't use as an array, use functions ->string() ->int() etc: ['" . $offset . "']" );
    }
    function __set( $offset, $value ) {
        throw new InputFilterException( "Don't modify directly: ['" . $offset . "'] = \"" . $value . "\"" );
    }

    // implement ArrayAccess

    function offsetExists( $offset ) {
        return isset( $this->data[$offset]) );
    }

    function offsetSet( $offset, $value ) {
        $this->data[$offset] = $value;
    }

    function offsetUnset( $offset ) {
        unset( $this->data[$offset] );
    }

    function offsetGet( $offset ) {
        throw new InputFilterException ("Don't use this object as an array, but were an array : ". $offset);
    }

    protected function getValue( $offset ) {

        if( is_array($this->data[$offset]) ) {
            throw new InputFilterException ("must use the asArray() function");
        }
        return $this->data[$offset];
    }

    function data_count() {
        return count($this->data);
    }

    public function set_value( $offset, $data ) {
        $this->offsetSet( $offset, $data );
    }

    // get an array *in* the data
    public function asArray($offset) {

        if( !is_array ($this->data[$offset]) ) {
            throw new InputFilterException("only use asArray() for arrays");
        }
        return new Filter( $this->data[$offset] );
    }

    // validators...

    function is_set( $offset ) {
        return $this->offsetExists($offset);
    }

    function is_empty( $offset ) {
        return $this->is_set($offset) && strlen($this->data[$offset]) == 0;
    }

    function is_numeric( $offset ) {
        return $this->is_set($offset) && is_numeric($this->data[$offset]);
    }

    function is_integer( $offset ) {

        if( !$this->is_set($offset) ) {
            return false;
        } elseif( is_numeric($this->data[$offset]) ) {
            $int_value = intval($this->data[$offset]);
            return $int_value == $this->data[$offset];
        } elseif( strlen($this->data[$offset]) == 0 ) {
            return true;
        }
        return false;
    }

    function is_array( $offset ) {
        return $this->is_set($offset) && is_array($this->data[$offset]);
    }

    // return data formatted

    function value_string( $offset ) {
        return $this->getValue($offset);
    }

    function value_string_html( $offset ) {
        return htmlentities( $this->getValue($offset), null, 'UTF-8' );
    }

    function value_integer( $offset ) {
        return intval( trim($this->getValue ($offset)) );
    }

    function value_numeric( $offset ) {
        return doubleval($this->getValue ($offset));
    }

    function value_alphanumeric( $offset ) {
        return preg_replace("*[^A-Za-z0-9]*", "", $this->getValue ($offset));
    }

    function value_unfiltered( $offset ) {
        return $this->getValue( $offset );
    }

}

?>

答案 4 :(得分:2)

你可以做一个辅助功能:

function getvar($var) {
    return isset($_GET[$var]) && !empty($_GET[$var]) ? $_GET[$var] : false;
}

$mid = getvar('mid');
$op = getvar('op');

if(is_numeric($mid) && $mid > 0) {
    if($op == 'info') {
    }

    if($op == 'cast') {
    }
}

这会使你的代码更清晰,但你自己的代码就没事了。

答案 5 :(得分:2)

你可以做的是定义一个过滤函数(已经存在于PHP&gt; = 5.2中),该过滤函数会根据一个变量过滤变量,无论是数字,字符串还是更多依赖根据您的要求。

function myfilter($variable, $type) {
    switch($type){
        case 'numeric':
        //check for numbers
        return the number or false based on check
        break;
        case 'alphanumberic':
        //check for alphanumeric
        return the text or false based on check
        break;
    }
}

然后使用此函数过滤使用$ _GET

获得的值
$foo = myfilter($_GET['foo'], 'numeric');
$bar = myfilter($_GET['bar'], 'alphanumeric');

答案 6 :(得分:0)

我会做类似下面的事情。或多或少。但是你也可以使用过滤器来处理这些事情。你也可以关闭警告,只使用empty()而不用担心第一块中的isset。

function checkVar($var)
{
    if(isset($var) && !empty($var)) {
        return true;
    }
    return false;
}

function checkID($id){
    if(checkVar($id) && is_numeric($id) && $id > 0) {
        return $id;
    }
    return false; 
}

if($mid = checkID($_GET['mid'])) {
    if(checkVar($_GET['op'])) {
        switch($_GET['op']) {
            case 'info':
            break;

            case 'cast':
            break;
        }
    }
}

答案 7 :(得分:0)

看起来有点复杂。但看起来你想要测试很多边缘条件。但是,有一些方法可以统一这个过程。我正在使用wrapper class

if ($_GET->int["mid"]) {
if ($_GET->in_array("op", "info,cast")) {

但是可以定义一个自定义方法,它结合了所有的isset和is_numeric或任何检查。

答案 8 :(得分:0)

我喜欢以下关于整数变量的方法:

private function _extract_int_val($val) {
    if ( isset($val) ) {
        $number = esc_sql($val);
        if ( is_numeric($number) && $number >= 0) {
            return (int) $number;
        }
    }
}

答案 9 :(得分:-1)

这没什么不对。嵌套的if语句绝对没问题。 您可以使用filter