views:

149

answers:

2

I have a page that displays a user's current personal information and a handler that cycles through the form elements, filtering them through to the relevant mysql query. There are two tables, one that contains the master data, e.g. username, email, password hash, and one that has address data. However, the script doesn't work and I can't see why. I've been over it a lot. It's quite long, I'm afraid, but it's all pertinent to understand the logic. Here it is...

    if(!$_POST) {
  //come directly via address bar
  header("Location: index.hmtl");
  exit;
}
//loop through all the post variables

foreach ($_POST as $k => $v) {

  if(eregi("confirm",$k) || eregi("old",$k)) {
//the field in question is a duplicate one or there for authentication purposes and shouldn't be added to a table
    continue;
  }

  if($k == "address" || $k == "town" || $k == "city" || $k == "postcode") {

    //use aromaAddress table


        $v = trim(htmlspecialchars(check_chars_mailto(mysqli_real_escape_string($mysqli,$v))));

        if(empty($v)) {
//the field is empty...do nothing
          continue; 
        }

  //create query
  $update_sql = "UPDATE aromaAddress SET ".$k." = '".$v."' WHERE userid = '".$_SESSION["userid"]."'";
  $update_res = mysqli_query($mysqli, $update_sql) or die(mysqli_error($mysqli));

  //add to session for the sake of having the form fields filled in next time

  $_SESSION["$k"] = $v;
  session_write_close();



  } else {
  //sanitize them

  $v = trim(htmlspecialchars(mysqli_real_escape_string($mysqli,check_chars_mailto($v))));

          if(empty($v)) {
          continue;
        }

  if(eregi("email",$k)) {

    if($_POST["email"] != $_POST["confirmEmail"]) {
      header("Location: account_management.php5?error=ef");
      exit();
    }

    $_SESSION["$k"] = $v;
      session_write_close();

  //if email address/username being changed, check for pre-existing account with new address/username

  $check_sql = "SELECT id FROM aromaMaster WHERE email='".$v."'";
  $check_res = mysqli_query($mysqli, $check_sql) or die(mysqli_error($mysqli));

  if(mysqli_num_rows($check_res) >= 1) {
    //duplicate entry
    mysqli_free_result($check_res);
    header("Location: account_management.php5?error=email");
    exit;
  }
  } else if(eregi("username",$k)) {

        if($_POST["username"] != $_POST["confirmUsername"]) {
      header("Location: account_management.php5?error=ef");
      exit();
    }


  $v = trim(htmlspecialchars(mysqli_real_escape_string($mysqli,check_chars_mailto($v))));

    //check for pre-existing account with same username
      $check_sql = "SELECT id FROM aromaMaster WHERE username='".$v."'";
  $check_res = mysqli_query($mysqli, $check_sql) or die(mysqli_error($mysqli));

  if(mysqli_num_rows($check_res) >=1 ) {
    //duplicate entry
    mysqli_free_result($check_res);
    header("Location: account_management.php5?error=username");
    exit;
  }

    } else if(eregi("newPassword",$k)) {

        if(($_POST["newPassword"] != $_POST["confirmNewUsername"]) || ($_POST["oldPassword"] != $_POST["confirmOldPassword"])) {
      header("Location: account_management.php5?error=ef");
      exit();
    }


  $v = trim(htmlspecialchars(mysqli_real_escape_string($mysqli,check_chars_mailto($v))));

    //check for pre-existing account with same username
      $check_sql = "SELECT id FROM aromaMaster WHERE id='".$_SESSION["userid"]."'";
  $check_res = mysqli_query($mysqli, $check_sql) or die(mysqli_error($mysqli));

  if(mysqli_num_rows($check_res) >=1 ) {
    //duplicate entry
    mysqli_free_result($check_res);
    header("Location: account_management.php5?error=username");
    exit;
  }
} else {

        $v = trim(htmlspecialchars(check_chars_mailto(mysqli_real_escape_string($mysqli,$v))));

  //create query
  $update_sql = "UPDATE aromaMaster SET ".$k." = '".$v."' WHERE id = '".$_SESSION["userid"]."'";
  $update_res = mysqli_query($mysqli, $update_sql) or die(mysqli_error($mysqli));

$_SESSION["$k"] = $v;
      session_write_close();
      header("Location: account_management.php5?res=suc");
      exit();
}
  }
  }
  mysqli_close($mysqli);
+2  A: 

what exactly is not working? it’s hard to guess …

you shouldn’t be using erigi to check for a substring: 1) it’s deprecated 2) use stripos instead.

edit:

your code screams sql injection!

knittl
see above for the symptoms...basically, nothing happens! I will swap out eregi for stripos, though, thanks.
there are no symptoms, the only thing i can see is your code with a note of »it does not work the way it should« …
knittl
ok, found ’em xD after header('Location: …') your `$_POST` array will be empty, could this be a problem?
knittl
Well, that shouldn't be a problem because the rest of the code won't even be executed if $_POST is empty, heh. That's the point of that - it doesn't process an empty form. As for sql injection, didn't you notice that I trim, mysqli_real_escape_string and pattern match(check_chars is a pattern match function) the input? It should be pretty safe after...I will add htmlspecialchars, too, but I'm just testing just now.
`$_SESSION['userid']` is not escaped. BUT regarding `$_POST`: i understand that this script won’t be executed if it is empty, but after redirecting with `header` it will be empty (empty for the called script, not for the calling one). that is `account_management.php5?res=suc` will have an empty `$_POST`
knittl
Ah, well $_SESSION["userid"] is fetched by me from a table and is an auto_incremented value, so no tinkering is possible there. You're right about $_POST being empty for account_management.php5, but that page is the form, not the handler, so it doesn't look for any $_POST values at all anyway.
A: 

What data gets submitted (i.e. what's in $_POST)?

Your foreach($_POST as $k => $v) loop is wrapped right around the whole chunk of code, so if you're submitting anything other than username and email-address, you've got no guarantee you'll be updating the db before redirecting to the res=suc URL.

Others have mentioned SQL injection possibilities. It looks like you're escaping $v properly, but you've done nothing to protect against people stuffing shit in $k.

Finally, your res=suc is a default option. i.e. your success criteria and redirection occur for ANY value of $k not explicitly coded and handled earlier in the code.

searlea
Hiya. I have pretty much decided to do this a whole other way - to in effect replicate my registration script and demand that the whole form be complete and just update everything, rather than foreach my way through the fields. The number of factors to consider makes it a more time consuming effort. As for people stuffing shit in $k, they could, but there wouldn't be a column in my table to match it, ergo nothing would be inserted and the script would just break at that insertion.