Wywołanie niezdefiniowanej metody mysqli_stmt :: get_result

113

Oto mój kod:

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

Otrzymuję błąd w ostatnim wierszu jako: Wywołanie niezdefiniowanej metody mysqli_stmt :: get_result ()

Oto kod dla 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();
        }
    }
}

Jeśli napiszę ten wiersz:

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

Wyświetla komunikat „Oświadczenie NIE zostało przygotowane” . Jeśli uruchomię zapytanie bezpośrednio w IDE zastępując? oznacza wartościami, działa dobrze. Należy pamiętać, że obiekt $ conn działa dobrze w innych zapytaniach w projekcie.

Proszę o pomoc .......

Kumar Kush
źródło
Chyba zapomniałeś $stmt = $conn->mysqli->stmt_init();?
favoretti
Sprawdź, czy te zmienne zostały $_POST['EmailID'], $_POST['SLA'], $_POST['Password']przesłane poprawnie za pomocą formularza HTML z metodą POST
ajreal
@ajreal: Zmienne są wysyłane poprawnie. Przetestowałem je używając print_r ($ _ POST).
Kumar Kush
@favoretti: Próbowałem użyć $ stmt = $ conn-> mysqli-> stmt_init (); . Wciąż nie ma szczęścia.
Kumar Kush
Jedną rzeczą, o której chciałbym wspomnieć, jest to, że użyłem podobnego kodu w innych miejscach i działają dobrze.
Kumar Kush

Odpowiedzi:

146

Przeczytaj uwagi użytkownika dotyczące tej metody:

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

Wymaga sterownika mysqlnd ... jeśli nie jest zainstalowany na Twojej przestrzeni internetowej, będziesz musiał pracować z 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
źródło
4
Wielkie dzięki. To się udało. I Odkomentowano się extension = php_mysqli_mysqlnd.dll w php.ini ; i zrestartowałem usługi Apache2.2 i MySQL. Czy powinienem odkomentować rozszerzenie linii = php_mysqli_libmysql.dll ? Jak na innej stronie, mysqlnd jest szybszy niż libmysql. Czy mogę się spodziewać zainstalowania mysqlnd u najpopularniejszych dostawców usług hostingowych?
Kumar Kush
1
Funkcja stmt_init () jest potrzebna tylko w przypadku instrukcji przygotowanej zgodnie z procedurą. więc nie potrzebujesz tego! Zobacz: link Co do libmysql : nie wiem. I nie liczyłbym na dostawców usług hostingowych do instalacji mysqlnd.dll ... lepiej spróbuj obejścia!
bekay
2
Uwaga: mysqli_stmt::get_result()jest dostępne tylko w wersji PHP 5.3.0 lub nowszej.
Raptor
4
@bekay Właśnie zapisałeś mi nowego laptopa i nowe okno. Gdyby był dostępny +10, dałbym ci go
James Cushing
1
@ kush.impetus, skąd pobierasz php_mysqli_mysqlnd.dll? Miałbym tylko php_mysqli.dllw swoim extfolderze.
Pacerier
51

Więc jeśli sterownik MySQL Native Driver (mysqlnd) nie jest dostępny, a zatem używając bind_result i fetch zamiast get_result , kod wygląda następująco:

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
źródło
$ stmt-> bind_result oszczędza mój czas. Jest to świetne rozwiązanie, gdy get_result nie jest dostępne.
Zafer
2
pytanie: skąd pochodzi zmienna $ EmailVerfied?
Rotimi
@ Akintunde007: $EmailVerfiedjest tworzony przez wywołanie bind_result().
AbraCadaver
Pojawia się błąd „Uncaught Error: Call to undefined method mysqli_stmt :: bind_results ()” przez użycie kodu
Devil's Dream
Jeśli mam zapytanie sql, takie jak „Wybierz * z nazwa_tabeli”, to jak zadeklarować wewnątrz bind_result (). * operator
Inderjeet,
46

W Twoim systemie brakuje sterownika mysqlnd!

Jeśli możesz zainstalować nowe pakiety na swoim serwerze (opartym na Debianie / Ubuntu), zainstaluj sterownik:

sudo apt-get install php5-mysqlnd

a następnie zrestartuj serwer WWW:

sudo /etc/init.d/apache2 restart
M_R_K
źródło
39

dla tych, którzy szukają alternatywy dla $result = $stmt->get_result()stworzyłem tę funkcję, która pozwala naśladować, $result->fetch_assoc()ale używając bezpośrednio obiektu 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;
}

