# [PHP/SQL] INSERT mit PDO prepared funktioniert nicht.



## BloodSteam (8. Januar 2019)

Moin,
hab schon verschiedene Sachen versucht und es geht irgendwie nicht.
Ich verstehe nicht wieso es nicht funktioniert, es postet "User has been created." aber in "HeidiSQL (localhost)" sehe Ich nichts.


```
if(empty($_POST['username']) || empty($_POST['email']) || empty($_POST['password'])){
    echo "Signup form isn't filled.";
    exit();
}else{
    // Set variables
    $username = $_POST['username'];
       $email = $_POST['email'];
    $password = $_POST['password'];


    // Prepare query
    $stmt = $pdo->prepare("SELECT * FROM users WHERE email = ? OR username = ?");
    $stmt->execute([$email,$username]);
    if($stmt->rowCount() !== 0){
        echo 'Email or username is taken.';
        exit();
    }else{
        // FIX: Doesn't insert anything into the DB.
        $stmt = $pdo->prepare("INSERT INTO users (email,password,username) VALUES (?,?,?)");
        $stmt->execute([$email,$password,$username]);
        echo 'User has been created.';
        exit();
    }
}
```


----------



## ZAM (8. Januar 2019)

Vielleicht ist das ja im Endeffekt aufschlussreicher

```
if(empty($_POST['username']) || empty($_POST['email']) || empty($_POST['password'])){
   echo 'Signup form isn\'t filled.';
}else{

   // Set variables
   // HIER TROTZDEM BESSER PRÜFEN. Prepared-Statements schützen nicht vor XSS.  
   $username = $_POST['username'];
   $email = $_POST['email'];
   // Und warum wird hier ein Klartext-Passwort gespeichert? ARGH ^^ Erinnert mich bitte daran, mich nie bei irgendeinem System von BloodSteam zu registrieren. ^^
   $password = $_POST['password'];

   // Prepare query
   $stmt = $pdo->prepare('SELECT 1 FROM users WHERE email = :email OR username = :username');
   $stmt->bindValue(':email', $email, PDO::PARAM_STR);
   $stmt->bindValue(':username', $username, PDO::PARAM_STR);
   if ( $stmt->execute() ) {
      if ( (int)$pdo->errorCode() ) {
         echo 'Fehler ' . print_r($pdo->errorInfo(), true);
      } else {
         if ($stmt->rowCount() !== 0) {
            exit('Email or username is taken.');
         } else {
            // FIX: Doesn't insert anything into the DB.
            $stmtInsert = $pdo->prepare('INSERT INTO users (email,password,username) VALUES (:email,:password,:username)');
            $stmtInsert->bindValue(':email', $email, PDO::PARAM_STR);
            $stmtInsert->bindValue(':password', $password, PDO::PARAM_STR);
            $stmtInsert->bindValue(':username', $username, PDO::PARAM_STR);
            if ( $stmtInsert->execute() ) {
               if ( (int)$pdo->errorCode() ) {
                  echo 'Fehler ' . print_r($pdo->errorInfo(), true);
               } else {
                  echo 'User has been created.';
               }
            }
         }
      }
   }
}
exit;
```


----------



## BloodSteam (8. Januar 2019)

Zu dem Passwort, Ich glaube wir haben beide ein anderen Verlauf beim Coden. Ich mache es immer so, Schritt -> Testen -> Schritt -> Testen. Schritt (INSERT) -> Testen -> Fixen. Solange es nicht gefixt ist, brauche Ich es nicht zu hashen. Wenn mein Insert funktioniert, dann wird weiter gemacht.

@edit
Hab was getestet.
Dies hier funktioniert nicht

```
$stmt = $pdo->prepare("INSERT INTO users (email,password,username) VALUES (?,?,?)");
```
und

```
$stmt = $pdo->prepare("INSERT INTO users (email,password,username) VALUES (:email, :password, :username)");
```
Das hier geht.

```
$stmt = $pdo->prepare("INSERT INTO users (email,password,username) VALUES ('abc','123','f121212')");
```


----------



## ZAM (9. Januar 2019)

Dann ist einer der übermittelten Werte leer und das zugehörige Tabellenfeld ist definiert mit "NOT NULL" oder es gibt eine andere Unstimmigkeit bei den Feld-Definitionen der Tabelle und den übermittelten Werten.
Interessant, dass du bei meinen Anpassungen keine Fehlermeldungen bekommst. Zumindest ein SQL-Fehler müsste dann ausgegeben werden.


