How do prepare dynamic and generic with mysqli?

Asked

Viewed 296 times

4

I have a mobile application that sends me the following parameters

$tabela    = $_POST[“tabela”];    // ex: “pessoa”
$atributos = $_POST[“atributos”]; // ex: “codigo, nome, cpf”
$valores   = $_POST[“valores”];   // ex: “10, Rafael, 1234567890”
$argumento = $_POST[“argumento”]; // ex: “iss”
$tamanho   = $_POST[“tamanho”];   // ex: “?, ?, ?”

After receiving the parameters, I make the prepare. This prepare will be generic. My question is on how I catch the $valores and save in new variables to be inserted in the $codigo, $nome, $cpf?

Remembering that this function is dynamic, time can receive a person, once a payment with more or less attributes and so on.

I thought about creating variables at runtime but I don’t know if that’s possible.

$stmt = $conn->prepare("INSERT INTO $tabela ($atributos) VALUES ($tamanho)");
$stmt->bind_param($argumento, $codigo, $nome, $cpf);
  • How about using a cycle to pick them all up until they’re done? Or this bind_param is not as it should be and should receive an array of values instead of the values themselves separately.

  • Can you show an example with array? So just make a explode in the $values variable

  • I just understood your question now, I’ll give you an answer.

  • I thought the idea was cool until I saw the table name and the names of the columns passed by POST. I believe that for these 2 it is better to use a string in the code itself rather than go through POST. The size can be dynamically identified by the number of column name posts sent.

  • @rray are variable arrays, this does not serve.

  • @Jorgeb. if I understand correctly just unpack (php5.6) $valores in $stmt->bind_param() otherwise only your answer will solve even.

  • @rray and that’s it, but he says $valores may be something other than the example. I also only noticed after Rafael’s comment.

  • Test my answer with your table. Any questions ask. Note that the generic_PDO_insert($connects,$table,$columns,$post) function can be used in any script, with an require, left together just to simplify. You can pass $table and $columns for $_POST and clear before moving to the function if you wish, but it is safer to set table name and column array in the script and take only form values.

Show 4 more comments

3 answers

3

What you want to do is a bind_param with variable arguments, you can create a reference array and use callback call_user_func_array to associate the bind function to the parameter array:

public function my_bind_param( $stmt, $argumento, $array_valores ) 
{
    $params = array_merge($argumento, $array_valores);

    return call_user_func_array( array( $stmt, 'bind_param' ), 
                                 referenciar( $params ));
}

private function referenciar( $array )
{
        $ref = array();

        foreach( $array as $key => $value )
            $ref[$key] = &$array[$key];

        return $ref;
} 

2

Well, it seems kind of strange to answer your own question, but it’s just that everyone who responded helped me to put together this script and come up with a result that I found satisfactory.

Below is just the parts referring to the question I performed, and this web-server I am developing contains more functionalities.

I don’t have much experience with security yet, but from what I’ve researched, it sounds like a good solution. Anyone who thinks otherwise, please express yourself because it will help me a lot.

follows the code:

<?php

include_once 'Funcoes.php';
include_once 'Config.php';
include_once 'MinhasTabelas.php';

class Util {

private $con;
private $tabela;
private $funcoes;

/**
 * Recebe a tabela que sera manipilada
 * O costrutor cria uma instancia da classe Funcao que contem funcoes uteis.
 * Depois elecria uma nova conexao mysqli e salva no atributo $con.
 * @param type $tabela : "usuario" : Nome da tabela que sera manipulada.
 */
public function __construct($tabela) {
    // Verifica se a tabela existe no banco de dados. se sim, segue o codigo ou para o programa.
    if ((new Tabelas ())->isExist($tabela)) {
        $this->tabela = $tabela;
        $this->funcoes = new Funcao();

        // Cria uma conexão;
        $this->con = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
        // Verifica conexão
        if ($this->con->connect_error) {
            $flag['flag'] = 'CONN_FAILED';
            die (json_encode($flag));
        }
    }else{
        $flag['flag'] = 'INVALID_TABLE';
        die(json_encode($flag));
    }
}

/**
 * Insere um registro no banco de dados.
 * @param type $atributos   = "nome, idade, sexo"
 * @param type $valores     = "rafael, 21, M"
 * @param type $argumentos  = "sis" 
 * @return int = json formated
 */
public function create($atributos, $valores, $argumentos) {
    $qtdValores = $this->funcoes->getInterrogacoes($atributos);

    $valores = explode(",", $valores);

    $sql = "INSERT INTO $this->tabela ($atributos) VALUES ($qtdValores)";
    if ($stmt = $this->con->prepare($sql)) {
        $stmt->bind_param($argumentos, ...$valores);
        $stmt->execute();

        if ($stmt->affected_rows >= 1) {
            $json['flag'] = $stmt->insert_id;
        } else {
            $json['flag'] = 0;
        }
    } else {
        $json['flag'] = 0;
    }

    $stmt->close();
    $this->con->close();

    return $json;
}

}

