Projekt Mitarbeiter

  • Hey zusammen,

    ich habe jetzt mit einem kleinen Projekt begonnen. Dabei möchte ich das ein Mitarbeiter das Mitarbeiterformular ausfüllt. Dann werden die Daten in die Datenbank gespeichert. Dann möchte ich mittels der id des jeweiligen Mitarbeiters auf einer anderen seite ein link ausgeben (welcher aus den vornamen und nachnamen besteht). Und zum Schluss auf der 3.Seite möchte ich das da die ganzen Daten zu diesem Mitarbeiter ausgegeben werden. Auf allen scripts habe ich verbindung zur datenbank.

    Mein Problem ist das immer nach dem klicken des submit buttons bei der file mitarbeitersuche.php folgende fehlermeldung kommt : Fehler bei Datenbankverbindung: SQLSTATE[HY000] [2002] Es konnte keine Verbindung hergestellt werden, da der Zielcomputer die Verbindung verweigerte.

    Warum ist das denn so ? Ich habe schon nachgeschaut ob password und die verbindungsdaten alle stimmen. Aber die stimmen alle.

    Hoffe ihr könnt mir helfen :)

    Hier ist die file mitarbeitersuche.php:


    Gruß,
    Stef

    Einmal editiert, zuletzt von Stef (6. Januar 2017 um 19:24)

    • Offizieller Beitrag

    Hi,

    Setz die Connection mal so um:

    PHP
    $pdo = new PDO (
            'mysql:host=127.0.0.1;dbname=apple231;charset=utf8','apple231','****',
            array(
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,     
                PDO::ATTR_EMULATE_PREPARES => false,                
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION         
            )
    );


    localhost kann ab PHP5.3+ und der mysqlnd Erweiterung manchmal zu Problemen führen. Über die IP des localhost sollte es dann klappen.

    Diese Zeile kannst Du entfernen:

    PHP
    $pdo->query("SET NAMES 'utf8'");

    Das funktioniert zwar, ist aber die "alte" Variante. Die "moderne" sieht die Verbindungskodierung im DSN vor, siehe oberer Codeblock.

    Gruß Arne

  • Hey,

    ich habe es nun mal geändert. Und nun funktioniert alles. Danke.

    Nun noch eine frage zur Sicherheit. Und zwar wenn jetzt ein "böser" Mitarbeiter javascript code in die text fälder eingiebt und somit eine attacke ausführt wie kann man sich dagegen am besten schützen ?

    ich habe gelesen das man die function htmlspecialchars() verwenden kann. Hab ich jetzt auch gemacht wie folgt:

    Dies erfolgt vor datenbank eintrag.
    Nun wenn ich jetzt über das Formular javascript code absende und auf der 2ten seite den Mitarbeiter mit namen aufrufe als link und dann auf ihn klick wird zwar die user eingabe angegeben (z.b. Mitarbeiter : <script>alert('Hallo Guys');</script> <script>alert('Hallo Guys');</script>) aber nicht ausgeführt. Bei den vorigen test wurde immer der js code ausgeführt. Ist es jetzt dann eigentlich sicher oder immernoch auf diese weise angreifbar ?

    Denn htmlspecialchars() sollte ja sonderzeichen in HTML-Code umwandeln. Hat es aber nicht gemacht.

    EDIT: Habe als Test nochmals mehrere XSS-Attacken durchgeführt (Javascript code in input feld reingeschrieben und abgesendet) und beim aufrufen des namens nach dem suchen klicken wird der JS-code dann ausgeführt. Also hat htmlspecialchars() nix genützt....

    Nochwas: Ich möchte überprüfen ob sucheingabe größer als $row->id ist. Ich habe es wie folgt gemacht:

    PHP
    if($personal_id > $row->id){
                    $error[] = '<p class="error">Bitte eine richtige Mitarbeiternummer angeben!</p>';
    
    
                }

    Nun wird aber bei jeder eingabe der nummer diese Meldung ausgegeben. Ich geh davon aus das $row-> id ja die zahlen 1-14 (momentan enthält als array) und daher immer der error kommt. Aber wie kann man es nun machen das die fehlermeldung erst kommt wenn man eine nummer größer als die letzte id eingibt ?

    Gruß,
    Stef

    7 Mal editiert, zuletzt von Stef (7. Januar 2017 um 14:46)

  • Hi,

    vielen Dank für die Info. Nun klappt es.

    Wenn ich jetzt alle formulareingaben in ein array lege, und dies dann mit filter_input_array() durchfiltere wie kann ich dann die werte in dem array in die db mit den platzhaltern eintragen ?

    Gruß Stef

    • Offizieller Beitrag

    Du kannst doch im Formular direkt Arrays definieren, das mache ich bei eigenen Formularen immer so, bspw:

    HTML
    <input type="text" name="frm[data][]">
    <input type="text" name="frm[data][]">

    Das kannst Du in PHP direkt über $_POST ansprechen:

    PHP
    $_POST['data'][0] // value aus dem ersten input element
    $_POST['data'][1] // value aus dem zweiten input element

    Auf die Weise gruppiere ich größere Formulare auch.

  • Hey,

    ok gut zu wissen ist auch viel weniger arbeit dann z.b. bei dem filtern usw.

    Ich habe jetzt mal so ein Beispiel erstellt. Hab ich es richtig gemacht oder kann man da noch was verbessern ?

    Hm komisch. Hier wird das filtern irgendwie nicht durchgeführt und keine fehlermeldungen angezeigt. Warum denn das?

    Stef

    • Offizieller Beitrag

    Hi,

    Die Prüfung der Daten kannst Du flexibler gestalten.
    Auf Deine Weise musst Du jedesmal, wenn ein Feld im Formular dazu kommt auch den Code anpassen, so wie hier musst Du das nicht:

    PHP
    $formulardaten = isset( $_POST['form']['data'] )? $_POST['form']['data']: null;
    
    
        if ( !is_null($formulardaten) )
            filter_var_array( $formulardaten, FILTER_SANITIZE_STRING );

    Grundsätzlich würde ich auch überlegen, ob Du die Formular Felder nicht auch komplett benennst:

    HTML
    <label>Vorname:</label><input type="text" name="form[data][vorname]"><br>
    <label>Nachname:</label><input type="text" name="form[data][nachname]"><br>
    <label>Wohnort:</label><input type="text" name="form[data][wohnort]"><br>


    Dann kannst Du - ist jetzt ein wenig weiter führend, aber erwähnenswert, wie ich finde - das Array $error bspw. bequem gegen die Namen laufen lassen:

    So brauchst Du auch im Prinzip nie wieder diese Logik anzufassen, selbst wenn Du Dein $_POST['form']['data'] mal erweiterst.Es gibt hier natürlich noch etliche andere Wege und auch bessere, aber es zeigt glaube ich ganz gut, dass man sich ne Menge Arbeit sparen kann, wenn man die Dinge logisch benennt und anpackt.

    Bei den try-/catch Blöcken unterstelle ich Dir mal, dass Du die Exceptions fangen willst, die von PDO kommen. Die sind allerdings dann vom Typ PDOException:

    PHP
    catch ( PDOException $e ) { ...

    Würde dann insgesamt alles so aussehen ( allerdings ungetestet! ):

    Gruß Arne

  • Hey,

    vielen Dank für die guten Ratschläge. Ups... ja ich wollte die Exceptions abfangen.

    Noch paar Fragen:
    1. Warum tuhst du $formulardaten nicht erst zu einem array umwandeln ?
    2. In der function welche schaut ob es errors gibt sprichst du mit $data die felder an und mit $key den namen des feldes ?
    3. Würdest du es bei der ausgabe der errors beim formular auch so machen oder hälst du dies etwas übertrieben?

    PHP
    <label>Vorname:</label><input type="text" name="form[data][vorname]" value ="<?php if(isset($formulardaten['vorname'])) print $formulardaten['vorname']?>"> <?php if(isset($errors['vorname'])){echo $errors['vorname'];} ?><br>
            <label>Nachname:</label><input type="text" name="form[data][nachname]" value ="<?php if(isset($formulardaten['nachname'])) print $formulardaten['nachname']?>"> <?php if(isset($errors['nachname']) ){echo $errors['nachname'];}?><br>
            <label>Wohnort:</label><input type="text" name="form[data][wohnort]" value = "<?php if(isset($formulardaten['wohnort'])) print $formulardaten['wohnort']?>">  <?php if(isset($errors['wohnort']) ){echo $errors['wohnort'];}?><br>

    Folgende Probleme treten jetzt auf:
    1. Die Eingaben werden nicht gefiltert! Es kommt so raus wie man es eingegeben hat.
    2. Es werden folgende Meldungen angezeigt :

    Warning: Missing argument 2 for {closure}() in E:\Web\XAMPP\htdocs\form.php on line 17
    Notice: Undefined variable: key in E:\Web\XAMPP\htdocs\form.php on line 18

    Der variable key wird nie ein wert beim testen zugefügt. Nie. und die Warning meldung kommt bestimmt weil $key nicht deklariert ist ?
    Denn als ich mal $key ganz rausgenommen habe kam keine Meldung mehr. Aber wie kann ich es nun machen ?

    Stef

    2 Mal editiert, zuletzt von Stef (12. Januar 2017 um 15:34)

    • Offizieller Beitrag

    Hi,

    Die beiden Meldungen kommen, weil ich vergessen habe die Keys des Array an die Closure zu übergeben, richtig muss es so aussehen:

    PHP
    $errors = array_filter(
                array_map(
                    function( $data, $key ) {
                        return empty(trim($data))? 'Bitte ' . $key . ' eingeben!': null;
                    }
                    , $formulardaten
                    , array_keys( $formulardaten )
                )
            );
    Zitat

    Warum tuhst du $formulardaten nicht erst zu einem array umwandeln ?


    Wozu? $formulardaten wird ja im Erfolgsfall ( also wenn die Formulardaten gesendet wurden ) ein Array zugewiesen. Und im Fehlerfall wird das auf null gesetzt.
    Dadurch kann ich an notwendigen Punkten ( siehe die Validierung ) mit !is_null() immer prüfen, ob Daten vorhanden sein müssten. Auch is_array() würde hier gehen, aber für nicht gesetzte Werte handle ich das immer gern mit null.

    Zitat

    In der function welche schaut ob es errors gibt sprichst du mit $data die felder an und mit $key den namen des feldes ?

    Ja richtig, ich hatte lediglich vergessen, das Array mit den Keys zu übergeben, s.o.

    Zitat

    Würdest du es bei der ausgabe der errors beim formular auch so machen oder hälst du dies etwas übertrieben?

    Das halte ich persönlich für übertrieben und entspricht für mein Verständnis nicht EVA.
    Ich würde die Ausgabe auf Basis des $errors-Array vorher zusammenklöppeln und in der Ausgabe dann nur kurz und knackig:

    PHP
    if ( is_null($sHtmlErrors) )
        echo $sHtmlErrors;


    Wobei $sHtmlErrors dann halt die zusammengelöppelte Variable ist.
    Ebenso kannst Du das auch mit dem Erfolgstext machen.

    Gruß Arne

  • Hey,

    Ok. Vielen Dank für die gute Hilfe :) Funktioniert jetzt auch alles.

    Ich habe mir nochmals die ganzen array-funktionen durchgelesen. Nun das ich es nochmals verstehe:

    array_filter wird als erstes verwendet und umgibt die anderen array funktionen weil array_filter alle Sachen löscht die FALSE sind, und Sachen die TRUE sind behält diese funktion.
    Dann wird array_map verwendet mit einer anonymen Funktion, die auch Closures genannt werden, (bei dieser brauch man keinen functionname) . Diese funktion gibt alles aus dieser function zurück, braucht dazu die formulardaten.
    Und in dieser function wird array_keys angewandt, welche alle Schlüssel eines Array liefert an die closure (Annonyme Funktion). D.h. arrey_keys liefert der anonymen funktion sozusagen die werte den mitgegebenden Parameter ?
    Dann werden alle Daten mit array_filter gefiltert und die die FALSE sind gelöscht.

    Warum hast du array_keys() in der funktion array_map() verwendet ?

    Gruß,
    Stef

    Einmal editiert, zuletzt von Stef (12. Januar 2017 um 17:39)

    • Offizieller Beitrag

    Hi,

    Du hast es fast ;)
    Bzgl. der Verarbeitung meinst Du das richtige, hast es aber andersrum erklärt, daher nochmal Step-by-Step:

    Bei verschachtelten Verarbeitungen wird von innen nach außen ausgewertet, d.h. hier wird zuerst array_map() verarbeitet.
    array_map() benötigt als Pflichtparameter ein Array, über dessen Werte es iteriert, hier übergeben wir einfach $formulardaten, weil wir die Werte daraus auf "leer" prüfen wollen.
    Zurückgeben möchten wir entweder eine Fehlermeldung oder null. Damit wir die Verarbeitung weitesgehend automatisieren können, habe ich den Formulardaten einen Array-Schlüssel verpasst, den wir in der Fehlermeldung verwenden können. Damit unsere Closure diese aber kennt, müssen wir sie als weiteren optionalen Parameter übergeben und das passiert mit array_keys(), welches ein Array mit den Schlüssel eines Array liefert:

    array_map() liefert der Closure immer in Paar, bestehend aus dem ersten und zweiten Parameter:

    Code
    1. Durchlauf: foo, vorname
    2. Durchlauf: bar, nachname
    3. Durchlauf: baz, wohnort

    Erst wenn array_map() alles verarbeitet hat, wird im dargestellten Fall das Ergebnis in Form eines Arrays an array_filter() übergeben, wo dann - wie Du richtig sagtest - alle Werte, entfernt werden, bei denen der Rückgabewert der Closure als false gecastet wird.
    Da wir für array_filter() keine Closure-Funktion angewendet haben, wird der jeweils zu bearbeitende Wert zu false gecastet. Ein Leerstring, also ein leeres Formularfeld ist zu bool gecastet in PHP auch false, daher fliegen die raus.
    Due hast so am Ende nur noch die aufgetretenen Fehler im Array.

    Auf die Weise spart man sich umständliche IF-Konstrukte und muss den Code nicht anpassen, wenn mal Formularfelder dazu kommen.

    Gruß Arne