PHP/MySQL: Verarbeitung / Durchiterieren von json response aus API-Endpunkt

Yaslaw

alter Rempler
Moderator
Habe mich teilweise geirrt. Das Datum muss doch als String im SQL-Datumsformat vorliegen. Aber ob ein String oder NULL kommt, ist egal
PHP: Vorbereitete Anweisungen (Prepared Statements) - Manual
PHP:
if($created_date == '' or !isset($created_date)) $created_date = null;
$insert_data = <<<SQL
        INSERT INTO {$destination_table_name}(created_date)
        VALUES(?)
        SQL;
//SQL Statement vorbereiten
$stmt = mysqli_prepare($db, $insert_data);
//Parameter übergeben
mysqli_stmt_bind_param($stmt, "s", $created_date);
//Ausführen
mysqli_stmt_execute($stmt);[/php]
 

canju

Mitglied
Ok, danke dir.

das funzt soweit. Was ich auf den ersten Blick recht "nervig" finde und bei vielen Feldern unübersichtlich wird ist dass ich hier: mysqli_stmt_bind_param($stmt, "is", $order_id, $created_date); die typenangabe für jedes feld festlegen muss. Die hab ich ja eigtl. schon in der DB selbst festgelegt.

"issiisssi":
PHP:
mysqli_stmt_bind_param($stmt, "issiisssi", $feld1, $feld2, $feld3, $feld4, $feld5, $feld6, $feld7, $feld8, $feld9)

Ich habe 63 felder die ich importieren muss, gibts da irgendwie eine "übersichtlichere" Variante?
 

Yaslaw

alter Rempler
Moderator
Nimm PDO anstelle von mysqli. Dann kannst du mit benannten Parametern arbeiten.
PHP: Prepared Statements und Stored Procedures - Manual
PHP: PDOStatement::execute - Manual

