spuštění batch souboru pomocí exec()
- Fajmy
- Člen | 10
Ahoj,
mám funkci, která využívá exec(), nicméně jsem zjistil, že mi to v Nette nejede. Zkoušel jsem v čistém PHP a funkce funguje jak má. Chci se tedy zeptat, jestli dělám něco špatně, nebo se spuštění externího programu v consoli řeší jinak.
Mám složku lflc, ve které jsou všechny potřebné soubory k dávkovému souboru lflc-run.bat, tuto složku mám ve www a následně exec volám takto:
exec("lflc/lflc-run.bat");
- Fajmy
- Člen | 10
Mám samostatnou třídu, ve které je jedna funkce a v té volám funkci
exec()
. Přikládám celou funkci:
class Lflc
{
public function lflc($v1, $v2, $v3){
$vystup = 0;
$inputFile = "lflc/data.txt";
$fh = fopen($inputFile, 'w') or die("nelze otevrit vstupni soubor");
$hlavicka_promenne = 'V1'."\t".'V2'."\t".'V3'."\r\n";
//Zapsani dat do vstupniho souboru
fwrite($fh, $hlavicka_promenne);
$v1_text = $v1."\t";
$v2_text = $v2."\t";
$v3_text = $v3."\t";
fwrite($fh, $v1_text);
fwrite($fh, $v2_text);
fwrite($fh, $v3_text);
fclose($fh);
//Spusteni LFLC
exec("lflc/lflc-run.bat");
$outputFile = "lflc/output.txt";
$fh = fopen($outputFile, 'r');
$output = fread($fh, filesize($outputFile));
fclose($fh);
//Nacteni vystupu
$values = explode("\t",$output);
dump($values);
$vystup_array = explode("\n",$values[6]);
$vystup_val = $vystup_array[0];
//LFLC dava cislo ve forme O,5 musim upravit na 0.5
$vystup_val = str_replace(",",".",$vystup_val);
dump($vystup_val);
return $vystup_val;
}
}
To volám v Manageru na testovací data:
$this->lflc->lflc('0', '0', '0');
$this->lflc->lflc('4', '0,7', '1,1');
Krok načtení, otevření a zápis dat do inputFile proběhne. Řádek
s funkcí exec()
jak kdyby se přeskočil. A načte se outputFile
a vypíše mi z něho data – nicméně se nikdy nezmění, jsou tam pořád
data, které jsem zkoušel v PHP.
Ano, soubor bat se nespouští.
- uestla
- Backer | 799
Do input souboru se ti to zapíše v pořádku jelikož ta relativní cesta
k input souboru se vyhodnotí jinak než relativní cesta k tomu baťáku,
který voláš z execu – v exec()
se tuším vyhodnocuje proti
aktuálnímu „pracovnímu adresáři“ (current working directory), což
pokud to voláš zevnitř Nette, by měl být adresář, ve kterém máš
index.php
.
Proto je lepší přístup mít místo relativní cesty absolutní – máš jistotu, že spouštíš správný skript a usnadní ti to případný budoucí přesun třídy / souboru, ze kterého daný skript voláš:
# common.neon
services:
- Lflc(%appDir%/../cesta-k-lflc-slozce)
class Lflc
{
private string $binDir;
public function __construct(string $binDir)
{
$this->binDir = $binDir;
}
public function lflc($v1, $v2, $v3): void
{
// ...
exec(escapeshellcmd(sprintf('%s/lflc-run.bat', $this->binDir)), $output, $status);
dump($output, $status);
// ...
}
}
- Fajmy
- Člen | 10
Pořád se mi to nějak nedaří. Tu cestu musím mít ke složce ve které
je ten baťák, pravda ?
To service Lflc je cesta k mé vytvořené třídě a já tam přidám tu cestu
do závorky? Ttedy v commonu to pak vypadá takto?
service:
- App\Services\Lflc(%appDir%/../Services/lflc)
to poslední lflc je pak složka, která obsahuje ten baťák. I tak to stále nefunguje.
Přesouvám tu složku z místa na místo a zkouším, ale nedaří se. Je správně, že je složka lflc, která obsauje baťák ve složce www ? Nemá být třeba jinde, abych na ten baťák dosáhl, nebo to je jedno ? Teď je ta složka s lflc ve složce Services, ve které je i třída Lflc.
Mám pocit, že jsem se do toho trochu zamotal.
- uestla
- Backer | 799
To rozmotáme :-)
Pokud máš tu složku lflc přímo ve složce s třídou Lflc, tak bude nejpřímočařejší do toho původní volání přidat absolutní cestu:
exec(escapeshellcmd(__DIR__ . '/lflc/lflc-run.bat'));
Za šťastnější bych ale považoval si danou cestu předat jako závislost, jak jsem popisoval výše.
- Fajmy
- Člen | 10
Tak jsem vyzkoušel a nic. Složku lflc ve které je baťák mám teda ve složce kde mám i třídu Lflc.
Takhle vypadá ten kus kódu:
exec(escapeshellcmd(__DIR__ . '/lflc/lflc-run.bat'), $out, $var);
dump($out, $var);
A tohle dostávám na výsledek:
array
0 => ""
1 => "D:\XAMPP\htdocs\DIPL\www>D:\XAMPP\htdocs\DIPL\www\hierarchic_base.exe -k D:\XAMPP\htdocs\DIPL\www\test_db.knb -i D:\XAMP\htdocs\DIPL\www\data.txt -o ... " (185)
1
Napadlo mě, nepotřebuji nějakou speciální knihovnu k tomu abych mohl
spouštět exec()
v Nette ?
- uestla
- Backer | 799
Tak to už vypadá, že se ten baťák volá – výstup ti ale Dumper ořízne (má celkem 185 znaků), takže nevidíš celou tu hlášku, ale evidentně dochází k nějaké chybě až uvnitř toho batch scriptu (voláš tam nějaký hierarchic_base.exe atd.).
Dumpni si to neořezané, třeba ti to prozradí víc:
Tracy\Debugger::$maxLength = false;
dump($out, $var);
- Fajmy
- Člen | 10
Po vyzkoušení dostávám takovouto hlášku: "":https://ctrlv.cz/ZoLw
Baťák vypadá takto:
@echo off
::
:: Environment settings
::
set dir=%cd%
set lflc=%dir%\hierarchic_base.exe
::
:: SGS LFLC default files
::
:: LFLC knowledge base file
set kbn=test_db.knb
:: LFLC input file
set input=data.txt
:: LFLC output file
set output=output.txt
::
:: LFLC execution
::
@echo on
%lflc% -k %dir%\%kbn% -i %dir%\%input% -o %dir%\%output%
Jedná se o simulaci expertního systému, vložím vstupní data do inputu
→ provede se baťák → a ten mi vyplivne výsledky podle expertního
systému vytvořeného právě v programu LFLC.
A jak jsem psal na začátku, tak když si vytvořím obyčejný php projekt,
tak mi to jde spustit a vše proběhne v pořádku.
- uestla
- Backer | 799
Je to pořád o té cestě k souboru – při spouštění v rámci
projektu máš working directory nastavenou na www složku.
V tom batchi se na řádku 6 používá CWD, tím pádem ti to nejspíše
spadne na tom, že to nenajde hierarchic_base.exe
(pro zbytek té
chybové zprávy si nastav Debugger::$maxLength = null
, s tím
false
jsem se přepsal, tak se to dělalo dříve).
Možná bude pro tebe nejjednodušší nastavit v tom execu ještě CWD:
exec(escapeshellcmd(sprintf('cd %s && lflc/lflc-run.bat', __DIR__)));
Tím pádem se to přepne do té složky, a jak exec(), tak samotný batch skript budou operovat se správnou working directory.
- Fajmy
- Člen | 10
Zkusil jsem a někam se to pohlo. První spuštění po změně, mi tento příkaz vrátil prázdné pole a 1:
exec(escapeshellcmd(sprintf('cd %s && /lflc/lflc-run.bat', __DIR__)), $out, $var);
dump($out, $var);
Pak jsem zkusil tuhle variantu
exec(__DIR__.'/lflc/lflc-run.bat', $o, $v);
dump($o, $v);
a to se už načítalo déle, po prvním spuštěním vyskočilo cmd a napsalo se že hieararchic-base.exe přestalo pracovat. Následně mi vyskočilo tohle:
array
0 => ''
1 => 'D:\XAMPP\htdocs\DIPL\www>D:\XAMPP\htdocs\DIPL\app\Services\lflc\\hierarchic_base.exe -k D:\XAMPP\htdocs\DIPL\app\Services\lflc\\test_db.knb -i D:\XAMP … output.txt'
3
Tento výstup dostávám teď po každém spuštění ikdyž se nezapne cmd a nevyskočí hláška že přestalo pracovat.