Hlavní navigace

PHP a skriptování v shellu

Luděk Chovanec

Že se PHP používá pro vývoj webových aplikací, ví asi každý. Méně známá je skutečnost, že PHP lze úspěšně použít pro psaní shellových skriptů. Mnoho uživatelů odrazuje od shellu syntaxe příkazů, obtížné ladění, nebo mají prostě více zkušeností s PHP. Pokud se rozhodnete vyzkoušet skriptování v PHP, tento článek vám poradí, jak na to.

Při použití pro webové aplikace pracuje PHP jako modul serveru Apache. Dnešní distribuce Linuxu však obvykle obsahují také interpreter PHP zkompilovaný jako spustitelný program, což nám umožňuje použití PHP jako skriptovacího jazyka pro shell.

PHP od verze 4.2 nabízí zdokonalenou podporu pro shellové skriptování (pomocí přepínače -enable-cli při kompilaci), všechny ukázky v tomto článku však fungují i ve verzích nižších.

Jak tedy psát shellové skripty v PHP? Vytvoříme textový soubor hello s následujícím obsahem:

#!/usr/bin/php -q
<?php
print "Hello World!\n";
?>

První řádek oznamuje shellu, že pro zpracování skriptu má použít program /usr/bin/php. Přepínač -q znamená, že PHP nebude posílat na výstup HTTP hlavičky, které pro shellové skriptování nepotřebujeme. Zbytek souboru je pak běžný PHP kód, který se interpretuje stejně jako při použití PHP s web serverem.

Změníme atributy souboru hello tak, aby byl spustitelný. Volání

./hello

nám pak dá očekávaný výsledek na výstupu:

Hello World!

V shellovém PHP skriptu můžeme využívat všech možností, které nám PHP nabízí, včetně práce s databázemi, poštou, XML a podobně. V další části článku se zaměříme na ty aspekty PHP, které se nejvíce týkají shellu a které při skriptování využijeme nejčastěji.

Volání příkazů shellu

Jazyk PHP obsahuje několik příkazů pro přímé volání externích programů: exec(), passthru(), shell_exec(), system(), proc_open()/proc_close(), obrácené apostrofy. Všechny můžeme využít i v PHP skriptech pro shell. Například následující skript:

#!/usr/bin/php -q
<?php
print "Dnesni datum a cas: " . system("/bin/date") . "\n";
?>

zavolá příkaz date a na standardní výstup vypíše jeho výsledek.

Operace s řetězci

Častou operací v shell skriptech je zpracování výstupu jiného programu. V klasickém shell skriptu většinou použijeme některou z variant utility awk, případně regulární výrazy, abychom z výstupu programu získali informace, které nás zajímají. V mnoha jednodušších případech lze v PHP k tomuto účelu použít operace s řetězci, zvláště funkce explode()implode().

#!/usr/bin/php -q
<?php
/* Zavolej program /bin/date */
$out = system("/bin/date");

/* Rozdel vystup po mezerach a uloz do pole */
$out_a = explode(" ", $out);

/* Ctvrta polozka je aktualni cas (h:m:s) */
$cas = $out_a[3];

/* Rozdel cas po dvojteckach a uloz do pole */
$cas_a = explode(":", $cas);

/* Vezmi hodnoty */
$hod = $cas_a[0];
$min = $cas_a[1];
$sek = $cas_a[2];

print "Je prave $hod hodin, $min minut a $sek sekund.\n";
?>

Návratová hodnota

Jsou situace, kdy nás při volání externího programu zajímá hlavně návratová hodnota. Pro tento účel si můžeme vytvořit vlastní variantu funkce  system():

#!/usr/bin/php -q
<?php
function system1($command) {
    if (!($p=popen("($command)2>&1","r"))) return 126;
    while (!feof($p))
        $l=fgets($p,1000);
    return pclose($p);
}

print "TRUE: " . system1("/bin/true") . "\n";
print "FALSE: " . system1("/bin/false") . "\n";
?>

Parametry skriptu

Pro práci s parametry skriptu slouží proměnná $argc a pole $argv, podobně jako v jazyce C.

#!/usr/bin/php -q
<?php
print "Pocet parametru: " . $argc . "\n";
foreach($argv as $param)
    print $param . "\n"
?>

Standardní vstup a chybový výstup

Pokud chceme skript použít jako filtr (pipe) nebo získávat vstup od uživatele, je
potřeba mít možnost číst data ze standardního vstupu. Občas je potřeba zapsat data
na chybový výstup. Obě situace ilustruje následující skript:

#!/usr/bin/php -q
<?php
function readline() {
    $fp = fopen("php://stdin","r");
    $line = fgets($fp, 1000);
    fclose($fp);
    return $line;
}

function print_error($msg) {
    $fp = fopen("php://stderr", "w");
    fputs($fp, $msg);
    fclose($fp);
}

print "Tvoje jmeno: ";
$jmeno = trim(readline());
print "$jmeno je OK!\n";
print_error("$jmeno ma chybu!\n");
?>

Závěr

Jak bývá v Linuxu zvykem, stejné věci jdou dělat mnoha různými způsoby. Jak je vidět z příkladů uvedených v článku, použití PHP v shellu není nic složitého a uživatelům PHP může ušetřit spoustu času stráveného jinak laděním a hledáním v manuálových stránkách.

Nové rozhraní CLI a experimentální podpora funkcí pro práci s ncurses  navíc naznačuje, že to vývojáři s podporou shellového skriptování myslí opravdu vážně a v příštích verzích PHP se máme na co těšit.

Našli jste v článku chybu?