Appel à la méthode non définie mysqli_stmt :: get_result

113

Voici mon code:

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();

J'obtiens l'erreur sur la dernière ligne comme: Appel à la méthode non définie mysqli_stmt :: get_result ()

Voici le code pour 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();
        }
    }
}

Si j'écris cette ligne:

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

Il imprime «Déclaration NON préparée» . Si j'exécute la requête directement dans l'EDI en remplaçant? marques avec des valeurs, cela fonctionne très bien. Veuillez noter que l'objet $ conn fonctionne correctement dans les autres requêtes du projet.

Toute aide s'il vous plaît .......

Kumar Kush
la source
Je pense que tu as oublié $stmt = $conn->mysqli->stmt_init();?
favoretti
Veuillez vérifier si ces variables sont $_POST['EmailID'], $_POST['SLA'], $_POST['Password']correctement soumises en utilisant un formulaire HTML avec la méthode POST
ajreal
@ajreal: Les variables sont affichées correctement. Je les ai testés en utilisant print_r ($ _ POST).
Kumar Kush
@favoretti: j'ai essayé d'utiliser $ stmt = $ conn-> mysqli-> stmt_init (); . Toujours pas de chance.
Kumar Kush
Une chose que je voudrais mentionner est que j'ai utilisé un code similaire dans d'autres endroits et qu'ils fonctionnent bien.
Kumar Kush

Réponses:

146

Veuillez lire les notes utilisateur pour cette méthode:

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

Il nécessite le pilote mysqlnd ... s'il n'est pas installé sur votre espace web, vous devrez travailler avec 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
la source
4
Merci beaucoup. Ça a marché. J'ai décommenté l' extension = php_mysqli_mysqlnd.dll dans php.ini ; et redémarré les services Apache2.2 et MySQL. Dois-je décommenter l' extension de ligne = php_mysqli_libmysql.dll ? Comme sur une autre page, mysqlnd est plus rapide que libmysql. En outre, puis-je m'attendre à ce que mysqlnd soit installé sur les fournisseurs de services d'hébergement les plus populaires?
Kumar Kush
1
stmt_init () n'est nécessaire que pour une instruction préparée procédurale. donc vous n'en avez pas besoin! Regardez: lien Quant à la libmysql : ne sais pas. Et je ne compterais pas sur les fournisseurs d'hébergement pour l'installation de mysqlnd.dll ... mieux vaut essayer une solution de contournement!
bekay
2
Remarque: mysqli_stmt::get_result()n'est disponible que sur PHP v5.3.0 ou supérieur.
Raptor
4
@bekay Vous venez de me sauver un nouvel ordinateur portable et une nouvelle fenêtre. Si +10 étaient disponibles, je vous le donnerais
James Cushing
1
@ kush.impetus, où téléchargez-vous php_mysqli_mysqlnd.dll? J'aurais seulement php_mysqli.dlldans mon extdossier.
Pacerier
51

Donc, si le pilote MySQL Native Driver (mysqlnd) n'est pas disponible, et donc en utilisant bind_result et fetch au lieu de get_result , le code devient:

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
la source
$ stmt-> bind_result me ​​fait gagner du temps. C'est une excellente solution lorsque get_result n'est pas disponible.
Zafer
2
question: d'où vient la variable $ EmailVerfied?
Rotimi
@ Akintunde007: $EmailVerfiedest créé par l'appel à bind_result().
AbraCadaver
Obtenir une erreur "Uncaught Error: Call to undefined method mysqli_stmt :: bind_results ()" en utilisant le code
Devil's Dream
Si j'ai une requête SQL comme "Select * from table_name" alors comment déclarer à l'intérieur de bind_result (). * opérateur
Inderjeet
46

Votre système n'a pas le pilote mysqlnd!

Si vous pouvez installer de nouveaux paquets sur votre serveur (basé sur Debian / Ubuntu), installez le pilote:

sudo apt-get install php5-mysqlnd

puis redémarrez votre serveur Web:

sudo /etc/init.d/apache2 restart
M_R_K
la source
39

pour ceux qui recherchent une alternative à $result = $stmt->get_result()j'ai créé cette fonction qui vous permet d'imiter le $result->fetch_assoc()mais en utilisant directement l'objet 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;
}