----------



## BloodSteam (9. Januar 2019)

Kannst du es auch erklären? Es funktionier danke aber dennoch lege Ich es Wert drauf es zu verstehen.

```
$stmtInsert = $pdo->prepare('INSERT INTO users (email,password,username) VALUES (:email,:password,:username)');
            $stmtInsert->bindValue(':email', $email, PDO::PARAM_STR);
            $stmtInsert->bindValue(':password', $password, PDO::PARAM_STR);
            $stmtInsert->bindValue(':username', $username, PDO::PARAM_STR);
            if ( $stmtInsert->execute() ) {
               if ( (int)$pdo->errorCode() ) {
                  echo 'Fehler ' . print_r($pdo->errorInfo(), true);
               } else {
                  echo 'User has been created.';
               }
            }
        exit;
```


----------



## ZAM (10. Januar 2019)

Was genau? Meinst du den Code-Ablauf?

PDO->errorCode() liefert nach einem execute() des Prepared-Statements in der Regel immer '0000', wenn kein Fehler auftritt, daher mache ich einen Int-Cast auf 0. Liefert die Funktion keine 0 zurück, liegt ein Fehler vor, den du mit PDO-errorInfo() (ist ein Array mit dem Error-Stack) abrufen kannst. 

bindValue mit direkten Namens( :xxx )- statt Positions( ? )-Platzierungen nutze ich aus Gewohnheit, falls man den gleichen Wert an mehreren Stellen braucht. Und man kann hier genau(er) definieren, um was für einen Übergabetyp es sich handelt mit PDO :: PARAM_*.


----------



## BloodSteam (22. Januar 2019)

I bims wieder  Der noob der nicht programmieren kann 

ALSO... Ich weiß nicht was hier nicht funktioniert. Ich bekomme kein SQL error oder sonnst was und es funktioniert nicht.

Ziel = Soll nur die id und usernamen ausgeben.

userlist.php

```
include_once 'dbh.php';

class Users extends Dbh
{
    private $sql = 'SELECT id,username FROM users';

    function __construct()
    {
        parent::__construct();
    }

    public function getUsers(){
        return $this->conn->query($this->sql);
    }
}

$users = new Users();

$result = $users->getUsers();
echo var_dump($result);
```

dbh.php

```
class Dbh
{
    private $host = '127.0.0.1';
    private $port = '3306';
    private $username = 'root';
    private $password = '123';
    private $dbname = 'loginsystemdb';
    private $charset = 'utf8mb4';

    protected $conn;

    function __construct()
    {
        try {
            $this->conn = new PDO("mysql:host=$this->host;port=$this->port;dbname=$this->dbname;charset=$this->charset", $this->username, $this->password);
            $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            return $conn;
        } catch (PDOException $e) {
            echo 'Mysql Connection failed: '.$e->getMessage();
        }
    }
}
```


----------



## DataDino (22. Januar 2019)

Versuch es mal mit:

```
echo var_dump($result->fetchall());
```

So weit ich mich erinnern kann, bekommst du bei einem Query immer ein PDOStatement-Objekt zurück und nicht direkt die Daten. Die erhältst du, wenn du die Daten aus dem Statement fetch'st.


----------



## BloodSteam (23. Januar 2019)

Nach 300 tutorials und ca 24h... geht.. aber nicht ganz.

ALSO... das hier geht.

```
public function insert($email,$password,$username)
    {
        $this->bind(':email', 'hello@kevin.com');
        $this->bind(':password', 'pro420');
        $this->bind(':username', 'XxPROxX');
        $this->execute();
    }
```

aber das hier nicht.

```
public function insert($email,$password,$username)
    {
        $this->query('INSERT INTO users (email, password, username) VALUES (:email, :password, :username)');
        $this->bind(':email', 'hello@kevin.com');
        $this->bind(':password', 'pro420');
        $this->bind(':username', 'XxPROxX');
        $this->execute();
    }
```

Und die variablen funktionieren 100%, wenn Ich ein echo nutze, wird alles angezeigt. :x Keine Fehler etc.

Wenn Ich nur ein echo hinzufüge.




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



