Jump to content

Problem transfering points or "cash" to other ID


luci2oo9

Recommended Posts

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>
";
Link to comment
Share on other sites

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).

Link to comment
Share on other sites

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 by luci2oo9
Link to comment
Share on other sites

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 by Jacques1
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.