Musst halt auch die db-anbindung auf PDO umstellen. Ich finde PDO eh besser las mysqli
PHP:
$sth = $dbh->prepare('SELECT name, colour, calories
    FROM fruit
    WHERE calories < :calories AND colour = :colour');
$sth->bindValue(':calories', $calories, PDO::PARAM_INT);
$sth->bindValue(':colour', $colour, PDO::PARAM_STR);

//oder alles in einem. Geht auch ohne Typenzuweisung.
$sth = $dbh->prepare('SELECT name, colour, calories
    FROM fruit
    WHERE calories < :calories AND colour = :colour');
$sth->execute(array(':calories' => $calories, ':colour' => $colour));
 

canju

Mitglied
Hallo nochmal ihr Lieben,

ich hänge wieder an einer Stelle fest.

Ausgangslage:
Den API-Endpunkt mit verschiedenen URL-Parametern aufrufen und alle Ergebnisse pro Request in eine MariaDB speichern.
Es handelt sich hier um Tarifdaten, die abhängig von Verbrauch und Postleitzahl abgefragt werden müssen. Verbrauch und PLZ hole ich mir dabei aus einer vorliegenden DB-Tabelle.
Jeder erfolgreiche Call liefert ~50+ Ergebnisse.

Das Zusammensetzen der Request-URL und das speichern in die Datenbank funktioniert bereits, allerdings wird immer nur das erste Ergebnis jedes Calls in die DB geschrieben.
Angenommen jeder Call liefert 50 Ergebnisse und ich habe 2 Verbrauchs- und Postleitzaheln Einträge vorliegen, so müsste ich eigtl. 100 Einträge in der DB erhalten.

Ich vermute ich habe wieder mal was in der Schleife versemmelt, sodass ich nur je 1 Eintrag erhalte?

Hier mein Code:
PHP:
<?php
$headers = array('Content-Type: application/json', 'Accesskey:' . $accesskey, 'Token:' . $accesstoken, 'charset=utf8mb4');

// destination table to import data
$destination_table_name = "table_name";

/* API url*/
$baseurl = 'https://api-provider.com/api/tariffs';

// querry param_values and put in array
$query_select ="SELECT zipcode, consumption FROM tariff_params";
$result_select = mysqli_query($db,$query_select);

$rows = [];
while($row = mysqli_fetch_array($result_select))
    $rows[] = $row;

$data=array();
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

/* Assign parameter values here */
foreach($rows as $row) {
    $zipcode              = $row['zipcode'];
    $consumption_primary  = $row['consumption'];

    /* $_GET Parameters to Send */
    $params = array(
        'zipcode'             =>   $zipcode,
        'consumption_primary' =>   $consumption
    );

    /* Update URL to container Query String of Paramaters */
    $url = urldecode($baseurl . '?' . http_build_query($params));
    echo($url);
    curl_setopt($ch, CURLOPT_URL, $url);
    $curl_response = curl_exec( $ch );

    // convert response into ass. array
    $decoded = json_decode($curl_response, true);

    if($decoded['success'] == 0) {
      echo "Keine Tarife zur Kombination vorhanden: $zipcode und $consumption \n";
      continue;
    } else {
          //get desired fields
          $tariff_id = $decoded["data"]["result"][0]["tariff_id"];

          //insert into mysql table
          $insert_data = <<<SQL
                INSERT INTO {$destination_table_name} (
                  tariff_id
                )
                  VALUES (?)
                SQL;
          //SQL Statement vorbereiten
          $stmt = mysqli_prepare($db, $insert_data);
          //Parameter übergeben
          mysqli_stmt_bind_param($stmt, "s",
                                $tariff_id
                                );
          //Ausführen
          mysqli_stmt_execute($stmt);
      }

}

curl_close($ch);
mysqli_close($db);

?>


var_dump($decoded); (hier stark eingekürzt) gibt mir auf jeden Fall alle Ergebnisse aus
Code:
array(2) {
  ["success"]=> int(1)
  ["data"]=> array(1) {
    ["result"]=> array(124) {
      [0]=> array(178) {
        ["tariff_id"]=> int(722571494)
Ich finde den Fehler nicht. Könnt ihr mir nochmal helfen bitte.


Grüße,
canju
 

canju

Mitglied
Nimm PDO anstelle von mysqli. Dann kannst du mit benannten Parametern arbeiten.
PHP: Prepared Statements und Stored Procedures - Manual
PHP: PDOStatement::execute - Manual

Musst halt auch die db-anbindung auf PDO umstellen. Ich finde PDO eh besser las mysqli
PHP:
$sth = $dbh->prepare('SELECT name, colour, calories
    FROM fruit
    WHERE calories < :calories AND colour = :colour');
$sth->bindValue(':calories', $calories, PDO::PARAM_INT);
$sth->bindValue(':colour', $colour, PDO::PARAM_STR);

//oder alles in einem. Geht auch ohne Typenzuweisung.
$sth = $dbh->prepare('SELECT name, colour, calories
    FROM fruit
    WHERE calories < :calories AND colour = :colour');
$sth->execute(array(':calories' => $calories, ':colour' => $colour));
Danke dir, werde ich ggf. in einem der nächsten Projekte einsetzen, muss mich da erst reinarbeiten. Bin froh, dass ich erstmal halbwegs mit mysqli "klar komme". Aber man lernt nie aus.
 

Sempervivum

Erfahrenes Mitglied
Beim Durchlesen kann ich nicht erkennen, dass Du etwas in der Schleife versemmelt hättest. Um das weiter zu untersuchen, schlage ich vor, auch mal im Erfolgszweig ein echo einzubauen, damit Du siehst, was passiert:
Code:
    if($decoded['success'] == 0) {
      echo "Keine Tarife zur Kombination vorhanden: $zipcode und $consumption \n";
      continue;
    } else {
          echo "Daten erfolgreich geladen";
          //get desired fields
          $tariff_id = $decoded["data"]["result"][0]["tariff_id"];
 

canju

Mitglied
Scheint zu funktionieren:
Code:
https://api-provider.com/api/tariffs?zipcode=08297&consumption=2500
Daten erfolgreich geladen
https://api-provider.com/api/tariffs?zipcode=18556&consumption=4000
Daten erfolgreich geladen
Die URL lasse ich mir weiter oben in der Schleife echo'n
 

Sempervivum

Erfahrenes Mitglied
Selber nicht so der PHP- und Datenbankexperte finde ich da dieses von jemand, der das gleiche Problem hatte wie Du:
PHP Prepare method not working when calling it twice?
Ich empfehle, das prepare nur einmal vor der Schleife zu machen und innerhalb der Schleife dann nur das bind_param und execute. Wenn ich das richtig verstehe, wäre das genau das was prepared statements vorsehen: Die Abfrage mit prepare einmal vorbereiten, dann kann sie mit unterschiedlichen Parametern mehrfach ausgeführt werden.
 

canju

Mitglied
Hmm, bleibt dabei. weiterhin nur jeweils ein Eintrag des ersten Ergebnisses.
So meintest du oder?:
PHP:
<?php
$headers = array('Content-Type: application/json', 'Accesskey:' . $accesskey, 'Token:' . $accesstoken, 'charset=utf8mb4');

// destination table to import data
$destination_table_name = "table_name";

/* API url*/
$baseurl = 'https://api-provider.com/api/tariffs';

// querry param_values and put in array
$query_select ="SELECT zipcode, consumption FROM tariff_params";
$result_select = mysqli_query($db,$query_select);

$rows = [];
while($row = mysqli_fetch_array($result_select))
    $rows[] = $row;

$data=array();
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

          //insert into mysql table
          $insert_data = <<<SQL
                INSERT INTO {$destination_table_name} (
                  tariff_id
                )
                  VALUES (?)
                SQL;
          //SQL Statement vorbereiten
          $stmt = mysqli_prepare($db, $insert_data);
          //Parameter übergeben
          mysqli_stmt_bind_param($stmt, "s",
                                $tariff_id
                                );


/* Assign parameter values here */
foreach($rows as $row) {
    $zipcode              = $row['zipcode'];
    $consumption_primary  = $row['consumption'];

    /* $_GET Parameters to Send */
    $params = array(
        'zipcode'             =>   $zipcode,
        'consumption_primary' =>   $consumption
    );

    /* Update URL to container Query String of Paramaters */
    $url = urldecode($baseurl . '?' . http_build_query($params));
    echo($url);
    curl_setopt($ch, CURLOPT_URL, $url);
    $curl_response = curl_exec( $ch );

    // convert response into ass. array
    $decoded = json_decode($curl_response, true);

    if($decoded['success'] == 0) {
      echo "Keine Tarife zur Kombination vorhanden: $zipcode und $consumption \n";
      continue;
    } else {
          //get desired fields
          $tariff_id = $decoded["data"]["result"][0]["tariff_id"];

          //Ausführen
          mysqli_stmt_execute($stmt);
      }

}

curl_close($ch);
mysqli_close($db);

?>


Hier nochmal der var_dump($decoded); (stark eingekürzt)

Code:
https://api-provider.com/api/tariffs?zipcode=08297&consumption=2500
Daten erfolgreich geladen
array(2) {
  ["success"]=>  int(1)
  ["data"]=>  array(1) {
    ["result"]=> array(121) {
      [0]=> array(178) {
        ["tariff_id"]=> int(452171494)
      [1]=> array(178) {
        ["tariff_id"]=> int(654149933)
      [2]=>  array(176) {
        ["tariff_id"]=> int(214286138)
      [3]=> array(176) {
        ["tariff_id"]=> int(571337882)
      ...   

https://api-provider.com/api/tariffs?zipcode=18556&consumption=4000
Daten erfolgreich geladen

array(2) {
  ["success"]=> int(1)
  ["data"]=> array(1) {
    ["result"]=> array(114) {
      [0]=>  array(176) {
        ["tariff_id"]=> int(831499737)
      [1]=>  array(176) {
        ["tariff_id"]=> int(647263587)
      [2]=> array(176) {
        ["tariff_id"]=> int(124773076)
      [3]=> array(176) {
        ["tariff_id"]=> int(674553389)
      ...