我可以将 empty() 用于未定义的变量吗?
Can i use empty() for a Undefined Variable?
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 = '';
}
要检查是否已设置变量,您应该使用 isset()
来测试它。 empty()
也将 return true
如果 returned 为假值。在文档页面中,以下值被认为是错误的:
"" (an empty string)
0 (0 as an integer)
0.0 (0 as a float)
"0" (0 as a string)
NULL
FALSE
array() (an empty array)
因此,如果 $user_id
可能具有这些值之一(可能是整数 0),那么您可能会得到意想不到的结果。如果 $user_id
永远不会成为这些值之一,那么您可以检查它是否使用 !empty()
设置而不会出现任何问题。
Am I doing it correctly?
首先,我的回答不会描述在您的案例中使用 empty()
来应对未定义变量警告的实现。这个答案是为了给你方向,并向你展示一些适合你的情况的 OOP 以及为什么它有效。
举个例子,页面 A 不需要用户进行读取访问身份验证,但页面 B 需要。
我们可以编写一个 class 结构,根据访问范围为您执行此操作,而不是在整个页面 'n' 的应用程序中始终如一地重新编写此检查。
让我们首先通过创建接口让应用程序知道何时禁止读取访问。每当我们想在用户未登录时撤销读取访问权限时,这最终将用于扩展用户身份验证class。
namespace Application\Auth;
interface MustBeLoggedIn
{
}
接下来,我们可以继续构建身份验证 class。这就是这个 class 将根据其实例类型执行其方法的方式或顺序的指令。
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);
}
}
最后,我们可以建立两个用户 classes。第一个 class 将撤销任何未授权用户的读取权限。
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();
}
}
第二个 class 将允许来宾和经过身份验证的用户具有读取权限。
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 because an ID (assuming representing an integer) is extremely easy to forge. Perhaps look at 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
块,在这种情况下忽略 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。
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 = '';
}
要检查是否已设置变量,您应该使用 isset()
来测试它。 empty()
也将 return true
如果 returned 为假值。在文档页面中,以下值被认为是错误的:
"" (an empty string)
0 (0 as an integer)
0.0 (0 as a float)
"0" (0 as a string)
NULL
FALSE
array() (an empty array)
因此,如果 $user_id
可能具有这些值之一(可能是整数 0),那么您可能会得到意想不到的结果。如果 $user_id
永远不会成为这些值之一,那么您可以检查它是否使用 !empty()
设置而不会出现任何问题。
Am I doing it correctly?
首先,我的回答不会描述在您的案例中使用 empty()
来应对未定义变量警告的实现。这个答案是为了给你方向,并向你展示一些适合你的情况的 OOP 以及为什么它有效。
举个例子,页面 A 不需要用户进行读取访问身份验证,但页面 B 需要。
我们可以编写一个 class 结构,根据访问范围为您执行此操作,而不是在整个页面 'n' 的应用程序中始终如一地重新编写此检查。
让我们首先通过创建接口让应用程序知道何时禁止读取访问。每当我们想在用户未登录时撤销读取访问权限时,这最终将用于扩展用户身份验证class。
namespace Application\Auth;
interface MustBeLoggedIn
{
}
接下来,我们可以继续构建身份验证 class。这就是这个 class 将根据其实例类型执行其方法的方式或顺序的指令。
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);
}
}
最后,我们可以建立两个用户 classes。第一个 class 将撤销任何未授权用户的读取权限。
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();
}
}
第二个 class 将允许来宾和经过身份验证的用户具有读取权限。
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 because an ID (assuming representing an integer) is extremely easy to forge. Perhaps look at 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
块,在这种情况下忽略 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。