Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP用户类(登录/注销/注册)_Php_Oop_Class_Login - Fatal编程技术网

PHP用户类(登录/注销/注册)

PHP用户类(登录/注销/注册),php,oop,class,login,Php,Oop,Class,Login,我开始尝试构建类,并开始将我的用户注册/登录转换为单个类。想在走得太远之前停下来征求反馈意见 class UserService { private $_email; private $_password; public function login($email, $password) { $this->_email = mysql_real_escape_string($email); $this->_passwo

我开始尝试构建类,并开始将我的用户注册/登录转换为单个类。想在走得太远之前停下来征求反馈意见

class UserService
{
    private $_email;
    private $_password;

    public function login($email, $password)
    {
        $this->_email = mysql_real_escape_string($email);
        $this->_password = mysql_real_escape_string($password);

        $user_id = $this->_checkCredentials();
        if($user_id){
            $_SESSION['user_id'] = $user_id;
            return $user_id;
        }
        return false;
    }

    protected function _checkCredentials()
    {
        $query = "SELECT *
                    FROM users
                    WHERE email = '$this->_email'";
        $result = mysql_query($query);
        if(!empty($result)){
            $user = mysql_fetch_assoc($result);
            $submitted_pass = sha1($user['salt'] . $this->_password);
            if($submitted_pass == $user['password']){
                return $user['id'];
            }
        }
        return false;
    }   
}
我确实有一个与我的课程相关的问题:我是否应该这样构建它:

$User = new UserService();
$User->login($_POST['email'], $_POST['password']);
其中login方法自动调用_checkCredentials方法。 还是应该像这样建造:

$User = new UserService();
$UserId = $User->checkCredentials($_POST['email'], $_POST['password']);
$User->login($UserId);
除此之外,我喜欢一些关于如何重组的建议,请指出我做错了什么


感谢各位

答案实际上取决于其他体系结构考虑因素,例如checkCredentials()方法是否需要在其他系统元素的类范围之外可用。如果用Login()方法调用它的唯一目的,请考虑将这两种方法组合成一种方法。
我可能还有一个建议,就是在命名方法中使用动词,这意味着“登录”可能过于笼统,乍一看无法理解其效果

这取决于您的设计和更简单解决方案的概念,以及您希望如何组织代码,使其更简单、更小,同时使其可维护

问问自己,为什么要先调用
checkCredentials
,然后调用
login
,然后再调用其他方法。你有这样做的理由吗?这是一个好的设计吗?我想用它实现什么

只需调用
login
,执行每个登录操作就更简单、更优雅了。在这样做的同时给它起另一个名字更容易理解,也更易于维护


如果你问我,我会使用构造函数。

我认为你的主要想法是将用户处理(会话)与数据库查询分开,这在我看来是件好事

但是,实际实现并非如此,因为
login
会转义要发送到数据库的数据,即使方法的其余部分与数据库无关。并不是说您的数据库查询依赖于一个全局资源来工作。在我这么做的同时,我还建议您使用PDO

此外,您的属性
$\u email
$\u password
属于私有范围,但可以通过受保护的方法访问。这可能会引起问题属性和方法应具有同等的可见性

现在,我可以看到您的
用户服务需要三件事:数据库处理程序、电子邮件和密码。把它放在构造函数中是有意义的

我会这样做:

class UserService
{
    protected $_email;    // using protected so they can be accessed
    protected $_password; // and overidden if necessary

    protected $_db;       // stores the database handler
    protected $_user;     // stores the user data

    public function __construct(PDO $db, $email, $password) 
    {
       $this->_db = $db;
       $this->_email = $email;
       $this->_password = $password;
    }

    public function login()
    {
        $user = $this->_checkCredentials();
        if ($user) {
            $this->_user = $user; // store it so it can be accessed later
            $_SESSION['user_id'] = $user['id'];
            return $user['id'];
        }
        return false;
    }

    protected function _checkCredentials()
    {
        $stmt = $this->_db->prepare('SELECT * FROM users WHERE email=?');
        $stmt->execute(array($this->email));
        if ($stmt->rowCount() > 0) {
            $user = $stmt->fetch(PDO::FETCH_ASSOC);
            $submitted_pass = sha1($user['salt'] . $this->_password);
            if ($submitted_pass == $user['password']) {
                return $user;
            }
        }
        return false;
    }

    public function getUser()
    {
        return $this->_user;
    }
}
然后按如下方式使用:

$pdo = new PDO('mysql:dbname=mydb', 'myuser', 'mypass');

$userService = new UserService($pdo, $_POST['email'], $_POST['password']);
if ($user_id = $userService->login()) {
    echo 'Logged it as user id: '.$user_id;
    $userData = $userService->getUser();
    // do stuff
} else {
    echo 'Invalid login';
}

我以前在stackoverflow上说过很多,但我认为你做错了,你再次尝试创建一个登录系统(即使是Jeff Atwood和我一起),这可能是不安全的。仅举几件可以:

  • 您没有通过安全连接(https)进行身份验证,这意味着您的用户名/密码可以通过网络嗅探
  • 它可能有XSS洞
  • 由于盐的使用不正确,数据库中出现了错误。你不是 我不是一个安全专家,所以我认为你甚至不应该在数据库中存储这样的敏感信息
  • 它有一个洞
还有一个问题是,我们还没有在您的服务器上创建另一个帐户。您可以也应该通过使用免费提供的备选方案之一来避免这种麻烦,这些备选方案已经过专家的安全漏洞测试:

  • openid=>是一个非常易于使用/集成的库。甚至stackoverflow/jeff atwood也在使用它,因为他知道很难正确获得登录系统。即使你是安全专家
  • 谷歌好友连接
  • facebook连接
  • twitter单一登录
因此,在再次设计另一个登录系统时,请确保您自己的安全,例如使用真正简单的lightopenid库,让用户使用google帐户登录。下面的代码段是使其工作所需的唯一代码:

<?php
# Logging in with Google accounts requires setting special identity, so this example shows how to do it.
require 'openid.php';
try {
    $openid = new LightOpenID;
    if(!$openid->mode) {
        if(isset($_GET['login'])) {
            $openid->identity = 'https://www.google.com/accounts/o8/id';
            header('Location: ' . $openid->authUrl());
        }
?>
<form action="?login" method="post">
    <button>Login with Google</button>
</form>
<?php
    } elseif($openid->mode == 'cancel') {
        echo 'User has canceled authentication!';
    } else {
        echo 'User ' . ($openid->validate() ? $openid->identity . ' has ' : 'has not ') . 'logged in.';
    }
} catch(ErrorException $e) {
    echo $e->getMessage();
}

使用谷歌登录

我认为
\u checkCredentials()
中缺少下划线,应该是
$stmt->execute(数组($this->\u电子邮件))
($user\u id=$userService->login())
@netcoder中也缺少一个相同的
=
@netcoder为什么要回滚?不应该
if($user\u id=$userService->login())
if($user\u id==$userService->login())
?@FrankPresenciaFandos:不是故意的。它将返回值分配给
$user\u id
,然后将其作为布尔值进行计算。您的编辑将(不存在的)
$user\u id
与返回值进行比较。这是一种常见的编程实践,请参见。
属性和方法应具有同等的可见性。
。我很确定这是一个愚蠢的问题,但是:$\u电子邮件和$\u密码是否必须设置为
private
,方法是否必须设置为protected?你选择的原因是什么?当你使用你的登录系统进行“公开公开”时,这是正确的,但是对于一家公司或政府来说,有时你有特定的帐户或问题,你必须建立一个登录系统,有时这样做的人并不是你所说的安全专家。因此,基本上这对某些情况下的某些人来说是可行的,在某些情况下,你可能需要处理大约600个或更少的用户。当你因为防火墙/代理而不能使用openID时,那么被泄露的风险也会小得多,因为来自internet的其他人可能也无法访问该本地网站。