检查用户是不是存在[重复]
Posted
技术标签:
【中文标题】检查用户是不是存在[重复]【英文标题】:Check if user exists [duplicate]检查用户是否存在[重复] 【发布时间】:2012-12-12 01:23:25 【问题描述】:可能重复:Phonegap - Load Values from Database based on a user ID
我正在创建一个需要用户注册的 Phonegap 应用程序。我通过一个 php 脚本作为 mysql 数据库的 Web 服务并使用 AJAX POST/Get 方法来执行此操作。
由于某种原因,LogCat 总是给我"There was an error"
(属于帖子的错误功能)。
更新:
从 MySQL 的日志中,我收到此错误:
PHP 致命错误:在非对象上调用成员函数 bindValue()
它指向这一行:$username = $_POST['username']
;
这是我的 JS 代码的 sn-p:
var u = $("#username").val();
var p = $("#password").val();
var userRegData = $('#registration').serialize();
$.ajax(
type: 'POST',
data: userRegData,
dataType: 'JSONp',
url: 'http://www.somedomain.com/php/userregistration.php',
success: function(data)
if(response==1)
// User can be saved
else
// User exsts already
,
error: function(e)
console.log('There was an error');
$.mobile.loading ('hide');
);
return false;
这是我的 PHP 代码的 sn-p。我正在使用 PDO。
$db = new PDO('mysql:host=' . $config['db']['host'] . ';dbname=' . $config['db']['dbname'], $config['db']['username'], $config['db']['password']);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$username = $_POST['username'];
$password = $_POST['password'];
$query->bindValue(':username', $username, PDO::PARAM_STR);
$query->bindValue(':password', $password, PDO::PARAM_STR);
try
$db->beginTransaction();
$db->query("SELECT `user`.`Username` FROM `user` WHERE `user`.`Username` = :username LIMIT 1");
try
if ( $query->rowCount() > 0 )
$response=1;
echo $response;
else
$response=0;
$db->query("INSERT INTO `user` (`user`.`Username`, `user`.`Password`) VALUES :username, :password");
echo $response;
$db->commit();
catch (PDOException $e)
die ($e->getMessage());
catch (PDOException $e)
$db->rollBack();
die ($e->getMessage());
【问题讨论】:
您应该检查浏览器的 XHR (Ajax) 控制台后端返回的内容。错误必须在后端而不是在前端。另一种调试方法是在后端对 POST 值进行硬编码,然后查看错误是什么。 只有在您的请求失败时才会抛出错误(404、403、500 错误)。我会检查以确保您的页面实际返回结果。 确保您使用的是 JSONP 你能试试吗:console.log(e);而不是 console.log('There was an error');请告诉我们输出是什么 仅供参考,您不需要在所有列前使用表名。大多数列名也不需要反引号,除非它们是保留关键字。 【参考方案1】:serialize 方法只是将您的变量转换为 JSON 数组,我假设您没有给出输入名称。所以你应该把名字放在你的 html 中是这样的:
<form id="registration">
<input type="text" name="username" ...
<input type="password" name="password" ...
现在,当您运行代码时,userRegData 将类似于:
username=value_in_username_input&password=value_in_password_input
【讨论】:
我已经有了名字,当我尝试 alert($('#registration').serialize());我得到了你给我的同样的字符串。我不确定发生了什么,因为当我按下确定时,什么也没有发生 - 它进入错误函数而不是成功 序列化后的形式是这样的:username=value_in_username&password=value_in_password&password-check=value_in_password_check 还有一件事要尝试,你能转储帖子变量吗?让我们看看输出【参考方案2】:这应该更有帮助,您还需要修改您的 sql。问题是您使用了两种不同的查询方法。绑定参数需要使用 Prepare 语句。
$username = $_POST['username'];
$password = $_POST['password'];
//new query
$query = $db->prepare("SELECT `user`.`Username` FROM `user` WHERE `user`.`Username` = :username LIMIT 1");
// since you're only using one argument, the password in the prior query I did not bind this here.
$query->bindParam(':username' PDO::PARAM_STR);
try
$db->execute();
【讨论】:
我需要先用SELECT语句检查用户是否存在于数据库中,如果用户不存在则触发INSERT语句。这就是为什么我的代码中有两条语句。但是我不确定这是否是正确的做法【参考方案3】:应该是这样的
您的 HTML 页面
<html>
<body>
<script>
function checkIfUserCanBeSaved()
var userRegData = $('#registration').serialize();
$.ajax(
type: 'POST',
data: userRegData,
url: 'http://www.somedomain.com/php/userregistration.php',
success: function(data)
if(response==1)
alert('user found');
else
alert('user saved')
,
error: function(e)
console.log('There was an error');
$.mobile.loading ('hide');
);
return false;
</script>
<form id="registration">
<input type="text" name="username">
<input type="text" name="password">
<input type="button" onclick="checkIfUserCanBeSaved()" value="submit">
</form>
</body>
</html>
您的 PHP 页面
$db = new PDO('mysql:host=' . $config['db']['host'] . ';dbname=' . $config['db']['dbname'], $config['db']['username'], $config['db']['password']);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$username = $_POST['username'];
$password = $_POST['password'];
try
$db->beginTransaction();
try
$query = $db->prepare("SELECT user.Username FROM user WHERE user.Username = :username LIMIT 1");
$query->bindValue(':username', $username, PDO::PARAM_STR);
$query->execute();
if ( $query->rowCount() > 0 )
$response=1;
echo $response;
else
$response=0;
$query = $db->prepare("INSERT INTO user ( username, password ) VALUES ( :username, :password )" );
$query->bindValue(':username', $username, PDO::PARAM_STR);
$query->bindValue(':password', $password, PDO::PARAM_STR);
$query->execute();
echo $response;
$db->commit();
catch (PDOException $e)
die ($e->getMessage());
catch (PDOException $e)
$db->rollBack();
die ($e->getMessage());
【讨论】:
由于我在数据库中检查一个值然后实际插入,这应该被视为 JS 中的 POST 还是 GET? 因为您使用“POST”类型的 Ajax 请求,所以使用 $_POST['username'] 应该可以工作。对此类请求使用 POST 也比 GET 更好 由于某种原因,我在尝试时遇到了 parserError :( 不知道出了什么问题 是我在 JS 中的 Ajax 调用是否正确,或者我那里有问题。这是我第一次以这种方式进行 ajax 调用并与 dbase 连接 我已经用 HTML 代码更新了我的答案,让我知道这是否有效【参考方案4】:这里有两个基本问题:你不了解 JSONP 的局限性,以及你错误地使用了 PDO。
PDO
有几种 PDO 使用模式。 (为了清晰和代码重用,您可以抽象这些模式,但从根本上说,您必须按此顺序使用对象。)
简单查询
// 1. Get a database handle
$dh = new PDO($DSN, $USERNAME, $PASSWORD, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
// 2. Issue a string query, no bindings!
$cursor = $dh->query('SELECT 1');
// 3. read results. There are many ways to do this:
// 3a. Iteration
foreach ($cursor as $row)
//...
// 3b. *fetch*
// You can use any one of multiple fetch modes:
// http://php.net/manual/en/pdostatement.fetch.php
while ($row = $cursor->fetch())
//...
// 3c. *fetchAll*
// *fetchAll* can also do some aggregation across all rows:
// http://php.net/manual/en/pdostatement.fetchall.php
$results = $cursor->fetchAll();
// 3d. *bindColumn*
$cursor->bindColumn(1, $id, PDO::PARAM_INT);
while ($cursor->fetch(PDO::FETCH_BOUND))
//$id == column 1 for this row.
// 4. close your cursor
$cursor->closeCursor();
准备好的陈述
// 1. Get a database handle
$dh = new PDO($DSN, $USERNAME, $PASSWORD, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION));
// 2. Prepare a statement, with bindings
$cursor = $dh->prepare('SELECT id, name FROM mytable WHERE name = :name');
// 3. Bind parameters to the statement. There are three ways to do this:
// 3a. via *execute*:
$cursor->execute(array(':name'=>$_GET['name']));
// 3b. via *bindValue*
$cursor->bindValue(':name', $_GET['name']);
// 3c. via *bindParam*. In this case the cursor receives a *reference*.
$name = 'name1';
$cursor->bindParam(':name', $name); // name sent to DB is 'name1'
$name = 'name2'; // name sent to DB is now 'name2'!
$name = 'name3'; // now it's 'name3'!
// 4. Execute the statement
$cursor->execute();
// 5. Read the results
// You can use any of the methods shown above.
foreach ($cursor as $row) // Iteration
// ...
// 6. Don't forget to close your cursor!
// You can execute() it again if you want, but you must close it first.
$cursor->closeCursor();
JSONP
您的代码还有许多其他问题,似乎归结为您不清楚浏览器和服务器之间的线路上传输的内容。
JSONP 是一种绕过浏览器对跨域请求的限制的技术。它通过将script
元素添加到带有url 和callback=
查询参数的当前页面来工作。服务器使用 JSON 准备响应,然后将回调字符串包装在 JSON 周围,将响应转换为函数调用。
例子:
功能doSomething(响应) response.name === '鲍勃'; response.callback === 'doSomething';
在服务器上:
header('Content-Type: text/javascript;charset=utf-8'); // NOT application/json!
echo $_GET['callback'], '(', $json_encode($_GET), ')';
回到浏览器,它返回的脚本是:
doSomething("name":"bob","callback","doSomething")
如您所见,JSONP 从根本上说是一种 hack。它不使用 XMLHttpRequest。 jQuery 在其$.ajax()
函数中做了一些事情来伪造它,但仍然有它无法逃脱的限制:
script src=
就是这样做的。
向服务器传递数据的唯一方法是通过查询字符串。
您的响应“回调”必须可从全局范围访问。
这是一个巨大的安全漏洞。您必须完全信任终端服务器,因为它可以输出它想要的任何脚本。
如果可能,请使用CORS 而不是 JSONP。
建议的解决方案
这是一种未经测试,建议您做您想做的事情。
一些注意事项:
注册地址为http://example.org/register。它总是返回 JSON,即使是错误的(你可以改变它)。它还发出 CORS 标头,因此您可以使用来自其他域的 XHR 向其 POST。 服务器代码有一点抽象:serviceRegisterRequest()
是执行 URL 操作的主要函数。它说明了如何使用 PDO 进行适当的异常处理。它返回 HTTP 响应的抽象。
userExists()
和 createUser()
展示了如何使用 PDO 准备好的语句。
createUser()
说明了正确使用 crypt()
method 来加密您的密码。 (不要存储明文密码!)
emitResponse()
展示了如何设置 CORS 标头以及如何生成 JSON 输出。
在浏览器上,http://example.COM/register:
<!DOCTYPE html>
<html>
<head>
<title>test registration</title>
<script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
</head>
<body>
<form id="theform">
<input name="u">
<input name="p" type="password">
</form>
<script>
$('#theform').submit(function(e)
$.ajax(
url: 'http://example.org/register',
type: 'POST',
data: $(e.target).serialize()
).done(function(response)
console.log('SUCCESS: ');
console.log(response);
).fail(function(jqXHR, textStatus)
console.log('FAILURE: ');
if (jqXHR.responseText)
console.log(JSON.parse(jqXHR.responseText));
);
);
</script>
</body>
在服务器上:
function userExists($dbh, $name)
$ps = $dbh->prepare('SELECT id, Username FROM user WHERE Username = ?');
$ps->execute(array($name));
$user = $ps->fetch(PDO::FETCH_ASSOC);
$ps->closeCursor();
return $user;
function createUser($dbh, $name, $pass, $salt)
$ps = $dbh->prepare('INSERT INTO user (Username, Password) VALUES (?,?)';
$crypt_pass = crypt($pass, $salt);
$ps->execute(array($name, $crypt_pass));
$user_id = $dbh->lastInsertId();
$ps->closeCursor();
return array('id'=>$user_id, 'name'=>$name);
function serviceRegisterRequest($method, $data, $salt, $DBSETTINGS)
if ($method==='POST')
$dbh = new PDO($DBSETTINGS['dsn'],$DBSETTINGS['username'],$DBSETTINGS['password']);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$response = array('status'=>200,'header'=>array(),'body'=>array());
$dbh->beginTransaction(); // if using MySQL, make sure you are using InnoDB tables!
try
$user = userExists($dbh, $data['u']);
if ($user)
$response['status'] = 409; // conflict
$response['body'] = array(
'error' => 'User exists',
'data' => $user,
);
else
$user = createUser($dbh, $data['u'], $data['p'], $salt);
$response['status'] = 201; //created
$response['header'][] = "Location: http://example.org/users/$user['id']";
$response['body'] = array(
'success' => 'User created',
'data' => $user,
);
$dbh->commit();
catch (PDOException $e)
$dbh->rollBack();
$response['status'] = 500;
$response['body'] = array(
'error' => 'Database error',
'data' => $e->errorInfo(),
);
catch (Exception $e)
$dbh->rollBack();
throw $e; // rethrow errors we don't know about
return $response;
function emitResponse($response)
// restrict allowed origins further if you can
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
foreach ($response['header'] as $header)
header($header);
header('Content-Type: application/json', true, $response['status']);
$output = json_encode($response['body']);
header('Content-Length: '.strlen($output));
echo $output;
exit();
$DBSETTINGS = array(
'dsn'=>'mysql:...',
'username' => 'USERNAME',
'password' => 'PASSWORD',
);
$salt = '$6$rounds=5000$MyCr4zyR2nd0m5tr1n9$';
$response = serviceRegisterRequest($_SERVER['REQUEST_METHOD'], $_POST, $salt, $DBSETTINGS);
emitResponse($response);
【讨论】:
精神上+1,因为我达到了投票限制,但如果你已经建议使用 crypt(),你可以并且应该使用 bcrypt ($2y$)。 我是 PHP 新手并尝试了您的代码,尽管我不得不完全改变我的逻辑。我了解您的代码更安全和专业,但是我只是在做演示,不需要这样的安全性。我还使用 sha1() 将密码保存在数据库中 使用简单的散列,例如 MD5 或 SHA1,即使使用盐,也几乎与明文密码一样糟糕。如果even the PHP docs 告诉你它不安全,那就是在说些什么。但是,我建议的代码的重点不是安全性,而是界面的清晰性和对 RESTful 原则的遵守。以上是关于检查用户是不是存在[重复]的主要内容,如果未能解决你的问题,请参考以下文章
HTML5 LocalStorage:检查密钥是不是存在[重复]