2

私は現在、API へのアクセスが登録ユーザーに制限されているプロジェクトに取り組んでいます。API 自体は既に完成しており、期待どおりに動作します。API へのアクセスを制限することも、かなり簡単であることがわかりました。しかし、私の問題 (というかむしろ質問) は、登録、検証、および/または紛失および発見プロセスのためのデータベース対話の効率を確保する方法です。

現在起こっていることの例を次に示します。

  1. ユーザーはメールアドレスを入力して API キーをリクエストします
  2. ユーザーに確認メールが送信されます
  3. ユーザーが電子メールのリンクをクリックすると、php がデータベースに対してハッシュをチェックします
  4. ハッシュが検証されると、API キーが生成され、保存され、電子メールで送信されます
  5. ユーザーが API キーを忘れた場合や紛失した場合は、再度メールで送信できます
  6. 確認メールが受信されていない場合は、再度メールを送信できます

データベース構造の例を次に示します: http://s13.postimage.org/h8ao5oo2v/dbstructure.png

おそらく想像できると思いますが、プロセスのこれらの特定のステップごとに、舞台裏で多くのデータベース対話が行われています。効率について疑問に思っている 1 つのステップは、特定のアイテムの一意性をチェックすることです。明らかに、重複した API キーが流出したり、電子メール検証ハッシュが重複したりすることは望ましくありません。

そこで、これらをデータベースに挿入する前にデータベースをチェックする非常に単純な関数を作成しました。しかし、このプロジェクトは、私が以前に着手したどのプロジェクトよりも数百倍も規模が大きくなっています。以前は 500 ~ 1,000 人のユーザーにサービスを提供するプロジェクトを構築して維持してきましたが、このプロジェクトは毎日最低でも約 50,000 人のユーザーにサービスを提供していると推定されています。ようやく大規模なプロジェクトに着手できたことを非常に嬉しく思いますが、その規模にますます圧倒されています。

いずれにせよ、データベースとやり取りしてアイテムを保存する前に一意性をチェックするために私が書いた関数を次に示します。

function isUnique($table, $col, $data) {
  mysql_connect("localhost", "root", "") or die(mysql_error());  
  mysql_select_db("api") or die(mysql_error());
  $check = mysql_query("SELECT ".$col." FROM ".$table." WHERE ".$col."='".$data."'");
  $match = mysql_num_rows($check);
  if($match < 1) {
    return true;
  }
  return false;
  mysql_close('localhost');
}

この関数は、メール検証ハッシュと API キー自体のために、0 ~ 9、az、および AZ のランダムな 40 桁の文字列を生成する別の関数と組み合わせて使用​​されます。(以下の関数)

function makeRandom($length = 40) {
  $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  $randomString = '';
  for($i = 0; $i < $length; $i++) {
    $randomString .= $characters[mt_rand(0, strlen($characters) - 1)];
  }
  return $randomString;
}

そして、API キーの発行に関連する 3 つの異なるページで、これら 2 つの機能の組み合わせが使用されます。今ここにそれが実際にあります:

$hash   = makeRandom();
$unique = isUnique('users', 'hash', $hash);
if($unique == false) {
  while($unique == false) {
    $hash   = makeRandom();
    $unique = isUnique('users', 'hash', $hash);
  }
}
else {
  $searchactive   = mysql_query("SELECT email, active FROM users WHERE email='".$email."' AND active='1'") or die(mysql_error());
  $matchactive    = mysql_num_rows($searchactive);
  $searchinactive = mysql_query("SELECT email, active FROM users WHERE email='".$email."' AND active='0'") or die(mysql_error());
  $matchinactive  = mysql_num_rows($searchinactive);

  if($matchactive > 0) {
    $hash = mysql_query("SELECT hash FROM users WHERE email='".$email."' AND active='1'") or die(mysql_error());
    $hash = mysql_fetch_assoc($hash);
    $hash = $hash['hash'];
    $msg = 'The email address you entered is already associated with an active API key. <a href="lost.php?email='.$email.'&amp;hash='.$hash.'&active=1">[Recover Lost API Key]</a>';
  }
  elseif($matchinactive > 0) {
    $hash = mysql_query("SELECT hash FROM users WHERE email='".$email."' AND active='0'") or die(mysql_error());
    $hash = mysql_fetch_assoc($hash);
    $hash = $hash['hash'];
    $msg = 'The email address you entered is already pending verification. <a href="lost.php?email='.$email.'&amp;hash='.$hash.'&active=0">[Resend Verification Email]</a>';
  }
}

私の主な質問は次のとおりです。このような (一見) 単純な関数のためだけにこれほど多くのクエリが実行されると、解決するよりも多くの問題が発生するのでしょうか? 明らかな理由から、検証ハッシュまたは API キーが重複していないことを確認する必要があります。しかし、推定 50,000 人がこの機能を使用しているため、SQL クエリの量が原因でサーバーが停止することはありますか? 主な懸念事項は、挿入前に生成されたコンテンツの一意性をチェックするために使用される while() ループによるものです。

これが舞台裏で何が起こっているかの完全な図ではないことはわかっていますが、残りのページがどのように機能するかについての手がかりを与えてくれます. プロセス全体についてさらに詳しい情報が必要な場合は、喜んで投稿します。

あなたが提供できる洞察をありがとう!

4

2 に答える 2

2

これに対処する 1 つの方法は、重複をチェックせず、最初から重複が起こらないようにすることです。そのため、ユーザー テーブルをバージョン管理するだけです (バージョンのフィールドを追加します)。これは、ユーザーの行が変更されるたびに進む int になります。

次に、ランダム キーを生成するときに、キーを保存する前に、それに user_id と user_version を追加します。

例:

11ap0w9jfoaiwej203989wesef

最初の 1 は user_id で、2 番目の 1 はユーザー バージョンです。

次に、大きなキーが 2 回生成されるという統計的にわずかな可能性があっても、ユーザー ID が一意であるため、キーは常に一意になります。

于 2012-05-03T20:20:05.610 に答える
1

独自のランダムな文字列をロールする代わりに、UUIDを使用することを検討します。すべての実用的な目的のために、これはユニークな価値になります。

http://dev.mysql.com/doc/refman/5.5/en/miscellaneous-functions.html#function_uuid

于 2012-05-03T20:28:54.333 に答える