luci2oo9 Posted April 27, 2014 Share Posted April 27, 2014 Hello, im working on a MMO RPG and im now trying to make a script transfer some points / or cash to other player. The problem is that all is working except when im transfering to an ID that doesn't exist, but players input that ID without knowledge in the form, my script transfers money/cash to that ID even if it doesn't exist instead of throwing player a message like "that user is not in our database". Can you help me? My script is: global $db,$userid; $_GET['userid'] = abs((int) $_GET['userid']); $_POST['xferu'] = abs((int) $_POST['xferu']); $_POST['money'] = abs((int) $_POST['money']); $xferuser = $_POST['xferu']; if($_POST['xferu'] == $userid) { print " <br /> Nu iti poti trimite bani singur! <br /> <br /> <a href=\"bank.php\">< Inapoi la Transferuri Bancare</a> <br /> <br /> "; } else { if((int) $_POST['money']) { if($_POST['money'] > $ir['money']) { print " <br /> Nu ai atata cash disponibil!<br /> Retrage din cont suma dorita apoi reincearca transferul.<br /> <br /> <a href=\"bank.php\">< Reincearca</a> <br /> <br /> "; } else { $db->query("UPDATE users SET money=money-{$_POST['money']} WHERE userid=$userid"); $db->query("UPDATE users SET money=money+{$_POST['money']} WHERE userid=$xferuser"); print " <br /> I-ai trimis suma de \${$_POST['money']} utilizatorului cu ID-ul $xferuser. <br /> <br /> <a href=\"bank.php\">< Inapoi la Transferuri Bancare</a> <br /> <br /> "; event_add($xferuser,"Ai primit un transfer bancar de \${$_POST['money']} de la {$ir['username']}.",$c); $it=$db->query("SELECT u.*,us.* FROM users u LEFT JOIN userstats us ON u.userid=us.userid WHERE u.userid=$xferuser"); $er=$db->fetch_row($it); $db->query("INSERT INTO cashxferlogs VALUES ('', $userid, $xferuser, {$_POST['money']}, unix_timestamp(), '{$ir['lastip']}', '{$er['lastip']}')"); } } else { print " <table width=\"90%\" class=\"table\" border=\"1\"> <tr><th colspan=\"2\">Transfer Bancar intre Jucatori</th></tr> <tr> <form action='bank.php' method='post'> <td>Beneficiar:</td> <td><input type='text' STYLE='color: black; background-color: white;' name='xferu' /></td> </tr> <tr> <td>Suma:</td> <td><input type='text' STYLE='color: black; background-color: white;' name='money' /></td> </tr> <tr> <td colspan=\"2\" align=\"center\"><input type='submit' STYLE='color: black; background-color: white;' value=' Trimite ' /></td> </form> </tr> </table> <br /> <table width=\"90%\" class=\"table\" border=\"1\"> <tr> <th colspan=\"4\">Ultimile 5 Transferuri (efectuate)</th> </tr> <tr> <td width=\"190px;\"><b>Data</b></td> <td width=\"190px;\"><b>Beneficiar</b></td> <td width=\"190px;\"><b>Suma</b></td> </tr> "; $q=$db->query("SELECT cx.*,u1.username as sender, u2.username as sent FROM cashxferlogs cx LEFT JOIN users u1 ON cx.cxFROM=u1.userid LEFT JOIN users u2 ON cx.cxTO=u2.userid WHERE cx.cxFROM=$userid ORDER BY cx.cxTIME DESC LIMIT 5"); while($r=$db->fetch_row($q)) { if($r['cxFROMIP'] == $r['cxTOIP']) { $m="<span style='color:red;font-weight:800'>MULTI</span>"; } else { $m=""; } print "<tr> <td>" . date("F j, Y, g:i:s a",$r['cxTIME']) . "</td><td>{$r['sent']} [{$r['cxTO']}] </td> <td> \${$r['cxAMOUNT']}</td> </tr>"; } print " </table> "; Quote Link to comment Share on other sites More sharing options...
mogosselin Posted April 27, 2014 Share Posted April 27, 2014 You just need to check if the use exists, first. Add a method that just check that. For example: function userExists($id) { .... if (!empty($rows)) { return true; } return false; } I don't know what is the framework you use so you might have to change the line with "!empty($rows)"... Then, you'll be able to do something like this: if (userExists($userid)) { ... transfer money... } else { ... error ... } Some free tips: I think that you will have to read a little bit about SQL injections (one of my post I made). Also, I think that an MMO RPG is a really ambitious project to make for a beginner. Is it 100% web based? If you're going to make a big application, you should also read about good practices, specifically how to sperate your presentation from your code. It's really hard to maintain and read code that has HTML mixed in with PHP (here's a link on stack overflow: http://stackoverflow.com/questions/18641738/how-i-separate-logic-from-presentation). Quote Link to comment Share on other sites More sharing options...
luci2oo9 Posted April 27, 2014 Author Share Posted April 27, 2014 (edited) ok... i narrowed the code with my test code - lines and i will explain after posting the code what is what... global $db,$userid; $_GET['userid'] = abs((int) $_GET['userid']); $_POST['xferu'] = abs((int) $_POST['xferu']); $_POST['money'] = abs((int) $_POST['money']); $xferuser = $_POST['xferu']; $chkxusr=$db->query("SELECT 1 FROM users WHERE userid=$xferuser"); if($chkxusr<0) { print " User does not exist, please insert another ID! "; } if($_POST['xferu'] == $userid) { print " <br /> You can't send money to yourself! <br /> <br /> <a href=\"bank.php\">< Back to Banking</a> <br /> <br /> "; } ok, so "xferu" is the data inserted in a form, on a input type text named xferu by my users.when my users want to transfer some money or whatever to another user, they must insert an ID (that is xferu). but now i want to make an IF statemant that will tell the users to go find santa claus else where because that ID doesn't exist in our database. i tried lots of tests, but none gave me the result i wanted. so...? any other details required? please tell and i will provide them... framework: MCcodes v2. Edited April 27, 2014 by luci2oo9 Quote Link to comment Share on other sites More sharing options...
Jacques1 Posted April 27, 2014 Share Posted April 27, 2014 (edited) Checking the user ID separately doesn't make a lot of sense and is kind of missing the point. The point is that the whole transaction is only valid if there was no error of any kind in the two actions. Errors include invalid user IDs, insufficient funds, database problems etc. Unfortunately, you cannot do this with PHP alone. Well, you can try, but it's not gonna work reliably, and people may exploit this for cheating (transfer money that does not exist etc.) If you're serious about your game and neither want broken data nor cheating, you'll have to take a very different approach using database transactions. The whole transfer must be atomic (all or nothing), and different transfers running at the same time must not interfere with each other. This does require some knowledge and rigor. So do you want the correct (but hard) way? Or are you OK with the game working only partly? Edited April 27, 2014 by Jacques1 Quote Link to comment Share on other sites More sharing options...
luci2oo9 Posted April 27, 2014 Author Share Posted April 27, 2014 Jacques1, im ok even with the hard way... do you have any solutions here? what im missing or what is to be done to make it work? please. Quote Link to comment Share on other sites More sharing options...
Jacques1 Posted April 27, 2014 Share Posted April 27, 2014 Like I said, you'll need to read up on transactions. The procedure is as follows: You start a transaction (in serializable mode). You read the current balance of the sender and at the same time lock the row so that concurrent transactions won't be seeing the same (now obsolete) value. If the balance is sufficient, you subtract the amount from the sender. If this UPDATE succeeded and has affected rows, you add the amount to the receiver. If this UPDATE also succeeded and has affected rows, you commit the transaction. In any other case, you roll it back. Note that the table must use the InnoDB engine, because MyISAM doesn't support transactions. As a quick demonstration: <?php $database_options = array( PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ); $database = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'NAME', 'PASSWORD'); // test data $remitterId = 2; $remitteeId = 1; $amount = 100; $database->query('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE'); $database->beginTransaction(); try { $transactionSuccessful = false; // get current balance $remitterBalanceStmt = $database->prepare(' SELECT balance FROM users WHERE user_id = :user_id FOR UPDATE -- this locks the row '); $remitterBalanceStmt->execute(array( 'user_id' => $remitterId, )); $remitterBalance = $remitterBalanceStmt->fetchColumn(); if ($remitterBalance === false) { echo 'Invalid remitter.<br>'; } elseif ($remitterBalance >= $amount) { // add amount to remittee's balance $addAmountStmt = $database->prepare(' UPDATE users SET balance = balance + :amount WHERE user_id = :user_id '); $addAmountStmt->execute(array( 'user_id' => $remitteeId, 'amount' => $amount, )); if ($addAmountStmt->rowCount()) { // subtract amount from remitter's balance $subtractAmountStmt = $database->prepare(' UPDATE users SET balance = balance - :amount WHERE user_id = :user_id '); $subtractAmountStmt->execute(array( 'user_id' => $remitterId, 'amount' => $amount, )); if ($subtractAmountStmt->rowCount()) { $transactionSuccessful = true; } else { echo 'Failed to subtract amount.<br>'; } } else { echo 'Failed to add amount.<br>'; } } else { echo 'Insufficient funds.<br>'; } if ($transactionSuccessful) { $database->commit(); echo 'The transaction was successful.<br>'; } else { $database->rollback(); echo 'The transaction failed.<br>'; } } catch (PDOException $transferError) { $database->rollBack(); echo 'The transaction failed due to technical problems.<br>'; } Do not copy and paste this code. Use it to understand the idea and then write your own script. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.