Annyh 4 Denunciar post Postado Setembro 12, 2011 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 Knupp Vital 136 Denunciar post Postado Setembro 12, 2011 call_user_func_array, atrelando as variáveis na string do sql. Compartilhar este post Link para o post Compartilhar em outros sites
Annyh 4 Denunciar post Postado Setembro 12, 2011 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
Bruno Augusto 417 Denunciar post Postado Setembro 13, 2011 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
Annyh 4 Denunciar post Postado Setembro 13, 2011 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
Andrey Knupp Vital 136 Denunciar post Postado Setembro 14, 2011 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
Bruno Augusto 417 Denunciar post Postado Setembro 14, 2011 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
Annyh 4 Denunciar post Postado Setembro 14, 2011 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
Andrey Knupp Vital 136 Denunciar post Postado Setembro 14, 2011 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
Annyh 4 Denunciar post Postado Setembro 14, 2011 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
Andrey Knupp Vital 136 Denunciar post Postado Setembro 14, 2011 Ao meu ver, está tudo certo. Compartilhar este post Link para o post Compartilhar em outros sites
Annyh 4 Denunciar post Postado Setembro 14, 2011 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 Augusto 417 Denunciar post Postado Setembro 14, 2011 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
Annyh 4 Denunciar post Postado Setembro 14, 2011 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