Chamada para método indefinido mysqli_stmt :: get_result

113

Este é meu código:

include 'conn.php';
$conn = new Connection();
$query = 'SELECT EmailVerified, Blocked FROM users WHERE Email = ? AND SLA = ? AND `Password` = ?';
$stmt = $conn->mysqli->prepare($query);
$stmt->bind_param('sss', $_POST['EmailID'], $_POST['SLA'], $_POST['Password']);
$stmt->execute();
$result = $stmt->get_result();

Recebo o erro na última linha como: Chamada para o método undefined mysqli_stmt :: get_result ()

Aqui está o código para conn.php:

define('SERVER', 'localhost');
define('USER', 'root');
define('PASS', 'xxxx');
define('DB', 'xxxx');
class Connection{
    /**
     * @var Resource 
     */
    var $mysqli = null;

    function __construct(){
        try{
            if(!$this->mysqli){
                $this->mysqli = new MySQLi(SERVER, USER, PASS, DB);
                if(!$this->mysqli)
                    throw new Exception('Could not create connection using MySQLi', 'NO_CONNECTION');
            }
        }
        catch(Exception $ex){
            echo "ERROR: ".$e->getMessage();
        }
    }
}

Se eu escrever esta linha:

if(!stmt) echo 'Statement prepared'; else echo 'Statement NOT prepared';

Ele imprime 'Declaração NÃO preparada' . Se eu executar a consulta diretamente no IDE substituindo? marcas com valores, funciona bem. Observe que o objeto $ conn funciona bem em outras consultas no projeto.

Qualquer ajuda por favor .......

Kumar Kush
fonte
Eu acho que você esqueceu $stmt = $conn->mysqli->stmt_init();?
favoretti
Verifique se essas variáveis ​​foram $_POST['EmailID'], $_POST['SLA'], $_POST['Password']enviadas corretamente usando um formulário HTML com o método POST
ajreal
@ajreal: As variáveis ​​estão sendo postadas corretamente. Testei-os usando print_r ($ _ POST).
Kumar Kush
@favoretti: Tentei usar $ stmt = $ conn-> mysqli-> stmt_init (); . Ainda sem sorte.
Kumar Kush
Uma coisa que gostaria de mencionar é que usei código semelhante em outros lugares e eles funcionam bem.
Kumar Kush

Respostas:

146

Leia as notas do usuário para este método:

http://php.net/manual/en/mysqli-stmt.get-result.php

Requer o driver mysqlnd ... se não estiver instalado em seu espaço web, você terá que trabalhar com BIND_RESULT & FETCH!

https://secure.php.net/manual/en/mysqli-stmt.bind-result.php

https://secure.php.net/manual/en/mysqli-stmt.fetch.php

bekay
fonte
4
Muito obrigado. Isso funcionou. Descomentei a extensão = php_mysqli_mysqlnd.dll em php.ini ; e reiniciou os serviços Apache2.2 e MySQL. Devo descomentar a extensão de linha = php_mysqli_libmysql.dll ? De acordo com outra página, mysqlnd é mais rápido que libmysql. Além disso, posso esperar que o mysqlnd esteja instalado na maioria dos provedores de serviços de hospedagem populares?
Kumar Kush
1
stmt_init () é necessário apenas para uma instrução preparada por procedimento. então você não precisa disso! Veja: link Quanto ao libmysql : não sei. E eu não contaria com provedores de hospedagem para a instalação de mysqlnd.dll ... melhor tentar alguma solução alternativa!
bekay 01 de
2
Nota: mysqli_stmt::get_result()só está disponível no PHP v5.3.0 ou superior.
Raptor
4
@bekay Você acabou de salvar um novo laptop e uma nova janela para mim. Se +10 estivesse disponível, eu daria a você
James Cushing
1
@ kush.impetus, onde você baixa php_mysqli_mysqlnd.dll? Eu só teria php_mysqli.dllna minha extpasta.
Pacerier
51

Portanto, se o driver nativo do MySQL (mysqlnd) não estiver disponível e, portanto, usando bind_result e fetch em vez de get_result , o código se torna:

include 'conn.php';
$conn = new Connection();
$query = 'SELECT EmailVerified, Blocked FROM users WHERE Email = ? AND SLA = ? AND `Password` = ?';
$stmt = $conn->mysqli->prepare($query);
$stmt->bind_param('sss', $_POST['EmailID'], $_POST['SLA'], $_POST['Password']);
$stmt->execute();
$stmt->bind_result($EmailVerified, $Blocked);
while ($stmt->fetch())
{
   /* Use $EmailVerified and $Blocked */
}
$stmt->close();
$conn->mysqli->close();
Bert Regelink
fonte
$ stmt-> bind_result salvou meu tempo. É uma ótima solução quando get_result não está disponível.
Zafer
2
pergunta: de onde vem a variável $ EmailVerfied?
Rotimi
@ Akintunde007: $EmailVerfiedé criado pela chamada para bind_result().
AbraCadaver
Obtendo um erro "Erro não detectado: chamada ao método indefinido mysqli_stmt :: bind_results ()" usando o código
Devil's Dream
Se eu tiver uma consulta sql como "Select * from table_name", como declarar dentro de bind_result (). * operador
Inderjeet
46

Seu sistema está sem o driver mysqlnd!

Se você conseguir instalar novos pacotes em seu servidor (baseado em Debian / Ubuntu), instale o driver:

sudo apt-get install php5-mysqlnd

e reinicie o seu servidor web:

sudo /etc/init.d/apache2 restart
M_R_K
fonte
39

para aqueles que procuram uma alternativa para $result = $stmt->get_result()eu fiz esta função que permite que você imite o $result->fetch_assoc()mas usando diretamente o objeto stmt:

function fetchAssocStatement($stmt)
{
    if($stmt->num_rows>0)
    {
        $result = array();
        $md = $stmt->result_metadata();
        $params = array();
        while($field = $md->fetch_field()) {
            $params[] = &$result[$field->name];
        }
        call_user_func_array(array($stmt, 'bind_result'), $params);
        if($stmt->fetch())
            return $result;
    }

    return null;
}

como você pode ver, ele cria uma matriz e a busca com os dados da linha, uma vez que usa $stmt->fetch()internamente, você pode chamá-la da mesma forma que chamaria mysqli_result::fetch_assoc(apenas certifique-se de que o $stmtobjeto esteja aberto e o resultado armazenado):

//mysqliConnection is your mysqli connection object
if($stmt = $mysqli_connection->prepare($query))
{
    $stmt->execute();
    $stmt->store_result();

    while($assoc_array = fetchAssocStatement($stmt))
    {
        //do your magic
    }

    $stmt->close();
}
MasterKitano
fonte
Esta é a resposta de substituição mais fácil aqui. Funcionou muito bem - obrigado!
Alex Coleman
Me economizou muito tempo!
Jahaziel
3
Se $statement->store_result();for necessário antes de chamar a função, por que não incluí-lo na função?
InsanityOnABun
Obrigado. Acabei de salvar minha bunda em um prazo
Kolob Canyon
20

Com o PHP versão 7.2, usei apenas nd_mysqli em vez de mysqli e funcionou como esperado.

Passos para habilitá-lo no servidor de hospedagem godaddy-

  1. Faça login no cpanel.
  2. Clique em "Selecionar versão PHP" .
  3. Conforme fornecido o instantâneo das configurações mais recentes, desmarque "mysqli" e habilite "nd_mysqli" .

insira a descrição da imagem aqui

IRSHAD
fonte
2
Obrigado, eu estava ficando louco!
Disse Iqbal de
1
Haaa, isso salva meu tempo! Obrigada mano!
Nurul Huda
1
ótimo! resposta perfeita para cPanel
Rashid
1
Muito obrigado!! Você me salva, cara, não posso agradecer o suficiente
Enes Çalışkan
Esta resposta deve estar no topo
Rishabh Gusain
10

Sei que já foi respondido qual é o problema real, no entanto, quero oferecer uma solução alternativa simples.

Eu queria usar o método get_results (), mas não tinha o driver e não estou em nenhum lugar onde possa adicioná-lo. Então, antes de ligar

$stmt->bind_results($var1,$var2,$var3,$var4...etc);

Eu criei uma matriz vazia e, em seguida, apenas vinculei os resultados como chaves nessa matriz:

$result = array();
$stmt->bind_results($result['var1'],$result['var2'],$result['var3'],$result['var4']...etc);

para que esses resultados possam ser facilmente passados ​​para métodos ou convertidos para um objeto para uso posterior.

