j4nk3y: Update einer Chatfunktion

0 151

Update einer Chatfunktion

j4nk3y
  • html
  • javascript
  • php
  1. 2
    Felix Riesterer
    • datenbank
    • php
    • sicherheit
    1. 0
      j4nk3y
      1. 0
        Gunnar Bittersmann
    2. 0
      Gunnar Bittersmann
      1. 0
        Matthias Apsel
        1. 0
          Gunnar Bittersmann
      2. 0
        j4nk3y
        1. 0
          Gunnar Bittersmann
          1. 0
            j4nk3y
      3. 0
        Felix Riesterer
        1. 0
          j4nk3y
          • zur info
          1. 1
            Felix Riesterer
            • php
            • programmiertechnik
            • zur info
            1. 0
              j4nk3y
        2. 0
          Gunnar Bittersmann
    3. 0
      j4nk3y
      1. 0
        Felix Riesterer
        • php
        • programmiertechnik
        • sicherheit
        1. 0
          j4nk3y
          1. 0
            Der Martin
            1. 0
              j4nk3y
              1. 0
                Der Martin
                1. 0
                  j4nk3y
          2. 0
            Felix Riesterer
            1. 0
              j4nk3y
              1. 0
                Der Martin
                1. 0
                  j4nk3y
              2. 1
                dedlfix
                1. 0
                  Gunnar Bittersmann
                  • typografie
                2. 0
                  j4nk3y
                  1. 0
                    dedlfix
                    1. 0
                      j4nk3y
                      1. 0
                        dedlfix
                        1. 0
                          j4nk3y
                          1. 0
                            dedlfix
                            1. 0
                              j4nk3y
                              1. 0
                                Der Martin
                                1. 0
                                  j4nk3y
                                  1. 0
                                    Der Martin
                              2. 1
                                dedlfix
                                1. 0
                                  Der Martin
                              3. 0
                                Gunnar Bittersmann
                                • datenbank
                                • programmiertechnik
                                1. 0
                                  j4nk3y
        2. 0
          Der Martin
        3. 0
          Gunnar Bittersmann
          • internationalisierung
          • php
          1. 0
            Felix Riesterer
            1. 0
              Tabellenkalk
              • zitat
              • zu diesem forum
              1. 1
                Matthias Apsel
    4. 0
      1unitedpower
      1. 1
        dedlfix
        1. 1
          1unitedpower
          1. 0
            Christian Kruse
          2. 0
            dedlfix
            1. 0
              1unitedpower
              1. 0
                dedlfix
                1. 0
                  Christian Kruse
                  1. 0
                    dedlfix
                  2. 0
                    1unitedpower
                    1. 0
                      Christian Kruse
                      1. 0
                        1unitedpower
                    2. 0
                      dedlfix
                      1. 0
                        1unitedpower
                        1. 0
                          dedlfix
  2. 0
    j4nk3y
    1. 0
      Gunnar Bittersmann
      • html
      1. 0
        j4nk3y
        1. 0
          Gunnar Bittersmann
          1. 0
            j4nk3y
            1. 0
              Matthias Apsel
              1. 0
                j4nk3y
  3. 0
    j4nk3y
  4. 0
    pl
    1. 0
      j4nk3y
      1. 0
        dedlfix
        1. 0
          j4nk3y
          1. 0
            dedlfix
            1. 0
              j4nk3y
              1. 0
                pl
                1. 0
                  j4nk3y
                  1. 0
                    pl
                    1. 0
                      dedlfix
                      1. -2
                        pl
                        1. 0
                          Matthias Apsel
                  2. 0
                    pl
              2. 0
                dedlfix
                1. 0
                  j4nk3y
                  1. 0
                    dedlfix
            2. 0
              j4nk3y
              1. 0
                dedlfix
      2. 0
        pl
  5. 0
    j4nk3y
    1. 0
      dedlfix
    2. 0
      j4nk3y
      1. 0
        j4nk3y
        1. 0
          pl
        2. 0
          dedlfix
          1. 0
            j4nk3y
            1. 0
              dedlfix
              1. 0
                j4nk3y
          2. 0
            j4nk3y
            1. 0
              j4nk3y
  6. 0
    j4nk3y
    1. 0
      Der Martin
      1. 0
        j4nk3y
        1. 0
          dedlfix
          1. 0
            j4nk3y
            1. 0
              Der Martin
              1. 0
                j4nk3y
        2. 0
          Der Martin
          1. 0
            j4nk3y
            1. 1
              Felix Riesterer
              1. 0
                j4nk3y
                1. 0
                  Matthias Apsel
                  1. 0
                    j4nk3y
                    • menschelei
                2. 0
                  Felix Riesterer
                  • php
                  • programmiertechnik
                  • sql
                  1. 0
                    j4nk3y
                    1. 0
                      Der Martin
                      1. 0
                        j4nk3y
                        1. 0
                          Der Martin
                          1. 0
                            j4nk3y
                            • menschelei
                    2. 0
                      Felix Riesterer
                      1. 0
                        pl
                      2. 0
                        j4nk3y
                        1. 2
                          dedlfix
                          1. 0
                            j4nk3y
                            1. 0
                              dedlfix
                              1. 0
                                Christian Kruse
                                1. 1
                                  dedlfix
                  2. 0
                    j4nk3y
                  3. 0
                    j4nk3y
                    1. 0
                      Felix Riesterer
                      1. 0
                        dedlfix
                        1. 0
                          j4nk3y
                          1. 0
                            pl
                            1. 0
                              j4nk3y
                          2. 0
                            dedlfix
                      2. 0
                        j4nk3y
                        1. 0
                          Der Martin
                        2. 0
                          Felix Riesterer
                          1. 0
                            Der Martin
                            1. 0
                              dedlfix
                          2. 0
                            j4nk3y
                            1. 1
                              Der Martin
                              1. 0
                                j4nk3y
    2. 0
      j4nk3y
      1. 0
        dedlfix
        1. 0
          j4nk3y
          1. 0
            Christian Kruse
            1. 0
              j4nk3y
              1. 0
                Christian Kruse
              2. 0
                Matthias Apsel
                • zu diesem forum
                1. 0
                  j4nk3y

Servus zusammen,

Ich bastel zurzeit an einer Chatfunktion für mein Projekt.

Diese ist für den Moment funktionsfähig aber noch sehr primitiv, daher möchte ich sie noch wesentlich verbessern.

Im Moment arbeiten 2 js funktionen und 2 php funktionen hand in hand um Nachrichten zu schreiben und wieder auszugeben.

Ich habe mir 2 Punkte vorgenommen aber komme gerade nicht wirklich weiter.

  1. kann ich zurzeit nur aus einer Tabelle die Nachrichten ausgeben bzw in diese schreiben. Ich möchte aber in mehrere Tabellen schreiben können, jenachdem wohin der User schreiben möchte.

  2. wird die chat_list funktion jede Sekunde ausgeführt, was ja sehr unschön ist und viel zuviel Serverkapazität benötigt, sprich eine Websocket verbindung soll her.

Nun scheitere ich an beidem kläglich.

Nungut hier ersteinmal ein wenig Anschauungsmaterial:

  1. Der Html Teil:
<section id="chat_wrapper">
<!--<form>

<input type="checkbox" name="world" class="checkbox_chat" id="chat_world_list" value="world" />
<label for="world">World</label>

<input type="checkbox" name="language" class="checkbox_chat" id="chat_language_list" value="<?php echo $_SESSION['language'];?>"/>
<label for="language">Language</label>

