Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

correct way of writing a MySQLi prepared statement in a function?

Prepared Statements

Okay, I've just started taking a look at MySQLi prepared statements. This was a big step for me as I'm very new to MySQL and PHP anyway, so I have an extremely tenuous grasp on the concept (perhaps about an hours worth), so your answers will have to be phrased similarly, sorry about this.

What I am wanting to know is if I am correctly writing a prepared statement. There's nothing worse than learning a method which is incorrect and getting used to it, therefore coding entire projects inefficiently.

To the point: I have a function which registers a user, and then returns the inserted id, which is therefore the referencing id of the user.

Previously, I was simply querying the database, which I was told had security risks despite the use of mysql_real_escape_string() and similar security measures.

Now, it looks something like this: (assume for the sake of this question that all referenced variables are defined, the bound parameters are strings, and all called functions exist and are working).

function registerUser($username, $fname, $email, $password, $region, $activation) {
    $uniqueSalt = uniqueSalt();
    $password = sha1($uniqueSalt . $password);

    $mysqli = mysqli_connect('localhost', 'root', '', 'database');

    if ($stmt = $mysqli->prepare("INSERT INTO `users` VALUES('', ?, ?, ?, ?, '$password', '$uniqueSalt', '$activation')") ) {
        $stmt->bind_param("ssss", $username, $fname, $email, $region);
        $stmt->execute();
        $stmt->close();
    } else {
        echo 'error preparing statement';
    }

    return mysqli_insert_id($mysqli);
}

Questions

It seems to work, but:

1) Is this correct syntax for executing a prepared statement?

2) I had included the file this function was in (call it function.php) with another file called init.php which previously defined the variable $mysqli. I found if I didn't include

$mysqli = mysqli_connect('localhost', 'root', '', 'database');

I would receive an error. Why did I have to redefine it inside the function?

3) When I previously ended the function before I used prepped statements, with return mysql_insert_id() which worked fine, now I've found I have to use mysqli_insert_id($mysqli).

If I don't include $mysqli inside the parentheses I get the error mysqli_insert_id() expects exactly 1 parameter, 0 given. Why is this and why does it differ from what I had before?

Cheers, Luke.

like image 920
marked-down Avatar asked Nov 05 '22 08:11

marked-down


1 Answers

  1. Your usage doesn't make a lot of sense. From the PHP Manual Example:

    $stmt = $mysqli->prepare("INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
    $stmt->bind_param('sssd', $code, $language, $official, $percent);
    

    Compare this to your usage:

    $stmt = $mysqli->prepare("INSERT INTO `users` VALUES('', ?, ?, ?, ?, '$password', '$uniqueSalt', '$activation')");
    $stmt->bind_param("ssss", $username, $fname, $email, $region);
    

    Notice anything strange? The Manual example is using ? as a placeholder, where you then use ->bind_param() to create the substitution set. So your example, I believe, should be:

    $stmt = $mysqli->prepare("INSERT INTO `users` VALUES('', ?, ?, ?, ?, ?, ?, ?)");
    $stmt->bind_param("sssssss", $username, $fname, $email, $region, $password, $uniqueSalt, $activation);
    

    Not knowing if $activation is a number or string value. (Also, I would suggest using the column names and not omitting them in the INSERT query.)

    Now, what you did should work in many cases simply because you're creating a single use statement and using variable expansion to insert the $pass, $uniqueSalt, $activation into the query string that is being prepared. Cases where it won't is if you accidentally have a ' in one or more variables you're putting in the query, which should either be parametized (using ->bind_param()), or using mysqli_real_escape_string(). However, mixing these approaches is poor practice and defeats the purpose of using prepared statements. There is no reason to do the first few, but not the last few.

  2. Your $mysqli variable is "out of scope" when you call it in the function if it's defined globally, hence when not available, you can't use it unless you import it or create another one locally (in the function). You can import it using the global $mysqli; syntax within the function (as long as it's created globally and not locally in another function).

  3. This is the same issue as #2. See: http://php.net/manual/en/mysqli.insert-id.php

My recommendation is to use PDO instead of the mysql_/mysqli_ functions.

like image 192
Jared Farrish Avatar answered Nov 09 '22 06:11

Jared Farrish