Espero que isso ajude quem está procurando fazer algo semelhante.

Kirkland
fonte
7

Eu estava recebendo este mesmo erro no meu servidor - PHP 7.0 com a extensão mysqlnd já habilitada.

A solução para mim (graças a esta página ) foi desmarcar a extensão mysqli e selecionar nd_mysqli .

NB - Você pode acessar o seletor de extensões no seu cPanel. (Eu acesso o meu através da opção Selecionar versão do PHP .)

ban-geoengenharia
fonte
Esta deve ser a resposta aceita. É muito melhor habilitar a extensão do que editar seu script inteiro para usar outro método! Ah, e funcionou para mim :)
ArabianMaiden
Eu tive o mesmo problema. Na verdade, usar a session_start()função do PHP me tornou um valor inexistente. Então eu atualizei para a versão 7.2do PHP e mudei a extensão de mysqlipara nd_mysqli (fixo). Mas, eu tenho duas perguntas, qual é a diferença entre os dois? e se haveria alguma lacuna na segurança para usar essa extensão?
jecorrales
6

Percebo que já faz um tempo que não houve qualquer nova atividade sobre essa questão. Mas, como outros participantes comentaram - get_result()agora está disponível apenas em PHP com a instalação do driver nativo MySQL (mysqlnd) e, em alguns casos, pode não ser possível ou desejável instalar mysqlnd. Então, achei que seria útil postar esta resposta com informações sobre como obter a funcionalidade que get_result()oferece - sem usar get_result().

get_result()é / era frequentemente combinado com fetch_array()para percorrer um conjunto de resultados e armazenar os valores de cada linha do conjunto de resultados em uma matriz indexada numericamente ou associativa. Por exemplo, o código a seguir usa get_result () com fetch_array () para percorrer um conjunto de resultados, armazenando os valores de cada linha no array $ data [] indexado numericamente:

$c=1000;
$sql="select account_id, username from accounts where account_id<?";
$stmt = $mysqli->prepare($sql);                 
$stmt->bind_param('i', $c);                                             
$stmt->execute();
$result = $stmt->get_result();       
while($data = $result->fetch_array(MYSQLI_NUM)) {
   print $data[0] . ', ' . $data[1] . "<BR>\n"; 
}

No entanto, se get_result()não estiver disponível (porque mysqlnd não está instalado), isso levará ao problema de como armazenar os valores de cada linha de um conjunto de resultados em um array, sem usar get_result(). Ou como migrar o código legado que usa get_result()para ser executado sem ele (por exemplo, usando ao bind_result()invés) - enquanto afeta o resto do código o mínimo possível.

Acontece que armazenar os valores de cada linha em uma matriz indexada numericamente não é tão simples de usar bind_result(). bind_result()espera uma lista de variáveis ​​escalares (não uma matriz). Portanto, é necessário algum esforço para armazená-los em um array os valores de cada linha do conjunto de resultados.

Claro, o código pode ser facilmente modificado da seguinte maneira:

$c=1000;
$sql="select account_id, username from accounts where account_id<?";
$stmt = $mysqli->prepare($sql);                 
$stmt->bind_param('i', $c);                                             
$stmt->execute();
$stmt->bind_result($data[0], $data[1]);
while ($stmt->fetch()) {
   print $data[0] . ', ' . $data[1] . "<BR>\n"; 
}

Mas, isso exige que listemos explicitamente $ data [0], $ data [1], etc. individualmente na chamada para bind_result(), o que não é o ideal. Queremos uma solução que não exija que listemos explicitamente $ data [0], $ data [1], ... $ data [N-1] (onde N é o número de campos na instrução select) na chamada para bind_results(). Se estivermos migrando um aplicativo legado que tem um grande número de consultas e cada consulta pode conter um número diferente de campos na selectcláusula, a migração será muito trabalhosa e sujeita a erros se usarmos uma solução como a acima .

Idealmente, queremos um snippet de código de 'substituição drop-in' - para substituir apenas a linha que contém a get_result()função e o loop while () na próxima linha. O código de substituição deve ter a mesma função do código que está substituindo, sem afetar nenhuma das linhas anteriores ou posteriores - incluindo as linhas dentro do loop while (). Idealmente, queremos que o código de substituição seja o mais compacto possível e não queremos ter que ajustar o código de substituição com base no número de campos na selectcláusula da consulta.