<?php if($page == "lobby"){echo '<input type="checkbox" name="alliance" class="checkbox_chat" id="chat_alliance_list" value="alliance" />
<label for="alliance">Alliance</label>';} ?>

</form>-->

<div id="chatbox"></div>

<!--<form>
<input type="radio" name="chat_destination" class="checkbox_chat" id="chat_world_post" value="world" checked />
<label for="chat_world_post">World</label>
<input type="radio" name="chat_destination" class="checkbox_chat" id="chat_language_post" value="<?php echo $_SESSION['language'];?>" />
<label for="chat_language_post">Language</label>
<?php if($page == "lobby"){echo '<input type="radio" name="chat_destination" class="checkbox_chat" id="chat_alliance_post" value="alliance" />
<label for="chat_alliance_post">Alliance</label>';} ?>-->

<input type="text" name="chat" id="chat_text" size="25" onkeydown = "if (event.keyCode == 13) {document.getElementById('chatbutton').click()}"/>

<button id="chatbutton" onclick="post_chat();" >Send</button>

</form>

<script>
list_chat();
</script>

</section>
  1. Die js Funktionen:
function list_chat()
{
var hr = new XMLHttpRequest();
	var url = "../functions/php/chat_list.php";
	
	hr.onreadystatechange = function()
	{
		if (hr.readyState == 4 && hr.status == 200)
		{
			document.getElementById("chatbox").innerHTML = hr.responseText;
			
			var div = document.getElementById("chatbox");
			div.scrollTop = div.scrollHeight;
		}
	}
	
	hr.open("GET", url, true)  // Mehr informationen zu der chat_list senden!...??
	hr.send();
	
	setTimeout(list_chat, 1000);   //Problem! zu wss ändern...??
}

function post_chat()
{
	var hr = new XMLHttpRequest();
	
	var url = "../functions/php/chat_insert.php";
	var chat = document.getElementById("chat_text").value;
	
	var text = "chat=" + chat;
	
	hr.open("POST", url, true);
	
	hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	hr.send(text);   // Mehr informationen zu der chat_insert senden!...??
	
	document.getElementById("chat_text").value = ""; 
	
}
  1. Nun zu php :

3.1 Die chat_list.php

$output = "";
require_once('db_connect_function.php');

$get_messages = "Select * FROM (Select message_writer, message, message_date FROM chat ORDER BY message_date DESC Limit 50 ) chat ORDER BY message_date ASC";

if($result = $db->query($get_messages))
{
	while($row = $result -> fetch_assoc())
	{
		$date = date("H:i:s", $row['message_date']);
		$output = '<p><span id="message_time">'.$date.' </span><span id="message_writer">'.$row['message_writer'].' : </span><span id="message">'.$row['message'].'</span></p>';
		echo $output;
	}
	$db -> close();
}
else
{
	//error_log
}

3.2 Die chat_insert.php

session_start();
require_once('db_connect_function.php');

if(isset($_POST['chat']) && !empty($_POST['chat']))
{
	$writer = $_SESSION['user_name'];
	$chat = $_POST['chat'];
	$world = $_POST['world'];
	$language = $_POST['language'];
	$alliance = $_POST['alliance'];
	$now = time();
	
	/*
	$world = $_POST['chat_world_post'];
	$language = $_POST['chat_language_post'];
	$alliance = $_POST['chat_alliance_post'];
	if(!empty($world))
	{
		$insert_message = "INSERT INTO chat (message_writer, message, message_date) VALUES ('$writer', '$chat', '$now')";
		if($db -> query($insert_message) === TRUE)
		{
			$db -> commit();
		}
		else
		{
			//error_log! $create_db_connect->error.
		}
	}
	elseif(!empty($language))
	{
		$table_name = "chat_".$language;
		
		$insert_message = "INSERT INTO $table_name (message_writer, message, message_date) VALUES ('$writer', '$chat', '$now')";
		if($db -> query($insert_message) === TRUE)
		{
			$db -> commit();
		}
		else
		{
			//error_log! $create_db_connect->error.
		}
	}
	elseif(!empty($alliance))
	{
		$table_name = "chat_".$alliance;
		
		$insert_message = "INSERT INTO $table_name (message_writer, message, message_date) VALUES ('$writer', '$chat', '$now')";
		if($db -> query($insert_message) === TRUE)
		{
			$db -> commit();
		}
		else
		{
			//error_log! $create_db_connect->error.
		}
	}*/
	
	$insert_message = "INSERT INTO chat (message_writer, message, message_date) VALUES ('$writer', '$chat', '$now')";
	if($db -> query($insert_message) === TRUE)
	{
		$db -> commit();
	}
	else
	{
		//error_log
	}
	
	
	exit();
}

Wie man erkennt, habe ich schon ein wenig damit experimentiert, informationen über checkboxen (imprinzip welche Tabellen die chat_list.php ausgeben / zusammenführen soll) weiter zu geben. Und ähnlich mit radio wohin die chat_insert.php die Daten schreiben soll. Nur bekomme ich das über die js funktionen irgendwie nicht geregelt.

Wie dem auch sei, freue ich mich ersteinmal über Anregungen und Tipps :)

Mit sommerlichem Gruß

Jo

  1. Lieber j4nk3y,

    Du machst da sehr gefährliche Sachen!

    	$chat = $_POST['chat'];
    	$world = $_POST['world'];
    	$language = $_POST['language'];
    	$alliance = $_POST['alliance'];
    

    Du kopierst hier potenziell bösartige Daten in Variablen um, denen man nicht mehr ansieht, dass ihr Inhalt potenziell böse ist.

    		$insert_message = "INSERT INTO chat (message_writer, message, message_date) VALUES ('$writer', '$chat', '$now')";
    

    Spätestens hier wird deutlich, dass Du potenziell bösartige Daten ungeprüft in SQL-Code überführst.

    Was würde wohl passieren, wenn in $_POST['chat'] folgender Wert stünde?

    ');DROP TABLE `chat_de`; -- 
    

    Die Zeichenkette "de" in "chat_de" ist bitte durch das zu ersetzen, was in $_POST['language'] steht.

    Informiere Dich umgehend über Kontextwechsel und kontextgerechtes Kodieren von Daten!!

    Wenn Du das getan hast, dann gewöhnst Du Dir an, potenziell bösartige Daten nicht mehr zu verstecken:

    $insert_message = sprintf(
        'INSERT INTO chat ('
        . 'message_writer, message, message_date'
        . ') VALUES ('
        . '\'%1$s\', \'%2$s\', \'%3$s\''
        . ')',
        $_SESSION['user_name'],
        $_POST['chat'],
        time()
    );
    

    Wenn Dir das zu doof ist, dann nutze PDO. Dort kannst Du das so notieren:

    $myPDO = new PDO(
        sprintf(
            'mysql:dbname=%1$s;host=%2$s;charset=UTF8;',
            $settings['db-name'],
            $settings['db-host']
        ),
        $settings['db-user'],
        $settings['db-pw'],
        array(
            PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
            PDO::MYSQL_ATTR_FOUND_ROWS => true,
            PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'
        )
    );
    
    $statement = $myPDO->prepare(
        'INSERT INTO chat ('
        . 'message_writer, message, message_date'
        . ') VALUES ('
        . ':message_writer, :message, :message_date'
        . ');'
    );
    
    $statement->execute(array(
        ':message_writer' => $_SESSION['user_name'],
        ':message' => $_POST['chat'],
        ':message_date' => time()
    ));
    

    Diese PDO-Kiste sorgt dafür, dass die potenziell bösartigen Daten in einer Weise kodiert werden, die Dein Programm nicht kaputt machen.

    Liebe Grüße,

    Felix Riesterer.

    1. Hey Felix Riesterer,

      Wenn ich das gerade richtig sehe sprichst du darauf an, dass irgendwas in der POST variablen stehen könnte was potenziell schädlich ist.

      Das habe ich schon oft gehört und daher prüfe ich in einer generellen abfrage alle POST variablen auf mögliche Gefahren. Die ist sicher noch nicht fertig aber ich weiss um die Schwachstelle. Das sieht bei mir im Moment noch so aus, wird aber zu gegeben Zeitpunkt erweitert.

      if($_POST)
      {
      	foreach($_POST as $key=>$value)
      	{
      		$_POST[$key]= mysql_escape_string($value);
      				
      		if (stripos($_POST[$key], "<script") !== false)	//Check more?
      		{
      			//Warn or delete/bann user!
      		}
      
      
      	}
      }
      

      Aber ich werde mich morgen nochmal genauer mit dem Kontext wechsel befassen, danke dafür!

      Und auch mit dem

      sprintf();
      

      , kurzes überfliegen hat nicht viel gebracht :/.

      PDO ist mit Sicherheit eine interessante Sache aber ich verstehe nicht einmal im Ansatz was deise Klasse macht. Also die Syntax ist mir vollkommen schleierhaft und ich bin immoment noch nicht bereit mich in dieses Kapitel einzuarbeiten, meine Abneigung dagegen möge man mir verzeihen. Ich habe "gerade" erst gelernt mit mysqli umzugehen und würde langsam gerne zu einem Ergebnis kommen ohne ständig wieder neue Baustellen anzufangen.

      Die Zeichenkette "de" in "chat_de" ist bitte durch das zu ersetzen, was in $_POST['language'] steht.

      In der POST variable steht aber z.b. de oder eng oder noch viele weiter.

      Somit wünsche ich ersteinmal ein Schönes Wochenende.

      Gruß Jo

      1. @@j4nk3y

        Das habe ich schon oft gehört und daher prüfe ich in einer generellen abfrage alle POST variablen auf mögliche Gefahren. Die ist sicher noch nicht fertig aber ich weiss um die Schwachstelle. Das sieht bei mir im Moment noch so aus, wird aber zu gegeben Zeitpunkt erweitert.

        Nein, falscher Ansatz.

        Anstatt zu versuchen, eine Blacklist mit allem zu erstellen, was gefährlich ist (die du vermutlich nie vollständig hinbekommen wirst), solltest du eine Whitelist erstellen mit dem, was unbedenklich ist.

        Falls du das überhaupt brauchst. Sollen Nutzer HTML-Tags verwenden dürfen? Vielleich keine so gute Idee.

        Wenn sie Text formatieren und Links setzen können sollen, bietet sich Markdown an. (Wie hier im Forum.)

        LLAP 🖖

        --
        “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
        Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
    2. @@Felix Riesterer

      Du machst da sehr gefährliche Sachen!

      Ja. Und das auch in der anderen Richtung:

      	        $date = date("H:i:s", $row['message_date']);
      		$output = '<p><span id="message_time">'.$date.' </span><span id="message_writer">'.$row['message_writer'].' : </span><span id="message">'.$row['message'].'</span></p>';
      		echo $output;
      

      Was, wenn der Name nun <script src="http://example.net/bad-code.js"></script> ist?

      Auch hier muss kontextgerecht escapet werden: htmlspecialchars().

      Natürlich nur die Daten. Markup sollte prinzipell nicht mit PHP echo ausgegeben werden.

      Da das Ganze in einer Schleife steht, sind die id-Attribute falsch; eineunddieselbe ID darf ja schließlich nur ein einziges Mal vergeben werden.

      Hier könnten dann Klassen vergeben werden. Wenn überhaupt – notwendig sind sie nicht, denn:

      Im Übrigen ist das Spanitis. HTML stellt passende Elemente bereit:

      <article>
        <footer>
          <time datetime="<?php echo date('c', $row['message_date']); ?>"><?php echo date('H:i:s', $row['message_date']); ?></time>
          <span class="author"><?php echo htmlspecialchars($row['message_writer']); ?></span>
        </footer>
        <p class="message"><?php echo htmlspecialchars($row['message']); ?></p>
      </article>
      

      Formatierung per CSS, bspw:

      article > footer,
      article > p
      {
        display: inline;
      }
      
      article > footer::after
      {
        content: " : ";
      }
      

      LLAP 🖖

      --
      “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
      Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
      1. Hallo Gunnar Bittersmann,

        Formatierung per CSS, bspw:

        article > footer::after
        {
          content: " : ";
        }
        

        Oh, ein Deppen Leer Zeichen. ;-p

        Bis demnächst
        Matthias

        --
        Wenn eine Idee nicht zuerst absurd erscheint, taugt sie nichts. (Albert Einstein)
        1. @@Matthias Apsel

          article > footer::after
          {
            content: " : ";
          }
          

          Oh, ein Deppen Leer Zeichen. ;-p

          Nee, ein Plenk. ;-p

          Ich hab mich hier mal an die Vorlage gehalten und : eher als irgendein Trennzeichen (wie – oder ☞) angesehen denn als Doppelpunkt.

          LLAP 🖖

          --
          “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
          Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
      2. Guten Morgen Gunnar Bittersmann,

        Was, wenn der Name nun <script src="http://example.net/bad-code.js"></script> ist?

        Dürfte ja nich drin stehen, da das <script ja durch den "$_POST check" rausfällt und der Name aus einer Datenbank kommt aber im Prinzip hast du Recht.

        Auch hier muss kontextgerecht escapet werden: htmlspecialchars().

        Richtig, wie gesagt ist die funktion noch primitiv, funktioniert aber fürs erste.

        Natürlich nur die Daten. Markup sollte prinzipell nicht mit PHP echo ausgegeben werden.

        Wie dann? Ich muss ja php irgendwie sagen können, dass er mir einen Bereich in einer Schleife ausgeben soll.

        Da das Ganze in einer Schleife steht, sind die id-Attribute falsch; eineunddieselbe ID darf ja schließlich nur ein einziges Mal vergeben werden.

        Ja richtig... wär mir auch später noch aufgefallen.

        <article>
          <footer>
            <time datetime="<?php echo date('c', $row['message_date']); ?>"><?php echo date('H:i:s', $row['message_date']); ?></time>
            <span class="author"><?php echo htmlspecialchars($row['message_writer']); ?></span>
          </footer>
          <p class="message"><?php echo htmlspecialchars($row['message']); ?></p>
        </article>
        

        Eine Schleife muss hier schon irgendwie rein...?? Du hast Recht, so könnte man das besser machen, da ich aber erst bei der Funktionalität bin hab ich auf html noch kein großen Wert gelegt.

        Gruß Jo

        1. @@j4nk3y

          Eine Schleife muss hier schon irgendwie rein...??

          Ja. In der alternativen Syntax.

          <?php if ($result = $db->query($get_messages)): ?>
            <?php while ($row = $result->fetch_assoc()): ?>
              <article>
                <footer>
                  <time datetime="<?php echo date('c', $row['message_date']); ?>"><?php echo date('H:i:s', $row['message_date']); ?></time>
                  <span class="author"><?php echo htmlspecialchars($row['message_writer']); ?></span>
                </footer>
                <p class="message"><?php echo htmlspecialchars($row['message']); ?></p>
              </article>
            <?php endwhile; ?>
          <?php endif; ?>
          

          LLAP 🖖

          PS: Kaputte Syntaxhighlighter sind kaputt.

          --
          “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
          Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
          1. Hey Gunnar Bittersmann,

            Eine Schleife muss hier schon irgendwie rein...??

            Ja. In der alternativen Syntax.

            <?php if ($result = $db->query($get_messages)): ?>
              <?php while ($row = $result->fetch_assoc()): ?>
                <article>
                  <footer>
                    <time datetime="<?php echo date('c', $row['message_date']); ?>"><?php echo date('H:i:s', $row['message_date']); ?></time>
                    <span class="author"><?php echo htmlspecialchars($row['message_writer']); ?></span>
                  </footer>
                  <p class="message"><?php echo htmlspecialchars($row['message']); ?></p>
                </article>
              <?php endwhile; ?>
            <?php endif; ?>
            

            Das hab ich so noch nie gesehn aber wenn es so richtig ist dann kann ich das einpflegen. Danke.

            Gruß Jo

      3. Lieber Gunnar,

        Markup sollte prinzipell nicht mit PHP echo ausgegeben werden.

        schon wieder ein Glaubenssatz? Wer sein Dokument mit einer passenden Klasse (wie z.B. DOMDocument) erstellt und manipuliert, der wird am Ende seines Scripts sehr wohl mit echo den HTML-Code an den Browser senden: echo $myDoc->saveHTML(); oder etwas ähnliches.

        Die von Dir bevorzugte HereDoc-Schreibweise ist in meinen Augen ebenso problematisch wie inline-JavaScript in einem HTML-Dokument, da Programm-Logik und Markup vermischt notiert werden. Da benutze ich lieber echte HTML-Dateien, in denen Elemente mit ID oder name-Attribut passend von meiner DOMDocument-Klasse "gefunden" und manipuliert werden.

        Liebe Grüße,

        Felix Riesterer.

        1. Hey,

          Markup sollte prinzipell nicht mit PHP echo ausgegeben werden.

          schon wieder ein Glaubenssatz? Wer sein Dokument mit einer passenden Klasse (wie z.B. DOMDocument) erstellt und manipuliert, der wird am Ende seines Scripts sehr wohl mit echo den HTML-Code an den Browser senden: echo $myDoc->saveHTML(); oder etwas ähnliches.

          Die von Dir bevorzugte HereDoc-Schreibweise ist in meinen Augen ebenso problematisch wie inline-JavaScript in einem HTML-Dokument, da Programm-Logik und Markup vermischt notiert werden. Da benutze ich lieber echte HTML-Dateien, in denen Elemente mit ID oder name-Attribut passend von meiner DOMDocument-Klasse "gefunden" und manipuliert werden.

          Krass... Ich hab nix verstanden.

          Gruß Jo

          P.s. Das ist nur eine Info, dass muss nicht kommentiert werden^^

          1. Lieber j4nk3y,

            Krass... Ich hab nix verstanden.

            man kann in PHP auf zwei Arten HTML-Code erzeugen und an den Browser ausgeben:

            1.) String-basiert

            $html = '<!doctype html><html><head><title>Meine Seite</title></head><body>';
            
            $html .= '<h1>Willkommen auf meiner Seite!</h1>';
            $html .= '<p>Vielleicht haben Sie ja Lust sich ein wenig umzuschauen?</p>';
            $html .= '</body></html>';
            
            echo $html;
            

            Das kann man mit verschiedenen Schreibweisen tun, unter anderem die heredoc-Schreibweise, aber im Grunde beschränkt man sich auf Stringoperationen, indem man den HTML-Code als Zeichenkette Stück für Stück zusammensetzt.

            P.s. Das ist nur eine Info, dass muss nicht kommentiert werden^^

            Warum sollte ich Dir keinen Ausblick auf das geben, wie Du vielleicht später einmal Deine Dokumente zusammen baust? Vielleicht mit einer DOM-Klasse?

            2.) Man erstellt eine Datenstruktur, die die Dokumentstruktur abbildet, das sogenannte Document Object Model (DOM). Nicht nur JavaScript im Browser, sondern auch PHP auf dem Server kann das. Der Vorteil ist, dass man sich um die syntaktische Richtigkeit des endgültigen HTML-Codes (lies: Schreibfehler oder fehlende Tags) keine Gedanken mehr machen muss, da das die Klasse übernimmt.

            $doc = new DOMDocument('1.0', 'UTF-8');
            $doc->preserveWhiteSpace = false;
            $doc->formatOutput = true;
            
            $doc->loadHTML(
                '<!doctype html><html><head><title>Meine Seite</title></head><body></body></html>'
            );
            
            $body = $doc->getElementsByTagName('body')->item(0);
            
            $h1 = $doc->createElement(
                'h1',
                'Willkommen auf meiner Seite!'
            );
            
            $p = $doc->createElement(
                'p',
                'Vielleicht haben Sie ja Lust sich ein wenig umzuschauen?'
            );
            
            $body->appendChild($h1);
            $body->appendChild($p);
            
            echo $doc->saveHTML();
            

            Es gibt eine PHP-Erweiterung namens Tidy, deren Sinn es ist den HTML-Code zu säubern und leserlich zu layouten. Wenn man nach der Methode 1 (String-basiert) seinen HTML-Code zusammenbaut, kann Tidy Fehler reparieren, bevor der Code an den Browser geht. Verwendet man aber gemäß Methode 2 eine DOM-Klasse, braucht man anschließend kein Tidy mehr, da der Ergebniscode garantiert korrekt ist (es sei denn die DOM-Klasse ist kaputt).

            Wenn ich in meinen Projekten echte (lies: formal vollständige) HTML-Dokumente als Templates (lies: Vorlagen) benutze, dann verwende ich in der DOM-Klasse die Möglichkeiten, gezielt nach ID oder Elementarten zu suchen, um Inhalte hineinzubasteln:

            <!doctype html>
            <html>
                <head>
                    <meta charset="utf-8">
                    <title>Einstellungen</title>
                </head>
                <body>
                    ...
                    <form>
                        ...
                        <label for="lang">{#language}</label>
                        <select id="lang" name="lang"></select>
                        ...
                    </form>
                    ...
                </body>
            </html>
            

            Da mehrere Sprachen unterstützt werden sollen, steht im Dokument ein Platzhalter "{#language}", der je nach Benutzerspracheinstellung mit z.B. "Language" oder "Sprache" befüllt wird. Die verfügbaren Sprachen müssen jetzt als <option>-Elemente in das <select> eingefügt werden. Da sind String-Operationen nicht mehr so leicht, wenn auch nicht unmöglich, mit der DOM-Klasse ist das Ergebnis sicherer:

            $select = $doc->getElementById('lang');
            
            if ($select) {
                foreach ($available_languages as $l) {
                    $option = $doc->createElement('option', $l);
                    $option->setAttribute('value', $l);
                    $select->appendChild($option);
                }
            }
            

            Wollte ich diesen Vorgang mit einer String-Operation tun, wäre das zwar auch möglich, aber deutlich schwerer zu lesen. Wenn es nur ein <select> im Dokument gibt, ist es etwas einfacher, als wenn es verschiedene davon gibt. Mit der DOM-Klasse weiß ich aber genau, was ich tue und kann mir sicher sein, dass der finale HTML-Code keine technischen Störungen haben wird - von fehlerhaft dargestellten Umlauten vielleicht einmal abgesehen.

            Liebe Grüße,

            Felix Riesterer.

            1. Lieber Felix Riesterer,

              Ersteinmal danke, dass du dir hier die Mühe gemacht hast!

              man kann in PHP auf zwei Arten HTML-Code erzeugen und an den Browser ausgeben:

              1.) String-basiert

              $html = '<!doctype html><html><head><title>Meine Seite</title></head><body>';
              
              $html .= '<h1>Willkommen auf meiner Seite!</h1>';
              $html .= '<p>Vielleicht haben Sie ja Lust sich ein wenig umzuschauen?</p>';
              $html .= '</body></html>';
              
              echo $html;
              

              Markup soll doch nicht mit echo ausgegeben werden, hab ich jedenfalls irgendwo mal gelsesen.

              P.s. Das ist nur eine Info, dass muss nicht kommentiert werden^^

              Warum sollte ich Dir keinen Ausblick auf das geben, wie Du vielleicht später einmal Deine Dokumente zusammen baust? Vielleicht mit einer DOM-Klasse?

              Man verzeihe mir aber ich bin noch lange nicht soweit, dass ich mit DOM-Klassen meine Seiten baue. Sehe darin auch für den Moment keine Notwendigkeit.

              2.) Man erstellt eine Datenstruktur, die die Dokumentstruktur abbildet, das sogenannte Document Object Model (DOM). Nicht nur JavaScript im Browser, sondern auch PHP auf dem Server kann das. Der Vorteil ist, dass man sich um die syntaktische Richtigkeit des endgültigen HTML-Codes (lies: Schreibfehler oder fehlende Tags) keine Gedanken mehr machen muss, da das die Klasse übernimmt.

              Das ist mit Sicherheit wirklich hilfreich. Aber warum sollte ich meine Fehler vorallem vor mir verstecken? Ich denke da an nicht geschloßene Tags, wenn das irgendwo auftaucht, sehe ich in der Ausgabe einen Fehler und suche daraufhin nach der Ursache und schließe das Tag. Oder eben ähnliches, wenn etwas nicht funktioniert, jedenfalls nicht so wie es Gedacht ist, dann geht man eben auf Fehlersuche.

              $doc = new DOMDocument('1.0', 'UTF-8');
              $doc->preserveWhiteSpace = false;
              $doc->formatOutput = true;
              
              $doc->loadHTML(
                  '<!doctype html><html><head><title>Meine Seite</title></head><body></body></html>'
              );
              
              $body = $doc->getElementsByTagName('body')->item(0);
              
              $h1 = $doc->createElement(
                  'h1',
                  'Willkommen auf meiner Seite!'
              );
              
              $p = $doc->createElement(
                  'p',
                  'Vielleicht haben Sie ja Lust sich ein wenig umzuschauen?'
              );
              
              $body->appendChild($h1);
              $body->appendChild($p);
              
              echo $doc->saveHTML();
              

              Ich sehe wohl einige Vorteile aber ich bin mit dem herkömmlichen Weg bis jetzt ganz zufrieden. Sprich neue PHP Datei erstellen und eine Seitenstruktur aufbauen so wie sie mir in Gedanken vorschwebt, sodass das Layout herauskommt was ich haben möchte.

              Wenn ich in meinen Projekten echte (lies: formal vollständige) HTML-Dokumente als Templates (lies: Vorlagen) benutze, dann verwende ich in der DOM-Klasse die Möglichkeiten, gezielt nach ID oder Elementarten zu suchen, um Inhalte hineinzubasteln:

              Also wenn ich etwas hinzufügen möchte mach ich die Datei auf und schreibe etwas rein. Da muss ich keiner DOM-Klasse sagen: "Such etwas und füge etwas hinzu".

              <!doctype html>
              <html>
                  <head>
                      <meta charset="utf-8">
                      <title>Einstellungen</title>
                  </head>
                  <body>
                      ...
                      <form>
                          ...
                          <label for="lang">{#language}</label>
                          <select id="lang" name="lang"></select>
                          ...
                      </form>
                      ...
                  </body>
              </html>
              

              Da mehrere Sprachen unterstützt werden sollen, steht im Dokument ein Platzhalter "{#language}", der je nach Benutzerspracheinstellung mit z.B. "Language" oder "Sprache" befüllt wird. Die verfügbaren Sprachen müssen jetzt als <option>-Elemente in das <select> eingefügt werden. Da sind String-Operationen nicht mehr so leicht, wenn auch nicht unmöglich, mit der DOM-Klasse ist das Ergebnis sicherer:

              $select = $doc->getElementById('lang');
              
              if ($select) {
                  foreach ($available_languages as $l) {
                      $option = $doc->createElement('option', $l);
                      $option->setAttribute('value', $l);
                      $select->appendChild($option);
                  }
              }
              

              Text für jede Sprache kommt aus der Datenbank oder einer includierten Datei. Verstehe nicht ganz was hier der Zweck oder das Ergebnis ist.

              Alles in allem würde ich gern abschließend noch einmal erwähnen. Es wäre vermessen zu sagen, dass ich weiterführende Kenntnisse in Webprogrammierung habe. Daher darf und bin ich diesen Gedanken und Tipps nicht von vornherein abgeneigt. Es ist allerdings so, dass man für sein (gefühltes und erhofftes) "ergebnis orientiertes Hobby" nicht alles braucht was einem jegliche Programiersprache zur verfügung stellt, geschweige denn die kombination aus vielen. (Ich meine ich habe einen Freund der macht viele Web Projekte in Phyton und kombiniert das mit jquery und ich verstehe nichts mehr wenn er mir verucht irgendwas nahe zu legen von dem er weiss, dass es für mich Sachen vereinfachen würde. Aber er ist eben auch studierter informatiker und ich nicht.)

              Es tut mir wirklich außerordentlich Leid wenn ich sagen muss, dass ich jedenfalls für den Moment befürchte, dass dieser wirklich hervorragende Erklärungsversuch leider gerade für mich keinen Sinn hat. Aber wenn ich irgendwann einmal erkennen sollte, welch hervorrangende möglichkeiten mir die DOM-Klasse hätte gebracht, dann erinnere ich mich hieran und werde das ganze nocheinmal aufrollen und versuchen nachzuvollziehen.

              Grüße, Jo

        2. @@Felix Riesterer

          Wer sein Dokument mit einer passenden Klasse (wie z.B. DOMDocument) erstellt und manipuliert, der wird am Ende seines Scripts sehr wohl mit echo den HTML-Code an den Browser senden: echo $myDoc->saveHTML(); oder etwas ähnliches.

          Das wäre dann die View in einer MVC-Architektur. Die Methode heißt dann desöfteren render().

          Die von Dir bevorzugte HereDoc-Schreibweise

          ?? HereDoc ist was ganz anderes. Aber das hast du inzwischen ja selbst herausgefunden.

          ist in meinen Augen ebenso problematisch wie inline-JavaScript in einem HTML-Dokument, da Programm-Logik und Markup vermischt notiert werden.

          Nein. Keine Programmlogik. Höchstens etwas Ausgabelogik: Wurden der Anfrage entsprechende Daten gefunden? Ja: gehe sie in einer Schleife durch und stelle sie dar. Nein: Gebe eine entsprechende Meldung aus.

          Genau das, was eine Templatesprache kann. Ob man nun sowas wie Smarty einsetzt oder PHP mit einfachen Kontrollstrukturen als Templatesprache verwendet, hängt vom Anwendungsfall ab.

          LLAP 🖖

          --
          “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
          Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
    3. Lieber Felix Riesterer,

      $insert_message = sprintf(
          'INSERT INTO chat ('
          . 'message_writer, message, message_date'
          . ') VALUES ('
          . '\'%1$s\', \'%2$s\', \'%3$s\''
          . ')',
          $_SESSION['user_name'],
          $_POST['chat'],
          time()
      );
      

      '\'%1$s\' Die Zeichenkette versteh ich gerade noch nicht vollständig. Das s sollte den übergebenen String beinhalten, das erste s dann hier $_SESSION['user_name'] usw. . Aber was macht das \'%1$.

      Wenn ich jetzt aber einfach mal sage das:

      if($_POST)
      {
      	foreach($_POST as $key=>$value)
      	{
      		$_POST[$key]= mysqli_real_escape_string($value);
      	}
      }
      

      Dann kommt ja z.b. ein ' garnicht durch als $_POSTvariable oder nicht?

      Gruß Jo

      1. Lieber j4nk3y,

        '\'%1$s\' Die Zeichenkette versteh ich gerade noch nicht vollständig. Das s sollte den übergebenen String beinhalten, das erste s dann hier $_SESSION['user_name'] usw. . Aber was macht das \'%1$.

        wenn Du bei PHP.net nachgelesen hast, das die Funktion sprintf Ersetzungen in Strings vornehmen kann, dann hast Du sicher gesehen, dass es nicht nur das s ist, sondern die Zeichenfolge %s. Man kann die Platzhalter mit Nummern versehen, um einen Teilstring, der öfter eingesetzt werden soll, nicht öfter in der Parameterliste notieren zu müssen:

        sprintf(
            'Wir haben %1$s %1$s %1$s haben %1$s %1$s %1$s haben %1$s %1$s %1$s haben %2$s!',
            'Hunger',
            'Durst'
        );
        

        Wenn in Deinem SQL-String der Wert in einfache Quotes verpackt werden soll, dann müssen diese mit einem Backslash escaped werden, da sonst Syntaxfehler entstehen:

        sprintf(
            'Wir haben '%1$s' '%1$s' '%1$s' haben '%1$s' '%1$s' '%1$s' haben '%1$s' '%1$s' '%1$s' haben '%2$s!'',
            'Hunger',
            'Durst'
        );
        

        Deshalb diese Schreibweise:

        sprintf(
            'Wir haben \'%1$s\' \'%1$s\' \'%1$s\' haben \'%1$s\' \'%1$s\' \'%1$s\' haben \'%1$s\' \'%1$s\' \'%1$s\' haben \'%2$s!\'',
            'Hunger',
            'Durst'
        );
        

        Wenn ich jetzt aber einfach mal sage das:

        if($_POST)
        {
        	foreach($_POST as $key=>$value)
        	{
        		$_POST[$key]= mysqli_real_escape_string($value);
        	}
        }
        

        Dann kommt ja z.b. ein ' garnicht durch als $_POSTvariable oder nicht?

        Warum willst Du alle geposteten Werte für den SQL-Kontext kodieren? Solltest Du eine Fehlermeldung ins Dokument schreiben, bei der Du etwas bemängelst, dann kannst Du den originalen Wert nicht mehr rekonstruieren:

        $_POST['lang'] = 'Leck mich!';
        
        if (!in_array($_POST['lang'], $available_languages) {
            // create error message
            $error = sprintf(
                '<p class="error">Falsche Sprache <strong>%1$s</strong>angegeben!</p>',
                htmlspecialchars($_POST['lang'])
            );
        }
        

        Man kodiert genau dort, wo man es benötigt. Im obigen Beispiel wird der gepostete Wert für den HTML-Kontext kodiert. Der Wert im $_POST-Array wird dabei aber nicht verändert, damit er an anderer Stelle wieder original zur Verfügung steht und für den dortigen Kontext passend kodiert werden kann (z.B. mit mysqli_real_escape_string). Das stand aber in dem von mir verlinkten und zur Lektüre ans Herz gelegten Artikel... ;-)

        Liebe Grüße,

        Felix Riesterer.

        1. Lieber Felix Riesterer,

          '\'%1$s\' Die Zeichenkette versteh ich gerade noch nicht vollständig. Das s sollte den übergebenen String beinhalten, das erste s dann hier $_SESSION['user_name'] usw. . Aber was macht das \'%1$.

          wenn Du bei PHP.net nachgelesen hast, das die Funktion sprintf Ersetzungen in Strings vornehmen kann, dann hast Du sicher gesehen, dass es nicht nur das s ist, sondern die Zeichenfolge %s. Man kann die Platzhalter mit Nummern versehen, um einen Teilstring, der öfter eingesetzt werden soll, nicht öfter in der Parameterliste notieren zu müssen:

          sprintf(
              'Wir haben %1$ %1$ %1$ haben %1$ %1$ %1$ haben %1$ %1$ %1$ haben %2$!',
              'Hunger',
              'Durst'
          );
          

          Wenn in Deinem SQL-String der Wert in einfache Quotes verpackt werden soll, dann müssen diese mit einem Backslash escaped werden, da sonst Syntaxfehler entstehen:

          sprintf(
              'Wir haben '%1$' '%1$' '%1$' haben '%1$' '%1$' '%1$' haben '%1$' '%1$' '%1$' haben '%2$!'',
              'Hunger',
              'Durst'
          );
          

          Deshalb diese Schreibweise:

          sprintf(
              'Wir haben \'%1$\' \'%1$\' \'%1$\' haben \'%1$\' \'%1$\' \'%1$\' haben \'%1$\' \'%1$\' \'%1$\' haben \'%2$!\'',
              'Hunger',
              'Durst'
          );
          

          Natürlich wie konnte ich nur so blind sein. Danke für die ausführliche Erklärung.

          Wenn ich jetzt aber einfach mal sage das:

          if($_POST)
          {
          	foreach($_POST as $key=>$value)
          	{
          		$_POST[$key]= mysqli_real_escape_string($value);
          	}
          }
          

          Dann kommt ja z.b. ein ' garnicht durch als $_POSTvariable oder nicht?

          Warum willst Du alle geposteten Werte für den SQL-Kontext kodieren? Solltest Du eine Fehlermeldung ins Dokument schreiben, bei der Du etwas bemängelst, dann kannst Du den originalen Wert nicht mehr rekonstruieren:

          Hm, eigentlich dachte ich alle Variablen die Irgendjemand eingibt schonmal vorab entschärfen.

          $_POST['lang'] = 'Leck mich!';
          
          if (!in_array($_POST['lang'], $available_languages) {
              // create error message
              $error = sprintf(
                  '<p class="error">Falsche Sprache <strong>%1$s</strong>angegeben!</p>',
                  htmlspecialchars($_POST['lang'])
              );
          }
          

          Das wird wohl nicht passieren, da die $_POST['lang'] aus der Datenbank gefüllt wird. Außer jemand fummelt an der $_SESSION variable rum, dann kommt er garnicht erst bis zu dem Punkt und die $_SESSION wird sofort beendet Und man müsste sich neu Einloggen.

          Man kodiert genau dort, wo man es benötigt. Im obigen Beispiel wird der gepostete Wert für den HTML-Kontext kodiert. Der Wert im $_POST-Array wird dabei aber nicht verändert, damit er an anderer Stelle wieder original zur Verfügung steht und für den dortigen Kontext passend kodiert werden kann (z.B. mit mysqli_real_escape_string). Das stand aber in dem von mir verlinkten und zur Lektüre ans Herz gelegten Artikel... ;-)

          Da hab ich schon drübergelesen, werde ich auch nochmal eingehender machen.

          Gruß Jo

          1. Hallo,

            $_POST['lang'] = 'Leck mich!';
            
            if (!in_array($_POST['lang'], $available_languages) {
                // create error message
                $error = sprintf(
                    '<p class="error">Falsche Sprache <strong>%1$s</strong>angegeben!</p>',
                    htmlspecialchars($_POST['lang'])
                );
            }
            

            Das wird wohl nicht passieren, da die $_POST['lang'] aus der Datenbank gefüllt wird.

            ganz gewiss nicht - die Werte im $_POST-Array kommen direkt vom Client! Sie können daher beliebig richtig, falsch oder manipuliert sein.

            So long,
             Martin

            --
            Logik ist die Theorie, Chaos die Praxis.
            1. Hallo,

              $_POST['lang'] = 'Leck mich!';
              
              if (!in_array($_POST['lang'], $available_languages) {
                  // create error message
                  $error = sprintf(
                      '<p class="error">Falsche Sprache <strong>%1$s</strong>angegeben!</p>',
                      htmlspecialchars($_POST['lang'])
                  );
              }
              

              Das wird wohl nicht passieren, da die $_POST['lang'] aus der Datenbank gefüllt wird.

              ganz gewiss nicht - die Werte im $_POST-Array kommen direkt vom Client! Sie können daher beliebig richtig, falsch oder manipuliert sein.

              <input type="checkbox" name="language" class="checkbox_chat" value="<?php echo $_SESSION['language'];?>"/>
              <label for="language">Language</label>
              

              Ganz gewiss! Die $_SESSION['language'] wird aus der Datenbank gefüllt bei jedem Einloggen eines Benutzers mit der in der Datenbank hinterlegten Sprache die der Benutzer beim Registrieren wählen kann. So ist es jedenfalls im Moment, ich überlege gerade ob ich ihm auch noch andere sprachen zugänglich machen will über ein <select><option></option>...</select>.

              OK, das gilt für den Normalfall, sicher kann der Client die gesendeten Daten manipulieren. Sicher muss ich davon ausgehen und mich darauf vorbereiten aber ich gehe mal vom normalen 08/15 Benutzer aus der nicht an der $_SESSION variable rum doktert oder an den $_POST variablen.

              Gruß Jo

              1. Hi,

                Das wird wohl nicht passieren, da die $_POST['lang'] aus der Datenbank gefüllt wird.

                ganz gewiss nicht - die Werte im $_POST-Array kommen direkt vom Client! Sie können daher beliebig richtig, falsch oder manipuliert sein.

                <input type="checkbox" name="language" class="checkbox_chat" value="<?php echo $_SESSION['language'];?>"/>
                <label for="language">Language</label>
                

                Ganz gewiss! Die $_SESSION['language'] wird aus der Datenbank gefüllt bei jedem Einloggen eines Benutzers mit der in der Datenbank hinterlegten Sprache die der Benutzer beim Registrieren wählen kann.

                ja, und dann? Dann gibst du das als Vorbelegung eines Formularfelds aus. Was aber beim nächsten Request in $_POST steht, muss beileibe nicht das sein, was du dem Client vorher mitgeteilt hast.

                Ich wiederhole: Die Werte im $_POST-Array kommen direkt vom Client! Sie können daher beliebig richtig, falsch oder manipuliert sein.

                So ist es jedenfalls im Moment, ich überlege gerade ob ich ihm auch noch andere sprachen zugänglich machen will über ein <select><option></option>...</select>.

                Bitte, ja. Rechne damit, dass ein Nutzer in bestimmten Fällen auch mal eine andere Sprache haben will. Sei es, weil er seine Sprachkenntnisse auf die Probe stellen will, oder weil gerade die Freundin aus Spanien neben ihm sitzt, die sich mit der spanischen Version leichter tut als mit der deutschen.

                Ciao,
                 Martin

                --
                Logik ist die Theorie, Chaos die Praxis.
                1. Hi,

                  ja, und dann? Dann gibst du das als Vorbelegung eines Formularfelds aus. Was aber beim nächsten Request in $_POST steht, muss beileibe nicht das sein, was du dem Client vorher mitgeteilt hast.

                  Ich wiederhole: Die Werte im $_POST-Array kommen direkt vom Client! Sie können daher beliebig richtig, falsch oder manipuliert sein.

                  Ja ich hatte das noch kurz hinterher geschoben:

                  OK, das gilt für den Normalfall, sicher kann der Client die gesendeten Daten manipulieren. Sicher muss ich davon ausgehen und mich darauf vorbereiten aber ich gehe erst einmal vom normalen 08/15 Benutzer aus der nicht an der $_SESSION variable rum doktert oder an den $_POST variablen.

                  So ist es jedenfalls im Moment, ich überlege gerade ob ich ihm auch noch andere sprachen zugänglich machen will über ein <select><option></option>...</select>.

                  Bitte, ja. Rechne damit, dass ein Nutzer in bestimmten Fällen auch mal eine andere Sprache haben will. Sei es, weil er seine Sprachkenntnisse auf die Probe stellen will, oder weil gerade die Freundin aus Spanien neben ihm sitzt, die sich mit der spanischen Version leichter tut als mit der deutschen.

                  Ja hier geht es ja nur darum aus welcher Tabell gerade die Nachrichten gezogen werden und wieder geschrieben werden. Nicht um die Anzeige Sprache der Webseite.

                  Gruß Jo

          2. Lieber j4nk3y,

            Hm, eigentlich dachte ich alle Variablen die Irgendjemand eingibt schonmal vorab entschärfen.

            das ist Unsinn. Die Idee, etwas zu entschärfen setzt voraus, dass es einen Kontext gibt, in dem diese Daten gefährlich sein könnten. Du kannst nicht irgendwo im Script von irgendeinem Kontext ausgehend die Daten für alle Kontexte entschärfen. Daher mein Einwand: Lass es einfach sein. Nimm die originalen Daten (erkennbar am $_GET- oder $_POST-Array) und kodiere sie an Ort und Stelle je nach Kontext entsprechend wie in meinem Beispiel. Dann hast Du die Daten hinsichtlich der Gefährlichkeit im Griff. Sonst verlässt Du Dich auf irgendeinen ominösen Zauber und bist am Ende verlassen.

            Liebe Grüße,

            Felix Riesterer.

            1. Lieber Felix Riesterer,

              Hm, eigentlich dachte ich alle Variablen die Irgendjemand eingibt schonmal vorab entschärfen.

              das ist Unsinn. Die Idee, etwas zu entschärfen setzt voraus, dass es einen Kontext gibt, in dem diese Daten gefährlich sein könnten. Du kannst nicht irgendwo im Script von irgendeinem Kontext ausgehend die Daten für alle Kontexte entschärfen. Daher mein Einwand: Lass es einfach sein. Nimm die originalen Daten (erkennbar am $_GET- oder $_POST-Array) und kodiere sie an Ort und Stelle je nach Kontext entsprechend wie in meinem Beispiel. Dann hast Du die Daten hinsichtlich der Gefährlichkeit im Griff. Sonst verlässt Du Dich auf irgendeinen ominösen Zauber und bist am Ende verlassen.

              Auf das man es an einer Stelle vergisst... Jede Eingabe von einem Benutzer ist potentiell gefährlich, darum muss man das ja machen. Und warum dann nicht Zentral für alles was ankommt? Naja wenn es gesagt wird, dann setzt der Leie das so um.

              Sprich:

              <?php
              session_start();
              require_once('db_connect_function.php');
              
              if(isset($_POST['chat']) && !empty($_POST['chat']))
              {
              	$writer = mysqli_real_escape_string ($_SESSION['user_name']);
              	$chat = mysqli_real_escape_string ($_POST['chat']);
              	$world = mysqli_real_escape_string ($_POST['world']);
              	$language = mysqli_real_escape_string ($_POST['language']);
              	$alliance = mysqli_real_escape_string ($_POST['alliance']);
              	
              	$insert_message = sprintf(
              	'INSERT INTO chat ('
                  . 'message_writer, message, message_date'
                  . ') VALUES ('
                  . '\'%1$s\', \'%2$s\', \'%3$s\''
                  . ')',
                  $_SESSION['user_name'],
                  $_POST['chat'],
                  time());
              
              	if($db -> query($insert_message) === TRUE)
              	{
              		$db -> commit();
              	}
              	else
              	{
              		//error_log! $create_db_connect->error.
              	}
              	
              	
              	exit();
              }
              ?>
              

              Gruß Jo

              1. Hallo,

                Auf das man es an einer Stelle vergisst... Jede Eingabe von einem Benutzer ist potentiell gefährlich

                ja, aber doch immer nur gefährlich für einen bestimmten Anwendungsfall. Darum unterscheidet sich doch die Art und Weise, wie man diese Daten "entschärfen" muss, abhängig von der Anwendung.

                Es ist zum Beispiel nutzlos, Gläser in Watte zu packen, wenn sie danach durch einen Hochofen geschoben werden sollen; da wäre eine hitzefeste Verpackung sinnvoller.

                darum muss man das ja machen. Und warum dann nicht Zentral für alles was ankommt?

                Ja, aber doch nicht einfach blind und pauschal nach den Regeln von SQL. Die Regeln, nach denen man Daten maskieren, codieren oder escapen muss, damit sie keinen Schaden anrichten, entscheiden sich doch immer danach, in welchen Kontext man diese Daten einbringt. Und auch erst an dieser Stelle.

                So long,
                 Martin

                --
                Logik ist die Theorie, Chaos die Praxis.
                1. Morgen,

                  Auf das man es an einer Stelle vergisst... Jede Eingabe von einem Benutzer ist potentiell gefährlich

                  ja, aber doch immer nur gefährlich für einen bestimmten Anwendungsfall. Darum unterscheidet sich doch die Art und Weise, wie man diese Daten "entschärfen" muss, abhängig von der Anwendung.

                  Sicherlich. Aber mir fällt gerade keine Stelle ein, wo ich Daten aus einem Formularfeld, sprich $_POST variablen nicht hinterher in ein SQL statement packe. Ich wüsste auch nicht wofür ich sonst ein Formularfeld brauche um nicht damit meine Datenbank zu füttern.

                  Es ist zum Beispiel nutzlos, Gläser in Watte zu packen, wenn sie danach durch einen Hochofen geschoben werden sollen; da wäre eine hitzefeste Verpackung sinnvoller.

                  Stimmt, außer man möchte eine Graphen Schicht auf dem Glas um sie elektrisch Leitfähig zu machen. Jedenfalls wenn die Temperatur im Hochofen nicht höher als ~1650K beträgt. Wenn man jedoch auf eine Glasschmelze aus ist dann sollte es schon noch ein wenig heißer sein. Da findet sich doch bestimmt irgendwo ein Anwednungsbereich für Graphen verstärktes Glas. Und ab 3900K wirds richtig Lustig, da schmilzt sogar das Graphen und es bildet sich ein Verbund aus Glas und Graphen schmelze, wo da wohl das Eutektikum liegt? Hm, aber das gehört hier wohl nicht wirklich her...

                  darum muss man das ja machen. Und warum dann nicht Zentral für alles was ankommt?

                  Ja, aber doch nicht einfach blind und pauschal nach den Regeln von SQL. Die Regeln, nach denen man Daten maskieren, codieren oder escapen muss, damit sie keinen Schaden anrichten, entscheiden sich doch immer danach, in welchen Kontext man diese Daten einbringt. Und auch erst an dieser Stelle.

                  Wie gesagt ist mir garkein anderer Anwendungsbereich bekannt, wohl weil ich einen anderen noch garnicht im Sinn hatte.

                  Ich weiß eure Anregungen wirklich zu schätzen aber soweit bin ich wohl einfach noch nicht. Trotzdem Danke!

                  Gruß Jo

              2. Tach!

                Auf das man es an einer Stelle vergisst... Jede Eingabe von einem Benutzer ist potentiell gefährlich, darum muss man das ja machen.

                Das ist der große Irrtum, der leider immer wieder so gepredigt wird und dann zu falschen Schlüssen führt. Die Eingabedaten sind nicht gefährlich, sie explodieren nicht einfach so, oder machen von sich aus irgendwelche gefährlichen Dinge. Es sind die Ausgabedaten, bei denen vergessen wurde, sie für den Ausgabekontext zu behandeln. Und es ist dabei völlig unerheblich, ob die Daten aus einer Eingabe oder aus einer anderen Quelle stammen - wenn sie Sonderzeichen enthalten können, müssen diese maskiert werden, oder was auch immer der aktuelle Kontext vorsieht.

                Und warum dann nicht Zentral für alles was ankommt? Naja wenn es gesagt wird, dann setzt der Leie das so um.

                Deswegen ist das ja auch nicht gut, wenn man das dem Laien immer so falsch erklärt. In deinem Beispiel gibst du die Daten direkt in Richtung SQL aus. Abgesehen davon, dass man mit Prepared Statements keine Behandlung mehr braucht ... stell dir mal vor, du nimmst die Daten und prüfst sie erst auf fachliche Richtigkeit. Du stellst nun fest, dass da Fehler drin sind, die der Anwender erstmal beseitigen muss, bevor sie gespeichert werden können. Also baust du ein Affenformular, das die Daten solange wieder in ein HTML-Formular schreibt und dem Anwender zurückgibt, bis sie korrekt sind. Solange gilt als Kontext HTML und erst dann gilt der Kontext SQL. Es nützt dir also nichts, beziehungsweise macht mehr Probleme als es löst, wenn du gleich am Eingang die SQL-Behandlung vornimmst. Das fügt zum Beispiel Backslashes vor Anführungszeichen, obwohl das in HTML &quot; sein muss (nicht immer, aber in Attributwerten, und anderswo schadet es auch nicht).

                Das Argument, man dürfe die Behandlung nicht vergessen ist insoweit richtig. Aber das muss man sich für die Ausgabe angewöhnen. "Jegliche Daten müssen dem Ausgabekontext entsprechend angepasst werden." Das ist der einfache Grundsatz. Der Teufel liegt dann jedoch mitunter im Detail, weil gelegentlich mehrere Kontext geschachtelt werden müssen. Daten, die in einer URL transportiert werden sollen, und die ihrerseite im HTML-Code steht, ist so ein geschtelter Fall. Das braucht zwei Behandlungen. Die Daten brauchen eine URL-gerechte Umformung, und die URL selbst muss HTML-Konform sein. Wir haben da im Wiki einen Artikel zum Kontextwechsel, der recht viele der im Webumfeld vorkommenden Kontexte beleuchtet.

                dedlfix.

                1. @@dedlfix

                  Das fügt zum Beispiel Backslashes vor Anführungszeichen, obwohl das in HTML &quot; sein muss (nicht immer, aber in Attributwerten, und anderswo schadet es auch nicht).

                  Doch, dem Auge. 😢

                  " hat im Text nichts zu suchen. Anführungszeichen (je nach Sprache „“ oder “” oder „” oder «» …) müssen nicht escapet werden. 😜

                  LLAP 🖖

                  --
                  “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
                  Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
                2. Moin!

                  Auf das man es an einer Stelle vergisst... Jede Eingabe von einem Benutzer ist potentiell gefährlich, darum muss man das ja machen.

                  Das ist der große Irrtum, der leider immer wieder so gepredigt wird und dann zu falschen Schlüssen führt. Die Eingabedaten sind nicht gefährlich, sie explodieren nicht einfach so, oder machen von sich aus irgendwelche gefährlichen Dinge. Es sind die Ausgabedaten, bei denen vergessen wurde, sie für den Ausgabekontext zu behandeln. Und es ist dabei völlig unerheblich, ob die Daten aus einer Eingabe oder aus einer anderen Quelle stammen - wenn sie Sonderzeichen enthalten können, müssen diese maskiert werden, oder was auch immer der aktuelle Kontext vorsieht.

                  Sicher explodieren sie nicht von alleine, sie explodieren ja nur wenn das von dem Benutzer beabsichtigt ist. Sprich XSS oder irgendwas anderes was ich nicht kenne.

                  Und warum dann nicht Zentral für alles was ankommt? Naja wenn es gesagt wird, dann setzt der Leie das so um.

                  Deswegen ist das ja auch nicht gut, wenn man das dem Laien immer so falsch erklärt. In deinem Beispiel gibst du die Daten direkt in Richtung SQL aus. Abgesehen davon, dass man mit Prepared Statements keine Behandlung mehr braucht ... stell dir mal vor, du nimmst die Daten und prüfst sie erst auf fachliche Richtigkeit. Du stellst nun fest, dass da Fehler drin sind, die der Anwender erstmal beseitigen muss, bevor sie gespeichert werden können. Also baust du ein Affenformular, das die Daten solange wieder in ein HTML-Formular schreibt und dem Anwender zurückgibt, bis sie korrekt sind. Solange gilt als Kontext HTML und erst dann gilt der Kontext SQL. Es nützt dir also nichts, beziehungsweise macht mehr Probleme als es löst, wenn du gleich am Eingang die SQL-Behandlung vornimmst. Das fügt zum Beispiel Backslashes vor Anführungszeichen, obwohl das in HTML &quot; sein muss (nicht immer, aber in Attributwerten, und anderswo schadet es auch nicht).

                  Das Argument, man dürfe die Behandlung nicht vergessen ist insoweit richtig. Aber das muss man sich für die Ausgabe angewöhnen. "Jegliche Daten müssen dem Ausgabekontext entsprechend angepasst werden." Das ist der einfache Grundsatz. Der Teufel liegt dann jedoch mitunter im Detail, weil gelegentlich mehrere Kontext geschachtelt werden müssen. Daten, die in einer URL transportiert werden sollen, und die ihrerseite im HTML-Code steht, ist so ein geschtelter Fall. Das braucht zwei Behandlungen. Die Daten brauchen eine URL-gerechte Umformung, und die URL selbst muss HTML-Konform sein. Wir haben da im Wiki einen Artikel zum Kontextwechsel, der recht viele der im Webumfeld vorkommenden Kontexte beleuchtet.

                  Danke für den Hinweis.

                  Gruß Jo

                  1. Tach!

                    Das ist der große Irrtum, der leider immer wieder so gepredigt wird und dann zu falschen Schlüssen führt. Die Eingabedaten sind nicht gefährlich, sie explodieren nicht einfach so, oder machen von sich aus irgendwelche gefährlichen Dinge.

                    Sicher explodieren sie nicht von alleine, sie explodieren ja nur wenn das von dem Benutzer beabsichtigt ist. Sprich XSS oder irgendwas anderes was ich nicht kenne.

                    Nein, auch dann explodieren sie nicht von allein. Die Daten sind nicht das Problem. Die unzureichende Beachtung des Ausgabekontextes ist das Problem, das zur "Explosion" führt.

                    dedlfix.

                    1. Moin!

                      Das ist der große Irrtum, der leider immer wieder so gepredigt wird und dann zu falschen Schlüssen führt. Die Eingabedaten sind nicht gefährlich, sie explodieren nicht einfach so, oder machen von sich aus irgendwelche gefährlichen Dinge.

                      Sicher explodieren sie nicht von alleine, sie explodieren ja nur wenn das von dem Benutzer beabsichtigt ist. Sprich XSS oder irgendwas anderes was ich nicht kenne.

                      Nein, auch dann explodieren sie nicht von allein. Die Daten sind nicht das Problem. Die unzureichende Beachtung des Ausgabekontextes ist das Problem, das zur "Explosion" führt.

                      Um ehrlich zu sein, versteh ich nicht was du meinst. was ist den der Ausgabekontext?

                      Gruß Jo

                      1. Tach!

                        Um ehrlich zu sein, versteh ich nicht was du meinst. was ist den der Ausgabekontext?

                        Das ist die Umgebung, in die du die Daten ausgibst. In deinem Fall nur das SQL-Statement, bei einer Ausgabe zum Browser wäre das HTML, und so weiter und so fort.

                        dedlfix.

                        1. Moin

                          Um ehrlich zu sein, versteh ich nicht was du meinst. was ist den der Ausgabekontext?

                          Das ist die Umgebung, in die du die Daten ausgibst. In deinem Fall nur das SQL-Statement, bei einer Ausgabe zum Browser wäre das HTML, und so weiter und so fort.

                          Achso, klar. Naja wie schon erwähnt, eigentlich alles was ich mit Formularen und $_POST Variablen mache landet in einem SQL-Statement. Und alles was Ausgegeben wird kommt aus der DB. Darum der Gedanke, warum nicht gleich jede $_POST Variable für das SQL_Statement Zentral prüfen.

                          Gruß Jo

                          1. Tach!

                            Achso, klar. Naja wie schon erwähnt, eigentlich alles was ich mit Formularen und $_POST Variablen mache landet in einem SQL-Statement. Und alles was Ausgegeben wird kommt aus der DB.

                            Und du meinst nun, weil sie aus der DB kommen, sind die Daten "sicher"? Das versuche ich dir ja zu erklären, dass die Herkunft der Daten keine Rolle spielt und nur das Ziel entscheidend ist, für die Art und Weise, wie bestimmte Zeichen maskiert werden müssen. Auch ein harmloses < in einer mathematischen Gleichung beispielsweise, ist in HTML ein Zeichen mit besonderer Bedeutung. Das muss nicht der Anfang eines XSS-Versuchs sein, um den Browser dazu zu bringen, Zeichen entgegen der eigentlichen Intention zu interpretieren. Wenn ein < einfach nur als solches ausgegeben werden soll, muss es als &lt; notiert werden (abgesehen von Fehlerkorrekturversuchen der Browser in manchen Fällen). Es spielt keine Rolle, ob es aus der Datenbank kommt oder aus einer Nutzereingabe oder aus einer Nutzereingabe, die in einer Datenbank abgelegt wurde.

                            Darum der Gedanke, warum nicht gleich jede $_POST Variable für das SQL_Statement Zentral prüfen.

                            Weil das zwar in deinem einfachen Fall zielführend ist, aber sobald deine Projekte komplexer werden, bekommst du mit der Herangehensweise immer mehr Probleme. Bitte lies den bereits verlinkten Kontextwechsel-Artikel. Der ist zweiteilig und in seiner Fortsetzung gibt es den Abschnitt HTML in der Datenbank. Darin kannst du Beispiele für ganz harmlose (also nicht sicherheitsrelevante) Probleme finden, wenn du Daten zu früh für einen bestimmten Ausgabekontext vorbereitest.

                            dedlfix.

                            1. Moin

                              Achso, klar. Naja wie schon erwähnt, eigentlich alles was ich mit Formularen und $_POST Variablen mache landet in einem SQL-Statement. Und alles was Ausgegeben wird kommt aus der DB.

                              Und du meinst nun, weil sie aus der DB kommen, sind die Daten "sicher"?

                              Naja wenn sie maskiert/codiert eingefügt wurden?

                              Das versuche ich dir ja zu erklären, dass die Herkunft der Daten keine Rolle spielt und nur das Ziel entscheidend ist, für die Art und Weise, wie bestimmte Zeichen maskiert werden müssen. Auch ein harmloses < in einer mathematischen Gleichung beispielsweise, ist in HTML ein Zeichen mit besonderer Bedeutung. Das muss nicht der Anfang eines XSS-Versuchs sein, um den Browser dazu zu bringen, Zeichen entgegen der eigentlichen Intention zu interpretieren. Wenn ein < einfach nur als solches ausgegeben werden soll, muss es als &lt; notiert werden (abgesehen von Fehlerkorrekturversuchen der Browser in manchen Fällen). Es spielt keine Rolle, ob es aus der Datenbank kommt oder aus einer Nutzereingabe oder aus einer Nutzereingabe, die in einer Datenbank abgelegt wurde.

                              Das verstehe ich wohl aber ich will ja verhindern das ein < oder ähnliches in die Datenbank kommt.

                              Darum der Gedanke, warum nicht gleich jede $_POST Variable für das SQL_Statement Zentral prüfen.

                              Weil das zwar in deinem einfachen Fall zielführend ist, aber sobald deine Projekte komplexer werden, bekommst du mit der Herangehensweise immer mehr Probleme. Bitte lies den bereits verlinkten Kontextwechsel-Artikel. Der ist zweiteilig und in seiner Fortsetzung gibt es den Abschnitt HTML in der Datenbank. Darin kannst du Beispiele für ganz harmlose (also nicht sicherheitsrelevante) Probleme finden, wenn du Daten zu früh für einen bestimmten Ausgabekontext vorbereitest.

                              Warum sollte man Markup in einer DB speichern? Natürlich gehe ich von meinem einfachen Fall aus und es ist interessant das einem noch viel mehr Möglichkeiten zu Verfügung stehen bei denen man dann auch einiges beachten muss. Nur ich sehe im Moment nicht die Notwendigkeit mir alles aneignen zu müssen was möglich und erst damit nötig ist.

                              Und es wäre hilfreich wenn mal ein Beispiel kommt was ich auch versteh und nicht eine Erklärung mit der verlinkung zu immer dem gleichen Artikel, den ich jetzt schon gelesen habe.

                              Also Wenn zum Beispiel:

                              if(isset($_POST['chat']) && !empty($_POST['chat']))
                              {
                              	$writer = mysqli_real_escape_string($_SESSION['user_name']);
                              	$chat = mysqli_real_escape_string($_POST['chat']);
                              	
                              	$insert_message = sprintf(
                              	'INSERT INTO chat ('
                                  . 'message_writer, message, message_date'
                                  . ') VALUES ('
                                  . '\'%1$s\', \'%2$s\', \'%3$s\''
                                  . ')',
                                  $_SESSION['user_name'],
                                  $_POST['chat'],
                                  time());
                              	if($db -> query($insert_message) === TRUE)
                              	{
                              		$db -> commit();
                              	}
                              	else
                              	{
                              		//error_log! $create_db_connect->error.
                              	}
                              	
                              	
                              	exit();
                              }
                              

                              Und in der $_POST['chat'] steht meinetwegen <script>böser.pfad</script>, was kommt in der Datenbank an?

                              Und wieso entschärft:

                               $output = "";
                              require_once('db_connect_function.php');
                              
                              $get_messages = "Select * FROM (Select message_writer, message, message_date FROM chat ORDER BY message_date DESC Limit 50 ) chat ORDER BY message_date ASC";
                              
                              if ($result = $db->query($get_messages)):
                              while ($row = $result->fetch_assoc()): 
                              ?>
                                  <article>
                                    <footer>
                                      <time datetime="<?php echo date('c', $row['message_date']); ?>"><?php echo date('H:i:s', $row['message_date']); ?></time>
                                      <span class="author"><?php echo htmlspecialchars($row['message_writer']); ?></span>
                                    </footer>
                                    <p class="message"><?php echo htmlspecialchars($row['message']); ?></p>
                                  </article>
                              <?php
                              endwhile;
                              else:
                              	//error_log! $create_db_connect->error.
                              endif;
                              

                              das nicht die Ausgabe?

                              Ich glaube mehr will ich überhaupt nicht. Also mir würde kein Beispiel einfallen wo ich etwas anderes machen möchte. Bzw. doch, eigentlich schon, vorher würde gern noch prüfen ob etwas derartiges in dem Formularfeld steht und dann die weiterleitung direkt unterbinden. Oder zumindest wenn nicht das drin steht was ich erwarte dann eben die weiterleitung unterbinden. Sprich, wenn ich in dem Formularfeld eine Zahl erwarte, dann hat das gefälligst auch eine zahl zu sein und kein String. Aber das ist Javascript, dass hab ich zwar schon irgendwo gefunden, aber mich noch nicht mit beschäftigt.

                              Gruß Jo

                              1. Hallo,

                                Das verstehe ich wohl aber ich will ja verhindern das ein < oder ähnliches in die Datenbank kommt.

                                und genau das ist der falsche Ansatz. Warum sollte man bestimmte Zeichen ausschließen, wenn man sie problemlos verwenden kann, solange man entsprechende Regeln einhält?

                                Warum sollte man Markup in einer DB speichern?

                                Warum nicht? - Okay, meist ist es sinnvoller, Informationen formatneutral zu speichern, also am besten als Plaintext. Aber es muss ja nicht unbedingt Markup sein. Wie dedlfix gezeigt hat, genügt ja schon ein '<', das als mathematisches Zeichen gemeint ist. Und dieses Zeichen kann gefahrlos in die DB geschrieben werden. Erst beim Auslesen, wenn der Text in HTML eingefügt werden soll, muss dieses Zeichen maskiert werden.

                                Und weil jeder individuelle Kontext (HTML, Javascript, SQL, CSS, ...) seine eigenen Sonderregeln und Sonderzeichen hat, muss man die Information immer dem Zielkontext entsprechend aufbereiten. Teilweise hat PHP fertige Funktionen dafür, die man an der richtigen Stelle einfach benutzen kann.

                                Natürlich gehe ich von meinem einfachen Fall aus und es ist interessant das einem noch viel mehr Möglichkeiten zu Verfügung stehen bei denen man dann auch einiges beachten muss. Nur ich sehe im Moment nicht die Notwendigkeit mir alles aneignen zu müssen was möglich und erst damit nötig ist.

                                Das halte ich für eine ungünstige Denkweise. Wenn du in deinem überschaubaren Fall Vereinfachungen machst, ist die Gefahr groß, dass du bei anderen Projekten aus Gewohnheit genauso verfährst. Warum sollte man es sich also nicht gleich "richtig" angewöhnen?

                                Und es wäre hilfreich wenn mal ein Beispiel kommt was ich auch versteh

                                Wenn du etwas nicht verstehst, frag bitte gezielt nach. Kein Problem. Ich versteh nämlich nicht, was für ein Beispiel du eigentlich noch brauchst.

                                if(isset($_POST['chat']) && !empty($_POST['chat']))
                                {
                                	$writer = mysqli_real_escape_string($_SESSION['user_name']);
                                	$chat = mysqli_real_escape_string($_POST['chat']);
                                	
                                	$insert_message = sprintf(
                                	'INSERT INTO chat ('
                                    . 'message_writer, message, message_date'
                                    . ') VALUES ('
                                    . '\'%1$s\', \'%2$s\', \'%3$s\''
                                    . ')',
                                    $_SESSION['user_name'],
                                    $_POST['chat'],
                                    time());
                                	if($db -> query($insert_message) === TRUE)
                                	{
                                		$db -> commit();
                                	}
                                	else
                                	{
                                		//error_log! $create_db_connect->error.
                                	}
                                	
                                	
                                	exit();
                                }
                                

                                Hier hast du dir selbst ein Bein gestellt: Warum kopierst du die Eingabedaten $_SESSION['user_name'] und $_POST['chat'] erst in andere Variablen um und maskierst sie dabei korrekt, benutzt aber im SQL-Statement doch wieder die unmaskierten Originaldaten? Ich gehe mal davon aus, dass in diesem Beispiel eigentlich $writer und $chat in der sprintf-Funktion stehen sollten.
                                Und mit dieser Korrektur gilt: Solange diese Anweisungen als zusammenhängender Block (z.B. in eine Funktion gekapselt) stehen, ist das völlig in Ordnung. Dann ist ja die kontextspezifische Maskierung ungefähr da, wo sie hingehört. Nämlich unmittelbar vor der Übergabe der Daten an die DB.

                                Und in der $_POST['chat'] steht meinetwegen <script>böser.pfad</script>, was kommt in der Datenbank an?

                                Genau das, was geliefert wurde: "<script>böser.pfad</script>"
                                Bis hierher kein Problem.

                                Und wieso entschärft:

                                 $output = "";
                                require_once('db_connect_function.php');
                                
                                $get_messages = "Select * FROM (Select message_writer, message, message_date FROM chat ORDER BY message_date DESC Limit 50 ) chat ORDER BY message_date ASC";
                                
                                if ($result = $db->query($get_messages)):
                                while ($row = $result->fetch_assoc()): 
                                ?>
                                    <article>
                                      <footer>
                                        <time datetime="<?php echo date('c', $row['message_date']); ?>"><?php echo date('H:i:s', $row['message_date']); ?></time>
                                        <span class="author"><?php echo htmlspecialchars($row['message_writer']); ?></span>
                                      </footer>
                                      <p class="message"><?php echo htmlspecialchars($row['message']); ?></p>
                                    </article>
                                <?php
                                endwhile;
                                else:
                                	//error_log! $create_db_connect->error.
                                endif;
                                

                                das nicht die Ausgabe?

                                Tut es doch. Durch die Verwendung von htmlspecialchars() werden die HTML-Sonderzeichen in &lt; und &gt; umgewandelt, so dass in der Browser-Ausgabe wieder "<script>böser.pfad</script>" steht. Als reiner Text, der keinen Schaden anrichtet.

                                Ciao,
                                 Martin

                                --
                                Logik ist die Theorie, Chaos die Praxis.
                                1. Hey,

                                  Das verstehe ich wohl aber ich will ja verhindern das ein < oder ähnliches in die Datenbank kommt.

                                  und genau das ist der falsche Ansatz. Warum sollte man bestimmte Zeichen ausschließen, wenn man sie problemlos verwenden kann, solange man entsprechende Regeln einhält?

                                  Stimmt. Vielleicht gehe ich einfach nur nicht generell genug an die Sache ran, sondern weiss wo ich was benötige oder eben nicht erwarte.

                                  Warum sollte man Markup in einer DB speichern?

                                  Warum nicht? - Okay, meist ist es sinnvoller, Informationen formatneutral zu speichern, also am besten als Plaintext. Aber es muss ja nicht unbedingt Markup sein. Wie dedlfix gezeigt hat, genügt ja schon ein '<', das als mathematisches Zeichen gemeint ist. Und dieses Zeichen kann gefahrlos in die DB geschrieben werden. Erst beim Auslesen, wenn der Text in HTML eingefügt werden soll, muss dieses Zeichen maskiert werden.

                                  Verstanden, Danke!

                                  Und weil jeder individuelle Kontext (HTML, Javascript, SQL, CSS, ...) seine eigenen Sonderregeln und Sonderzeichen hat, muss man die Information immer dem Zielkontext entsprechend aufbereiten. Teilweise hat PHP fertige Funktionen dafür, die man an der richtigen Stelle einfach benutzen kann.

                                  Natürlich gehe ich von meinem einfachen Fall aus und es ist interessant das einem noch viel mehr Möglichkeiten zu Verfügung stehen bei denen man dann auch einiges beachten muss. Nur ich sehe im Moment nicht die Notwendigkeit mir alles aneignen zu müssen was möglich und erst damit nötig ist.

                                  Das halte ich für eine ungünstige Denkweise. Wenn du in deinem überschaubaren Fall Vereinfachungen machst, ist die Gefahr groß, dass du bei anderen Projekten aus Gewohnheit genauso verfährst. Warum sollte man es sich also nicht gleich "richtig" angewöhnen?

                                  Naja andere Projekte werden es wohl nie werden dafür studiere ich das falsche.

                                  Und es wäre hilfreich wenn mal ein Beispiel kommt was ich auch versteh

                                  Wenn du etwas nicht verstehst, frag bitte gezielt nach. Kein Problem. Ich versteh nämlich nicht, was für ein Beispiel du eigentlich noch brauchst.

                                  Ich meine nur für welchen Fall ich was machen muss. Aber viele sehe ich eben jetzt nicht das ich sie mal brauchen könnte, daher würde ich wenn so vorgehen, dass ich mir den speziellen Fall dann anschaue wenn ich ihn brauche.

                                  if(isset($_POST['chat']) && !empty($_POST['chat']))
                                  {
                                  	$writer = mysqli_real_escape_string($_SESSION['user_name']);
                                  	$chat = mysqli_real_escape_string($_POST['chat']);
                                  	
                                  	$insert_message = sprintf(
                                  	'INSERT INTO chat ('
                                      . 'message_writer, message, message_date'
                                      . ') VALUES ('
                                      . '\'%1$s\', \'%2$s\', \'%3$s\''
                                      . ')',
                                      $_SESSION['user_name'],
                                      $_POST['chat'],
                                      time());
                                  	if($db -> query($insert_message) === TRUE)
                                  	{
                                  		$db -> commit();
                                  	}
                                  	else
                                  	{
                                  		//error_log! $create_db_connect->error.
                                  	}
                                  	
                                  	
                                  	exit();
                                  }
                                  

                                  Hier hast du dir selbst ein Bein gestellt: Warum kopierst du die Eingabedaten $_SESSION['user_name'] und $_POST['chat'] erst in andere Variablen um und maskierst sie dabei korrekt, benutzt aber im SQL-Statement doch wieder die unmaskierten Originaldaten? Ich gehe mal davon aus, dass in diesem Beispiel eigentlich $writer und $chat in der sprintf-Funktion stehen sollten.
                                  Und mit dieser Korrektur gilt: Solange diese Anweisungen als zusammenhängender Block (z.B. in eine Funktion gekapselt) stehen, ist das völlig in Ordnung. Dann ist ja die kontextspezifische Maskierung ungefähr da, wo sie hingehört. Nämlich unmittelbar vor der Übergabe der Daten an die DB.

                                  Ja ist beim kopieren schief gegangen, sry. Danke für den Hinweis. Ich denke mir eben nur, dass das nichts anderes ist als das, was ich vorher schon gemacht hab:

                                  if($_POST)
                                  {
                                  	foreach($_POST as $key=>$value)
                                  	{
                                  		$_POST[$key]= mysqli_real_escape_string($value);
                                  				
                                  		if (stripos($_POST[$key], "<script") !== false)	//Check more?
                                  		{
                                  			unset $_POST[$key];
                                  			//Warn or delete User!
                                  		}
                                  	}
                                  }
                                  

                                  Wie auch immer lasse ich das sein und mache es in jedem fall einzeln.

                                  Und in der $_POST['chat'] steht meinetwegen <script>böser.pfad</script>, was kommt in der Datenbank an?

                                  Genau das, was geliefert wurde: "<script>böser.pfad</script>"
                                  Bis hierher kein Problem.

                                  Ja stimmt.

                                  Danke für die Erklärungen und die Mühe.

                                  Gruß Jo

                                  1. Hallo,

                                    Ich denke mir eben nur, dass das nichts anderes ist als das, was ich vorher schon gemacht hab:

                                    if($_POST)
                                    {
                                    	foreach($_POST as $key=>$value)
                                    	{
                                    		$_POST[$key]= mysqli_real_escape_string($value);
                                    				
                                    		if (stripos($_POST[$key], "<script") !== false)	//Check more?
                                    		{
                                    			unset $_POST[$key];
                                    			//Warn or delete User!
                                    		}
                                    	}
                                    }
                                    

                                    doch, das ist etwas ganz anderes. Erstens wendest du hier schon mysqli_real_escape_string() an, obwohl von einer Übergabe der Daten an die DB weit und breit noch nichts zu sehen ist (auch wenn die vielleicht später tatsächlich erfolgt), und zweitens gilt es als sehr schlechter Stil, veränderte Daten in $_POST zurückzuschreiben, wo man eigentlich unverfälschte Eingabedaten erwartet.

                                    Ciao,
                                     Martin

                                    --
                                    Logik ist die Theorie, Chaos die Praxis.
                              2. Tach!

                                Und du meinst nun, weil sie aus der DB kommen, sind die Daten "sicher"?

                                Naja wenn sie maskiert/codiert eingefügt wurden?

                                Du hast es anscheinend immer noch nicht verstanden. Maskiert/codiert wofür? Es gibt keine "Mach-alles-Böse-raus-Maskierung". Für SQL müssen vor allem Anführungszeichen umgeschrieben werden, aber < und > sind da harmlos und bleiben wie sie sind. Für HTML müssen diese beiden aber umgeschrieben werden und Anführungszeichen müssen nicht mit Backslash ergänzt sondern als &quot; geschrieben werden (nicht in jedem Fall, aber in Attributen).

                                Das verstehe ich wohl aber ich will ja verhindern das ein < oder ähnliches in die Datenbank kommt.

                                Warum willst du das verhindern? Was hat das Zeichen denn verbrochen? Man kann auch mit allen anderen harmlos scheinenden Zeichen Unsinn anstellen, indem Nutzer zum Beispiel Texte verfassen, die man als Betreiber nicht haben möchte (Spam, etc.).

                                Warum sollte man Markup in einer DB speichern?

                                Das kommt doch auf den Anwendungsfall an. Manchmal will man das, manchmal nicht. Hier im Forum ist es Sinn und Zweck, dass Anweder HTML eingeben, das auch in der Datenbank zu liegen kommt. Nur muss es beim Ausgaben an den Browser so maskiert sein, dass der das nicht als HTML interpretiert, sondern als Zeichen, die anzuzeigen sind.

                                Natürlich gehe ich von meinem einfachen Fall aus und es ist interessant das einem noch viel mehr Möglichkeiten zu Verfügung stehen bei denen man dann auch einiges beachten muss. Nur ich sehe im Moment nicht die Notwendigkeit mir alles aneignen zu müssen was möglich und erst damit nötig ist.

                                Wichtig ist vor allem, das Prinzip zu verstehen. Alle Einzelheiten, besonders die in der Fortsetzung muss man sich nicht merken, das kann man auch erst bei Bedarf nachschlagen. Aber man muss erkennen, wann der Bedarf da ist. Und deshalb ist wenigstens eine allgemeine Sensibilisierung für das Thema wichtig.

                                Also Wenn zum Beispiel:

                                if(isset($_POST['chat']) && !empty($_POST['chat']))
                                {
                                	$writer = mysqli_real_escape_string($_SESSION['user_name']);
                                	$chat = mysqli_real_escape_string($_POST['chat']);
                                	
                                	$insert_message = sprintf(
                                	'INSERT INTO chat ('
                                    . 'message_writer, message, message_date'
                                    . ') VALUES ('
                                    . '\'%1$s\', \'%2$s\', \'%3$s\''
                                    . ')',
                                    $_SESSION['user_name'],
                                    $_POST['chat'],
                                    time());
                                	if($db -> query($insert_message) === TRUE)
                                	{
                                		$db -> commit();
                                	}
                                	else
                                	{
                                		//error_log! $create_db_connect->error.
                                	}
                                	
                                	
                                	exit();
                                }
                                

                                Und in der $_POST['chat'] steht meinetwegen <script>böser.pfad</script>, was kommt in der Datenbank an?

                                In der Datenbank kommt <script>böser.pfad</script> an. In dem Text kommt kein Zeichen vor, das im SQL-Statement eine Sonderbedeutung hat.

                                Aber anscheinend ist dir nicht einmal aufgefallen, dass du zwar schön maskiert hast, aber die Ergebnisse in Variablen ablegst, die du dann gar nicht verwendest. Also genauer gesagt: du hast gar nichts maskiert und eine potentielle SQL-Injection-Lücke. Mit dem Prinzip Maskieren beim Übergang in den anderen Kontext wäre das nicht passiert. Du hast da grad selbst ein schönes Beispiel geliefert, warum man nicht schon vorher, sondern genau zum richtigen Zeitpunkt die Maskierung vornehmen sollte.

                                $insert_message = sprintf(
                                    "INSERT INTO chat ("
                                    . "message_writer, message, message_date"
                                    . ") VALUES ("
                                    . "'%s', '%s', %s"
                                    . ")",
                                    mysqli_real_escape_string($_SESSION['user_name']),
                                    mysqli_real_escape_string($_POST['chat']),
                                    time());
                                

                                time() liefert übrigens ausnahmslos einen Zahlenwert. Der braucht nicht maskiert zu werden und der braucht auch keine Anführungszeichen im Statement. Außerdem habe ich die Positionsangaben in den Platzhaltern weggelassen (nur %s statt %1$s), weil sie in diesem Fall keinen Nutzen bringen. Die Reihenfolge der Parameter ist immer exakt gleich und ändert sich nicht, wie beispielsweise bei Übersetzungen in andere Spachen mit anderen Grammatiken und Reihenfolgen im Satz.

                                Nochmal zum Inhalt von $_POST['chat']. Um das SQL unbeabsichtigt umzugestalten, musst du einen Text mit einfachem Anführungszeichen drin übergeben. Ohne Escaping würde an der Stelle der Wert zu Ende sein und alles weitere würde als Code angesehen werden. Für das SQL müssen lediglich diese Zeichen berücksichtigt werden und nicht irgendwelche mit besonderer Bedeutung im HTML-Kontext. Die Datenbank hat keine Ahnung, in welchem Kontext später mal ihr Inhalt landen soll und deshalb kann sie dafür auch keine Entschärfungen vornehmen.

                                Und wieso entschärft:

                                ?>
                                    <time datetime="<?php echo date('c', $row['message_date']); ?>"><?php echo date('H:i:s', $row['message_date']); ?></time>
                                    <span class="author"><?php echo htmlspecialchars($row['message_writer']); ?></span>
                                  </footer>
                                  <p class="message"><?php echo htmlspecialchars($row['message']); ?></p>
                                

                                das nicht die Ausgabe?

                                Doch, das "entschärft" die Ausgabe. Hier ist es genauso gemacht, wie es sein sollte: beim Übergang in den HTML-Kontext, nicht eher und auch nicht wirkungslos, weil im nicht vorhandenen "eher" nun kein Fehler mehr stecken kann.

                                Mit deinem Beispiel von vorhin <script>böser.pfad</script> würde das genauso auf dem Bildschirm zu stehen kommen und nicht vom Browser als Code interpretiert werden.

                                Dass diese Ausgabe trotzdem unerwünscht ist, ist nicht das Problem fehlender Maskierungen, sondern nur eins, das mit Moderation gelöst werden muss. Diese und andere Inhalte unangenehmer Zeitgenossen musst du händisch entfernen. Technische Lösungen können in Einzelfällen helfen, aber dann kommt die nächste Spamwelle mit anderen Inhalten und umgeht deine Maßnahmen wieder.

                                Ich glaube mehr will ich überhaupt nicht. Also mir würde kein Beispiel einfallen wo ich etwas anderes machen möchte. Bzw. doch, eigentlich schon, vorher würde gern noch prüfen ob etwas derartiges in dem Formularfeld steht und dann die weiterleitung direkt unterbinden.

                                Du kannst sicher eine Regel definieren, mit der "derartiges" erkannt werden kann. Aber was ist mit "andersartigem"?

                                Oder zumindest wenn nicht das drin steht was ich erwarte dann eben die weiterleitung unterbinden. Sprich, wenn ich in dem Formularfeld eine Zahl erwarte, dann hat das gefälligst auch eine zahl zu sein und kein String. Aber das ist Javascript, dass hab ich zwar schon irgendwo gefunden, aber mich noch nicht mit beschäftigt.

                                Nicht unbedingt. HTML5 und moderne Browser kennen auch <input type="number">. Aber nur weil du sowas in dein HTML einbaust, heißt das noch lange nicht, dass man nur noch moderne Browser einsetzen kann und die das für dich verhindern. Oder wenn es denn eine Javascript-Lösung sein soll, dann können auch nur Browser mit eingeschaltetem Javascript Fehleingaben verhindern. Spam-Bots, die ihre HTML-Requests zu Fuß zusammenbauen und abschicken, interessieren sich nicht dafür, dass du sie gebeten hast, nur Zahlen zu liefern. Die schicken dir trotzdem ihren Müll zu. Den kannst du nur serverseitig erkennen und aussortieren. Bei Zahlen oder Werten aus einer vorher definierten Liste geht das noch einfach, bei Freitext wird es herausfordernder bis unmöglich, alles Ungewünschte zu erkennen.

                                dedlfix.

                                1. Hi,

                                  Aber anscheinend ist dir nicht einmal aufgefallen, dass du zwar schön maskiert hast, aber die Ergebnisse in Variablen ablegst, die du dann gar nicht verwendest.

                                  doch, nachdem ich ihn darauf hingewiesen habe, ist es ihm aufgefallen.
                                  Ich unterstelle mal einen C&P Error.

                                  ?>
                                      <time datetime="<?php echo date('c', $row['message_date']); ?>"><?php echo date('H:i:s', $row['message_date']); ?></time>
                                      <span class="author"><?php echo htmlspecialchars($row['message_writer']); ?></span>
                                    </footer>
                                    <p class="message"><?php echo htmlspecialchars($row['message']); ?></p>
                                  

                                  Doch, das "entschärft" die Ausgabe.

                                  Habe ich auch schon bestätigt.

                                  So long,
                                   Martin

                                  --
                                  Logik ist die Theorie, Chaos die Praxis.
                              3. @@j4nk3y

                                Das verstehe ich wohl aber ich will ja verhindern das ein < oder ähnliches in die Datenbank kommt.

                                Nein. Wenn du <=8 hast, dann soll genau das in die Datenbank geschrieben werden, und nicht &lt;=8.

                                Zu dem Zeitpunkt steht gar nicht fest, was du später mit den Daten anfangen willst; es sind ja auch andere Ausgaben als HTML denkbar.

                                Und selbst wenn das gegenwärtig(!) noch nicht geplant sein sollte, die Datenbank hat die spätere Verwendung der Daten nicht zu interessieren.

                                LLAP 🖖

                                --
                                “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
                                Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
                                1. Moin,

                                  Das verstehe ich wohl aber ich will ja verhindern das ein < oder ähnliches in die Datenbank kommt.

                                  Nein. Wenn du <=8 hast, dann soll genau das in die Datenbank geschrieben werden, und nicht &lt;=8.

                                  Zu dem Zeitpunkt steht gar nicht fest, was du später mit den Daten anfangen willst; es sind ja auch andere Ausgaben als HTML denkbar.

                                  Und selbst wenn das gegenwärtig(!) noch nicht geplant sein sollte, die Datenbank hat die spätere Verwendung der Daten nicht zu interessieren.

                                  Stimmt, da hast du Recht, Danke!

                                  Gruß Jo

        2. Hi,

          sprintf(
              'Wir haben %1$ %1$ %1$ haben %1$ %1$ %1$ haben %1$ %1$ %1$ haben %2$!',
              'Hunger',
              'Durst'
          );
          

          wieviel Bier muss man intus haben, um sich so ein dämliches Beispiel auszudenken?
          Okay, immerhin gibt es die Möglichkeiten recht deutlich wieder.

          So long,
           Martin

          --
          Logik ist die Theorie, Chaos die Praxis.
        3. @@Felix Riesterer

          wenn Du bei PHP.net nachgelesen hast, das die Funktion sprintf Ersetzungen in Strings vornehmen kann, dann hast Du sicher gesehen, dass es nicht nur das s ist, sondern die Zeichenfolge %s. Man kann die Platzhalter mit Nummern versehen, um einen Teilstring, der öfter eingesetzt werden soll, nicht öfter in der Parameterliste notieren zu müssen:

          Man sollte die Platzhalter auch mit Nummern versehen, um Lokalisierung zu ermöglichen. Siehe Internationalization issues unter Variables that cannot be reordered.

          sprintf(
              'Wir haben %1$ %1$ %1$ haben %1$ %1$ %1$ haben %1$ %1$ %1$ haben %2$!',
              'Hunger',
              'Durst'
          );
          

          Nettes Beispiel; leider falsch. Womit nicht die fehlenden Kommas, sondern die fehlenden s gemeint sind:

          sprintf(
              'Wir haben %1$s %1$s %1$s haben %1$s %1$s %1$s haben %1$s %1$s %1$s haben %2$s!',
              'Hunger',
              'Durst'
          );
          

          LLAP 🖖

          --
          “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
          Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
          1. Lieber Gunnar,

            Nettes Beispiel; leider falsch. Womit nicht die fehlenden Kommas, sondern die fehlenden s gemeint sind:

            sprintf(
                'Wir haben %1$s %1$s %1$s haben %1$s %1$s %1$s haben %1$s %1$s %1$s haben %2$s!',
                'Hunger',
                'Durst'
            );
            

            danke für die Korrektur. Habe ich doch tatsächlich die s vergessen...

            Liebe Grüße,

            Felix Riesterer.

            1. Hallo,

              Nettes Beispiel; leider falsch. Womit nicht die fehlenden Kommas, sondern die fehlenden s gemeint sind:

              sprintf(
                  'Wir haben %1$s %1$s %1$s haben %1$s %1$s %1$s haben %1$s %1$s %1$s haben %2$s!',
                  'Hunger',
                  'Durst'
              );
              

              danke für die Korrektur.

              @Matthias Apsel, kann das im Zitatvorschlag bitte auch korrigiert werden?

              Gruß
              Kalk

              1. Hallo Tabellenkalk,

                @Matthias Apsel, kann das im Zitatvorschlag bitte auch korrigiert werden?

                done.

                Bis demnächst
                Matthias

                --
                Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
    4. Wenn Dir das zu doof ist, dann nutze PDO. Dort kannst Du das so notieren:

      $statement = $myPDO->prepare(
          'INSERT INTO chat ('
          . 'message_writer, message, message_date'
          . ') VALUES ('
          . ':message_writer, :message, :message_date'
          . ');'
      );
      
      $statement->execute(array(
          ':message_writer' => $_SESSION['user_name'],
          ':message' => $_POST['chat'],
          ':message_date' => time()
      ));
      

      Diese PDO-Kiste sorgt dafür, dass die potenziell bösartigen Daten in einer Weise kodiert werden, die Dein Programm nicht kaputt machen.

      mysqli bietet im Übrigen auch Unterstützung für prepared statements. Der Kontextwechsel findet dort allerdings nicht ganz automatisch wie bei PDO statt, man muss bei der Übergabe der Variablen noch zusätzliche Typinformationen mitgeben[1].

      $statement = $mysqli->prepare("INSERT INTO chat(message_writer, message, message_date) VALUES (?,?,?)");
      $statement->bind_param("ssi", $_SESSION["user_name"], $_POST["chat"], time());
      

      1. Warum auch immer. ↩︎

      1. Tach!

        mysqli bietet im Übrigen auch Unterstützung für prepared statements. Der Kontextwechsel findet dort allerdings nicht ganz automatisch wie bei PDO statt,

        Kontextwechsel? Findet da keiner statt. Die Werte werden in Rohform übergeben. Das ist ein ganz normaler Funktionsaufruf mit Parameterübergabe. Kontextwechsel ist, wenn Daten als Literal in anderen Code eingefügt werden müssen.

        man muss bei der Übergabe der Variablen noch zusätzliche Typinformationen mitgeben. Warum auch immer.

        Weil das die darunterliegende in C geschriebene MySQL-API so möchte und PHP einfach nur die Funktionen gewrappt hat. Die Werte werden als Zeiger auf einen untypisierten Buffer übergeben. Und damit die Bind-Funktion weiß, welcher Datentyp da zu erwarten ist, muss man das mit diesen Buchstaben sagen. Für PHP ist das nicht wirklich sinnvoll, denn da gibt es keine untypisierten Datenstrukturen. Der Typ kann aus den Metadaten der Variablen ermittelt werden. Der PDO-Weg ist hier deutlich angenehmer. Vor allem kann man auch seine Werte als Array übergeben und muss nicht einzelne Variablen bereitstellen, damit diese referenziert werden können.

        dedlfix.

        1. Tach!

          mysqli bietet im Übrigen auch Unterstützung für prepared statements. Der Kontextwechsel findet dort allerdings nicht ganz automatisch wie bei PDO statt,

          Kontextwechsel? Findet da keiner statt. Die Werte werden in Rohform übergeben. Das ist ein ganz normaler Funktionsaufruf mit Parameterübergabe. Kontextwechsel ist, wenn Daten als Literal in anderen Code eingefügt werden müssen.

          Ich fasse Kontextwechsel allgemeiner auf, nämlich: … wenn Daten in anderen Code eingefügt werden müssen. Wenn Programmdaten in einer MySQL-Datenbank gespeichert werden sollen, müssen die Daten irgendwann ja in gültige MySQL-Querys verpackt werden. Das kann per Hand durch den Programmierer geschehen oder eben automatisch z.B. durch den mysqli-Treiber. Automatischer Kontextwechsel bedeutet für den Programmierer also kein Kontextwechsel, um den er sich kümmern müsste. Man könnte auch von impliziten und expliziten Kontextwechseln sprechen, das macht es noch deutlicher. Ganz grundsätzlich wäre es schön, wenn "implizit" der Normalfall wäre und nicht die Ausnahme.

          man muss bei der Übergabe der Variablen noch zusätzliche Typinformationen mitgeben. Warum auch immer.

          Weil das die darunterliegende in C geschriebene MySQL-API so möchte und PHP einfach nur die Funktionen gewrappt hat. Die Werte werden als Zeiger auf einen untypisierten Buffer übergeben. Und damit die Bind-Funktion weiß, welcher Datentyp da zu erwarten ist, muss man das mit diesen Buchstaben sagen. Für PHP ist das nicht wirklich sinnvoll, denn da gibt es keine untypisierten Datenstrukturen. Der Typ kann aus den Metadaten der Variablen ermittelt werden.

          Ah, ein Artefakt aus C also. Das "s" in PHP steht für sophisticated.

          1. Hallo 1unitedpower,

            Ah, ein Artefakt aus C also. Das "s" in PHP steht für sophisticated.

            rotfl made my day

            LG,
            CK

          2. Tach!

            Ich fasse Kontextwechsel allgemeiner auf, nämlich: … wenn Daten in anderen Code eingefügt werden müssen. Wenn Programmdaten in einer MySQL-Datenbank gespeichert werden sollen, müssen die Daten irgendwann ja in gültige MySQL-Querys verpackt werden.

            Genau das passiert bei (echten) Prepared Statements nicht. Das würde dem Sinn von "prepared" entgegenlaufen, wenn das Statement nicht vorbereitet bleiben könnte, sondern immer wieder nebst den darin einzufügenden Daten neu geparst werden müsste. Nicht-String-Daten wie Zahlen müssten dabei immer erst als Literal ausformuliert werden, nur um dann wieder zurückgeparst zu werden.

            Das kann per Hand durch den Programmierer geschehen oder eben automatisch z.B. durch den mysqli-Treiber. Automatischer Kontextwechsel bedeutet für den Programmierer also kein Kontextwechsel, um den er sich kümmern müsste. Man könnte auch von impliziten und expliziten Kontextwechseln sprechen, das macht es noch deutlicher.

            Das kann man, wenn Prepared Statements nur simuliert werden, weil die Datenbank oder die Abstraktionsschicht sie nicht direkt unterstützt. Die MySQL(i)-API simuliert nicht, inwieweit (/seit wann) PDO das nativ macht, entzieht sich meiner Kenntnis.

            dedlfix.

            1. Ich fasse Kontextwechsel allgemeiner auf, nämlich: … wenn Daten in anderen Code eingefügt werden müssen. Wenn Programmdaten in einer MySQL-Datenbank gespeichert werden sollen, müssen die Daten irgendwann ja in gültige MySQL-Querys verpackt werden.

              Genau das passiert bei (echten) Prepared Statements nicht. Das würde dem Sinn von "prepared" entgegenlaufen, wenn das Statement nicht vorbereitet bleiben könnte, sondern immer wieder nebst den darin einzufügenden Daten neu geparst werden müsste. Nicht-String-Daten wie Zahlen müssten dabei immer erst als Literal ausformuliert werden, nur um dann wieder zurückgeparst zu werden.

              Wenn du mit "echten" Prepared Statements solche meinst, die über das Binärprotokoll abgewickelt werden, ist es das selbe nur in grün. Auch beim Binärprotokoll muss dafür gesorgt, dass Nutzdaten nicht irrtümlich als Steuerdaten fehlinterpretiert werden. Für die Performance wird man aber wohl nicht auf Maskierung, sondern auf Längenangaben gesetzt haben. Für native Prepared Statements der menschenlesbaren SQL gilt was ich in meiner letzten Antwort geschrieben habe.

              1. Tach!

                Wenn du mit "echten" Prepared Statements solche meinst, die über das Binärprotokoll abgewickelt werden,

                Ich meine damit Prepared Statements im Sinne des Erfinders und keine Emulation in einer Abstraktionsschicht, bei der im Hintergund doch wieder ein SQL-Statement daraus gebastelt wird.

                ist es das selbe nur in grün. Auch beim Binärprotokoll muss dafür gesorgt, dass Nutzdaten nicht irrtümlich als Steuerdaten fehlinterpretiert werden. Für die Performance wird man aber wohl nicht auf Maskierung, sondern auf Längenangaben gesetzt haben.

                Die Fehlinterpretation wird ausgeschlossen, wenn ein eindeutiges Protokoll verwendet wird. Die Längenangabe hat eine feststehende Länge, zum Beispiel 4 oder 8 Bytes. Diese Länge ist bekannt und muss nicht in Start- und Stopp-Zeichen/-Bytes eingerahmt werden. Danach folgen die Nutzdaten und die sind exakt die angegebene Länge an Bytes lang. Auch diese werden nicht in Start- und Stopp-Zeichen/-Bytes eingerahmt. Es besteht damit keine Notwendigkeit, diese nicht vorhandenen Start- und Stopp-Zeichen/-Bytes innerhalb der Nutzdaten zu kennzeichen/maskieren. Neben solchen variabel langen Daten (String, BLOB), die eine Längenangabe benötigen, gibt es auch noch solche, die eine feststehende Byteanzahl haben, wie alle Sorten von Integer und Fließkommabinärformate.

                Im Gegensatz dazu arbeiten serialisierende Formate wie JSON. Die haben keine Längenangabe, sondern rahmen die Nutzdaten in Begrenzungszeichen ein, und dann braucht man Makierungen für diese Zeichen mit Sonderbedeutung. Es besteht aber keine Notwendigkeit, solche Serialisierungen zu verwenden, wenn der Übertragungsweg frei von menschlichem Eingriff ist oder keine unbekannten Systeme beteiligt sein können, die eventuell andere Binärformate für ihre Daten verwenden (also beispielsweise nicht die gängigen wie Zweierkomplement oder IEEE 754).

                Für native Prepared Statements der menschenlesbaren SQL gilt was ich in meiner letzten Antwort geschrieben habe.

                Was meinst du mit "native Prepared Statements der menschenlesbaren SQL"? Entweder sind Prepared Statements nativ/direkt/echt von der Datenbank, dem Treiber und der Abstraktionsschicht unterstützt oder sie werden emuliert. Deine Begriffswahl klingt für mich nach einem Widerspruch in sich.

                dedlfix.

                1. Hallo dedlfix,

                  Für native Prepared Statements der menschenlesbaren SQL gilt was ich in meiner letzten Antwort geschrieben habe.

                  Was meinst du mit "native Prepared Statements der menschenlesbaren SQL"? Entweder sind Prepared Statements nativ/direkt/echt von der Datenbank, dem Treiber und der Abstraktionsschicht unterstützt oder sie werden emuliert. Deine Begriffswahl klingt für mich nach einem Widerspruch in sich.

                  Sie ist vor allem auch falsch. Denn auch „native Prepared Statements“ sind menschenlesbares SQL.

                  LG,
                  CK

                  1. Tach!

                    Sie ist vor allem auch falsch. Denn auch „native Prepared Statements“ sind menschenlesbares SQL.

                    Sagen wir es mal so: Der eine Teil von (echten/nativen) Prepared Statements ist das menschenlesbare SQL, das mit den Platzhaltern drin. Das wird im Prepare-Schritt zum DBMS übertragen. Der andere Teil ist die Übertragung der Werte, und der ist nicht mehr auf Menschenlesbarkeit ausgelegt. Mit dem Binding werden die Werte an die API übergeben und beim Execute findet die Übertragung an das DBMS statt. Binding und Execute können beliebig oft wiederholt werden. Emulierte Prepared Statements senden nur einmal etwas an das DBMS, das SQL-Statement mit eingebauten Werten. Auch hier wird emuliert, dass man Binden und Execute mehrfach aufrufen kann, aber dabei wird im Hintergrund jedes Mal ein neues vollständiges SQL-Stetement erzeugt und zum DBMS gesendet. Aus der Sicht des DBMS ist das also kein Prepared Statement mehr, sondern herkömmliche Einzelanfragen.

                    dedlfix.

                  2. Für native Prepared Statements der menschenlesbaren SQL gilt was ich in meiner letzten Antwort geschrieben habe.

                    Was meinst du mit "native Prepared Statements der menschenlesbaren SQL"? Entweder sind Prepared Statements nativ/direkt/echt von der Datenbank, dem Treiber und der Abstraktionsschicht unterstützt oder sie werden emuliert. Deine Begriffswahl klingt für mich nach einem Widerspruch in sich.

                    Sie ist vor allem auch falsch. Denn auch „native Prepared Statements“ sind menschenlesbares SQL.

                    MySQL hat zwei native Interfaces um mit Prepared Statements zu arbeiten. Es gibt eine Schnittstelle aufbauend auf dem Binärprotokoll und eine menschenlesbare Schnittstelle in MySQL-Syntax. Beide Varianten müssen gewährleisten, dass Nutzdaten nicht versehentlich als Steuerdaten interpretiert werden. Im einen Fall geschieht das über eine zusätzliche Längenangabe der Nutzdaten, im anderen Fall über Maskierung der Nutzdaten. Selbes Problem - unterschiedliche Lösungen.

                    Unter "Emulation" verstehe ich nach jetzigem Kenntnisstand noch etwas anderes, nämlich wenn eine Programm-API intern eine eigene Verwaltung von Prepared-Statements nutzt, die auf keine der beiden nativen Interfaces beruht. Bei einer solchen Emulation müsste bei einem Commit dann irgendwie eine äquivalente Sequenz von Datenbank-Operationen erzeugt werden ohne die nativen Möglichkeiten zu nutzen.

                    1. Hallo 1unitedpower,

                      MySQL hat zwei native Interfaces um mit Prepared Statements zu arbeiten. Es gibt eine Schnittstelle aufbauend auf dem Binärprotokoll und eine menschenlesbare Schnittstelle in MySQL-Syntax.

                      Ist mir bewusst. Das Protokoll, also die Transport-Ebene, ist aber nicht relevant für die Lesbarkeit des SQL, das ich an den Server schicke ;)

                      Unter "Emulation" verstehe ich nach jetzigem Kenntnisstand noch etwas anderes, nämlich wenn eine Programm-API intern eine eigene Verwaltung von Prepared-Statements nutzt, die auf keine der beiden nativen Interfaces beruht.

                      Ja, wurde für MySQL-Versionen, die noch keine prepared statements unterstützten, entwickelt.

                      LG,
                      CK

                      1. MySQL hat zwei native Interfaces um mit Prepared Statements zu arbeiten. Es gibt eine Schnittstelle aufbauend auf dem Binärprotokoll und eine menschenlesbare Schnittstelle in MySQL-Syntax.

                        Ist mir bewusst. Das Protokoll, also die Transport-Ebene, ist aber nicht relevant für die Lesbarkeit des SQL, das ich an den Server schicke ;)

                        Das Protokoll ist nicht nur für den Transport da, es bietet auch lowlevel-Funktionalität, die du auf der SQL-Ebene nicht ansprechen kannst. Ich zitiere aus der oben genannten Quelle:

                        An alternative SQL interface to prepared statements is available. This interface is not as efficient as using the binary protocol through a prepared statement API, but requires no programming because it is available directly at the SQL level

                    2. Tach!

                      MySQL hat zwei native Interfaces um mit Prepared Statements zu arbeiten. Es gibt eine Schnittstelle aufbauend auf dem Binärprotokoll und eine menschenlesbare Schnittstelle in MySQL-Syntax.

                      Ach, diese (verlinkte) meinst du. Die ist dafür da, den Vorteil des Preparieren und nicht immer wieder neu parsen Müssens in gescriptetem SQL zu haben, also in Stored Programs (Procedures und Functions). Die hatte ich jetzt gar nicht auf dem Radar, weil sie noch seltener als Stored Programs selbst Verwendung findet (Seltenheit bezogen auf die gefühlte Verwendung der MySQL-Features im typischen Webumfeld).

                      Beide Varianten müssen gewährleisten, dass Nutzdaten nicht versehentlich als Steuerdaten interpretiert werden.

                      Mir scheint, dass du dich hier irrst. Bei der verlinkten Variante werden beim Execute Variablennamen angegeben. Wie die Werte in die Variablen kommen ist nicht das Problem der Prepared Statements. Dem Execute können nur Variablen und keine Literale übergeben werden. Und selbst wenn, wäre das Maskieren im Literal ebenfalls kein Problem des Prepared Statements an sich, ebensowenig wie wenn für das Variablenbefüllen Literale notwendig sind. Die eigentlichen Werte in den Variablen müssen im Rohformat vorliegen. Ich sehe da weder ex- noch implizites Maskieren.

                      Unter "Emulation" verstehe ich nach jetzigem Kenntnisstand noch etwas anderes, [...]

                      In dem Punkt sind wir uns einig.

                      dedlfix.

                      1. Beide Varianten müssen gewährleisten, dass Nutzdaten nicht versehentlich als Steuerdaten interpretiert werden.

                        Mir scheint, dass du dich hier irrst. Bei der verlinkten Variante werden beim Execute Variablennamen angegeben. Wie die Werte in die Variablen kommen ist nicht das Problem der Prepared Statements.

                        Sobald die Variablen aber mit Programmdaten gefüllt werden müssen, gibt es einen Schritt da findet ein Kontextwechsel statt.

                        Ich sehe da weder ex- noch implizites Maskieren.

                        Mir scheint es so, als setzt du Kontextwechsel gleich mit der Notwendigkeit Daten maskieren zu müssen. Maskierung ist doch nur eine Möglichkeit einen Kontextwechsel zu behandeln, Längenangaben sind eine weitere.

                        1. Tach!

                          Beide Varianten müssen gewährleisten, dass Nutzdaten nicht versehentlich als Steuerdaten interpretiert werden.

                          Mir scheint, dass du dich hier irrst. Bei der verlinkten Variante werden beim Execute Variablennamen angegeben. Wie die Werte in die Variablen kommen ist nicht das Problem der Prepared Statements.

                          Sobald die Variablen aber mit Programmdaten gefüllt werden müssen, gibt es einen Schritt da findet ein Kontextwechsel statt.

                          Das ist aber nicht Teil des Prepared Statements. Natürlich hat man Kontextwechsel auch an anderen Stellen, wenn man Literale formulieren muss. Das sind aber andere Baustellen, selbst wenn man die Baustellen so aneinandereiht, dass die Variablenzuweisung-mit-Literal-Baustelle sich vor der Prepared-Statement-Baustelle befindet.

                          Ich sehe da weder ex- noch implizites Maskieren.

                          Mir scheint es so, als setzt du Kontextwechsel gleich mit der Notwendigkeit Daten maskieren zu müssen. Maskierung ist doch nur eine Möglichkeit einen Kontextwechsel zu behandeln, Längenangaben sind eine weitere.

                          Ja, das sehe ich hier wohl etwas enger. Bei aneinandergereihten Längenangabe-Nutzdaten-Paaren sehe ich keinen Kontext, in den sie eingefügt werden. Sie bilden quasi selbst den Kontext. Es sind für mich nicht zwei verschiedene Systeme, die gemischt werden, sondern nur eins.

                          Wie auch immer, aus praktischer Sicht spielt es keine Rolle, ob es irgendwo intern in einer Blackbox einen impliziten Kontextwechsel gibt oder nicht. Darauf hat man keinen Einfluss und kann ihn als nicht existent betrachten. Unabhängig davon sehe ich es selbstverständlich als legitim an, zu Studienzwecken die Blackbox zu öffnen. Aber das zieht keine gravierende Verhaltensänderung beim Verwenden nach sich. Besonders bei Blackboxen, deren Inhalt sich ändern kann oder unbekannt ist, darf das Innenleben nicht für die Verwendung relevant sein, da muss die Schnittstellenbeschreibung genügen.

                          dedlfix.

  2. Servus zusammen,

    So kurz einmal die Anregungen umgeschrieben.

    1. Die Eingabe:
    <?php
    session_start();
    require_once('db_connect_function.php');
    
    if(isset($_POST['chat']) && !empty($_POST['chat']))
    {
    	$writer = $_SESSION['user_name'];
    	$chat = $_POST['chat'];
    	$world = $_POST['world'];
    	$language = $_POST['language'];
    	$alliance = $_POST['alliance'];
    	
    	$insert_message = sprintf(
    	'INSERT INTO chat ('
        . 'message_writer, message, message_date'
        . ') VALUES ('
        . '\'%1$s\', \'%2$s\', \'%3$s\''
        . ')',
        $_SESSION['user_name'],
        $_POST['chat'],
        time());
    
    	if($db -> query($insert_message) === TRUE)
    	{
    		$db -> commit();
    	}
    	else
    	{
    		//error_log! $create_db_connect->error.
    	}
    	
    	
    	exit();
    }
    ?>
    

    Wie schon erwähnt verstehe ich \'%1$s\ diese Zeichenkette noch nicht genau. Das das s für den String steht der übergeben wird ist mir schon aufgegangen. Der Rest aber noch nicht.

    1. Die Ausgabe:
    <?php
    $output = "";
    require_once('db_connect_function.php');
    
    $get_messages = "Select * FROM (Select message_writer, message, message_date FROM chat ORDER BY message_date DESC Limit 50 ) chat ORDER BY message_date ASC";
    
    if ($result = $db->query($get_messages)):
    while ($row = $result->fetch_assoc()): 
    ?>
        <article>
          <footer>
            <time datetime="<?php echo date('c', $row['message_date']); ?>"><?php echo date('H:i:s', $row['message_date']); ?></time>
            <span class="author"><?php echo htmlspecialchars($row['message_writer']); ?></span>
          </footer>
          <p class="message"><?php echo htmlspecialchars($row['message']); ?></p>
        </article>
    <?php
    endwhile;
    else:
    //error_log! $create_db_connect->error.
    endif;
    ?>
    

    Warum steht der <footer> oben? Dachte der gehört immer an das Ende eines übergeordneten Elementes. Und braucht das <time> Element das datetime="..."? Erscheint mir etwas unnötig.

    Gruß Jo

    1. @@j4nk3y

      Warum steht der <footer> oben? Dachte der gehört immer an das Ende eines übergeordneten Elementes.

      Nö, footer kann überall stehen, „where flow content is expected.

      footer hat (wie alle HTML-Elemente) nichts damit zu tun, wie und wo sein Inhalt dargestellt wird, sondern was das für Inhalt ist. “A footer typically contains information about its section such as who wrote it, links to related documents, copyright data, and the like.“

      S.a. dieses Beispiel

      Und braucht das <time> Element das datetime="..."? Erscheint mir etwas unnötig.

      Braucht’s in dem Fall nicht. 'H:i:s' liefert ein für datetime value gültiges Format.

      Das datetime-Attribut findet vor allem Verwendung, wenn der Inhalt des time-Elements nicht in einem gültigen maschinenlesbaren Format ist: <time datetime="20:15">Viertel neun</time>.

      Ich hatte ins datetime-Attribut den Zeitpunkt mit Datum reingeschrieben. Wenn du das Datum nicht brauchst, kannst du auch <time><?php echo date('H:i:s', $row['message_date']); ?></time> schreiben.

      LLAP 🖖

      --
      “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
      Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
      1. @@Gunnar

        Warum steht der <footer> oben? Dachte der gehört immer an das Ende eines übergeordneten Elementes.

        Nö, footer kann überall stehen, „where flow content is expected.

        footer hat (wie alle HTML-Elemente) nichts damit zu tun, wie und wo sein Inhalt dargestellt wird, sondern was das für Inhalt ist. “A footer typically contains information about its section such as who wrote it, links to related documents, copyright data, and the like.“

        S.a. dieses Beispiel

        Ja das ist ja richtig, nur sieht es für mein Verständnis im HTML oben komisch aus. Und wo das ganze hinterher Angezeigt wird liegt dann in der Order des Flexbox-Elementes.

        Und braucht das <time> Element das datetime="..."? Erscheint mir etwas unnötig.

        Braucht’s in dem Fall nicht. 'H:i:s' liefert ein für datetime value gültiges Format.

        Das datetime-Attribut findet vor allem Verwendung, wenn der Inhalt des time-Elements nicht in einem gültigen maschinenlesbaren Format ist: <time datetime="20:15">Viertel neun</time>.

        Ich hatte ins datetime-Attribut den Zeitpunkt mit Datum reingeschrieben. Wenn du das Datum nicht brauchst, kannst du auch <time><?php echo date('H:i:s', $row['message_date']); ?></time> schreiben.

        Ja, sah eben nur etwas Unnötig aus. Darum fragte ich. Danke!

        Gruß Jo

        1. @@j4nk3y

          Ja das ist ja richtig, nur sieht es für mein Verständnis im HTML oben komisch aus. Und wo das ganze hinterher Angezeigt wird liegt dann in der Order des Flexbox-Elementes.

          Pass besser dein Verständnis von HTML an und lass die Finger von order; das bringt Accessibility-Probleme mit sich.

          LLAP 🖖

          --
          “You might believe there are benefits for the developer, but first of all, you should put those behind the interest of the user.” —Stefan Tilkov
          Selfcode: sh:) fo:} ch:? rl:) br:> n4:& va:| de:> zu:} fl:{ ss:| ls:# js:|
          1. @@j4nk3y

            Ja das ist ja richtig, nur sieht es für mein Verständnis im HTML oben komisch aus. Und wo das ganze hinterher Angezeigt wird liegt dann in der Order des Flexbox-Elementes.

            Pass besser dein Verständnis von HTML an und lass die Finger von order; das bringt Accessibility-Probleme mit sich.

            Natürlich kann ich ein Element in HTML hinschreiben wo ich Lustig bin, ob oben oder unten oder rechts oder links. Das was ich meine ist einfach nur, dass ich noch keinen Text oder Artikel z.B. in der Zeitung gelesen hab wo die Überschrift unter dem Inhalt steht. Es sieht einfach ungewohnt aus.

            Gruß Jo

            1. Hallo j4nk3y,

              Natürlich kann ich ein Element in HTML hinschreiben wo ich Lustig bin, ob oben oder unten oder rechts oder links.

              Nein, das kannst du nicht. Links und Rechts gibt es im Quelltext nicht ;-)

              Das was ich meine ist einfach nur, dass ich noch keinen Text oder Artikel z.B. in der Zeitung gelesen hab wo die Überschrift unter dem Inhalt steht. Es sieht einfach ungewohnt aus.

              Trenne dich von Vorstellungen der Printmedien, wenn du HTML-Dokumente erstellen möchtest. HTML ist eine Auszeichnungssprache. Die Elementnamen beschreiben den Inhalt, nicht das Aussehen.

              Bis demnächst
              Matthias

              --
              Wenn eine Idee nicht zuerst absurd erscheint, taugt sie nichts. (Albert Einstein)
              1. Moin Matthias

                Natürlich kann ich ein Element in HTML hinschreiben wo ich Lustig bin, ob oben oder unten oder rechts oder links.

                Nein, das kannst du nicht. Links und Rechts gibt es im Quelltext nicht ;-)

                Klar kann ich das. Ichkann doch alles mit nem Tabulator einrücken dann steht es rechts...

                Das was ich meine ist einfach nur, dass ich noch keinen Text oder Artikel z.B. in der Zeitung gelesen hab wo die Überschrift unter dem Inhalt steht. Es sieht einfach ungewohnt aus.

                Trenne dich von Vorstellungen der Printmedien, wenn du HTML-Dokumente erstellen möchtest. HTML ist eine Auszeichnungssprache. Die Elementnamen beschreiben den Inhalt, nicht das Aussehen.

                Das ist mir klar, css macht das aussehen.

                Gruß Jo

  3. Nun gut.

    Also bleibt es nach den neuen Veränderungen in der chat_list.php und der chat_insert.php bei den 2 Fragestellungen:

    Erstens kann ich zurzeit nur aus einer Tabelle die Nachrichten ausgeben bzw. in diese schreiben. Ich möchte aber in mehrere Tabellen schreiben können, jenachdem wohin der User schreiben möchte.

    Zweitens wird die chat_list funktion jede Sekunde ausgeführt, was ja sehr unschön ist und viel zuviel Serverkapazität benötigt, sprich eine Websocket verbindung soll her.

    1. Der Html Teil * geändert:
    <section id="chat_wrapper">
    <!--<form>
    
    <input type="checkbox" name="world" class="checkbox_chat" id="chat_world_list" value="world" />
    <label for="world">World</label>
    
    <input type="checkbox" name="language" class="checkbox_chat" id="chat_language_list" value="<?php echo $_SESSION['language'];?>"/>
    <label for="language">Language</label>
    
    <?php if($page == "lobby"){echo '<input type="checkbox" name="alliance" class="checkbox_chat" id="chat_alliance_list" value="alliance" />
    <label for="alliance">Alliance</label>';} ?>
    
    </form>-->
    
    <div id="chatbox"></div>
    
    <!--<form>
     <select name="destination" size="5">
        <option selected>World</option>
        <option>Language_1</option>
        <option>Language_2</option>
        <option>Alliance</option>
        <option>Private_name_1</option>
        <option>Private_name_2</option>
        <option>Private_name_3</option>
        <option>Private_name_4</option>
      </select>
    -->
    
    <input type="text" name="chat" id="chat_text" size="25" onkeydown = "if (event.keyCode == 13) {document.getElementById('chatbutton').click()}"/>
     
    <button id="chatbutton" onclick="post_chat();" >Send</button>
     
    </form>
     
    <script>
    list_chat();
    </script>
     
    </section>
    

    Hier hab ich nur kurz eine Auswahlliste hinzugefügt, so wie sie aussehen könnte. World ist die standart Tabelle, weiter wären Language_1 , Language_2 , Alliance und Private.

    1. Die js Funktionen:
    
    function list_chat()
    {
    var hr = new XMLHttpRequest();
    	var url = "../functions/php/chat_list.php";
    	
     	hr.onreadystatechange = function()
     	{
     		if (hr.readyState == 4 && hr.status == 200)
     		{
     			document.getElementById("chatbox").innerHTML = hr.responseText;
     			
     			var div = document.getElementById("chatbox");
     			div.scrollTop = div.scrollHeight;
     		}
     	}
     	
     	hr.open("GET", url, true)  // Mehr informationen zu der chat_list senden!...??
     	hr.send();
     	
     	setTimeout(list_chat, 1000);   //Problem! zu wss ändern...??
     }
     
     function post_chat()
     {
     	var hr = new XMLHttpRequest();
     	
     	var url = "../functions/php/chat_insert.php";
     	var chat = document.getElementById("chat_text").value;
     	
     	var text = "chat=" + chat;
     	
     	hr.open("POST", url, true);
     	
     	hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
     	hr.send(text);   // Mehr informationen zu der chat_insert senden!...??
     	
     	document.getElementById("chat_text").value = ""; 
     	
     }
    
    1. Nun zu php *geändert :

    3.1 Die chat_list.php

     $output = "";
    require_once('db_connect_function.php');
    
    $get_messages = "Select * FROM (Select message_writer, message, message_date FROM chat ORDER BY message_date DESC Limit 50 ) chat ORDER BY message_date ASC";
    
    if ($result = $db->query($get_messages)):
    while ($row = $result->fetch_assoc()): 
    ?>
        <article>
          <footer>
            <time datetime="<?php echo date('c', $row['message_date']); ?>"><?php echo date('H:i:s', $row['message_date']); ?></time>
            <span class="author"><?php echo htmlspecialchars($row['message_writer']); ?></span>
          </footer>
          <p class="message"><?php echo htmlspecialchars($row['message']); ?></p>
        </article>
    <?php
    endwhile;
    else:
    	//error_log! $create_db_connect->error.
    endif;
    

    3.2 Die chat_insert.php *geändert

     session_start();
    require_once('db_connect_function.php');
    
    if(isset($_POST['chat']) && !empty($_POST['chat']))
    {
    	$writer = $_SESSION['user_name'];
    	$chat = $_POST['chat'];
    	$world = $_POST['world'];
    	$language = $_POST['language'];
    	$alliance = $_POST['alliance'];
    	
    	$insert_message = sprintf(
    	'INSERT INTO chat ('
        . 'message_writer, message, message_date'
        . ') VALUES ('
        . '\'%1$s\', \'%2$s\', \'%3$s\''
        . ')',
        $_SESSION['user_name'],
        $_POST['chat'],
        time());
    	if($db -> query($insert_message) === TRUE)
    	{
    		$db -> commit();
    	}
    	else
    	{
    		//error_log! $create_db_connect->error.
    	}
    	
    	
    	exit();
    }
    

    Sonniger Gruß Jo

  4. Du machst das viel zu kompliziert. Mach den Chat über Websocket/Broadcast da geht die Post ab und Du hast außerdem den Vorteil, dass nirgendwo Daten gespeichert werden müssen. Und dann kann ein Chatter auch selbst bestimmen, wielange er den Verlauf des Geschnatters im Browser sehen will, nach einen Reload ist alles weg aber die Verbindung ist gleich wieder da. Es sei denn, Du bietest eine Speichern unter.... Funktion an.

    1. Moin pl,

      Du machst das viel zu kompliziert. Mach den Chat über Websocket/Broadcast da geht die Post ab

      Genau das will ich ja machen. Das war die eingehende Fragestellung 2.

      und Du hast außerdem den Vorteil, dass nirgendwo Daten gespeichert werden müssen.

      Ich würd aber gern den Verlauf nachträglich prüfen können in bezug auf mögliche Beleidigungen oder ähnliches was gegen die Netiquette/AGB verstößt.

      Gruß Jo

      1. Tach!

        Du machst das viel zu kompliziert. Mach den Chat über Websocket/Broadcast da geht die Post ab

        Genau das will ich ja machen. Das war die eingehende Fragestellung 2.

        In den anderen Zweigen geht es ja meist um spezielle Randprobleme. Wie weit bist du mit der eigentlichen Aufgabe gekommen? Besteht da noch Klärungsbedarf und wenn ja?

        und Du hast außerdem den Vorteil, dass nirgendwo Daten gespeichert werden müssen.

        Ich würd aber gern den Verlauf nachträglich prüfen können in bezug auf mögliche Beleidigungen oder ähnliches was gegen die Netiquette/AGB verstößt.

        Mit anderen Worten, den Chatverlauf nicht zu speichern, ist gar kein Vorteil bezogen auf die Anforderungen. Auch ist es völlig unabhängig von der verwendeten Übertragungsmethode, ob die Daten gespeichert werden sollen oder nicht. Ich sehe grade nicht, warum Websocket einen Vorteil gegenüber anderen Verfahren bieten soll, was das Speichern oder Nichtspeichern von Daten angeht. Ob die eine oder andere Übertragungsmethode besser oder schlechter für den gegebenen Anwendungsfall ist, kann man herausfinden und das ist auch sinnvoll. Nur das Speichern hat da keine Aktie dran.

        Beispielsweise benötigt Websocket zumindest halbwegs aktuelle Browser (vielleicht weniger relevant) und auch entsprechende Einrichtungen auf dem Webserver (damit steht oder fällt die Verwendbarkeit von Websockets). Ajax-Polling und andere Polling-Verfahren hingegen sind zwar technisch weniger schön, aber sie gehen auch ohne besondere Vorkehrungen mit 08/15-Webservern.

        dedlfix.

        1. Moin!

          In den anderen Zweigen geht es ja meist um spezielle Randprobleme. Wie weit bist du mit der eigentlichen Aufgabe gekommen? Besteht da noch Klärungsbedarf und wenn ja?

          Naja noch garnicht, ging ja bisher nur um den noch nicht vorhandenen Kontextwechsel.

          use Net::WebSocket::Server;
          
              Net::WebSocket::Server->new(
                  listen => 8080,
                  on_connect => sub {
                      my ($serv, $conn) = @_;
                      $conn->on(
                          handshake => sub {
                              my ($conn, $handshake) = @_;
                          },
                          utf8 => sub {
                              my ($conn, $msg) = @_;
                              $_->send_utf8($msg) for $conn->server->connections;
                          },
                          binary => sub {
                              my ($conn, $msg) = @_;
                              $_->send_binary($msg) for $conn->server->connections;
                          },
                      );
                  },
              )->start;
          

          und dazu gehöriges javascript etwa :

          /* Nachricht senden */
          function sendit(){
              var mesg = rltrim(document.getElementById('mesg').value);
              if( ! mesg.length ) {
                  document.getElementById('mesg').value = '';
                  return false;
              }
          
              ws.send(JSON.stringify({mesg: mesg, nickname: '%nickname%'}));
              document.getElementById('mesg').value = '';
              return false;
          }
          
          
          /* Nachricht im Browser anhängen */
          ws.onmessage = function (e) {
              var dataobj = JSON.parse(e.data);
              var outtab = document.getElementById('outtab');
          
              var mesg = dataobj.mesg;
              var row = outtab.insertRow(0);
              var cell = row.insertCell(0);
              $(cell).css('font-family','Courier New, Courier, monospace');
              $(cell).text(mesg);
          
              var nickname = decodeURIComponent(dataobj.nickname);
              row = outtab.insertRow(0);
              $(row).css({'background-color': '#369', 'color': 'white'});
              cell = row.insertCell(0);
              $(cell).css('font-family','Courier New, Courier, monospace');
              $(cell).text(nickname+' schrieb um '+hms());
          };
          
          function hms(){
              var d = new Date();
              return d.getHours()+':'+d.getMinutes()+':'+d.getSeconds();
          }
          

          Laut pl sieht so, oder ähnlich, der Websocket in perl aus. Mit perl hatte ich noch garnichts zu tun, also verstehe ich da eher weniger. Ich habe mir aber schon einige Beispiele mit javascript angeschaut die da etwa so aussehen:

          var connection = new WebSocket('ws://url', ['soap', 'xmpp']);
          
          / When the connection is open, send some data to the server
          connection.onopen = function () {
            // Sending String
          connection.send('your message');
          };
          
          // Log errors
          connection.onerror = function (error) {
            console.log('WebSocket Error ' + error);
          };
          
          // Log messages from the server
          connection.onmessage = function (e) {
            console.log('Server: ' + e.data);
          };
          

          Nur so sehr weit reicht mein javascript Horizont leider auch nicht, dass ich da nach meinen Wünschen munter los manipulieren könnte.

          Zusätzlich schaffe ich es schon in der Ausgangsversion nicht, mehere Tabellen anzusprechen. Sprich der javascript Funktion list_chat() die ganzen Werte aus den Checkboxen mitzugeben und die dann in die chat_list.php zu migrieren. Genauso wie post_chat() einen Wert mitgeben damit chat_insert.php weiss, in welche Tabelle (wie und was) geschreiben werden soll.

          Mit anderen Worten, den Chatverlauf nicht zu speichern, ist gar kein Vorteil bezogen auf die Anforderungen. Auch ist es völlig unabhängig von der verwendeten Übertragungsmethode, ob die Daten gespeichert werden sollen oder nicht. Ich sehe grade nicht, warum Websocket einen Vorteil gegenüber anderen Verfahren bieten soll, was das Speichern oder Nichtspeichern von Daten angeht. Ob die eine oder andere Übertragungsmethode besser oder schlechter für den gegebenen Anwendungsfall ist, kann man herausfinden und das ist auch sinnvoll. Nur das Speichern hat da keine Aktie dran.

          Sicher, dass reine speichern des Chatverlaufs hat performant nichts mit einem Websocket zutun. Es geht ja nur darum die chat_list() nicht jede Sekunde für jeden User der gerade "online" ist auszuführen und immer wieder die gleichen Daten neu aus der Datenbank zu ziehen.

          Gruß Jo

          1. Tach!

            Laut pl sieht so, oder ähnlich, der Websocket in perl aus. Mit perl hatte ich noch garnichts zu tun, also verstehe ich da eher weniger.

            Es gibt auch Websocket-Implementationen für PHP, beispielsweise Ratchet. Was da dafür unbedingt brauchst, ist der Zugriff auf den Server, denn Websocket ist serverseitig nicht einfach nur ein PHP-Script, das über Requests aufgerufen wird. Da muss ständig ein separater Server auf Verbindungsversuche lauschen. Und diesen Server musst du starten können, was nicht damit getan ist, per FTP Dateien ins DocumentRoot des Webservers zu legen.

            Ich habe mir aber schon einige Beispiele mit javascript angeschaut die da etwa so aussehen:

            Das sind grundsätzliche Beispiele, wie man ein paar Bytes Information überträgt. Was du noch brauchst, ist ein Protokoll, das festlegt, welche Nachrichten Client und Server austauschen und wie die zu formatieren sind. Das muss ja nichts großartig komplexes sein, aber ganz ohne Überlegungen wirst du nicht weit kommen. Ok, man kann sich auch bis zum Ziel durchscheitern, aber angenehm ist sowas nicht unbedingt.

            Nur so sehr weit reicht mein javascript Horizont leider auch nicht, dass ich da nach meinen Wünschen munter los manipulieren könnte.

            Der erste Schritt wäre Verständnis aufzubauen, was da in diesen einfachen Einführungsbeispielen passiert.

            Zusätzlich schaffe ich es schon in der Ausgangsversion nicht, mehere Tabellen anzusprechen. Sprich der javascript Funktion list_chat() die ganzen Werte aus den Checkboxen mitzugeben und die dann in die chat_list.php zu migrieren. Genauso wie post_chat() einen Wert mitgeben damit chat_insert.php weiss, in welche Tabelle (wie und was) geschreiben werden soll.

            Brich doch diese Anforderung mal runter auf kleine Teileinheiten. Solche kleinen Einheiten kann man nämlich wesentlich besser separat entwickeln und testen als zu versuchen, in einem großen Topf Spaghetti die Nudeln in eine Ordnung zu bringen. Der erste Schritt ist, die Eingabeelemente so auszulesen, dass die Daten in einer strukturtierten Form vorliegen. Also zum Beispiel ein Objekt erstellen und mit console.log() schauen, ob es gut aussieht. Unabhängig davon kann man auf der Serverseite probieren, Daten in mehrere Tabellen aufzuteilen (wenn das dein Ziel ist). Aber dazu nimmt man erstmal Testdaten unabhängig vom Client und sieht zu, es mit diesen hinzubekommen. Sonst hat man gleichzeitig zwei oder noch mehr Baustellen zu beachten, wenn was nicht funktioniert. Wenn diese Teile einzeln gut arbeiten, kann man sie zusammenbringen.

            Sicher, dass reine speichern des Chatverlaufs hat performant nichts mit einem Websocket zutun. Es geht ja nur darum die chat_list() nicht jede Sekunde für jeden User der gerade "online" ist auszuführen und immer wieder die gleichen Daten neu aus der Datenbank zu ziehen.

            Dann empfielt sich vielleicht ein Zeitstempel und den Client fragen zu lassen: Gib mir mal alle Daten ab $time. Der Websocket hat den Vorteil, dass man solche Polling-Anfragen nicht stellen muss, sondern der Server von sich aus neue Informationen schicken kann. Aber dazu muss man die Voraussetzungen für Websockets haben, womit wir wieder dabei sind, erstmal diese Voraussetzungen abzuklären.

            dedlfix.

            1. Moin,

              Es gibt auch Websocket-Implementationen für PHP, beispielsweise Ratchet.

              Das klingt schonmal sehr interessant, dass hab ich noch garnicht gefunden. Danke!

              Ich habe mir aber schon einige Beispiele mit javascript angeschaut die da etwa so aussehen:

              Das sind grundsätzliche Beispiele, wie man ein paar Bytes Information überträgt.

              Wie grundsätzlich ein Websocket funktioniert ist mir klar. Ich bin nur vollkommen damit überfordert wie es weiter geht.

              Was du noch brauchst, ist ein Protokoll, das festlegt, welche Nachrichten Client und Server austauschen und wie die zu formatieren sind. Das muss ja nichts großartig komplexes sein, aber ganz ohne Überlegungen wirst du nicht weit kommen.

              Das ist mir klar und genau daran scheitere ich, was mich auf die glorreiche Idee gerbracht hat einfach mal die Experten zu fragen.

              Ok, man kann sich auch bis zum Ziel durchscheitern, aber angenehm ist sowas nicht unbedingt

              Ich würde gern am Scheitern scheitern. Darum frage ich euch.

              Wie grundsätzlich ein Websocket funktioniert ist mir klar. Ich bin nur vollkommen damit überfordert wie es weiter geht. Was ich also machen muss damit, dass was vom Client ankommt was ich in php verwerten kann und wie das dann wieder zurück geschickt wird in abhängigkeit davon was angekommen ist.

              Der erste Schritt wäre Verständnis aufzubauen, was da in diesen einfachen Einführungsbeispielen passiert.

              1. Websocket object wird angelegt:
              var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);
              
              1. Wenn die Websocket verbindung aufgebaut "werden kann"/ist (hier bin ich mir etwas unsicher aber sollte, ist sein) dann sende etwas zum Server.
              connection.onopen = function () {
                connection.send('Ping');
              };
              
              1. Falls bei der Verbindung ein Fehler auftritt gib den error an die Consol.log weiter:
              connection.onerror = function (error) {
                console.log('WebSocket Error ' + error);
              };
              
              1. Da müsste doch noch ein .onclose kommen? Obwohl, da sollte/dürfte ja nichts weltbewegendes passieren.
              connection.onclose = function () {
                };
              

              Zusätzlich schaffe ich es schon in der Ausgangsversion nicht, mehere Tabellen anzusprechen. Sprich der javascript Funktion list_chat() die ganzen Werte aus den Checkboxen mitzugeben und die dann in die chat_list.php zu migrieren. Genauso wie post_chat() einen Wert mitgeben damit chat_insert.php weiss, in welche Tabelle (wie und was) geschreiben werden soll.

              Brich doch diese Anforderung mal runter auf kleine Teileinheiten. Solche kleinen Einheiten kann man nämlich wesentlich besser separat entwickeln und testen als zu versuchen, in einem großen Topf Spaghetti die Nudeln in eine Ordnung zu bringen. Der erste Schritt ist, die Eingabeelemente so auszulesen, dass die Daten in einer strukturtierten Form vorliegen.

              Ja, das kriege ich eben nicht hin. Ich schaffe es nicht, mehr Variablen aus dem Formular in die javascript Funktionen und dann weiter zu php zu reichen.

              Sicher, dass reine speichern des Chatverlaufs hat performant nichts mit einem Websocket zutun. Es geht ja nur darum die chat_list() nicht jede Sekunde für jeden User der gerade "online" ist auszuführen und immer wieder die gleichen Daten neu aus der Datenbank zu ziehen.

              Dann empfielt sich vielleicht ein Zeitstempel und den Client fragen zu lassen: Gib mir mal alle Daten ab $time.

              Genau das passiert doch gerade jede Sekunde.

              Der Websocket hat den Vorteil, dass man solche Polling-Anfragen nicht stellen muss, sondern der Server von sich aus neue Informationen schicken kann. Aber dazu muss man die Voraussetzungen für Websockets haben, womit wir wieder dabei sind, erstmal diese Voraussetzungen abzuklären.

              Genau das ist der Ansatzpunkt der Frage, das eben keine Polling-Anfragen Zyklisch passieren.

              Gruß Jo

              1. Ja, das kriege ich eben nicht hin. Ich schaffe es nicht, mehr Variablen aus dem Formular in die javascript Funktionen und dann weiter zu php zu reichen.

                Der Socketserver echo.websocket.org kriegt keine Variablen, sondern nur eine Bytesequenz. Und genau die schickt er wieder zurück. Da ist schonmal gar kein PHP im Spiel, es sei denn, Du baust Dir einen Websocketserver mit PHP.

                Wenn der ein Chatserver sein soll, schickt er jede Sequenz die er von einem beliebigen Client kriegt, als Broadcast zurück an alle Clients.

                JSON ist eine Möglichkeit, aus einer JS-Datenstruktur (Array, Objekt) eine Bytesequenz zu erzeugen. D.h. aus mehreren Variablen (Zeitstempel, Username, Text) machst Du erst ein Objekt, daraus dann den JSON -String und der wird gesendet. Was zurückkommt wird genauso wieder ausgepackt wie es eingepackt wurde.

                Das sind die Basics, die musst Du verstehen und dann kannst Du das auch so zusammenbauen, dass es funktioniert. Meine Demo nutzt o.g. Server. Deswegen ist es eine Demo: Der Server macht keinen Broadcast. Für einen richtigen Chat ist es jedoch ganz genau derselbe Client mit Javascript, der braucht nur einen Server der den Broadcast macht, also, wenn du einen Solchen hast, nur die Zeile var ws = new WebSocket("wss://echo.websocket.org"); ändern.

                --
                Top, die Wette gilt.
                1. Hi pl,

                  Ja, das kriege ich eben nicht hin. Ich schaffe es nicht, mehr Variablen aus dem Formular in die javascript Funktionen und dann weiter zu php zu reichen.

                  Der Socketserver echo.websocket.org kriegt keine Variablen, sondern nur eine Bytesequenz. Und genau die schickt er wieder zurück. Da ist schonmal gar kein PHP im Spiel, es sei denn, Du baust Dir einen Websocketserver mit PHP.

                  Das bezog sich allein auf die Ausgangssituation und noch nicht auf die Websocket Verbindung.

                  Wenn der ein Chatserver sein soll, schickt er jede Sequenz die er von einem beliebigen Client kriegt, als Broadcast zurück an alle Clients.

                  Das ist der Sinn dabei.

                  JSON ist eine Möglichkeit, aus einer JS-Datenstruktur (Array, Objekt) eine Bytesequenz zu erzeugen. D.h. aus mehreren Variablen (Zeitstempel, Username, Text) machst Du erst ein Objekt, daraus dann den JSON -String und der wird gesendet. Was zurückkommt wird genauso wieder ausgepackt wie es eingepackt wurde.

                  Das sind die Basics, die musst Du verstehen und dann kannst Du das auch so zusammenbauen, dass es funktioniert. Meine Demo nutzt o.g. Server. Deswegen ist es eine Demo: Der Server macht keinen Broadcast. Für einen richtigen Chat ist es jedoch ganz genau derselbe Client mit Javascript, der braucht nur einen Server der den Broadcast macht, also, wenn du einen Solchen hast, nur die Zeile var ws = new WebSocket("wss://echo.websocket.org"); ändern.

                  Ja ich versteh das schon aber die Demo macht ja noch nicht das was ich erreichen möchte. Nämlich erstens : Den Chatverlauf in einer DB, in unterschiedlichen Tabellen speichern. Und zweitens : Ein Client kann sich nicht aussuchen von welchen anderen Clients er Nachrichten empfangen will. Bzw. welche bei ihm ankommen. Wenn ich das nach meinen Wünschen modifizieren könnte müsste ich nicht fragen.

                  Gruß Jo

                  1. Nämlich erstens : Den Chatverlauf in einer DB, in unterschiedlichen Tabellen speichern.

                    Der Socketserver muss das unterstützen, d.h. er braucht eine API wo Du die Daten abgreifen kannst. Das DB-Design hingegen und alles jenseits der API musst Du schon selbst machen.

                    Und zweitens : Ein Client kann sich nicht aussuchen von welchen anderen Clients er Nachrichten empfangen will. Bzw. welche bei ihm ankommen. Wenn ich das nach meinen Wünschen modifizieren könnte müsste ich nicht fragen.

                    Auch da musst Du Dich schonmal ein bischen selbst mit dem Thema p2p befassen.

                    mfg

                    1. Tach!

                      Und zweitens : Ein Client kann sich nicht aussuchen von welchen anderen Clients er Nachrichten empfangen will. Bzw. welche bei ihm ankommen. Wenn ich das nach meinen Wünschen modifizieren könnte müsste ich nicht fragen.

                      Auch da musst Du Dich schonmal ein bischen selbst mit dem Thema p2p befassen.

                      Nein, das ist in seinem Fall kontraproduktiv, weil er ja serverseitig den Chatverlauf mitschneiden möchte. Wenn P2P für die Kommunikation untereinander verwendet werden sollte, dann würde man einen zweiten Datenstrom zum Server benötigen, zumindest von einem der beteiligten P2P-Partner, der die Kommunikation zum Speichern abliefert. Da kann man auch gleich über Bande (sprich Server) agieren. Bei einem Chat kommt es auch nicht auf Echtzeitübertragung an, wofür das WebRTC hauptsächlich notwendig ist. Zudem braucht man da anders als bei Websocket noch ein paar zuzsätzliche Kopfstände, um das Problem NAT und Verbindungsaufbau über Firewalls zu lösen.

                      dedlfix.

                      1. Du bist ein klasse Theoretiker. Und schön, dass Du es auch verstanden hast, dass Daten, wenn sie aufgezeichnet werden sollen, über den Server laufen müssen. Und ganz besonders toll ist es, diese ganz persönlich gewonnen Erkenntnisse hier in der Öffentlichkeit kundzutun. Weiter so!

                        Wg

                        1. Hallo pl,

                          Du bist ein klasse Theoretiker.

                          Und auch ein klasse Praktiker. Sowohl, was das Geschäftsgebaren, erkennbar zum Beispiel am geleisteten Support, als auch die abgelieferte Software betrifft.

                          Bis demnächst
                          Matthias

                          --
                          Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
                  2. He Jo,

                    Ja ich versteh das schon aber die Demo macht ja noch nicht das was ich erreichen möchte. Nämlich erstens : Den Chatverlauf in einer DB, in unterschiedlichen Tabellen speichern. Und zweitens : Ein Client kann sich nicht aussuchen von welchen anderen Clients er Nachrichten empfangen will. Bzw. welche bei ihm ankommen. Wenn ich das nach meinen Wünschen modifizieren könnte müsste ich nicht fragen.

                    Bei einem Chat per Websocket läuft alles über den Sever. Dem wird eine eindeutige Kennung mitgegeben, welcher Client sich da verbindet. Dieser Kennung, nennen wir sie Session-ID (SID) ist gleichermaßen ein Nickname zugeordnet.

                    Jede Nachricht schickt die eigene Kennung mit und ggf. eine Kennung desjenigen Clients, für den die Nachricht bestimmt ist. Hier mal einen Auszug vom CODE aufm Server:

                                utf8 => sub {
                                    my ($conn, $msg) = @_;
                                    my $msgobj = from_json($msg); # Nachricht auspacken
                                                                  # für Random Access
                                    
                                    my $sid = $msgobj->{sid};
                                    my $nickname = $msgobj->{nickname};
                                    $JOINS{$sid} = $nickname if $nickname && $sid;
                                    my @joined = grep {length $_} sort values %JOINS;
                                    my $diamond = pack "UUU", 0x20,0x25C6,0x20; 
                               
                                    # Anwesenheitsliste
                                    $msgobj->{joined} = join $diamond, map{ents($_)} @joined;
                                    # Zeitstempel einfügen
                                    $msgobj->{time} = strftime("%X", localtime);
                                    $msg = to_json($msgobj);
                    
                                    # Private Nachricht nur an bestimmte SID
                                    if(my $tosid = $msgobj->{tosid}){
                                        for ($conn->server->connections){
                                            next if $_->{SID} ne $tosid;
                                            $_->send_utf8($msg);    
                                        }
                                    }
                                    else{
                                        # Broadcast
                                        $_->send_utf8($msg) for $conn->server->connections;      
                                    }
                    
                                    # Hier kann die Log-DB beschrieben werden
                                    # oder Ausgabe in die Console
                                    #print Dumper $msg;
                                },
                    

                    Jede Chat-Nachricht enthält die eigene SID, Nickname und die Nachricht selbst als JSON Sequenz verpackt. Aufm Server wirds ausgepackt damit der Zeitstempel hinzugefügt werden kann. Und es wird geschaut, ob die Nachricht nur an eine bestimmte SID gehen soll. Außerdem wird die Anwesenheitsliste hinzugefügt und dann wird alles wieder als JSON eingepackt und zurückgeschickt: Entweder an alle Clients (Broadcast) oder nur an einen bestimmten Client.

                    Guck Dir mal das JS im Life Chat an (der loggt nicht). So kompliziert ist das garnicht.

                    .pl

              2. Tach!

                Ich schaffe es nicht, mehr Variablen aus dem Formular in die javascript Funktionen und dann weiter zu php zu reichen.

                Das sind schon wieder drei Schritte auf einmal. Bei welchem Schritt scheiterst du denn? Die Werte aus den Formularelementen zu holen? Die Werte so zusammenzubauen, dass man sie in Richtung PHP reichen kann? Oder sie dort entgegenzunehmen?

                dedlfix.

                1. Moin,

                  Ich schaffe es nicht, mehr Variablen aus dem Formular in die javascript Funktionen und dann weiter zu php zu reichen.

                  Das sind schon wieder drei Schritte auf einmal. Bei welchem Schritt scheiterst du denn? Die Werte aus den Formularelementen zu holen? Die Werte so zusammenzubauen, dass man sie in Richtung PHP reichen kann? Oder sie dort entgegenzunehmen?

                  Deine ersten beiden Schritte, genau das meinte ich mit meinem Satz. Aber das wird wohl eh überflüssig, wenn ich das mit einer Websocket Verbindung realisieren möchte.

                  Gruß Jo

                  1. Tach!

                    Bei welchem Schritt scheiterst du denn? Die Werte aus den Formularelementen zu holen? Die Werte so zusammenzubauen, dass man sie in Richtung PHP reichen kann? Oder sie dort entgegenzunehmen?

                    Deine ersten beiden Schritte, genau das meinte ich mit meinem Satz. Aber das wird wohl eh überflüssig, wenn ich das mit einer Websocket Verbindung realisieren möchte.

                    Nein, denn genau diese beiden Schritte brauchst du unabhängig von der späteren Übertragung an den Server.

                    Das Holen aus einem Formularelement geht, indem man es identifiziert (über dessen ID oder dem Namen im Formular) und dann value ausliest, oder checked bei Checkboxen. Und aus den einzelnen Werten baust du dir beispielsweise ein Objekt zusammen.

                    werte = {
                      name1: wert1,
                      name2: wert2
                    };
                    

                    Nun steht an, wie man diese Daten dem XMLHttpRequest übergibt. Und da komme ich ins Straucheln, das direkt zu verwenden, weil ich mich gar nicht mehr in diese Niederungen begebe, mal etwas überheblich formuliert. Ich will mich nicht damit befassen, wie man die Daten in Form bringt, wenn es Software gibt, die das für mich tun kann. Beispielsweise jQerys Ajax-Handler. Dem übergebe ich einfach das Objekt und gut ist. Allerdings schaue ich mir dann in den Entwicklertools des Browser an, wie der Request wirklich aussieht und korrigiere gegebenenfalls mit dem einen oder anderen Konfigurationsparameter beim Ajax-Aufruf.

                    Und selbst wenn du jetzt Websocket verwendest, nützt dir das Objekt grundsätzlich etwas, denn du kannst es mit JSON.stringify() versandfertig machen, das als Message schicken und am anderen Ende in PHP mit json_decode() auspacken.

                    dedlfix.

            2. Guten Morgen!

              Es gibt auch Websocket-Implementationen für PHP, beispielsweise Ratchet.

              So gestern Abend hab ich da nochmal ein wenig drüber nachgegrübelt und hab mir gedacht, dass müsste doch garnicht so schwer sein das php Beispiel etwas zu verbiegen. Folgende Idee hatte ich da.

              <?php
              namespace MyApp;
              use Ratchet\MessageComponentInterface;
              use Ratchet\ConnectionInterface;
              
              class Chat implements MessageComponentInterface {
                  public function onOpen(ConnectionInterface $conn) {
                  }
              
                  public function onMessage(ConnectionInterface $from, $msg) {
              /* Der Funktion onMessage könnte man ja noch ein wenig mehr Variablen mitgeben. zum Beispiel für eine Abfrage in Welche Tabelle etwas in die DB geschrieben wird. Sprich die Informationen aus den Checkboxen. Bezug zu Kommentar 2 */
                  }
              
                  public function onClose(ConnectionInterface $conn) {
                  }
              
                  public function onError(ConnectionInterface $conn, \Exception $e) {
                  }
              }
              
              <?php
              namespace MyApp;
              use Ratchet\MessageComponentInterface;
              use Ratchet\ConnectionInterface;
              
              class Chat implements MessageComponentInterface {
                  protected $clients;
              
                  public function __construct() {
                      $this->clients = new \SplObjectStorage;
                  }
              
                  public function onOpen(ConnectionInterface $conn) {
                      // Store the new connection to send messages to later
              
                     /*Die Infos aus den checkboxen müssten ja mindestens hier einmal auftachen, dann würden sie aber nicht erneuert, wenn ein client ein neues häckchen setzt/entfernt erneuert, oder?
              
                      $this->clients->attach($conn);
              
                      echo "New connection! ({$conn->resourceId})\n";
                  }
              
                  public function onMessage(ConnectionInterface $from, $msg) {
                      $numRecv = count($this->clients) - 1;
                      echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n"
                          , $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
              
                      foreach ($this->clients as $client) {
                          /* Kommentar 2 : Dann könnte man hier im  if  fragen in welche tabelle man eine neue  Zeile anlegen will und $msg und alles was man eben hat in ein SQL-Statement basteln.*/
                         
                         /* etwa so:
                          
                         if ($to !== $world) {
                              
                          **SQL
                              if($clients ???){
                                    $client->send($msg , ...);
                              }
              
                           **jetzt müsste ich hier noch irgendwie Informationen aus onOpen (?) herkriegen die sagen welcher client welche Nachrichten lesen will (Die Infos aus dem SELECT)
                          }*/
                      }
                  }
              
                  public function onClose(ConnectionInterface $conn) {
                      // The connection is closed, remove it, as we can no longer send it messages
                      $this->clients->detach($conn);
              
                      echo "Connection {$conn->resourceId} has disconnected\n";
                  }
              
                  public function onError(ConnectionInterface $conn, \Exception $e) {
                      echo "An error has occurred: {$e->getMessage()}\n";
              
                      $conn->close();
                  }
              }
              

              Was da dafür unbedingt brauchst, ist der Zugriff auf den Server, denn Websocket ist serverseitig nicht einfach nur ein PHP-Script, das über Requests aufgerufen wird. Da muss ständig ein separater Server auf Verbindungsversuche lauschen. Und diesen Server musst du starten können, was nicht damit getan ist, per FTP Dateien ins DocumentRoot des Webservers zu legen.

              Ähm...^^ SRY Denn ersten Satz versteh ich noch, dann wird kritisch.

              Gruß Jo

              1. Tach!

                    public function onMessage(ConnectionInterface $from, $msg) {
                /* Der Funktion onMessage könnte man ja noch ein wenig mehr Variablen mitgeben. zum Beispiel für eine Abfrage in Welche Tabelle etwas in die DB geschrieben wird. Sprich die Informationen aus den Checkboxen. Bezug zu Kommentar 2 */
                    }
                

                Nein, du kannst da keine weiteren Variablen einbauen. Die Funktion wird genauso von Ratchet aufgerufen. Du hast nur die beiden Parameter und nichts weiter. Du musst all deine Daten aus der Message entnehmen. Und das war der Grund, warum ich sagte, dass du da ein Protokoll brauchst. Im einfachsten Fall packst du deine Daten auf dem Client mit JSON zusammen. Das ist dann deine Message. Die kannst du auf dem Server auseinandernehmen und hast wieder die einzelnen Bestandteile. Und nun kannst du mit den extrahierten Daten deine Funktionen aufrufen, die damit irgendwas spezielles tun.

                    public function onOpen(ConnectionInterface $conn) {
                        // Store the new connection to send messages to later
                
                       /*Die Infos aus den checkboxen müssten ja mindestens hier einmal auftachen, dann würden sie aber nicht erneuert, wenn ein client ein neues häckchen setzt/entfernt erneuert, oder?
                    }
                

                Nein. Dieser Event-Handler wird nur beim Verbindungsaufbau aufgerufen. Dabei werden noch keine Nutzdaten übertragen. Die kommen frühestens im ersten onMessage-Event.

                    public function onMessage(ConnectionInterface $from, $msg) {
                        $numRecv = count($this->clients) - 1;
                        echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n"
                            , $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
                
                        foreach ($this->clients as $client) {
                            /* Kommentar 2 : Dann könnte man hier im  if  fragen in welche tabelle man eine neue  Zeile anlegen will und $msg und alles was man eben hat in ein SQL-Statement basteln.*/
                

                Ja. Nein. Die Daten musst du schon hier in diesem Eventhandler zumindest entgegennehmen. Sie auch noch hier auszuwerten, bläht die ganze Funktion ganz schön auf, was man der Übersichtlichkeit wegen vermeiden möchte. Aber das lasse ich mal eben unberücksichtigt.

                Du bekommst eine $msg übergeben. Aus der musst du die Information zur Tabelle und den eigentlichen Chat-Text herausfischen. Das war das Ja. Das Nein bezieht sich darauf, dass du hier schon im foreach bist. In diesem Beispiel wird einfach stur an alle derzeit verbundenen Clients die eingegangene Chatnachricht rausgesendet. Außerdem ist dieses Beispiel so einfach gehalten, dass nur die Chatnachricht und nichts weiter übertragen werden. Da ist noch nichtmal ein Name dabei, so dass die Clients keine Information bekommen, wer die Nachricht geschickt hat. Vielleicht kannst du aus den Metadaten im $from noch eine IP-Adresse finden, aber das wars dann auch schon. Du musst also erstmal auf anderem Weg an den Namen kommen, den der Nutzer bei sich eingegeben hat, falls du den Gesprächsbeteiligten nicht nur eine ID anzeigen möchtest. Das ist der nächste Grund für ein sich zu überlegendes Protokoll, damit festgelegt ist, wie solche Metainformationen übertragen werden.

                         **jetzt müsste ich hier noch irgendwie Informationen aus onOpen (?) herkriegen die sagen welcher client welche Nachrichten lesen will (Die Infos aus dem SELECT)
                

                Nicht aus dem onOpen, sondern aus einem der onMessages. Womit wir wieder beim Protokoll sind.

                Was da dafür unbedingt brauchst, ist der Zugriff auf den Server, denn Websocket ist serverseitig nicht einfach nur ein PHP-Script, das über Requests aufgerufen wird. Da muss ständig ein separater Server auf Verbindungsversuche lauschen. Und diesen Server musst du starten können, was nicht damit getan ist, per FTP Dateien ins DocumentRoot des Webservers zu legen.

                Ähm...^^ SRY Denn ersten Satz versteh ich noch, dann wird kritisch.

                Herkömmlich ist der Apache dafür ausgelegt, einen Request zu bekommen, den übergibt er dem PHP-Script, das erzeugt eine Antwort und ist daraufhin fertig und wird beendet. Für deinen Chat über Websockets brauchst du eine ständige Verbindung und nicht nur eine, die kurz für einen Request-Response besteht. Für solche Dauerverbindungen ist der Apache nicht direkt ausgelegt. In der aktuellen Version 2.4 gibt es lediglich ein Proxy-Modul, das die Kommunikation durchreicht. Und das an einen weiteren Server (sprich in deinem Fall: Ratchet), der ständig laufen muss und nicht nur ein kurz aufgerufenes PHP-Script ist. Diesen Server musst du starten können, wofür du Zugriff auf das Betriebssystem brauchst. Ein Webspace allein reicht dafür nicht, da brauchst du einen Server (diesmal als Hardware gemeint, inklusive virtualisierte). Der Proxy im Apachen ist nicht unbedingt notwendig, aber dann brauchst du einen zweiten Port, auf dem der Ratchet laufen kann und die Clients verbinden sich direkt dorthin. Das hat den Nachteil, dass dieser Port von den Firewalls der Clients nicht geblockt werden darf. In restriktiven Umgebungen wird meist nur Verkehr zum Port 80 (und 443) durchgelassen. Kurz: Du brauchst einen Server und musst diesen administrieren können.

                Die Alternative dazu ist Polling. Das funktioniert herkömmlich und dabei wird die Request-Response-Verbindung künstlich lange (bis zum Timeout) offengehalten, darüber Daten gesendet, wenn in der Zeit welche anfallen. Nahc dem Timeout muss die Verbindung wieder aufgebaut werden. Oder sie fragen nur einen normalen Request an, der sofort mit "hab was/nichts neues" beendet wird und feuern diese entsprechend oft.

                Bei Websocket musst du auch noch dafür Sorge tragen, dass warum auch immer unterbrochene Verbindungen wieder aufgebaut werden. Beim Polling passiert das ja schon aus Prinzip ständig.

                Du siehst hoffentlich, mit ein paar kleinen Änderungn ist da nichts getan. Das System braucht noch ein paar mehr Überlegungen.

                dedlfix.

      2. Ich würd aber gern den Verlauf nachträglich prüfen können in bezug auf mögliche Beleidigungen oder ähnliches was gegen die Netiquette/AGB verstößt.

        Das wäre im Socket-Server zu implementieren. Hier eine Demo für Chat via Socket.

        PS: Die Benutzer sollten wissen, ob mitgeschnitten wird und wielange die Daten auf Halde liegen.

  5. Servus zusammen,

    So ich habe mich jetzt fürs erste entschieden kein Websocket zu verwenden, dass kann ich später immernoch ändern.

    Da ich aber die Javascript Funktionen in ähnlicher Form auch an anderer Stelle verwenden kann, würde ich ersteinmal die Funktionalität kurz an dem Chat-beispiel erarbeiten.

    Die Frage ist, wie bekomme ich mehrere Variablen aus Javascript zu php.

    Kurz nochmal das Formular wo das <select> (wo die Nachricht später gespeichert werden sollen) und die Checkboxen (woher die Nachrichten kommen) noch auskommentiert sind.

    <section>
    				<!--<form>
    					<input type="checkbox" name="world" class="checkbox_chat" id="chat_world_list" value="world" /><label for="world">World</label>
    					<input type="checkbox" name="language" class="checkbox_chat" id="chat_language_list" value="<?php echo $_SESSION['language'];?>" /><label for="language">Language</label>
    					<?php if($page == "lobby"){echo '<input type="checkbox" name="alliance" class="checkbox_chat" id="chat_alliance_list" value="alliance" /><label for="alliance">Alliance</label>';} ?>
    
    				</form>-->
    				<div id="chatbox"></div>
    				<!--<form>
    						<select name="chat_destination" id="chat_destination">
    							<option>World Chat</option>
    							<option>Alliance</option>
    							<option>Language 2</option>
    						</select>
    				-->
    <input type="text" name="chat" id="chat_text" size="23" onkeydown = "if (event.keyCode == 13) {document.getElementById('chatbutton').click()}"/>
    					<button class="button" id="chatbutton" onclick="post_chat();" >Send</button>
    				</form>
    				
    				<script>
    				list_chat();
    				</script>
    			</section>
    

    Die Chat_post Funktion, die die Variable chat_destination aus dem <select> aufnehmen soll und an php weiter geben soll.

    function post_chat()
    {
    	var hr = new XMLHttpRequest();
    	
    	var url = "../functions/php/chat_insert.php";
    	var chat = document.getElementById("chat_text").value;
    	var chat_destination = document.getElementById("chat_destination").value;
    	
    	var message = "chat=" + chat;
    	var message_destination = "chat_destination=" + chat_destination;
    	
    	var post = new Array([message][textdestination]);    //*1
    	
    	hr.open("POST", url, true);
    	
    	hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    	hr.send(post);    //*1.1
    	
    	document.getElementById("chat_text").value = ""; 
    	
    }
    

    Hier habe ich schon ein wenig probiert, führt aber noch nicht wirklich zum Ergebnis da ich nicht genau weiss wie ich das js Array in php aufnehme. *1 und *1.1 funktioniert das so?

    Dazu kurz nochmal die chat_insert.php:

    session_start();
    require_once('db_connect_function.php');
    
    if(isset($_POST['chat']) && !empty($_POST['chat']))
    {
    	$writer = $_SESSION['user_name'];
    	$chat = $_POST['chat'];                      //*2
    	$destination = $_POST['textdestination'];    //*2.1
    	
    	$insert_message = sprintf(
    	'INSERT INTO chat ('
        . 'message_writer, message, message_date'
        . ') VALUES ('
        . '\'%1$s\', \'%2$s\', \'%3$s\''
        . ')',
        $_SESSION['user_name'],
        $_POST['chat'],
        time());
    	if($db -> query($insert_message) === TRUE)
    	{
    		$db -> commit();
    	}
    	else
    	{
    		//error_log! $create_db_connect->error.
    	}
    	
    	
    	exit();
    }
    ?>
    

    Wie spreche ich bei *2 und *2.1 das Array-Element aus js an?

    Oder geht das vllt ganz easy etwa in der Form:

    $post = json_encode($_POST['post']);                      //*2
    

    Soweit das erste, wenn das klappt, dann bin ich schonmal ein ganzes Stück weiter. Danke und noch einen schönen Sonntag.

    Gruß Jo

    1. Tach!

      Die Frage ist, wie bekomme ich mehrere Variablen aus Javascript zu php.

      Variablen können zwischen zwei Systemen nicht ausgetauscht werden. Das ist nicht nur eine Spitzfindigkeit, sondern für das Verständnis essentiell. Man kann lediglich Werte, gegebenenfalls mit Metadaten wie Namen, auf den Transport schicken. Key-Value-Pärchen sind eine Möglichkeit, Serialisieren eine andere (besonders bei komplexen Strukturen).

      Mit einem GET-Request: Querystring bauen (Escaping nicht vergessen) und an die URL hängen.

      Mit einem POST-Request und nativen POST-Daten: Dokumentationen zu XMLHttpRequest lesen, wie da Key-Value-Pärchen übergeben werden.

      Mit einem POST-Request und Serialisierung: JSON-String erzeugen und dann siehe vorhergehender Punkt.

      <input type="text" name="chat" id="chat_text" size="23" onkeydown = "if (event.keyCode == 13) {document.getElementById('chatbutton').click()}"/>
      					<button class="button" id="chatbutton" onclick="post_chat();" >Send</button>
      

      Du baust dir mit dem onkeydown grade eine Funktionalität nach, die bereits gegeben ist, wenn du ein Formular nehmen würdest und den Button zum Submit-Button umfunktionierst. Das onclick fällt weg, dafür bekommt das Formular einen Eventhandler für das submit-Ereignis. Man muss nur das Absenden verhindern, was aber kein großartiges Problem ist.

      var message = "chat=" + chat;
      var message_destination = "chat_destination=" + chat_destination;

      Escapen nicht vergessen! Andererseits kannst du auch eine Instanz von FormData an den XHR übergeben. FormData übergibt man das Formular und den Rest machen die beiden von selbst.

      var post = new Array([message][textdestination]); //*1

      Das ist zwar keine ungültige Syntax, aber ein nicht sehr sinnvolles Konstrukt.

      Hier habe ich schon ein wenig probiert, führt aber noch nicht wirklich zum Ergebnis da ich nicht genau weiss wie ich das js Array in php aufnehme. *1 und *1.1 funktioniert das so?

      Nein. Aber die Arbeitsweise des XHR ist in den Weiten des Internets bereits ausreichend oft mit Beispielen beschrieben.

      Wie spreche ich bei *2 und *2.1 das Array-Element aus js an?

      Gar nicht. Variablen von Javascript existeren in PHP nicht und kommen da auch nicht an, wie eingangs schon erwähnt. Du bekommst Werte übergeben. Und die nimmst du so entgegen, wie es üblich ist. Zur Not schaust du dir das $_POST-Array mit einer Kontrollausgabe an: var_dump($_POST)

      dedlfix.

    2. Servus zusammen,

      Ich bin jetzt seit 2 Tagen am rumprobieren und ich komme einfach nicht weiter. Jetzt funktioniert irgendwie nichts mehr und ich weiß einfach nicht warum, deshalb brauche ich euren Rat.

      Zum testen hab ich mal die post Funktion und das Formular in eine test.php gepackt:

      
      			<form>
      				<select name="chat_destination" id="chat_destination">
      					<option value="chat">World Chat</option>
      					<option value="<?php echo "lang_ger"; ?>">d Chat</option>
      					<option value="<?php echo "lang_eng"; ?>">e Chat</option>
      					<option value="<?php echo "lang_swe"; ?>">s Chat</option>
      					<!-- Alliance, Friends-->
      						
      				</select>
      				
      				<input type="text" name="chat" id="chat_text" onkeydown = "if (event.keyCode == 13) {document.getElementById('chatbutton').click()}"/>
      				<button class="button" id="chatbutton" onclick="post_chat();" >Send</button>
      			</form>
      				<div id="status"></div>
      <script language="JavaScript" type="text/javascript">
      
      function post_chat()
      {
      	var hr = new XMLHttpRequest();
      	
      	var url = "test2.php";
      	
      	var chat = document.getElementById("chat_text").value;
      	var chat_destination = document.getElementById("chat_destination").value;
      	
      	var data = "chat="+chat+"&destination="+chat_destination;
      	
      	hr.open("POST", url, true);
      	
      	hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
      	hr.onreadystatechange = function() {
      	if (hr.readyState == 4 && hr.status == 200)
      		{
      			document.getElementById("status").innerHTML = hr.responseText;
      			
      		}
      	}
      	hr.send(data);
      	
      	document.getElementById("chat_text").value = ""; 
      	document.getElementById("status").innerHTML = "processing...";
      }
      </script>
      

      so um dann zu schauen was in test2.php ankommt, steht dort folgendes:

      echo $_POST['chat'];//.$_POST['destination'];
      

      Das sollte ja dann im div mit der id Status rauskommen.

      Nur erstens kommt nichts zurück und die Seite wird neu geladen.
      Und die Console zeigt mir keinen Fehler an.

      console.log(data); gibt das aus was es soll, nämlich chat=teststring&destination=chat, aber von php kommt nichts zurück. was mache ich falsch?

      Und dnn noch eine Frage. hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); was macht diese Zeile? Müssen header = Content-type und value = application/x-www-form-urlencoded genau so gesetzt sein?

      Ich Danke euch für eure Hilfe!

      Gruß Jo

      P.s Ja, ich muss das mit Sicherheit auch noch für Javascript richtig escapen aber ich bin immoment erstmal bei der grundsätzlichen Funktionlität.

      1. Kleines update;

        test2.php liefert das gewünschte Ergebnis zurück, nur so schnell das ich es bisher nicht bemerkt habe. Also die Seite wird so schnell neu geladen, dass ich es nicht gesehen habe.

        Ich verstehe aber nicht warum die Seite neu geladen wird?

        Gruß
        Jo

        1. Ich verstehe aber nicht warum die Seite neu geladen wird?

          Verstehe ich auch nicht, aber Deine Idee mit der anderen Farbe für private Nachrichten finde ich gut. Demnächst auch verschlüsselt mfg

        2. Tach!

          Ich verstehe aber nicht warum die Seite neu geladen wird?

          Ein <form> tut was ein Form tun muss. Es setzt einen Request ab. Auch dann, wenn kein action-Attribut vorhanden ist, dann gilt per Default die eigene Seite. Ich glaube, ich hatte schon einmal empfohlen, statt Klick-Ereignisse und Entertasten abzufangen, das Submit-Ereignis des Forms zu verwenden. Dort musst du dann verhindern, dass der übliche Mechanismus losgeht. Das war irgendwas mit preventDefault, findet man aber an jeder Ecke, an der über Javascript-Ereignisbehandlung gesprochen wird.

          dedlfix.

          1. Moin,

            Ich verstehe aber nicht warum die Seite neu geladen wird?

            Ein <form> tut was ein Form tun muss. Es setzt einen Request ab. Auch dann, wenn kein action-Attribut vorhanden ist, dann gilt per Default die eigene Seite. Ich glaube, ich hatte schon einmal empfohlen, statt Klick-Ereignisse und Entertasten abzufangen, das Submit-Ereignis des Forms zu verwenden. Dort musst du dann verhindern, dass der übliche Mechanismus losgeht. Das war irgendwas mit preventDefault,

            Ja hattest du, ich hab aber kein plan was du sagst. Bzw, warum das besser sein sollte als so wie es jetzt ist und ja auch schon so funktioiert hat.

            2. Beispiel Sowas?

            findet man aber an jeder Ecke, an der über Javascript-Ereignisbehandlung gesprochen wird.

            Schade nur das ich mit den meisten Sachen einfach nichts anfangen kann und nicht verstehe was die machen oder verhindern sollen oder was auch immer. Weshalb ich wohl auch nicht sehe wenn ich etwas brauchen könnte oder wo meine Fehler liegen könnten. Was ich in dem Zuge dann auch nicht kann ist ein Beispiel nehmen und es nach meinen Bedürfnissen umbauen. Wie auch immer kann ich gerade mit deiner gut gemeinten Antwort nichts anfangen, was mir wirklich Leid tut, denn du gibst dir echt viel mühe und das schätze ich sehr und bin dir sehr dankbar dafür.

            Ich bin einfach nicht an dem Punkt in Javascript, dass ich deinen Vorschlag nehme und in JS umsetzen kann. In PHP bekomme ich das mittlerweile recht gut hin das ich mir überlege was ich brauche oder machen möchte und der Code sich in Gedanken von selbst schreibt.

            Gruß Jo

            1. Tach!

              Ja hattest du, ich hab aber kein plan was du sagst. Bzw, warum das besser sein sollte als so wie es jetzt ist und ja auch schon so funktioiert hat.

              Du hast Funktionalität nachgebaut, die bereits vorhanden ist.

              <form onsubmit="post_chat(); event.preventDefault();">
                  <!-- hier muss noch das select rein -->
                  <input type="text" id="chat_text">
                  <button class="button">Send</button>
              </form>
              

              Das ist alles was du brauchst. [1] Klickst du auf den Button, wird Submit ausgelöst. Drückst du Enter im Eingabefeld, wird auch Submit ausgelöst. Es reicht nun, sich nur in das Submit einzuklinken.

              Schade nur das ich mit den meisten Sachen einfach nichts anfangen kann und nicht verstehe was die machen oder verhindern sollen oder was auch immer.

              Es gibt Default-Aktionen, die in den Browsern eingebaut sind. Ein Submit schickt das Formular ab. Ein Submit-Button löst beim Klick das Submit aus. Wenn man solche Default-Aktionen nicht haben möchte, dann muss man sie verhindern. In deinem Beispiel möchtest du das Formular nicht an den Server geschickt haben, sondern du möchtest selbst was mit Javascript erreichen. Du kannst aber trotzdem die generelle Submit-Funktionalität der Browser nutzen - also zumindest den Teil, der vor dem eigentlichen Starten des Requests zum Server stattfindet - musst aber verhindern, dass sie weiterarbeitet, nachdem du dich da eingeklinkt hast.

              dedlfix.


              1. für die Mitleser: ja, da steht ein herkömmlicher onsubmit-Handler, ich habe es nicht auf die Verwendung von addEventListener() umgeschrieben. ↩︎

              1. Moin,

                Du hast Funktionalität nachgebaut, die bereits vorhanden ist.

                <form onsubmit="post_chat(); event.preventDefault();">
                    <!-- hier muss noch das select rein -->
                    <input type="text" id="chat_text">
                    <button class="button">Send</button>
                </form>
                

                Ja gemerkt, das hab ich so aus einem (anscheinend schlechtem) "Tutorial" übernommen ohne nachzudenken ob es anders schon vorhanden ist.

                Es gibt Default-Aktionen, die in den Browsern eingebaut sind. Ein Submit schickt das Formular ab. Ein Submit-Button löst beim Klick das Submit aus. Wenn man solche Default-Aktionen nicht haben möchte, dann muss man sie verhindern. In deinem Beispiel möchtest du das Formular nicht an den Server geschickt haben, sondern du möchtest selbst was mit Javascript erreichen. Du kannst aber trotzdem die generelle Submit-Funktionalität der Browser nutzen - also zumindest den Teil, der vor dem eigentlichen Starten des Requests zum Server stattfindet - musst aber verhindern, dass sie weiterarbeitet, nachdem du dich da eingeklinkt hast.

                Ja, verstanden! Danke.

                Gruß
                Jo

          2. So,

            Ein <form> tut was ein Form tun muss. Es setzt einen Request ab. Auch dann, wenn kein action-Attribut vorhanden ist, dann gilt per Default die eigene Seite. Ich glaube, ich hatte schon einmal empfohlen, statt Klick-Ereignisse und Entertasten abzufangen, das Submit-Ereignis des Forms zu verwenden. Dort musst du dann verhindern, dass der übliche Mechanismus losgeht. Das war irgendwas mit preventDefault, findet man aber an jeder Ecke, an der über Javascript-Ereignisbehandlung gesprochen wird.

            Nach ein bissl rumsuchen hab ich das bei Stackoverflow gefunden.
            Das schon eher, oder?

            Nur das steht da in JQuery und davon hab ich noch weniger Ahnung als von Javascript.
            Und JQuery hab ich beim ersten Versuch schon nicht zum laufen gekriegt und habs denn erstmal mit Javascript probiert.

            Ach ich bgin Ratlos...

            Gruß Jo

            1. Wow...

              ich glaub ich habs!

              <input type="text" name="chat" id="chat_text"/>
              <input type="submit" name="submit" id="submit" onclick="post_chat()"/>
              
              document.getElementById("submit").addEventListener("click", function(event){
                  event.preventDefault()
              });
              

              So?

              Jedenfalls wird die Seite nicht neu geladen.

              Gruß Jo

  6. Servus zusammen,

    Servus,

    Eine kleinigkeit, die etwas komisch ist:

    $insert_message = sprintf(
    'INSERT INTO %s ('
    . 'message_writer, message,message_date'
    . ') VALUES ('
    . '\'%s\', \'%s\', \'%d\''
    . ')',
    $_POST['destination'],
    $_SESSION['user_name'],
    $_POST['chat'],
    time());
    

    Dieses time() schreibt in die Datenbank immer den gleichen wert. Eben war es 1463920000 und heute morgen war es 1463900000 und jetzt ist es gerade auf 1463930000 gesprungen.

    Gruß Jo

    1. Hallo,

      $insert_message = sprintf(
      'INSERT INTO %s ('
      . 'message_writer, message,message_date'
      . ') VALUES ('
      . '\'%s\', \'%s\', \'%d\''
      . ')',
      $_POST['destination'],
      $_SESSION['user_name'],
      $_POST['chat'],
      time());
      

      Dieses time() schreibt in die Datenbank immer den gleichen wert.

      nein, ganz bestimmt nicht.

      Eben war es 1463920000 und heute morgen war es 1463900000 und jetzt ist es gerade auf 1463930000 gesprungen.

      Das ist der Wert, den du wieder zurückliest, aber bestimmt nicht der Wert, der an die DB übergeben wird. Was für einen Type hat denn die Spalte message_date? Vielleicht FLOAT? Dieses Format entspricht in seiner kleinsten Form dem IEEE-Datentyp single und hat nur eine Genauigkeit von etwa 6..7 gültigen Stellen.

      Da ein Unix-Timestamp eine Ganzzahl ist, verwende am besten den Datentyp INTEGER für diese Spalte.

      So long,
       Martin

      PS: Du tust etwas sehr Riskantes, wenn du Werte aus Benutzereingaben (POST) ungeprüft und unmaskiert an das DBMS übergibst. Beachte den Kontextwechsel!!

      --
      Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
      - Douglas Adams, The Hitchhiker's Guide To The Galaxy
      1. Hey,

        Dieses time() schreibt in die Datenbank immer den gleichen wert.

        nein, ganz bestimmt nicht.

        Eben war es 1463920000 und heute morgen war es 1463900000 und jetzt ist es gerade auf 1463930000 gesprungen.

        Das ist der Wert, den du wieder zurückliest, aber bestimmt nicht der Wert, der an die DB übergeben wird.

        Naja das kommt in der Tabelle an.

        Was für einen Type hat denn die Spalte message_date? Vielleicht FLOAT? Dieses Format entspricht in seiner kleinsten Form dem IEEE-Datentyp single und hat nur eine Genauigkeit von etwa 6..7 gültigen Stellen.

        OK gerade getestet als INT geht es wieder. Und ja ich hab es auf Float gewechselt da ich die Zeit gern mit:

        function microtime_float()
        {
            list($milli_sec, $sec) = explode(" ", microtime());
            return ((float)$milli_sec + (float)$sec);
        }
        

        speichern möchte.
        Aber das funktioniert absolut nicht.

        Das müsste ich wohl machen da ich die Ergebnisse aus verschiedenen Tabellen in einem Array speichere und die Zeit als key verwende, um mit ksort() das ganze in die richtige Reihenfolge zu bringen. Wenn nun also zwei Nachrichten den selben Timestamp hätten würde die später hinzugefügte überschrieben werden. Außer ich finde irgendwann nochmal eine Möglichkeit Array Elemente durch dessen Inhalt zu sortieren.

        PS: Du tust etwas sehr Riskantes, wenn du Werte aus Benutzereingaben (POST) ungeprüft und unmaskiert an das DBMS übergibst. Beachte den Kontextwechsel!!

        Naklar, kommt direkt nachdem die funktionalität steht.

        Gruß Jo

        1. Tach!

          function microtime_float()
          {
              list($milli_sec, $sec) = explode(" ", microtime());
              return ((float)$milli_sec + (float)$sec);
          }
          

          Diese uralten Notlösungen schwirren immer noch im Internet rum? Dabei gibts doch schon seit Jahren (seit es PHP 5 gibt) einen booleschen Parameter für microtime(), der die Zeit direkt als float liefert.

          PS: Du tust etwas sehr Riskantes, wenn du Werte aus Benutzereingaben (POST) ungeprüft und unmaskiert an das DBMS übergibst. Beachte den Kontextwechsel!!

          Naklar, kommt direkt nachdem die funktionalität steht.

          Das gehört zur Funktionalität dazu, denn die ist kaputt, wenn du einen Text mit ' drin in den Chat eingibst. Da muss noch nicht mal jemand was böses wollen.

          dedlfix.

          1. Tach!

            function microtime_float()
            {
                list($milli_sec, $sec) = explode(" ", microtime());
                return ((float)$milli_sec + (float)$sec);
            }
            

            Diese uralten Notlösungen schwirren immer noch im Internet rum? Dabei gibts doch schon seit Jahren (seit es PHP 5 gibt) einen booleschen Parameter für microtime(), der die Zeit direkt als float liefert.

            Von da hab ich das ja, hab nur nicht weiter gelesen.

            PS: Du tust etwas sehr Riskantes, wenn du Werte aus Benutzereingaben (POST) ungeprüft und unmaskiert an das DBMS übergibst. Beachte den Kontextwechsel!!

            Naklar, kommt direkt nachdem die funktionalität steht.

            Das gehört zur Funktionalität dazu, denn die ist kaputt, wenn du einen Text mit ' drin in den Chat eingibst. Da muss noch nicht mal jemand was böses wollen.

            Ja, Danke. Aber fürs erste schreibe ja nur ich darein um zu schaun ob es funktioniert oder nicht. Aber mein Float bekomme ich immernoch nicht in die Tabelle, obwohl ich schon das Richtige geändert haben müsste.

            $insert_message = sprintf(
            'INSERT INTO %s ('
            . 'message_writer, message,message_date'
            . ') VALUES ('
            . '\'%s\', \'%s\', %f'
            . ')',
            $_POST['destination'],
            $_SESSION['user_name'],
            $_POST['chat'],
            microtime(true));
            

            Gruß Jo

            1. Hi,

              PS: Du tust etwas sehr Riskantes, wenn du Werte aus Benutzereingaben (POST) ungeprüft und unmaskiert an das DBMS übergibst. Beachte den Kontextwechsel!!

              Naklar, kommt direkt nachdem die funktionalität steht.

              Das gehört zur Funktionalität dazu, denn die ist kaputt, wenn du einen Text mit ' drin in den Chat eingibst. Da muss noch nicht mal jemand was böses wollen.

              Ja, Danke. Aber fürs erste schreibe ja nur ich darein um zu schaun ob es funktioniert oder nicht.

              diese Einstellung kann gefährlich sein, denn die Erfahrung zeigt: Nicht ist so dauerhaft wie ein Provisorium. Irgendwann "funktioniert" es, und wie's Murphy will, denkt man dann nicht mehr dran, alles noch auf Struktur und Sicherheit zu prüfen und nachzubessern.

              Aber mein Float bekomme ich immernoch nicht in die Tabelle, obwohl ich schon das Richtige geändert haben müsste.

              Was für einen Spaltentyp hast du denn nun? INT/INTEGER? Dann geht natürlich der Nachkommaanteil (die Microsekunden) verloren.

              So long,
               Martin

              --
              Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
              - Douglas Adams, The Hitchhiker's Guide To The Galaxy
              1. Hi,

                PS: Du tust etwas sehr Riskantes, wenn du Werte aus Benutzereingaben (POST) ungeprüft und unmaskiert an das DBMS übergibst. Beachte den Kontextwechsel!!

                Naklar, kommt direkt nachdem die funktionalität steht.

                Das gehört zur Funktionalität dazu, denn die ist kaputt, wenn du einen Text mit ' drin in den Chat eingibst. Da muss noch nicht mal jemand was böses wollen.

                Ja, Danke. Aber fürs erste schreibe ja nur ich darein um zu schaun ob es funktioniert oder nicht.

                diese Einstellung kann gefährlich sein, denn die Erfahrung zeigt: Nicht ist so dauerhaft wie ein Provisorium. Irgendwann "funktioniert" es, und wie's Murphy will, denkt man dann nicht mehr dran, alles noch auf Struktur und Sicherheit zu prüfen und nachzubessern.

                Darum dachte ich am Anfang das Zentral zu machen. Nun muss ich eben wenn ein Teil funktioniert alles durchschauen und richtig maskieren,escapen etc.

                Aber mein Float bekomme ich immernoch nicht in die Tabelle, obwohl ich schon das Richtige geändert haben müsste.

                Was für einen Spaltentyp hast du denn nun? INT/INTEGER? Dann geht natürlich der Nachkommaanteil (die Microsekunden) verloren.

                Das ist Klar, ne ich habs jetzt auf double geändert und nach einer kurzen Suche, da zwischenzeitlich nichts mehr funktioniert hat, habe ich noch ein } entfernt und jetzt läuft alles.

                So dann kann ich ja mit dem escapen etc. anfangen. und nochmal suchen wie ich für Javascript richtig escape.

                Danke!

                Gruß Jo

        2. Hi,

          Das ist der Wert, den du wieder zurückliest, aber bestimmt nicht der Wert, der an die DB übergeben wird.

          Naja das kommt in der Tabelle an.

          ja, nachdem der Wert dem Spaltentyp entsprechend gestutzt und gerundet wurde.

          OK gerade getestet als INT geht es wieder. Und ja ich hab es auf Float gewechselt

          Ohne vorher zu überlegen, ob der Wertebereich und vor allem die Genauigkeit ausreichen? Für diesen Fall sollte es dann wenigstens DOUBLE sein. Dieses Format kann etwa 15 gültige Dezimalstellen wiedergeben, das würde gerade eben reichen, um den Timestamp tatsächlich auf Mikrosekunden aufzulösen, wobei die letzten drei Nachkommastellen vermutlich nicht mehr so entscheidend sind.

          function microtime_float()
          {
              list($milli_sec, $sec) = explode(" ", microtime());
              return ((float)$milli_sec + (float)$sec);
          }
          

          Warum so kompliziert? Lass dir doch den gewünschten Wert gleich von microtime() liefern, indem du den optionalen Parameter auf true setzt.

          PS: Du tust etwas sehr Riskantes, wenn du Werte aus Benutzereingaben (POST) ungeprüft und unmaskiert an das DBMS übergibst. Beachte den Kontextwechsel!!

          Naklar, kommt direkt nachdem die funktionalität steht.

          Warum nicht gleich von Anfang an ordentlich?

          Ciao,
           Martin

          --
          Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
          - Douglas Adams, The Hitchhiker's Guide To The Galaxy
          1. Hi,

            PS: Du tust etwas sehr Riskantes, wenn du Werte aus Benutzereingaben (POST) ungeprüft und unmaskiert an das DBMS übergibst. Beachte den Kontextwechsel!!

            Naklar, kommt direkt nachdem die funktionalität steht.

            Warum nicht gleich von Anfang an ordentlich?

            Weil ich immernoch nicht über den Anfang hinaus bin bzw. gerade noch im Anfang stecke.

            Gruß
            Jo

            1. Lieber j4nk3y,

              Warum nicht gleich von Anfang an ordentlich?

              Weil ich immernoch nicht über den Anfang hinaus bin bzw. gerade noch im Anfang stecke.

              es heißt doch so schön "wehret den Anfängen!". @Gunnar Bittersmann schreibt das auch gerne hier immer wieder, wenn auch in anderen Kontexten.

              Ich empfehle Dir dringend die PDO-Klasse. Wenn die auf sowohl Deinem Testsytem, als auch auf Deinem Produktivsystem verfügbar ist (phpinfo() ist Dein Freund), dann solltest Du sofort darauf umsteigen! Alles andere ist ziemlich unschlau!

              Wenn Du Hilfe braucht, Deine PDO-Klasse bequem zu nutzen, dann kann man Dir auch dabei helfen. Du solltest aber unbedingt wollen, sonst ist Dir nicht zu helfen!

              Liebe Grüße,

              Felix Riesterer.

              1. Lieber Felix,

                Ich empfehle Dir dringend die PDO-Klasse. Wenn die auf sowohl Deinem Testsytem, als auch auf Deinem Produktivsystem verfügbar ist (phpinfo() ist Dein Freund), dann solltest Du sofort darauf umsteigen! Alles andere ist ziemlich unschlau!

                Ja das wurde schon sooft gesagt. Aber ich habe erst mysql gelernt und habe damit angefangen, dann hat Jemand gesagt warum machst du das nicht mit mysqli? Daraufhin hab ich mich in mysqli eingelesen und alles was ich hatte umgeschrieben. Verzeih mir aber ich habe keine Lust wieder von vorne Anzufangen. Den das mache ich ständig egal mit was. Sei es z.B. CSS wo ich mit position angefangen habe, dann alles auf display umschreiben sollte und dann wieder alles auf flexbox umgeschrieben habe.
                Irgendwann würde ich ganz gern zu einem Ergebnis kommen und wenn ich schon 18 Tage brauche um Punkt 1 zu realisieren und immernoch nicht beim websocket bin, sehe ich Schwarz das ich vor 2020 fertig bin.

                Wenn Du Hilfe braucht, Deine PDO-Klasse bequem zu nutzen, dann kann man Dir auch dabei helfen. Du solltest aber unbedingt wollen, sonst ist Dir nicht zu helfen!

                Danke, ich hoffe ihr wisst dass ich eure Hilfe sehr zuschätzen weiss.

                Liebe Grüße,
                Jo

                1. Hallo j4nk3y,

                  Sei es z.B. CSS wo ich mit position angefangen habe, dann alles auf display umschreiben sollte und dann wieder alles auf flexbox umgeschrieben habe.

                  Das klingt, als würdest du um die Grundlagen drumrum lernen.

                  Irgendwann würde ich ganz gern zu einem Ergebnis kommen und wenn ich schon 18 Tage brauche um Punkt 1 zu realisieren und immernoch nicht beim websocket bin, sehe ich Schwarz das ich vor 2020 fertig bin.

                  Wenn du tatsächlich etwas lernen möchtest und dieses Wissen auch für die Zukunft abrufbereit haben möchtest, kommst du um einen entsprechenden Zeitaufwand nicht herum.[1]

                  Wenn du jedoch nur schnelle Ergebnisse sehen möchtest, dann wirst du damit rechnen müssen, dass Bösewichte deinen Server missbrauchen werden.

                  Bis demnächst
                  Matthias

                  --
                  Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.

                  1. Mediengestalter ist nicht umsonst ein Ausbildungsberuf. ↩︎

                  1. Hallo Matthias,

                    Sei es z.B. CSS wo ich mit position angefangen habe, dann alles auf display umschreiben sollte und dann wieder alles auf flexbox umgeschrieben habe.

                    Das klingt, als würdest du um die Grundlagen drumrum lernen.

                    Wieso drumrum? Hab ja jetzt so gut wie alles durch was man z.B in CSS oder PHP machen kann. Nur streube ich mich etwas davor PDO noch anzufangen, da ich auch mit dem Klassen konstruct nicht viel anfangen kann.

                    Irgendwann würde ich ganz gern zu einem Ergebnis kommen und wenn ich schon 18 Tage brauche um Punkt 1 zu realisieren und immernoch nicht beim websocket bin, sehe ich Schwarz das ich vor 2020 fertig bin.

                    Wenn du tatsächlich etwas lernen möchtest und dieses Wissen auch für die Zukunft abrufbereit haben möchtest, kommst du um einen entsprechenden Zeitaufwand nicht herum.

                    Ich programmiere ja schon mehr als das ich mich auf mein Studium konzentriere.

                    Mediengestalter ist nicht umsonst ein Ausbildungsberuf.

                    Sicherlich aber nicht meiner und Informatik studiere ich auch nicht.

                    Wenn du jedoch nur schnelle Ergebnisse sehen möchtest, dann wirst du damit rechnen müssen, dass Bösewichte deinen Server missbrauchen werden.

                    Von schnellen Ergebnissen kann keine rede sein. Ich sitze ja mittlerweile schon über ein Jahr dran und komme nicht über die dritte Seite hinaus.

                    Gruß
                    Jo

                2. Lieber j4nk3y,

                  Aber ich habe erst mysql gelernt und habe damit angefangen, dann hat Jemand gesagt warum machst du das nicht mit mysqli? Daraufhin hab ich mich in mysqli eingelesen und alles was ich hatte umgeschrieben.

                  ich verstehe, dass das für Dich eine wesentliche Menge an Einarbeitung und Lernstoff war - nur reicht das leider noch nicht.

                  Verzeih mir aber ich habe keine Lust wieder von vorne Anzufangen. Den das mache ich ständig egal mit was.

                  Das nennt man Lernen. Früher war auch gängige Meinung die Welt sei eine Scheibe. Da hatten es die Navi-Geräte noch relativ leicht... ;-)

                  Ne, im Ernst. Du macht da sehr gefährliche Sachen. Das sollte man überhaupt nicht erst anfangen. Egal ob mysqli oder PDO, Du darfst keine SQL-Injection-Lücken aufreissen. Es lohnt sich also, die Handhabung mit SQL-Code und Parametern irgendwie zu abstrahieren. Dann hast Du zum einen weniger Geschäft beim Schreiben Deines Codes (immer von Vorteil) und zum anderen mehr Sicherheit.

                  Wäre das ein Deal?

                  Für PDO könnte ich Dir eine klitzekleine Klasse anbieten, die Dir im Hintergrund etwas vereinfacht, sodass Du nur noch folgendes schreiben brauchst (falls Du ansonsten noch nicht objektorientiert PHP schreibst und noch weiter abstrahieren kannst):

                  // Hole aus DB
                  $query = array(
                      'select' => 'SELECT `login`, `pass` FROM `users` WHERE `login`=:login',
                      'params' => array(
                          ':login' => $_POST['login']
                      )
                  );
                  
                  $array = $db->get($query['select'], $query['params']);
                  
                  // Schreibe in DB
                  $query = array(
                      'update' => 'UPDATE `users` SET `pass`=:pass WHERE `login`=:login',
                      'params' => array(
                          ':login' => $_POST['login'],
                          ':pass' => password_hash($_POST['pass'], PASSWORD_DEFAULT)
                      )
                  );
                  
                  $db->send($query['update'], $query['params']);
                  

                  Mir hilft das beim Schreiben, weil ich sehe, ob ich etwas von der DB haben will (und auf welche Weise), oder ob ich etwas in die DB füttere (und auf welche Weise).

                  Na, wäre das eine vernachlässigbare Menge des Umlernens? In Deine Scripte müsstest Du nur ein PHP-Script einbinden, welches Dir diese $db->send() oder $db->get() zur Verfügung stellt. Das könntest Du haben. Wir könnten auch die Klasse so anpassen, dass Du nur noch das Array $query an $db->send() oder $db->get() übermitteln bräuchtest.

                  Liebe Grüße,

                  Felix Riesterer.

                  1. Lieber Felix,

                    Aber ich habe erst mysql gelernt und habe damit angefangen, dann hat Jemand gesagt warum machst du das nicht mit mysqli? Daraufhin hab ich mich in mysqli eingelesen und alles was ich hatte umgeschrieben.

                    ich verstehe, dass das für Dich eine wesentliche Menge an Einarbeitung und Lernstoff war - nur reicht das leider noch nicht.

                    Verzeih mir aber ich habe keine Lust wieder von vorne Anzufangen. Den das mache ich ständig egal mit was.

                    Das nennt man Lernen. Früher war auch gängige Meinung die Welt sei eine Scheibe. Da hatten es die Navi-Geräte noch relativ leicht... ;-)

                    Ne, im Ernst. Du macht da sehr gefährliche Sachen. Das sollte man überhaupt nicht erst anfangen. Egal ob mysqli oder PDO, Du darfst keine SQL-Injection-Lücken aufreissen. Es lohnt sich also, die Handhabung mit SQL-Code und Parametern irgendwie zu abstrahieren. Dann hast Du zum einen weniger Geschäft beim Schreiben Deines Codes (immer von Vorteil) und zum anderen mehr Sicherheit.

                    Dann wäre es schön wenn man gleich auf dem richtigen Level Anfangen könnte und nicht "alte" Tutorials findet wo einem was altes/falsches beigebracht wird. Zum Beispiel: warum gibt es noch position oder display wenn alles mit flexbox viel einfacher geht. Warum mysql oder mysqli wenn PDO das maß der dinge ist.

                    Wäre das ein Deal?

                    Für PDO könnte ich Dir eine klitzekleine Klasse anbieten, die Dir im Hintergrund etwas vereinfacht, sodass Du nur noch folgendes schreiben brauchst (falls Du ansonsten noch nicht objektorientiert PHP schreibst und noch weiter abstrahieren kannst):

                    Das wär äußerst großzügig. aber auch da müsste ich jetzt jeden der mittlerweile sicher 250 querys umschreiben. Und eine wirkliche Vereinfachung seh ich da auf anhieb nicht. Mit mysqli sehe ich auch direkt was wie wo rein oder aus der DB geht/kommt.

                    // Hole aus DB
                    $query = array(
                        'select' => 'SELECT `login`, `pass` FROM `users` WHERE `login`=:login',
                        'params' => array(
                            ':login' => $_POST['login']
                        )
                    );
                    
                    $array = $db->get($query['select'], $query['params']);
                    
                    // Schreibe in DB
                    $query = array(
                        'update' => 'UPDATE `users` SET `pass`=:pass WHERE `login`=:login',
                        'params' => array(
                            ':login' => $_POST['login'],
                            ':pass' => password_hash($_POST['pass'], PASSWORD_DEFAULT)
                        )
                    );
                    
                    $db->send($query['update'], $query['params']);
                    

                    Und jetzt habt ihr mir so in den Kopf geprügelt das ich die $_POST Variablen für mysql escapen muss aber bei dir seh ich da nichts von.

                    Mir hilft das beim Schreiben, weil ich sehe, ob ich etwas von der DB haben will (und auf welche Weise), oder ob ich etwas in die DB füttere (und auf welche Weise).

                    Na, wäre das eine vernachlässigbare Menge des Umlernens? In Deine Scripte müsstest Du nur ein PHP-Script einbinden, welches Dir diese $db->send() oder $db->get() zur Verfügung stellt. Das könntest Du haben. Wir könnten auch die Klasse so anpassen, dass Du nur noch das Array $query an $db->send() oder $db->get() übermitteln bräuchtest.

                    Wie gesagt geht es nicht vorrangig um die Menge des umlernens, ich hab jetzt den Code 3 mal gelesen und verstehe was passiert bzw wie was zusammen hängt. Es ist nur der Aufwand ~30.000 zeilen Code in ~40 Dateien durchzugehen und jeden der ~250 querys umzuschreiben.

                    Gruß Jo

                    P.S. Ich seh mich ja schon fast wieder von vorne Anfangen...-.- Und ich will nicht :(

                    1. Hallo,

                      Ne, im Ernst. Du macht da sehr gefährliche Sachen. Das sollte man überhaupt nicht erst anfangen. Egal ob mysqli oder PDO, Du darfst keine SQL-Injection-Lücken aufreissen. Es lohnt sich also, die Handhabung mit SQL-Code und Parametern irgendwie zu abstrahieren. Dann hast Du zum einen weniger Geschäft beim Schreiben Deines Codes (immer von Vorteil) und zum anderen mehr Sicherheit.

                      Dann wäre es schön wenn man gleich auf dem richtigen Level Anfangen könnte und nicht "alte" Tutorials findet wo einem was altes/falsches beigebracht wird. Zum Beispiel: warum gibt es noch position oder display wenn alles mit flexbox viel einfacher geht.

                      du vergleichst hier gerade Nägel mit Schrauben. Layouts mit absoluter Positionierung zu bauen, war noch nie eine gute Idee, die display-Eigenschaft hat ihren ganz speziellen Sinn, und flex ist zwar eine vergleichsweise neue Technik, aber das heißt nicht, dass die nun die einzig wahre ist.

                      Mit der Auswahl einer bestimmten SQL-Schnittstelle und deren Verwendung hat das aber nicht viel zu tun. Die alten mysql-Funktionen gehören tatsächlich zum alten Eisen und fallen in absehbarer Zeit endgültig weg. Die mysqli-Funktionen nicht. Ob mysqli oder PDO ist zunächst mal eine Frage der persönlichen Präferenzen; wenn man sich für eine der beiden Möglichkeiten entscheidet, sollte man sie aber auch "richtig" nutzen.

                      Warum mysql oder mysqli wenn PDO das maß der dinge ist.

                      Nein, das ist eben nicht so. Das ist eher vergleichbar mit der Frage "VW oder Opel". Wenn der Fuhrpark bisher ausschließlich VW-Fahrzeuge vorhält und sämtliche Serviceverträge mit VW ausgehandelt sind, ist es nicht sinnvoll, wegen eines bestimmten technischen Merkmals plötzlich einen Opel anzuschaffen.

                      Wie gesagt geht es nicht vorrangig um die Menge des umlernens, ich hab jetzt den Code 3 mal gelesen und verstehe was passiert bzw wie was zusammen hängt. Es ist nur der Aufwand ~30.000 zeilen Code in ~40 Dateien durchzugehen und jeden der ~250 querys umzuschreiben.

                      Das wäre in der Tat ein sinnloser Aufwand.

                      So long,
                       Martin

                      --
                      Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
                      - Douglas Adams, The Hitchhiker's Guide To The Galaxy
                      1. Hey,

                        Ne, im Ernst. Du macht da sehr gefährliche Sachen. Das sollte man überhaupt nicht erst anfangen. Egal ob mysqli oder PDO, Du darfst keine SQL-Injection-Lücken aufreissen. Es lohnt sich also, die Handhabung mit SQL-Code und Parametern irgendwie zu abstrahieren. Dann hast Du zum einen weniger Geschäft beim Schreiben Deines Codes (immer von Vorteil) und zum anderen mehr Sicherheit.

                        Dann wäre es schön wenn man gleich auf dem richtigen Level Anfangen könnte und nicht "alte" Tutorials findet wo einem was altes/falsches beigebracht wird. Zum Beispiel: warum gibt es noch position oder display wenn alles mit flexbox viel einfacher geht.

                        du vergleichst hier gerade Nägel mit Schrauben. Layouts mit absoluter Positionierung zu bauen, war noch nie eine gute Idee, die display-Eigenschaft hat ihren ganz speziellen Sinn, und flex ist zwar eine vergleichsweise neue Technik, aber das heißt nicht, dass die nun die einzig wahre ist.

                        Irgendwer, sagte das letztens zu mir das ich flexbox benutzen sollte. Ich meine sogar das du derjenige warst. Wie dem auch sei da es nur drei Seiten waren und ich nach kurzem einarbeiten gemerkt hab, dass das wirklich sinnvoll ist und einiges vereinfacht, hab ich das in einer woche umgeschrieben.

                        Mit der Auswahl einer bestimmten SQL-Schnittstelle und deren Verwendung hat das aber nicht viel zu tun. Die alten mysql-Funktionen gehören tatsächlich zum alten Eisen und fallen in absehbarer Zeit endgültig weg. Die mysqli-Funktionen nicht. Ob mysqli oder PDO ist zunächst mal eine Frage der persönlichen Präferenzen; wenn man sich für eine der beiden Möglichkeiten entscheidet, sollte man sie aber auch "richtig" nutzen.

                        Ja das stimmt, ich übertreibe manchmal ein wenig. Aber alles schreitet vorran und jemand der das aus Spaß anfängt, hat keine Ahnung ob das was er sich versucht anzueignen sinnvoll oder Blödsinn ist weil er ja eben keine Ahnung hat. Gut darüber bin ich denk ich mittlerweile hinaus, trotzdem weiss ich das ich das ihr und viele andere einfach mehr Ahnung haben und ich versuche mich an eure tipss und Anregungen zu halten.

                        Warum mysql oder mysqli wenn PDO das maß der dinge ist.

                        Nein, das ist eben nicht so. Das ist eher vergleichbar mit der Frage "VW oder Opel". Wenn der Fuhrpark bisher ausschließlich VW-Fahrzeuge vorhält und sämtliche Serviceverträge mit VW ausgehandelt sind, ist es nicht sinnvoll, wegen eines bestimmten technischen Merkmals plötzlich einen Opel anzuschaffen.

                        Ja wie gesagt übertreibe ich manchmal etwas, Sry. Danke für deine Antwort!

                        Gruß Jo

                        1. Hi,

                          Irgendwer, sagte das letztens zu mir das ich flexbox benutzen sollte. Ich meine sogar das du derjenige warst.

                          sicher nicht, das musst du wohl verwechseln. Denn ich bin selbst noch nicht wirklich vertraut damit. Und etwas, das ich selbst nicht beherrsche, würde ich auch nicht jemand anderem empfehlen.

                          vorran

                          Autsch. Gute Besserung.

                          So long,
                           Martin

                          --
                          Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
                          - Douglas Adams, The Hitchhiker's Guide To The Galaxy
                          1. Hey,

                            Irgendwer, sagte das letztens zu mir das ich flexbox benutzen sollte. Ich meine sogar das du derjenige warst.

                            sicher nicht, das musst du wohl verwechseln. Denn ich bin selbst noch nicht wirklich vertraut damit. Und etwas, das ich selbst nicht beherrsche, würde ich auch nicht jemand anderem empfehlen.

                            Sry Mein Fehler Das war Matthias. Danke nochmal dafür! Das vereinfacht vieles!

                            vorran

                            Autsch. Gute Besserung.

                            Danke :)

                            Gruß
                            Jo

                    2. Lieber j4nk3y,

                      Das wär äußerst großzügig. aber auch da müsste ich jetzt jeden der mittlerweile sicher 250 querys umschreiben. Und eine wirkliche Vereinfachung seh ich da auf anhieb nicht. Mit mysqli sehe ich auch direkt was wie wo rein oder aus der DB geht/kommt.

                      naja, ob Du mysqli oder PDO nimmst, das werkelt nur im Hintergrund. Was Du im Vordergrund nutzen möchtest, ist eine Abstraktionsschicht. Im Grunde willst Du überhaupt nicht mit SQL hantieren. Du willst eigentlich (auch wenn Du das noch nicht wusstest) mit Objekten hantieren.

                      Wie wäre es, wenn Du folgende Konstrukte nutzen könntest?

                      // Dein Datenbank-Krimskrams befindet sich in der Klasse Chat:
                      $c = new Chat();
                      
                      // Du benötigst User-Objekte, die von Chat erzeugt werden können:
                      $user = $c->find_user($_POST['user']); // User-Objekt
                      $user->post($_POST['message']); // erzeugt einen neuen Chat-Beitrag
                      
                      // Du benötigst Message-Objekte, die von Chat erzeugt werden können:
                      $m = $c->get_latest_message(); // Message-Objekt
                      $array = $c->get_latest_10_messages(); // Array mit Message-Objekten
                      
                      // Ein Message-Objekt kann verschiedene Dinge.
                      $m->display(); // generiert HTML-Code um diesen darzustellen
                      

                      P.S. Ich seh mich ja schon fast wieder von vorne Anfangen...-.- Und ich will nicht :(

                      Dann hast Du im Vorfeld zu wenig überlegt, wie es gehen muss.

                      Liebe Grüße,

                      Felix Riesterer.

                      1. Lieber j4nk3y,

                        Das wär äußerst großzügig. aber auch da müsste ich jetzt jeden der mittlerweile sicher 250 querys umschreiben. Und eine wirkliche Vereinfachung seh ich da auf anhieb nicht. Mit mysqli sehe ich auch direkt was wie wo rein oder aus der DB geht/kommt.

                        naja, ob Du mysqli oder PDO nimmst, das werkelt nur im Hintergrund. Was Du im Vordergrund nutzen möchtest, ist eine Abstraktionsschicht. Im Grunde willst Du überhaupt nicht mit SQL hantieren. Du willst eigentlich (auch wenn Du das noch nicht wusstest) mit Objekten hantieren.

                        Genau. Idealerweise haben diese Objekte sowohl im Browser/JavaScript als auch serverseitig/PHP genau dieselbe Struktur und dieselben Methoden (namentlich). D.h., auf diese Art und Weise wird der Transport ebenfalls transparent. Egal ob der Transport per HTTP oder Socket erfolgt, diese Schicht ist dann durchsichtig und die API ist nur noch eine Methode.

                      2. Lieber Felix,

                        Was Du im Vordergrund nutzen möchtest, ist eine Abstraktionsschicht.

                        Was will ich?

                        Im Grunde willst Du überhaupt nicht mit SQL hantieren.

                        Und wie schreibe ich dann in die Datenbank?

                        Du willst eigentlich (auch wenn Du das noch nicht wusstest) mit Objekten hantieren.

                        Und was bringt mir das?

                        Wie wäre es, wenn Du folgende Konstrukte nutzen könntest?

                        // Dein Datenbank-Krimskrams befindet sich in der Klasse Chat:
                        $c = new Chat();
                        
                        // Du benötigst User-Objekte, die von Chat erzeugt werden können:
                        $user = $c->find_user($_POST['user']); // User-Objekt
                        $user->post($_POST['message']); // erzeugt einen neuen Chat-Beitrag
                        
                        // Du benötigst Message-Objekte, die von Chat erzeugt werden können:
                        $m = $c->get_latest_message(); // Message-Objekt
                        $array = $c->get_latest_10_messages(); // Array mit Message-Objekten
                        
                        // Ein Message-Objekt kann verschiedene Dinge.
                        $m->display(); // generiert HTML-Code um diesen darzustellen
                        

                        Da kommt aber nichts aus der Datenbank? Verstehe nicht was das bringt?

                        P.S. Ich seh mich ja schon fast wieder von vorne Anfangen...-.- Und ich will nicht :(

                        Dann hast Du im Vorfeld zu wenig überlegt, wie es gehen muss.

                        Na das Glaub ich nicht, ich habe mir schon viele Gedanken gemacht. Nur eben auf dem Niveau bzw mit den Mitteln die ich kann.

                        Gruß
                        Jo

                        1. Tach!

                          Was Du im Vordergrund nutzen möchtest, ist eine Abstraktionsschicht.

                          Was will ich?

                          Du möchtest sozusagen, dass du dich nicht in die Niederungen der Datenbankprogrammierung begeben und das immer wieder programmieren musst, vor allem nicht bei Standardvorgängen. Stattdessen möchtest du auf einem höheren Niveau die Daten übergeben und die "Drecksarbeit" delegieren.

                          Im Grunde willst Du überhaupt nicht mit SQL hantieren.

                          Und wie schreibe ich dann in die Datenbank?

                          Du lässt schreiben.

                          Du willst eigentlich (auch wenn Du das noch nicht wusstest) mit Objekten hantieren.

                          Und was bringt mir das?

                          Übersichtlichkeit, wenn man es richtig macht. Natürlich muss man auch unter der Haube alles ausprogrammieren. Aber man kann viele nebensächlichen Dinge aus dem eigentlichen Programmfluss heraushalten. Es ist ja so, dass du eine Hauptaufgabe hast, die erledigt werden soll. Dazu kommen aber eine Menge kleinere Hilfsarbeiten. Und wenn du alles in einem Geradeaus-Script stehen hast, dann ist das schwerer zu überblicken. Deswegen ist es auch wichtig, das man seine Aufgabe in kleine selbständige Einheiten herunterbrechen kann, die man dann auslagern kann.

                          Um dieses Ideal zu erreichen, muss man aber auch eine Menge Erfahrung gesammelt haben. Ich sehe ja, dass es dir schwerfällt, möchte dich nun auch nicht zu etwas drängen, was dir noch mehr Probleme bereitet. Aber zumindest erklären kann man ja mal versuchen.

                          Wie wäre es, wenn Du folgende Konstrukte nutzen könntest?

                          [...]

                          Da kommt aber nichts aus der Datenbank? Verstehe nicht was das bringt?

                          Doch, da kommt was, nur nicht direkt, sondern es ist versteckt, weil das nebensächliche Dinge sind. Die Hauptaufgabe kann man eigentlich auch in dieser Kurzform beschreiben. Es ist ungefähr so, wie wenn du jemanden bittest, dir einen Kaffee zu machen. Das sagst du auch in einem Satz und beschreibst nicht jede Einzelheit des Zubereitens. Jedenfalls nicht immer wieder, sondern höchstens einmal, wenn der Gebetene neu ist.

                          P.S. Ich seh mich ja schon fast wieder von vorne Anfangen...-.- Und ich will nicht :(

                          Dann hast Du im Vorfeld zu wenig überlegt, wie es gehen muss.

                          Na das Glaub ich nicht, ich habe mir schon viele Gedanken gemacht. Nur eben auf dem Niveau bzw mit den Mitteln die ich kann.

                          Es ist ja auch schwer, wenn man die Möglichkeiten nicht kennt, sie hinreichend genau im Voraus zu planen.

                          dedlfix.

                          1. Moin,

                            Du möchtest sozusagen, dass du dich nicht in die Niederungen der Datenbankprogrammierung begeben und das immer wieder programmieren musst, vor allem nicht bei Standardvorgängen. Stattdessen möchtest du auf einem höheren Niveau die Daten übergeben und die "Drecksarbeit" delegieren.

                            Trotzdem muss ich auch Bei PDO jedes Statement vorbereiten und denen dann die Daten übermitteln. Ich glaube nicht, das ich irgendwo 2 gleiche Statements habe, und wenn es mir auffallen sollte, dann suche ich nach einer Möglichkeit das zentral zu machen.

                            Im Grunde willst Du überhaupt nicht mit SQL hantieren.

                            Und wie schreibe ich dann in die Datenbank?

                            Du lässt schreiben.

                            Ähm, mir ist klar, dass nicht ich in die Datenbank schreibe sondern ein mysqli/PDO Statement. Außer natürlich Jemand erklärt sich bereit in meine Datenbank zu schreiben.

                            Du willst eigentlich (auch wenn Du das noch nicht wusstest) mit Objekten hantieren.

                            Und was bringt mir das?

                            Übersichtlichkeit, wenn man es richtig macht. Natürlich muss man auch unter der Haube alles ausprogrammieren. Aber man kann viele nebensächlichen Dinge aus dem eigentlichen Programmfluss heraushalten. Es ist ja so, dass du eine Hauptaufgabe hast, die erledigt werden soll. Dazu kommen aber eine Menge kleinere Hilfsarbeiten. Und wenn du alles in einem Geradeaus-Script stehen hast, dann ist das schwerer zu überblicken. Deswegen ist es auch wichtig, das man seine Aufgabe in kleine selbständige Einheiten herunterbrechen kann, die man dann auslagern kann.

                            Das ist nichts anderes als ich im Moment auch mache. Genau so. Ich unterteile mir die Aufgaben und lagere das aus.

                            Um dieses Ideal zu erreichen, muss man aber auch eine Menge Erfahrung gesammelt haben. Ich sehe ja, dass es dir schwerfällt, möchte dich nun auch nicht zu etwas drängen, was dir noch mehr Probleme bereitet. Aber zumindest erklären kann man ja mal versuchen.

                            Gerne, ich denke nicht das ich total Erkenntnisresistent bin.

                            Wie wäre es, wenn Du folgende Konstrukte nutzen könntest?

                            [...]

                            Da kommt aber nichts aus der Datenbank? Verstehe nicht was das bringt?

                            Doch, da kommt was, nur nicht direkt, sondern es ist versteckt, weil das nebensächliche Dinge sind. Die Hauptaufgabe kann man eigentlich auch in dieser Kurzform beschreiben. Es ist ungefähr so, wie wenn du jemanden bittest, dir einen Kaffee zu machen. Das sagst du auch in einem Satz und beschreibst nicht jede Einzelheit des Zubereitens. Jedenfalls nicht immer wieder, sondern höchstens einmal, wenn der Gebetene neu ist.

                            Richtig. Aber ob das Statement nun in mysqli oder PDO in dieser Datei oder in einer anderen liegt und ausgeführt werden soll ist letztendlich egal, oder nicht?

                            Es ist ja auch schwer, wenn man die Möglichkeiten nicht kennt, sie hinreichend genau im Voraus zu planen.

                            Darum meine ich, ein Tutorial was da ansetzt was den Stand der möglichkeiten darstellt wäre besser als eines welches das nicht tut.

                            Gruß
                            Jo

                            1. Tach!

                              Du möchtest sozusagen, dass du dich nicht in die Niederungen der Datenbankprogrammierung begeben und das immer wieder programmieren musst, vor allem nicht bei Standardvorgängen. Stattdessen möchtest du auf einem höheren Niveau die Daten übergeben und die "Drecksarbeit" delegieren.

                              Trotzdem muss ich auch Bei PDO jedes Statement vorbereiten und denen dann die Daten übermitteln. Ich glaube nicht, das ich irgendwo 2 gleiche Statements habe, und wenn es mir auffallen sollte, dann suche ich nach einer Möglichkeit das zentral zu machen.

                              Die meisten (gefühlte Statistik) Datenbankvorgänge sind 1:1-Vorgänge aus der Abteilung RUDI oder auch CRUD. RUDI heißt Read, Update, Delete, Insert. CRUD ist dasselbe, nur dass es da Create statt Insert heißt (und ist die am häufigsten zu findende Variante). Für diese Standardvorgänge reicht im Prinzip, wenn man einen Tabellennamen und ID im Falle von Read und Delete übergibt und einen Datensatz zurückbekommt (außer bei Delete). Für Create/Insert und Update übergibt man ein Objekt oder ein assoziatives Array und bekommt die Daten des geschriebenen Satzes zurück (kann ja um auto_increment und nicht angegebene Standard-Values ergänzt worden sein). Diese Standardvorgänge will man nicht immer wieder neu formulieren. Die Statements sehen immer gleich aus, nur Tabellenname und die Anzahl und Namen der Felder änderen sich. Deswegen schreibt man sich am besten einen ganz allgemein gehaltenen CRUD/RUDI-Handler und hat dann für all seine 08/15-Datenbankzugriffe eine komfortable Verwendung, indem man einfach nur die reinen Daten an eine der vier Methoden/Funktionen übergibt.

                              Im Grunde willst Du überhaupt nicht mit SQL hantieren.

                              Und wie schreibe ich dann in die Datenbank?

                              Du lässt schreiben.

                              Ähm, mir ist klar, dass nicht ich in die Datenbank schreibe sondern ein mysqli/PDO Statement. Außer natürlich Jemand erklärt sich bereit in meine Datenbank zu schreiben.

                              Ich meinte nicht, dass du dir jemanden suchen sollst, sondern das Datenbank-Handling gemäß dem obigen Absatz abstrahierst, so dass du nur noch zum Beispiel
                              geschriebener_datensatz = create(tabellenname, datenobject_oder_array);
                              aufrufen musst.

                              Aber ob das Statement nun in mysqli oder PDO in dieser Datei oder in einer anderen liegt und ausgeführt werden soll ist letztendlich egal, oder nicht?

                              Ja, Hauptsache es ist richtig implementiert, so dass es nicht anfällig gegen SQL-Injection ist, beispielsweise.

                              dedlfix.

                              1. Hallo dedlfix,

                                Ich meinte nicht, dass du dir jemanden suchen sollst, sondern das Datenbank-Handling gemäß dem obigen Absatz abstrahierst, so dass du nur noch zum Beispiel
                                geschriebener_datensatz = create(tabellenname, datenobject_oder_array);
                                aufrufen musst.

                                NIH, anyone? Für genau diesen Zweck wurden die ORMs entwickelt. Für PHP dürfte das bekannteste wohl Doctrine sein.

                                LG,
                                CK

                                1. Tach!

                                  Ich meinte nicht, dass du dir jemanden suchen sollst, sondern das Datenbank-Handling gemäß dem obigen Absatz abstrahierst, so dass du nur noch zum Beispiel
                                  geschriebener_datensatz = create(tabellenname, datenobject_oder_array);
                                  aufrufen musst.

                                  NIH, anyone? Für genau diesen Zweck wurden die ORMs entwickelt. Für PHP dürfte das bekannteste wohl Doctrine sein.

                                  Ja, stimmt. Nach dem Beschreiben des Prinzips wollte ich eigentlich noch erwähnen, dass es dafür schon fertige ORMs gibt. Das hab ich aber einfach nur vergessen.

                                  dedlfix.

                  2. Guten Morgen Felix

                    Wäre das ein Deal?

                    Für PDO könnte ich Dir eine klitzekleine Klasse anbieten, die Dir im Hintergrund etwas vereinfacht, sodass Du nur noch folgendes schreiben brauchst (falls Du ansonsten noch nicht objektorientiert PHP schreibst und noch weiter abstrahieren kannst):

                    // Hole aus DB
                    $query = array(
                        'select' => 'SELECT `login`, `pass` FROM `users` WHERE `login`=:login',
                        'params' => array(
                            ':login' => $_POST['login']
                        )
                    );
                    
                    $array = $db->get($query['select'], $query['params']);
                    
                    // Schreibe in DB
                    $query = array(
                        'update' => 'UPDATE `users` SET `pass`=:pass WHERE `login`=:login',
                        'params' => array(
                            ':login' => $_POST['login'],
                            ':pass' => password_hash($_POST['pass'], PASSWORD_DEFAULT)
                        )
                    );
                    
                    $db->send($query['update'], $query['params']);
                    

                    Nagut, dann schreibe ich alles um. Wie wäre dann die Klasse?

                    Mit freundlichem Gruß
                    Jo

                  3. Morgen,

                    Entschuldigung hatte etwas viel mit der Uni zutun und konnte leider nicht weiterarbeiten. Morgen hab ich aber endlich wieder einen Tag frei und kann mich ans Werk machen.

                    Lieber Felix,

                    Für PDO könnte ich Dir eine klitzekleine Klasse anbieten, die Dir im Hintergrund etwas vereinfacht, sodass Du nur noch folgendes schreiben brauchst:

                    Also generell übergebe ich an die PDO-klasse nur ein Array der Form:

                     
                    $query = array(
                        'select' => 'MySQL-Statement',
                        'params' => array(
                            ':var' => $_POST['var'],
                     	':var2' => '$var2'
                        )
                    );
                     
                    $array = $db->get($query['select'], $query['params']);
                    
                    

                    Oder? Woher kommen die funktion get() bzw. send() [aus deiner Antwort], ich finde diese nicht im Manual?

                    Wie sieht dann hier die PDO-klasse aus?

                    Lieben Gruß

                    Jo

                    1. Lieber j4nk3y,

                      Für PDO könnte ich Dir eine klitzekleine Klasse anbieten, die Dir im Hintergrund etwas vereinfacht,[...] Woher kommen die funktion get() bzw. send() [aus deiner Antwort], ich finde diese nicht im Manual?

                      natürlich nicht, die gehören ja zu meiner Klasse, die auf PDO aufbaut. Hier für Dich meine Datenbank-Klasse:

                      <?php
                      /**
                       * database handling
                       */
                      
                      class MyPDO {
                      
                        /**
                         * error messages
                         *
                         * @var array
                         */
                        public  $errors;
                      
                        /**
                         * PDO instance
                         *
                         * @var object PDO instance
                         */
                        private $pdo;
                      
                        /**
                         * constructor
                         *
                         * This function needs an array with these keys:
                         * $settings = array(
                         *     'db-host' => (string),
                         *     'db-name' => (string),
                         *     'db-user' => (string),
                         *     'db-pw' => (string)
                         * )
                         *
                         * @param array
                         */
                        public  function __construct ($settings) {
                          $t = $this;
                      
                          $t->errors = array();
                      
                          try {
                      
                            $t->pdo = new PDO(
                              sprintf(
                                'mysql:dbname=%1$s;host=%2$s;charset=UTF8;',
                                $settings['db-name'],
                                $settings['db-host']
                              ),
                              $settings['db-user'],
                              $settings['db-pw'],
                              array(
                                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                                PDO::MYSQL_ATTR_FOUND_ROWS => true,
                                PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'
                              )
                            );
                      
                          } catch (PDOException $e) {
                      
                            $t->errors[] = $t->get_error($e);
                          }
                        }
                      
                        /**
                         * wrapper for PDO::prepare, PDOStatement::execute
                         * and PDOStatement::fetchAll
                         *
                         * This function passes the parameters through to the PDO object.
                         *
                         * @param string SQL
                         * @param array parameters list
                         * @param int column number for PDO::FETCH_COLUMN fetch mode
                         * @return array result sets
                         */
                        public  function get ($sql = '', $params = array(), $col = null) {
                          $t = $this;
                      
                          $r = array();
                      
                          if (empty($sql)) {
                            return $r;
                          }
                      
                          $st = $t->pdo->prepare($sql);
                      
                          try {
                      
                            $st->execute($params);
                      
                            $r = (
                              !is_null($col) && is_numeric($col)
                              ? $st->fetchAll(PDO::FETCH_COLUMN, $col)
                              : $st->fetchAll(PDO::FETCH_ASSOC)
                            );
                      
                          } catch (PDOException $ex) {
                      
                            $t->errors[] = $t->get_error(
                              $ex,
                              array('sql' => $sql, 'params' => $params)
                            );
                          }
                      
                          return $r;
                        }
                      
                        /** function to extract error code information
                         *
                         * @param PDOException object
                         * @param array with SQL query data
                         */
                        private function get_error ($e, $query) {
                          $error = sprintf(
                            'DB returned an error:'."\r\n"
                            . '%1$s'."\r\n"
                            . 'Query:'."\r\n"
                            . '%2$s',
                            $e->getMessage(),
                            print_r($query, true)
                          );
                      
                          return $error;
                        }
                      
                        /**
                         * function to send a query to the DB
                         *
                         * This function passes the parameters through to the PDO object.
                         *
                         * @param string SQL
                         * @param array parameters list
                         * @return int number of affected rows
                         */
                        public  function send ($sql = '', $params = array()) {
                          $t = $this;
                      
                          if (empty($sql)) {
                            return;
                          }
                      
                          $st = null;
                      
                          try {
                      
                            $st = $t->pdo->prepare($sql);
                            $st->execute($params);
                      
                          } catch (PDOException $ex) {
                      
                            $t->errors[] = $t->get_error(
                              $ex,
                              array('sql' => $sql, 'params' => $params)
                            );
                      
                          }
                      
                          if (is_object($st) && method_exists($st, 'rowCount')) {
                            return $st->rowCount();
                          }
                      
                          return 0;
                        }
                      }
                      

                      Wenn Du diese Klasse mit require_once einbindest, dann kannst Du sie so nutzen:

                      <?php
                      
                      // DB-Klasse laden
                      require_once './db-klasse-mit-pdo.php';
                      
                      // Verbindung zur Datenbank aufbauen
                      $db = new MyPDO(array(
                        'db-host' => 'localhost',
                        'db-name' => 'chat',
                        'db-user' => 'j4nk3y',
                        'db-pw'   => 'sehrgeheim'
                      ));
                      
                      // in Datenbank schreiben
                      $db->send(
                        // SQL
                        'INSERT INTO `chatlog` (`message`, `user`) VALUES (:message, :user);',
                        // Parameter für SQL-Platzhalter
                        array(
                          ':message' => 'hey j4nk3y wassup?',
                          ':user' => $_SESSION['login']['user']
                        )
                      ));
                      
                      // von Datenbank lesen
                      $array = $db->get(
                        // SQL
                        'SELECT * FROM `chatlog` WHERE `user`=:user;',
                        // Parameter
                        array(':user' => 'j4nk3y')
                      );
                      

                      Liebe Grüße,

                      Felix Riesterer.

                      1. Tach!

                        Hier für Dich meine Datenbank-Klasse:

                        Ich würde die Fehlerbehandlung aus der Klasse rauslassen. Du fängst sie ab und versteckst sie im Array errors. Wenn man das nicht abfragt, bemerkt man ganz schlecht, wenn es Fehler gibt. Es ist nicht verkehrt, die originale Meldung abzufangen und um eigene Daten zu ergänzen, aber dann sollte sie wieder oder eine neue Exception geworfen werden.

                        In deinem Fall sind die Zusatzdaten aber nicht so super hilfreich, denn es sind exakt die übergebenen Parameter, die innerhalb der Klasse nicht weiter bearbeitet sondern nur 1:1 durchgereicht werden. Die hat man also auch im Hauptprogramm schon vorliegen und kann sie dort ausgeben, oder was immer man machen möchte.

                        dedlfix.

                        1. Morgen,

                          Hier für Dich meine Datenbank-Klasse:

                          Ich würde die Fehlerbehandlung aus der Klasse rauslassen. Du fängst sie ab und versteckst sie im Array errors. Wenn man das nicht abfragt, bemerkt man ganz schlecht, wenn es Fehler gibt. Es ist nicht verkehrt, die originale Meldung abzufangen und um eigene Daten zu ergänzen, aber dann sollte sie wieder oder eine neue Exception geworfen werden.

                          Ich würde $error[] dann in der Klasse aufgreifen und in ein Error-Log file schreiben.

                          Gruß
                          Jo

                          1. Ich würde $error[] dann in der Klasse aufgreifen und in ein Error-Log file schreiben.

                            Der Benutzer sollte in jedem Fall auch eine Meldung bekommen.

                            1. Moin,

                              Ich würde $error[] dann in der Klasse aufgreifen und in ein Error-Log file schreiben.

                              Der Benutzer sollte in jedem Fall auch eine Meldung bekommen.

                              Sicher, aber wohl nicht in dem Umfang wie es dann im Log file für mich steht, damit ich dann auf Fehler suche gehen kann.

                              Gruß
                              Jo

                          2. Tach!

                            Ich würde $error[] dann in der Klasse aufgreifen und in ein Error-Log file schreiben.

                            Dazu brauchst du aber das Array nicht. Außerdem muss auch der aufrufende Kontext informiert werden, dass seine Daten nicht ordnungsgemäß verarbeitet wurden. Nur dort kann entschieden werden, in welcher Form die Information an den Nutzer sinnvoll ist. Technische Details gehen die Anwender ja nichts an. In der Klasse kann das nicht entscheiden werden, ihre universelle Einsetzbarkeit steht einer individuellen Reaktion im Wege.

                            Der Nutzer muss auch nicht in jedem Fall informiert werden, denn es gibt auch Situationen, in denen man ganz bewusst Fehler in Kauf nimmt. Wenn man beispielsweise Daten nur dann eintragen möchte, wenn sie noch nicht vorhanden sind, ist es ungünstig, erst mit einem Select zu prüfen und dann ein Insert nachzuschieben. Es besteht die Wahrscheinlichkeit, dass in der Zwischenzeit ein anderer Prozess schneller war. Das nennt sich TOCTTOU-Problem. Stattdessen setzt man einen Unique-Index und führt einfach sofort das Insert aus. Kein Fehler => alles ok. Unique Constraint Error => Datensatz existiert schon. Das ist ja kein Fehler im eigentlichen Sinne und muss auch nicht mit großem Tamtam dem Anwender angezeigt werden. Ach ja, und für den Fall ist es auch sinnlos, das Logfile zu beschreiben. Ein unbedingtes Logfile-Schreiben in die Klasse einzubauen, ist also auch keine so tolle Idee.

                            dedlfix.

                      2. Guten Morgen Felix,

                        natürlich nicht, die gehören ja zu meiner Klasse, die auf PDO aufbaut. Hier für Dich meine Datenbank-Klasse:

                        Ah, i see.
                        Ich danke dir.

                        Immoment hab ich folgendes für meine Datenbank Verbindung:

                        //Database Login values
                        
                        $db_host = "localhost";
                        $db_user = "root";
                        $db_pass = "";
                        $db_name = "DB";
                        
                        //Database connection
                        
                        $db = @new mysqli($db_host, $db_user, $db_pass);
                        
                        if (!$db->connect_error)
                        {
                        	// Select database
                        	
                        	$select_db = mysqli_select_db($db, $db_name);
                        	
                        	// If database not exist
                        	
                        	if($select_db === FALSE)
                        	{
                        		// Create database
                        		$create_db = "CREATE DATABASE IF NOT EXISTS $db_name DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci";
                        
                        		if ($db->query($create_db))
                        		{
                        			// Create tables
                        			mysqli_select_db($db, "$db_name");
                        			require_once('functions/php/create_tables_function.php');
                        		}
                        		else
                        		{
                        			die("<pre>".$db->connect_error."</pre>");
                        			// error_log! No Database selected
                        		}
                        	}
                        	else
                        	{
                        		$db->query("SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE");
                        		$db->begin_transaction(MYSQLI_TRANS_START_READ_WRITE);
                        	}
                        }
                        else
                        {
                        	//error log! No connection to Database
                        }
                        

                        Sprich, wenn die Datenbank nicht nicht existiert dann lege sie an und erstelle alle nötigen Tabellen. bis jetzt sind das etwa 40 die Teilweise direkt mit Daten gefüttert werden. Wie mach ich das dann mit PDO, einfach nur das SQL-Statement von einem INSERT INTO-Statement zu einem CREATE TABLE-Statement ändern und abflug mit der send() Funktion? Und wie mache ich das mit UPDATE, DROP TABLE und DELETE-Statements? Da diese Statments jaa keine Daten von der Datenbank zurück bekommen einfach die send()-Funktion, oder?

                        Außerdem wird eine Transaktion gestartet, damit alle danach kommenden Statements eben zusammen ausgeführt werden bevor ein anderer Client irgendwas mit der DB machen kann. Grundlegend kann ich eine Transaction für PDO ja mit public bool PDO::beginTransaction ( void ) starten und mit PDO::commit() respektive PDO::rollBack() beenden. Aber wie füge ich das dann in die Klasse ein?

                        Und wie escape ich da richtig?

                        // in Datenbank schreiben
                        $db->send(
                          // SQL
                        sprintf(
                        	'INSERT INTO %s ('
                        	. 'v2, v3, v4'
                        	. ') VALUES ('
                        	. '\'%s\', \'%s\', %f'
                        	. ')',
                        	:v1,
                        	:v2,
                        	:v3,
                        	:v4,,
                          
                        // Parameter für SQL-Platzhalter
                          array(
                            ':v2' => 'string',
                            ':v3' => quote($_POST['v2']),  //??
                            ':v4' => microtime(true),
                          )
                        ));
                        
                        

                        Umgekehrt, das was ich aus der Datenbank zurückbekommen mit get() escape ich weiterhin mit htmlspecialchars() bzw htmlentities().

                        Gruß
                        Jo

                        1. Moin,

                          // in Datenbank schreiben
                          $db->send(
                            // SQL
                          sprintf(
                          	'INSERT INTO %s ('
                          	. 'v2, v3, v4'
                          	. ') VALUES ('
                          	. '\'%s\', \'%s\', %f'
                          	. ')',
                          	:v1,
                          	:v2,
                          	:v3,
                          	:v4,,
                            
                          // Parameter für SQL-Platzhalter
                            array(
                              ':v2' => 'string',
                              ':v3' => quote($_POST['v2']),  //??
                              ':v4' => microtime(true),
                            )
                          ));
                          

                          ich habe bisher keinen Schimmer von der PDO-Schnittstelle, aber das kann nicht richtig sein. Weder der Doppelpunkt vor einigen Argumenten, noch ein doppeltes Komma in der Parameterliste. Das ergibt einen PHP-Syntaxfehler.
                          Und ein Array einfach so in einen String-Kontext auszugeben, produziert nur den Text "array", aber nicht die darin enthaltenen Werte.

                          Umgekehrt, das was ich aus der Datenbank zurückbekommen mit get() escape ich weiterhin mit htmlspecialchars() bzw htmlentities().

                          Natürlich (und bevorzugt ersteres). Damit hat die Datenbank ja nichts zu tun.

                          So long,
                           Martin

                          --
                          Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
                          - Douglas Adams, The Hitchhiker's Guide To The Galaxy
                        2. Lieber j4nk3y,

                          Sprich, wenn die Datenbank nicht nicht existiert dann lege sie an und erstelle alle nötigen Tabellen. bis jetzt sind das etwa 40 die Teilweise direkt mit Daten gefüttert werden.

                          wenn Du Deinen Chat auf Deiner Seite am laufen hast, wie oft wird es wohl vorkommen, dass Du die Datenbank neu erstellen musst? Genau, niemals! Um eine DB einzurichten, verwende ich phpMyAdmin, ein Tool, welches auch viele Webhoster ihren Kunden zur DB-Administration anbieten. Dann ist die DB eingerichtet und meine Software kann loslegen.

                          Du könntest eine Art install.php-Script bereitstellen, welches vor einer ersten Benutzung die Datenbank tatsächlich einrichtet - aber nur ihre Tabellen. Die DB selbst musst Du bei einem "Shared Webhosting" zusammen mit dem DB-Benutzer vorher schon bereitgestellt haben.

                          Außerdem wird eine Transaktion gestartet,

                          Meine Klasse ist nicht für Transaktionen entwickelt worden.

                          Und wie escape ich da richtig?

                          Was war an meinen Beispielen missverständlich? Dort wird nichts escaped, das übernimmt die PDO-Klasse, die von meiner Klasse benutzt wird.

                          Umgekehrt, das was ich aus der Datenbank zurückbekommen mit get() escape ich weiterhin mit htmlspecialchars() bzw htmlentities().

                          Nein, das lässt Du hübsch als "raw"-Format unverändert. Erst wenn Du Daten an einer bestimmten Stelle in einem bestimmten Kontext (z.B. HTML) ausgibst, maskierst Du sie an eben dieser Stelle kontextgerecht. Also:

                          // nicht so:
                          $quark = htmlspechialchars($db->get($query['sql'], $query['params']));
                          echo "<html><head><title>Chat</title></head><body>$quark</body></html>";
                          
                          // sondern so:
                          $data = $db->get($query['sql'], $query['params']);
                          echo "<html><head><title>Chat</title></head><body>",htmlspecialchars($data),"</body></html>";
                          

                          Im Übrigen bin ich immer noch der Meinung, dass Du für Deinen Chat besser Objekte entwirfst, die (ähnlich wie MyPDO den Umgang mit PDO etwas vereinfacht) in Deinem Programm diverse Vorgänge vereinfachen.

                          Stellen wir uns doch einmal einen User vor. Was hat der und was kann der?

                          class ChatUser {
                            // Eigenschaften
                            private $email;
                            private $login;
                            private $pw;
                          
                            // Methoden
                            public  function __construct ($db_data) {} // Konstruktor-Funktion, nimmt DB-Daten auf
                            public  function change_email () {}
                            public  function change_pw () {}
                            public  function login () {}
                            public  function logout () {}
                            private function save_data () {} // wird von change_email und change_pw benötigt
                            public  function send_message () {}
                          }
                          

                          Die Methoden change_email und change_pw nutzen intern die Methode save_data, welche z.B. mit MyPDO (oder etwas völlig anderem - egal) den Datenabgleich mit der DB regelt. Möchte sich ein User z.B. bei Deinem Chat anmelden (z.B. example.org/chat/login), so lädt Dein Haupt-Script alle DB-Einträge aus der DB, deren Login-Namen dem gePOSTeten Wert entsprechen und erstellt daraus ChatUser-Objekte. Diese dürfen dann der Reihe nach ihre login-Methode ausführen, um einen Login-Vorgang zu testen. Ist er erfolgreich, wird z.B. das ChatUser-Objekt in $_SESSION['user'] gespeichert, um Deiner Anwendung zu signalisieren, dass da ein erfolgreicher Login war.

                          Die Methode send_message hat intern auch wieder Code, der mit der Datenbank interagiert, z.B. die Message in der Tabelle chatlog abzuspeichern.

                          Auf diese Art und Weise modularisierst Du Dein Programm mit Objekten, um im Hauptprogramm dann mit diesen zu operieren.

                          Liebe Grüße,

                          Felix Riesterer.

                          1. Hallo,

                            Umgekehrt, das was ich aus der Datenbank zurückbekommen mit get() escape ich weiterhin mit htmlspecialchars() bzw htmlentities().

                            Nein, das lässt Du hübsch als "raw"-Format unverändert. Erst wenn Du Daten an einer bestimmten Stelle in einem bestimmten Kontext (z.B. HTML) ausgibst, maskierst Du sie an eben dieser Stelle kontextgerecht.

                            so hatte ich ihn auch verstanden, deshalb überrascht mich dein vehementes "Nein".

                            // nicht so:
                            $quark = htmlspechialchars($db->get($query['sql'], $query['params']));
                            echo "<html><head><title>Chat</title></head><body>$quark</body></html>";
                            
                            // sondern so:
                            $data = $db->get($query['sql'], $query['params']);
                            echo "<html><head><title>Chat</title></head><body>",htmlspecialchars($data),"</body></html>";
                            

                            Das ist didaktisch absolut richtig, aber in der Sache nur bedingt relevant. Wenn $quark etwa ausschließlich dazu dienen soll, den Wert zu speichern, um ihn an mehreren Stellen in HTML einzubauen und auszugeben, würde ich die erste Variante auch abnicken - wenn auch mit dem Hinweis: "Aber denk dran, ..."

                            So long,
                             Martin

                            --
                            Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
                            - Douglas Adams, The Hitchhiker's Guide To The Galaxy
                            1. Tach!

                              // nicht so:
                              $quark = htmlspechialchars($db->get($query['sql'], $query['params']));
                              echo "<html><head><title>Chat</title></head><body>$quark</body></html>";
                              

                              Das ist didaktisch absolut richtig, aber in der Sache nur bedingt relevant. Wenn $quark etwa ausschließlich dazu dienen soll, den Wert zu speichern, um ihn an mehreren Stellen in HTML einzubauen und auszugeben, würde ich die erste Variante auch abnicken - wenn auch mit dem Hinweis: "Aber denk dran, ..."

                              Auch dann würde ich das so nicht tun. Man kann den $quark für die Ausgabe vorbereiten, doch dann läuft man Gefahr, dass man einen Mischmasch erzeugt. Einige Werte sind schon vorbereitet, andere müssen noch beim Einfügen in die Ausgabe aufbereitet werden. Ist sowas denn einfach zu durchschauen und zu warten? Ich habe da meine Zweifel. Aber wie auch immer, selbst wenn man das so machen möchte, dann sollte man als Zeitpunkt nicht die Abfrage der Daten aus dem DBMS nehmen, sondern das Vorbereiten der Ausgabe.

                              dedlfix.

                          2. Lieber Felix,

                            Sprich, wenn die Datenbank nicht nicht existiert dann lege sie an und erstelle alle nötigen Tabellen. bis jetzt sind das etwa 40 die Teilweise direkt mit Daten gefüttert werden.

                            wenn Du Deinen Chat auf Deiner Seite am laufen hast, wie oft wird es wohl vorkommen, dass Du die Datenbank neu erstellen musst? Genau, niemals!

                            Das ist richtig. Aber es geht ja nicht nur um den Chat das ist nur eine kleine Funktion die nichtmal 0,1% am gesamten Projekt ausmacht.

                            Um eine DB einzurichten, verwende ich phpMyAdmin, ein Tool, welches auch viele Webhoster ihren Kunden zur DB-Administration anbieten. Dann ist die DB eingerichtet und meine Software kann loslegen.

                            Nutze ich auch. Aber da ich häufiger meine Datenbank lösche und wieder neu einrichte, habe ich ganz am Anfang beschloßen das per php zu erledigen.

                            Du könntest eine Art install.php-Script bereitstellen, welches vor einer ersten Benutzung die Datenbank tatsächlich einrichtet - aber nur ihre Tabellen. Die DB selbst musst Du bei einem "Shared Webhosting" zusammen mit dem DB-Benutzer vorher schon bereitgestellt haben.

                            Darauf sollte es hinaus laufen.

                            Außerdem wird eine Transaktion gestartet,

                            Meine Klasse ist nicht für Transaktionen entwickelt worden.

                            Dann kann ich die nicht nutzen. Die sind zwingend erforderlich, sonst kommt es zu Fehlern.

                            Und wie escape ich da richtig?

                            Was war an meinen Beispielen missverständlich? Dort wird nichts escaped, das übernimmt die PDO-Klasse, die von meiner Klasse benutzt wird.

                            Hm, achso ok. Danke.

                            Nein, das lässt Du hübsch als "raw"-Format unverändert. Erst wenn Du Daten an einer bestimmten Stelle in einem bestimmten Kontext (z.B. HTML) ausgibst, maskierst Du sie an eben dieser Stelle kontextgerecht. Also:

                            // nicht so:
                            $quark = htmlspechialchars($db->get($query['sql'], $query['params']));
                            echo "<html><head><title>Chat</title></head><body>$quark</body></html>";
                            
                            // sondern so:
                            $data = $db->get($query['sql'], $query['params']);
                            echo "<html><head><title>Chat</title></head><body>",htmlspecialchars($data),"</body></html>";
                            

                            Nichts anderes meinte ich.

                            Im Übrigen bin ich immer noch der Meinung, dass Du für Deinen Chat besser Objekte entwirfst, die (ähnlich wie MyPDO den Umgang mit PDO etwas vereinfacht) in Deinem Programm diverse Vorgänge vereinfachen.

                            Stellen wir uns doch einmal einen User vor. Was hat der und was kann der?

                            class ChatUser {
                              // Eigenschaften
                              private $email;
                              private $login;
                              private $pw;
                            
                              // Methoden
                              public  function __construct ($db_data) {} // Konstruktor-Funktion, nimmt DB-Daten auf
                              public  function change_email () {}
                              public  function change_pw () {}
                              public  function login () {}
                              public  function logout () {}
                              private function save_data () {} // wird von change_email und change_pw benötigt
                              public  function send_message () {}
                            }
                            

                            Die Methoden change_email und change_pw nutzen intern die Methode save_data, welche z.B. mit MyPDO (oder etwas völlig anderem - egal) den Datenabgleich mit der DB regelt. Möchte sich ein User z.B. bei Deinem Chat anmelden (z.B. example.org/chat/login), so lädt Dein Haupt-Script alle DB-Einträge aus der DB, deren Login-Namen dem gePOSTeten Wert entsprechen und erstellt daraus ChatUser-Objekte. Diese dürfen dann der Reihe nach ihre login-Methode ausführen, um einen Login-Vorgang zu testen. Ist er erfolgreich, wird z.B. das ChatUser-Objekt in $_SESSION['user'] gespeichert, um Deiner Anwendung zu signalisieren, dass da ein erfolgreicher Login war.

                            Die Methode send_message hat intern auch wieder Code, der mit der Datenbank interagiert, z.B. die Message in der Tabelle chatlog abzuspeichern.

                            Auf diese Art und Weise modularisierst Du Dein Programm mit Objekten, um im Hauptprogramm dann mit diesen zu operieren.

                            Das hört sich alles schön und gut an, nur kann ich das nicht umsetzen weil ich mich wie gesagt in Objektorientiertem php nicht auskenne, keine Übung habe und auch nicht sehe welche vorteile das für mich hat. Objektorientiertes php ist für mich einfach komplizierter bzw. unübersichtlicher als das was ich derzeit mache.

                            Liebe Grüße,
                            Jo

                            1. Hallo,

                              Das hört sich alles schön und gut an, nur kann ich das nicht umsetzen weil ich mich wie gesagt in Objektorientiertem php nicht auskenne, keine Übung habe und auch nicht sehe welche vorteile das für mich hat. Objektorientiertes php ist für mich einfach komplizierter bzw. unübersichtlicher als das was ich derzeit mache.

                              objektorientierte Programmierung ist nicht schwieriger oder einfacher als konventionelle, prozedurale Programmierung - sie ist anders. Sie erfordert eine etwas andere Denkweise, weil nicht eine lineare Abfolge von Anweisungen im Vordergrund steht, sondern die Daten selbst und was mit ihnen passiert. Daten werden sinnvoll zu Objekten zusammengefasst, die ihre eigenen Fähigkeiten ("Methoden") mitbringen.

                              Ob OOP für ein bestimmtes Projekt einen Vorteil bringt, muss man im Einzelfall beurteilen; mehrere Programmierer kommen dabei oft auch zu unterschiedlichen Urteilen, weil es natürlich auch auf die Gewohnheit und Routine ankommt.

                              In großen Projekten mit vielen gleichartigen oder ähnlich gestrickten Objekten kann OOP sehr günstig sein und das Prokekt sogar übersichtlicher (auf jeden Fall aber modularer) machen; bei kleineren Projekten überwiegt vielleicht der OOP-bedingte Overhead.

                              So long,
                               Martin

                              --
                              Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
                              - Douglas Adams, The Hitchhiker's Guide To The Galaxy
                              1. Hallo,

                                objektorientierte Programmierung ist nicht schwieriger oder einfacher als konventionelle, prozedurale Programmierung - sie ist anders.

                                Ja, das verstehe ich schon. Ich sage ja nur, dass ich mit Objektorientierter programmierung eben im Moment nicht umgehen kann.

                                mehrere Programmierer kommen dabei oft auch zu unterschiedlichen Urteilen, weil es natürlich auch auf die Gewohnheit und Routine ankommt.

                                Genau, und meine Routine ist eben nicht das OOP.

                                Gruß
                                Jo

    2. Hey,

      Hab da nochmal ne doofe Frage:

      <?php
      if(!empty($friends_list)):
      foreach($friends_list as $friends):
      	$friend = explode("_", $friends);
      ?>
      
      	<option value="<?php echo "private_".$friends?>"><?php echo $friend[1]?></option>
      <?php
      endforeach;
      endif;
      ?>
      

      Warum wird <option... > ausgegeben wenn $friends_list leer ist?
      Ich bekomme nämlich ein Undefined offset: 1 für das $friend[1].

      Gruß
      Jo

      1. Tach!

        Warum wird <option... > ausgegeben wenn $friends_list leer ist?

        Anscheinend entspricht der Inhalt von $friends_list nicht der Definition von empty. var_dump($friends_list) kann helfen die Situation zu analysieren.

        dedlfix.

        1. Morgen,

          Warum wird <option... > ausgegeben wenn $friends_list leer ist?

          Anscheinend entspricht der Inhalt von $friends_list nicht der Definition von empty. var_dump($friends_list) kann helfen die Situation zu analysieren.

          Anscheinend gibt explode(",", "");
          array{[0]=> "" [1]=>""} zurück.

          Gruß
          Jo

          1. Hallo j4nk3y,

            Anscheinend gibt explode(",", "");
            array{[0]=> "" [1]=>""} zurück.

            Definitiv nein:

            → ckruse@sunshine ~  % php -r 'var_dump(explode(",", ""));'
            array(1) {
              [0]=>
              string(0) ""
            }
            

            LG,
            CK

            1. Hallo j4nk3y,

              Anscheinend gibt explode(",", "");
              array{[0]=> "" [1]=>""} zurück.

              Definitiv nein:

              → ckruse@sunshine ~  % php -r 'var_dump(explode(",", ""));'
              array(1) {
                [0]=>
                string(0) ""
              }
              

              Es liefert aber ein nicht leeres Array zurück. Ich hab meine Ausgabe nicht mehr die sah ähnlich aus wie das hier array{[0]=> "" [1]=>""}, vielleicht nich genau so.

              Gruß
              Jo

              1. Hallo j4nk3y,

                Es liefert aber ein nicht leeres Array zurück.

                Klar. Ein leerer String, getrennt bei einem Komma, gibt wieder einen leeren String und deshalb gibt explode() - richtigerweise - einen Array mit einem Element zurück, das einen leeren String enthält.

                LG,
                CK

              2. Hallo j4nk3y,

                es wäre für die Lesbarkeit deiner Beiträge und damit der gesamten Diskussion sehr hilfreich, wenn du (wie du das hier von fast allen anderen siehst) die Beiträge, auf die du antwortest, um mehr als nur die Anrede und Verabschiedung kürzt. Es ist nicht notwendig, so große Teile des Vorpostings zu zitieren. Das stört nur den Lesefluss und man muss sich dann trotzdem wieder die „richtige“ Stelle heraussuchen. Zitiere bitte nur das, worauf du dich konkret beziehst. Damit erhöhst du auch deine Chancen auf zielführende Unterstützung, weil es für potentielle Helfer weniger anstrengend ist, der Diskussion zu folgen.

                Bis demnächst
                Matthias

                --
                Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
                1. Hey,

                  es wäre für die Lesbarkeit deiner Beiträge und damit der gesamten Diskussion sehr hilfreich, wenn du die Beiträge, auf die du antwortest, um mehr als nur die Anrede und Verabschiedung kürzt.

                  Werde ich machen.

                  Gruß Jo