spuštění batch souboru pomocí exec()

Fajmy
Člen | 10
+
0
-

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");
uestla
Backer | 799
+
0
-

Ahoj,

kde a jak spouštíš kód, který volá tu funkci exec()?
„Nejede v Nette“ znamená, že se ten baťák nespouští?

Fajmy
Člen | 10
+
0
-

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
+
0
-

Ověř si, co vrací a dává na výstup samotné volání toho execu().
Moje podezření je, že to ten baťák nenajde, protože to máš jako relativní cestu.

exec("lflc/lflc-run.bat", $output, $return);
dump($output, $return);
Fajmy
Člen | 10
+
0
-

Vrací mi to 1, jestli to dobře chápu tak je to špatně a mělo by to vracet 0.

uestla
Backer | 799
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

Tenhle příkaz mi vyhodí prázdné pole.

uestla
Backer | 799
+
0
-

To nemusí být nutně špatně – záleží, co má nebo by měl vypisovat ten batch skript.
Status kód toho execu je pořád 1?

Fajmy
Člen | 10
+
0
-

Ano status je stále 1. Podle mě a co jsem zkoušel, tak ten batch skript nevypisuje nic, pouze vypočte ze vstupních hodnot výstupní hodnotu a tu zapíše do output.txt, který je pořád stejný a hodnoty se nemění.

n3t
Člen | 37
+
0
-

Ahoj,

je to o té cestě. Ten bat soubor se spustí v cestě webu, takže cd vratí ne cestu, kde je uložen ten bat, ale cestu kde je to php. Změň si v toma bat souboru řádek

set dir=%cd%

na

set dir=%~d0%~p0

a mělo by to fungovat.

Fajmy
Člen | 10
+
0
-

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.

Fajmy
Člen | 10
+
+2
-

Včera jsem s kolegou řešil problém a problém jsme vyřešili. Měli jste pravdu, bylo to o cestě, jenže baťák si tam přidával lomítka navíc. Postupným debuggováním jsme problém vyřešili. Nicméně vám chci poděkovat za vaše rady a připomínky, byly velice užitečné.