Pesquisando na internet, encontrei uma série de soluções que usam bind_param()com call_user_func_array() (por exemplo, vincular dinamicamente os parâmetros mysqli_stmt e depois vincular o resultado (PHP) ), mas a maioria das soluções que encontrei eventualmente levam ao armazenamento dos resultados em uma matriz associativa, não uma matriz indexada numericamente, e muitas dessas soluções não eram tão compactas quanto eu gostaria e / ou não eram adequadas como 'substituições imediatas'. No entanto, a partir dos exemplos que encontrei, fui capaz de remendar esta solução, que se encaixa no projeto:

$c=1000;
$sql="select account_id, username from accounts where account_id<?";
$stmt = $mysqli->prepare($sql);                 
$stmt->bind_param('i', $c);                                             
$stmt->execute();
$data=array();
for ($i=0;$i<$mysqli->field_count;$i++) { 
    $var = $i;
    $$var = null; 
    $data[$var] = &$$var; 
}
call_user_func_array(array($stmt,'bind_result'), $data);
while ($stmt->fetch()) {
   print $data[0] . ', ' . $data[1] . "<BR>\n"; 
}

Claro, o loop for () pode ser reduzido em uma linha para torná-lo mais compacto.

Espero que isso ajude quem está procurando uma solução usando bind_result()para armazenar os valores de cada linha em uma matriz indexada numericamente e / ou procurando uma maneira de migrar o código legado usando get_result(). Comentários são bem-vindos.

mti2935
fonte
Sim. Mudou para o PDO há 3 anos. Obrigado de qualquer forma.
Kumar Kush
5

Aqui está minha alternativa. É orientado a objetos e é mais parecido com coisas mysql / mysqli.

class MMySqliStmt{
    private $stmt;
    private $row;

    public function __construct($stmt){
        $this->stmt = $stmt;
        $md = $stmt->result_metadata();
        $params = array();
        while($field = $md->fetch_field()) {
            $params[] = &$this->row[$field->name];
        }
        call_user_func_array(array($stmt, 'bind_result'), $params) or die('Sql Error');
    }

    public function fetch_array(){
        if($this->stmt->fetch()){
            $result = array();
            foreach($this->row as $k => $v){
                $result[$k] = $v;
            }
            return $result;
        }else{
            return false;
        }
    }

    public function free(){
        $this->stmt->close();
    }
}

Uso:

$stmt = $conn->prepare($str);
//...bind_param... and so on
if(!$stmt->execute())die('Mysql Query(Execute) Error : '.$str);
$result = new MMySqliStmt($stmt);
while($row = $result->fetch_array()){
    array_push($arr, $row);
    //for example, use $row['id']
}
$result->free();
//for example, use the $arr
ch271828n
fonte
2

Eu escrevi duas funções simples que fornecem a mesma funcionalidade $stmt->get_result();, mas não requerem o driver mysqlnd.

Você simplesmente substitui

$result = $stmt->get_result(); com $fields = bindAll($stmt);

e

$row= $stmt->get_result(); com $row = fetchRowAssoc($stmt, $fields); .

(Para obter o número de linhas retornadas que você pode usar $stmt->num_rows.)

Você apenas precisa colocar essas duas funções que escrevi em algum lugar do seu script PHP . (por exemplo, bem na parte inferior)

function bindAll($stmt) {
    $meta = $stmt->result_metadata();
    $fields = array();
    $fieldRefs = array();
    while ($field = $meta->fetch_field())
    {
        $fields[$field->name] = "";
        $fieldRefs[] = &$fields[$field->name];
    }

    call_user_func_array(array($stmt, 'bind_result'), $fieldRefs);
    $stmt->store_result();
    //var_dump($fields);
    return $fields;
}

function fetchRowAssoc($stmt, &$fields) {
    if ($stmt->fetch()) {
        return $fields;
    }
    return false;
}

Como funciona :

Meu código usa a $stmt->result_metadata();função para descobrir quantos e quais campos são retornados e, a seguir, vincula automaticamente os resultados buscados a referências pré-criadas. Funciona como um encanto!

Stefan S.
fonte
Não faço ideia por que foi rejeitado. Funciona muito bem - usei-o em muitos projetos.
Stefan S.