如何";适当地;在PHP中处理$\u获取变量?

如何";适当地;在PHP中处理$\u获取变量?,php,validation,variables,get,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(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的类想法,因为它看起来更好、更有条理。

我将编写一个函数,该函数将采用索引的名称,并在
$\u 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";

您可以创建一个助手函数:

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') {
    }
}

这将使您的代码更简洁,但您的代码本身是正确的。

这没有什么问题。嵌套的if语句是绝对正确的。 不过你可以用

  • empty
    已检查变量
    是否已设置
  • 是数值的
    有点冗长,因为您也在检查
    0
  • switch语句最适合于根据多个字符串值检查变量
  • 我会这样做:

    $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;
        }
    }
    

    如果以后需要在变量中存储
    $\u GET['op']
    ,您可以在开关块之前执行此操作,但除非需要,否则我不会执行此操作。

    您可以定义一个筛选函数(已存在于PHP>=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;
        }
    }
    
    然后使用此函数过滤使用$\u get获得的值

    $foo = myfilter($_GET['foo'], 'numeric');
    $bar = myfilter($_GET['bar'], 'alphanumeric');
    
    我会使用过滤器\消毒\编号\浮动过滤器作为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;
      }
    }
    

    我会像下面这样做。或多或少。但是你也可以用过滤器来处理这些事情。您还可以关闭警告,只需使用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;
            }
        }
    }
    

    看起来有点复杂。但是,您似乎需要测试大量的边缘条件。然而,有一些方法可以统一这个过程。我使用的是一个:

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

    但是可以定义一个自定义方法,该方法将所有isset和数字或任何检查组合在一起

    我喜欢创建一个实现ArrayAccess的InputFilter类。这是更面向对象和更可定制的,因为您可以随心所欲地添加自定义方法,并使用相同的主筛选对象

    $get = new InputFilter($_GET);
    echo $get->value_integer('variable_name');
    
    还有一点很好,就是它可以被$\u POST等重用。您只需要做一些类似于
    $POST=new InputFilter($\u POST)。而且,您还可以将其用于其他输入源

    或者,如果您有足够新的php版本,您也可以稍后实现filter_input(),正如@Arkh所建议的那样。在我看来,拥有自己的类感觉更加可重用和持久

    <?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 );
        }
    
    }
    
    ?>
    

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

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


    首先,使您的代码合理
    if(is numeric($mid)&&$mid>0){
    if(is numeric($mid))
    if(isset($\u GET['mid'])&!empty($\u GET['mid'])
    if(!empty($\u GET['mid'])等等。看我不知道
    是数值()
    0
    返回false。另一个我也不知道。它不知道。在
    0
    上返回
    TRUE
    。但是,你可以将
    isset()
    折叠成
    !empty()
    。@马克·特拉普:告诉40%的回答者。是数字,但你已经用empty()检查了0,因此,不需要额外的$mid>0是的,问题更多的是关于“代码复杂度”的外观。我通常倾向于有80个字符长的行,并且有很多嵌套的if语句,“真正的代码”会有很少的喘息空间。好吧,对于初学者来说,empty已经检查了一个变量是否已设置。你能给出一个关于该类方法的示例吗?相当不错,尽管使用static并不是那么“好”或可重复使用_POST@zanlok:将数组传递给构造函数是留给读者的一个练习。您的答案没有相同的方法;根本不同。过于保守?我想知道如果您这样做会发生什么;
    echo GET::int('hour'))
    当您的url类似时;
    ?hour=0
    检查变量
    是否设置了
    和/或
    为空
    是多余的。
    为空
    已检查它是否已设置。这有一个问题:if
    $\u GET['op']
    包含字符串
    info
    ,您的开关块在任何情况下都会运行所有代码。您应该添加中断。@Mark ehh…没有想到。实际上它存在于PHP>=5.2中,它会重载
    $\u GET
    超全局?不好!@Stephen:是的。语义很接近。但如果您喜欢复杂性,还可以定义wrapper对象:
    $getVars=新输入($\u-GET)
    yikes。我不知道为什么会被否决。我可能不同意建议的实现,但它仍然是一个有效的策略。+1表示平衡。@Stephen:我可能也否决了它,因为它对于OP想要的东西来说有点太过苛刻了。但是它是一个选项,而且确实简化了事情——一旦你成为朋友或扩展了API.Ch检查变量
    isset
    和/或not
    empty
    是否冗余。
    empty
    已经检查了它是否已设置。@Stephen:不是根据文档。这意味着它会抛出警告。可能吧