PHP Checkboxen per POST versenden und verarbeiten

_CH_K_1991_

Lieutenant
Registriert
Nov. 2008
Beiträge
772
Hallo zusemmen

Ich bin momentan an einer relative komplexen Website, auf welcher gewisse Personen Anmeldungen (welche schriftlich gekommen sind) für einen Kongress digital in die Datenbank speichern können.
Es gibt vier verschiedene Berufsgruppen die man anmelden kann.
Jede Berufsgruppe hat als Checkboxen weitere möglichkeiten an verschiedenen Workshops teilzunehmen.
Die Hauptfrage dreht sich jetzt um das Problem, wenn ich in einem Formular mehrere Checkboxen habe...

PHP:
      <input type="checkbox" name="ha-1" value="3">WS 1<br>
      <input type="checkbox" name="ha-2" value="4">WS 2<br>
      <input type="checkbox" name="ha-3" value="5">WS 3<br>
      <input type="checkbox" name="ha-8" value="22">WS 4<br>
      <input type="checkbox" name="ha-4" value="7">WS 5<br>
      <input type="checkbox" name="ha-5" value="8">WS 6<br>
Die Value entspricht der ProduktID in der Datenbank.

...möchte ich diese beim Absenden so wie unten in ein Array schreiben.

PHP:
if (isset($_POST['ha-0']) && $_POST['ha-0']=='HA')
    {
     $ha = [''];
     $ha[0] = $_POST['ha-1'];
     $ha[1] = $_POST['ha-2'];
     $ha[2] = $_POST['ha-3'];
     $ha[3] = $_POST['ha-4'];
     $ha[4] = $_POST['ha-5'];
     $ha[5] = $_POST['ha-6'];
     $ha[6] = $_POST['ha-7'];
     $ha[7] = $_POST['ha-8'];
     $arrlen = count($ha);

     for ($i=0; $i < $arrlen; $i++)
     {
      mysqli_query($con, "INSERT INTO gast_produkt (GID, PID)
       VALUES ((SELECT GID FROM gast WHERE vorname = $vorname AND nachname = $nachname)
        , $ha[$i]");
     }
    }

Das Problem ist nur, wenn eine Checkbox nicht aktiviert wird habe ich das Problem, dass PHP verständlicherweise den Fehler...
Notice: Undefined index
.. ausgibt und der Rest der Aktion abgebrochen wird.

Wie kann ich das einfach umgehen, in anbetracht an die knapp 20 Checkboxen.
Muss ich hier überall eine If (Isset()) Abfrage machen oder gibt es noch andere Möglichkeiten?

Danke für Informationen
Gruss Matthias
 
Das hier dürfte helfen

if(isset($_POST['ha-1']))
$ha[0] = $_POST['ha-1'];​

PHP:
if (isset($_POST['ha-0']) && $_POST['ha-0']=='HA')
    {
     $ha = [''];
     if(isset($_POST['ha-1']))
         $ha[0] = $_POST['ha-1'];
     if(isset($_POST['ha-2']))
         $ha[0] = $_POST['ha-2'];
     if(isset($_POST['ha-3']))
         $ha[0] = $_POST['ha-3'];
     if(isset($_POST['ha-4']))
         $ha[0] = $_POST['ha-4'];
     if(isset($_POST['ha-5']))
         $ha[0] = $_POST['ha-5'];
     if(isset($_POST['ha-6']))
         $ha[0] = $_POST['ha-6'];
     if(isset($_POST['ha-7']))
         $ha[0] = $_POST['ha-7'];
     if(isset($_POST['ha-7']))
         $ha[0] = $_POST['ha-7'];
     $arrlen = count($ha);
 
     for ($i=0; $i < $arrlen; $i++)
     {
      mysqli_query($con, "INSERT INTO gast_produkt (GID, PID)
       VALUES ((SELECT GID FROM gast WHERE vorname = $vorname AND nachname = $nachname)
        , $ha[$i]");
     }
    }

oder
PHP:
if (isset($_POST['ha-0']) && $_POST['ha-0']=='HA')
{
     for ($i = 1; $i <= 8; $i++) {
         if(isset($_POST['ha-'.$i]))
          mysqli_query($con, "INSERT INTO gast_produkt (GID, PID)
            VALUES ((SELECT GID FROM gast WHERE vorname = $vorname AND nachname = $nachname)
            , $_POST['ha-'.$i]");
        }
}
 
Zuletzt bearbeitet:
Und wenn du hier nur Zahlen erwartest kann man das auch noch wunderbar testen bevor man das einfach so in die Datenbank schreibt. Was per Post übertragen wird kann jeder beliebig ändern.

Ganz faul könnte man auch einfach noch ("+ 0") null addieren und somit PHP dazu bringen das ganze in eine Zahl umzuwandeln. Allerdings führt das dann zu "falschen" einträgen.
Besser wäre zu testen ob es Zahlen sind und wenn nicht das zu Reklamieren und keine Eintragung vornehmen.
 
Zuletzt bearbeitet: (Rechtschreibung)
_CH_K_1991_ schrieb:
Muss ich hier überall eine If (Isset()) Abfrage machen oder gibt es noch andere Möglichkeiten?
Du kannst das alles auch einfach als Array übertragen.
Code:
<input type="checkbox" name="workshops[]">
o.ä., dann kannst du einfach per
Code:
is( isset( $_POST['workshops'] ) && is_array( $_POST['workshops'] ) ) // wenn überhaupt was übertragen wurde
    foreach( $_POST['workshops'] as $workshopid )
drüberiterieren.

Falls du was speziferisches brauchst, kannst du natürlich auch ein
Code:
<input type="checkbox" name="workshops[1][]">
<input type="checkbox" name="workshops[2][]">
<input type="checkbox" name="workshops[3][]">
machen.
 
Vll. hilft ja sowas:

Code:
<input name="subselect[]" ...
<input name="subselect[]" ...
<input name="subselect[]" ...

foreach($_POST['subselect'] as $k => $v){

}

ich schmeiß auch nochmal array_keys() und array_key_exists() in den Raum.

Edit: Yuuri war schneller.
 
Zuletzt bearbeitet:
Danke vielmals für die guten Antworten.
Da die von Yuuri am einfachsten aussah, habe ich diese mal ausprobiert und ich glaube die funktioniert auch nicht schlecht ;)
Aber wie soll ich jetzt dieses Query umschreiben?

PHP:
mysqli_query($con, "INSERT INTO gast_produkt (GID, PID)
       VALUES ((SELECT GID FROM gast WHERE vorname = $vorname AND nachname = $nachname)
        , $ha[$i]");

Das gibt nämlich diesen Fehler:

Notice: Undefined offset: 4
und
1064: You have an error in your SQL Syntax... u.s.w.

Danke

EDIT vllt besser mit dem ganzen if Statement
PHP:
if (isset($_POST['ha']) && is_array($_POST['ha']))
    {
     $ha = $_POST['ha'];
     $arrlen = count($ha);
     print_r($ha);
     for ($i=0; $i < $arrlen; $i++)
     {
      mysqli_query($con, "INSERT INTO gast_produkt (GID, PID)
       VALUES ((SELECT GID FROM gast WHERE vorname = $vorname AND nachname = $nachname)
        , $ha[$i]");
     }
    }
 
Man arbeitet bei solchen Sachen besser mit id anstatt Strings. NutzerIDs. Was wenn zwei Nutzer identischen Vor- und Nachname haben?

Code:
$sth = $db->prepare('INSERT INTO gast_produkt ( gid, pid ) 
VALUES ( ( SELECT gid FROM gast WHERE uid = ? ), ? ) ');

foreach ( $_POST['ha'] as &$v ){

    $sth->execute( ( int ) $uid, ( int ) $v );

}
 
Zuletzt bearbeitet:
Hey, Danke für die Antwort.
Das mit der UID ist natürlich richtig, nur ist GID (GastID) die eigentliche Identifikationsnr, welche ich hier wieder auslesen möchte. Ich kann also diese nur über Namen oder Emailadressen aufrufen.
Deshalb nehme ich diesen möglichen Fehler ganz bewusst in Kauf. Oder gibt es eine Variante die letzte ID besser aufzurufen, denn der User wird ein paar Zeilen weiter vorne INSERTet.

Zu deinem Code BSP, bei mir funktioniert das leider nicht, es kommt bei folgendem Code, folgende Meldung:

PHP:
if (isset($_POST['ha']) && is_array($_POST['ha']))
    {
     $ha = $_POST['ha'];
     $arrlen = count($ha);
     for ($i=0; $i < $arrlen; $i++)
     {
      $sth = $con->prepare('INSERT INTO gast_produkt (GID, PID)
       VALUES ((SELECT GID FROM gast WHERE vorname = $vorname AND nachname = $nachname)
        , $v)');
      foreach ($_POST['ha'] as $v)
      {
       $sth->execute(intval($v));
      }
     }
    }

Fatal Error: Call to a member function execute() on a non-object....

Ich habe deinen Code auch schon in diverse andere Variationen umgewandelt, die ich kenne oder wo ich geglaubt habe, dass diese funktionieren könnten.

Danke
 
:D

Was ist bei dir $con...?

Vermutlich identisch mit dem hier?:
mysqli_query($con ...

Das:

$sth->execute(intval($v));

bringt nix wenn das hier :
... $vorname AND nachname = $nachname), $v)');

Da du leider bisher nicht wirklich anwendest was man dir anbietet bin ich weg.

Wenn man sagt foreach dann postest Du einen forloop, sagt man int möchtest Du intval etc... Warum?

Aktuell weiß ich nicht mal ob $_POST['ha'] überhaupt korrekt ist.
 
Zuletzt bearbeitet:
keine Angst îch habe das was du geposstet hast sehr wohl in meinen Code genommen, das hat allerdings nicht funktioniert, weil ich nicht genau verstehe was du mit den Fragezeichen meinst...

$con ist der ConnectionString, da ich mal angenommen habe, dass du mit $db den ConnectionString meinst, weil ich keine Variable habe die $db heist.

Vielleicht bringt und das ja weiter, ich schaue nochmals in den Code.
Gruss
Ergänzung ()

Edit: Huch, jap hier passierte ein Fehler mit der for Schlaufe, die hätte nicht mehr sein dürfen...
Aber trotzdem gelten noch die obrigen Fragen ;)
Danke

Zu deiner letzten Aussage... Hier bekomme ich ein Array zurück das eigentlich richtig aussieht.
Ich denke nicht, das hier der Fehler liegt.

Array ([0] => 3 [1] => 4 [4] => 7 [5] => 8)
 
Zuletzt bearbeitet:
_CH_K_1991_ schrieb:
keine Angst îch habe das was du geposstet hast sehr wohl in meinen Code genommen, das hat allerdings nicht funktioniert, weil ich nicht genau verstehe was du mit den Fragezeichen meinst...
Wenn du nicht weißt was die Fragezeichen sollen, warum liest du dann nicht einfach mal die offizielle Dokumentation zu Prepared Statements? Da stehts gleich im 2. Beispiel:
http://php.net/manual/de/pdo.prepared-statements.php

Evtl. geht dir dann auch ein Licht auf, wie sichere SQL-Anfragen funktionieren und wie man für so etwas SChleifen verwendet.
 
$db ist ein Objekt. Das Fragezeichen ist ein Platzhalter. Das ganze ist ein prepared Statement welches im Loop dann mit verschiedenen Werten gefeuert wird.

Code:
function MySQLConnection(){

  try{

    $user     = 'name';
    $passwd   = 'passwd';
    $database = 'db';
    $host     = '127.0.0.1';

    $optin = array(PDO::MYSQL_ATTR_INIT_COMMAND => " SET NAMES utf8");

    $obj = new PDO("mysql:host={$host};dbname={$database}", $user, $passwd, $optin);
    return $obj;

  } catch (PDOException $p) { /* What to do on error */ }

}

$db = MySQLConnection();

Array ([0] => 3 [1] => 4 [4] => 7 [5] => 8)

Besser wäre es in Deinem Fall so:

Code:
Array ([0] => 3 [1] => 4 [2] => 7 [3] => 8)

Aus:

<input name="ha[id]" ...

Wird:

<input name="ha[]" ...
 
Zuletzt bearbeitet:
Danke für die Antwort...
Nur so, ich kann noch nicht so lang php und zweitens habe ich solch aufgebaute Schleifen noch nie gebraucht, noch wurde mir das je erklärt.
Gruss
 
Du bist niemandem Rechenschaft schuldig.

foreach ist für solche Fälle gedacht.

PS:

Die Funktion oben zum erzeugen des DB Objekts nutzen:

Code:
$db = MySQLConnection();

Vorarbeit:
Code:
try{

  $sth = $db->prepare('INSERT INTO gast_produkt (GID, PID)
  VALUES ((SELECT GID FROM gast WHERE vorname = $vorname AND nachname = $nachname) , ?)');

Danach loopen:
Code:
  foreach( $_POST['ha'] as &$id ){

      // query mit verschiedenen
      // Werten feuern

      $sth->execute( ( int ) $id );

  }

} catch (PDOException $p) { /* What to do on error */ }


PS: try catch in der Funktion zum erzeugen des Objekts ist, glaube ich, unnötig. Aber man weiß ja nie...


PPS: Wie oben mit dem Link zu sessions angedeutet:
gastID = session_id();
http://php.net/manual/de/function.session-id.php
 
Zuletzt bearbeitet:
omaliesschen schrieb:
PS: try catch in der Funktion zum erzeugen des Objekts ist, glaube ich, unnötig. Aber man weiß ja nie...


Hat schon Sinn :) Die Verbindung wird streng genommen bereits durch den Konstruktor-Aufruf hergestellt, was fehlschlagen kann.
 
Hi,

ich war mir nicht ganz sicher. Man lernt immer dazu.

Oben ist ein Fehler drinn. Innerhalb des prepares dürfen die Variablen $vorname,$nachname nicht in der Form eingebunden werden. Das bricht die Sicherheit.

Code:
 $sth = $db->prepare('INSERT INTO gast_produkt (GID, PID)
VALUES ((SELECT GID FROM gast WHERE vorname = ? AND nachname = ?) , ?)');

Und danach:
Code:
$sth->execute( $vorname, $nachname, ( int ) $id );
 
Den Weg find ich sehr... daneben. Die Parameterzahl kann sich immer mal ändern und ebenso die Reihenfolge.
Code:
<?php

$q = $db->prepare( <<<SQL
INSERT INTO gast_produkt (
	GID,
	PID
) VALUES (
	(SELECT GID FROM gast WHERE vorname = :vorname AND nachname = :nachname),
	:pid
)
SQL
);
$q->bindValue( ':vorname', $vorname );
$q->bindValue( ':nachname', $nachname );
$q->bindValue( ':pid', $id, PDO::PARAM_INT );
$q->execute();
Deutlich wartbarer. Ggf. auch bindParam verwenden.
 
omaliesschen schrieb:
Soso, findest Du das also?
Ja, die Begründung steht drunter. Die Wartbarkeit ist dabei komplett fürn Popo, weil du ständig alle Parameter durchzählen musst und wehe du hast mal irgendwo ein Fragezeichen übersehen, dann kommen gleich falsche Daten in die DB usw. Lieber Named Placeholders verwenden, die sind narrensicher.
 
Zurück
Oben