I suggest, in that case, you use Prepared statements, both present in the PDO as in the OO interface of Mysqli, to avoid the famous SQL injections, which may indicate the vulnerability of your system, so to speak.
Anyway, here I present a solution using the method you ask for, and another using the method "safer".
Using the functions mysqli_*
public function cadastrarProdutos(string $tabela, array $campos, array $valores) {
$query = "INSERT INTO $tabela";
$query .= ' (' . implode(', ', $campos) . ') ';
$query .= 'VALUES (\n';
//Aqui adiciona aspas para todos os valores e escapa as que já vieram no valor. Ou seja,
// se o texto veio como 'Olá, 'mundo'!', transformará em
// 'Olá \'mundo\'!'
$valores = array_map(function($item) { return "'".addslashes($item)."'"; }, $valores);
$query .= implode(', ', $valores);
$query .= '\n);';
mysqli_query($this->conexao, $query);
//...
}
Using Prepared statements with PDO
Having obviously made all PDO settings, the method could look like this:
public function cadastrarProdutos(string $tabela, array $campos, array $valores) {
$statement = $this->pdoConn->prepare('INSERT INTO ' . $tabela . ' (' . implode(', ', $campos) . ') VALUES (' . implode(', ', str_split( str_repeat('?', count($campos) ) ) ) . ');');
for ($i=0;$i<count($campos);$i++) {
$statement->bindValue($i+1, array_values($valores)[$i]);
}
$statement->execute();
}
Here I use the for
to be able to take each value and its position, since, in logic, the sequence of elements in the array of the values shall be the same as array of the fields (as well as the size of both must be the same), thus using the parameter bindValue
to replace the value at the position equivalent to its field. That is, the SQL command at the beginning would look like this:
INSERT INTO produtos (Nome, Descricao, Valor, ValorDesconto) VALUES (?, ?, ?, ?);
And after all the replacements had been made, it would look something like this:
INSERT INTO produtos (Nome, Descricao, Valor, ValorDesconto) VALUES ('<nome>', '<desc>', '<valor>'|<valor>, '<valor_desconto>'|<valor_desconto>);
OBS.: the ratings '<valor>'|<valor>
and '<valor_desconto>'|<valor_desconto>
indicate that the value to be entered may be a text or a numerical value.
And, in both forms, you could create an "algorithm" to know the type of the value and thus pass from the "correct" form to the SQL command, differentiating between those that are texts and those that are numbers, either through the manual form (the first solution), or by Prepared statements, using the method bindValue
, that even has the parameter data_type
, which by default accepts all as one string.
Using Prepared statements with mysqli
(object-oriented)
Additionally, you can also use the Prepared statements with the object-oriented "interface" of Mysqli, which you can see better in the documentation how to use, and do similarly to PDO:
public function cadastrarProdutos(string $tabela, array $campos, array $valores) {
$statement = $this->mysqli->prepare('INSERT INTO ' . $tabela . ' (' . implode(', ', $campos) . ') VALUES (' . implode(', ', str_split( str_repeat('?', count($campos) ) ) ) . ');');
$statement->bind_param("ssss", ...array_values($valores));
$statement->execute();
//$statement->close();
}
The question of the meaning of those "ssss"
, you can also see on documentation, but basically I’m informing you that all the values that are to be put in charge are strings. And after, I use the Operator spread ("scattering" operator, free translation) to pass the values of the array as parameters, but there may be other (better) ways to do. And here comes, once again, the possibility for you to change the values for the correct (data) types, according to your needs.
Completion
Finally, to use the method cadastrarProdutos
, whatever the chosen form of the above, would be:
require "...";
$tabela = "produtos";
$campos = array('Nome', 'Descricao', 'Valor', 'ValorDesconto');
$valores = array_filter($_POST);
$metodos->cadastrarProdutos($tabela, $campos, $valores);
I hope I’ve helped!
One of the problems with this code is the injection of SQL and the difficulty of treating the parameters. This class will fatally violate Open-Closed Principle because the first chance of this approach being inadequate or insufficient for a data set you will have to modify the project or adding methods creating a spaghetti class or patching this method with gabiarras.
– Augusto Vasques