-1

This code works and adds tables to my database. My question is how do I protect it with prepared statements.

 require "conn.php";
    $MyServer =($_POST["username"]);
        $sql = ("CREATE TABLE $MyServer (
            id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, 
            username VARCHAR(30) NOT NULL
            )");
        if($conn->query($sql) === TRUE){
            echo "Table created successfully";
        }

I am using MySQLi. I tryed this and it isn't adding the table.

$MyServer =($_POST["username"]);
    if (!preg_match('^/[A-Za-z][A-Za-z0-9]{0,7}$/', $MyServer)) {
       throw new Exception ('username unsuitable for use as a table name');
    }
    $sql = ("CREATE TABLE `$MyServer` (
        id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, 
        username VARCHAR(30) NOT NULL
        )");
    if($conn->query($sql) === TRUE){
        echo "Table created successfully";
    } else {
        echo "Table is not created successfully ";
    }

3 Answers3

1

I guess you're thinking about how to avoid SQL injection into your query via that $MyServer variable in your sample program.

You cannot use a parameterized value to name a table (or a database, or a column) in SQL. You must do the variable substitution shown in your program.

You can use php to sanitize your $MyServer variable before you use it for subsitution though.

For example: How to check, if a php string contains only english letters and digits?

You could do this, or something like it. This requires the variable to start with a letter, then contain up to seven more characters that are letters or digits. If the variable doesn't match it throws an exception.

if (!preg_match('^/[A-Za-z][A-Za-z0-9]{0,7}$/', $MyServer)) {
     throw new Exception ('username unsuitable for use as a table name');
}
O. Jones
  • 103,626
  • 17
  • 118
  • 172
0

Although it is questionable whether it is a good plan to allow users to create tables, to answer your question:

First of all, make sure your variable doesn't contain any strange character. Although MySQL allows (a subset of) unicode characters, you probably only want normal letters and numbers:

if (
    !preg_match('/^[a-z0-9]+$/i', $MyServer)
    || preg_match(/^[0-9]+$/, $MyServer) // Identifiers may begin with a digit but unless quoted may not consist solely of digits.
    || strlen($MyServer) > 64 // Limit of table-name length
) {
    // Insert your own error handling
    die('Not allowed');
}

Second, to make sure SQL treat it as a identifier, quote it in backticks

$sql = "CREATE TABLE `$MyServer` (...etc..."

CREATE TABLE index (...etc... will raise an error in MySQL because index is a keyword

CREATE TABLE `index` (...etc...

wont, because it is marked as an identifier.

Peter van der Wal
  • 11,141
  • 2
  • 21
  • 29
0

Honestly, you are really opening yourself up to SQL injection here by getting the data from $_POST.

Your method is a definite no go unless your usernames are already stored in your database and do not have special characters that will lead to SQL injection (such as quotations).

EDIT: I see two answers above that compliment what I have said, you could use one of those two answers (O. Jones is my preferred one).

If you want your code to be a bit more in line with PDO procedure (binding PDO values to avoid SQL injection), why not create one table with columns (username, saved_username) and you can interact with the information in that table effectively with PDO statements.

For example, all you will have to do to insert data would be:

$query = 'INSERT INTO table (username, saved_username) VALUES (:username, :username_to_save)';
$stmt->bindParam(':username', $_POST['username']);
$stmt->bindParam(':username_to_save', $_POST['username_to_save']);
$stmt->execute()

And to select the data:

$query = 'SELECT * FROM table WHERE username = :username';
$stmt->bindParam(':username', $_POST['username']);
$stmt->execute()
$users_saved_usernames = $stmt->fetchAll();
MinistryOfChaps
  • 1,458
  • 18
  • 31