Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Annyh

[Resolvido] funcao para inserir dados no bando de dados, adaptand

Recommended Posts

salve pessoal...

 

tenho uma função para inserir dados no banco, ela funciona muito bem...

 

a chamada dela é assim:

 

inserir('tabela', 'valor_para_inserir_vindo_do_array');
array('id' => NULL, 'descricao' => 'Programador');

 

a saída é essa: INSERT INTO produto (id, descricao) VALUES ('', 'Programador')

 

ta funcionando certinho...

 

mas queria adapta-lá para PDO, mas não to conseguindo, ja que em PDO tem o bindValue:

 

$qr->bindValue(':campo', $varialvel, PDO::PARAM_STR|INT|etc);

 

como fazer para dinamicamente ele fazer o bindValue corretamente?

 

minha função completa:

 

<?php

mysql_connect('localhost', 'root', '') or die (mysql_error());
mysql_select_db('teste') or die (mysql_error());

function inserir($tabela, $dados) {

// verifica se os dados são um array
if (is_array($dados)) {

	$totalCampos = count($dados); // conta total de campos que serão inseridos
	$posicao = array_keys($dados); // pega posição no array de acordo com o índice

	$sql = 'INSERT INTO ' .$tabela. ' (';

	for ($i = 0; $i < $totalCampos; $i++) {
		$sql .= $posicao[$i] . ', ';

	}

	$sql = substr($sql, 0, -2);
	$sql .= ') VALUES (';
	$indice = 0;

	for ($i = 0; $i < $totalCampos; $i++) {
		$sql .= "'" .$dados[$posicao[$i]]. "', ";
	}

	$sql = substr($sql, 0, -2);
	echo $sql .= ')';
} else {
	echo 'São permitido apenas entrada por array!';
	die();
}

$res = mysql_query($sql) or die ('<br />ERRO SQL: ' .mysql_error());
}

$dados = array('id' => NULL, 'descricao' => 'Programador');
inserir('produto', $dados);
?>

Compartilhar este post


Link para o post
Compartilhar em outros sites

Andrey, vi isto no manual do PHP mas não entendi muito bem, nem consigo aplica-lo, tu não pode dar outra dica ou um exemplo mais explicativo?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olha só que legal a saída do code abaixo:

 

$fields = array( 'id' => NULL, 'name' => 'Bruno', 'age' => 23 );

// Está separado pois a linha acima não existe. array_filter() vai receber o array que você passar

$fields = array_filter( $fields );

$table = 'users';

printf(

   'INSERT INTO `%s` ( `%s` ) VALUES ( %s )',

   $table,

   implode( '`, `',
       array_keys( $fields )
   ),

   implode( ', ',
       array_fill( 0, count( $fields ), '?' )
   )
);

Vou explicar.

 

Primeiro você "limpa" seu array de dados, removendo todos os valores vazios dele através da função array_filter() sem segundo parâmetro.

 

Isso porque você não precisa das partes do SQL referentes a campos nulos pois se um campo pode ser nulo, omitir da query já o fará. Se ele não pode ser nulo, você deve validar antes de montar a query.

 

Depois você monta sua query. printf() vai ecoar em tela. No seu caso, como a query vai ser passada para PDO::prepare(), você vai usar sprintf().

 

Você pode não usar a função e ir concatenando tudo. Mas assim fica bem mais legível :thumbsup:

 

Meu printf() tem três placeholders: Um para a tabela, que virá através de parâmetro e outros dois para, respectivamente, os campos a serem inseridos e seus valores.

 

Tanto para os campos como para os valores, a estrutura são strings separadas por vírgulas. Como os nomes dos campos já estão nos índices do array, array_keys() aliado à implode() é a combinação perfeita.

 

Já os valores você não vai preenchê-los na query, mas sim criar novos placeholders para que PDOStatement::execute() saiba o que fazer.

 

Como você nem sempre vai saber quantos campos estarão sendo passados, para evitar loops e condicionais desnecessários, usamos array_fill() que vai criar um novo array ali, na hora, com aquilo que você vai passar.

 

