Classe de usuário PHP (login / logout / inscrição)

Comecei a experimentar com a construção de aulas, e comecei convertendo meu registro / login do usuário em uma única class. Queria parar e pedir feedback antes de chegar muito longe.

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

Uma das perguntas que eu tenho relacionadas com a minha class é: devo estar construindo isso como este:

 $User = new UserService(); $User->login($_POST['email'], $_POST['password']); 

Onde o método de login chama o método _checkCredentials automaticamente. Ou deve ser construído como:

 $User = new UserService(); $UserId = $User->checkCredentials($_POST['email'], $_POST['password']); $User->login($UserId); 

Além disso, adoro algumas dicas sobre como reestruturar isso e, por favor, salte tudo o que estou fazendo de errado!

obrigado rapazes

Eu acho que sua idéia principal era separar o gerenciamento de usuários (session) da consulta do database , o que é uma coisa boa na minha opinião.

No entanto, este não é o caso da sua implementação real, porque o login escapa aos dados a serem enviados para o database, mesmo que o resto do método não tenha nada a ver com os bancos de dados. Para não dizer que sua consulta de database depende de um recurso global para funcionar . Enquanto estiver com isso, sugiro também que você use DOP.

Além disso, suas propriedades $_email e $_password estão no âmbito privado, mas devem ser acessadas por um método protegido. Isso pode causar problemas. As propriedades e o método devem ter visibilidade equivalente .

Agora, posso ver que o seu UserService requer três coisas : um manipulador de database, um email e uma senha. Teria sentido colocá-lo em um construtor .

Veja como eu faria isso:

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

Em seguida, use-o como tal:

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

Eu disse muito isso no stackoverflow antes, mas o que eu acho que você está fazendo de errado é que você está tentando criar um sistema de login (até Jeff Atwood concorda comigo sobre isso), o que provavelmente não será seguro. Apenas para citar algumas coisas que podem dar errado :

  • Você não faz autenticação por conexão segura (https), o que significa que seu nome de usuário / senha pode ser cheirado pelo fio.
  • Poderia ter XSS-hole.
  • As senhas não são armazenadas seguras no database devido ao uso incorreto de sal. Você não é especialista em segurança, então eu não acho que você deve armazenar informações tão sensíveis em seu database de qualquer maneira!
  • Tem um object CSRF .

Depois, há o aborrecimento que ainda temos para criar outra conta em seu servidor. Você poderia e deveria evitar esse incômodo, usando uma das alternativas livremente disponíveis que foram testadas para vulnerabilidades de segurança por especialistas:

  • openid => Lightopenid é uma biblioteca realmente fácil de usar / integrar. Mesmo stackoverflow / jeff atwood está usando porque ele sabe que é difícil obter o sistema de login corretamente. Mesmo se você for um especialista em segurança.
  • Google Friend Connect.
  • facebook connect.
  • início de session do Twitter.

Então, segure-se o tempo de criar novamente outro sistema de login e, em vez disso, use, por exemplo, a biblioteca de lightopenid muito simples e deixe os usuários efetuar o login com a conta do Google google. O snippet abaixo é o único código que você precisa para que ele funcione:

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

Depende do seu design e da noção de uma solução mais simples, e como você deseja organizar seu código e mantê-lo mais simples, menor e torná-lo sustentável ao mesmo tempo.

Pergunte-se por que você chamaria checkCredentials e, em seguida, ligue para login e, em seguida, talvez algum outro método. Você tem um bom motivo para isso, é um bom design, o que eu quero alcançar com isso.

Ligar apenas para login e executar todas as operações de login é muito mais simples e elegante. Dar-lhe outro nome enquanto faz isso é muito mais compreensível e também mais sustentável.

Se você me perguntar, eu usaria um construtor.

A resposta realmente depende de outras considerações de arquitetura, como se o método checkCredentials () precisa estar disponível fora do escopo da class para outros elementos do sistema. Se o seu único objective é ser chamado pelo método login (), considere combinar os dois em apenas um método.

Mais uma recomendação que eu possa ter é usar verbos em methods de nomeação, o que significa que o “login” pode ser geral para entender seus efeitos à primeira vista.