[PHP] Uitvoeren van .bat file met directe output in browser

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Clock
  • Registratie: Maart 2005
  • Laatst online: 20-09 16:46
Goedenavond,

Ik heb een webserver draaien op een fileservertje hier, en die is alleen bereikbaar vanuit het LAN. Het hoofddoel van deze webserver is het serveeren van een startpagina en onderhoudspagina aan de computers in het netwerk.

Ik heb een batch file geschreven die bepaalde partities backupt naar andere locaties(het uitvoeren hiervan kan lang duren). De bedoeling is dat deze door de user geactiveerd wordt, en dus wil ik deze batch file aanroepen via PHP.

Dat aanroepen 'mag' van mij op 2 manieren:
  1. Door op een linkje te klikken wordt een pagina geopend, waarna middels PHP de batch file gestart wordt, en de user weer terug wordt gestuurd naar de originele pagina. Zo 'runt' de batch file op de achtergrond, net als dat het gestart wordt door 'geplande taken'.
  2. Door op een linkje te klikken wordt een pagina geopend, waarna middels PHP de batch file gestart wordt, en de output van de batch file (geupdate files, etc) direct in de browser wordt getoont. (Heeft als nadeel dat je zit met de max_execution_time, maar dat zal niet vaak voorkomen)
De voorkeur gaat uit naar de 2e optie.

Het aanroepen van de batch file is geen probleem, dat doe ik middels de volgende code:
code:
1
2
3
4
<?php
header('Content-Type: text/plain');
exec("backup.bat");
?>


Het probleem is dat op deze manier gewacht wordt tot de batch file helemaal uitgevoert wordt, en dat de output dan pas naar de browser gestuurd wordt. Ik dacht dat te veranderen door passthru() te gebruiken, maar ook hier wordt eerst gewacht tot de batch file compleet is doorlopen alvorens de output naar de browser te sturen.

Op wat voor manier kan ik een van beide gewenste opties realiseren? Met exec() en passthru() functies zit ik wél met de max_execution_time, maar zie nog steeds geen realtime output.

Alvast bedankt!

Acties:
  • 0 Henk 'm!

  • eamelink
  • Registratie: Juni 2001
  • Niet online

eamelink

Droptikkels

Je kunt popen() gebruiken om een file pointer te openen, daarvan kan je zonder veel te bufferen steeds een beetje data naar de gebruiker flush()'en.

Verder kan je de max execution time gewoon ophogen natuurlijk :)

Acties:
  • 0 Henk 'm!

  • Freeaqingme
  • Registratie: April 2006
  • Laatst online: 22:03
Je zou ook kunnen forken of threaden, als je wlilt dat de boel tegelijkertijd wordt uitgevoerd.

No trees were harmed in creating this message. However, a large number of electrons were terribly inconvenienced.


Acties:
  • 0 Henk 'm!

  • Clock
  • Registratie: Maart 2005
  • Laatst online: 20-09 16:46
eamelink schreef op vrijdag 08 februari 2008 @ 00:08:
Je kunt popen() gebruiken om een file pointer te openen, daarvan kan je zonder veel te bufferen steeds een beetje data naar de gebruiker flush()'en.

Verder kan je de max execution time gewoon ophogen natuurlijk :)
Ok, dit is even een stapje moeilijker. Moet ik me eerst even in verdiepen :)

De max execution time heb ik natuurlijk ook al opgehoogt, maar mocht er een keer op een dag iets heel geks gebeuren (alle fotocamera's legen, een bunch muziek cd's digitaliseren, wat lichte videobewerken, allemaal tegelijk), dan moet het updatescript best wat gb's overhevelen. Het is niet heel erg wenselijk om hiervoor afhankelijk te zijn van de max execution time.

Acties:
  • 0 Henk 'm!

Verwijderd

Execute de bat file en laat die alle output in een log file zetten, deze file kun je dan inlezen onder het uitvoeren doormiddel van een refreshende pagina of ajax.

Acties:
  • 0 Henk 'm!

  • Clock
  • Registratie: Maart 2005
  • Laatst online: 20-09 16:46
Verwijderd schreef op vrijdag 08 februari 2008 @ 00:33:
Execute de bat file en laat die alle output in een log file zetten, deze file kun je dan inlezen onder het uitvoeren doormiddel van een refreshende pagina of ajax.
Dat was mijn eerste idee, en heb ik ook al uitgevoerd. Heb het zelfs al door de bat file in de database laten zetten. Dan moet ik echter wel een manier hebben om de batch file aan te roepen zonder dat PHP wacht op een antwoord/output. Dus optie 1: aanroepen en direct verdergaan.

Ik heb nu de volgende code:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
ob_start();
$i=0;
$handle = popen('backup.bat', 'r');

while (!feof ($handle)) {
    echo $i;    
    echo fgets($handle);
    ob_flush();
    $i++;
}

pclose($handle);
ob_end_flush();
?>


