クラスの構築の実験を開始し、ユーザー登録/ログインを単一のクラスに変換することから始めました。立ち去る前に立ち止まってフィードバックを求めたかった。
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;
}
}
私のクラスに関連する質問の1つは次のとおりです。
$User = new UserService();
$User->login($_POST['email'], $_POST['password']);
ログインメソッドが_checkCredentialsメソッドを自動的に呼び出す場所。または、次のように構築する必要があります。
$User = new UserService();
$UserId = $User->checkCredentials($_POST['email'], $_POST['password']);
$User->login($UserId);
それ以外に、これを再構築する方法に関するいくつかのヒントが大好きで、間違っていることを指摘してください!
みんなありがとう
あなたの主なアイデアはデータベースクエリからユーザー処理(セッション)を分離するだったと思います。これは私の意見では良いことです。
ただし、メソッドの残りの部分がデータベースとは関係がない場合でも、login
はデータベースに送信されるデータをエスケープするため、実際の実装には当てはまりません。 データベースクエリは動作するグローバルリソースに依存しているとは言いません。私はそれに取り組んでいますが、PDOを使用することもお勧めします。
また、プロパティ$_email
および$_password
はプライベートスコープ内にありますが、保護されたメソッドによってアクセスされます。これにより問題が発生する可能性があります。 プロパティとメソッドの可視性は同等でなければなりません。
これで、あなたのUserService
つのことを必要とします:データベースハンドラー、メール、パスワードがわかります。 コンストラクターに入れるに意味があります。
私がそれをする方法は次のとおりです。
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でこれをたくさん言いましたが、あなたが間違っていると思うのは、あなた再びがログインシステムを作成しようとしているということです(ジェフさえも) Atwood agrees これで私と)これはおそらく安全ではないでしょう。 間違っている :
次に、サーバー上に別のアカウントを作成する必要があります。専門家によってセキュリティの脆弱性についてテストされている、無料で利用可能な代替手段の1つを使用することで、この面倒を回避できます。
もう一度別のログインシステムを考案し、代わりにたとえば非常に単純な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();
}
それは、設計とより単純なソリューションの概念、およびコードを整理し、よりシンプルで小さく保ち、同時に保守可能にする方法に依存します。
checkCredentials
を呼び出してからlogin
を呼び出してから、他のメソッドを呼び出す理由を考えてください。そうする理由はありますか、これは良いデザインですか、これで何を達成したいのですか?.
login
を呼び出して、すべてのログイン操作を実行することは、はるかに単純でエレガントです。そうする間に別の名前を付けると、はるかに理解しやすくなり、保守しやすくなります。
あなたが私に尋ねるなら、私はコンストラクタを使用します。
答えは、checkCredentials()メソッドを他のシステム要素のクラススコープ外で使用可能にする必要があるかどうかなど、他のアーキテクチャ上の考慮事項に依存します。その唯一の目的がlogin()メソッドによって呼び出される場合、2つを1つのメソッドに結合することを検討してください。
もう1つの推奨事項は、命名方法に動詞を使用することです。つまり、「ログイン」は一見しただけではその効果を理解するには一般的すぎる可能性があります。