Mysqli Php выполняет инструкции в случайном порядке (очень странно)Php

Кемеровские программисты php общаются здесь
Ответить
Anonymous
 Mysqli Php выполняет инструкции в случайном порядке (очень странно)

Сообщение Anonymous »

Кажется, у меня очень странная проблема. У меня есть веб-сайт, который использует стороннюю авторизацию для входа. Мои пользователи используют для этого две социальные сети: Facebook и Вконтакте (российский аналог).
При входе я ищу в базе данных пользователя с переданным социальным идентификатором (который в зависимости от выбранной социальной сети представляет собой идентификатор пользователя в FB или ВК, для которого у меня есть два разных столбца) и извлекаю его.
Если пользователь имеет учетные записи как в FB, так и в VK и вошел в систему через них, у него теперь есть два отдельных аккаунта на моем сайте. Однако он может объединить их в одну, войдя в систему через одну социальную сеть (это будет его основная учетная запись) и используя функцию user_bind с другой социальной сетью.
Эта функция находит другую учетную запись пользователя и повторно связывает все данные в базе данных с основной учетной записью. Затем он удаляет другую учетную запись и добавляет ее социальный идентификатор к основной учетной записи, так что теперь пользователь может войти в систему через обе социальные сети. Столбец Social id, естественно, имеет индекс UNIQUE.
Однако при выполнении сценария он, похоже, выполняет UPDATE, который добавляет социальный идентификатор, перед оператором DELETE, который удаляет старого пользователя. Это приводит к ошибке, поскольку он пытается добавить существующий социальный идентификатор (поскольку старый пользователь все еще там).
Когда я проверяю базу данных после выполнения сценария, старый пользователь исчез, поэтому я предполагаю, что это означает, что оператор DELETE действительно выполняется, но с задержкой, с которой выполняются другие операторы. Журнал MySQL Workbench подтверждает это, хотя я не уверен, надежен ли он.
Мой вопрос: как мне убедиться, что DELETE (или любой другой оператор MySQL в этом отношении) действительно был выполнен до выполнения остальной части сценария? И почему вообще это происходит?
Вот адекватно прокомментированный код (хотя я с радостью приму ответ, в котором нет кода и просто объясняется принцип).
Функция user_bind:
function user_bind($eSourceType)
{
//$eSourceType can be 'fb' or 'vk', depending on the social network of the secondary account

$usrMe=get_gl_me(); //gets the user's account, through which he is logged in - the master account
if ($eSourceType=='fb') //if the social network that we are binding this account to is Facebook
{
$vSidName='facebook_id'; //name of the column which contains the social id
if (!$usrMe->get_private_property("facebook_id") & $usrMe->get_private_property("vkontakte_id") ) //check if the master account really doesn't have facebook_id set
{
$fb=get_facebook();//gets facebook object (from FB PHP SDK)
$sid=$fb->getUser();//gets user's id in facebook (social id)
}
else
{
error("The account has facebook_id set");
}
}
elseif($eSourceType=='vk')//same as before, but the id is fetched through $_GET, not object
{
$vSidName='vkontakte_id';
if ($usrMe->get_private_property("facebook_id") & !$usrMe->get_private_property("vkontakte_id") ) //check if it's the right account
{
$sid=$_GET['uid'];
}
else
{
error("The account has vkontakte_id set");
}
}

if(!$sid) //if we couldn't retrieve the social id
{
error("Can't bind: \$sid not set.");
}

$idNew=$usrMe->get_id();//get id (database id) of the master account

$usrOld=fetch_user_by_sid($sid, $eSourceType, true); //fetches the 'user' object by the social id we retrieved before
if ($usrOld)//if there is a user with this social id (if there is a secondary account)
{
$idOld=$usrOld->get_id();//get id of the secondary account
$tblsRelink=array("comments", "posts", "users_private", "vote_posts", "vote_comments"); //get tables in which we have to relink users
foreach($tblsRelink as $tbl)
{
//update set users_idusers to userid
$sp=new Statement_Parameter; //this is a class from PHP.com: http://php.net/manual/en/mysqli-stmt.bind-param.php. It allows to bind variables to the prepared statement in MySQLi without much pain
$query="UPDATE $tbl SET users_idusers=" . db_stmt_operands($idNew, $sp, 'idNew') . " WHERE users_idusers=". db_stmt_operands($idOld, $sp, 'idOld'); //db_stmt_operands inserts question marks in the query, while binding the variables through Statement_Parameter
$affected_rows=db_submit($query, $sp);//see below for the db_submit() function explanation
}

//delete old user
$sp=new Statement_Parameter; //clear Statement_Parameter

$query="DELETE FROM users WHERE idusers=" . db_stmt_operands($idOld, $sp, 'idOld');
$affected_rows=db_submit($query, $sp);
echo "
affected: $affected_rows
"; //this actually returns 1

//lets see if the user was actually deleted
$usrTest=fetch_user_by_sid($sid, $eSourceType, true); //fetch the user by the social id
if($usrTest) //if a user is fetched
{
debug_array($usrTest); //custom implementation of print_r
error("User still exsists. Oh no.");//it always does
}
}

$usrMe->set_private_property($vSidName, $sid);//sets the property 'facebook_id' or 'vkontakte_id' to the social id that we got in the beginning
$usrMe->update();//UPDATE statement, which brings the object's properties in the database up to date (in our case: adds the social id)
//the UPDATE statement doesn't execute because the old user is still there
}

Функция db_submit:
function db_submit($query, $sp=NULL)
{
$mysqli = db_connect(); //fetches PHP MySQLi object
if ($stmt = $mysqli->prepare($query)) //if the statement is successfully prepared
{
if($sp)//if there is a Statement_Parameter passed
{
$sp->Bind_Params($stmt); //bind parameters from SP
}

if($stmt->execute())//try to execute the statement
{
//on success
if ($mysqli->insert_id) //if this was an INSERT
{
return $mysqli->insert_id;
}
else //if this was DELETE or UPDATE
{
return $mysqli->affected_rows;
}
}
else
{
//on failure
error("Could not submit: could not execute statement. Query: $query." . $stmt->error); //this kills the script
}
}
else
{
error("Could not submit. Query: $query." . $mysqli->error);
}
}


Подробнее здесь: https://stackoverflow.com/questions/810 ... ry-strange
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Php»