Isto é o que li até agora sobre PDO::ATTR_EMULATE_PREPARES
:
- A emulação de preparação do PDO é melhor para desempenho, pois a preparação nativa do MySQL ignora o cache de consulta .
- A preparação nativa do MySQL é melhor para segurança (evitando injeção de SQL) .
- A preparação nativa do MySQL é melhor para relatórios de erros .
Não sei mais o quão verdadeira qualquer uma dessas afirmações é. Minha maior preocupação ao escolher uma interface MySQL é prevenir a injeção de SQL. A segunda preocupação é o desempenho.
Meu aplicativo atualmente usa MySQLi procedural (sem instruções preparadas) e utiliza bastante o cache de consulta. Raramente reutilizará instruções preparadas em uma única solicitação. Comecei a mudança para PDO para os parâmetros nomeados e segurança das instruções preparadas.
Estou usando MySQL 5.1.61
ePHP 5.3.2
Devo deixar PDO::ATTR_EMULATE_PREPARES
ativado ou não? Existe uma maneira de ter o desempenho do cache de consulta e a segurança das instruções preparadas?
Respostas:
Para responder às suas preocupações:
MySQL> = 5.1.17 (ou> = 5.1.21 para as instruções
PREPARE
eEXECUTE
) pode usar instruções preparadas no cache de consulta . Portanto, sua versão do MySQL + PHP pode usar instruções preparadas com o cache de consulta. No entanto, observe cuidadosamente as advertências para os resultados das consultas em cache na documentação do MySQL. Existem muitos tipos de consultas que não podem ser armazenadas em cache ou que são inúteis, embora estejam armazenadas em cache. Na minha experiência, o cache de consulta geralmente não é uma grande vitória. Consultas e esquemas precisam de construção especial para aproveitar ao máximo o cache. Freqüentemente, o armazenamento em cache no nível do aplicativo acaba sendo necessário de qualquer maneira a longo prazo.A preparação nativa não faz diferença para a segurança. As instruções pseudo-preparadas ainda escaparão dos valores dos parâmetros de consulta, isso apenas será feito na biblioteca PDO com strings em vez de no servidor MySQL usando o protocolo binário. Em outras palavras, o mesmo código PDO será igualmente vulnerável (ou não vulnerável) a ataques de injeção, independentemente de sua
EMULATE_PREPARES
configuração. A única diferença é onde ocorre a substituição do parâmetro - comEMULATE_PREPARES
, ela ocorre na biblioteca PDO; semEMULATE_PREPARES
, ele ocorre no servidor MySQL.Sem
EMULATE_PREPARES
você pode obter erros de sintaxe no tempo de preparação em vez de no tempo de execução; comEMULATE_PREPARES
você só obterá erros de sintaxe em tempo de execução porque PDO não tem uma consulta para dar ao MySQL até o tempo de execução. Observe que isso afeta o código que você escreverá ! Especialmente se você estiver usandoPDO::ERRMODE_EXCEPTION
!Uma consideração adicional:
prepare()
(usando instruções preparadas nativas), portanto, aprepare();execute()
com instruções preparadas nativas pode ser um pouco mais lento do que emitir uma consulta de texto simples usando instruções preparadas emuladas. Em muitos sistemas de banco de dados, o plano de consulta para a tambémprepare()
é armazenado em cache e pode ser compartilhado com várias conexões, mas não acho que o MySQL faça isso. Portanto, se você não reutilizar seu objeto de instrução preparado para várias consultas, sua execução geral pode ser mais lenta.Como recomendação final , acho que com versões anteriores do MySQL + PHP, você deve emular instruções preparadas, mas com suas versões mais recentes você deve desligar a emulação.
Depois de escrever alguns aplicativos que usam PDO, fiz uma função de conexão PDO que tem o que considero ser as melhores configurações. Você provavelmente deve usar algo assim ou ajustar suas configurações preferidas:
fonte
mysql_real_escape_string
com caracteres multibyte) ainda deixaria alguém aberto a ataques de injeção?mysql_real_escape_string
under the capô e as vulnerabilidades consequentes que podem surgir (em casos muito específicos).Cuidado ao desabilitar
PDO::ATTR_EMULATE_PREPARES
(ativar preparações nativas) quando seu PHPpdo_mysql
não for compiladomysqlnd
.Como o antigo
libmysql
não é totalmente compatível com algumas funções, pode levar a bugs estranhos, por exemplo:PDO::PARAM_INT
(0x12345678AB será cortado para 0x345678AB na máquina de 64 bits)LOCK TABLES
(lançaSQLSTATE[HY000]: General error: 2030 This command is not supported in the prepared statement protocol yet
exceção)mysqlnd
ou emulado prepara isso automaticamente faz este trabalho para você e não sai de sincronia com o servidor mysql)Esses bugs descobri em meu projeto simples quando migrei para outro servidor que usava
libmysql
para opdo_mysql
módulo. Talvez haja muito mais bugs, não sei. Também testei no debian jessie de 64 bits fresco, todos os bugs listados ocorrem quando euapt-get install php5-mysql
, e desaparecem quando euapt-get install php5-mysqlnd
.Quando
PDO::ATTR_EMULATE_PREPARES
é definido como verdadeiro (como padrão) - esses bugs não acontecem de qualquer maneira, porque o PDO não usa instruções preparadas neste modo. Portanto, se você usar opdo_mysql
baseado emlibmysql
(substring "mysqlnd" não aparece no campo "Versão da API do cliente" dapdo_mysql
seção no phpinfo) - você não devePDO::ATTR_EMULATE_PREPARES
desligar.fonte
Eu desligaria as preparações de emulação enquanto você está executando o 5.1, o que significa que o PDO aproveitará a funcionalidade de instrução preparada nativa.
http://php.net/manual/en/ref.pdo-mysql.php
Eu troquei o MySQLi pelo PDO para as declarações nomeadas preparadas e a melhor API.
No entanto, para ser equilibrado, o PDO tem um desempenho insignificante mais lento do que o MySQLi, mas é algo para se ter em mente. Eu sabia disso quando fiz a escolha e decidi que uma API melhor e usar o padrão da indústria era mais importante do que usar uma biblioteca desprezivelmente mais rápida que conecta você a um mecanismo específico. FWIW Acho que a equipe do PHP também está olhando favoravelmente para o PDO em vez do MySQLi para o futuro.
fonte
Eu recomendo habilitar
PREPARE
chamadas de banco de dados reais , pois a emulação não pega tudo .., por exemplo, ela irá prepararINSERT;
!A saída
Terei prazer em obter um impacto sobre o desempenho do código que realmente funciona.
FWIW
Versão do PHP: PHP 5.4.9-4ubuntu2.4 (cli)
Versão do MySQL: 5.5.34-0ubuntu0
fonte
prepare
fazer o trabalho que deveria. (Além disso, sempre assumi que o analisador de parâmetros do lado do cliente necessariamente terá seus próprios bugs.)https://tech.michaelseiler.net/2016/07/04/dont-emulate-prepared-statements-pdo-mysql/
fonte
Estou surpreso que ninguém tenha mencionado um dos maiores motivos para desativar a emulação. Com a emulação ativada, o PDO retorna todos os inteiros e flutuantes como strings . Quando você desativa a emulação, inteiros e flutuantes no MySQL tornam-se inteiros e flutuantes no PHP.
Para obter mais informações, consulte a resposta aceita para esta pergunta: PHP + PDO + MySQL: como faço para retornar colunas inteiras e numéricas do MySQL como inteiros e numéricos em PHP? .
fonte
Para o registro
PDO :: ATTR_EMULATE_PREPARES = true
Isso pode gerar um efeito colateral desagradável. Ele pode retornar valores inteiros como string.
PHP 7.4, pdo com mysqlnd.
Executando uma consulta com PDO :: ATTR_EMULATE_PREPARES = true
Coluna: id
Tipo: inteiro
Valor: 1
Executando uma consulta com PDO :: ATTR_EMULATE_PREPARES = false
Coluna: id
Tipo: string
Valor: "1"
Em qualquer caso, os valores decimais são sempre retornados como uma string, independentemente da configuração :-(
fonte