jak widać, tworzy tablicę i pobiera ją z danymi wiersza, ponieważ używa $stmt->fetch()wewnętrznie, możesz ją wywołać tak, jak byś wywołała mysqli_result::fetch_assoc(tylko upewnij się, że $stmtobiekt jest otwarty, a wynik jest zapisany):

//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
źródło
To jest najłatwiejsza odpowiedź zastępcza typu drop-in. Działało świetnie - dzięki!
Alex Coleman,
Zaoszczędziłeś mi dużo czasu!
Jahaziel
3
Jeśli $statement->store_result();jest to konieczne przed wywołaniem funkcji, dlaczego po prostu nie uwzględnić jej w funkcji?
InsanityOnABun
Dziękuję Ci. Właśnie uratowałem mój tyłek w terminie
Kolob Canyon
20

W wersji PHP 7.2 użyłem tylko nd_mysqli zamiast mysqli i wszystko działało zgodnie z oczekiwaniami.

Kroki, aby włączyć go do serwera hostingowego GoDaddy-

  1. Zaloguj się do cpanel.
  2. Kliknij „Wybierz wersję PHP” .
  3. Zgodnie z zapisem stanu najnowszych konfiguracji odznacz „mysqli” i włącz „nd_mysqli” .

wprowadź opis obrazu tutaj

IRSHAD
źródło
2
Dziękuję, oszalałem!
Ussaid Iqbal
1
Haaa, to oszczędza mi czas! Dziękuję brachu!
Nurul Huda
1
świetny! doskonała odpowiedź dla cPanel
Rashid
1
Dziękuję bardzo!! Ocal mnie stary, nie mogę ci wystarczająco podziękować
Enes Çalışkan
Ta odpowiedź powinna być na topie
Rishabh Gusain
10

Wiem, że już udzielono odpowiedzi na temat tego, jaki jest rzeczywisty problem, jednak chcę zaproponować proste obejście.

Chciałem użyć metody get_results (), ale nie miałem sterownika i nie jestem gdzieś, gdzie mogę to dodać. Więc zanim zadzwoniłem

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

Utworzyłem pustą tablicę, a następnie powiązałem wyniki jako klucze w tej tablicy:

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

aby te wyniki można było łatwo przekazać do metod lub rzutować na obiekt w celu dalszego wykorzystania.

Mam nadzieję, że pomoże to każdemu, kto chce zrobić coś podobnego.

Kirkland
źródło
7

Otrzymałem ten sam błąd na moim serwerze - PHP 7.0 z już włączonym rozszerzeniem mysqlnd .

Rozwiązaniem było dla mnie (dzięki tej stronie ) odznaczenie rozszerzenia mysqli i zamiast tego wybranie nd_mysqli .

NB - Możesz mieć dostęp do selektora rozszerzeń w swoim cPanel. (Mam dostęp do mojego poprzez opcję Wybierz wersję PHP ).

zakaz geoinżynierii
źródło
To powinna być akceptowana odpowiedź. O wiele lepiej jest włączyć rozszerzenie niż edytować cały skrypt w celu użycia innej metody! Aha i to u mnie zadziałało :)
ArabianMaiden
Miałem ten sam problem. W rzeczywistości użycie session_start()funkcji PHP sprawiło, że poczułem się jak nieistniejąca wartość. Następnie zaktualizowałem do wersji 7.2PHP i zmieniłem rozszerzenie mysqlina nd_mysqli (naprawione). Ale mam dwa pytania, jaka jest różnica między nimi? i czy byłaby jakaś luka w bezpieczeństwie korzystania z tego rozszerzenia?
jecorrales
6

Zdaję sobie sprawę, że minęło trochę czasu, odkąd pojawiły się nowe działania w tej kwestii. Ale, jak komentowali inni plakaty - get_result()jest teraz dostępny tylko w PHP po zainstalowaniu natywnego sterownika MySQL (mysqlnd), aw niektórych przypadkach może nie być możliwe lub pożądane zainstalowanie mysqlnd. Pomyślałem więc, że pomocne byłoby opublikowanie tej odpowiedzi z informacjami o tym, jak uzyskać oferowaną funkcjonalność get_result()- bez użycia get_result().

get_result()jest / był często łączony z, fetch_array()aby zapętlić zestaw wyników i przechowywać wartości z każdego wiersza zestawu wyników w tablicy indeksowanej numerycznie lub asocjacyjnej. Na przykład poniższy kod wykorzystuje metodę get_result () z funkcją fetch_array () do przechodzenia przez zestaw wyników, przechowując wartości z każdego wiersza w tablicy $ data [] indeksowanej numerycznie:

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