E você vai justamente passar o símbolo de interrogação, chamado no âmbito da PDO "muito criativamente" de question mark placeholders tantas vezes quantos valores existirem no array. E para isso usamos count()

 

Com a query pronta, basta passá-la para PDO::prepare() e invocar PDOStatement::execute() passando como argumento o array que você limpou lá em cima.

 

O próprio método se encarregará de combinar os nomes dos campos com os placeholders e atribuir os devidos valores direitinho.

 

E você não faz mais nada :grin:

Compartilhar este post


Link para o post
Compartilhar em outros sites

Value Bruno, deu quase tudo certo aqui no meu script...

ta dando um erro Warning: PDOStatement::execute() expects parameter 1 to be array, string given in C:\wamp\www\funcao_insert.php on line 49;

 

<?php

function inserir($tabela, $dados) {
// arquivo de conexão
require 'config.php';

// verifica se os dados são um array
if (is_array($dados)) {

	$totalCampos = count($dados); // conta total de campos que serão inseridos
	$posicao = array_keys($dados); // pega posição no array de acordo com o índice

	$sql = 'INSERT INTO ' .$tabela. ' (';

	for ($i = 0; $i < $totalCampos; $i++) {
		$sql .= $posicao[$i] . ', ';

	}

	$sql = substr($sql, 0, -2);
	$sql .= ') VALUES (';
	$indice = 0;

	for ($i = 0; $i < $totalCampos; $i++) {
		$sql .= "'" .$dados[$posicao[$i]]. "', ";
	}

	$sql = substr($sql, 0, -2);
	echo $sql .= ')';

} else {
	echo 'São permitido apenas entrada por array!';
	die();
}

// filtra os dados
$dados = array_filter($dados);

$sql1 = sprintf (
		    'INSERT INTO %s (%s) VALUES (%s)',
			$tabela,
		    implode(', ', array_keys($dados)),
		    implode(', ', array_fill(0, count($dados), '?'))
    	);

try {

	$qr = $conecta->prepare($sql1);
	$qr->execute($dados);

} catch (Exception $erroSQL) {
	echo 'Erro:<br />', $erroSQL->getMessage();
}

echo 'valor da sql1: ', $sql1;
}

// passando os valores e chamado a função para inserir
$dados = array('descricao' => 'Programador');
inserir('produto', $dados);

?>

Compartilhar este post


Link para o post
Compartilhar em outros sites

A idéia do Bruno Augusto é perfeita, basta você adaptar o bindValue para não ter problemas com injection.

<?php
	$PDO = new PDO( ... );

	function createInsertStatement( Array $Data , $Table ) { 
		 $Data = array_filter( $Data ) ;
		 $SQLStatement = sprintf( 'INSERT INTO `%s`( `%s` ) VALUES( %s )' , $Table ,
		 implode( '`, `' , array_keys( $Data ) ) , implode( ', ' , array_fill( 0 , count( $Data ) , '?' ) ) );
		 return $SQLStatement;
        }

	function attach( Array $Data , PDOStatement $Statement ) {
	         $i = 1 ;
	 	 foreach( $Data as $Value ) {
		  	  $DataType = !is_numeric( $Value ) ? PDO::PARAM_STR : PDO::PARAM_INT;
			  call_user_func( Array( $Statement , 'bindValue' ) , $i , $Value , $DataType );
			  ++$i;
	         }
	}

	$Dados =  Array( 'id' => 10 , 'nome' => 'aeiou' );

	$Statement = $PDO->prepare( createInsertStatement( $Dados , 'teste' ) );
	attach( $Dados , $Statement );

	print_r( $Statement->debugDumpParams() );
	$Statement->execute();

 

Saída:

SQL: [50] INSERT INTO `teste`( `id`, `nome` ) VALUES( ?, ? )
Params:  2
Key: Position #0:
paramno=0
name=[0] ""
is_param=1
param_type=1
Key: Position #1:
paramno=1
name=[0] ""
is_param=1
param_type=2

 

