Ir para conteúdo

POWERED BY:

Arquivado

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

Bruno_Quaresma

Porque Usar E Como Usar O Pdo Em Suas Aplicações Php

Recommended Posts

Entretanto, não há especificação nenhuma do que é utilizado em execute(). Exceto pelo fato de todos os dados serem tratados como PDO::PARAM_STR.

Agora você me preocupou. É sério isso? :o

 

Todo esse tempo eu achava que as possíveis conversões de tipo eram feitas automaticamente e agora isso vem contra aquilo que aprendi anos atrás.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Galera, boa noite!

 

Estou tentando fazer uma classe PDO para uso nos meus projetos mas tá osso.

 

Fiz os seguintes arquivos

 

PDOConnection.class.php (Classe de conexão PDO) Fonte: http://www.htmlstaff.org/ver.php?id=9527

<?php 

class PDOConnection{

	# recebe a conexão
	public $con 	= null;

	# qual o banco de dados? "mysql"
	public $dbType 	= "";

	# parâmetros de conexão
	public $host 	= "";
	public $user 	= "";
	public $senha 	= "";
	public $db 		= "";

	# seta a persistência da conexão
	public $persistent = false;

	# new PDOConnection( true ) <--- conexão persistente
	# new PDOConnection() <--- conexao não persistente
	public function PDOConnection( $persistent=false ){
		# verifico a persistência da conexao
		if( $persistent != false){ $this->persistent = true; }
	}

	public function getConnection(){
		try{
			# realiza a conexão
			$this->con = new PDO($this->dbType.":host=".$this->host.";dbname=".$this->db, $this->user, $this->senha,
			array( PDO::ATTR_PERSISTENT => $this->persistent ) );
			# realizado com sucesso, retorna conectado
			return $this->con;
			# caso ocorra um erro, retorna o erro;
		}catch ( PDOException $ex ){ echo "Erro: ".$ex->getMessage(); }
	}

	# desconecta
	public function Close(){
		if( $this->con != null )
		$this->con = null;
	}
}
?>

 

 

DB.php (Dados de acesso ao banco)

<?php 

# Abrindo conexão com banco de dados
require_once("PDOConnection.class.php");

try {
	$pdo = new PDOConnection();

	$pdo->dbType= 'mysql';
	$pdo->host 	= 'localhost';
	$pdo->user 	= 'ezequiel';
	$pdo->senha = '123';
	$pdo->db 	= 'adm';

	$pdo->getConnection();	
	$pdo = null;

}catch (PDOException $ex){ echo $ex->getMessage(); }
?>

 

 

teste.php (Aqui tento fazer um SLQ simples)

