PHP/MYSQL: Nachrichten-System

Hm, das klappt auch nicht.

Also ich benutze bei fast allen Sachen MySQLI und dann halt objektorientiert. Ich habe bisher nur bei einem Projekt PDO benutzt.

Könnte aber hierfür gut PDO benutzen, die Connect-Datei dazu habe ich ja.

Ich habe nur bisher fast nie was mit PDO gemacht, deshalb wüsste ich nicht, wie man so eine "dynamische" Query machen könnte.
Die Anzahl der Übergebenen Variablen variiert ja, je nachdem wie viele Benutzer/Gruppen als Empfänger ausgegeben wurden.
 
Habe jetzt folgende Zeile:
PHP:
call_user_func_array((array($sql_link, 'bind_param')), array_merge(array($sql_link, $type3), $value_references3));

und bekomme folgende Fehlermeldung:
Warning: call_user_func_array() expects parameter 1 to be a valid callback, first array member is not a valid class name or object
Fatal error: Call to a member function execute() on a non-object
 
Hm, ne. Bin das nochmal durchgegangen und hab das mal mit nem alten Projekt von mir verglichen. Zumindest den Fehler kann ich mir nicht erklären... (Das mit der Klammer war mal wieder nen BrainFart von mir... Nochmal nachgezählt, stimmte doch...) Die Version sollte eigentlich funktionieren:

call_user_func_array
(array($sql_link, 'bind_param'), array_merge(array($sql_link, $type3), $value_references3));

Welcher fehler kam da? Auch der valid callback error?
 
Warning: call_user_func_array() expects parameter 1 to be a valid callback, first array member is not a valid class name or object
Fatal error: Call to a member function execute() on a non-object
 
Ne, wie kann man das denn überprüfen? Aber wie gesagt, die vorherigen Queries (die genau diese Passage auch nutzen) funktionieren.
 
Einfach nach dem prepare ausgeben lassen...
var_dump($sql_link)

Ansonsten sollte man generell überprüfen ob da was falsch läuft nachdem man das prepare ausgeführt hat bspw. mit
if(!$sql_link) {
//error handling.
}
 
Ausgegebener Text mit vardump:
bool(false)
Warning: call_user_func_array() expects parameter 1 to be a valid callback, first array member is not a valid class name or object
Fatal error: Call to a member function execute() on a non-object

Mein Code:
PHP:
$sql_data = $db->prepare("INSERT INTO msg_data (betreff, nachricht, to_string, user_id) VALUES (?, ?, ?, ?)");
	$sql_data->bind_param('sssi', $input_betreff, $input_nachricht3, $input_names2, $user_id);
	if ($sql_data->execute()) {
		$sql_data_lastinsertid = $sql_data->insert_id;
		
		$placeholders_empfaenger_ids = implode(', ', array_fill(0, count($empfaenger_ids2), "(?, ?, ?)"));
		
		$sql_link_query = "INSERT INTO msg_link (to_id, msg_id, gelesen) VALUES ($placeholders_empfaenger_ids)";
		$sql_link = $db->prepare($sql_link_query);
		var_dump($sql_link);
		$type3 = str_repeat('iis', count($empfaenger_ids2));
		foreach ($empfaenger_ids2 as $to_id) {
			$values3[] = $to_id;
			$values3[] = $sql_data_lastinsertid;
			$values3[] = $null;
		}
		foreach ($values3 as $key3 => $value3) {
			$value_references3[$key3] = &$values3[$key3];
		}
		call_user_func_array(array($sql_link, 'bind_param'), array_merge(array($sql_link, $type3), $value_references3));
		if ($sql_link->execute()) {
			echo '<div id="ajax_response_css"><span class="green">Nachricht wurde erfolgreich an '.htmlentities($input_names2, ENT_QUOTES, 'UTF-8').' verschickt.</span></div>';
			exit;
		} else {
			echo '<div id="ajax_response_css"><span class="red">Fehler: Nachricht konnte nicht verschickt werden. [Fehlercode: SQL-01a]</span></div>';
			exit;
		}
	} else {
		echo '<div id="ajax_response_css"><span class="red">Fehler: Nachricht konnte nicht gespeichert und nicht verschickt werden. [Fehlercode: SQL-01a]</span></div>';
		exit;
	}
 