No banco de dados ..

C:\dev\mysql\bin>mysql -u root -p
Enter password: ************
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 14
Server version: 5.1.41 Source distribution

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create schema teste;
Query OK, 1 row affected (0.03 sec)

mysql> use teste;
Database changed
mysql> create table teste(
   ->     id integer,
   ->    nome varchar( 10 )
   -> );
Query OK, 0 rows affected (0.11 sec)

mysql> select * from teste;
+------+---------+
| id   | nome    |
+------+---------+
|   10 | aeiou   |
+------+---------+
1 rows in set (0.02 sec)

mysql>

Compartilhar este post


Link para o post
Compartilhar em outros sites

Mas Andrey, não precisa fazer o bind semi-manualmente.

 

No seu exemplo mesmo, basta:

 

$Dados =  Array( 'id' => 10 , 'nome' => 'aeiou' );

$Statement = $PDO->prepare( createInsertStatement( $Dados , 'teste' ) );

$Statement->execute( array_values( $Dados ) );

PDOStatement::execute() se encarregará sozinho de combinar as interrogações com os respectivos valores.

 

Mas, se comparar tem apenas uma coisinha de diferente, que esqueci de mencionar antes.

 

Descobri "aos trancos e barrancos" que quando usando question mark placeholders, pelo menos para alguns drivers suportados pela PDO, você deve enviar um array indexado numericamente, então deve-se passar um array_value() para reindexar o array ali, na hora.

 

@Annyh, seu código ficou confuso. Você apenas pegou o que eu escrevi e jogou dentro da sua função antiga gerando códig desnecessário.

 

O problema é que o jeito que você fazia antes, considerava uma verificação com is_array() e agora o bloco novo ficou fora dele.

 

Eu imagino que alguma coisa está sobrescrevendo o $dados, alterando o tipo dele.

 

Dá uma olhadinha no código do Andrey, especificamente na declaração da função e veja o que tem de diferente do seu e você vai entender o porquê sua função não precisa desse is_array() e vai garantir que funcione.

Compartilhar este post


Link para o post
Compartilhar em outros sites

galera, na boa...

 

vocês me fizeram ficar mais confusa do que ja estava...

 

o Andrey mostra um código, o Bruno mostra outro...

 

poxa eu não manjo tanto quanto vocês de PDO...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bruno, .. você não entendeu o uso do call_user_func .. o execute vai tratar tudo como String, qualquer valor .. então se você tiver inteiro, ele vai entrar lá no banco com 'aspas' e ser tratado como string.

An array of values with as many elements as there are bound parameters in the SQL statement being executed. 
All values are treated as PDO::PARAM_STR.

 

Descobri "aos trancos e barrancos" que quando usando question mark placeholders, pelo menos para alguns drivers suportados pela PDO, você deve enviar um array indexado numericamente, então deve-se passar um array_value() para reindexar o array ali, na hora.

 

Veja onde o $i da função attach começa, não precisava dos 'trancos e barrancos' para descobrir isso ..

Parameter identifier. For a prepared statement using named placeholders, this will be a parameter name of the form :name. 
For a prepared statement using question mark placeholders, this will be the 1-indexed position of the parameter.

 

Annyh, o código é o mesmo .. apenas passei pra uma função separada .. da mesma forma que você pode usar a função 'attach', você pode usar sem ela, da forma que o Bruno Augusto mostrou, enviando $Dados para o execute.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Andrey, então...

 

resumindo fica como, qual o certo?

 

meu script agora esta assim, mas acho ele meio confuso para mim...

 

<?php

define('HOST', 'localhost');
define('USER', 'root');
define('SENHA', '');
define('BD', 'teste');

$conex = 'mysql:host='.HOST.';dbname='.BD;
$PDO = new PDO($conex, USER, SENHA);

function Inserir(Array $dados, $tabela) { 
$dados = array_filter($dados);
$SQLStatement = sprintf('INSERT INTO `%s` (`%s`) VALUES (%s)', $tabela,
implode('`, `', array_keys($dados)),
implode(', ', array_fill(0, count($dados), '?')));
return $SQLStatement;
}

