Jörg: Datenbanken sichern

0 75

Datenbanken sichern

Jörg
  • datenbank
  • php
  • sicherheit
  1. 0
    Raketentester
    1. 0

      Noch ein Hinweis

      Raketentester
    2. 0

      Letzte Hinweise

      Raketentester
      1. 0
        Jörg
    3. 0
      Jörg
      1. 0
        Raketentester
        1. 0
          Jörg
          1. 0
            Raketentester
            1. 0
              Jörg
              1. 0
                Jörg
                1. 0
                  Raketentestpilot
  2. 0

    Das willst Du auch nicht...

    Raktentester
    1. 0
      Jörg
      1. 0
        Raketentester
        1. 0

          Das willst Du auch nicht... / Nachfrage

          Jörg
          1. 0
            Raketentestpilot
            1. 0
              Jörg
              1. 0
                Raketentestpilot
              2. 0
                Rolf B
                1. 0
                  Jörg
                  1. 0
                    Rolf B
                    1. 0
                      Jörg
                      1. 0
                        Der Martin
                    2. 0
                      Jörg
                      1. 0
                        Jörg
                        1. 0
                          Raketenskripter
                          1. 0
                            Rolf B
                            1. 0
                              Raketenrechtgeber
                          2. 0
                            Jörg
                            1. 0

                              „Tut“ leider nicht

                              Raketenskripter
                              1. 0
                                Jörg
                  2. 0

                    Warum denn einfach wenn es kpmpliziert geht ...

                    Raketenskripter
                    1. 0
                      Rolf B
                      1. 0
                        Raketenskripter
                        1. 0
                          Rolf B
                          1. 0
                            Raketenskripte
                    2. 0

                      Ein paar weitere Funktionen ...

                      Raketenskripter
                      1. 0
                        Rolf B
                        1. 0
                          Raketenskripter
                          1. 0
                            Jörg
                            1. 0
                              Raketenskripter
                      2. 0
                        Jörg
                        1. 0
                          Raketenskripter
                          1. 0
                            Jörg
                            1. 0
                              Raketenskripter
                              1. 0
                                Raketenskripter
                              2. 0
                                Jörg
                          2. 0
                            Jörg
                            1. 0
                              Raketenskripter
                              1. 0
                                Raketenskripter
                              2. 0
                                Jörg
                                1. 0
                                  Raktenskripter
                                  1. 0
                                    Raketenskripter
                                    1. 0
                                      Jörg
                                      1. 0
                                        Raketenskripter
                                2. 0
                                  Jörg
                                  1. 0
                                    Raketenskripter
                                    1. 0
                                      Jörg
                                      1. 0

                                        Shellscripting

                                        Jörg
                                        1. 0
                                          Raketenskripter
                                          1. 0
                                            Jörg
                                            1. 0
                                              Jörg
                                              1. 0
                                                Raketenskripter
                                                1. 0
                                                  Jörg
                                                  1. 0
                                                    Raketenwilli
                                                    1. 0
                                                      Jörg
                  3. 0

                    Statt Support

                    Raketentestpilot
                    1. 0
                      Jörg
  3. 0

    Datenbanken sichern / Nochmal mit Kommentaren

    Jörg
    1. 0
      Jörg
      1. 0
        MudGuard
        1. 0
          Jörg
    2. 0
      dedlfix
      1. 0
        Jörg

Hallo,

leider kann ich meine Datenbanken nicht per ssh sichern, hierzu fehlen mir Rechte. Bisher habe ich sie mit einem perlscript gesichert, was seinerzeit beim sqldumper dabei war. Funktioniert einigermaßen komfortabel, aber nicht 100% zuverlässig, wenn ich neue Datenbanken einpflege und diese nicht sofort auch in die config-Datei des perlscripts übernehme.

Daher habe ich ein script geschrieben, das diese Arbeit übernehmen soll.

Es soll ermitteln, welche Datenbanken vorhanden sind und diese dann nach und nach sichern, wobei sich das script dann jeweils selber wieder aufrufen soll.

Ich würde das script hier gerne mal zur Diskussion stellen ujnd um eventuelle verbesserungen und Kritik bitten.

Btw.: Ich würde sagen, es sollte laufen, aber ich habs noch nicht Probe laufen lassen können, da system-Befehle auf meinem Testserver nicht laufen. Auf dem produktivserver laufen sie, aber dort habe ich nur den reinen "Dump-Teil" getestet. Der läuft.

$sql = "SHOW DATABASES";
$dbhost = 'localhost';
$dbuser = 'user';
$dbpass = 'pass';
$path = '/bla/bla/';

$link = mysqli_connect($dbhost,$dbuser,$dbpass) or die ('Error connecting to mysql: '.mysqli_error($link).'\r\n');

if(!($result = mysqli_query($link,$sql))) {
    printf("Error: %s\n",mysqli_error($link));
}

while($row = mysqli_fetch_row($result)) {
    if(($row[0] != "mysql") || ($row[0] == "information_schema")) {
        // DB-User sind immer die ersten 10 zeichen des DB-Namens
        $arr_list[] = $row[0]."_".substr($row[0],0,10);
    }
}

if(!isset($_GET['listID'])) {
    $listID = 0;
} else {
    $listID = $_GET['listID'];
}

