Problem mit CSV in Datenbank zu schreiben

Myar

Mitglied
Hallöchen!

Kurze Erklärung:

Ich bekomme eine CSV die Produktdaten enthält und mit denen muss halt ein Update oder ein Insert der Daten in die DB durchgeführt werden.
Für Testzwecke beschränke ich mich erstmal auf ein Update der ek_preise.

Ich habe bereits den Schritt fertig, in dem die CSV ausgewählt wird und auf dem Server gespeichert. Der Pfad auf dem Server wird in der Session gespeichert. So kann man die Datei holaden, sich den Inhalt angucken und dann sagen -> in die DB damit.

Der letzte Schritt funktioniert nicht. Und ich weiß einfach nicht warum.

Ich bin halt noch nicht sehr geübt in PHP. Bzw. bisher, wenn PHP, eher rein mit CMS und Webseiten zu tun gehabt.

Mein Quellcode:

PHP:
public function csvUpload(){   
    
    try{
      $ausgabe = '';
      $pfad = $_SESSION['datei'];
      $fp = fopen($pfad,'r');
      $rows = 0;
      $data = fgetcsv ($fp, 1000, ";");
      array_shift($data);
      $data2 = str_replace(",",".",$data[1]);
        
      while ( $data2 !== FALSE ){ 
      
        $pdoparams = array( 
        ':ekpreis' => $data2[1], 
        ':artnr' => $data2[0] 
        ); 
        $sql = "UPDATE products SET ek_preis = :ekpreis WHERE products_model2 = :artnr"; 
        $stmt = MyDB::getInstance()->prepare($sql); 
        $stmt->execute($pdoparams);
        $rows++;
        //for($c=0;$c<count($data);$c++) {}
    }
    $ausgabe = 'Anfrage ausgeführt. '.$rows.' Datensätze wurden aktualisiert';
    fclose($fp);
    }catch(Exception $e){
      $ausgabe  = 'Datei konnte nicht eingelesen werden!';
  }
  return $ausgabe;
}

Ich bekomme nur Dauerschleifen oder Fehlermeldungen wie:
Notice: Undefined variable: data2 in C:\xampp\htdocs\csv_handle.php on line 15

Warning: Invalid argument supplied for foreach() in C:\xampp\htdocs\csv_handle.php on line 15

Notice: Undefined variable: data2 in C:\xampp\htdocs\csv_handle.php on line 18

Vor allem die Dauerschleife verstehe ich gar nicht...

Edit: Das replace von Punkt und Komma deswegen, weil die Preise mit Kommas getrennt sind, aber die DB will Punkte...
 
item: Mit fgetcsv() kannst du deine csv-Datei direkt in ein Array einlesen und musst ihn nicht von Hand zerlegen.

item: Arebitest du mit MySQLi? Das Prepared Statement sieht dazu ziemlich falsch aus.


item: Dauerschleife:
while ( $data2 !== FALSE )
Das bedeutet, dass die Schleife ausgeführt wird, bis $data2 FALSE ist (und vom Typ Boolean)
Vor der Schleife ist aber $data2 ein Array. In der Schleife änderst du den Array nie in ein Boolean (du veränderst ihn überhaubt nie). Ergo wird bei jedem Durchgang FALSE gegen denselben Array geprüft. und somit ist die Bedinung immer True und du hast deine ewige Schleife
 
Hast Du es schon die Update zeile so geändert gehabt?
PHP:
  $sql = "UPDATE products SET ek_preis = ".$pdoparams[':ekpreis']." WHERE products_model2 = ".$pdoparams[':artnr'];
gebe ich jetzt keine Garantie drauf das es klappt^^
 
@Yugeen
Ist aber auch nicht sauber. Entwerder er arbeitet wirklich mit Prepared Statements oder er kann gleich $data verwenden. Mir sieht es aber danach aus, als ob seine DB-Klasse im Hintergrund irgendwei die :Namen ersetzt, denn bei MySQLi währe beim execute-Befehl kein Array als Paramter mit dabei
 
@Yugeen
Ist aber auch nicht sauber. Entwerder er arbeitet wirklich mit Prepared Statements oder er kann gleich $data verwenden. Mir sieht es aber danach aus, als ob seine DB-Klasse im Hintergrund irgendwei die :Namen ersetzt, denn bei MySQLi währe beim execute-Befehl kein Array als Paramter mit dabei

Stimmt habe ich jetzt darüber nicht nachgedacht, für mich sah es halt so aus das die Zeile ek_preis auf ':ekpreis' gesetzt wird und nicht auf den Wert der sich dahinter verbirgt, ich entschuldige mich für die Irreführung ^^
 
