Formchecker mit PHP

PHP:
 if($GLOBALS['FELD']['vorname']['mandatory_field'] = "yes")
prüft nicht, sondern setzt 'yes'. zum Vergleichen solltest du == verwenden. Aber ich würde da eher ein Boolean setzen, dann ists einfacher

PHP:
$GLOBALS['FELD']['vorname']      = array('mandatory_field' => true,
...
Dann kannst du direkt auf den Ture/False prüfen
PHP:
if($GLOBALS['FELD']['vorname']['mandatory_field']) { 
...
 
Habe nun das Array erweitert:
Letztes TO-DO:
Die Funktion checkVorname() variabel gestalten, also check$field(), so dass diese Funktionen sich selbst erstellen und ausführen.

Jetzt kommt der zeitpunkt wo Klassen das Leben erleichtern können.
Ich habe mal eben eine kleine Checker-Klasse erstellt. Von dieser wird für jedes Feld eine Instance erstellt und anschliessend darauf geprüft.

PHP:
<?php

//Beispielaufruf

//$_POST simulieren (Im gebrauch mit einem Formular wieder löschen!)
$_POST = array(
    'vorname' => 'yaslaw',
    'nachname' => 'Hallo Welt und überhaubt');

//Definition erstellen
$check = new Checker('vorname');
$check->addDef(Checker::C_MANDATORY_FIELD, true);
$check->addDef(Checker::C_MIN_LENGTH, 3);
$check->addDef(Checker::C_MAX_LENGTH, 15);
$check->addDef(Checker::C_REGEXP, "/^[a-zA-Z]+$/s", 'Dieses Feld darf nur Buchstaben beinhalten');
$checks['vorname'] = $check;

$check = new Checker('nachname');
$check->addDef(Checker::C_MANDATORY_FIELD, true);
$check->addDef(Checker::C_MIN_LENGTH, 3);
$check->addDef(Checker::C_MAX_LENGTH, 20);
$check->addDef(Checker::C_REGEXP, "/^[a-zA-Z]+$/s", 'Dieses Feld darf nur Buchstaben beinhalten');
$checks['nachname'] = $check;

//Eingabe prüfen
$valid = true;
$htmlMessages = array();
foreach($checks as $name => $check){
     $valid = $check->check($_POST[$name]) ? $valid : false;
     $htmlMessages[] = $check->getHtmlMessage();
}

//Resultat ausgeben
echo(implode('<hr />', $htmlMessages));



/**
* @copyright    mpl by ERB software
*               All rights reserved
* @author       stefan.erb@erb-software.com
*/
Class Checker{
    /**
     * Konstanten um den Check-Type zu definieren
     */
    const C_MANDATORY_FIELD = 'mandatory';
    const C_MIN_LENGTH = 'min';
    const C_MAX_LENGTH = 'max';
    const C_REGEXP = 'regexp';
    
    protected $messages = array();
    protected $checks = array();
    protected $fieldName;
    protected $htmlMessage;
    
    /**
     * Konstrukteur
     * @param $fieldName    String      Feldname
     */
    public function __construct($fieldName){
        $this->fieldName = $fieldName;
    }
    
    /**
     * Definition hinzufügen
     * @param $type     String      Eine der Klassenkonstanten elche dei Check-Typen definieren
     * @param $arg      Variant     Argument zur Prüfung
     * @param $msg      String      Optional: Fehlermessage
     */
    public function addDef($type, $arg, $msg = NULL){
        $this->checks[] = array(
            'type'  => $type, 
            'arg'   => $arg, 
            'msg'   => $msg);    
    }
    
    /**
     * führt die Prüfung eines Wertes durch
     * @param $value    Variant     Zu prüfenden Wert
     * @return          Boolean
     */
    public function check($value){
        $this->messages = array();
        $valid = true;
        foreach($this->checks as $check){
            $checkFunction = $check['type'];         
            $valid = $this->$checkFunction($check['arg'], $value, $check['msg']) ? $valid : false;           
        }
        if($valid){
            $this->htmlMessage =  "Feld {$this->fieldName} mit dem Inhalt '{$value}' ist gültig";
        }else{
            $this->htmlMessage = "Feld {$this->fieldName} mit dem Inhalt '{$value}' ist ungültig:<br />";
            $this->htmlMessage .= implode('<br />', $this->messages);
        }
        return $valid;
    }
    
    /**
     * Gibt die HTML-Message der Prüfung aus
     * @return          String
     */
    public function getHtmlMessage(){
        return $this->htmlMessage;
    } 
    
    /**
     * Interne Funktion um ggf die Message in den Array zu schreiben
     * @param $invalid  Boolean     Angabe ob die Prüfung fehlgeschlagen ist
     * @param $message  String
     * @return          Boolean     Der Valid-Wert.
     */
    protected function setFail($invalid, $message){
        if($invalid) $this->messages[] = $message;
        return !$invalid;
    }
    
    /**
     * Prüfung auf Mandatory
     * @param $arg      Boolean     Angabe ob ein Wert enthalten sein muss
     * @param $value    Variant     Prüfwert
     * @param $msg      String      Optional
     * @return          Boolean
     */
    protected function mandatory($arg, $value, $msg = NULL){
        if (!isset($msg)) $msg = 'Dieses Feld ist ein Plichtfeld';
        return $this->setFail($arg && empty($value), $msg);
    }

    /**
     * Prüfung auf Minimum
     * @param $arg      Integer     Minimum
     * @param $value    Variant     Prüfwert
     * @param $msg      String      Optional
     * @return          Boolean
     */
    protected function min($arg, $value, $msg = NULL){
        if (!isset($msg)) $msg = "Dieses Feld muss mindestens {$arg} Zeichen beinhalten";
        return $this->setFail(strlen($value) < $arg, $msg);
    }

    /**
     * Prüfen auf Maximum
     * @param $arg      Integer     Maximum
     * @param $value    Variant     Prüfwert
     * @param $msg      String      Optional
     * @return          Boolean
     */
    protected function max($arg, $value, $msg = NULL){
        if (!isset($msg)) $msg = "Dieses Feld darf maximal {$arg} Zeichen beinhalten";       
        return $this->setFail(strlen($value) > $arg, $msg);
    }

    /**
     * Prüfen mittels Regulärem Ausdruck
     * @param $arg      String      Pattern
     * @param $value    Variant     Prüfwert
     * @param $msg      String      Optional
     * @return          Boolean
     */
    protected function regexp($arg, $value, $msg = NULL){      
        if (!isset($msg)) $msg = "Dieses Feld muss dem Regulären Ausdruck {$arg} entsprechen";
        return $this->setFail(preg_match($arg, $value)==0, $msg);
    }    
}
?>
 
Grüß Dich yaslaw,

wow, danke für das Mega-Feedback. Jedoch möchte ich den Code, den du mir da geschrieben hast auch verstehen. Von daher werde ich mich die Tage mal dem Thema "Klassen" widmen. Ich denke ich verstehe das Prinzip welches dahinter ist, jedoch sind mir u.a. zwei Kleinigkeiten unklar:

Wie sieht es mit SQL-Injections aus? Es wäre doch am besten, wenn ich die per POST erhaltenen Daten zuallererst mittels mysql_real_escape_string escape, oder? Bzw. wenn ich register_globals auf on habe, brauche ich die empfangenen Daten nicht extra escapen, richtig?

Wie kann ich nun einzelne Messages selektieren? Ich möchte also prüfen, ob speziell für das Feld "vorname" Fehler vorhanden sind. Wenn ja, soll er diese an dieser Stelle hier ausgeben.
Mir ist bewusst, dass ich bei jedem Feld die einzelne Abfrage rein setze. Damit nicht beim ersten Aufruf des Formulars gleich die Fehler angezeigt werden, werde ich mit dem submit-Button eine "id" mitliefern und erst prüfen, ob die id gesetzt ist.

Wie lautet jetzt jedoch der Schnippsel für die Abfrage? Etwa so:
PHP:
<?php if($valid=false) { echo $htmlMessages["vorname"];} ?>

Das kann ja nicht Funktionieren. Wie spreche ich das jeweilige Feld nun an?
 
Erweitern wir die Definition am Anfang der Klasse mal um
PHP:
    protected $htmlMessage;
    public $valid = false;
Dann ersetzen wir in der Methode check() alle $valid durch $this->valid
PHP:
    public function check($value){
        $this->messages = array();
        $this->valid = true;
        foreach($this->checks as $check){
            $checkFunction = $check['type'];         
            $this->valid = $this->$checkFunction($check['arg'], $value, $check['msg']) ? $this->valid : false;           
        }
        if($this->valid){
            $this->htmlMessage =  "Feld {$this->fieldName} mit dem Inhalt '{$value}' ist gültig";
        }else{
            $this->htmlMessage = "Feld {$this->fieldName} mit dem Inhalt '{$value}' ist ungültig:<br />";
            $this->htmlMessage .= implode('<br />', $this->messages);
        }
        return $this->valid;
    }

Nun können wir jederzeit das Resultat abfragen
PHP:
if($checks['vorname']->valid){
    //TODO: irgendwas sinnvolles
}

Die SQL-Injections kommen erst nachher, wenn du auf die DB zugreiffst.
 
Zuletzt bearbeitet:
Grüß Dich yaslaw,

habe das nun entsprechend angepasst und zum auslesen benutze ich:

PHP:
<?php if(!$checks['vorname']->valid){
//Resultat ausgeben
print_r($htmlMessages[0]);
};
?>

Wobei wie du siehst, dass Array nur Standartmäßig ansprechbar ist. Würde die nun, gerne in $htmlMessages[vorname] umwandeln, damit ich da keine Zahlen drin stehen habe. Und dann ist es eigentlich Perfekt.

Kann ich am Ende der Vorgangs prüfen ob $valid bei ALLEN Feldern true ist? Mit

PHP:
if(!$checks->valid)
funktioniert es schon mal nicht.

Ansonsten denke ich haben wir (du!) da ein schickes Script geschrieben, welches sicherlich auch vielen anderen helfen wird. Werde nach Theadabschluss nochmal eine komplette Version rein stellen.

EDIT: Habe nun den Schnippsel zusammengeführt mit dem Formular und prüfe per

PHP:
if (isset($_POST['submit']))
{ SCRIPT } else { FORMULAR };
Ob das Formular versendet wurde. Das klappt soweit, bis auf das er nun die Klasse 'Checker' nicht mehr finden kann?!
 
Zuletzt bearbeitet:
$checks->valid kann nicht gehen. $checks ist nur ein Array mit mehreren Checks drin. Aber hier steht doch, dass $valid am Ende sagt ob alle valid sind oder nicht
PHP:
//$valid ist nur true, wenn alle Felder korrekt ausgefüllt wurden
$valid = true;

foreach($checkfields as $index => $field){
  $checkanweisung = "check$field";
  $valid = check($field, $checkanweisung, $htmlMessage) ? $valid : false;
  $htmlMessages[$index] = $htmlMessage;
}

Und genau da kannst du übrigens die Zahl durch den String ersetzen
PHP:
  $htmlMessages[$field] = $htmlMessage;
 
Ich erhalten jetzt jedoch
Code:
Warning: Invalid argument supplied for foreach() in

für die Zeile
PHP:
foreach($checkfields as $index => $field){

Meine Schleife sah so aus:

PHP:
    $htmlMessages[$index] = $htmlMessage;
    foreach($checks as $name => $check){
       $valid = $check->check($_POST[$name]) ? $valid : false;
       $htmlMessages = $check->getHtmlMessage();
    }

Und jetzt hab ich deinen Code verwendet. Und dadurch der Fehler.
 
Zuletzt bearbeitet:
Hab den Code vom falschen Ort kopiert. Du solltest aber verscuhen zu verstehen was da ab geht, sonst bist du immer auf mich angeweisen...
 
Ich versuche es, ja.

Wenn ich
PHP:
    $htmlMessages[$index] = $htmlMessage; 
    foreach($checks as $name => $check){ 
       $valid = $check->check($_POST[$name]) ? $valid : false; 
       $htmlMessages = $check->getHtmlMessage(); 
    }
durch
PHP:
    $htmlMessages[$field] = $htmlMessage; 
    foreach($checks as $name => $check){ 
       $valid = $check->check($_POST[$name]) ? $valid : false; 
       $htmlMessages = $check->getHtmlMessage(); 
    }

ersetze, erhalte ich das gleiche Array geliefert. Also:

Array ( [] => [0] => Feld vorname mit dem Inhalt 'w' ist ungültig:
Dieses Feld muss mindestens 3 Zeichen beinhalten [1] => Feld nachname mit dem Inhalt 'w' ist ungültig:
Dieses Feld muss mindestens 3 Zeichen beinhalten )

Ich müsste als die letzte Zeile abändern.

PHP:
$htmlMessages[] = $check->getHtmlMessage();
in
PHP:
$htmlMessages[$field] = $check->getHtmlMessage();

Geht jedoch leider auch nicht. So:

PHP:
$htmlMessages[$name] = $check->getHtmlMessage();
scheint es jedoch zu gehen. Jedoch macht mich das "Hauptarray" stutzig.
Code:
Array ( [] => [vorname] => Feld vorname mit dem Inhalt '' ist ungültig:
Dieses Feld ist ein Plichtfeld
Dieses Feld muss mindestens 3 Zeichen beinhalten
Dieses Feld darf nur Buchstaben beinhalten [nachname] => Feld nachname mit dem Inhalt '' ist ungültig:
Dieses Feld ist ein Plichtfeld
Dieses Feld muss mindestens 3 Zeichen beinhalten
Dieses Feld darf nur Buchstaben beinhalten )
Also nehme ich die erste Zeile
PHP:
$htmlMessages[$index] = $htmlMessage;
raus und es dürfte passen.

Jetzt brauche ich also nur noch die if-Abfrage, wo ich weiter machen kann, wenn alle Felder $vaild true; sind. Wo setze ich diese hin? Direkt nach der Schleife?
 
Zuletzt bearbeitet:
item: du überschreibst $htmlMessages immer wieder.
item: Was macht die zuweisung vor der Schleife?

So sollte es aussehen
PHP:
$valid = true;
$htmlMessages = array();
foreach($checks as $name => $check){
     $valid = $check->check($_POST[$name]) ? $valid : false;
     $htmlMessages[$name] = $check->getHtmlMessage();
}
 
Zurück