comme vous pouvez le voir, il crée un tableau et le récupère avec les données de ligne, car il utilise en $stmt->fetch()interne, vous pouvez l'appeler comme vous l'appeleriez mysqli_result::fetch_assoc(assurez-vous simplement que l' $stmtobjet est ouvert et que le résultat est stocké):

//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
la source
C'est la réponse de remplacement la plus simple ici. A très bien fonctionné - merci!
Alex Coleman
M'a fait gagner beaucoup de temps!
Jahaziel
3
Si $statement->store_result();c'est nécessaire avant d'appeler la fonction, pourquoi ne pas simplement l'inclure dans la fonction?
InsanityOnABun
Je vous remercie. Je viens de sauver mon cul à une date limite
Kolob Canyon
20

Avec la version 7.2 de PHP, je viens d'utiliser nd_mysqli au lieu de mysqli et cela a fonctionné comme prévu.

Étapes pour l'activer dans le serveur d'hébergement de godaddy-

  1. Connectez-vous à cpanel.
  2. Cliquez sur "Sélectionner la version PHP" .
  3. Comme fourni, l'instantané des dernières configurations décochez "mysqli" et activez "nd_mysqli" .

entrez la description de l'image ici

IRSHAD
la source
2
Merci, je devenais fou!
Ussaid Iqbal
1
Haaa, cela me sauve du temps! Merci broh!
Nurul Huda
1
génial! réponse parfaite pour cPanel
Rashid
1
Merci beaucoup!! Vous me sauvez mec, je ne peux pas assez vous remercier
Enes Çalışkan
Cette réponse devrait être au top
Rishabh Gusain
10

Je sais que cela a déjà été répondu quant à quel est le problème réel, mais je veux offrir une solution de contournement simple.

Je voulais utiliser la méthode get_results () mais je n'avais pas le pilote, et je ne suis pas quelque part où je peux l'ajouter. Alors, avant d'appeler

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

J'ai créé un tableau vide, puis j'ai simplement lié les résultats sous forme de clés dans ce tableau:

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

afin que ces résultats puissent facilement être passés en méthodes ou transtypés en un objet pour une utilisation ultérieure.

J'espère que cela aidera tous ceux qui cherchent à faire quelque chose de similaire.

Kirkland
la source
7

J'obtenais cette même erreur sur mon serveur - PHP 7.0 avec l' extension mysqlnd déjà activée.

La solution était pour moi (grâce à cette page ) de désélectionner l' extension mysqli et de sélectionner nd_mysqli à la place.

NB - Vous pourrez peut-être accéder au sélecteur d'extensions dans votre cPanel. (J'accède au mien via l' option Select PHP Version .)

interdiction de la géo-ingénierie
la source
Cela devrait être la réponse acceptée. Il vaut mieux activer l'extension que de modifier l'intégralité de votre script pour utiliser une autre méthode! Oh et ça a marché pour moi :)
ArabianMaiden
J'ai eu le même problème. En fait, l'utilisation de la session_start()fonction PHP m'a fait comme une valeur inexistante. Ensuite, je suis passé à la version 7.2de PHP et j'ai changé l'extension de mysqlien nd_mysqli (corrigé). Mais, j'ai deux questions, quelle est la différence entre les deux? et s'il y aurait une lacune dans la sécurité pour l'utilisation de cette extension?
jecorrales le
6

Je me rends compte que cela fait un moment qu'il n'y a pas eu de nouvelle activité sur cette question. Mais, comme d'autres auteurs l'ont commenté - get_result()n'est désormais disponible en PHP qu'en installant le pilote natif MySQL (mysqlnd), et dans certains cas, il peut ne pas être possible ou souhaitable d'installer mysqlnd. Donc, j'ai pensé qu'il serait utile de publier cette réponse avec des informations sur la façon d'obtenir la fonctionnalité get_result()offerte - sans utiliser get_result().

get_result()est / était souvent combiné avec fetch_array()pour parcourir un jeu de résultats et stocker les valeurs de chaque ligne du jeu de résultats dans un tableau indexé numériquement ou associatif. Par exemple, le code ci-dessous utilise get_result () avec fetch_array () pour parcourir un jeu de résultats, en stockant les valeurs de chaque ligne dans le tableau $ data [] à indexation numérique:

$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"; 
}

Cependant, si get_result()n'est pas disponible (car mysqlnd n'est pas installé), cela conduit au problème de savoir comment stocker les valeurs de chaque ligne d'un jeu de résultats dans un tableau, sans utiliser get_result(). Ou comment migrer le code hérité qui get_result()fonctionne sans lui (par exemple en utilisant à la bind_result()place) - tout en impactant le moins possible le reste du code.

Il s'avère que stocker les valeurs de chaque ligne dans un tableau à indexation numérique n'est pas si simple à utiliser bind_result(). bind_result()attend une liste de variables scalaires (pas un tableau). Il faut donc du temps pour stocker les valeurs de chaque ligne du jeu de résultats dans un tableau.

Bien sûr, le code pourrait facilement être modifié comme suit:

$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"; 
}

Mais cela nous oblige à lister explicitement $ data [0], $ data [1], etc. individuellement dans l'appel à bind_result(), ce qui n'est pas idéal. Nous voulons une solution qui ne nous oblige pas à lister explicitement $ data [0], $ data [1], ... $ data [N-1] (où N est le nombre de champs dans l'instruction select) dans l'appel à bind_results(). Si nous migrons une application héritée qui a un grand nombre de requêtes, et que chaque requête peut contenir un nombre différent de champs dans la selectclause, la migration sera très laborieuse et sujette à des erreurs si nous utilisons une solution comme celle ci-dessus .

Idéalement, nous voulons un extrait de code de «remplacement» - pour remplacer uniquement la ligne contenant la get_result()fonction et la boucle while () sur la ligne suivante. Le code de remplacement doit avoir la même fonction que le code qu'il remplace, sans affecter aucune des lignes avant, ni aucune des lignes après - y compris les lignes à l'intérieur de la boucle while (). Idéalement, nous voulons que le code de remplacement soit aussi compact que possible, et nous ne voulons pas avoir à adapter le code de remplacement en fonction du nombre de champs dans la selectclause de la requête.

En recherchant sur Internet, j'ai trouvé un certain nombre de solutions qui utilisent bind_param()avec call_user_func_array() (par exemple, lier dynamiquement les paramètres mysqli_stmt puis lier le résultat (PHP) ), mais la plupart des solutions que j'ai trouvées mènent finalement au stockage des résultats dans un tableau associatif, pas un tableau indexé numériquement, et beaucoup de ces solutions n'étaient pas aussi compactes que je le souhaiterais et / ou n'étaient pas adaptées en tant que «remplacements instantanés». Cependant, à partir des exemples que j'ai trouvés, j'ai pu bricoler cette solution, qui correspond à la facture:

$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"; 
}

Bien sûr, la boucle for () peut être réduite en une seule ligne pour la rendre plus compacte.

J'espère que cela aidera tous ceux qui recherchent une solution en utilisant bind_result()pour stocker les valeurs de chaque ligne dans un tableau indexé numériquement et / ou qui recherchent un moyen de migrer le code hérité en utilisant get_result(). Commentaires bienvenus.

mti2935
la source
Yupp. Passé à l'AOP il y a 3 ans. Merci quand même.
Kumar Kush le
5

Voici mon alternative. Il est orienté objet et ressemble plus à des choses 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();
    }
}

Usage:

$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
la source
2

J'ai écrit deux fonctions simples qui donnent les mêmes fonctionnalités que $stmt->get_result();, mais elles ne nécessitent pas le pilote mysqlnd.

Vous remplacez simplement

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

et

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

(Pour obtenir le nombre de lignes renvoyées, vous pouvez utiliser $stmt->num_rows.)

Il vous suffit de placer ces deux fonctions que j'ai écrites quelque part dans votre script PHP . (par exemple tout en bas)

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;
}

Comment ça marche :

Mon code utilise la $stmt->result_metadata();fonction pour déterminer combien et quels champs sont retournés, puis lie automatiquement les résultats récupérés à des références pré-créées. Fonctionne comme un charme!

Stefan S.
la source
Je ne sais pas pourquoi il a été déclassé. Cela fonctionne très bien - je l'ai utilisé dans de nombreux projets.
Stefan S.