while($listID < count($arr_list)) {
    $myEintrag = $arr_list[$listID];
    $arr_myEintrag = explode('_',$myEintrag);
    $dbname = $arr_myEintrag[0];
    $dbuser = $arr_myEintrag[1];
    $db_kennzeichen = $dbuser.'_'.date("d_m_Y_G_i");

    system('/usr/bin/mysqldump -u'.$dbuser.' -p'.escapeshellarg($dbpass).' -h'.$dbhost.' '.$dbname.' | /bin/gzip >'.$path.'dump/'.$db_kennzeichen.'.sql.gz',$fp);

    if(($fp == 0) && (false !== chmod($path.'dump/'.$db_kennzeichen.'.sql.gz',0666))) {
        //echo "Daten exportiert";
    } else {
        echo "Es ist ein Fehler aufgetreten".$fp;
    }
    $listID++;
    header("Location: http://mysite.bla/dump.php?listID=".$listID."");
}
echo "fertig";
exit;
  1. Die Zeile

    #$dbuser = $arr_myEintrag[1];
    

    hab ich auskommentiert, weil sonst wurde natürlich versucht, in der Zeile

    system('/usr/bin/mysqldump -u'.$dbuser.' -p'.escapeshellarg($dbpass)

    diesen ermittelten Benutzername zu verwenden, der dann nicht zum Passwort passte (oder nicht visa versa).

    $dbuser und $dbpass wurden ja in den Zeilen 3 und 4 konfiguriert.

    Ach so. Du dumpst auch das Schema namens „shema".

    1. Ach so:

    2. chmod($path.'dump/'.$db_kennzeichen.'.sql.gz',0666)

      0666: Ich bin mir fast sicher, dass Du DAS nicht willst. Willst Du es, dann solltest Du DAS nicht wollen.

      Bei Nutzung eines normalen benutzernamens (nicht: root) scheitert das Sichern des Schemas "information_schema". Den Grund findest Du in Deinem Skript ('information' sind 10 Zeichen…, dann folgt ein Unterstrich)

      Die Ausgabe von $arr_list lautete in meinem Test:

      array(3) {
        [0]=>
        string(7) "OSM_OSM"
        [1]=>
        string(29) "information_schema_informatio"
        [2]=>
        string(9) "test_test"
      }
      

      Vielleicht soll ja

      if(($row[0] != "mysql") || ($row[0] == "information_schema")) {
      

      viel mehr

      if ( 
          $row[0] != "mysql" &&
          $row[0] != "information_schema"
      ) {
      

      lauten?

      1. Vielleicht soll ja

        if(($row[0] != "mysql") || ($row[0] == "information_schema")) {
        

        viel mehr

        if ( 
            $row[0] != "mysql" &&
            $row[0] != "information_schema"
        ) {
        

        lauten?

        Ja, natürlich. Hab ich vergessen, wieder zu ändern. Ursprünglich hieß es natürlich so. Danke für den Hinweis.

        Jörg

    3. Hallo Raketen*

      Die Zeile

      #$dbuser = $arr_myEintrag[1];
      

      hab ich auskommentiert, weil sonst wurde natürlich versucht, in der Zeile

      Hab ich etwas verpasst? Wo hast Du das gemacht?

      Zudem: Die darfst Du nicht auskommentieren, die Variable muss überschrieben werden. Das (Master)passwort bleibt bestehen.

      Jörg

      1. Wo hast Du das gemacht?

        Vielleicht in Deinem Skript?

        Zudem: Die darfst Du nicht auskommentieren, die Variable muss überschrieben werden.

        Nicht auf meinem System.

        Haben denn alle Datenmbanken/Schemas einen eigenen User? Und wieso haben dann alle das gleiche Passwort? Und wieso willst Du diese nicht unter Angabe des „Masterusers“ mit dem „Masterpasswort“ sichern?

        Hat der eventuell keine Leserechte an Tabellen oder Spalten?

        1. Haben denn alle Datenmbanken/Schemas einen eigenen User? Und wieso haben dann alle das gleiche Passwort? Und wieso willst Du diese nicht unter Angabe des „Masterusers“ mit dem „Masterpasswort“ sichern?

          Alle Datenbanken haben einen eigenen User und ein eigenes Passwort. Zudem kann ich das Masterpasswort nutzen.

          1. Haben denn alle Datenmbanken/Schemas einen eigenen User? Und wieso haben dann alle das gleiche Passwort? Und wieso willst Du diese nicht unter Angabe des „Masterusers“ mit dem „Masterpasswort“ sichern?

            Alle Datenbanken haben einen eigenen User und ein eigenes Passwort. Zudem kann ich das Masterpasswort nutzen.

            Das wäre mir neu. Was hast Du da? STRATO (Ich vermute dort liegen Deine Datenbanken) sagt: “Das Masterpasswort kann nach der Vergabe eines separaten Datenbank-Passwortes nicht mehr für diese Datenbank verwendet werden.“

            Ansonsten kenne ich das nur so:

            Ein Benutzer, ein Passwort - also so, dass es eben kein „Master-Passwort“ gibt, mit welchem man sich $Admin als Benutzer $soundso anmelden kann.

            1. Ein Benutzer, ein Passwort - also so, dass es eben kein „Master-Passwort“ gibt, mit welchem man sich $Admin als Benutzer $soundso anmelden kann.

              Doch, genau so ists bei mir. Zusätzlich zu dem DBuser-Passwort natürlich.

              1. Ein Benutzer, ein Passwort - also so, dass es eben kein „Master-Passwort“ gibt, mit welchem man sich $Admin als Benutzer $soundso anmelden kann.

                Doch, genau so ists bei mir. Zusätzlich zu dem DBuser-Passwort natürlich.

                Oh, es ist bei mir nicht so, ich muss mich korrigieren. Mit dem Masterpasswort kann ich zwar meines Wissens mit dem php-myadmin auf die DBs zugreifen, aber der dump erfordert tatsächlich das originale Passwort.

                1. Mit dem Masterpasswort kann ich zwar meines Wissens mit dem php-myadmin auf die DBs zugreifen, aber der dump erfordert tatsächlich das originale Passwort.

                  Das „Masterpasswort“ wird dem php-myadmin in die Konfiguartion geschrieben und benutzt dann die ebenfalls in php-myadmin-Konfiguration gespeicherten User-Passwort-Paare.

  2. header("Location: http://mysite.bla/dump.php?listID=".$listID."");
    

    Das führt über den erneuten Aufruf zum sofortigen Neustart des Skriptes und damit zu weiteren Backup-Versuchen, wenn die Datenbanken sehr klein sind eventuell auch zum Überschreiben von Backups. Ich vermute, das willst Du auch nicht. Außerdem würde ich den Datumsteil mit date('Y-m-d_H:i:s') ermitteln. Das lässt sich später besser sortieren und z.B. downloaden und löschen.

    1. header("Location: http://mysite.bla/dump.php?listID=".$listID."");
      

      Das führt über den erneuten Aufruf zum sofortigen Neustart des Skriptes und damit zu weiteren Backup-Versuchen, wenn die Datenbanken sehr klein sind eventuell auch zum Überschreiben von Backups. Ich vermute, das willst Du auch nicht.

      Doch, das will ich.

      Ok, ich poste das Script nochmal mit ein paar kommentaren, ok?

      Jörg

      1. Doch, das will ich.

        Oh. Das solltest Du aber nicht wollen. Glaub mir: Das ist ein Error auf OSI-Layer 9.

        1. Doch, das will ich.

          Oh. Das solltest Du aber nicht wollen. Glaub mir: Das ist ein Error auf OSI-Layer 9.

          Ich verstehe nicht ganz, was Du meinst. Das Script soll sich doch neu aufrufen, um eine eventuell vorhandene begrenzte Scriptlaufzeit zu umgehen. Oder ist das ein Trugschluß und "header:location" umgeht die Scriptlaufzeit gar nicht?

          Ich habs jetzt jedenfalls ein paar mal durchlaufen lassen und es sichert alle Datenbanken sauber. Gesamtdauer ca. 4 Minuten.

          An dieser Stelle übrigens danke für die Tips! 👍

          Hier nochmal das Script, wie ichs nutzen möchte:

          $sql = "SHOW DATABASES";
          $dbhost = 'localhost';
          $dbuser = 'Masteruser';
          $dbpass = 'Masterpass';
          $path = '/bla/';
          
          $link = mysqli_connect($dbhost,$dbuser,$dbpass) or die ('Error connecting to mysql: '.mysqli_error($link).'\r\n');
          
          if(!($result = mysqli_query($link,$sql))) {
              printf("Error: %s\n",mysqli_error($link));
          }
          
          while($row = mysqli_fetch_row($result)) {
              if(($row[0] != "schema") && ($row[0] != "information_schema")) {
          		// Liste der Datenbanken füllen
                  $arr_list[] = $row[0];
              }
          }
          
          if(!isset($_GET['listID'])) {
              $listID = 0;
          } else {
              $listID = $_GET['listID'];
          }
          
          if($listID < count($arr_list)) {
          
              $dbname = $arr_list[$listID];
              $db_kennzeichen = $dbname.'_'.date("d-m-Y_G:i");
          
              system('/usr/bin/mysqldump -u'.$dbuser.' -p'.escapeshellarg($dbpass).' -h'.$dbhost.' '.$dbname.' | /bin/gzip >'.$path.'dump/'.$db_kennzeichen.'.sql.gz',$fp);
          
              if(($fp == 0) && (false !== chmod($path.'dump/'.$db_kennzeichen.'.sql.gz',0666))) {
                  // echo "Daten exportiert";
              } else {
                  echo "Es ist ein Fehler aufgetreten";
              }
          
              $listID++;
              header("Location: http://mysite.bla/script.php?listID=".$listID."");
          
          } else {
              echo "fertig";  
              exit;  
          }
          

          Jörg

          1. Oder ist das ein Trugschluß und "header:location" umgeht die Scriptlaufzeit gar nicht?

            Genau so: "header:location" umgeht die Scriptlaufzeit nicht.

            1. Oder ist das ein Trugschluß und "header:location" umgeht die Scriptlaufzeit gar nicht?

              Genau so: "header:location" umgeht die Scriptlaufzeit nicht.

              Das habe ich befürchtet. Hatte daher auch mal

              echo ("<meta http-equiv='refresh' content='1;URL=".$scriptname."?listID=$listID'>");

              ausprobiert, aber das macht wget nicht mit.

              Anruf beim Support bracjte die Erkentniss, dass (vermutlich) Scripte, die über cron angestoßen werden, dem script-time-limit nicht unterliegen, aber "sollte/könnte/würde" bringt auch nicht wirklich was. Wir leben nicht im Konjunktiv.

              SSH-Zugang habe ich ja, aber die entsprechenden Rechte zum dumpen der DB sind hier nicht frei gegeben.

              Gibts ne andere Möglichkeit, dass sich das Script selber aufruft?

              Gruß, Jörg

              1. Gibts ne andere Möglichkeit, dass sich das Script selber aufruft?

                Der ganze Plan ist falsch:

                1. Du bittest einen Webserver, ein PHP-Skript auszuführen, welches Shell-Befehle und also Linux-Programme startet.
                2. Der Webserver startet also PHP, PHP startet die Shell-Befehle und also die Linux-Programme.
                3. Um den Webserver zu schützen gibt es Grenzen für PHP (Laufzeit, Speicher, …). Werden diese Grenzen „gerissen“ wird die Abarbeitung des PHP-Skriptes beendet.
                4. Damit verlieren die SHell-Befehle und die Linux-Programme (hier mysql-dump) den Vaterprozess und werden also ebenfalls gekillt.

                Ein erneuter Skriptaufruf (via neuem Request des Browsers - den Du mit der header-Zeile auslöst) führt nur zu dem gleichen Problem.

                Lösungen habe ich Dir hier genannt.

                Diese kannst Du wie folgt verwenden:

                • Wenn ein isolierter Prozess mit batch, nohup, screen (oder was auch immer) gestartet wird, dann lässt sich das feststellen. Notfalls erzeuge ein Flagfile und lösche es nach Beendigung des Prozesses.
                • Dein Skript sollte also prüfen, ob der Prozess läuft (z.B. testen ob das Flagfile existiert) und wenn das der Fall ist, den Browser eine kleine Seite schicken, mit der Anweisung, diese nach einigen (3-60?) Sekunden neu zu laden.
                • Wenn nicht wird mysql-dump mit batch, nohup oder screen gestartet, alle Ausgaben kommen in Files, welche Du auswerten kannst.
              2. Hallo Jörg,

                Anruf beim Support bracjte die Erkentniss, dass (vermutlich) Scripte, die über cron angestoßen werden, dem script-time-limit nicht unterliegen, aber "sollte/könnte/würde" bringt auch nicht wirklich was. Wir leben nicht im Konjunktiv

                Es gibt zwei potenzielle Script-Execution Killer:

                1. PHP, mit max_execution_time in der php.ini. Diesen Wert kannst Du je nach PHP Einrichtung mit set_time_limit überschreiben. Die PHP Doku sagt: Wird PHP von der Kommandozeile gestartet, ist max_execution_time=0 (also unbegrenzt)

                guckst du

                1. Die Ausführungsumgebung. Für einen Webrequest ist das der Webserver (apache), für einen cron-Job ist es was anderes. Ein Timeout Wert im Apache gilt deshalb für einen cron Job nicht. Und wenn Du im cron Job PHP aus einem Script heraus startest, ist das ein Kommandozeilenaufruf, der max_execution_time aushebeln dürfte, so dass nur ein in cron gesetztes Ausführungslimit greifen sollte.

                Ein kompetenter Support sollte Dir das ohne Konjunktive und mit exakten Zahlen erklären können.

                Ansonsten hilft nur probieren, mach ein Script, das in einer Logdatei zu Beginn den Startzeitpunkt und die gefundenen DBs einträgt und nach jedem Dump den den gedumpten DB-Namen und den Fertigstellungszeitpunkt loggt. Dann siehst Du ja, wie lange er braucht und ob er abbricht.

                Dein Self-Restart ergibt dann und nur dann einen Sinn, wenn der Dump jeder einzelnen Datenbank innerhalb der Script-Ausführungszeit liegt, aber die Summe der Ausführungszeiten zu groß wird. Ein cron Job ist für Backups eh besser, würde ich sagen, weil der vom Server aus zeitgesteuert ist.

                Rolf

                --
                sumpsi - posui - obstruxi
                1. Hallo Rolf,

                  Anruf beim Support bracjte die Erkentniss, dass (vermutlich) Scripte, die über cron angestoßen werden, dem script-time-limit nicht unterliegen, aber "sollte/könnte/würde" bringt auch nicht wirklich was. Wir leben nicht im Konjunktiv

                  Es gibt zwei potenzielle Script-Execution Killer:

                  1. PHP, mit max_execution_time in der php.ini. Diesen Wert kannst Du je nach PHP Einrichtung mit set_time_limit überschreiben. Die PHP Doku sagt: Wird PHP von der Kommandozeile gestartet, ist max_execution_time=0 (also unbegrenzt)

                  guckst du

                  Also bringt meine .htaccess ggf. hier gar nichts, die auf die php.ini Einfluss ausüben soll. Alles klar, danke.

                  1. Die Ausführungsumgebung. Für einen Webrequest ist das der Webserver (apache), für einen cron-Job ist es was anderes. Ein Timeout Wert im Apache gilt deshalb für einen cron Job nicht. Und wenn Du im cron Job PHP aus einem Script heraus startest, ist das ein Kommandozeilenaufruf, der max_execution_time aushebeln dürfte, so dass nur ein in cron gesetztes Ausführungslimit greifen sollte.

                  Leider kann ich per cron nicht den php-interpreter direkt ansprechen, ich muss es über ein Batchscript und wget machen (laut Support).

                  Ein kompetenter Support sollte Dir das ohne Konjunktive und mit exakten Zahlen erklären können.

                  Bin nur bis zum first level-Support durchgedrungen. Reine Glücksache bei meinem Provider. 😕

                  Ansonsten hilft nur probieren, mach ein Script, das in einer Logdatei zu Beginn den Startzeitpunkt und die gefundenen DBs einträgt und nach jedem Dump den den gedumpten DB-Namen und den Fertigstellungszeitpunkt loggt. Dann siehst Du ja, wie lange er braucht und ob er abbricht.

                  Meine derzeitigen Datenbanken schafft der Cron, dauert ca. 4 Minuten. Da die DBs aber die Angewohnheit haben, mit der Zeit größer zu werden, werde ich mir mal ein paar Kopien der größten DBs anfertigen, sodass ich mal 10 Minuten ausprobieren kann. Dann weiß ich, ob es künftig Probleme geben könnte. Die Idee, das Ganze zu loggen (sagte Raketen* auch schon), habe ich auf dem Plan. Ich mache das dann über einen 2. Cron, der ca. 1 Std. später nachschaut, ob alle DBs gesichert wurden und mir eine Mail schreibt, falls nicht.

                  Dein Self-Restart ergibt dann und nur dann einen Sinn, wenn der Dump jeder einzelnen Datenbank innerhalb der Script-Ausführungszeit liegt, aber die Summe der Ausführungszeiten zu groß wird. Ein cron Job ist für Backups eh besser, würde ich sagen, weil der vom Server aus zeitgesteuert ist.

                  Das ist korrekt. Ich bin aber gar nicht sicher, ob das Script wirklich neu gestartet wird und die Scriptlaufzeit überhaupt von neuem beginnt. Raketen* sagte, das sei nicht der Fall. Und der Aufruf im Browser sieht auch nihct so aus, als würde das Script neu starten. Was mienst Du dazu?

                  Gruß, Jörg

                  1. Hallo Jörg,

                    wenn Du einen wget machst, rufst Du das PHP Script wieder über den Webserver auf. D.h. in die Situation, wo PHP von der Kommandozeile gerufen wird, kommst Du nicht.

                    Dein Self-Restart funktioniert schon, denke ich, vorausgesetzt, es gibt keine Fehlermeldung die an den Browser geht. Header kann man ja nur setzen solange es keinen regulären Output gab (bzw. man muss den regulären Output puffern).

                    Du schreibst den Header sobald ein Dump durch ist, der geht an den Browser und der Browser folgt dem Redirect. Es kann nur sein, dass der Browser das abbricht, denn die Anzahl der redirects, denen ein Browser folgt, ist limitiert (frag mich jetzt nicht, worauf, aber ich habe schon die Fehlermeldung Too Many Redirects gesehen).

                    Mein Loggingvorschlag sollte Dir sagen, welcher Dump wie lange dauert. Sobald Du das weißt, mach einmal mehrere Dumps in einem PHP Script, die das normale Ausführungslimit von 30s sicher reißen.

                    Und dann schau mal, ob set_time_limit einen Effekt hat.

                    Und du könntest deinen Provider fragen, ob es denn keinen regulären Weg zum DB Backup gibt, denn was Du da machst, erinnert schon an den Gynäkologen, der zum KFZ Mechaniker umschulte. Alle staunten, wie er eine Zylinderkopfdichtung wechselte…

                    Rolf

                    --
                    sumpsi - posui - obstruxi
                    1. Hi Rolf,

                      Mein Loggingvorschlag sollte Dir sagen, welcher Dump wie lange dauert. Sobald Du das weißt, mach einmal mehrere Dumps in einem PHP Script, die das normale Ausführungslimit von 30s sicher reißen.

                      Und dann schau mal, ob set_time_limit einen Effekt hat.

                      Würde ich jetzt machen. Ich überlege gerade, wie ich dem Script beibringen kann, "n" mal durchzulaufen, bevor es "fertig" ist. Dann könnte ich damit ein wenig "spielen".

                      Und du könntest deinen Provider fragen, ob es denn keinen regulären Weg zum DB Backup gibt, denn was Du da machst, erinnert schon an den Gynäkologen, der zum KFZ Mechaniker umschulte. Alle staunten, wie er eine Zylinderkopfdichtung wechselte…

                      Habe ich schon gemacht. Ich kann entweder über ein menü manuell sichern oder über den Weg des php-scriptes. Ich kann auch direkt aus der Konsole heraus dumpen, das Script von Rakenten* lief prima, aber ich erhalte keine Mail und trotz dump auch einen Fehler mysqldump: Error: 'Access denied; you need (at least one of) the PROCESS privilege(s) for this operation' when trying to dump tablespaces

                      Über das php-script läuft es einwandfrei und ähnlich schnell.

                      Jörg

                      1. Hallo Jörg,

                        Ich überlege gerade, wie ich dem Script beibringen kann, "n" mal durchzulaufen, bevor es "fertig" ist.

                        die for-Schleife ist dir aber geläufig, oder?

                        Ich kann entweder über ein menü manuell sichern oder über den Weg des php-scriptes. Ich kann auch direkt aus der Konsole heraus dumpen, das Script von Rakenten* lief prima, aber ich erhalte keine Mail und trotz dump auch einen Fehler `mysqldump: Error: 'Access denied; you need (at least one of) the PROCESS privilege(s) for this operation' when trying to dump tablespaces

                        Bei welchem Schritt?

                        <ins> Okay, die Frage war überflüssig, es gibt nur einen mysqldump-Aufruf im Script. Es hätte besser heißen müssen: Bei welcher Datenbank, falls es mehrere gibt? </ins>

                        Und bist du sicher, dass der Dump dann auch vollständig war? Vermutlich eher nicht.

                        Über das php-script läuft es einwandfrei und ähnlich schnell.

                        Also anscheinend doch eine seltsame Rechte-Konfiguration. Unter welchem Benutzer führst du denn die Batchdatei aus (whoami)? Und unter welchen Benutzer läuft PHP (whoami)?

                        Oder dein PHP-Script läuft auf denselben Fehler, aber du wertest ihn nicht aus.

                        Live long and pros healthy,
                         Martin

                        --
                        Klein φ macht auch Mist.
                    2. Hallo Rolf,

                      Mein Loggingvorschlag sollte Dir sagen, welcher Dump wie lange dauert. Sobald Du das weißt, mach einmal mehrere Dumps in einem PHP Script, die das normale Ausführungslimit von 30s sicher reißen.

                      Und dann schau mal, ob set_time_limit einen Effekt hat.

                      Hat definitiv einen Effekt.
                      Der Reload bringt übrigens nichts, das hätte ich auch in einer einzigen Schleife innerhalb des Scriptes machen können.

                      Ich habe jetzt mal 30 x dieselbe DB gesichert.
                      1 Sicherung dauert etwa 1 Minute.
                      Ich habe 15 von 30 Sicherungen geschafft und mein set_time_limit lag bei 900, das passt also, zeigt aber auch, dass das Script nicht wirklich reloaded.

                      Jetzt prüfe ich nochmal gegen, ob ein Heraufsetzen des set_time_limit entsprechend mehr als 15 Durchläufe schafft.

                      Jörg

                      1. Und dann schau mal, ob set_time_limit einen Effekt hat.

                        Hat definitiv einen Effekt.

                        Von wegen. Hat es doch nicht, ich muss mich korrigieren.
                        Egal, on es auf 70, 900, 5000 steht, das Script bricht immer nach 15-20 Minuten ab (nicht gemessen, sondern geschätzt). Wird also eine Obergrenze seitens des Providers sein.
                        Für mich soweit aber erstmal ok, weil ein normaler Durchölauf < 5 min ist und das auch absehbar so bleibt. Insofern hats genügend Reserve.

                        Jörg

                        1. (nicht gemessen, sondern geschätzt)

                          <?php
                          header( 'Content-Type:text/plain' );
                          header( 'Cache-Control: no-cache, no-store' );
                          $start = date( 'U' ); 
                          while ( true ) {
                          	echo date( 'U' ) - $start . " Sekunden." . PHP_EOL;
                          	flush();
                          	sleep( 1 );
                          }
                          

                          Einfach laufen lassen bis nichts mehr kommt und dann auf die letzte Zeile schauen.

                          1. Hallo Raketenskripter,

                            beachte, dass sleep nicht zur max_execution_time mitgerechnet wird.

                            Steht bei set_time_limit.

                            Hm. Da steht aber auch, das system calls ebenfalls nicht zählen. Das könnte die Zeit bis zum Abbruch des Scripts sehr günstig beeinflussen.

                            Rolf

                            --
                            sumpsi - posui - obstruxi
                            1. beachte, dass sleep nicht zur max_execution_time mitgerechnet wird.

                              Du hast Recht. Das Skriptlein taugt damit nicht für den Test des Limits.

                          2. (nicht gemessen, sondern geschätzt)

                            <?php
                            header( 'Content-Type:text/plain' );
                            header( 'Cache-Control: no-cache, no-store' );
                            $start = date( 'U' ); 
                            while ( true ) {
                            	echo date( 'U' ) - $start . " Sekunden." . PHP_EOL;
                            	flush();
                            	sleep( 1 );
                            }
                            

                            Einfach laufen lassen bis nichts mehr kommt und dann auf die letzte Zeile schauen.

                            Danke Dir für den Code.👍 Aber aktuell ist es egal, ob nach 15 oder 20 Minuten abgebrochen wird, weil ich weit drunter liege. Sollte das in ein paar jahren mal aktuell sein, ist immer noch Zeit genug. Möglicherweise gelten dann aber wieder andere Rahmenbedingungen.

                            Jörg

                            1. Einfach laufen lassen bis nichts mehr kommt und dann auf die letzte Zeile schauen.

                              Danke Dir für den Code.👍

                              Leider tut der Code nicht, was er sollte.

                              1. Einfach laufen lassen bis nichts mehr kommt und dann auf die letzte Zeile schauen.

                                Danke Dir für den Code.👍

                                Leider tut der Code nicht, was er sollte.

                                Habe ich schon mitbekommen.
                                Trotzdem danke für deine Mühe.

                                Jörg

                  2. Warum baust Du Dir nicht einfach ein Shell-Skript

                    #! /bin/bash
                    ### file /Path/To/backup.sh
                    
                    user="test"
                    passwort="#####";
                    
                    ### Für den output
                    directory="/tmp/"; 
                    
                    ### Datenbanken nicht dumpen (Trenner ist GENAU ein PIPE "|"):
                    nodump="information_schema|mysql|Database"; 
                    
                    
                    datetime=`date +%Y-%m-%d_%H:%M:%S`;
                    databases=`echo 'show schemas' | mysql --user="$user" --password="$passwort" | grep -vP $nodump`;
                    mysqldump --user="$user" --password="$passwort" -B $databases | gzip -c > "${directory}/${datetime}_sql.gz" 2> "${directory}/${datetime}.log" ;
                    
                    

                    und startest das einfach per cronjob?

                    Vergiss nicht, dass Output-Directory per htaccess zu schützen, falls es im Webspace liegen sollte (Was durchaus sehr gefährlich sein kann -> womöglich personenbezogene Daten, sogar Passwörter?)

                    1. Hallo Raketenskripter,

                      und da guck ich gestern noch das neueste Wintergatan Video, wo Martin ein Zitat von Elon Musk bringt: bevor Du anfängst, ein Teil zu optimieren, schau erstmal, ob Du es weglassen kannst.

                      Ja klar. PHP ganz weglassen wär die beste Idee. Sofern denn der Dump im Cron direkt aufrufbar ist, da scheinen merkwürdige Rechteverhältnisse zu herrschen.

                      Rolf

                      --
                      sumpsi - posui - obstruxi
                      1. Ja klar. PHP ganz weglassen wär die beste Idee. Sofern denn der Dump im Cron direkt aufrufbar ist,

                        HM. Eine letzte Zeile mit chmod und/oder chown auf die "${directory}/${datetime}_sql.gz" sollte da auch ohne PHP Möglichkeiten schaffen.

                        1. Hallo Raketenskripter,

                          was ich meinte, ist: Wenn man PHP nicht aufrufen darf (d.h. der cron-User kein X Recht auf das PHP Executable hat) - darf man dann /usr/bin/mysqldump aufrufen? Bisher scheint Jörg ja einen cron Job zu nutzen, der einen wget macht und damit via Apache ein PHP Script startet.

                          Ich weiß nicht viel von Linux, würde aber annehmen, dass /usr im Apache Kontext etwas anderes ist als für einen cron oder einen interaktiven User, so dass eine PHP Installation oder ein mysqldump gar nicht verfügbar ist. Und die Installation einer weiteren Software dürfte dann auch nicht unbedingt gelingen.

                          Rolf

                          --
                          sumpsi - posui - obstruxi
                          1. Ich weiß nicht viel von Linux, würde aber annehmen, dass /usr im Apache Kontext etwas anderes ist als für einen cron oder einen interaktiven User, so dass eine PHP Installation oder ein mysqldump gar nicht verfügbar ist.

                            "Gar nicht verfügbar" ist so eine Sache.

                            Also im Allgemeinen sollten die von cron gestarteten Prozesse unter der UID/GID es Users und damit mit dessen Rechten starten. Und im Allgmeinen kann jeder user mysqldump starten. Ferner gibt im Allgemeinen ein Support korrekte Auskünfte.

                            Aber wie das mit dem „Allgmeinen“ so ist...

                            • Es kann sein, dass cron die Prozesse unter einer Art Proxy-User ausführt. Also nicht unter dem Benutzerkennzeichen, welches man erwartet…
                            • Es kann sein, dass man vielen Benutzern das Ausführen von bestimmten Programmen z.B per acl entzogen hat.
                            • Es kann tatsächlich sein, dass der Webserver und der Server, auf dem cron ausgeführt werden zwei verschiedene sind (der als Webserver genutzte Server z.B. Verzeichnisse aus einem mount nutzt)
                            • Es kann sein, dass der Support angewiesen wurde, einfache Auskünfte wie „geht nicht“ zu geben um kompliziertere Anfragen zu vermeiden oder Kunden mit billigen Paketen dazu zu bewegen, ein teureres zu kaufen.
                            • … (else)

                            Es kann aber auch sein, dass man mit ein paar Linux-Kenntnissen den Hoster ein wenig austricksen kann, denn oft sind diese Beschneidungen („nun ja“) „nicht wirklich wirksam“, bestehen z.B. aus nicht gesetzten PATH-Variablen, fehlenden Links in /etc/alternatives oder dergleichen…

                            Manches weiß mancher über manchen Hoster, herausfinden lässt sich fast alles.

                            @Jörg:

                            <?php
                            echo $DEIN_HOSTER;
                            echo $DEIN_PAKET
                            
                    2. #! /bin/bash
                      ### file /Path/To/backup.sh
                      
                      user="USER";
                      passwort="PASSWORT";
                      mail='USER[@HOST]'; #Wer bekommt die Mails?
                      
                      ### Für den output
                      directory="/tmp/"; 
                      
                      ### Schemas("Datenbanken") nicht dumpen (Trenner ist GENAU ein PIPE "|", 'Database' muss stehen bleiben):
                      nodump="Database|information_schema|mysql"; 
                      
                      # showMessages=1 zeigt Nachrichten (bei cronjob vermeiden)
                      showMessages=1;
                      
                      # Pfade zu Programmen
                      
                      mysql_bin=`which mysql`;
                      mysqldump_bin=`which mysqldump`;
                      mail_bin=`which mail`;
                      
                      #mysql_bin="/usr/bin/mysql";
                      #mysqldump_bin="/usr/bin/mysqldump";
                      #mail_bin="/usr/bin/mail";
                      
                      ### Programm: ###
                      
                      err=0;
                      counter=0;
                      datetime=`date +%Y-%m-%d_%H:%M:%S`;
                      databases=`echo 'show schemas' | $mysql_bin --user="$user" --password="$passwort" | grep -vP $nodump`;
                      
                      for database in $databases; do
                      
                         outFile="${directory}/${datetime}_${database}.sql.gz";
                         logFile="${directory}/${datetime}.log";
                         
                         if [ 1 -eq $showMessages ]; then
                           echo -n "Dumpe Schema: '${database}'.";
                         fi
                         
                         $mysqldump_bin --user="$user" --password="$passwort" -B $databases | gzip -c > "${outFile}" 2>> "${logFile}" ;
                         
                         if [ 0 -eq $? ]; then
                           counter=$(($counter+1));
                           if [ 1 -eq $showMessages ]; then
                             echo "Shema '${database}' wurde gesichert." >> "${logFile}";
                      	   echo -e "\b -> fertig.";
                      	 fi
                         else
                      	 if [ 1 -eq $showMessages ]; then
                      	   echo -e "\b -> FEHLER!";
                      	 fi
                      	 err=1;
                         fi
                      done
                      if [ 1 -eq $err ]; then
                      	cat "${directory}/${datetime}.log" | $mail_bin -s "Fehler beim Backup" $mail;
                      fi
                      fileList=`ls -al ${datetime}*`;
                      echo -en "${counter} Schemas wurden gesichert.\nAngelegte Dateien:\n\n${fileList}" | $mail_bin -s "Erfolgtes Backup" $mail;
                      
                      1. Hallo Raketentroller,

                        bitte erkläre, warum die Bash-Transpilierung des PHP Scripts eines Minus würdig ist. Angesichts der bisher identifizierten Probleme mit dem PHP Umweg finde ich diese Lösung extrem hilfreich. Wenn es keine Tippfehler, oder weitere Folgeprobleme, gibt, hat diese Lösung meiner Meinung nach den "Lösung" Haken verdient.

                        Rolf

                        --
                        sumpsi - posui - obstruxi
                        1. #! /bin/bash
                          ### file /Path/To/backup.sh
                          ### code in utf-8
                          
                          host="localhost";
                          port="3306"
                          user="test";
                          passwort="HalloJosch";
                          
                          # siehe mysqldump --help
                          moreDumpOptions='--add-drop-database --add-drop-table --allow-keywords --extended-insert=TRUE'; 
                          
                          #Wer bekommt die Mails?
                          mailto='bürgerlicher Name <user@host>';
                          
                          ### Verzeichnis für den Output
                          directory="/tmp/"; 
                          
                          ### Schemas("Datenbanken") nicht dumpen (Trenner ist GENAU ein PIPE "|", 'Database' muss stehen bleiben):
                          nodump="information_schema|mysql|OSM"; 
                          
                          # showMessages=1 zeigt Nachrichten (bei cronjob vermeiden)
                          showMessages=1;
                          
                          # Pfade zu Programmen
                          
                          mysql_bin=`which mysql`;
                          mysqldump_bin=`which mysqldump`;
                          mail_bin=`which mail`;
                          
                          #mysql_bin="/usr/bin/mysql";
                          #mysqldump_bin="/usr/bin/mysqldump";
                          #mail_bin="/usr/bin/mail";
                          
                          # Es ist "ein wenig schwierig", automatisch zu ermitteln, ob für die Ermittlung der Datenbanken 'show schemas' oder 'show databases' benutzt werden muss:
                          #schemasName="databases";
                          schemasName="schemas";
                          
                          ### Programm: ###
                          
                          mailto=`echo "${mailto}" | iconv -f UTF-8 -t ASCII//TRANSLIT`;
                          
                          err=0;
                          counter=0;
                          datetime=`date +%Y-%m-%d_%H:%M:%S`;
                          databases=`echo "show ${schemasName};" | $mysql_bin --host="${host}" --port="${port}" --user="${user}" --password="${passwort}" --column-names=FALSE | grep -vP "${nodump}"`;
                          
                          for database in $databases; do
                          	outFile="${directory}/${datetime}_${database}.sql.gz";
                          	logFile="${directory}/${datetime}.log";
                             
                          	if [ 1 -eq $showMessages ]; then
                          		echo -n "Dumpe Schema: '${database}'.";
                          	fi
                          
                          	$mysqldump_bin --host="${host}" --port="${port}" --user="${user}" --password="${passwort}" $moreDumpOptions -B $databases | gzip -c > "${outFile}" 2>> "${logFile}" ;
                             
                          	if [ 0 -eq $? ]; then
                          		counter=$(($counter+1));
                          		if [ 1 -eq $showMessages ]; then
                          			echo "Schema \"${database}\" wurde gesichert." >> "${logFile}";
                          			echo -e "\b -> fertig.";
                          		fi
                          	else
                          		if [ 1 -eq $showMessages ]; then
                          			echo -e "\b -> FEHLER!";
                          		fi
                          		err=1;
                          	fi
                          done
                          
                          if [ 1 -eq $err ]; then
                          	cat "${directory}/${datetime}.log" | $mail_bin -s "Fehler beim Datenbank-Backup von ${host}:${port}" "${mailto}";
                          fi
                          
                          fileList=`ls -alh ${directory}/${datetime}*`;
                          echo -en "${counter} Schemas wurden gesichert.\nAngelegte Dateien:\n\n${fileList}" | $mail_bin --subject="Erfolgtes Datenbank-Backup von ${host}:${port}" "${mailto}";
                          
                          
                          

                          Einen echten Fehler habe ich gefunden: Beim Ermitteln der $fileList fehlte ${directory}.

                          Weitere Veränderungen betreffen die "Schönheit", z.B. die bequeme Angabe von Optionen.

                          1. Hi,

                            Es ist "ein wenig schwierig", automatisch zu ermitteln, ob für die Ermittlung der Datenbanken 'show schemas' oder 'show databases' benutzt werden muss:

                            #schemasName="databases"; schemasName="schemas";

                            Schließen die beiden sich eigentlich aus? Soll heißen, wenn das Script so läuft, würde die andere Option nicht laufen?

                            Gruß, Jörg

                            1. Hi,

                              # Es ist "ein wenig schwierig", automatisch zu ermitteln, ob für die Ermittlung der Datenbanken 'show schemas' oder 'show databases' benutzt werden muss:
                              #schemasName="databases";
                              schemasName="schemas";
                              

                              Schließen die beiden sich eigentlich aus? Soll heißen, wenn das Script so läuft, würde die andere Option nicht laufen?

                              Gruß, Jörg

                              Genau eine der beiden Angaben muss sein!

                              • (Sehr) Alte Versionen von MySQL/MariaDB kennen nur "databases" - Künftige Versionen von MySQL/MariaDB vorhersehbar nur "schemas".
                              • Mein aktuelles MariaDB kommt gegenwärtig)sic!) (Stichwort „Rückwärtskompatibilität“) mit genau einer der beiden obigen Angaben klar.
                      2. #! /bin/bash
                        ### file /Path/To/backup.sh
                        

                        ...schönes Script, vielen Dank auch dafür.

                        Ist noch ein kleiner Fehler drin, unten in ls hast du den Pfad vergessen. leider bekomme ich eine fehlermeldung, was das email versenden angeht:

                        mail: cannot send message: Process exited with a non-zero status

                        Zudem ist es nicht schneller als der Aufruf über "wget und phpscript".

                        Die Frage, ob ich eine Scriptlaufzeit einhalten muss, hat sich auch noch nicht geklärt. 😕

                        Und den php-interpreter direkt von der Kommandozeile aus anzusprechen ist mir nicht gelungen, obwohl ich alle Pfade dank deiner Hilfe und dem Codeschnipsel ermitteln konnte (danke auch dafür). Den perl-interpreter kann ich übrigens direkt von der Komandozeile aus ansprechen.

                        Insofern bin ich derzeit noch beim php-script geblieben, weil ich dort den Code wenigstens verstehe und ihn so erweitern kann.

                        Jörg

                        1. Zudem ist es nicht schneller als der Aufruf über "wget und phpscript".

                          Für Dich nicht messbar schneller…

                          Die Frage, ob ich eine Scriptlaufzeit einhalten muss, hat sich auch noch nicht geklärt.

                          Wenn Du ein PHP-Skript mit wget aufrufst, dann wird es via Webserver aufgerufen und nach einem konfigurierbaren und recht kurzem Zeitraum abgebrochen.

                          In der Standardkonfiguration für den Aufruf per shell/crontab (als „CLI“) ist diese Laufzeit regelmäßig unbegrenzt.

                          Insofern bin ich derzeit noch beim php-script geblieben, weil ich dort den Code wenigstens verstehe und ihn so erweitern kann.

                          Das ist jetzt so eine Sache. Wenn Du auf diesem Niveau Webseiten verwalten willst, dann solltest Du Dir baldmöglichst Kenntnisse über Linux und die Shell, also auch Shellbefehle (und ergo Shell-Skripte) verschaffen.

                          Hilfreich dabei sind: Virtuelle Maschinen, z.B. mit einem minimalen Debian ohne grafische Oberfläche und diverse Kurse zahlreicher Anbieter.

                          mail: cannot send message: Process exited with a non-zero status

                          Hm. Da müsste man von $HOSTER erfahren, WAS davon WIESO nicht gehen mag. Leider gibt es verschiedene Programme, die mit mail aufgerufen werden - und einen konfigurierten lokalen SMTP-Server erwarten.

                          Und den php-interpreter direkt von der Kommandozeile aus anzusprechen ist mir nicht gelungen,

                          Wie hast Du das GENAU getan, welches war der gemeldete Fehler?

                          1. Insofern bin ich derzeit noch beim php-script geblieben, weil ich dort den Code wenigstens verstehe und ihn so erweitern kann.

                            Mein php-script läuft manchmal sauber durch,. aber immer wieder bricht es auch ab.

                            Aber der Aufruf deines sh-scriptes bringt mir Folgendes:

                            Es werden alle dbs gebackuped, aber zb. die erste DB ist ungepackt 30mb und daraus wird ein 600mb großes Archiv gemacht.

                            Da alle Archive gleich groß werden, vermute ich mal, dass das Archiv die Größe aller DBs hat, aber nur 1 DB sich auch darin befindet. Jedes archiv dauert auch in der Herstellung entsprechend lang.

                            Und die andseren DBs natürlich entsprechend auch.

                            Hast du da ne Lösung für?

                            Jörg

                            1. Da alle Archive gleich groß werden, vermute ich mal, dass das Archiv die Grße aller DBs hat, aber nur 1 DB sich auch darin befindet.

                              Ah. Ich habe es.

                              Es gibt diese Zeile 56:

                              $mysqldump_bin --host="${host}" --port="${port}" --user="${user}" --password="${passwort}" $moreDumpOptions -B $databases | gzip -c > "${outFile}" 2>> "${logFile}" ;
                              

                              Darin ist das '$databases' durch '$database' (ohne das "s" am Ende) zu ersetzen:

                              $mysqldump_bin --host="${host}" --port="${port}" --user="${user}" --password="${passwort}" $moreDumpOptions -B $database | gzip -c > "${outFile}" 2>> "${logFile}" ;
                              

                              EDIT: Ich habe das mal tatsächlich getan. [Der Martin]

                              1. Es wurden einfach jede Datenbank in jede Datei gesichert. Das erklärt auch, warum die alle gleich groß sind.

                              2. Hallo,

                                Darin ist das '$databases' durch '$database' (ohne das "s" am Ende) zu ersetzen:

                                $mysqldump_bin --host="${host}" --port="${port}" --user="${user}" --password="${passwort}" $moreDumpOptions -B $database | gzip -c > "${outFile}" 2>> "${logFile}" ;
                                

                                Ich hatte es schon fast vermutet, habe mich aber nicht getraut 😉 Danke, ich probiers mal aus.

                                Jörg

                          2. Also...das Script läuft prinzipiell gut durch. 👍 Nur:

                            Bei jeder DB erhalte ich folgende Meldung:

                            mysqldump: Error: 'Access denied; you need (at least one of) the PROCESS privilege(s) for this operation' when trying to dump tablespaces -> fertig.

                            Und ganz zum Schluss dann noch:

                            mail: cannot send message: Process exited with a non-zero status

                            Allerdings werden die DBs sauber gebackupped. Warum erhalte ich also eine (bzw. viele) Fehlermeldung?

                            Jörg

                            1. Also...das Script läuft prinzipiell gut durch. 👍 Nur:

                              Bei jeder DB erhalte ich folgende Meldung:

                              mysqldump: Error: 'Access denied; you need (at least one of) the PROCESS privilege(s) for this operation' when trying to dump tablespaces -> fertig.

                              Das ist merkwürdig. Fehlermeldung, aber korrektes Ergebnis? Ich kann das Skript anpassen, damit die individuellen Namen und Passwörter der Datenbankbenutzer übergeben werden statt des, ich nenne ihn mal

                              Dann finde ich:

                              mysqldump requires … and (as of MySQL 8.0.21) PROCESS if the --no-tablespaces option is not used. Certain options might require other privileges as noted in the option descriptions.

                              Wenn Du die „tablespaces“ nicht verwendest (was ich vermute), dann kannst Du aber auch ganz einfach in Zeile 11:

                              moreDumpOptions='--add-drop-database --add-drop-table --allow-keywords --extended-insert=TRUE --no-tablespaces'; 
                              

                              notieren.

                              Und ganz zum Schluss dann noch:

                              mail: cannot send message: Process exited with a non-zero status

                              Ja. Wir wissen ja schon, dass $DeinProvider es nicht geschafft hat, den Mailversand (exim4, postfix, #whatElse) fürs Terminal zu konfigurieren. Die Zeile solltest Du abschalten.

                              1. Ich kann das Skript anpassen, damit die individuellen Namen und Passwörter der Datenbankbenutzer übergeben werden statt des, ich nenne ihn mal

                                „Hauptbenutzer“.

                              2. Hi,

                                moreDumpOptions='--add-drop-database --add-drop-table --allow-keywords --extended-insert=TRUE --no-tablespaces'; 
                                

                                notieren.

                                Ja, die Option --no-tablespaces hat Abhilfe geschaffen.

                                Jetzt bekomme ich nur noch das warning: [Warning] Using a password on the command line interface can be insecure.

                                Und die Mailfehlermeldung heißt nun: mail: No recipients specified

                                Ich habe aber noch ne Frage:

                                Kann man das CREATE DATABASE Statement mit irgendeiner Option aus dem Dump heraus nehmen? Weil ich sonst im Importfall dieses statement manuell entfernen müsste. Das gibt bei meinem Provider nämlich ne Fehlermeldung, weil ich Datenbanken nur über sein Konfigurationsmenü anlegen darf.

                                Und weißt Du, was noch cool wäre? Ich hatte mir im php-script (was ja leider nicht gut genug läuft) eigefügt, dass für jeden Tag ein neues Verzeichnis angelegt wird und alle dumps ujnd logfiles dann taggenau dort einsortiert werden.

                                Danke für die Hilfe. Jedenfalls läuft Dein Script bisher bei jedem Durchlauf sauber durch! 👍

                                Jörg

                                Und ganz zum Schluss dann noch:

                                mail: cannot send message: Process exited with a non-zero status

                                Ja. Wir wissen ja schon, dass $DeinProvider es nicht geschafft hat, den Mailversand (exim4, postfix, #whatElse) fürs Terminal zu konfigurieren. Die Zeile solltest Du abschalten.

                                1. Und die Mailfehlermeldung heißt nun: mail: No recipients specified

                                  Da Mail nicht funktioniert ist es am einfachsten, den Abschnitt

                                  fileList=`ls -alh ${directory}/${datetime}*`;
                                  echo -en "${counter} Schemas wurden gesichert.\nAngelegte Dateien:\n\n${fileList}" | $mail_bin --subject="Erfolgtes Datenbank-Backup von ${host}:${port}" "${mailto}";
                                  
                                  

                                  mithin die letzten beiden Zeilen zu löschen.

                                  Ich habe aber noch ne Frage:

                                  Kann man das CREATE DATABASE Statement mit irgendeiner Option aus dem Dump heraus nehmen?

                                  Handbuch.

                                  Da steht:

                                  --no-create-db
                                      
                                     Do not write CREATE DATABASE statements
                                  ~~~
                                  
                                  Füge das also zu den Optionen hinzu und prüfe im Handbuch, was Du noch brauchen kannst.
                                  
                                  1. Kann man das CREATE DATABASE Statement mit irgendeiner Option aus dem Dump heraus nehmen?

                                    Diese Option musst Du außerdem entfernen:

                                    --add-drop-database
                                    
                                    1. Kann man das CREATE DATABASE Statement mit irgendeiner Option aus dem Dump heraus nehmen?

                                      Diese Option musst Du außerdem entfernen:

                                      --add-drop-database
                                      

                                      Sicher? Ich dachte, die könne drin bleiben, weil effektlos?

                                      Because the output contains no CREATE DATABASE statement, the --add-drop-database option has no effect. If you use it, it produces no DROP DATABASE statement.

                                      Jörg

                                      1. Sicher? Ich dachte, die könne drin bleiben, weil effektlos?

                                        Because the output contains no CREATE DATABASE statement, the --add-drop-database option has no effect. If you use it, it produces no DROP DATABASE statement.

                                        Na gut. Du musst sie nicht entfernen, Du sollst die Angabe entfernen.

                                        Grund: --add-drop-database und --no-create-db gemeinsam zu verwenden kann - insbesondere bei langen Zeilen Dich oder einen anderen verwirren.

                                2. Und weißt Du, was noch cool wäre? Ich hatte mir im php-script (was ja leider nicht gut genug läuft) eigefügt, dass für jeden Tag ein neues Verzeichnis angelegt wird und alle dumps ujnd logfiles dann taggenau dort einsortiert werden.

                                  Habs so gelöst:

                                  err=0;
                                  counter=0;
                                  heute=`date +%Y-%m-%d`;
                                  mkdir -p ${directory}/${heute};
                                  datetime=`date +%Y-%m-%d_%H:%M:%S`;
                                  databases=`echo "show ${schemasName};" | $mysql_bin --host="${host}" --port="${port}" --user="${user}" --password="${passwort}" --column-names=FALSE | grep -vP "${nodump}"`;
                                  
                                  for database in $databases; do
                                  	outFile="${directory}/${heute}/${datetime}_${database}.sql.gz";
                                  	logFile="${directory}/${heute}/${datetime}.log";
                                  ...
                                  
                                  1. Habs so gelöst:

                                    😀👍

                                    Ich sehe, das sachte Hindrücken Richtung „Lernen von Shellscripting“ funktioniert.

                                    Du hast gut untersucht was ich da mache und dann selbst gebaut. Gratuliere zum Erfolg!

                                    1. Habs so gelöst:

                                      😀👍

                                      Ich sehe, das sachte Hindrücken Richtung „Lernen von Shellscripting“ funktioniert.

                                      Du hast gut untersucht was ich da mache und dann selbst gebaut. Gratuliere zum Erfolg!

                                      Danke 😇

                                      1. ... übrigens ein mega interessantes Thema 😀

                                        Habe mir da heute noch ein paar Tutorials zu angesehen. Sehr interessant. Wußte gar nicht, dass man da sogar mit Arrays arbeiten kann.

                                        Unglaublich, wie mächtig diese Scripte sind. Mir selber fehlen leider wichtige Unix/Linux-Kenntnisse, aber trotzdem möchte ioch mich da ein wenig hinein arbeiten.

                                        Übrigens, die Supportanfrage bzgl. der nicht funktionierenden Mail ist auch an den Support raus, weil das brauch ich ja "alle Nase lang". Wenns hierzu bei meinem Provider irgendwas Besonderes braucht, sollen sie es mir halt sagen. Aber selbst auf der Konsole sollte doch ein echo "test" | mail -s "test" me@myhost.end funktionieren, oder?

                                        Jörg

                                        1. Aber selbst auf der Konsole sollte doch ein echo "test" | mail -s "test" me@myhost.end funktionieren, oder?

                                          Ja. Genau. Du bis ein angemeldeter Benutzer und da ist es unverständlich, dass die Mail nicht rausgehen können soll.

                                          1. Aber selbst auf der Konsole sollte doch ein echo "test" | mail -s "test" me@myhost.end funktionieren, oder?

                                            Ja. Genau. Du bis ein angemeldeter Benutzer und da ist es unverständlich, dass die Mail nicht rausgehen können soll.

                                            So schauts aus. Stattdessen erhalte ich:

                                            mail: cannot send message: Process exited with a non-zero status

                                            😬

                                            1. echo -e "Subject: test\n\ntest" | sendmail -f ABSENDERADDR EMPFÄNGERADDR

                                              funktioniert😀

                                              1. echo -e "Subject: test\n\ntest" | sendmail -f ABSENDERADDR EMPFÄNGERADDR

                                                funktioniert😀

                                                Ja. In einem Shell-Skript ist es allerdings kaum beherrschbar und definitiv nicht ökonomisch, alle Konfigurations- und Softwareauswahl-Optionen abzufragen und darauf zu reagieren.

                                                Man nutzt die Skripte ja weil diese einfach zu ändern sind.

                                                1. Ja. In einem Shell-Skript ist es allerdings kaum beherrschbar und definitiv nicht ökonomisch, alle Konfigurations- und Softwareauswahl-Optionen abzufragen und darauf zu reagieren.

                                                  Man nutzt die Skripte ja weil diese einfach zu ändern sind.

                                                  Stimmt schon. Aber für mich war ja alternativ nur möglich, die Mailoption komplett wegzulassen, insofern ist es (für mich) eine Verbesserung.

                                                  Das der Server hier ggf. nicht korrekt eingestellt ist, ist davon unberührt.

                                                  Danke jedenfalls für Deine Hilfe, das Script läuft jetzt seit ein paar tagen wunderschön durch und backupt alle DBs. Mein ursprüngliches php-Script zum selben Zweck läuft theoretisch auch, aber praktisch eben nicht zuverlässig, weil es immer wieder mal mit der Meldung "Mysqlserver has gone" abbricht.

                                                  1. weil es immer wieder mal mit der Meldung "Mysqlserver has gone" abbricht.

                                                    ... Was eine „nur sehr bedingt gelungene Optimierung des Servers“ (genau genommen kann man die Variablen auch für Clients setzen) vermuten lässt.

                                                    ABER:

                                                    Hast Du möglicherweise übersehen, dass Dein Hoster Dir bereits täglich einen Dump zur Verfügung stellt?

                                                    Meiner macht das. Jeden Morgen gegen 5 Uhr.

                                                    1. Hast Du möglicherweise übersehen, dass Dein Hoster Dir bereits täglich einen Dump zur Verfügung stellt?

                                                      Meiner macht das. Jeden Morgen gegen 5 Uhr.

                                                      Meiner macht das auch, aber nur für den Webspace kostenfrei wieder einspielbar. Das Einspielen von dumps ist kostenpflichtig und man ist darauf angewiesen, wann der Hoster zeitnah die zeit hierfür findet. Musste ich zuletzt mal in Anspruch nehmen. Hat dann 2-3 Std. gedauert, aber hat prima geklappt. Kosten waren auch sehr überschaubar. Aber ich habe schon gerne zusätzlich meine eigenen Sicherungen, daher bin ich ganz happy mit dem Script. Früher habe ich das mit dem (von mir gepimpten) perlscript des mysqldumpers gemacht, aber da muss ich zusätzlich angelegte DBs immer in dessen config einfügen, daher wollte ich das ändern. Dein Script macht das sehr schön und ich bin zufrieden damit.👍

                  3. Leider kann ich per cron nicht den php-interpreter direkt ansprechen, ich muss es über ein Batchscript und wget machen (laut Support).

                    Soso.

                    <?php
                    header('Content-Type: text/plain');
                    
                    echo "which php:\n";
                    echo `which php`;
                    echo "\n/etc/alternatives/php:\n";
                    echo `ls -l /etc/alternatives/php`;
                    echo "\nls -l /usr/bin/php*\n";
                    echo `ls -l /usr/bin/php*`;
                    echo "\nfind / -executable -name \"php\":\n";
                    echo `find / -executable -name "php"  2> /dev/null`;
                    

                    Gut, dass man ein paar Sachen auch selbst herausfinden kann.

                    1. Leider kann ich per cron nicht den php-interpreter direkt ansprechen, ich muss es über ein Batchscript und wget machen (laut Support).

                      Soso.

                      <?php
                      header('Content-Type: text/plain');
                      
                      echo "which php:\n";
                      echo `which php`;
                      echo "\n/etc/alternatives/php:\n";
                      echo `ls -l /etc/alternatives/php`;
                      echo "\nls -l /usr/bin/php*\n";
                      echo `ls -l /usr/bin/php*`;
                      echo "\nfind / -executable -name \"php\":\n";
                      echo `find / -executable -name "php"  2> /dev/null`;
                      

                      Gut, dass man ein paar Sachen auch selbst herausfinden kann.

                      cool 👍 Haben alle funktioniert 😀

  3. // Konfiguration Masterzugang
    $sql = "SHOW DATABASES";
    $dbhost = 'localhost';
    $dbuser = 'user';
    $dbpass = 'pass';
    $path = '/bla/bla/';
    
    $link = mysqli_connect($dbhost,$dbuser,$dbpass) or die ('Error connecting to mysql: '.mysqli_error($link).'\r\n');
    
    if(!($result = mysqli_query($link,$sql))) {
        printf("Error: %s\n",mysqli_error($link));
    }
    
    while($row = mysqli_fetch_row($result)) {
        if(($row[0] != "mysql") || ($row[0] == "information_schema")) {
            // DB-User sind immer die ersten 10 zeichen des DB-Namens
            $arr_list[] = $row[0]."_".substr($row[0],0,10);
        }
    }
    
    // Nun sind die DB-Namen und die entsprechenden Usernamen im Array $arr_list.
    // Dieses Array will ich anschließend gem. numerischem Index durchlaufen, wobei sich das Script immer wieder selber aufrufen soll, damit die Scriptlaufzeit eingehalten wird.
    
    if(!isset($_GET['listID'])) {
        $listID = 0;
    } else {
        $listID = $_GET['listID'];
    }
    
    while($listID < count($arr_list)) {
        $myEintrag = $arr_list[$listID];
        $arr_myEintrag = explode('_',$myEintrag);
    
        // DB und User des Arrayeintrages mit dem Index $listID ermitteln
        $dbname = $arr_myEintrag[0];
        $dbuser = $arr_myEintrag[1];
        $db_kennzeichen = $dbuser.'_'.date("Y-m-d_H:i:s");
    
      //Dump erstellen
        system('/usr/bin/mysqldump -u'.$dbuser.' -p'.escapeshellarg($dbpass).' -h'.$dbhost.' '.$dbname.' | /bin/gzip >'.$path.'dump/'.$db_kennzeichen.'.sql.gz',$fp);
    
        if(($fp == 0) && (false !== chmod($path.'dump/'.$db_kennzeichen.'.sql.gz',0666))) {
            //echo "Daten exportiert";
        } else {
            echo "Es ist ein Fehler aufgetreten".$fp;
        }
    
       // Script aufrufen mit neuer ListID
        $listID++;
        header("Location: http://mysite.bla/dump.php?listID=".$listID."");
    }
    echo "fertig";
    exit;
    
    1. if(($row[0] != "mysql") || ($row[0] == "information_schema")) {
      

      Oops...

      if(($row[0] != "mysql") && ($row[0] == "information_schema")) {

      1. Hi,

        if(($row[0] != "mysql") || ($row[0] == "information_schema")) {
        

        Oops...

        if(($row[0] != "mysql") && ($row[0] == "information_schema")) {

        Sicher?

        Denn das läßt sich zu if ($row[0] == "information_schema")vereinfachen (wenn der rechte Teil des && erfüllt ist, row[0] also "information_schema" ist, ist der linke automatisch erfüllt, weil "information_schema" != "mysql" ist.

        cu,
        Andreas a/k/a MudGuard

        1. Hi,

          if(($row[0] != "mysql") || ($row[0] == "information_schema")) {
          

          Oops...

          if(($row[0] != "mysql") && ($row[0] == "information_schema")) {

          Sicher?

          Ach ja...war ein langer Tag heute 😉

          if(($row[0] != "mysql") && ($row[0] != "information_schema")) {

    2. Tach!

      if(!($result = mysqli_query($link,$sql))) {
          printf("Error: %s\n",mysqli_error($link));
      }
      

      Wenn an dieser Stelle ein Fehler auftritt, ist es nicht sinnvoll, nach dem Ausgeben der Meldung fortzufahren.

      dedlfix.

      1. Tach!

        if(!($result = mysqli_query($link,$sql))) {
            printf("Error: %s\n",mysqli_error($link));
        }
        

        Wenn an dieser Stelle ein Fehler auftritt, ist es nicht sinnvoll, nach dem Ausgeben der Meldung fortzufahren.

        dedlfix.

        Ok. Das lässt sich ja durch ein exit; beheben, danke.