Publicidade (Anuncie Aqui)

Usando o MySQLi Orientado a Objetos

Usando o MySQLi Orientado a Objetos

Fala minha gente!

Hoje vou mostrar para vocês como usar a extensão MySQLi (MySQL Improved ou MySQL Melhorado) do MySQL.

Já falei um pouco sobre o MySQLi nesse post, mas foi sobre o método procedural, e hoje vamos falar sobre o método orientado a objetos.

Antes de mais nada: o MySQLi só está presente na versão 4.1.3+ do MySQL e na versão 5 do PHP, se você tem um servidor que não tenha alguma dessas versões, se mate. :)

E vejam que coisa interessante está escrita na Overview do MySQLi:

Note: If you are using MySQL versions 4.1.3 or later it is strongly recommended that you use this extension.

Que em tradução livre seria:

Nota: Se você está usando a versão 4.1.3 ou superior do MySQL é altamente recomendável que você use essa extensão.

Começando do começo: O velho modo

Acredito que todos vocês já viram uma conexão e consulta MySQL feita da seguinte forma:

<?php

// Conecta ao banco de dados
mysql_connect('127.0.0.1', 'usuario', 'senha');
mysql_select_db('meusite');

// "Hoje" em formato SQL
$data = date('Y-m-d');

// Monta e executa uma consulta SQL
$sql = "SELECT `id`, `titulo`, `link` FROM `noticias` WHERE `ativa` = 1 AND `data` <= '". $data ."'";
$query = mysql_query($sql);

// Para cada resultado encontrado...
while ($noticia = mysql_fetch_assoc($query)) {
	// Exibe um link com a notícia
	echo '<a href="'. $noticia['link'] .'" title="'. $noticia['titulo'] .'">'. $noticia['titulo'] .'</a>';
	echo '<br />';
} // fim while

// Total de notícias
echo '<br />Total de notícias: ' . mysql_num_rows($query);

?>

Não há nada de especial com esse código… Conectamos ao MySQL e depois procuramos todas as notícias ativas e anteriores ao dia de hoje (inclusive)… O código por si só não é feito nem “mal organizado”, mas isso é por que vocês ainda não conhecem o MySQLi!

Orientação a Objetos: a beleza programação

Agora veja o código que faz a mesma coisa que o anterior, só que em sua versão MySQLi orientada a objetos:

<?php

// Conecta ao banco de dados
$mysqli = new mysqli('127.0.0.1', 'usuario', 'senha', 'meusite');

// Verifica se ocorreu algum erro
if (mysqli_connect_errno()) {
    die('Não foi possível conectar-se ao banco de dados: ' . mysqli_connect_error());
    exit();
}

// "Hoje" em formato SQL
$data = date('Y-m-d');

// Prepara uma consulta SQL
if ($sql = $mysqli->prepare("SELECT `id`, `titulo`, `link` FROM `noticias` WHERE `ativa` = 1 AND `data` <= ?")) {

	// Atribui valores às variáveis da consulta
	$sql->bind_param('s', $data); // Coloca o valor de $data no lugar da primeira interrogação (?)

	// Executa a consulta
	$sql->execute();

	// Atribui o resultado encontrado a variáveis
	$sql->bind_result($id, $titulo, $link);

	// Para cada resultado encontrado...
	while ($sql->fetch()) {
		// Exibe um link com a notícia
		echo '<a href="'. $link .'" title="'. $titulo .'">'. $titulo .'</a>';
		echo '<br />';
	} // fim while

	// Total de notícias
	echo '<br />Total de notícias: ' . $sql->num_rows;

	// Fecha a consulta
	$sql->close();
}

// Fecha a conexão com o banco de dados
$mysqli->close();

?>

De primeiro contato sei que muita gente vai achar que o MySQLi é mais complicado, é só ver o número de linhas: quase o dobro.. Mas o MySQLi tem uma vantagem indescutível em cima do MySQL normal: a segurança.

Primeiro nós PREPARAMOS uma consulta com um local para receber um valor variável… É aquela interrogação.

Depois nós dizemos que o local reservado receberá um conteúdo do tipo string (s) com valor $data.. Ou seja, se $data fosse um inteiro ou booleando a consulta daria um erro, ela só aceitará strings, e digo mais: strings que não modifiquem a consulta… se for uma SQL Injection o MySQLi irá escapá-la e ele [o ataque] não funcionará!

Depois é só executar, reservar variáveis para o resultado e usá-las com um fetch() normal.. ;)

Vejam um exemplo de consulta com três parâmetros: duas strings e um inteiro:

<?php

// "Hoje" em formato SQL
$data = date('Y-m-d');
// Nome do autor
$autor = 'Thiago Belem';

