Possible Duplicate:
Phonegap - Load Values from Database based on a user ID
I am creating a Phonegap application that requires user registration. I am doing this through a PHP Script acting as a web service to a MySQL database and using the AJAX POST/Get method.
For some reason LogCat is always giving me "There was an error"
(falls in the error function of the post) .
UPDATED:
From the logs of MySQL I am getting this error:
PHP Fatal error: Call to a member function bindValue()
on a non-object
It points to this line: $username = $_POST['username']
;
Here is a snippet of my JS code:
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;
And here is a snippet of my PHP code. I am using 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());
}
It should be like
Your HTML Page
<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>
Your PHP Page
$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());
}
There are two basic problems here: You don't understand the limitations of JSONP, and you are using PDO incorrectly.
There are a few patterns of PDO usage. (You can abstract these patterns for clarity and code reuse, but fundamentally you have to use the objects in this order.)
// 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();
There are many other problems with your code that seem to come down to you being unclear about what is traveling over the wire between the browser and the server.
JSONP is a technique to get around restrictions in browsers against cross-domain requests. It works by adding a script
element to the current page with a url and a callback=
query parameter. The server prepares a response with JSON, and then wraps the callback string around the JSON, turning the reply into a function call.
Example:
function doSomething(response) { response.name === 'bob'; response.callback === 'doSomething'; }
On the server:
header('Content-Type: text/javascript;charset=utf-8'); // NOT application/json!
echo $_GET['callback'], '(', $json_encode($_GET), ')';
Back to the browser, the script it gets back is:
doSomething({"name":"bob","callback","doSomething"})
As you can see, JSONP is fundamentally a hack. It doesn't use XMLHttpRequest. jQuery does some things to fake it in its $.ajax()
function, but there are still limitations it can't escape:
script src=
does.If at all possible, use CORS instead of JSONP.
This is an untested, suggested way of doing what you want.
Some notes:
serviceRegisterRequest()
is the main function which performs the action of the URL. It illustrates how to use PDO with proper exception handling. It returns an abstraction of an HTTP response.userExists()
and createUser()
show how to use PDO prepared statements.createUser()
illustrates the proper use of the crypt()
method to encrypt your passwords. (Do not store plaintext passwords!)emitResponse()
shows how to set CORS headers and how to produce JSON output.On the browser, 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>
On the server:
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With