PHP-Script: Ausführung per Cronjob gelingt nicht, Speicher voll

  • Hallo,

    ich habe vor längerer Zeit bereits einen Raspberry erhalten. Bislang dümpelte er vor sich hin und hat die Wetterdaten aufgezeichnet. Aktuell ist er in den Vordergrund gerückt, da ich für eine kleinere Auswertung automatisiert Aktien-/Währungsdaten ziehen und speichern möchte.

    Dazu gibt es einmal folgendes Shell-Script (stocks.sh):

    Bash
    #!/bin/sh
    # Daten holen
    curl -s 'http://download.finance.yahoo.com/d/quotes.csv?s=BAS.DE,DAI.DE,USDEUR=X,WBA,WFC,WTR&f=snl1de7jke8rc4&e=.csv' | tee /home/pi/aktien/daten.csv


    Das Script wird nach vorgegebenen Zeiten mittels Cronjob aufgerufen und ausgeführt (crontab).

    Code
    1 0 * * * 1-5 /home/pi/aktien/stocks.sh


    Bis dahin funktioniert alles tadellos. Die Datei daten.csv enthält immer die aktuellen Daten.
    Dann habe ich ein PHP-Script, welches die Daten aus der daten.csv in eine MySQL-Datenbank übertragen soll. Rufe ich es in der Konsole mittels

    Code
    php /home/pi/aktien/index.php


    auf, dann läuft es durch und die Daten sind in der Datenbank.

    Die Datei ist mittels chmod +x index.php ausführbar gemacht und enthält zudem den Shebang

    Code
    #!/usr/bin/php


    Versuche ich aber das Script durch die stocks.sh aufzurufen mittels

    Code
    php /home/pi/aktien/index.php


    oder

    Code
    /usr/bin/php /home/pi/aktien/index.php


    dann werden keine Daten übertragen.

    Auch der Aufruf mittels Cronjob schlägt fehl:

    Code
    10 0 * * * 1-5 /usr/bin/php /home/pi/aktien/index.php

    Um zu prüfen, ob das PHP-Script überhaupt läuft, erzeugt dieses am Ende eine Datei update.info, in welcher sie das Datum und die Uhrzeit speichert. Manuell in der Konsole ausgeführt, funktioniert es - egal ob ich die index.php über die stocks.sh aufrufe oder ob ich sie direkt starte. Das Ganze via Cronjob schlägt fehl - sowohl wenn der Aufruf durch die stocks.sh erfolgt, wie auch direkt als eigener Cronjob.

    Lasse ich die Ausführung per Cronjob erledigen, läuft mir mit der Zeit der Speicher des Raspberry voll, weil zwar jedes Mal die index.php aufgerufen, aber nicht beendet wird.

    Ich habe schon nach diversen Lösungen gesucht, aber bislang will das bei mir einfach nicht funktionieren. Die Daten landen nicht in der Datenbank - außer bei manuellem Aufruf. Irgendwelche Ideen, wo der Fehler stecken könnte?

  • PHP-Script: Ausführung per Cronjob gelingt nicht, Speicher voll? Schau mal ob du hier fündig wirst!

  • Ups... Das ist mir tatsächlich durchgerutscht...


    [code=php]#!/usr/bin/php
    <?php
    $db_host = 'localhost';
    $db_user = 'user';
    $db_password = 'pwd';
    $db_name = 'daten';
    $db = new mysqli($db_host, $db_user, $db_password, $db_name);
    if ($db->connect_error){
    die("Auf Datenbank kann nicht zugegriffen werden: " . $db->connect_error);
    }
    $fp = fopen('daten.csv', 'r');

    $daten = array();
    while(!feof($fp)){
    $daten = fgetcsv($fp, 4096, ",");
    $zeile = array();
    foreach($daten as &$detail){
    $zeile[] = str_replace("N/A", "0.0", $detail);
    }
    $query = "INSERT INTO Daten (Kuerzel, Bezeichnung, Kurs, Div_Prognose, EPS, Low, High, EPS_NextY, KGV, Waehrung) VALUES ('".$zeile[0]."', '".$zeile[1]."', ".$zeile[2].", ".$zeile[3].", ".$zeile[4].", ".$zeile[5].", ".$zeile[6].", ".$zeile[7].", ".$zeile[8].", '".$zeile[9]."')";
    $db->query($query);
    }
    fclose($fp);
    $db->close();
    $Datum = date("d.m.Y", time()). " - " . date("H:i", time());
    $fp = fopen('update.info','a+');
    fwrite($fp, $Datum);
    fclose($fp);
    ?>
    [/php]

  • Wieso nutzt du PHP zum schreiben in die Datenbank?
    Wenn ich das richtig sehe möchtest du die PHP Datei eh nicht übers Web ansprechen - dann könntest du das auch direkt im bash Script abhandeln und PHP weg lassen :huh: Du könntest aber auch bash weg lassen und alles in PHP machen :D

    Übrigens: Wenn du die Datei direkt dem Interpreter übergibst wird ein Shebang ignoriert und 'chmod +x' ist dann auch wurscht ;)

  • Probehalber in die stocks.sh aufgenommen und diese gestartet, läuft es durch und die Daten sind in der Datenbank. Bleibt das Ergebnis des Cronjobs abzuwarten.

    Schon mal vielen Dank!


    Wieso nutzt du PHP zum schreiben in die Datenbank?
    Wenn ich das richtig sehe möchtest du die PHP Datei eh nicht übers Web ansprechen - dann könntest du das auch direkt im bash Script abhandeln und PHP weg lassen :huh:


    Korrekt, das PHP-Script soll nicht übers Weg gestartet werden.

    Ich hatte überlegt, die Daten direkt über Shellscript in die DB zu laden. Allerdings schlägt dies fehl, da in der CSV manchmal N/A steht. Das hat mir jedes Mal die DB zerhauen. Ich muss aber eingestehen, dass meine Kenntnisse in Sachen Shellprogrammierung sehr rudimentär sind.

    Einmal editiert, zuletzt von comlar (20. Februar 2017 um 15:56)

  • Du kannst das auch direkt in PHP abhandeln wenn dir bash nicht so liegt ;) Hätte den Vorteil das du die SD nicht unnötig mit dem schreiben der *.csv Datei belastest...

    [code=php]
    <?php
    $url='http://download.finance.yahoo.com/d/quotes.csv?s…7jke8rc4&e=.csv';
    $daten = file($url);

    $zeile=array();
    foreach($daten as $detail){
    echo $detail;
    $zeile[] = str_replace("N/A", "0.0", $detail);
    }
    var_dump($zeile);
    ?>
    [/php] die echo und var_dump Zeile ist nur zum debuggen und dein MySQL Zeug musst du da natürlich auch noch einbauen ;)

    Warum du deine Datenbank mit N/A zerschießt ist etwas seltsam.. Normal ist sowas jedenfalls nicht. Evtl. die Tabelle falsch erzeugt?


  • Du kannst das auch direkt in PHP abhandeln wenn dir bash nicht so liegt ;) Hätte den Vorteil das du die SD nicht unnötig mit dem schreiben der *.csv Datei belastest...


    Super Vorschlag! Das PHP-Script war ein erster Entwurf und noch nicht ausgereift. Von daher bietete sich natürlich Deine Idee zur Umsetzung an.


    Warum du deine Datenbank mit N/A zerschießt ist etwas seltsam.. Normal ist sowas jedenfalls nicht. Evtl. die Tabelle falsch erzeugt?


    Die eigentliche Tabelle hat noch ein paar optionale Spalten, die nicht mit Daten aus der Datei befüllt werden. Ich habe die CSV-Datei versucht über LOAD DATA INFILE zu importieren. Das gab dann Probleme mit der Zuordnung der eingelesenen Daten zur richtigen Spalte und wenn in der CSV-Datei ein N/A auftauchte, waren danach in der Datenbank alle Felder fehlerhaft. Beides vermutlich auch zu lösen, wenn man weiß wie... ;) Für einen Anfang war der Umweg über PHP für mich gangbarer. Ich wollte mich aber nochmal mit dem LOAD DATA INFILE befassen - das scheint mir letztendlich die komfortablere Lösung zu sein, sofern sie zur Anwendung gelangen kann.

    Zwischenzeitlich hätte das Script zwei Mal durchlaufen müssen, so dass sich Testdaten in der Datenbank befinden sollten. Leider ist dies immer noch nicht der Fall. Die eingangs erwähnte Problematik besteht also nach wie vor.

    Einmal editiert, zuletzt von comlar (20. Februar 2017 um 18:21)


  • Bitte poste das aktuelle Script - oder stelle selber sicher das du wirklich absolute Pfade zu den Dateien verwendest


    Am Script hat sich nicht viel verändert, da ich bislang nur die Pfade geändert habe (Deine obigen Vorschläge konnte ich noch nicht einarbeiten). Einmal zur CSV-Datei und einmal zur Logdatei update.info. Rufe ich das Script direkt in der Shell auf, werden die Daten in die DB übertragen. Bei Aufruf mittels Cronjob oder über stocks.sh nicht.

    [code=php]#!/usr/bin/php

    <?php
    $db_host = 'localhost';
    $db_user = 'user';
    $db_password = 'pwd';
    $db_name = 'daten';
    $db = new mysqli($db_host, $db_user, $db_password, $db_name);
    if ($db->connect_error){
    die("Auf Datenbank kann nicht zugegriffen werden: " . $db->connect_error);
    }

    $fp = fopen('/home/pi/aktien/daten.csv', 'r');
    $daten = array();

    while (!feof($fp)){

    $daten = fgetcsv($fp, 4096, ",");

    $zeile = array();

    foreach($daten as &$detail){
    $zeile[] = str_replace("N/A", "0.0", $detail);
    }

    $query = "INSERT INTO Daten (Kuerzel, Bezeichnung, Kurs, Div_Prognose, EPS, Low, High, EPS_NextY, KGV, Waehrung) VALUES ('".$zeile[0]."', '".$zeile[1]."', ".$zeile[2].", ".$zeile[3].", ".$zeile[4].", ".$zeile[5].", ".$zeile[6].", ".$zeile[7].", ".$zeile[8].", '".$zeile[9]."')";


    $db->query($query);
    }
    fclose($fp);
    $db->close();

    $Datum = date("d.m.Y", time()). " - " . date("H:i", time())."\n";
    $fp = fopen('/home/pi/aktien/update.info','a+');
    fwrite($fp, $Datum);
    fclose($fp);
    ?>[/php]

    Einmal editiert, zuletzt von comlar (20. Februar 2017 um 18:41)

  • Der Cronjob an sich dürfte nicht das Problem sein: Die Datei stocks.sh wird nachweislich aufgerufen und ausgeführt. Und in dieser soll wiederum die index.php aufgerufen werden. Aber das passiert nicht.

    Das Logfile gibt folgendes an (wenn ich es so ändere, dass die index.php separat durch einen Cronjob ausgeführt wird):

    Code
    Feb 19 17:20:01 raspberrypi CRON[29151]: (pi) CMD (/home/pi/aktien/stocks.sh)
    Feb 19 17:20:01 raspberrypi CRON[29152]: (pi) CMD (/usr/bin/php /home/pi/aktien/index.php)
    Feb 19 17:20:25 raspberrypi CRON[19529]: (CRON) info (No MTA installed, discarding output)


    Fehlermeldungen hierzu sind nicht vorhanden. Die MTA-Meldung dürfte irrelevant sein.

    Einmal editiert, zuletzt von comlar (20. Februar 2017 um 18:57)

  • Na, offensichtlich gibt es doch ein Problem beim ausführen der php Datei - crontab versucht zumindest Ausgaben zu mailen, es ist aber kein MTA eingestellt .... Also generell zeigt diese MTA Zeile im crontab-Log dass der vorherige Crontabeintrag eine Ausgabe erzeugt hat, ob das nun eine reguläre Ausgabe oder eine Fehlerausgabe ist steht da so nicht.....

    Also:
    1) stocks.sh zeigen
    2) Mögliche Ausgaben sowie Fehlermeldungen in eine Datei umleiten lassen

    Wie 2. geht steht in besagter Anleitung unter "Anmerkungen", nur halt nicht in den Mülleimer sondern einer Datei, auch natürlich wieder mit absolutem Pfad.

  • Kein Problem. Das kann ich entsprechend anpassen.

    Ich vermute, dass die Ausgabe, welche erzeugt wird, von der PHP-Datei selbst stammt. Da waren anfangs noch Ausgaben vorgesehen (SQL-Anweisungen wurden zur Überprüfung ausgegeben, Rückmeldungen über Datenbankverbindung usw.). Die hatte ich für's Forum rausgenommen, um es übersichtlich zu halten.

    Die stocks.sh habe ich bereits im ersten Beitrag stehen (erster Code-Block).

  • Ich vermute, dass die Ausgabe, welche erzeugt wird, von der PHP-Datei selbst stammt.

    Da brauchst du nichts vermuten - das ist Fakt :fies: Hab ich doch gerade beschrieben: Erst wird das PHP Script von Crontab ausgeführt, danach kommt eine MTA Meldung... Ergo gab es irgend ein Output der PHP Datei.

    Da waren anfangs noch Ausgaben vorgesehen (SQL-Anweisungen wurden zur Überprüfung ausgegeben, Rückmeldungen über Datenbankverbindung usw.). Die hatte ich für's Forum rausgenommen, um es übersichtlich zu halten.

    Das ist nicht cool... Könnte uns einige Mühe spart wenn du direkt den tatsächlichen Code gezeigt hättest... Wer weiß vllt steckt da auch ein kleiner Fehler drin den du übersiehst?

    Der erste Fehler, der auch ständig gemacht wird: keine absoluten Pfade. Woher soll crontab wissen wo "daten.csv" sein soll bzw das es auch noch einen Unterordner im HOME des Benutzers gibt wo die Datei rein soll?
    Das nächste wäre: Keine Schreibrechte auf die zu erzeugenden Dateien. Hast du das Script zuvor vielleicht mit "sudo" ausgeführt? Dann würde die daten.csv root gehören aber "pi" darf da natürlich nicht drin rum schreiben...

  • Da brauchst du nichts vermuten - das ist Fakt :fies: Hab ich doch gerade beschrieben: Erst wird das PHP Script von Crontab ausgeführt, danach kommt eine MTA Meldung... Ergo gab es irgend ein Output der PHP Datei.


    Das habe ich auch nur bestätigt. Und hier die Meldung:


    Zeile 25:
    [code=php]foreach($daten as &$detail){[/php]
    Zeile 29:
    [code=php]$query = "INSERT INTO Daten (Kuerzel, Bezeichnung, Kurs, Div_Prognose, EPS, Low, High, EPS_NextY, KGV, Waehrung) VALUES ('".$zeile[0]."', '".$zeile[1]."', ".$zeile[2].", ".$zeile[3].", ".$zeile[4].", ".$zeile[5].", ".$zeile[6].", ".$zeile[7].", ".$zeile[8].", '".$zeile[9]."')";[/php]
    Die Meldungen gibt es auch, wenn ich das PHP-Script direkt in der Konsole starte. Dennoch läuft es durch und trägt die Daten ein. Weitere Meldungen gibt es nicht.

    Das ist nicht cool... Könnte uns einige Mühe spart wenn du direkt den tatsächlichen Code gezeigt hättest... Wer weiß vllt steckt da auch ein kleiner Fehler drin den du übersiehst?


    Da ich zu 100% ausschließen kann, dass der Fehler von einer Zeile wie bspw. echo $query; oder echo "Datenübertragung beendet"; bzw. // Daten der Datenbankverbindung kommt, habe ich mir tatsächlich erlaubt, sie nicht zu posten. Der Übersichtlichkeit willen. Darin kann ich keinen Fehler erkennen. Zumal solche einfachen Fehler üblicherweise durch die IDE direkt angezeigt werden.

    Das nächste wäre: Keine Schreibrechte auf die zu erzeugenden Dateien. Hast du das Script zuvor vielleicht mit "sudo" ausgeführt? Dann würde die daten.csv root gehören aber "pi" darf da natürlich nicht drin rum schreiben...


    Also ich habe zwar den Pi noch nicht intensiv eingesetzt, aber d.h. nicht, dass ich völlig unbedarft bin. Die Scripte werden und wurden nicht mit sudo ausgeführt. Alle Dateirechte liegen bei pi, der die Scripte auch ausführt. Deshalb auch den Eintrag in der Crontab des Benutzers und nicht in der Crontab des Systems.

    Der erste Fehler, der auch ständig gemacht wird: keine absoluten Pfade. Woher soll crontab wissen wo "daten.csv" sein soll bzw das es auch noch einen Unterordner im HOME des Benutzers gibt wo die Datei rein soll?


    Das nehme ich wiederum gerne auf meine Kappe. Das war war tatsächlich eine Unaufmerksamkeit von mir, die ich aber direkt nach dem ersten Hinweis bereits korrigiert habe. Daran sollte es also auch nicht mehr liegen.

    Einmal editiert, zuletzt von comlar (20. Februar 2017 um 20:48)

  • Hm dann würde ich vermuten dass das PHP Script keinen "Return Code" oder auch "Exit Code" von 0 zurück gibt sondern höher - da es eine Fehlermeldung gab. Jeder exitcode > 0 deutet auf ein Fehler oder Problem hin.
    Siehe dazu auch:
    https://de.wikipedia.org/wiki/Return_Code
    http://de.wikipedia.org/wiki/Signal_(Unix)

    Auf jeden Fall solltest du möglichst fehlerfrei programmieren, auch wenn es so aussieht als würde es trotzdem funktionieren... Insbesondere "Warning" Meldungen sollte man nicht ignorieren.

    Bevor du jetzt aber rum grübelst wie du dein Konstrukt fehlerfrei kriegst, mach es doch direkt ohne bash Script und wurschtel dein Zeug da noch zu:

    Beachte:
    Es gibt nicht immer eine 10. bzw 11. Spalte
    In der letzten Spalte bzw am Ende jeder Zeile ist ein Zeilenumbruchszeichen enthalten, deshalb der extra trim().


  • Die stocks.sh habe ich bereits im ersten Beitrag stehen (erster Code-Block).

    Aber nicht vollständig: Der aktuelle Aufruf des PHP-Skriptes steht da nicht drin.

    Code
    PHP Warning:  Invalid argument supplied for foreach() in /home/pi/aktien/index.php on line 25
    PHP Notice:  Undefined offset: 0 in /home/pi/aktien/index.php on line 29
    ...
    PHP Notice:  Undefined offset: 9 in /home/pi/aktien/index.php on line 29

    Gib doch mal in Deinem Skript nach jedem fgetcsv() die eingelesenen $daten aus - vielleicht gibt das ja einen Hinweis, was das Skript einliest. Deine CSV-Datei scheint es nach den obigen Meldungen jedenfalls nicht zu sein...

  • Also ich bedanke mich nochmals für die bisherigen Hilfestellungen.

    Beachte:
    Es gibt nicht immer eine 10. bzw 11. Spalte

    Das ist ein Problem, dass sich aber erst durch Deine vorgeschlagene Lösungsvariante mit explode ergibt. Dein Delimiter ist nämlich manchmal Teil der Firmenbezeichnung. Konkret zB hier:

    Das "Inc" ist Teil der Firmenbezeichnung, aber mittels Komma getrennt und durch den Einsatz von explode wird es separiert. Das darf natürlich nicht passieren, da sonst eine Übertragung in die Datenbank fehlschlägt.

    Aber nicht vollständig: Der aktuelle Aufruf des PHP-Skriptes steht da nicht drin.

    Doch vollständig. Weil der Aufruf des PHP-Scripts per Cronjob erfolgen soll. Ich habe das PHP-Script nur testweise über die stocks.sh aufgerufen. Ich wollte schließlich ausschließen, dass es am Cronjob liegt, dass die Ausführung nicht erfolgt. Also: Exakt so, wie die stocks.sh oben angezeigt wird, entspricht sie auch der Realität.

    Gib doch mal in Deinem Skript nach jedem fgetcsv() die eingelesenen $daten aus - vielleicht gibt das ja einen Hinweis, was das Skript einliest. Deine CSV-Datei scheint es nach den obigen Meldungen jedenfalls nicht zu sein...

    Was soll es denn sonst sein? Wenn ich das Script manuell starte passt doch alles? Ich habe dennoch Deinen Vorschlag umgesetzt. Das Ergebnis:

    Alle Daten der Datei werden eingelesen. Am Ende der Datei gibt es einen Fehler, da nichts mehr eingelesen werden kann. Dazu die Fehlermeldung aus Zeile 26:

    [code=php]foreach($daten as &$detail){[/php]

  • Okay, ich hatte das hier


    Die Meldungen gibt es auch, wenn ich das PHP-Script direkt in der Konsole starte.

    übersehen und angenommen, die Fehlermeldungen träten nur im cronjob auf. Persönlich würde ich ja ein "if $daten != false" vor das foreach setzen, um die Meldungen zu vermeiden, aber Dein Problem liegt offenbar woanders.

    Sicherheitshalber nachgefragt: Der output in Post #19 ist aus dem cronjob heraus entstanden? Und der gibt außer den Fehlermeldungen nichts aus? Wird denn die update.info vom cronjob geschrieben? Und kannst Du noch mal den genauen Eintrag in der crontab zeigen? In welcher crontab steht der?

    Reine Spekulation: Kann es sein, daß das PHP-Skript im cronjob aus irgendwelchen Gründen mit den obigen Fehlermeldungen aussteigt, deswegen die Datenbankverbindung nicht vernünftig geschlossen und deswegen evtl. die SQL statements nicht commited werden? Bau doch hinter das Schließen der DB noch mal eine Ausgabe, damit man sieht, ob das Skript bis dahin kommt. Sonst fällt mir erst mal nichts ein...

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!