Aha. Also wirft das prepared nen Fehler...

Lass dir mal $sql_link_query ausgeben und guck dir an wo da der Fehler liegen könnte...
 
Da bekomm ich folgende Ausgabe (die Fehler sind natürlich weiterhin die gleichen):
string(75) "INSERT INTO msg_link (to_id, msg_id, gelesen) VALUES ((?, ?, ?), (?, ?, ?))"

Sieht eigentlich richtig aus, denn ich habe eine Gruppe ausgewählt (mit einem Mitglied) und dann noch einen Benutzer. Ergibt zwei Benutzer insgesamt und für jeden Benutzer wird in msg_link ja eine Row angelegt mit jeweils 3 Spalten.
Das einzige, was mich verwirrt, ist das strin(75) davor. Kommt das von var_dump?
 
Die einzelnen Datensätze werden durch Kommata getrennt. Die komplett umschließende Klammer ist nicht korrekt.
 
Oh, vielen Dank! :D

Jetzt bekomme ich folgenden Fehler:
Warning: Parameter 2 to mysqli_stmt::bind_param() expected to be a reference, value given

Edit:

Wenn ich mir mal das Array "value_references3" ausgeben lasse, bekomme ich folgendes.
Code:
Array
(
    [0] => 3
    [1] => 40
    [2] => 0
    [3] => 29
    [4] => 40
    [5] => 0
)

Das macht beim zweiten Hingucken schon Sinn, denn in jedem 3er-Abschnitt ist die erste Zahl die Benutzer-ID (Empfänger), dann die Msg-ID und dann der Wert, ob die Nachricht gelesen wurde (beim Senden 0).

Aber wird das auch richtig interpretiert, wahrscheinlich nicht, sonst würde es ja funktionieren :D.

Edit 2:
Es funktioniert nun wieder. Folgenen Code musste ich verwenden:
PHP:
call_user_func_array('mysqli_stmt_bind_param', array_merge(array($sql_link, $type3), $value_references3));
 
Zuletzt bearbeitet:
Klar funktioniert es jetzt. Du nutzt jetzt auch wieder den prozeduralen Stil. Beim objektorientierten Stil hättest du bei array_merge einfach nur das $sql_link wegnehmen müssen. Dann wäre das auch gegangen.

So zum Beispiel:
PHP:
call_user_func_array(array($sql_link, 'bind_param'), array_merge(array($type3), $value_references3));

bzw. in sauber:
PHP:
array_unshift($value_references3,$type3);
call_user_func_array(array($sql_link, 'bind_param'), $value_references3);
 
Zuletzt bearbeitet:
Stimmt, so wärs auch gegangen.

Ich habe nochmal eine Frage :D.

Ich habe am Anfang der PHP-Datei, bei der der Inhalt einer Nachricht ausgegeben wird, eine Blockade eingebaut, sodass man da nichts angezeigt bekommt, falls die Nachricht nicht für einen bestimmt war (= nicht Empfänger war). Nun baue ich gerade den Gesendet-Bereich und daher muss ich diese Blockade nun umbauen.

Vorher wurde das so geprüft:
PHP:
$sql_sec = $db->prepare("SELECT msg_id FROM msg_link WHERE msg_id = ? AND to_id = ?");
$sql_sec->bind_param('ii', $input_id, $user_id);

Jetzt muss ich ja noch die Autor-ID berücksichtigen und habe dann folgendes getestet:
PHP:
$sql_sec = $db->prepare("SELECT ml.msg_id FROM msg_link ml LEFT JOIN msg_data md ON md.id = ml.msg_id WHERE (ml.msg_id = ? AND ml.to_id = ?) OR (md.user_id = ?)");
$sql_sec->bind_param('iii', $input_id, $user_id, $user_id);

