Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if user exists [duplicate]

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());
}
like image 943
user1809790 Avatar asked Dec 26 '12 13:12

user1809790


Video Answer


2 Answers

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());
}
like image 99
Akash Avatar answered Oct 21 '22 07:10

Akash


There are two basic problems here: You don't understand the limitations of JSONP, and you are using PDO incorrectly.

PDO

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.)

Simple Queries

// 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();

Prepared statements

// 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

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:

  • The only possible method is GET (no POST) because that's what script src= does.
  • The only way to pass data to the server is via query strings.
  • Your response "callback" must be accessible from the global scope.
  • It is a huge security hole. You must trust the end server completely because it can output any script it wants.

If at all possible, use CORS instead of JSONP.

Suggested solution

This is an untested, suggested way of doing what you want.

Some notes:

  • The registration url is http://example.org/register. It always returns JSON, even for errors (you can change this). It also emits CORS headers, so you can POST to it using XHR from other domains.
  • The server code has a little bit of abstraction:
    • 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);
like image 1
Francis Avila Avatar answered Oct 21 '22 07:10

Francis Avila