# Abrindo conexão com banco de dados
require_once("DB.php");

	   $stmte = $pdo->prepare("	SELECT 
	   								id_usuario, 
									nome, 
									email 
								FROM tb_usuario
								WHERE (usuario=:usuario) and (senha=:senha)");


	   $stmte->bindParam(':usuario', 'ezequiel', PDO::PARAM_STR);
	   $stmte->bindParam(':senha', '123', PDO::PARAM_STR);
	   $executa = $stmte->execute();

 

 

Ao executar recebo o seguinte erro

 

Fatal error: Call to a member function prepare() on a non-object in

 

Estou a tarde toda nisso e não encontro o problema.

 

Caso alguém tenha a solução ou uma classe melhor, posta para a galera.

 

Obrigado!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Não olhei o código de todo, fui atrás do problema apenas. Np arquivo DB.php, remova essa linha:

$pdo = null;

 

Entenda o que acontece. Você está criando a conexão, e logo após, atribuindo o valor NULL para a variável que antes continha objeto de conexão.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olá Gabriel!

 

Procurei entender o máximo antes de solicitar ajuda aqui no fórum.

Ontem havia removido aquela instrução, porém assim mesmo continua dando erro, o erro é outro agora.

 

Fatal error: Call to undefined method PDOConnection::prepare() in

 

Obrigado pela ajuda.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Aqui, no mesmo arquivo (DB.php), altere essa linha:

$pdo = $pdo->getConnection();

 

Não havia percebido qual classe estava sendo instanciada.

 

Assim vai funcionar de cara, mas deveria ser mudado o nome da variável.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Aqui, no mesmo arquivo (DB.php), altere essa linha:

$pdo = $pdo->getConnection();

 

Não havia percebido qual classe estava sendo instanciada.

 

Assim vai funcionar de cara, mas deveria ser mudado o nome da variável.

 

 

Gabriel, muito muito muito obrigado!

Você não tem ideia do quanto me bati com isso.

 

Fera, podes explicar o que estava acontecendo para eu entender?

 

Também peço que caso tenha sugestões ou uma classe melhor, favor indicar.

 

Valeu!!!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Você estava passando os parâmetros de conexão e retornando a conexão (getConnection()).

 

Entretanto, a conexão não estava sendo atribuída em variável alguma.

 

Como fábrica de conexões, esta aqui é excelente, bem complexa.

http://forum.imasters.com.br/topic/401441-organizar-codigo/page__p__1572696#entry1572696

Compartilhar este post


Link para o post
Compartilhar em outros sites

Obrigado pela explicação Gabriel.

 

Entendi agora.

 

 

Referente ao link que você passou, muito muito bom, porém me deu um nó nos neurônios.

Vou olhar novamente com calma no fim de semana.

Compartilhar este post


Link para o post
Compartilhar em outros sites

 

Um artigo breve que eu escrevi dando uma pequena introdução ao PDO e como utilizar seus recursos para deixar suas aplicações mais seguras.

Porque usar?

 

Além de ser bastante seguro o PDO é também bastante prático.

 

Para usá-lo basta apenas instanciar um objeto PDO com as configurações de acesso ao banco de dados.

 

<?php

$db = new PDO('mysql:host=localhost;dbname=nome_banco',$usuario,$senha);

?>

 

Organizando melhor o código ele ficará assim

 

 
<?php

//CONFIGURAÇÕES
$type_db = 'mysql';
$host = 'localhost';
$dbname = 'nome_do_banco';
$usuario = 'usuario';
$senha = 'senha';

$db = new PDO($type_db.':host='.$host.';dbname='.$db_name,$usuario,$senha);

?>

 

Agora podemos fazer nossas consultas. Imagine que você tem uma tabela chamada “usuarios” onde eu tenho os seguintes campos ‘nome,sobrenome,email,idade,estado‘ e precisamos selecionar os usuarios por uma certa idade no qual nos é passada via $_POST['idade'].

 

... Veja mais aqui

 

 

Espero que a pescaria tenha sido boa.

 

http://net.tutsplus.com/tutorials/php/pdo-vs-mysqli-which-should-you-use/

 

Aí nesse link fala lá na parte de Perfomance que MySQLi consegue uns 6,5% (pode ser muito em aplicações pesadas) de velocidade a mais que o PDO se usado prepared statements, e sem usar isso, é uns 2,5%.

 

 

A "deficiência", entre aspas porque não é e nunca foi da alçada da PDO suportar, estaria no fato de que ela não abstrai a pseudo-linguagem SQL em si.

 

Se separamos PHP do HTML do JavaScript do CSS, porque não separar, também o SQL?

 

Que tal mysql_queries.ini, postgre_queries.ini, sqlite_queries.ini??

 

Continuando... Se sua aplicação não tem qualquer possibilidade de usar outro SGBD, não existe motivo em se usar a PDO.

 

Se existe tal possibilidade, ainda assim deve-se pensar duas vezes antes de usá-la pelos motivos expostos acima (e outros mais).

 

E a reusabilidade de código?? Se eu posso ter código reutilizável independente de SGDB, eu vou amarrar só porque não tenho pretensão de trocar de driver?

 

Vinicius, quais os tipos de aplicações que jamais migrariam de banco de dados? Ou que a chance de isso acontecer seja bem pequena? Um dos que me vêm à são os hotsites, que depois de uns meses são excluídos.

 

Outro ponto. Antes de se começar a codificar um projeto, é feito um levantamento sobre o projeto e a empresa dona do mesmo. Dentre esses dados pode ser incluído uma projeção de crescimento tanto da empresa quanto do número de usuários em relação à divulgação da aplicação/site.

 

Acredito que todo mundo aqui conheça a realidade de mais de 80% dos projetos no nosso meio... O Twitter mesmo não foi pensado para ser escalável, todo mundo lembra das fail whales.

 

como disseram cada um pode ganhar em uma coisa mais você tem que por em check o que é melhor para o sistema.

 

Performance x Segurança

 

[...]

 

agora respondam pra vocês mesmo, querem o sistema rápido ou seguro?

 

Performance e segurança não devem ser features. Qual você escolhe? Performance ou segurança?? Ora bolas, eu escolho o maior nível de segurança possível com o maior nível de performance possível!!!

 

Como exemplo, posso citar que hoje é prática comum armazenar as senhas do BD passadas por um hash, qualquer que seja ele.

Você poria em cheque se deve ou não "sacrificar" performance em troca de armazenar as senhas criptografadas?

 

Prefiro me perguntar de outra forma:

Dentre as formas de segurança viáveis, qual me oferece melhor performance com o mesmo resultado??

 

parece que se falando de banco de dados essas duas coisas se desencontram pois o PDO tem uma excelente biblioteca na parte de segurança

 

Que camada de segurança PDO te adiciona????

 

 

Galera, boa noite!

 

Estou tentando fazer uma classe PDO para uso nos meus projetos mas tá osso.

 

Ja está errado partindo daqui. PDO já está pronta, você não faz uma classe PDO. Há uma série de antipadrões no seu código. A parte de programação em si também pode ser aprimorada.

 

Se você quer simplificar a forma de criar uma conexão PDO, sugiro que estude sobre o Design Pattern Factory, como o @Gabriel Heming já sugeriu.

 

Queridos, agora, minha opinião pessoal.

 

Não cheguei a testar a performance MySQLi vs PDO. Prefiro me agarrar ao manual:

It is recommended to use either the mysqli or PDO_MySQL extensions. It is not recommended to use the old mysql extension for new development. A detailed feature comparison matrix is provided below. The overall performance of all three extensions is considered to be about the same. Although the performance of the extension contributes only a fraction of the total run time of a PHP web request. Often, the impact is as low as 0.1%.

 

Ainda que existisse essa diferença de performance, ela é justificável: PDO é uma Façade para uma série de Adapters, enquanto o Mysqi se comunica diretamente com a lib do driver.

 

Particularmente, não dispenso a quantidade de formas que posso fazer FETCH no PDO por performance alguma. Também, como já citei acima, há a questão de reusabilidade e portabilidade de código. Os benefícios vão muito além de performance/pseudosegurança.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Complementando o assunto pertinente, diga-se de passagem, que o Evandro iniciou. Tem algo que, poucas pessoas conhecem sobre a PDO, que eu descobri "errando" para o bem da verdade.

 

É a interpretação das queries. Logo quando eu estava aprendendo PDO. Fazia muito tempo que não realizava uma query pura. O sistema já estava pronto, utilizava uma camada de abstração. Então, eu na minha "normalidade" escrevi a seguinte query:

"INSERT pessoa SET nome = 'Gabriel Heming';"

 

E para o meu espanto.... isso funcionou. A pdo reconhece que está tentando realizar um insert e que está escrito da mesma forma que um UPDATE, e trabalha isso para o desenvolvedor que errou.

Compartilhar este post


Link para o post
Compartilhar em outros sites
Que camada de segurança PDO te adiciona?

 

SQL injection, não precisa daquele monte de regex.

 

o fato do proprio PDO fechar a conexão sozinho também pode ser levado em conta tanto para velocidade quanto para segurança.

 

o que quero dizer a respeito de performance ou segurança é que cada SGBD vai lhe oferecer algo e você não pode juntar tudo.

Compartilhar este post


Link para o post
Compartilhar em outros sites

SQL injection, não precisa daquele monte de regex.

 

o fato do proprio PDO fechar a conexão sozinho também pode ser levado em conta tanto para velocidade quanto para segurança.

 

o que quero dizer a respeito de performance ou segurança é que cada SGBD vai lhe oferecer algo e você não pode juntar tudo.

 

Que regex, meu caro???

http://br2.php.net/manual/pt_BR/function.mysql-real-escape-string.php

 

Ainda que, até hoje, eu não tenha visto algo que não funcione assim:

 

str_replace('"', '\"', $valor);

 

<?php

$query = 'INSERT INTO table VALUES (":nome", ":sobrenome", ":idade")';
// 3 linhas, exatamente equivalente ao que seria feito com bindParam
$query = str_replace(':nome', str_replace('"', '\"', $_POST['nome']));
$query = str_replace(':sobrenome', str_replace('"', '\"', $_POST['sobrenome']));
$query = str_replace(':idade', str_replace('"', '\"', $_POST['idade']));

// ou, 1 linha, como seria feito com execute($_POST)
foreach ($_POST as $search => $value) $query = str_replace(":{$search}", str_replace('"', '\"', $value));

 

Convenhamos, quem não conhece SQL Injection não vai saber se proteger independente da forma como acesse o banco

<?php

/**
* Formulário de login, campos email e senha
* preenchi o campo email com o seguinte valor:
* "' or id > 0; -- "
*/

$query      = "SELECT * FROM mysql.user
               WHERE User = '{$usuario}' AND Password = '{$senha}'";

$pdo    = new PDO('mysql:host=localhost', 'root', 'root');
$stmt   = $pdo->query($query);

if ($stmt->rowCount()) { // logado
...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Evandro, agradeço pelas dicas.

Tenho certeza que meu código está falho e tem muito o que melhorar.

Estou aprendendo OOPHP agora, por isso dos erros, porém estou estudando muito, muito mesmo e a cada dica nova reviso todo o meu código para aplicá-la.

 

Neste momento estou tendo dificuldades de utilizar uma classe de conexão PDO juntamente com a Classe de usuários.

Vou postar o conceito que criei abaixo, depois de muita leitura e testes.

 

Qualquer dica será bem vinda.

 

 

PDOConnection.class.php

<?php # http://www.htmlstaff.org/ver.php?id=9527

class PDOConnection{

	# recebe a conexão
	public $con 	= null;

	# qual o banco de dados? "mysql"
	public $dbType 	= "";

	# parâmetros de conexão
	public $host 	= "";
	public $user 	= "";
	public $senha 	= "";
	public $db 		= "";

	# seta a persistência da conexão
	public $persistent = false;

	# new PDOConnection( true ) <--- conexão persistente
	# new PDOConnection() <--- conexao não persistente
	public function PDOConnection( $persistent=false ){
		# verifico a persistência da conexao
		if( $persistent != false){ $this->persistent = true; }
	}

	public function getConnection(){
		try{
			# realiza a conexão
			$this->con = new PDO($this->dbType.":host=".$this->host.";dbname=".$this->db, $this->user, $this->senha,
			array( PDO::ATTR_PERSISTENT => $this->persistent ) );
			# realizado com sucesso, retorna conectado
			return $this->con;
			# caso ocorra um erro, retorna o erro;
		}catch ( PDOException $ex ){ echo "Erro: ".$ex->getMessage(); }
	}

	# desconecta
	public function Close(){
		if( $this->con != null )
		$this->con = null;
	}
}
?>

 

 

DB.php

<?php 

# Abrindo conexão com banco de dados
require_once("PDOConnection.class.php");

class DB extends PDOConnection { 

		# Método Construtor
		public function __construct(){

			$this->dbType	= 'mysql';
			$this->host 	= 'localhost';
			$this->user 	= 'ezequiel';
			$this->senha	= '123';
			$this->db 		= 'adm';

			$pdo = $this->PDOConnection();
		}
}
?>

 

 

tb_usuario.class.php

Como pode ser notado aqui, transformei minha classe "Usuario" em uma extends da classe "DB" para usar a conexão da mesma.

Não sei se é a maneira correta, por isso estou aberto a sugestões.

<?php 
# Abrindo conexão com banco de dados
require_once('DB.php'); 


class Usuario extends DB { 

	# Nome da tabela de usuários
	var $tabelaUsuarios = 'tb_usuario';

	# Nomes dos campos onde ficam o usuário e a senha de cada usuário
	var $campos = array(
		'id_cliente' => 'id_cliente',
		'usuario' => 'usuario',
		'senha' => 'senha'
	);

	# O usuário e senha são case-sensitive?
	var $caseSensitive = true;

	# -------------------------------------------------- #

	# CODIFICA SENHA
	function codificaSenha($senha) {
		return md5(sha1(hash('sha512', trim($senha))));
	}

	# VALIDA USUÁRIO 
	function validaUsuario($usuario, $senha, $id_cliente=0) {
		$senha = $this->codificaSenha($senha);

		# Os dados são case-sensitive?
		$binary = ($this->caseSensitive) ? 'BINARY' : '';

		# Abre conexão com o banco de dados
		$pdo = new DB();
		$pdo = $pdo->getConnection();

		$stmte = $pdo->prepare("SELECT COUNT(*) AS total 
					FROM {$this->tabelaUsuarios}
					WHERE 
					{$binary} {$this->campos['usuario']}=:usuario 									AND 
{$binary} {$this->campos['senha']}=:senha 
AND 
{$this->campos['id_cliente']}=:id_cliente 
AND 
stats=1");

		$stmte->bindParam(':usuario', $usuario, PDO::PARAM_STR);
		$stmte->bindParam(':senha', $senha, PDO::PARAM_STR);
		$stmte->bindParam(':id_cliente', $id_cliente, PDO::PARAM_INT);
		$executa = $stmte->execute();

		if($executa){
			$reg = $stmte->fetch(PDO::FETCH_OBJ);
			$total 	= $reg->total;
		}else {
			# A consulta foi mal sucedida, retorna false
			return false;
		}

		# Se houver apenas um usuário, retorna true
		return ($total == 1) ? true : false;
	}

}

?>

 

 

Obrigado!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ezequiel, certifique-se de entender como funciona o conceito de Orientação a Objetos.

 

Herança, normalmente nos remete ao que se passa de pai para filho, criaturas que fazem parte de uma mesma "família".

 

Veja:

class Usuario extends DB

 

Usuário não é um DB. Usuário usa um DB. Não é porque você precisa de alguma coisa que você deva estendê-la. Inclusive, na maioria das vezes, essa não é a solução mais adequada.

 

Reforço que se você quiser simplificar a criação de objetos PDO, - que, na minha opinião, já é simplíssima - releia o link postado pelo Gabriel e tente extrair algo de útil de lá. Se não tiver entendido nada, você terá que recomeçar sua leitura sobre orientação a objetos.

 

Não se preocupe. Querer criar Uma classe pra acessar o banco de dados/fazer crud é o primeiro erro de uma enorme parcela de programadores PHP que começam a aprender OOP. Eu inclusive.

 

Para que você possa atacar o seu problema de forma precisa, a primeira coisa que você precisa fazer é isolá-lo.

 

Eu tenho um problema, gostaria de colocar tudo que é pertinente às operações de usuário - como validação, criptografia de senha - de uma forma que faça sentido e as linhas de código me digam o que elas fazem.

 

Perfeito. Princípio de Única Responsabilidade: Sua classe Usuário tem a responsabilidade de manter as informações (do usuário) consistentes no banco.

 

Voltamos ao terceiro parágrafo:

suário não é um DB. Usuário usa um DB.

 

Veja, quando você estende o DB para um usuário, passa a ser possível fazer isso aqui:

$usuario = new Usuario('localhost','root','root','adm');

 

E então:

$usuario->getConnection();

 

?!?!

 

Entendeu a confusão? Teste, é seu próprio código, foi você quem criou esse monstro!!

 

Violamos o princípio de responsabilidade única e não resolvemos nosso problema. O código não é previsível. Não é possível ler o que foi programado e entender o que aquilo faz.

 

Porque, para criar um novo usuário, eu devo passar parâmetros de conexão ao banco??

 

Porque a instância de um usuário me permite 'pegar a conexão'? Conexão do que a quem?? Se eu for usar o seu código para fazer um mapeamento de vias aéreas, eu poderia entender que esse método me retorna as conexões que o usuário (do vôo) vai fazer, por exemplo.

 

Usuário, poderia ter um método chamado saveTo, que recebe um objeto de camada de persistência, pode ser um PDO - conexão ao banco de dados - mas, também, (porque não?) poderia ser um ponteiro de um arquivo!

 

Minhas dicas:

 

- Releia tudo que você já leu sobre OOP. Às vezes você teve uma dúvida em algum lugar e, hoje, pode entender melhor esse algum lugar.

- Dê uma visitada no Curso básico de OOP do Neto. Leia os comentários também! Há muita coisa lá que agrega, complementa e exemplifica a "aula".

- Pense em reusabilidade e flexibilidade. Hoje você só precisa se conectar ao MySQL. Se amanhã precisar trabalhar com SQLite, esse trabalho que você teve não vai te ajudar de nada.

- Abstraia o máximo possível. Pense de modo genérico. Eu tenho um problema, posso resolvê-lo dessa forma.

- Comece a programar. Essa deverá ser, sem dúvida, a última etapa.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Complementando o assunto pertinente, diga-se de passagem, que o Evandro iniciou. Tem algo que, poucas pessoas conhecem sobre a PDO, que eu descobri "errando" para o bem da verdade.

 

É a interpretação das queries. Logo quando eu estava aprendendo PDO. Fazia muito tempo que não realizava uma query pura. O sistema já estava pronto, utilizava uma camada de abstração. Então, eu na minha "normalidade" escrevi a seguinte query:

"INSERT pessoa SET nome = 'Gabriel Heming';"

 

E para o meu espanto.... isso funcionou. A pdo reconhece que está tentando realizar um insert e que está escrito da mesma forma que um UPDATE, e trabalha isso para o desenvolvedor que errou.

 

Isso não é PDO, o MySQL aceita esta sintaxe desde a versão 3.22.10.

Estamos falando de MySQL?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Foi testado em MsSQL e MySQL. Bom, agora que você mencionou, não posso dizer com certeza se o MsSQL oferece esse suporte.

 

Não encontrei nada sobre o suporte dessa sintaxe pelo MsSQL, isso que é extremamente rígido.

http://msdn.microsoft.com/en-us/library/ms174335.aspx

Compartilhar este post


Link para o post
Compartilhar em outros sites

Foi testado em MsSQL e MySQL. Bom, agora que você mencionou, não posso dizer com certeza se o MsSQL oferece esse suporte.

 

Não encontrei nada sobre o suporte dessa sintaxe pelo MsSQL, isso que é extremamente rígido.

http://msdn.microsoft.com/en-us/library/ms174335.aspx

 

Não é uma standard. Há relatos pela Interwebs que funcione.

 

Testei aqui em MySQL, Postgres, Firebird e Sqlite.

 

Só funciona no primeiro, tanto nos respectivos shell-interativos quanto com PDO.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Testei agora no MsSQL e só funciona através da PDO, direto do Management Studio não rola.

 

Para maiores detalhes:

- SQLServer 2008 R2;

- PDO drive ODBC e SQL_SRV (em ambos funcionam, o terceiro drive DBLIB foi removido do PHP >= 5.3);

- PHP 5.3.8.

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.