// Prepara uma consulta SQL
if ($sql = $mysqli->prepare("SELECT `id`, `titulo`, `link` FROM `noticias` WHERE (`data` <= ?) AND (`ativa` = ?) AND (`autor` = ?)")) {

	// Atribui valores às variáveis da consulta
	$sql->bind_param('sis', $data, 1, $autor);

	// Executa a consulta
	$sql->execute();

	// ... Todo o resto é igual
}
?>

Nessa consulta nós reservamos espaços para três variáveis… Depois nós passamos os seus tipos e valores usando o método bind_param(), o primeiro parâmetro traz os tipos dos valores, no exemplo foi usado “sis” que significa: uma string, um integer (inteiro) e uma string… Depois nós passamos os valores normalmente.. :)

Os tipos de valores aceitos pelo MySQLi são:

  • i para integer (inteiro)
  • s para string
  • d para double (decimal)
  • b para blob

Quem quiser saber um pouco mais sobre MySQLi, é só checar a documentação no php.net, e não se esqueça de deixar o seu comentário agradecendo (ou reclamando o.O)!

Espero que tenham gostado! :)

Você também vai gostar de ler:

Postado em Artigos, Destaques, MySQL, PHP, Tutoriais

Com as tags , , , , , , , , , , , , , , , , , , , , , , , , ,

Escrito por Thiago Belem

Gostou desse artigo?

Não se esqueça de assinar o RSS e divulgue-o para o mundo:

View Comments

  1. André disse:

    Lembrando que funções como bind_param são obsoletas e serão removidas.
    Agora é mysqli_stmt_bind_param

    André.

  2. Vinícius disse:

    E aí Thiago,

    Cara, me tira uma dúvida. A extensão antiga retorna um vetor em consultas, isso não é melhor do que criar outras variáveis pra imprimir esses valores? Tem como fazer isso no Mysqli? Não é mais usual, ou eu tô falando besteira? :D

    abraço

  3. Hugo Leonardo disse:

    Thiago, seria redundante usar o mysql_real_scape_string em conjunto com o mysqli? ou tornaria mais seguro?

    e se for redundante, eu perderia alguma coisa se optar por usar mysql_query em conjunto com mysql_real_scape _string (eu acho mais fácil de escrever o código) ou tem mais alguma vantagem que eu estaria perdendo além da proteção contra o SQL Injection?

    Obrigado desde já.

    • Thiago Belem disse:

      @Hugo
      Acredito que você não coneguiria usar os dois juntos pois o mysql_real_scape_string() usa a conexão aberta com o mysql_connect(), o que você não terá se usar MySQLi (que abre uma outra conexão).

      O MySQLi é mais rápido e mais seguro que o MySQL normal e procedural… Além da segurança existem outros recursos que você pode fazer uso no MySQLi como os stored procedures onde você tem um “padrão” de consulta e você muda apenas as variáveis… É como se, na versão procedural, você fizesse uma função para realizar a consulta X mas recebendo como parâmetros algumas variáveis que serão usadas dentro da consulta.

      Até a própria documentação do PHP recomenda que você use o MySQLi se você tiver a opção de usá-lo (leia-se: se ele existir no seu servidor). :)

  4. Bruno disse:

    Thiago blz?
    Cara, eu usava essa classe do fabyo
    http://forum.imasters.uol.com.br/index.php?/topic/125343-classe-de-conexao-com-mysqli/

    Gostei muito da sua, será que teria como adptar?? Tipo da um prepare e um execute ?

    [s]

  5. Vinícius Almeida disse:

    Opa, realmente uma excelente dica!

    Como sugestão, você poderia fazer um artigo sobre as Stored Procedures.

    Abraço ai pro pessoal de Pará… huahuahauha ^^

  6. Leandro disse:

    Parabéns pelo post. Já tinha lido o anterior e não tinha percebido muito bem as vantagens. Agora sim foi possivel notar como é útil esta extensão. Vlw

  7. hugo leonardo disse:

    tenho umas dúvidas….

    você usa um if na hora de preparar a query, então se houver algum erro na preparação, como uma sintaxe errada, a preparação retorna zero e o resto não seria executado?

    se ainda seria possível acontecer SQL injection mesmo usando o MySQLi, como funcionaria isso já que você disse que ele bloqueia? como evitar?

    uhh…tive um problema recentemente quando coloquei um nome de um campo de uma tabela minha como ‘group’. o problema se resolveu quando eu simplesmente mudei o nome do campo. seria esse um nome proibido ou coisa assim?

    acho que é só :p
    haha, abusei nas perguntas. mas se puder me ajudar com essas dúvidas eu fico meeega grato (:

    • Thiago Belem disse:

      @Hugo Leonardo

      você usa um if na hora de preparar a query, então se houver algum erro na preparação, como uma sintaxe errada, a preparação retorna zero e o resto não seria executado?

      Exatamente :)

      se ainda seria possível acontecer SQL injection mesmo usando o MySQLi, como funcionaria isso já que você disse que ele bloqueia? como evitar?

      Com o prepare e os parâmetros (?) na query, quando você passa o parametro para a consulta você diz de que tipo ele é (string, integer e etc.) e o MySQLi cuida de escapar o parâmetro para evitar injection.

      uhh…tive um problema recentemente quando coloquei um nome de um campo de uma tabela minha como ‘group’. o problema se resolveu quando eu simplesmente mudei o nome do campo. seria esse um nome proibido ou coisa assim?

      GROUP é uma palavra reservada do MySQL, assim como outras palavras como SELECT, UPDATE, DELETE, WHERE, FROM, ORDER e etc… Você pode ver uma lista das palavras reservadas aqui: http://dev.mysql.com/doc/refman/5.1/en/reserved-words.html

  8. Plinio pavin disse:

    Parabéns Thiago. Você poderia me dizer se existe alguma vantagem do mysqli sobre o PDO ?

    • Thiago Belem disse:

      @Plinio
      O MySQLi é só para MySQL já o PDO funciona com SQL Server, Firebird/Interbase, MySQL, Oracle, ODBC, DB2, PostgreSQL e SQLite… Eu pessoalmente prefiro o MySQLi.. Mas isso vai de cada um.

  9. Sempre me perguntei a diferença entre o MySql e o MySqli, mas nunca tinha ido atras saber. Teu artigo esclareceu as idéias. Valeu.

  10. Jeferson disse:

    eu prefiro continuar usando o PDO do PHP :P

  11. Ronald disse:

    Show!

    A primeira vez que li pensei que fosse mysql(li) de light.

    Agora que vi que é mysql(i) de Improved.

    Muito bom o artigo.

    Parabéns!

  12. Fillipe Moraes disse:

    Confesso que não entendi muito bem. Especialmente na parte de atribuir a variável.

    1º – Por que fazer desse modo? Pq não montar a query diretamente?
    Ex: Pq não colocar diretamente a variável $hoje no lugar do 1º ‘?’ ?
    $mysqli->prepare("SELECT `id`, `titulo`, `link` FROM `noticias` WHERE (`data` <= ?) AND (`ativa` = ?) AND (`autor` = ?)")

    2º – O que significa o ‘sis’ do código abaixo?
    Ex: $sql->bind_param('sis', $hoje, 1, $autor);

    • Thiago Belem disse:

      @Fillipe
      1º – A “graça” do MySQLi está justamente nos prepared statements que é esse formato onde você prepara a query antes e passa os parâmetros depois.
      2º – Leia o artigo com mais atenção que explico o por que do “sis”. :)

  13. Leandro disse:

    Thiago “de Belém”, foi ótimo. auhuahuahaua.

    E então você recomenda msm o MySQLi ? Msm usando o ainda tem algum risco de SQL Injection?

    Muito legal essa dica Thiago, valew!

    • Thiago Belem disse:

      @Leandro
      Sim, eu recomendo… E sim, ainda há risco de SQL Injection, por isso você deve fazer as coisas com atenção e responsabilidade… Não é uma funcionalidade ou extensão que vai deixar o seu sistema seguro.

  14. villas disse:

    Cara enfiei o pé fundo no ADOdb que faz estas 44 linhas em 5 e achei o máximo. Eu acredito que em termos de segurança, satisfaça os requisitos mas fico sempre me perguntando se seria adequado ou se terá suporte no futuro e tal. Na php 5.3 o odbc é nativo certo? será que é uma boa opção tb para o MySQL?

    Abrax

  15. Leonardo Tavares disse:

    É muito bom rever algumas funcionalidades :)

    Acredito que tenha ocorrido um erro de declaração de variáveis, veja:

    $sql->bind_param('sis', $hoje, 1, $autor);

    No início você fez a seguinte declaração: $data = date(‘Y-m-d’);

    Logo o correto seria assim, não?

    $sql->bind_param('s', $data);

    Abraços!

  16. Eduardo Spek disse:

    Sigo seu blog e aprendo muita coisa. Parabéns!

  17. Carlos Alan disse:

    Olá Thiago.. Parabéns pelo post
    Morei um tempo em Belém.. agora vejo que tem gente boa nesses lados dai..
    Abs

  18. Renan Leme disse:

    Fora o while estar errado no primeiro código, está muito bom o teu texto!

    Realmente é um pouco complicado no começo, mais acho que depois de usar umas 3 x já fica sussa :D

    O problema é usar a primeira hdsauihdusai

    Linha 15: whlie

    []‘s

blog comments powered by Disqus