function anexa(Array $dados, PDOStatement $qr) {
$i = 1 ;

foreach($dados as $valor) {
	$tipoDado = !is_numeric($valor) ? PDO::PARAM_STR : PDO::PARAM_INT;
	call_user_func(Array($qr, 'bindValue'), $i, $valor, $tipoDado);
	++$i;
}
}

$dados =  Array('nome' => 'Junior', 'sobrenome' => 'Eberhardt');
$qr = $PDO->prepare(Inserir($dados, 'produto'));
anexa($dados, $qr);

//print_r($qr->debugDumpParams());
$qr->execute();

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ao meu ver, está tudo certo.

 

 

então tambem esta protegido contra sqlinjection?

 

se sim eu vou colocar o script no banco de scripts, certo?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bruno, .. você não entendeu o uso do call_user_func .. o execute vai tratar tudo como String, qualquer valor .. então se você tiver inteiro, ele vai entrar lá no banco com 'aspas' e ser tratado como string.

An array of values with as many elements as there are bound parameters in the SQL statement being executed. 
All values are treated as PDO::PARAM_STR.

Bom a julgar que quando desenvolvi esta parte em particular do meu sistema e com os testes que eu fiz, mesmo que o campo na Tabela fosse um tipo numérico, se eu cadastrasse um inteiro ou uma string numérica, ao fazer o SELECT sempre me retornava como string numérica.

 

Veja onde o $i da função attach começa, não precisava dos 'trancos e barrancos' para descobrir isso ..

Parameter identifier. For a prepared statement using named placeholders, this will be a parameter name of the form :name. 
For a prepared statement using question mark placeholders, this will be the 1-indexed position of the parameter.

Quando eu criei pela primeira vez (mas a primeira meeeesmo), achava mais fácil os named placeholders, até mesmo para depurar.

 

Evoluindo, percebi que, nativamente, a depuração com qualquer dois dois tipos de placeholder era a mesma, sendo ambas limitadas, então fiz algo melhor.

 

E então, ampliei o sistema, permitindo suportar com maior precisão cada particularidade dos drivers da PDO, e percebi que haviam algumas inconsistências em alguns deles, fazendo com que uma query construída com parâmetros nomeados não funcionasse da mesma forma que com interrogações.

 

Daí padronizei tudo e foi aí que caracterizou os "trancos e barrancos" citados.

Annyh, o código é o mesmo .. apenas passei pra uma função separada .. da mesma forma que você pode usar a função 'attach', você pode usar sem ela, da forma que o Bruno Augusto mostrou, enviando $Dados para o execute.

 

;)

Compartilhar este post


Link para o post
Compartilhar em outros sites

fiz uma outra função para facilitar a chamada da mesma..

 

<?php
function Inserir($dados, $tabela) {

require 'config.php';

function filtro(array $dados, $tabela) {
	$dados = array_filter($dados) ;
	$sql = sprintf('INSERT INTO `%s` (`%s`) VALUES (%s)',
	$tabela,
	implode('`, `', array_keys($dados)),
	implode(', ', array_fill(0, count($dados), '?')));

	return $sql;
}

function anexa(array $dados, PDOStatement $afirmacao) {
	$i = 1;
	foreach ($dados as $valor) {
		$tipoDados = !is_numeric($valor) ? PDO::PARAM_STR : PDO::PARAM_INT;
		call_user_func(array($afirmacao, 'bindValue'), $i, $valor, $tipoDados);
		++$i;
	}
}

//$dados = array('nome' => 'Isabelly', 'sobrenome' => 'LE');
$qr = $PDO->prepare(filtro($dados, $tabela));
anexa($dados, $qr);

//print_r($Statement->debugDumpParams());

$qr->execute();

}

$dados = array('nome' => 'Isabelly', 'sobrenome' => 'LE');
Inserir($dados, 'produto');

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.