Ik krijg netjes voor elke lijn output een cijfertje, maar hij flusht het niet na elke lijn naar de browser. Iemand enig idee wat ik fout doe? Ik ben hier helaas niet zo heel erg in thuis.

Acties:
  • 0 Henk 'm!

Verwijderd

Als je wel de output krijgt maar niet na elke lijn zeg maar dan ligt het niet aan je script maar mogelijk aan de buffering van je webserver.

Acties:
  • 0 Henk 'm!

  • SchizoDuckie
  • Registratie: April 2001
  • Laatst online: 18-02 23:12

SchizoDuckie

Kwaak

pleur eens 200 spaties achter je echo($i)

:P

Stop uploading passwords to Github!


Acties:
  • 0 Henk 'm!

  • Perceptive
  • Registratie: December 2002
  • Laatst online: 14-07-2024
Misschien nog even een breakje na elke regel?

code:
1
echo fgets($handle).'<br/>';

Acties:
  • 0 Henk 'm!

  • FragFrog
  • Registratie: September 2001
  • Laatst online: 22:47
Clock schreef op vrijdag 08 februari 2008 @ 00:41:
Dan moet ik echter wel een manier hebben om de batch file aan te roepen zonder dat PHP wacht op een antwoord/output. Dus optie 1: aanroepen en direct verdergaan.
En wat nu als je de output piped naar een file en de inhoud van die file in een zichzelf refreshen iFrame weergeeft? Output pipen is simpel genoeg ( `commando | file.log`) en zorgt er bovendien voor dat PHP direct verder gaat :)

[ Site ] [ twitch ] [ jijbuis ]


Acties:
  • 0 Henk 'm!

  • Clock
  • Registratie: Maart 2005
  • Laatst online: 20-09 16:46
Verwijderd schreef op vrijdag 08 februari 2008 @ 08:05:
Als je wel de output krijgt maar niet na elke lijn zeg maar dan ligt het niet aan je script maar mogelijk aan de buffering van je webserver.
Het is gewoon Apache 2.nogwat zonder bijzondere edits. Of is het nodig buffering te enablen in de webserver?
Perceptive schreef op vrijdag 08 februari 2008 @ 08:58:
Misschien nog even een breakje na elke regel?

code:
1
echo fgets($handle).'<br/>';
Helaas, ik krijg gewoon de output van de bach file, maar dan met een mooi oplopend nummertje ervoor. En deze output krijg ik dus pas allemaal ineens, als de batch file helemaal uitgevoerd is.
SchizoDuckie schreef op vrijdag 08 februari 2008 @ 08:46:
pleur eens 200 spaties achter je echo($i)

:P
Haalt niks uit? O-)
FragFrog schreef op vrijdag 08 februari 2008 @ 11:17:
[...]


En wat nu als je de output piped naar een file en de inhoud van die file in een zichzelf refreshen iFrame weergeeft? Output pipen is simpel genoeg ( `commando | file.log`) en zorgt er bovendien voor dat PHP direct verder gaat :)
Ga ik nog even naar kijken :)

Acties:
  • 0 Henk 'm!

  • Sh4wn
  • Registratie: December 2006
  • Laatst online: 12-11-2017

Sh4wn

Bio-informatica

http://www.php.net/ob_implicit_flush

Zet die functie is boven aan je script. :)

Acties:
  • 0 Henk 'm!

  • Clock
  • Registratie: Maart 2005
  • Laatst online: 20-09 16:46
