MarkusH.: Problem mit .bat Datei die über php ausgeführt wird

Hallo,

ich habe versucht eine .bat datei mit php auszuführen... das geht auch eigentlich doch ich bekomme einen Fehler das findstr im .bat script eine datei nicht öffnen kann. Brauch der Browser irgendwelche berechtigungen?

PHP script:

$datei = fopen("C:\Users\markus\Desktop\server\adminnames.txt","w");
fwrite($datei, "test hamacher");
fclose($datei);
exec('start C:\Users\markus\Desktop\server\server.bat');

.bat script:

@echo on
set LineNo=0
goto :Zeile

:Zähler
if "%counter%" == "%szeilen%" (
goto :End
) else (
goto :Main
)

:Main
set "line="
set "name="
for /f "delims=" %%a in ('more/e +%LineNo% ^< adminnames.txt') do (
  if not defined line set "line="%%a""
  if not defined name set "name=%%a"
)
mkdir %line%
echo "Ordner: " %name% " erstellt"
copy "C:\Users\markus\Desktop\server\vorlage" "C:\Users\markus\Desktop\server\%name%"
set /a LineNo+=1
set /a szeilen+=1
goto :Zähler

:Zeile
set /a "counter=0"
FOR /F "delims=:" %%A IN ('findstr /N .* "adminnames.txt"') DO set /a "counter=%%A"
set /a szeilen=0
goto :Zähler

:End
echo "Es wurden " %counter% " ordner erstellt!"
echo "names.txt wird gelöscht..."
del "C:\Users\markus\Desktop\server\adminnames.txt"
echo "Fertig"
pause
ping 127.0.0.1 -n 2 >nul
exit

Ich freue mich über jede Hilfe 😀

MarkusH.