Danke schonmal für eure Antworten :)
Also meine Datenbankklasse sieht so aus (1:1 kopiert):

PHP:
require 'mysql_inc.php';

class MyDB { 
 private static $db; 
 
 static public function getInstance() { 
     if(!self::$db) { 
         self::$db = new PDO( 
             'mysql:host='.Configuration::DB_HOST.';dbname='.Configuration::DB_DATABASE.';port='.Configuration::DB_PORT, 
             Configuration::DB_USER, 
             Configuration::DB_PASSWORD, 
             array( 
                 PDO::ATTR_PERSISTENT => true, 
                 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ,
                 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
             ) 
         ); 
     } 
     return self::$db; 
 } 
}

Ich habe mir bereits ein wenig helfen lassen, nur die Dauerschleife, wenn das alles in die DB soll ist nicht weg:

PHP:
public function csvUpload(){   
    
    try{
      $ausgabe = '';
      $pfad = $_SESSION['datei'];
      $fp = fopen($pfad,'r');
      $rows = 0;
      $header = fgetcsv($fp, 1000, ';');
      $data = array();
      
      while ($row = fgetcsv($fp, 1000, ';')) {
            $data[] = str_replace(",",".",$row);
      }
      
      for($c=0;$c<count($data);$c++) {
        //$ausgabe .= 'UPDATE products SET ek_preis= '.$data[$c][1].' WHERE products_model2 = '.$data[$c][0];
        $pdoparams = array( 
        ':ekpreis' => $data[$c][1], 
        ':artnr' => $data[$c][0] 
        ); 
        $sql = "UPDATE products SET ek_preis = :ekpreis WHERE products_model2 = :artnr"; 
        $stmt = MyDB::getInstance()->prepare($sql); 
        $stmt->execute($pdoparams);
        $rows++;
      }
    
    $ausgabe = 'Anfrage ausgeführt. '.$rows.' Datensätze wurden aktualisiert';
    fclose($fp);
    }catch(Exception $e){
      $ausgabe  = 'Datei konnte nicht eingelesen werden!';
  }
  return $ausgabe;
}
 
item: Du Arebitest mit PDO als Datenbankklasse - gut, da hab ich keine Erfahrung mit.

item: Was soll das?
$data[] = str_replace(",",".",$row);
Da steht, Ersetze alle , durch Punkte im Array. Nicht in jedem Element des Arrays. Das wird so sicher nicht funktionieren
Verschiebe das Ersetzen dahin wo du das Feld ausliest
PHP:
      while ($row = fgetcsv($fp, 1000, ';')) {
            $data[] = $row;
      }
      
      for($c=0;$c<count($data);$c++) {
        $pdoparams = array( 
        ':ekpreis' => str_replace(",",".",$data[$c][1]), 
        ':artnr' => $data[$c][0] );
...
 
Danke, jeder Verbesserung des Codes/fehlerbehebung ist sehr hilfreich :)

Aber wegen der Dauerschleife weißt du auch net weiter?
Es muss wohl doch an dem PDO liegen, denn wenn ich (wie im Quelltext auskommentiert) mir nur mal die SQL Statements ausgeben lasse, ist alles okay. Erst wenn die DB ins Spiel kommt, tritt das Problem auf...
 
Hallo,

ich weiß jetzt nicht, ob dich das weiter bringt, aber ich würde es zusätzlich zu Yaslaws Umbauvorschlägen noch so probieren:

PHP:
      while ($row = fgetcsv($fp, 1000, ';')) {
            $data[] = $row;
      }
      
      $sql = "UPDATE products SET ek_preis = :ekpreis WHERE products_model2 = :artnr"; 
      $stmt = MyDB::getInstance()->prepare($sql); 

      if( !is_a($stmt, 'PDOStatement' ) ) {
        echo "<pre>"; print_r( MyDB::getInstance()->errorInfo );  echo "</pre>";
        throw new Exception("Error creating prepared statement: Errorcode " . MyDB::getInstance()->errorCode);
      }

      for($c=0;$c<count($data);$c++) {
        $pdoparams = array( 
        ':ekpreis' => str_replace(",",".",$data[$c][1]), 
        ':artnr' => $data[$c][0] );
        if( ! $stmt->execute($pdoparams) ) {
          echo "<pre>"; print_r( $stmt->errorInfo ); echo "</pre>";
          throw new Exception("Error creating prepared statement: Errorcode " . $stmt->errorCode);
        }
        $rows++;
      }

Der große Vorteil von Prepared Statements ist, das man sie nur einmal preparen muss, eine Eigenschaft, die du nicht nutzt, da du bei jeden Schleifendurchlauf neu preparierst.
 
Zurück