PS: Ja Ich hashe die Passwörter, will aber nicht dieses gekritzel sehen und deswegen hab es auskommentiert und einfach nur $_POST benutze weil Ich weiß dass es funktioniert lul.  Wenn Ich das gehashte benutze ist die Konsole voll :x


----------



## ZAM (23. Januar 2019)

Da interessieren mich zwei Dinge,

1. Woher kommt bind() - PDO wäre bindParam oder (für den Fall mit Benamung) bindValue() korrekt. Und query() statt prepare() ? Was hast du da für eine Klasse zusammengefummelt?
2. Tabellenstruktur von "user", zeige mal die komplette CREATE-Anweisung.


----------



## BloodSteam (23. Januar 2019)

Jetzt geht es  Password Tabelle hatte eine Länge von 55 nicht 255 -_-


----------



## BloodSteam (24. Januar 2019)

Ist es eine gute Idee php sessions zu verwenden oder gibt es da eine bessere dennoch sichere möglichkeit?
Ich nutze PHP 7.2.8


----------



## ZAM (25. Januar 2019)

BloodSteam schrieb:


> Ist es eine gute Idee php sessions zu verwenden oder gibt es da eine bessere dennoch sichere möglichkeit?
> Ich nutze PHP 7.2.8



Für kleine Gammelprojekte kannst du das gern machen. Bei Community-Getriebenen Seiten mit ein paar hundert/tausend AU pro Tag, würde ich das eher nicht. ^^
Alternativen gibt es dann genug bspw. über Datenbanken bzw. NOSQL oder Memory-Cache. Whatever - was deine Infrastruktur halt bietet und du umsetzen kannst.


----------



## BloodSteam (25. Januar 2019)

ZAM schrieb:


> Für kleine Gammelprojekte kannst du das gern machen. Bei Community-Getriebenen Seiten mit ein paar hundert/tausend AU pro Tag, würde ich das eher nicht. ^^
> Alternativen gibt es dann genug bspw. über Datenbanken bzw. NOSQL oder Memory-Cache. Whatever - was deine Infrastruktur halt bietet und du umsetzen kannst.



Also hab Ich ein Array im MemCache mit den allen usern? Aber wie vergebe Ich die logins? Sende Ich eine zufällige Nummer im Header and den user? Dann muss Ich aber auch was machen damit Sich die nummer nie ändert. Ich hab nur eine PHP Datei und alles andere läuft mit AJAX.


----------



## ZAM (25. Januar 2019)

Mh, fange mal an so zu denken, wie das Script "abläuft" ^^


----------



## BloodSteam (31. Januar 2019)

Ich nutze mal einfach dieses Thread anstatt wieder ein neues zu eröffnen.

Wie Ich ein "Key : Value" Paar an das Frontend senden? Also zb:

```
return { 'type' : 'signup', 'text' : 'Erfolgreich Zugestellt'}
```


----------



## BloodSteam (2. Februar 2019)

Ich raste gleich aus....

Hab alles auf ein Webhosting hochgeladen und bekomme einen Fehler obwohl die SQL Daten stimmen.
Lustinge dran ist dass es mit Mamp funktioniert (localhost).


```
<br /> <b>Fatal error</b>:  Uncaught Error: Call to a member function prepare() on null in dbc.php:51 Stack trace:
#0 signup.php(12): Database->query('SELECT email,us...') 
#1 router.php(37): Signup->addNewUser('damian@q.com', '$2y$10$xEf6v.7a...', 'damian') 
#2 {main}   thrown in <b>dbc.php</b> on line <b>51</b><br />
```

Was kann das bedeuten? #0 ist eine Query zusehen, bei #1 sind Sachen aus $_POST zusehen.

In Line 51 hab Ich dies hier:

```
public function query($query)
    {
        $this->stmt = $this->dbh->prepare($query);
    }
```


----------



## ZAM (7. Februar 2019)

Naja "Call to a member function prepare() on null" heißt, dass $this->dbh kein PDO-Objekt an der Stelle ist. Das kann bspw. entstehen, wenn deine Live-Umgebung kein PDO aktiv hat. Das kannst du bspw. herausfinden mit class_exists('PDO') und dann die Server-Config entsprechend anpassen, sofern dein Hoster bzw. dein Paket es zulässt.


----------