class Tabelas {

private $tabs;

public function __construct() {
    // Em $tabs devera conter todas as tabelas que serão manipiuladas pelo sistema.
    // Elas devem ser separadas por ", " (virgula e um espaço);
    $tabs = "adm, usuario";
    $this->tabs = explode(", ", $tabs);
}

/**
 * Verifica se a tabela passada por parametro existe no banco de dados.
 * @param type $tabela = "usuario" : Nome da tabela que será verificada a existencia
 * @return boolean : retorna um true ou false
 */
public function isExist($tabela) {
    foreach ($this->tabs as &$val) {
        if ($val === $tabela) {
            return TRUE;
        }
    }
    return FALSE;
}

}

class Funcao {

/**
 * Esse metodo tem a função de trazer as quantidades de variaveis que serão manipuladas
 * @param type $param = "nome, sexo"    : Recebe os parametros que serão manipilados
 * @return type = "?, ?"                : retorna uma String com as ? para mysqli->prepare.
 */
function getInterrogacoes($param) {
    $qtdValores = explode(",", $param);
    foreach ($qtdValores as &$value) {
        $value = "? ";
    }
    $qtdValores = implode(",", $qtdValores);
    return $qtdValores;
}

}

1

I have now created a generic insertion function using PDO.

To test, I created a table with two fields:

CREATE TABLE `teste` 
( 
    `id` INT NOT NULL AUTO_INCREMENT , 
    `nome` VARCHAR(255) NOT NULL , 
    `email` VARCHAR(255) NOT NULL , 
    PRIMARY KEY (`id`)
);

Html form:

<!DOCTYPE html>
<html>
<head>
    <title>Teste Insert PDO Genérico</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

</head>
<body>

<form action="pdo_generico.php" method="post">

    Nome: <input type="text" name="nome"><br>
    E-mail: <input type="mail" name="email"><br>
    <input type="submit" value="Enviar">

</form>

</body>
</html>

pdo_generico.php

<?php
//CONFIG CONEXÃO
$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'root';
$password = '';

// CONFIG TABELA E COLUNAS
$tabela = "teste";


                            // Os tipos podem ser:  
                            // bool,  int, str, file, outros(será tratado como str) 
$colunas = array(
                 'nome'  => 'str',
                 'email' => 'str',
                 );  

try 
{
    $pdo_connection = new PDO($dsn, $user, $password);
} catch(PDOException $e) 
{
    echo 'Connection failed: ' . $e->getMessage();
}   

$retorno_do_insert =  generic_PDO_insert($pdo_connection, $tabela, $colunas, $_POST);

if($retorno_do_insert)
{
    echo 'Dados inseridos com sucesso.';
}
else
{
    echo 'Erro.';
}

// =============================================

function generic_PDO_insert($conecta,$tabela,$colunas,$post)
{

    $pdo_tipos = array(
                        'bool'  => PDO::PARAM_BOOL, 
                        'int'   => PDO::PARAM_INT,
                        'str'   => PDO::PARAM_STR, 
                        'file'  => PDO::PARAM_LOB,
                        'outros'=> PDO::PARAM_STR
                      );        

    // Remove os campos que não forem enviados por POST para não criar placeholders para eles
    $colunas_existentes = array();
    $colunas_arr_key = array();
    foreach($colunas as $coluna => $tipo)
    {
        if(isset($post[$coluna]))
        {
            $colunas_existentes[$coluna]=$tipo;
            $colunas_arr_key[]=$coluna;
        }
    }
    $colunas = $colunas_existentes;

    //GERA os PLACEHOLDERS
    $colunas_str='';
    $placeholders_str='';

    $colunas_str = implode(",",$colunas_arr_key);
    $placeholders_str = ':'.implode(",:",$colunas_arr_key); 

    $sql= "INSERT INTO $tabela($colunas_str) VALUES($placeholders_str)";
    // echo $sql;

    try
    {
        $query= $conecta->prepare($sql);

        foreach ($colunas as $coluna => $tipo) 
        {
            $query->bindValue(":$coluna", $post[$coluna], $pdo_tipos[$tipo]);
        }

        $query->execute();

        return true;
    }
    catch(Exception $e)
    {
        return false;
        //echo $e->getMessage();
    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.