Jeśli jednak get_result()nie jest dostępny (ponieważ mysqlnd nie jest zainstalowany), prowadzi to do problemu z przechowywaniem wartości z każdego wiersza zestawu wyników w tablicy bez użycia get_result(). Albo jak przeprowadzić migrację starszego kodu, get_result()który działa bez niego (np. Używając bind_result()zamiast tego) - przy jak najmniejszym wpływie na resztę kodu.

Okazuje się, że przechowywanie wartości z każdego wiersza w tablicy indeksowanej numerycznie nie jest tak proste w użyciu bind_result(). bind_result()oczekuje listy zmiennych skalarnych (nie tablicy). Tak więc wymaga trochę pracy, aby przechowywać wartości z każdego wiersza zestawu wyników w tablicy.

Oczywiście kod można łatwo zmodyfikować w następujący sposób:

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

Ale to wymaga od nas, abyśmy w wywołaniu funkcji wyraźnie wymieniali $ data [0], $ data [1] itd. bind_result(), Co nie jest idealne. Chcemy rozwiązania, które nie wymaga od nas jawnej listy $ data [0], $ data [1], ... $ data [N-1] (gdzie N to liczba pól w instrukcji select) w wezwaniu do bind_results(). Jeśli przeprowadzamy migrację starszej aplikacji, która ma dużą liczbę zapytań, a każde zapytanie może zawierać inną liczbę pól w selectklauzuli, migracja będzie bardzo pracochłonna i podatna na błędy, jeśli użyjemy rozwiązania takiego jak powyższe .

Idealnie byłoby, gdybyśmy potrzebowali fragmentu kodu „zastępującego wstawianie” - aby zastąpić tylko wiersz zawierający get_result()funkcję i pętlę while () w następnym wierszu. Kod zastępczy powinien mieć taką samą funkcję jak kod, który zastępuje, bez wpływu na żadną z wierszy przed ani na wiersze po - w tym wiersze wewnątrz pętli while (). W idealnym przypadku chcemy, aby kod zastępczy był możliwie jak najbardziej zwarty i nie chcemy modyfikować kodu zastępczego na podstawie liczby pól w selectklauzuli zapytania.

Szukając w Internecie, znalazłem szereg rozwiązań, które używają bind_param()z call_user_func_array() (na przykład Dynamiczne wiązanie parametrów mysqli_stmt, a następnie wiązanie wyniku (PHP) ), ale większość rozwiązań, które znalazłem, ostatecznie prowadzi do przechowywania wyników w tablicy asocjacyjnej, a nie tablica indeksowana numerycznie, a wiele z tych rozwiązań nie było tak zwartych, jak bym chciał i / lub nie nadawało się jako „zamienniki typu drop-in”. Jednak z przykładów, które znalazłem, udało mi się zebrać razem to rozwiązanie, które pasuje do rachunku:

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

Oczywiście pętlę for () można zwinąć w jedną linię, aby była bardziej zwarta.

Mam nadzieję, że pomoże to każdemu, kto szuka rozwiązania używającego bind_result()do przechowywania wartości z każdego wiersza w tablicy indeksowanej numerycznie i / lub szukającego sposobu na migrację starszego kodu przy użyciu get_result(). Komentarze mile widziane.

mti2935
źródło
Tak. Przeniesione do ChNP 3 lata temu. W każdym razie dzięki.
Kumar Kush,
5

Oto moja alternatywa. Jest zorientowany obiektowo i bardziej przypomina rzeczy 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();
    }
}

Stosowanie:

$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
źródło
2

Napisałem dwie proste funkcje, które dają taką samą funkcjonalność jak $stmt->get_result();, ale nie wymagają sterownika mysqlnd.

Po prostu wymieniasz

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

i

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

(Aby uzyskać liczbę zwróconych wierszy, których możesz użyć $stmt->num_rows).

Musisz tylko umieścić te dwie funkcje , które napisałem gdzieś w swoim skrypcie PHP . (na przykład na dole)

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

Jak to działa :

Mój kod używa tej $stmt->result_metadata();funkcji, aby dowiedzieć się, ile i które pola są zwracane, a następnie automatycznie wiąże pobrane wyniki z wstępnie utworzonymi odwołaniami. Działa jak marzenie!

Stefan S.
źródło
Nie mam pojęcia, dlaczego został odrzucony. Działa bardzo dobrze - używałem go w wielu projektach.
Stefan S.