-3

I'm building a full HTML/PHP/CSS website for learning purposes as it's my first website. my site subject is private trainers [gym~workout~sport] and I added packages to the database, only trainers can add these packages and also update them to change inside information.

There are 3 plans: Free, Silver, Gold, to update the package the trainer must his username+password. if it's correct is should show this message: Update successful if the username or password wrong it should show this message: Could not update

The problem is when he choosing plan and entering the right user and password, it's working and also showing the success message, but if he entering the wrong user or password, it's still showing the success message but not updating in the database.

php image

here is the PHP:

<?php
    //Create connection to the database.
    $host="localhost";  // Host name    
    $dbusername="root"; //username   
    $dbpassword="";     //username password   
    $dbname="proil";    //db name      
    // Connect to server and select database.   
    $con = mysqli_connect($host,$dbusername,$dbpassword,$dbname);

    //Input posted data.
    $zehut = $_POST["id"];
    $answer = $_POST['pickclass'];
    $pass = $_POST['pass'];
    $count=0;
    
    if ($answer == "free") {          
      
         $query =  "UPDATE trainer_packages AS b
         INNER JOIN trainer_d AS g ON b.trainer_pack_id = g.id
         SET b.package__name= 'free'
         WHERE  b.trainer_pack_id = '$zehut'  and g.pass ='$pass' ";
         $count=$count+1;
                    
    }
    if ($answer == "silver") {      
         $query =  "UPDATE trainer_packages AS b
         INNER JOIN trainer_d AS g ON b.trainer_pack_id = g.id
         SET b.package__name= 'silver'
         WHERE  b.trainer_pack_id = '$zehut'  and g.pass ='$pass' ";
         $count=$count+1;
    }
    if ($answer == "gold") {
            
         $query = "UPDATE trainer_packages AS b
         INNER JOIN trainer_d AS g ON b.trainer_pack_id = g.id
         SET b.package__name= 'gold'
         WHERE  b.trainer_pack_id = '$zehut'  and g.pass ='$pass' ";
         $count=$count+1;
    }
            
    

//Run SQL query
    mysqli_query($con, $query) or die ("ERROR: Cannot do insert ".mysqli_error($con));   
    
    if (mysqli_query($con, $query)) {
        echo "Update successful.";
      } else {
        echo "Could not update: " . mysqli_error($con);
      }
    
    //Close the SQL connection.
    mysqli_close($con);
?>
Will B.
  • 17,883
  • 4
  • 67
  • 69
DNC
  • 1
  • 2
  • 2
    learning purposes, start here: [How can I prevent SQL injection in PHP?](https://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php?rq=1), then here: [How to use PHP's password_hash to hash and verify passwords](https://stackoverflow.com/questions/30279321/how-to-use-phps-password-hash-to-hash-and-verify-passwords) – Lawrence Cherone Oct 06 '20 at 19:39
  • Your code's reliance on user-provided variables directly concatenated into query strings makes your code vulnerable to critical [SQL injection vulnerabilities](https://stackoverflow.com/questions/601300/what-is-sql-injection). – esqew Oct 06 '20 at 19:41
  • Thanks a lot for letting me know about this!! I will check this after I will understand the problem of the PHP and SQL, thanks again. – DNC Oct 06 '20 at 19:42

1 Answers1

1

You have a few issues that need to be addressed. Aside from using password_hash() and password_verify()

Redundant Query Call

The first is that you are calling the mysqli_query($con, $query) twice.

You need to remove the mysqli_query($con, $query) or die ("ERROR: Cannot do insert ".mysqli_error($con)); line.

Also redundant is the closing PHP tag ?>, you should omit the closing PHP tag when not switching between languages, to prevent accidental raw-text processing and being displayed that would occur otherwise.

Logging Errors

It is considered bad practice to output the query errors to the end-users with mysqli_error($con). Displaying the error messages may expose sensitive details to the end-user, that could be used to further progress an attack on your application.
You should be logging the errors instead. Please research an appropriate logging method for your application.

Prepared Statements

As mentioned in the comments, your queries are subject to SQL injection. For any queries that accept userland data, you should implement prepared statements.

Affected Records vs Query Failure

mysqli_query($con, $query) will only return false on failure, such as SELECT FROM NOTVALID. Instead you need to check the mysqli_affected_rows($con).

if (mysqli_query($con, $query)) {
    if (mysqli_affected_rows($con) > 0) {
        echo "Update successful.";
    } else {
        echo "No changes were made.";
    }
} else {
   echo "Could not update";
}

Recommended Solution

I recommend separating the queries into a SELECT FROM trainer_d and failing with an invalid username/password error, before issuing the UPDATE trainer_packages query.

<?php

//... omitted for brevity

// Connect to server and select database.
$con = new mysqli($host, $dbusername, $dbpassword, $dbname);

//enable exception handling for mysqli
$driver = new mysqli_driver();
$driver->report_mode = MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT;

// Input posted data.
$zehut = $_POST['id'];
$answer = $_POST['pickclass'];
$pass = $_POST['pass'];

try {
    // Validate the user
    $isValid = false;

    $stmt = $con->prepare('SELECT EXISTS(
SELECT 1 
FROM trainer_d AS g 
INNER JOIN trainer_packages AS b 
ON b.trainer_pack_id = g.id
WHERE g.id = ?
AND g.pass = ?)');
    $stmt->bind_param('ss', $zehut, $pass);
    $stmt->execute();
    $stmt->bind_result($isValid);
    $stmt->fetch();
    $stmt->close();
    
    if (!$isValid) {
        throw new InvalidArgumentException('Invalid username and/or password.');
    }

    if (!in_array($answer, ['free', 'silver', 'gold'], true)) {
        //validate package
        throw new InvalidArgumentException('Invalid package selected.');
    }

    // Update the training package
    $stmt = $con->prepare('UPDATE trainer_packages AS b
SET b.package__name = ?
WHERE b.trainer_pack_id = ?');
    $stmt->bind_param('ss', $answer, $zehut);
    $stmt->execute();
    $stmt->close();

    echo 'Update successful.';
} catch (Exception $e) {
    if ($e instanceof InvalidArgumentException) {
        //catch specific exception to handle them
        echo $e->getMessage();
        exit;
    }
    //handle other exceptions
    die('Could not update.');
} finally {
    //Close the SQL connection.
    $con->close();
}
Will B.
  • 17,883
  • 4
  • 67
  • 69