Argh, ik kom er niet uit |:(

Waarom heeft PHP niet gewoon de mogelijkheid een programma aan te roepen zonder dat die moet blijven babysitten tot het programma volledig is uitgevoerd? Zo moeilijk hoeft dat toch niet te zijn?

En het outputten van de buffer is blijkbaar ook te lasig...

Acties:
  • 0 Henk 'm!

  • Clock
  • Registratie: Maart 2005
  • Laatst online: 20-09 16:46
Was ik idd vergeten (A)
Maar met onderstaande code wordt nog steeds gewacht tot het script klaar is:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
ob_implicit_flush();
ob_start();
$i=0;
$handle = popen('backup.bat', 'r');

while (!feof ($handle)) {
    echo $i;    
    echo fgets($handle)."<br>";
    ob_flush();
    $i++;
}

pclose($handle);
ob_end_flush();
?>


Dit resulteert in de volgende output (allemaal ineens op het eind dus)

code:
1
2
3
4
5
6
7
8
9
10
11
0##############################
1Automatisch backup bijwerken
2##############################
3
4Bezig met vergelijken en bijwerken van backup
5Update compleet
6
7Changelog in database opslaan
8
9SQL bestand verwijderen
10

Acties:
  • 0 Henk 'm!

  • FragFrog
  • Registratie: September 2001
  • Laatst online: 22:47
Clock schreef op vrijdag 08 februari 2008 @ 12:54:
Waarom heeft PHP niet gewoon de mogelijkheid een programma aan te roepen zonder dat die moet blijven babysitten tot het programma volledig is uitgevoerd? Zo moeilijk hoeft dat toch niet te zijn?
Note: If you start a program using this function and want to leave it running in the background, you have to make sure that the output of that program is redirected to a file or some other output stream or else PHP will hang until the execution of the program ends.
manual

[ Site ] [ twitch ] [ jijbuis ]


Acties:
  • 0 Henk 'm!

Verwijderd

Hier een stukje uit een php code die ik geschreven heb om een programma te starten en te wachten tot deze klaar is (incl timeout).
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function execute_epw202($file)
{
    if($pp=proc_open("\"Calculate.exe\" '".$file."' '".$file.".csv'",array(),&$pipes))
    {
        $t=time();
        $status=proc_get_status($pp);
        while($status["running"])
        {
            if($t<(time()-60))
            {
                trigger_error("EPW timed out",E_USER_ERROR);
                proc_terminate($pp);
                @unlink("EpwLock.lck");
                return false;
            }
            usleep(300000);
            $status=proc_get_status($pp);
        }
        proc_close($pp);
        return true;
    }
    return false;
}


proc_open start het programma en gaat vervolgens verder met php zonder te wachten totdat de gestarte prog klaar is. Je kan de status opvragen via proc_get_status, maar verwacht niet teveel van deze gegevens.
Ah well, je begrijpt het idee wel.

edit: zie zowaar een fout in de gebruikte code :(

[ Voor 3% gewijzigd door Verwijderd op 08-02-2008 13:44 ]


Acties:
  • 0 Henk 'm!

  • KabouterSuper
  • Registratie: September 2005
  • Niet online
En als je de oplossing nou eens zoekt in de batch file. Als de batch file nou een wrapper is voor je echte batchfile die je aanroept via het START commando. De batch file zal doorgaan en eindigen, terwijl je echte batchfile doorgaat.

When life gives you lemons, start a battery factory


Acties:
  • 0 Henk 'm!

  • FragFrog
  • Registratie: September 2001
  • Laatst online: 22:47
KabouterSuper schreef op vrijdag 08 februari 2008 @ 13:48:
En als je de oplossing nou eens zoekt in de batch file. Als de batch file nou een wrapper is voor je echte batchfile die je aanroept via het START commando. De batch file zal doorgaan en eindigen, terwijl je echte batchfile doorgaat.
Dan krijgt hij nog steeds geen status updates ;)

[ Site ] [ twitch ] [ jijbuis ]


Acties:
  • 0 Henk 'm!

  • WouZz
  • Registratie: Mei 2000
  • Niet online

WouZz

Elvis is alive!

Dit resulteert in de volgende output (allemaal ineens op het eind dus)
doe eens een flush na je ob_flush()

On track


Acties:
  • 0 Henk 'm!

  • pasz
  • Registratie: Februari 2000
  • Laatst online: 01-09 23:08
Ik wil niet vervelend klinken, maar wat voor gedrag verwacht je als twee gebruikers tegelijk deze PHP pagina aanroepen ?

woei!


Acties:
  • 0 Henk 'm!

  • mac-er
  • Registratie: November 2006
  • Laatst online: 01-09 12:55
Allereerst, ik weet dat dit een late reactie is aangezien het een gedateerd topic is.

Ik was zelf naar wat informatie aan het zoeken over dit onderwerp. Maar misschien is dit heel makkelijk te realiseren, laat gewoon na iedere uitgevoerde opdracht een regel wegschrijven naar een txt bestand. Dit txt bestand laad je dan weer aanroepen binnen een Iframe in je php pagina dat met een bepaalde interval ververst.

To Apple or not to Apple? That's the banana!


Acties:
  • 0 Henk 'm!

  • Clock
  • Registratie: Maart 2005
  • Laatst online: 20-09 16:46
Ik weet dat de post een tikje oud is, maar heb het nu pas helemaal kunnen afronden. Het is me gelukt met de tips die jullie gegeven hebben. Ik heb ervoor gekozen om de output niet realtime naar de browser te versturen, omdat de kans op een time-out (server of client side) te groot was, en het niet bijzonder veel toegevoegde waarde had. In plaats daarvan sla ik de data via de commandline op in een MySQL database, die het script gewoon weer uitleest.

Paar screens van het resultaat:
Screen 1
Screen 2
Screen 3
Screen 4

Het is zoals jullie vast konden opmaken een soort interne startpagina. Hierin heb ik 4 tabs gemaakt. Op de eerste tab is te zien welke pc's/printers ingeschakeld zijn en hoe ze verbonden zijn met het netwerk (met draad of wireless). Ook is de netwerkprinter in/uit te schakelen mbv een computergestuurd relais. Op het tweede tab is te zien hoe het staat met het hardeschijfgebruik en de temperaturen van de fileserver. De derde tab is voor de backups. De interne backup houdt in dat de kritieke schijf gemirror't wordt met de backupschijf. De externe backup houdt in dat de kritieke schijf gemirror't wordt met een externe HDD die zich normaal buiten het huis bevind. Op de vierde tab is het mogelijk in te loggen op het webbased-email systeem.
Pagina: 1