6

重複の可能性:
Phonegap - ユーザー ID に基づいてデータベースから値を読み込む

ユーザー登録が必要な Phonegap アプリケーションを作成しています。MySQL データベースへの Web サービスとして機能し、AJAX POST/Get メソッドを使用する PHP スクリプトを介してこれを行っています。

何らかの理由で、LogCat は常に私に"There was an error"(投稿のエラー機能に該当します) を与えています。

更新: MySQL のログから、次のエラーが発生しています:
PHP Fatal error: Call to a member function bindValue()on a non-object
It points to this line: $username = $_POST['username'];

これが私のJSコードのスニペットです:

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コードのスニペットです。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());
}
4

4 に答える 4

1

次のようになるはずです

あなたの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());
}
于 2012-12-26T15:45:43.913 に答える
1

ここには 2 つの基本的な問題があります。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 をコールバック文字列でラップして、応答を関数呼び出しに変換します。

例:

function doSomething(response) { 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 は基本的にハックです。XMLHttpRequest を使用しません。jQuery は関数内でそれを偽造するためにいくつかのことを行い$.ajax()ますが、それでも逃れられない制限があります。

  • 可能な唯一のメソッドは GET (no POST) ですscript src=
  • サーバーにデータを渡す唯一の方法は、クエリ文字列を使用することです。
  • 応答の「コールバック」は、グローバル スコープからアクセスできる必要があります。
  • これは巨大なセキュリティ ホールです。エンド サーバーは必要なスクリプトを出力できるため、エンド サーバーを完全に信頼する必要があります。

可能であれば、JSONP の代わりにCORSを使用してください。

推奨される解決策

これは、テストされていない、推奨される方法です。

いくつかのメモ:

  • 登録 URL はhttp://example.org/registerです。エラーの場合でも、常に JSON を返します (これは変更できます)。CORS ヘッダーも発行するため、他のドメインから XHR を使用して POST できます。
  • サーバーコードには少し抽象化されています。
    • serviceRegisterRequest()URL のアクションを実行するメイン関数です。適切な例外処理で PDO を使用する方法を示します。HTTP 応答の抽象化を返します。
    • userExists()createUser()PDO 準備済みステートメントの使用方法を示します。
    • createUser()は、パスワードを暗号化するcrypt()方法の適切な使用法を示しています。(プレーンテキストのパスワードを保存しないでください!)
    • 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);
于 2012-12-26T16:11:14.390 に答える
0

これはもう少し役立つはずです。SQLを修正する必要もあります。問題は、2つの異なるクエリ方法を使用していることです。パラメータをバインドするには、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();
于 2012-12-26T15:32:57.897 に答える
0

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
于 2012-12-26T14:25:55.557 に答える