我可以对未定义变量使用empty()吗?

时间:2018-12-12 23:02:01

标签: php variables session isset

index.php:

if(isset($_SESSION['user_id'])){
  $user_id = $_SESSION['user_id'];
}
###$_SESSION['user_id'] is = to $user['user_id'] that i get from database in a select query on login.php

正如您在上面看到的,我仅在用户登录时才设置变量$user_id。我使用if(empty($user_id)){}进行了一些调整,并且效果很好,但是我很好奇,因为如果用户未登录$user_id将是一个未定义的变量,我是php的新手,所以我想知道我是否做对了。

在用户除非登录后就不应查看的页面上,我添加了以下代码:

if(empty($user_id)) {
  $_SESSION['message'] = "You need to loge in to view this page";
  header("location: verify/error.php");
  exit;    
}

并使用以下代码显示与用户相关的一些内容:

if(!empty($user_id)){
   echo 'content related to the user, divs...etc';
}

我有两个问题:

1-我做得正确吗?

2-我应该将代码更改为:

if(isset($_SESSION['user_id'])){
  $user_id = $_SESSION['user_id'];
}else{
  $user_id = '';
}

2 个答案:

答案 0 :(得分:1)

要检查是否已设置变量,应使用getLocalizableSampleTemplateForComplication进行测试。如果返回错误的值,isset()也将返回empty()。在文档页面中,以下值被视为false:

  

“”(空字符串)

     

0(0为整数)

     

0.0(浮点数为0)

     

“ 0”(0作为字符串)

     

NULL

     

     

array()(一个空数组)

因此,如果true可以具有这些值之一(可能是整数0),则可能会得到意外的结果。如果$user_id永远不是这些值之一,则可以检查是否使用$user_id进行了设置。

答案 1 :(得分:1)

  

我做对了吗?

首先,我的答案将不会描述针对未定义的变量警告使用empty()的实现。答案是为您提供指导,并向您展示一些针对您的情况的OOP以及为何有效。

举个例子,页面A不需要对用户进行身份验证才能进行读取访问,而页面B则需要进行身份验证。

我们可以在整个应用程序中始终为页面“ n”重新编写此检查,而不是重新编写此检查,而是根据访问范围来编写一个为您执行此检查的类结构。

首先,通过创建接口使应用程序知道何时禁止读取访问。每当我们要在用户未登录时撤销读取访问权限时,它将最终用于扩展User身份验证类。

namespace Application\Auth;

interface MustBeLoggedIn
{
}

接下来,我们可以继续构建身份验证类。这就是该类如何根据其实例类型执行其方法的指令。

namespace Application\Auth;

class Authenticable {

    protected $_user_id;
    private $_csrf = 'user_id';

    public function __construct()
    {
        # PHP 7+
        $this->_user_id = $_SESSION[$this->_csrf] ?? '';

        # PHP < 5.6
        # $this->user_id = isset($_SESSION[$this->_csrf]) ? $_SESSION[$this->csrf] : '';

        if($this instanceof MustBeLoggedIn)
            $this->mustBeLoggedIn();
    }

    private function mustBeLoggedIn()
    {
        if(!isset($this->_user_id))
            $this->authError();
    }

    protected function authError()
    {
        exit();
    }

    protected function isLoggedIn()
    {
        return isset($this->_user_id);
    }

}

最后,我们可以构建两个User类。头等舱将撤销对任何未授权用户的读取访问权限。

namespace Application\Auth;

class User extends Authenticable implements MustBeLoggedIn
{
    public function doSomething()
    {
        if($this->isLoggedIn())
            echo $this->_user_id;
    }

    protected function authError()
    {
        $_SESSION['message'] = 'Oh snap! Looks like you need to be logged in to view this page.';
        header('Location: verify/error');
        exit();
    }
}

第二堂课将允许来宾和经过身份验证的用户都具有读取权限。

namespace Application;

class User extends Authenticable
{
    public function doSomething()
    {
        if($this->isLoggedIn())
            echo $this->_user_id;

        if(!$this->isLoggedIn())
            echo 'Well, you can still view this page';
    }
}

部署视图现在很容易。不必不断地重新声明值是否存在并决定要做什么,您可以实例化适合您范围的对象。

如果我们想授予用户登录或注销时的读取权限,则可以使用Application \ User。

class MyView extends \Application\User {
    public function sayHi() {
        echo $this->isLoggedIn() ? "Hi, {$this->user_id}!" : "Hi, Guest!";
    }
}

(new MyView())->sayHi();

如果我们想撤消对未授权用户的读取访问权限,可以使用Application \ Auth \ User。

class MyView extends \Application\Auth\User {
    public function sayHi() {
        echo "Hi, {$this->user_id}!";
    }
}

(new MyView())->sayHi(); # Guests will be redirected to error/verify

我希望通过向您展示这一点,可以帮助您进一步了解PHP。另外,需要注意的是,您很容易受到CSRF attacks的攻击,因为ID(假设代表整数)非常容易伪造。也许看看using a JSON Web Token并将用户ID传递给它。

$_SESSION['csrf'] = \Firebase\JWT\JWT::encode(array('user_id' => 1), 'secret'); # An integer represented a base-64 encoding is going to stand out, perhaps store a generated unique token or something else in regards to identifying this user
$user = \Firebase\JWT\JWT::decode($_SESSION['csrf'], 'secret', array('HS256')); # $user['user_id'] would hold 1

在fyrye关于JWT的使用中有关利用的评论中,要带走的最大点是源自秘密的HS256安全性多数。 这是什么意思?这意味着您可以控制其安全性。我使用的方法是考虑安全密码,但与JWT有关。

$secret = '_userAuthentication%App';

然后,为了提高安全性,在将密码提供给HS256进行加密之前,我先对密码进行了哈希处理。

use \Firebase\JWT\JWT;

JWT::encode(array(
    'Data' => 'You want to secure from the user',
    'Integrity' => 'This STILL should not mean it is trusted data'
), password_hash($secret, PASSWORD_BCRYPT));

解码JWT时,记住基础知识-永不信任数据也很重要。我们可以使用try catch finally块,在这种情况下最终不用理会,以确保我们能获得正确的信息。

use \Firebase\JWT\JWT;

try {
    $csrf = JWT::decode($jwt, password_hash($secret, PASSWORD_BCRYPT), array('HS256'));
} catch (Exception $e) {
    // Data was invalid - Potential forge ?
}

最后一点,如果您正在使用SSL(目前是必需的),请使用RSA签署JWT。