I am currently trying to dynamically create a database with a user provided string. I can get the database created using:
DB::connection()->statement("CREATE DATABASE {$sName}")
Obviously this is not an acceptable solution and I'd prefer to sanitize the input but using both of these throws an error:
DB::connection()->statement("CREATE DATABASE :sName", ['sName' => $sName]);
DB::connection()->statement("CREATE DATABASE ?", [$sName]);
The error states: > SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 1 (SQL: CREATE DATABASE :sName).
Everything I've read says this should work but nothing seems to get me past it. Any help is appreciated.
$sNames = filter_var($sName, FILTER_SANITIZE_STRING);
sanitize before use?
Are you sanitize input? if yes and still has problem then this problem because of MySQL Naming Rules.It restricate some name may be they are reserved keyword or any other problem.
these are simple rules
Cannot contain / \ or . characters
Cannot contain characters that are not permitted in file names.
Cannot end with space characters
see here for more sql naming Rules.
http://www.informit.com/articles/article.aspx?p=30875
I've attempted multiple replacements. I'm pretty sure it has nothing to do with reserved keywords. If I use the same name it works in this line:
DB::connection()->statement("CREATE DATABASE {$sName}")
but not in this:
DB::connection()->statement("CREATE DATABASE :sName", ['sName' => $sName]);
So I doubt it has to do with reserved keywords.
I've considered using a sanitize filter as a stop gap but wanted to see if there was something I could do to get the PDO replacement working.
To my knowledge, DDL [1] statements usually don't support bound parameters, only DML [2].
Although under the hood Laravel is using PDO, the decription from mysqli_stmt_prepare
seems to fit:
In general, parameters are legal only in Data Manipulation Language (DML) statements, and not in Data Definition Language (DDL) statements.
Now, I know that PDO supports emulated and native prepared statements. But a) I don't know which driver supports what exactly and b) if these restriction still apply. According to your experience, it does.
My TL;DR would be: performing sanitization on your own is the way to go.
[1] Data Definition Language
[2] Data Manipulation Language
Thanks guys. I've solved the problem by creating a stored procedure in my master DB that takes bound parameters to create the tenant DBs. This circumvents the need for custom sanitization.
CREATE DEFINER=`user`@`localhost` PROCEDURE `tenantCreator`(IN dbname VARCHAR(64), IN dbpass VARCHAR(64))
BEGIN
SET @db = dbname;
SET @dbuser = dbname;
SET @dbpass = dbpass;
SET @statement = CONCAT('CREATE DATABASE ',@db);
PREPARE prepared_statement FROM @statement;
EXECUTE prepared_statement;
SET @usercreate = CONCAT(CREATE USER ', @dbuser, '@'localhost IDENTIFIED BY ', @dbpass);
PREPARE create_stmnt FROM @usercreate;
EXECUTE create_stmnt;
SET @permissions = CONCAT('GRANT ALL ON ' , @db, '.* TO ', @dbuser, '@'localhost');
PREPARE permission_stmnt FROM @permissions;
EXECUTE permission_stmnt;
END
Then I call it:
$sql = "CALL tenantCreator(:sName, :pass)";
$params = ['sName' => $sName, 'pass' => $pass];
return DB::connection()->statement($sql, $params);
Sign in to participate in this thread!
The Laravel portal for problem solving, knowledge sharing and community building.
The community