akzeptierte Antworten

  1. Tach!

    ich habe versucht eine .bat datei mit php auszuführen... das geht auch eigentlich doch ich bekomme einen Fehler das findstr im .bat script eine datei nicht öffnen kann. Brauch der Browser irgendwelche berechtigungen?

    Nein. Der Browser sendet nur einen Request an den Server. Der Server führt das PHP-Script aus oder er delegiert es an einen Prozess, in dem das PHP läuft. Wer am Ende das PHP-Script ausführt, braucht erst die entsprechenden Berechtigungen im Dateisystem.

    dedlfix.

    1. Also wenn der Server das ausführt dann ist das ja eig. das System und der hat ja eig. immer alle Permissions also ist es doch was anderes aber was? 😕

      1. Also wenn der Server das ausführt dann ist das ja eig. das System und der hat ja eig. immer alle Permissions

        So ist das mit dem Wissen und dem, dieses vortäuschenden Denglisch.

        Der Apache-WebServer wird zwar auch unter Windows mit den Rechten eines Administrators gestartet (sonst könnte er nicht an einem Port <= 1024 lauschen und das folgende auch nicht), aber dieser Prozess macht nichts anderes als Arbeitsprozesse zu starten (und diese zu verwalten), die dann die Anfragen beantworten.

        Und diese Prozesse (also auch das PHP-Skript, welches Deine bat-Datei startet) laufen unter einem anderen, nicht privilegiertem Benutzer. z.B. "www-data" oder "www-run".

        Unter welchem genau steht in der Konfigurationsdatei des Apache-Servers, die Du wenigstens mal durchlesen solltest. Da stehen nämlich auch interessante Kommentare - unter anderem zu diesem Thema. Alles was da nicht steht, steht im Handbuch.

        also ist es doch was anderes aber was?

        Falls Du zufällig die Rechte vergeben hast, dann steht die andere Ursache im Error-Log. Wo Du das findest steht in der Serverkonfiguration. Wo die wiederum sein soll steht im Handbuch bzw. der Installationsanleitung der freundlichen, aber von Dir nicht erwähnten Organisation, welche Dir den Apache für Windows kompiliert und in ein Programmpaket gepackt hat.

        1. Also, ich habe nochmal nachgesehen. Einer aktuellen, nicht vom Hersteller kommentierten Meldung (Januar 2018) im Forum der Hersteller des XAMPP-Paketes zufolge laufen auch die Kindprozesse deren Apache-Version (angeblich) unter dem Systemkonto. Ergo auch PHP. Ergo wird auch versucht, Deine Batchdatei mit dem Systemkonto zu starten.

          Aus diesem Grund dürften die Macher des XAMPP gut beraten sein, PHP das (also das Ausführen eines Skriptes außerhalb des Dokument-Root des Webservers) zu verbieten

          exec('start C:\Users\markus\Desktop\server\server.bat');
          

          ... sollte verboten sein, wenn C:\Users\markus\Desktop\server nicht das Document-Root ist.

          Lese also bitte bei PHP zu exec und safe_mode nach und überprüfe die Konfiguration.

          Ich weiß aber nicht, ob das stimmt und auch nicht, ob Du überhaupt den XAMPP hast - oder welche andere Binärversion - andere Distributionen können das (aus gutem Grund) anders machen. Du hast nicht geschrieben, welche Version Du hast - deshalb schaue ich nicht bei den anderen für Dich nach.

          Was also bleibt, ist

          1. im Error-Log nachzusehen;
          2. robuster zu programmieren (Dein Batch-Skript behauptet zwar, Dateien und Ordner angelegt zu haben, hat das aber nur versucht) und macht im Fehlerfall gar nichts. Es überprüft nicht mal die Existenz von Dateien.
          3. Dir sehr genau zu überlegen, wieso eigentlich ein Batch-Skript eine Aufgabe erledigen soll, die PHP auch erledigen kann.
          4. Dir sehr genau zu überlegen, ob es sinnvoll ist, durch den Aufruf einer Webseite Dateien wie "C:\Users\markus\Desktop\server\adminnames.txt" zu lesen, zu ändern, anzulegen oder zu löschen.

          Hinzu kommt:

          Deine Batch-Datei ist ein "Hupfding". Da wird munter und recht sinnfrei mit GOTO gesprungen. Ein Abschnitt wie MAIN ist, wenn überhaupt verwendet, z.B. stets der Teil, der das gesamte Skript und den Aufruf von anderen Subs steuert.

          1. Tach!

            Lese also bitte bei PHP zu exec und safe_mode nach und überprüfe die Konfiguration.

            Der Safe Mode ist seit längerer Zeit Geschichte (seit PHP 5.4). Beschränkungen kann man aber mit open_basedir konfigurieren. Das betrifft jedoch genau wie beim Safe Mode lediglich das, was PHP direkt kontrollieren kann, was in dem Fall also "start" wäre. Tieferen Einfluss auf das System und fremde Prozesse kann PHP nicht ausüben, es baut keine Sandbox für die exec−Funktion.

            Was also bleibt, ist

            1. im Error-Log nachzusehen;

            Auch im Event Viewer von Windows.

            dedlfix.

            1. Tieferen Einfluss auf das System und fremde Prozesse kann PHP nicht ausüben, es baut keine Sandbox für die exec−Funktion.

              Stimmt. Aber da eine Datei außerhalb des Document-Root geöffnet und ausgeführt werden soll gehe ich mal davon aus, dass die Paketbauer das dem PHP alternativ mit open_basedir verboten haben.

              Dann wäre noch einige Kandidaten:

              • disable_functions und, trotz Deines Hinweises über in PHP 5.4 entfernte Funktionen, auch:
              • safe_mode (und vor allem auch safe_mode_exec_dir ) - Denn wir wissen nichts über die verwendete PHP-Version.
              1. Tach!

                Tieferen Einfluss auf das System und fremde Prozesse kann PHP nicht ausüben, es baut keine Sandbox für die exec−Funktion.

                Stimmt. Aber da eine Datei außerhalb des Document-Root geöffnet und ausgeführt werden soll gehe ich mal davon aus, dass die Paketbauer das dem PHP alternativ mit open_basedir verboten haben.

                Das was ausgeführt werden soll ist "start" und das ist keine Datei, sondern ein eingebauter Befehl in der Shell. Die eigentliche Batchdatei ist nur ein Parameter davon. Wenn also grundlegend solche Kommandos ausgeführt werden können, ist PHP und seine Restriktionen schon raus aus der Sache.

                dedlfix.

                1. Das was ausgeführt werden soll ist "start" und das ist keine Datei, sondern ein eingebauter Befehl in der Shell

                  Stimmt. Hab es überlesen. Jetzt überlegen wir mal, woran DAS scheitern könnte … und warum keine Ausgaben sichtbar werden können - "wenn es denn tun würde".

                  Tip:

                  Start a program, command or batch script (opens in a new window.)

      2. Hallo MarkusH.,

        hast Du das Batchfile selbst geschrieben oder ist das Programming by StackOverflow? Es enthält einige Merkwürdigkeiten, die den Verdacht nahelegen, dass Du nicht verstanden hast was Du tust.

        Erste Frage ist: Du sagst, dass findstr eine Datei nicht findet. Im Gegensatz zu einigen anderen Kommentaren gehe ich davon aus, dass findstr selbst sehr wohl gefunden wird, das BAT aber das falsche Arbeitsverzeichnis hat. CMD-Prozesse aus Diensten werden gerne mit dem Windows-Ordner als aktuellem Verzeichnis gestartet, nicht dem Ordner, in dem das Batchfile liegt. Bekommst Du die Echos aus dem Batch zu sehen? Setz mal einen Befehl CD an den Anfang. Oder wenn Du die Echos nicht zu sehen bekommst:

        CD >C:\Users\markus\Desktop\server\script.log.

        Du wirst sicherlich zu Beginn in deinen Arbeits-Ordner wechseln müssen. Das kann man mit einer absoluten Verzeichnisangabe tun. Bei Dir ist es aber so, dass das Script selbst im Arbeitsordner liegt. Es wäre daher schick, wenn das Script einfach in "seinen" Ordner wechselt. Das geht, siehe unten.

        Zweite Frage wäre: Warum liegt das Ganze in deinem Userprofil? Ein Server sollte in eigenen Bereichen hantieren; ich persönlich würde einen ganz eigenen Root-Ordner dafür anlegen. Wenn der Apache unter einem eigenen Account läuft, kannst Du diesen Ordner für diesen Account berechtigen und musst dem Apache nicht das Recht geben, dein Userprofil potenziell zu schreddern.

        Dritte Frage ist: Woher hast Du diese seltsame set Syntax? Ich habe noch nie gesehen, dass alles hinter SET in Anführungszeichen gesetzt wird. Sowas bräuchtest Du - hab's grad mal probiert - dann, wenn Du Umgebungsvariablennamen verwenden willst, die Leerstellen enthalten. Das tust Du aber nicht. Du kannst die Anführungszeichen weglassen. Bei ECHO übrigens auch. ECHO würde die einfach mit ausgeben.

        Vierte Frage ist: Was soll da eigentlich passieren? Du schreibst test hamacher in die Textdatei, die vom Batch durchgelesen wird. Soll ein Ordner namens "test hamacher" entstehen? Es ist dann aber eigentlich nicht so gut, die Anführungszeichen, die der MD dafür braucht, in einer Variablen einzubauen. Das ginge einfacher mit

        MD "%name%"

        Fünfte Frage: Warum zählst Du erst und holst dann mühsam mit More Zeile für Zeile heraus, wobei Du dann noch dafür sorgen musst, nur die erste Ergebniszeile des More zu verarbeiten? Du hast Doch gar keine Notwendigkeit, die Anzahl der Zeilen vorher zu wissen. Das Ganze geht viel einfacher, wenn Du mit FOR /F einfach Zeile für Zeile verarbeitest.

        Sechste Frage: Kennst Du XCOPY? Der kopiert und legt mit Option /i auch gleich den Zielordner an.

        Also:

        • Arbeitsordner aktivieren (CD)
        • Variablen initialisieren
        • FOR /F Schleife über alle Zeilen laufen lassen
        • Je Durchlauf die Vorlage auf das Zielverzeichnis kopieren - XCOPY macht alles allein. ECHO und Zähler sind für den Spaß noch dabei.
        • Abschlussmeldung und fertig.
        cd /D %~dp0
        set /a counter=0
        
        for /f "delims=" %%a in (adminnames.txt) do (
          xcopy vorlage "%%a" /s /e /i
          echo Ordner: %%a erstellt
          set /a counter=counter+1
        )
        
        echo Es wurden %counter% Ordner erstellt!
        echo adminnames.txt wird gelöscht...
        del adminnames.txt
        echo Fertig
        

        Fertig. Das ist eigentlich das ganze Batchfile. Und ja, direkt aus PHP heraus geht das sicherlich auch.

        Der %~dp0 Klops verwendet gleich zwei Batchtricks. Trick 1: Der Parameter %0 enthält immer den Namen des laufenden Batchfiles. Trick 2: Mit %~ kann man Namensteile von Dateien aus Parametern holen. Das wird in der Hilfe von for für FOR-Variablen erklärt, funktioniert aber auch mit Batch-Parametern. Gib mal auf einer Kommandozeile help for ein, die Erklärung ist ziemlich am Schluss. %~dp0 bedeutet: Ich möchte von dem Dateinamen in %0 bitte Laufwerk und Pfad haben. Wenn %0 also C:\Users\markus\Desktop\server\server.bat enthält, ist das Ergebnis von %~dp0 C:\Users\markus\Desktop\server\. Immer mit abschließendem Backslash!

        Rolf

        --
        sumpsi - posui - clusi
        1. Hi there,

          Sechste Frage: Kennst Du XCOPY? Der kopiert und legt mit Option /i auch gleich den Zielordner an.

          Beinahe. /T wäre in dem Fall die gewünschte Option...😉

          1. Hallo klawischnigg,

            du bist im Irrtum. xcopy /? sagt:

            /T        Erstellt die Verzeichnisstruktur, kopiert aber keine Dateien.

            Rolf

            --
            sumpsi - posui - clusi
            1. Hallo klawischnigg,

              du bist im Irrtum. xcopy /? sagt:

              /T        Erstellt die Verzeichnisstruktur, kopiert aber keine Dateien.

              Ja, klar, /T alleine nicht, sondern /T /E /S, sorry, das hab ich vorausgesetzt…

              1. Hallo klawischnigg,

                Nein. Du hast nicht genau gelesen. /T VERHINDERT das Kopieren von Dateien, es überträgt nur die Verzeichnisstruktur.

                /S sorgt dafür, dass alle Unterverzeichnisse mitgenommen werden - was hier vermutlich nicht nötig ist sonst hätte der OP sein Batch anders geschrieben, und /E kopiert leere Unterverzeichnisse mit. /S ist in /T bereits implizit enthalten, /E nicht, steht so in der Hilfe ausdrücklich drin.

                Und wenn das Ziel nicht existiert, fragt /T ohne /I erstmal nach, ob das Ziel eine Datei oder ein Verzeichnis sein soll - was Unfug ist weil /T ja keine Dateien kopiert. XCOPY /T /-I tut einfach gar nichts außer ein paar CPU-Takte knabbern.

                Microsoft Dokumentation - hat zwar Windows Server als Überschrift, gilt aber genauso für Client.

                Rolf

                --
                sumpsi - posui - clusi
                1. Hi there,

                  Nein. Du hast nicht genau gelesen. /T VERHINDERT das Kopieren von Dateien, es überträgt nur die Verzeichnisstruktur.

                  ich hab gar nicht gelesen, ich hatte das so in Erinnerung. Aber jetzt wo Du es so sagst, glaub ich's Dir, vielleicht ist ja das auch der Grund, warum ich mich über den xcopy-Befehl immer so geärgert habe...;) (Ein Schelm der Böses denkt und ein weiterer Beweis dafür, daß man schlechte oder falsche Angewohnheiten nicht wegbekommt) Dabei war xcopy (afaik mit DOS 3.3 eingeführt) ein echter Fortschritt gegenüber dem internen copy-Befehl. Wenn man ihn halt richtig angewendet hat...😉

        2. Hallo,

          super danke funktioniert alles und ich glaube ich habe jetzt auch meine Fehler verstanden

          MarkusH.

          1. super danke funktioniert alles und ich glaube ich habe jetzt auch meine Fehler verstanden

            Also wenn nur zufällig auf das start verzichtet hast, dann eher nicht.

            Im Übrigen würde ich, wenn es darum geht, einen Apache Testserver zu haben, diesen zusammen mit einem Linux als virtuelle Maschine aufsetzen und, falls die Bearbeitung der Dateien direkt von Windows aus erwünscht ist, entweder auf dem Linux auch noch den Samba-Server aufsetzen (und /var/www im "Windows-Netzwerk" freigeben) oder die Möglichkeit des Virtualisierungsmanagers nutzen, dem virtuellen Host ein "gemeinsames Verzeichnis" als Platte vorzugaukeln. Das müsste freilich z.B. nach /var/www gemounted werden.

            Grund: Ein Teil des Apache-, Mysql-/MariaDB-, Perl-, PHP-Stacks unter Windows funktioniert

            • so ziemlich genau wie unter Linux
            • "anders" als unter Linux - oder eben
            • gar nicht.
  2. Hallo,

    ich habe versucht eine .bat datei mit php auszuführen... das geht auch eigentlich doch ich bekomme einen Fehler das findstr im .bat script eine datei nicht öffnen kann.

    Das Übliche: Der Pfad zu findstr wird nicht gefunden. Bedenke daß derjenige der die Batch ausführt eine ganz andere Umgebung hat als Du auf der Kommandozeile.

    Lösung: Für alle Commandos innerhalb der Batch die vollständige Pfadangabe notieren.

    MfG

  3. Hallo @MarkusH.,

    ich bekomme einen Fehler das findstr im .bat script eine datei nicht öffnen kann.

    PHP script:

    $datei = fopen("C:\Users\markus\Desktop\server\adminnames.txt","w");
    fwrite($datei, "test hamacher");
    fclose($datei);
    exec('start C:\Users\markus\Desktop\server\server.bat');
    

    In welchem Verzeichnis wird denn die Batch-Datei ausgeführt? Wenn ich das richtig verstehe, geht die Batch-Datei ganz am Anfang schon auf die Bretter:

    .bat script:

    @echo on
    set LineNo=0
    goto :Zeile
    
    REM oved …
    
    :Zeile
    set /a "counter=0"
    FOR /F "delims=:" %%A IN ('findstr /N .* "adminnames.txt"') DO set /a "counter=%%A"
    set /a szeilen=0
    goto :Zähler
    

    Das findstr ist vielleicht in einem anderen Verzeichnis als die Textdatei.

    Viele Grüße
    Robert

    1. hi,

      Das findstr ist vielleicht in einem anderen Verzeichnis als die Textdatei.

      findstr.exe ist in einem Verzeichnis auf welches die Path Variable zeigt. Nur hat derjenige der die Batch ausführt keine Solche.

      MfG

      1. Hallo pl,

        ich präzisiere: Vielleicht ist das working directory von findstr nicht das Verzeichnis, in dem sich die Textdatei befindet.

        Viele Grüße
        Robert

        1. hi,

          ich präzisiere: Vielleicht ist das working directory von findstr nicht das Verzeichnis, in dem sich die Textdatei befindet.

          findstr.exe gehört zu den Kommandozeilenprogrammen die normalerweise in \windows\system32 abgelegt sind. Es ist nicht Sinn und Zweck von Kommandozeilenprogrammen, diese jedesmal in eine working directory zu kopieren. Vielmehr gibt es dafür eine Umgebungsvariable PATH die es ermöglicht, ein Kommandozeilenprogramm in dem Verzeichnis aufzurufen, in dem es gerade gebraucht wird.

          Die zu bearbeitende Textdatei in ein Systemverzeichnis zu kopieren ist natürlich genauso unsinnig. Auf Linux würde man mit which findstr schauen wohin die Path~Variable zeigt für dieses Programm. Auf einen Win32/OS gibt es andere Tools zum Suchen von Dateien.

          In einer Batch~Datei sollte man Kommandozeilenprogramme stets mit der vollständigen PFadangabe notieren. Das gilt übrigens auch für die crontab~Datei unter Linux & CO.

          MfG

          1. Hallo pl,

            ich präzisiere: Vielleicht ist das working directory von findstr nicht das Verzeichnis, in dem sich die Textdatei befindet.

            findstr.exe gehört zu den Kommandozeilenprogrammen die normalerweise in \windows\system32 abgelegt sind. Es ist nicht Sinn und Zweck von Kommandozeilenprogrammen, diese jedesmal in eine working directory zu kopieren. Vielmehr gibt es dafür eine Umgebungsvariable PATH die es ermöglicht, ein Kommandozeilenprogramm in dem Verzeichnis aufzurufen, in dem es gerade gebraucht wird.

            Und genau dieses Verzeichnis, in dem es gerade gebraucht wird, heißt working directory. Das Programm kann dieses mit Hilfe seiner Standardbibliothek ermitteln, z.B. pwd in der Unix-Shell, getcwd in C, mittels der Umgebungsvariablen %CD% unter Windows, mit dem Perl-Modul Cwd, …

            In einer Batch~Datei sollte man Kommandozeilenprogramme stets mit der vollständigen PFadangabe notieren. Das gilt übrigens auch für die crontab~Datei unter Linux & CO.

            Ja, weil man sich nicht auf den $PATH verlassen kann.

            Viele Grüße
            Robert

            1. Tach!

              Das Programm kann dieses [working directory] mit Hilfe seiner Standardbibliothek ermitteln, z.B. pwd in der Unix-Shell, getcwd in C, mittels der Umgebungsvariablen %CD% unter Windows, mit dem Perl-Modul Cwd, …

              Muss es eigentlich nicht, denn wenn man die Dateinamen ohne Pfad angibt, dann greift die Betriebssystemfunktion zu Öffnen der Datei bereits von selbst ins Working Directory, also in das aktuelle Verzeichnis.

              In einer Batch~Datei sollte man Kommandozeilenprogramme stets mit der vollständigen PFadangabe notieren. Das gilt übrigens auch für die crontab~Datei unter Linux & CO.

              Ja, weil man sich nicht auf den $PATH verlassen kann.

              Unter Windows ist das erfahrungsgemäß weniger kritisch als unter Unix. Bei Unix wird oftmals der Pfad drastisch beschnitten, beziehungswiese gleich gar nicht so umfangreich aufgebaut wie in der Shell des Anwenders. Bei Windows hingegen weiß man üblicherweise nicht mal, wo sich die Programmdatei befindet, wenn es um einen System-Befehl gehört. Die üblichen verdächtigen Windowsverzeichnisse sollten also gesetzt sein.

              Für den vorliegenden Fall wäre sonst auch die Meldung, dass findstr nicht gefunden werden konnte, wenn der PATH ein Problem darstellen sollte.

              dedlfix.

          2. Hallo pl,

            die Windows-Systemprogramme sind normalerweise immer im PATH zu finden. Da müsste schon jemand gezielt was kaputtkonfiguriert haben, und dann würde noch viel mehr nicht laufen. Es ist also eher unnötig, findstr mit vollständiger Pfadangabe aufzurufen. Und wenn man es täte, dann läuft man Gefahr es falsch zu machen:

            C:\windows\system32\findstr.exe bla bla bla
            

            Korrekt ist es so: (system32 ist nicht per Umgebungsvariable definiert, es sei denn man verwendet die Pfad-Angabe von %ComSpec%, aber wer garantiert mir, dass der User das standardmäßige CMD.EXE verwendet)

            "%windir%\system32\findstr.exe" bla bla bla
            

            Zumindest in älteren Windosen konnte der User sagen, dass Windows in "D:\foo bar" installiert werden soll. Deswegen auch noch die Anführungszeichen. Das schmeißt zwar mindestens 90% aller Software aus der Kurve, aber SAGEN konnte man es. Ob es in neueren Windosen noch konfigurierbar ist, weiß ich nicht.

            Das Thema Arbeitsverzeichnis hatte ich ja schon im anderen Beitrag angesprochen, das wird die Problemursache sein.

            Man sollte übrigens im Normalbetrieb davon absehen, das BAT mit START zu starten und darin ein PAUSE zu haben, dann läuft es als eigener Prozess los und macht ein Konsolenfenster auf. Auf einem Server ist das tödlich. Zum lokalen Fehlersuchen ist es natürlich ok.

            Rolf

            --
            sumpsi - posui - clusi
            1. hi,

              die Windows-Systemprogramme sind normalerweise immer im PATH zu finden. Da müsste schon jemand gezielt was kaputtkonfiguriert haben, und dann würde noch viel mehr nicht laufen. Es ist also eher unnötig, findstr mit vollständiger Pfadangabe aufzurufen.

              Doch, genau das sollte man in einer Batchdatei tun!

              "%windir%\system32\findstr.exe" bla bla bla
              

              %windir% zu verwenden ist genauso unzuverlässig wie %path% zu verwenden. Und dann wäre noch etwas: call kommando sichert die Rückkehr in die Batchdatei nachdem kommando ausgeführt wurde!

              MfG