2012-05-03 2 views
2

В настоящее время я работаю над проектом, в котором доступ к API ограничен зарегистрированными пользователями. Сам API уже завершен и работает так, как ожидалось. Ограничение доступа к API оказалось довольно простым. Однако моя проблема (или вопрос, скорее) заключается в том, как обеспечить эффективность взаимодействия с базами данных для регистрации, проверки и/или потерянного и найденного процесса.проверка уникальности элементов перед вставкой в ​​базу данных

Вот пример того, что в настоящее время происходит: просит

  1. Пользователь ключ API, введя свой адрес электронной почты
  2. пользователя отправляется письмо с подтверждением
  3. пользователь нажимает ссылку на электронную почту и PHP проверки хэш против база данных
  4. После хэш проверяется, ключ API генерируется, хранится, и по электронной почте
  5. Если пользователь забыл/потерял ключ API, он может быть отправлен снова
  6. Если проверка электронной почты не был получен, он может быть отправлен снова

Вот пример структуры базы данных: http://s13.postimage.org/h8ao5oo2v/dbstructure.png

Как вы можете себе представить, есть много взаимодействия с базой данных происходит за кулисами для каждого из этих конкретных шагов в этом процессе. Один шаг, который мне интересен в отношении эффективности, - это проверка уникальности определенных элементов. Очевидно, что мы не хотим, чтобы все дублирующие API-ключи плавали вокруг, и мы не хотим дублировать хэши проверки электронной почты.

Итак, я написал мертвую простую функцию, которая проверяет базу данных для этих вещей, прежде чем вставлять их в базу данных. Однако этот проект находится на порядок в сотни раз больше, чем я ранее делал. Я разработал и поддерживал проекты, обслуживающие 500-1000 пользователей до ..., но, по оценкам, этот проект обслуживает минимум около 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'); 
} 

Эта функция используется в сочетании с другой функцией, которая просто генерирует случайное 40 цифр строки 0-9, A-Z и A-Z для электронной проверки хэш, а также сам ключ API. (Функция ниже)

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

И тогда сочетание этих 2-х функций используются в 3-х различных страницах, связанных с ключом выдачи API: Page один для регистрации/запроса, второй страницы для проверки электронной почты, Page 3 для потерянного ключи или непринятые письма. Сейчас здесь на практике:

$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>'; 
    } 
} 

Мой основной вопрос заключается в следующем: С этим много query'g происходит только для такого (на первый взгляд) простая функция, это собирается создать больше проблем, чем решает? Мне действительно нужно убедиться, что нет никаких повторяющихся хэшей проверки или ключей API по очевидным причинам. Однако, по оценкам, около 50 тыс. Человек, использующих эту функцию, это приведет к запугиванию сервера из-за количества SQL-запросов? Основная проблема связана с циклом while(), который используется для проверки уникальности сгенерированного содержимого перед его вставкой.

Я знаю, что это не полная картина того, что происходит за кулисами, но это дает представление о том, как работают остальные страницы. Если вам нужна дополнительная информация о процессе в целом, я буду рад опубликовать его.

Спасибо за понимание, которое вы можете предложить!

+0

Для хэша, вы можете использовать адрес электронной почты + время() + RAND() в определенном порядке, чтобы не имея Dups. – honyovk

ответ

2

Один из способов решения этой проблемы - не проверять наличие дубликатов, а просто обеспечить, чтобы они никогда не происходили в первую очередь. Итак, просто версия вашей таблицы пользователя (добавьте поле для версии). Это будет просто int, который продвигается в любое время, когда изменяется строка пользователя.

Затем, когда вы создаете свой случайный ключ, добавьте user_id и user_version к нему, прежде чем хранить ключ.

Пример:

11ap0w9jfoaiwej203989wesef

В случае, если первый 1 является идентификатор_пользователя и второй 1 является версией пользователя.

Тогда даже при статистически небольшой вероятности того, что большой ключ будет создан дважды, он всегда будет уникальным, потому что ваш идентификатор пользователя будет уникальным.

+0

интересная идея ... Я об этом не подумал. Кажется, что это будет довольно просто, поскольку, как база данных уже увеличивает поле идентификатора для каждой сохраненной записи. Тем не менее, я все равно буду делать запрос, чтобы получить текущий ID # для добавления, так что это уменьшит общие запросы? –

+0

То, как я понимаю вашу систему, вы будете вводить их электронную почту в базу данных во время запроса и отправлять по электронной почте хэш. Вы уже проверите хэш прямо в этот момент, и я предполагаю, что вы поместили их в таблицу пользователей с флагом, в котором говорилось, что они непроверены. Итак, как только вы аутентифицируете этот первоначальный ключ из электронной почты, вы уже выполнили запрос и знаете свой идентификатор строки. –

+0

В основном система работает следующим образом: введите адрес электронной почты -> проверьте базу данных на существующий адрес электронной почты + проверенный или непроверенный маркер -> либо добавьте электронное письмо в базу данных, либо распечатайте ссылки для восстановления потерянного ключа ... Поэтому я полагаю, что вы правы. Хотя я немного не понимаю, что вы имеете в виду, когда говорите «добавить пользовательскую версию» в таблицу. –

Смежные вопросы