Zweiteres gibt mir nur leider keine Rows zurück. Woran kann das liegen?
 
Lass mich raten. Die Nachricht, die du abprüfst ist zwar vom Autor, aber nicht an den abzurufenden Benutzer adressiert? Das ist vollkommen normal. Denn du hast dort eine Join-Anweisung, bei der die msg_data Tabelle eingefügt wird, sobald es für md.id und ml.msg_id eine Übereinstimmung gibt. Blöd nur, wenn der Nutzer Author und kein Empfänger ist. Denn dann fehlt diese Übereinstimmung und es wird keine Zeile zurückgeliefert. Versuche es mal mit Dual-Select:
Code:
SELECT ml.msg_id, md.id FROM msg_link ml, msg_data md WHERE (ml.msg_id = ? AND ml.to_id = ?) OR (md.user_id = ?)
Das kann ich jetzt nicht testen und kann dir auch nicht sagen, ob das funktioniert. Aber mit einer JOIN-Anweisung wird es definitiv nichts. Denn wenn die Bedingung für das Join nicht erfüllt wird, dann kann md.user_id auch nicht geprüft werden. Zur Not nutzt du 2 Querries dafür oder eben UNION.
 
Lass mich raten. Die Nachricht, die du abprüfst ist zwar vom Autor, aber nicht an den abzurufenden Benutzer adressiert? Das ist vollkommen normal. Denn du hast dort eine Join-Anweisung, bei der die msg_data Tabelle eingefügt wird, sobald es für md.id und ml.msg_id eine Übereinstimmung gibt. Blöd nur, wenn der Nutzer Author und kein Empfänger ist. Denn dann fehlt diese Übereinstimmung und es wird keine Zeile zurückgeliefert. Versuche es mal mit Dual-Select:
Code:
SELECT ml.msg_id, md.id FROM msg_link ml, msg_data md WHERE (ml.msg_id = ? AND ml.to_id = ?) OR (md.user_id = ?)
Das kann ich jetzt nicht testen und kann dir auch nicht sagen, ob das funktioniert. Aber mit einer JOIN-Anweisung wird es definitiv nichts. Denn wenn die Bedingung für das Join nicht erfüllt wird, dann kann md.user_id auch nicht geprüft werden. Zur Not nutzt du 2 Querries dafür oder eben UNION.

Dual Select ist eigentlich nichts anderes als ein impliziter Join und nichts anderes macht die Datenbank intern... Also wird es wohl 2 Queries brauchen.
 
Hm ich hatte immer im Hinterkopf, das ein Join-Query erst dann liefert, wenn die Abhängigkeitsbedingung erfüllt wird. Aber wenn dem so ist, dann 2 Querries.
 
Wie stark beeinflussen Queries eigentlich so die Performance? Ich scheue mich immer davor mehrere zu benutzen, weil mir ich mir das schlecht für die Geschwindigkeit einer Website vorstelle.

Edit: Bisher funktioniert die Variante mit Union übrigens.
 
Zuletzt bearbeitet:
Das kommt ganz auf du Datenbank und dessen Füllstand an. Wenn ich mir ansehe, wie viele Querries Wordpress oder Joomla da manchmal raushauen (oder auch PHPBB), dan biste noch bestens dabei. Am wichtigsten für die Performance sind die Querries auf stark frequentierten Seiten. Die Nachrichtenfunktion zum Beispiel wird weniger stark frequentiert als eine Startseite wie hier bei PCGH, wo unzählige News, Artikel oder Videos aus der Datenbank geholt werden. Man darf es nicht zu streng sehen. Versuche mit so wenig Querries wie nötig zu arbeiten. Aber mach dir auch kein Kopf, wenn du für ein Skript ein oder 2 Querries mehr brauchst.
 
Zurück