Parsing command line: optimization is evil!
One thing all contributors on this page forgotten is that you can suround an argv with single or double quotes. So the join coupled together with the preg_match_all will always break that :)
Here is a proposal:
#!/usr/bin/php
<?php
print_r(arguments($argv));
function arguments ( $args )
{
array_shift( $args );
$endofoptions = false;
$ret = array
(
'commands' => array(),
'options' => array(),
'flags' => array(),
'arguments' => array(),
);
while ( $arg = array_shift($args) )
{
// if we have reached end of options,
//we cast all remaining argvs as arguments
if ($endofoptions)
{
$ret['arguments'][] = $arg;
continue;
}
// Is it a command? (prefixed with --)
if ( substr( $arg, 0, 2 ) === '--' )
{
// is it the end of options flag?
if (!isset ($arg[3]))
{
$endofoptions = true;; // end of options;
continue;
}
$value = "";
$com = substr( $arg, 2 );
// is it the syntax '--option=argument'?
if (strpos($com,'='))
list($com,$value) = split("=",$com,2);
// is the option not followed by another option but by arguments
elseif (strpos($args[0],'-') !== 0)
{
while (strpos($args[0],'-') !== 0)
$value .= array_shift($args).' ';
$value = rtrim($value,' ');
}
$ret['options'][$com] = !empty($value) ? $value : true;
continue;
}
// Is it a flag or a serial of flags? (prefixed with -)
if ( substr( $arg, 0, 1 ) === '-' )
{
for ($i = 1; isset($arg[$i]) ; $i++)
$ret['flags'][] = $arg[$i];
continue;
}
// finally, it is not option, nor flag, nor argument
$ret['commands'][] = $arg;
continue;
}
if (!count($ret['options']) && !count($ret['flags']))
{
$ret['arguments'] = array_merge($ret['commands'], $ret['arguments']);
$ret['commands'] = array();
}
return $ret;
}
exit (0)
/* vim: set expandtab tabstop=2 shiftwidth=2: */
?>
Utilizzo di PHP da linea di comando
A partire dalla versione 4.3.0, il PHP supporta un nuovo tipo di SAPI (Server Application Programming Interface) chiamata CLI che significa Interfaccia per la Linea di Comando (Command Line Interface). Come il nome stesso suggerisce, questo tipo di SAPI è mirato allo sviluppo di applicazioni shell (o desktop) con PHP. Esistono alcune differenze tra la CLI SAPI e le altre SAPI; queste saranno illustrate nel corrente capitolo. Val la pena ricordare che CLI e CGI sono differenti SAPI sebbene condividano il medesimo comportamento in diverse situazioni.
La CLI SAPI è stata rilasciata per la prima volta con PHP 4.2.0, ma era ancora sperimentale e quindi doveva essere esplicitamente abilitata con --enable-cli nell'esecuzione di ./configure. A partire dal PHP 4.3.0 la CLI SAPI non viene più considerata sperimentale e quindi l'opzione --enable-cli è attivata per default. Vedere --disable-cli per disabilitare l'opzione.
Dal PHP 4.3.0, il nome, la posizione, e l'esistenza di eseguibili CLI/CGI differirà in base a come il PHP sarà installato sul sistema. Per default quando si esegue il make, si compila sia la versione CLI sia la versione CGI e saranno poste rispettivamente in sapi/cgi/php e sapi/cli/php a partire dalla directory dei sorgenti. Occorre notare che entrambi gli eseguibili sono chiamati php. Ciò che accade durante l'esecuzione di dipende dalla linea di configurazione. Se durante la configurazione si è scelto un modulo SAPI, tipo apxs, o si è attivato --disable-cgi, l'eseguibile CLI viene copiato in durante make install, altrimenti in questa cartella sarà posto l'eseguibile CGI. Così, per esempio, se si ha come parametro di configurazione --with--apxs allora l'eseguibile CLI sarà copiato in {PREFIX}/bin/php durante make install. Se si vuole evitare l'installazione dell'eseguibile CGI, utilizzare make install-cli dopo make install. In alternativa si può specificare --disable-cgi nella linea di configurazione.
Nota: Poichè sia --enable-cli sia --enable-cgi sono abilitati per default, avere semplicemente --enable-cli nella linea di configurazione non significa necessariamente che l'eseguibile CLI sia copiato come {PREFIX}/bin/php con l'esecuzione di make install.
Nel pacchetto per Windows, nelle versioni tra PHP 4.2.0 e PHP 4.2.3, l'eseguibile CLI era presente come php-cli.exe, nella medesima cartella della versione CGI php.exe. A partire dal PHP 4.3.0 nel pacchetto per Windows la versione CLI viene distribuita come php.exe in una cartella a parte chiamata cli, avendo perciò cli/php.exe. A partire dal PHP 5, la versione CLI viene inserita nella cartella principale, con il nome php.exe. La versione CGI sarà chiamata php-cgi.exe.
Sempre dal PHP 5, sarà introdotto un nuovo file chiamato php-win.exe. Questo è equivalente alla versione CLI, tranne che php-win non visualizzerà nulla e quindi non vi sarà la finestra di console (non compare la fienstra dos nello schermo). Questo comportamento è stato ripreso da php-gtk. Si dovrebbe configurare il PHP con --enable-cli-win32.
Nota: Quale SAPI ho? Da shell, digitando php -v si avrà l'informazione di quale php si tratta, CGI o CLI. Vedere anche la funzione php_sapi_name()e la costante PHP_SAPI per dettagli.
Nota: Una pagina stile man di Unix è stata aggiunta in PHP 4.3.2. La si può visualizzare digitando man php da linea di comando.
Le principali differenze tra la CLI SAPI e le altre SAPI sono:
-
A differenza di CGI SAPI, non sono inviate in output delle intestazioni.
Mentre nella CGI SAPI esiste un modo per sopprimere le intestazioni, nella CLI SAPI non si ha una opzione per abilitare le intestazioni.
Per default CLI parte in modalità silenziosa, si è mantenuto, comunque, l'opzione -q e --no-header per motivi di compatibilità; in questo modo si possono utlizzare i vecchi script CGI.
Non cambia la directory di lavoro in quella dello script. (E' rimasta l'opzione -C e --no-chdir per compatibilità)
Messaggi di errore in formato testo (non formattati in HTML).
-
Esistono, inoltre, alcune direttive del php.ini che sono forzate nell'impostazione dalla CLI SAPI poichè non hanno senso nell'ambiente di shell:
Direttive del php.ini forzate Direttiva CLI SAPI valore di default Commento html_errors FALSE E' difficile leggere i messaggi di errore nella shell quando sono affogati in tag HTML prive di significato; pertanto il default della direttiva è impostato a FALSE. implicit_flush TRUE E' desiderabile che ogni tipo di output proveniente da print(), echo() e simili sia scritto immediatamente e non venga bufferizzato. Tuttavia è ancora possibile utilizzare le funzioni di controllo dell'output se si desidera ritardare o manipolare lo standard output. max_execution_time 0 (unlimited) Considerate le svariate possibilità offerte da PHP nell'ambiente di shell, il tempo massimo di esecuzione è stato impostato a infinito. Mentre nelle applicazione scritte per il web i tempi di esecuzione sono rapidi, le applicazioni di shell tendono ad avere tempi di esecuzione molto più lunghi. register_argc_argv TRUE Poichè è impostato a TRUE nella CLI SAPI si ha sempre la possibilità di accedere alla variabili argc (numero di argomenti passati all'applicazione) e argv (matrice degli argumenti).
A partire da PHP 4.3.0, quando si utilizza la CLI SAPI le variabili PHP $argc e $argv sono sempre registrate e valorizzate in modo appropriato. Prima di questa versione la creazione di queste variabili era coerente con il comportamento delle versioni CGI e MODULO le quali richiedevano che la direttiva PHP register_globals fosse impostata a on. A prescindere dalla versione o dall'impostazione di register_globals si può sempre accedere alle variabili $_SERVER o $HTTP_SERVER_VARS. Esempio: $_SERVER['argv']
Nota: Queste direttive non possono essere inizializate con altri valori dal file di configurazione php.ini o da uno personalizzato (se specifictao). Questa è una limitazione perchè questi valori di default sono applicati dopo avere esaminato tutti i file di configurazione. Tuttavia i loro valori possono essere cambiati durante l'esecuzione (operazione che non ha senso per queste direttive, ad esempio register_argc_argv).
-
Per potere lavorare meglio con le shell, sono state definite le seguenti costanti:
Costanti specifiche per CLI Costante Descrizione STDIN Un flusso già aperto allo stdin. Questo evita di aprirlo con Se si desidera leggere una singola linea dallo stdin, si può utilizzare<?php
$stdin = fopen('php://stdin', 'r');
?><?php
$line = trim(fgets(STDIN)); // reads one line from STDIN
fscanf(STDIN, "%d\n", $number); // reads number from STDIN
?>STDOUT Un flusso già aperto allo stdout. Questo evita di aprirlo con <?php
$stdout = fopen('php://stdout', 'w');
?>STDERR Un flusso già aperto allo stderr. Questo evita di aprirlo con <?php
$stderr = fopen('php://stderr', 'w');
?>Stante a quanto descritto non occorre più aprire in autonomia flussi per, ad esempio, lo stderr, ma semplicemente si può usare le costanti anzichè una nuova risorsa di flusso:
Non occorre chiudere esplicitamente questi flussi, saranno chiusi automaticamente dal PHP alla fine dello script.php -r 'fwrite(STDERR, "stderr\n");'
-
La CLI SAPI non cambia la directory corrente in quella dello script eseguito!
Il seguente esempio illustra la diferenza rispetto alla CGI SAPI:
<?php
// Semplice esempio di test chiamato test.php
echo getcwd(), "\n";
?>Quando si usa la versione CGI, si avrà il seguente output:
Questo evidenzia chiaramente come il PHP cambi la directory corrente con quella in cui si trova lo script.$ pwd /tmp $ php -q another_directory/test.php /tmp/another_directory
Utilizzando la versione CLI SAPI abbiamo:
Questo permette una grande flessibilità nello scrivere tools in PHP.$ pwd /tmp $ php -f another_directory/test.php /tmp
Nota: La CGI SAPI supporta il comportamento della CLI SAPI attivando l'opzione -C quando viene eseguito da linea di comando.
L'elenco completo delle opzioni del PHP disponibili da linea di comando può essere visualizzato in qualsiasi momento eseguendo il PHP con l'opzione -h:
Usage: php [options] [-f] <file> [--] [args...] php [options] -r <code> [--] [args...] php [options] [-B <begin_code>] -R <code> [-E <end_code>] [--] [args...] php [options] [-B <begin_code>] -F <file> [-E <end_code>] [--] [args...] php [options] -- [args...] -a Run interactively -c <path>|<file> Look for php.ini file in this directory -n No php.ini file will be used -d foo[=bar] Define INI entry foo with value 'bar' -e Generate extended information for debugger/profiler -f <file> Parse <file>. -h This help -i PHP information -l Syntax check only (lint) -m Show compiled in modules -r <code> Run PHP <code> without using script tags <?..?> -B <begin_code> Run PHP <begin_code> before processing input lines -R <code> Run PHP <code> for every input line -F <file> Parse and execute <file> for every input line -E <end_code> Run PHP <end_code> after processing all input lines -H Hide any passed arguments from external tools. -s Display colour syntax highlighted source. -v Version number -w Display source with stripped comments and whitespace. -z <file> Load Zend extension <file>. args... Arguments passed to script. Use -- args when first argument starts with - or script is read from stdin
La vesione CLI SAPI ha tre differenti modi per eseguire il codice PHP:
-
Dire al PHP di eseguire certi file.
Entrambi i metodi (con o senza l'opzione -f) eseguono il file my_script.php. Si può scegliere qualsiasi nome per lo script da eseguire - non è obbligatorio che gli script PHP finiscano con l'estensione .php, ma possono avere qualsiasi nome o estensione che si desideri.php my_script.php php -f my_script.php
-
Passare il codice PHP da eseguire direttamente da linea di comando.
Occorre prestare molta attenzione alla sostituzione delle variabili di shell e all'uso degli apici.php -r 'print_r(get_defined_constants());'
Nota: Osservando con attenzione l'esempio si nota l'assenza dei tag di inizio e fine! L'opzione -r non li richiede. L'uso dei tag genera un errore di parsing.
-
Si può passare il codice PHP da eseguire via standard input (stdin).
Questo da la possibilità di generare dinamicamente del codice PHP e passarlo all'eseguibile, come illustrato nel seguente esempio (fittizio):
$ some_application | some_filter | php | sort -u >final_output.txt
Come qualsiasi applicazione di shell, anche l'eseguibile PHP accetta diversi argomenti, ma anche lo script PHP può ricevere argomenti. Il numero degli argomenti passabili allo script non è limitato dal PHP (si rammenta che la shell ha un limite nel numero di caratteri che possono essere passati; solitamente non si raggiunte questo limite). Gli argomenti passati allo script sono disponibili nell'array $argv. L'indice zero contiene sempre il nome dello script (che è - nel caso in cui il codice PHP provenda o dallo standard input o dalla linea di comando con l'opzione -r). La seconda variabile globale registrata è $argc la quale contiene il numero degli elementi nella matrice $argv (non è il numero degli argomenti passati allo script).
Fino a quando gli argomenti passati allo script non iniziano con il carattere - non si deve prestare alcuna cautela. Tuttavia se si passa allo script argomenti che iniziano con - si hanno dei problemi perchè lo stesso PHP ritiene di doverli gestire. Per evitare ciò occorre utilizzare il separatore di argomenti --. Dopo che il PHP ha incontrato questo separatore, ogni argomento verrà passato direttamente allo script.
# Questo non visualizzerà il codice passato, ma l'elenco delle opzioni $ php -r 'var_dump($argv);' -h Usage: php [options] [-f] <file> [args...] [...] # Questo passerà il '-h'allo script ed eviterà al PHP di visualizzare le opzioni $ php -r 'var_dump($argv);' -- -h array(2) { [0]=> string(1) "-" [1]=> string(2) "-h" }
Tuttvia esiste un'altro modo per eseguire gli script PHP. Si può scrivere uno script la cui prima riga inizi con #!/usr/bin/php. Seguendo questa regola si può posizionare il normale codice PHP tra i tag di apertura e chiusura del PHP. Una volta impostati correttamente gli attributi del file (ad esempio chmod +x test) lo script può essere eseguito come una normale shell o script perl:
#!/usr/bin/php
<?php
var_dump($argv);
?>
$ chmod +x test $ ./test -h -- foo array(4) { [0]=> string(6) "./test" [1]=> string(2) "-h" [2]=> string(2) "--" [3]=> string(3) "foo" }
I parametro lunghi sono disponibili dal PHP 4.3.3.
| Parametro | Parametro lungo | Descrizione |
|---|---|---|
| -a | --interactive |
Esegue il PHP in modo interattivo. |
| -c | --php-ini |
Con questa opzione si può sia specificare la directory in cui cercare il php.ini o si può specificare un file INI personalizzato (che non deve necessariamente chiamarsi php.ini), ad esempio:
|
| -n | --no-php-ini |
Ignora del tutto il php.ini. Opzione disponibile dal PHP 4.3.0. |
| -d | --define |
Questa opzione permette di impostare valori personalizzati per qualsiasi delle direttive di configurazione previste in php.ini. La sintassi è:
Esempi (le linee vanno a capo per motivi di layout):
|
| -e | --profile-info |
Genera informazioni estese per il debugger/profiler. |
| -f | --file |
Analizza ed esegue il file passato con l'opzione -f. Questo parametro è opzionale e può essere omesso. Basta fornire il nome del file da eseguire. |
| -h e -? | --help e --usage | Con questa opzione si ha l'elenco dei comandi di linea ed una breve descrizione di questi. |
| -i | --info | Questa opzione della linea di comando richiama la funzione phpinfo(), e ne visualizza il risultato. Se il PHP non funziona correttamente, è opportuno utilizzare php -i per verificare se sono visualizzati messaggi di errore prima o al posto della tabella con le informazioni. Fare attenzione quando si usa la modalità CGI, l'output è in formato HTML e quindi abbastanza abbondante. |
| -l | --syntax-check |
Questa opzione fornisce un metodo pratico per eseguire un controllo sintattico di un dato codice PHP. Se il controllo ha successo, verrà visualizzato il testo No syntax errors detected in <filename> e alla shell sarà restituito il codice 0. Se si rilevano errori si avrà il testo Errors parsing <filename>, inoltre si avranno anche i messaggi di errore del parser ed alla shell sarà restituito il codice 255. Questa opzione non rileva errori fatali (tipo funzioni non definite). Occorre utilizzare l'opzione -f se si desidera rilevare gli errori fatali.
|
| -m | --modules |
Utilizzare questa opzione per visualizzare i moduli PHP e di Zend integrati (e quindi caricati):
|
| -r | --run |
Questa opzione permette l'esecuzione di codice PHP direttamente da linea di comando. I tag PHP di apertura e di chiusura (<?php e ?>) non sono necessari anzi, se presenti, causano un errore del parser.
|
| -B | --process-begin |
Codice PHP da eseguirsi prima di processare stdin. Aggiunto in PHP 5. |
| -R | --process-code |
Esegue il codice PHP per ogni linea di input. Aggiunto in PHP 5. In questa modalità si hanno due variabili speciali: $argn ed $argi. $argn contiene la linea PHP in elaborazione al momento, mentre $argi contiene il numero di linea. |
| -F | --process-file |
Esegue il file PHP per ogni linea di input. Aggiunto in PHP 5. |
| -E | --process-end |
Codice PHP da eseguirsi dopo il processamento dell'input. Aggiunto in PHP 4. Esempio di utilizzo delle opzioni -B, -R e -E per contare il numero di linea di un progetto.
|
| -s | --syntax-highlight e --syntax-highlighting |
Visualizza il sorgente con sintassi colorata. Questa opzione utilizza il meccanismo interno di parsing dei file e produce una versione HTML del sorgente e la dirige verso lo standard output. Occore notare che questa funzione genera dei blocchi di tag HTML <code> [...] </code> e non le intestazione HTML.
|
| -v | --version |
Visualizza le versioni di PHP, PHP SAPI, e Zend nello standard output, ad esempio:
|
| -w | --strip |
Visualizza il sorgente senza gli spazi e i commenti.
|
| -z | --zend-extension |
Carica l'estensione Zend. Soltano se si fornisce un nome di file, il PHP tenta di caricare l'estensione dal corrente percorso di default delle librerie (solitamente, sui sistemi Linux, /etc/ld.so.conf). Se si fornisce un nome di file con percorso assoluto, ls libreria non sarà cercata nella directory di default. Un nome di file con percorso relativo indica al PHP di tentare di caricare l'estensione con percorso relativo alla directory corrente. |
L'eseguibile PHP può essere utilizzato per eseguire script PHP in modo indipendente dal server web. Se ci si trova su sistemi Unix, si può aggiungere una prima linea speciale allo script PHP e renderlo eseguibile, in questo modo il sistema sa quale programma deve interpretare lo script. Sui sistemi Windows si può associare php.exe all'estensione .php, o si può scrivere un batch per eseguire gli script tramite PHP. La prima riga inserita per i sistemi Unix non crea problemi in Windows, in questo modo si possono scrivere batch multi-piattaforma. Seguirà un semplice esempio di programma PHP da linea di comando.
Example #1 Script sviluppato per essere esguito da linea di comando (script.php)
#!/usr/bin/php
<?php
if ($argc != 2 || in_array($argv[1], array('--help', '-help', '-h', '-?'))) {
?>
Questo è uno script PHP da linea di comando con una opzione.
Utilizzo:
<?php echo $argv[0]; ?> <opzione>
<opzione> può essere qualsiasi parola che si desidera
stampata. Con --help, -help, -h,
o -? si ottiene questo aiuto.
<?php
} else {
echo $argv[1];
}
?>
Nello script precedente, abbiamo utilizzato la prima riga per indicare che questo file deve essere interpretato dal PHP. Poichè qui lavoriamo con la versione CLI non vengono prodotte intestazioni HTTP. Esistono due variabili che si possono utilizzare nelle applicazioni PHP da linea di comando: $argc e $argv. La prima è il numero di argomenti più uno (il nome dello script). La seconda è una matrice contenente gli argomenti, iniziando dal nome dello script all'indice zero ($argv[0]).
Nel programma precedente abbiamo verificato se i parametri passati erano di più o di meno di uno. Inoltre se l'argomento è --help, -help, -h oppure -?, si visualizza un messaggio di aiuto, visualizzando in modo dinamico il nome dello script. Se si riceve un argomento differente questo sarà visualizzato.
Se si desidera eseguire lo script precedente su Unix, occorre, per prima cosa, renderlo eseguibile, e quindi richiamarlo con script.php echothis oppure script.php -h. Su Windows occorre scrivere un batch per ottenere questo risultato:
Example #2 File batch per eseguire uno script PHP da linea di comando (script.bat)
@c:\php\cli\php.exe script.php %1 %2 %3 %4
Assumendo che programma precedente sia chiamato script.php, che la versione CLI di php.exe sia in c:\php\cli\php.exe questo batch eseguirà lo script con le opzioni passate: script.bat echothis oppure script.bat -h.
Vedere anche la documentazione del modulo Readline per informazioni su funzioni che possono essere utilizzate per migliorare le applicazioni da linea di comando.
Utilizzo di PHP da linea di comando
15-Jun-2008 12:08
07-May-2008 10:08
If a module SAPI is chosen during configure, such as apxs, or the --disable-cgi option is used, the CLI is copied to {PREFIX}/bin/php during make install otherwise the CGI is placed there.
versus
Changed CGI install target to php-cgi and 'make install' to install CLI when CGI is selected. (changelog for 5.2.3)
http://www.php.net/ChangeLog-5.php#5.2.3
29-Feb-2008 03:32
When you want to get inputs from STDIN, you may use this function if you like using C coding style.
<?php
// up to 8 variables
function scanf($format, &$a0=NULL, &$a1=NULL, &$a2=NULL, &$a3=NULL,
&$a4=NULL, &$a5=NULL, &$a6=NULL, &$a7=NULL)
{
$num_args = func_num_args();
if($num_args > 1) {
$inputs = fscanf(STDIN, $format);
for($i=0; $i<$num_args-1; $i++) {
$arg = 'a'.$i;
$$arg = $inputs[$i];
}
}
}
scanf("%d", $number);
?>
17-Feb-2008 06:29
I find regex and manually breaking up the arguments instead of havingon $_SERVER['argv'] to do it more flexiable this way.
cli_test.php asdf asdf --help --dest=/var/ -asd -h --option mew arf moo -z
Array
(
[input] => Array
(
[0] => asdf
[1] => asdf
)
[commands] => Array
(
[help] => 1
[dest] => /var/
[option] => mew arf moo
)
[flags] => Array
(
[0] => asd
[1] => h
[2] => z
)
)
<?php
function arguments ( $args )
{
array_shift( $args );
$args = join( $args, ' ' );
preg_match_all('/ (--\w+ (?:[= ] [^-]+ [^\s-] )? ) | (-\w+) | (\w+) /x', $args, $match );
$args = array_shift( $match );
/*
Array
(
[0] => asdf
[1] => asdf
[2] => --help
[3] => --dest=/var/
[4] => -asd
[5] => -h
[6] => --option mew arf moo
[7] => -z
)
*/
$ret = array(
'input' => array(),
'commands' => array(),
'flags' => array()
);
foreach ( $args as $arg ) {
// Is it a command? (prefixed with --)
if ( substr( $arg, 0, 2 ) === '--' ) {
$value = preg_split( '/[= ]/', $arg, 2 );
$com = substr( array_shift($value), 2 );
$value = join($value);
$ret['commands'][$com] = !empty($value) ? $value : true;
continue;
}
// Is it a flag? (prefixed with -)
if ( substr( $arg, 0, 1 ) === '-' ) {
$ret['flags'][] = substr( $arg, 1 );
continue;
}
$ret['input'][] = $arg;
continue;
}
return $ret;
}
print_r( arguments( $argv ) );
?>
12-Feb-2008 03:21
Here's an update to the script a couple of people gave below to read arguments from $argv of the form --name=VALUE and -flag. Changes include:
Don't use $_ARG - $_ is generally considered reserved for the engine.
Don't use regex where a string operation will do just as nicely
Don't overwrite --name=VALUE with -flag when 'name' and 'flag' are the same thing
Allow for VALUE that has an equals sign in it
function arguments($argv) {
$ARG = array();
foreach ($argv as $arg) {
if (strpos($arg, '--') === 0) {
$compspec = explode('=', $arg);
$key = str_replace('--', '', array_shift($compspec));
$value = join('=', $compspec);
$ARG[$key] = $value;
} elseif (strpos($arg, '-') === 0) {
$key = str_replace('-', '', $arg);
if (!isset($ARG[$key])) $ARG[$key] = true;
}
}
return $ARG;
}
29-Oct-2007 12:51
Here's <losbrutos at free dot fr> function modified to support unix like param syntax like <B Crawford> mentions:
<?php
function arguments($argv) {
$_ARG = array();
foreach ($argv as $arg) {
if (preg_match('#^-{1,2}([a-zA-Z0-9]*)=?(.*)$#', $arg, $matches)) {
$key = $matches[1];
switch ($matches[2]) {
case '':
case 'true':
$arg = true;
break;
case 'false':
$arg = false;
break;
default:
$arg = $matches[2];
}
/* make unix like -afd == -a -f -d */
if(preg_match("/^-([a-zA-Z0-9]+)/", $matches[0], $match)) {
$string = $match[1];
for($i=0; strlen($string) > $i; $i++) {
$_ARG[$string[$i]] = true;
}
} else {
$_ARG[$key] = $arg;
}
} else {
$_ARG['input'][] = $arg;
}
}
return $_ARG;
}
?>
Sample:
eromero@ditto ~/workspace/snipplets $ foxogg2mp3.php asdf asdf --help --dest=/var/ -asd -h
Array
(
[input] => Array
(
[0] => /usr/local/bin/foxogg2mp3.php
[1] => asdf
[2] => asdf
)
[help] => 1
[dest] => /var/
[a] => 1
[s] => 1
[d] => 1
[h] => 1
)
22-Oct-2007 11:11
I was looking for a way to interactively get a single character response from user. Using STDIN with fread, fgets and such will only work after pressing enter. So I came up with this instead:
#!/usr/bin/php -q
<?php
function inKey($vals) {
$inKey = "";
While(!in_array($inKey,$vals)) {
$inKey = trim(`read -s -n1 valu;echo \$valu`);
}
return $inKey;
}
function echoAT($Row,$Col,$prompt="") {
// Display prompt at specific screen coords
echo "\033[".$Row.";".$Col."H".$prompt;
}
// Display prompt at position 10,10
echoAT(10,10,"Opt : ");
// Define acceptable responses
$options = array("1","2","3","4","X");
// Get user response
$key = inKey($options);
// Display user response & exit
echoAT(12,10,"Pressed : $key\n");
?>
Hope this helps someone.
22-Oct-2007 04:01
I have not seen in this thread any code snippets that support the full *nix style argument parsing. Consider this:
<?php
print_r(getArgs($_SERVER['argv']));
function getArgs($args) {
$out = array();
$last_arg = null;
for($i = 1, $il = sizeof($args); $i < $il; $i++) {
if( (bool)preg_match("/^--(.+)/", $args[$i], $match) ) {
$parts = explode("=", $match[1]);
$key = preg_replace("/[^a-z0-9]+/", "", $parts[0]);
if(isset($parts[1])) {
$out[$key] = $parts[1];
}
else {
$out[$key] = true;
}
$last_arg = $key;
}
else if( (bool)preg_match("/^-([a-zA-Z0-9]+)/", $args[$i], $match) ) {
for( $j = 0, $jl = strlen($match[1]); $j < $jl; $j++ ) {
$key = $match[1]{$j};
$out[$key] = true;
}
$last_arg = $key;
}
else if($last_arg !== null) {
$out[$last_arg] = $args[$i];
}
}
return $out;
}
/*
php file.php --foo=bar -abc -AB 'hello world' --baz
produces:
Array
(
[foo] => bar
[a] => true
[b] => true
[c] => true
[A] => true
[B] => hello world
[baz] => true
)
*/
?>
27-Sep-2007 02:54
an another "another variant" :
<?php
function arguments($argv)
{
$_ARG = array();
foreach ($argv as $arg)
{
if (preg_match('#^-{1,2}([a-zA-Z0-9]*)=?(.*)$#', $arg, $matches))
{
$key = $matches[1];
switch ($matches[2])
{
case '':
case 'true':
$arg = true;
break;
case 'false':
$arg = false;
break;
default:
$arg = $matches[2];
}
$_ARG[$key] = $arg;
}
else
{
$_ARG['input'][] = $arg;
}
}
return $_ARG;
}
?>
$php myscript.php arg1 -arg2=val2 --arg3=arg3 -arg4 --arg5 -arg6=false
Array
(
[input] => Array
(
[0] => myscript.php
[1] => arg1
)
[arg2] => val2
[arg3] => arg3
[arg4] => true
[arg5] => true
[arg5] => false
)
16-Aug-2007 09:24
For those who was unable to clear the windows screen trying to run CLS command:
CLS is not an windows executable file! It is an option from command.com!
So, the rigth command is
system("command /C cls");
22-Jul-2007 08:04
Just another variant of previous script that group arguments doesn't starts with '-' or '--'
function arguments($argv) {
$_ARG = array();
foreach ($argv as $arg) {
if (ereg('--([^=]+)=(.*)',$arg,$reg)) {
$_ARG[$reg[1]] = $reg[2];
} elseif(ereg('^-([a-zA-Z0-9])',$arg,$reg)) {
$_ARG[$reg[1]] = 'true';
} else {
$_ARG['input'][]=$arg;
}
}
return $_ARG;
}
$ php myscript.php --user=nobody /etc/apache2/*
Array
(
[input] => Array
(
[0] => myscript.php
[1] => /etc/apache2/apache2.conf
[2] => /etc/apache2/conf.d
[3] => /etc/apache2/envvars
[4] => /etc/apache2/httpd.conf
[5] => /etc/apache2/mods-available
[6] => /etc/apache2/mods-enabled
[7] => /etc/apache2/ports.conf
[8] => /etc/apache2/sites-available
[9] => /etc/apache2/sites-enabled
)
[user] => nobody
)
25-Jun-2007 08:02
In 5.1.2 (and others, I assume), the -f form silently drops the first argument after the script name from $_SERVER['argv']. I'd suggest avoiding it unless you need it for a special case.
04-Jun-2007 02:16
Just a variant of previous script to accept arguments with '=' also
<?php
function arguments($argv) {
$_ARG = array();
foreach ($argv as $arg) {
if (ereg('--([^=]+)=(.*)',$arg,$reg)) {
$_ARG[$reg[1]] = $reg[2];
} elseif(ereg('-([a-zA-Z0-9])',$arg,$reg)) {
$_ARG[$reg[1]] = 'true';
}
}
return $_ARG;
}
?>
$ php myscript.php --user=nobody --password=secret -p --access="host=127.0.0.1 port=456"
Array
(
[user] => nobody
[password] => secret
[p] => true
[access] => host=127.0.0.1 port=456
)
12-May-2007 11:55
While working with command line scripts it is tedious to handle the arguments in a numerated array.
The following code will:
If the argument is of the form –NAME=VALUE it will be represented in the array as an element with the key NAME and the value VALUE. I the argument is a flag of the form -NAME it will be represented as a boolean with the name NAME with a value of true in the associative array.
<?php
function arguments($argv) {
$_ARG = array();
foreach ($argv as $arg) {
if (ereg('--[a-zA-Z0-9]*=.*',$arg)) {
$str = split("=",$arg); $arg = '';
$key = ereg_replace("--",'',$str[0]);
for ( $i = 1; $i < count($str); $i++ ) {
$arg .= $str[$i];
}
$_ARG[$key] = $arg;
} elseif(ereg('-[a-zA-Z0-9]',$arg)) {
$arg = ereg_replace("-",'',$arg);
$_ARG[$arg] = 'true';
}
}
return $_ARG;
}
?>
Example:
<?php print_r(arguments($argv)); ?>
# php5 myscript.php --user=nobody --password=secret -p
Array
(
[user] => nobody
[password] => secret
[p] => true
)
09-Apr-2007 12:27
I had a problem with PHP 5.2.0 (cli) (winXP) that no output was printed when I tried to run any file. Using the -n switch solved the problem.
Apparently the interpreter can't always find php.ini, even though both exist in the same folder and the PATH variable is set correctly. No error messages were printed either.
23-Mar-2007 08:48
i use emacs in c-mode for editing. in 4.3, starting a cli script like so:
#!/usr/bin/php -q /* -*- c -*- */
<?php
told emacs to drop into c-mode automatically when i loaded the file for editing. the '-q' flag didn't actually do anything (in the older cgi versions, it suppressed html output when the script was run) but it caused the commented mode line to be ignored by php.
in 5.2, '-q' has apparently been deprecated. replace it with '--' to achieve the 4.3 invocation-with-emacs-mode-line behavior:
#!/usr/bin/php -- /* -*- c -*- */
<?php
don't go back to your 4.3 system and replace '-q' with '--'; it seems to cause php to hang waiting on STDIN...
09-Mar-2007 04:14
To display colored text when it is actually supported :
<?php
echo "\033[31m".$myvar; // red foreground
echo "\033[41m".$myvar; // red background
?>
To reset these settings :
<?php
echo "\033[0m";
?>
More fun :
<?php
echo "\033[5;30m;\033[48mWARNING !"; // black blinking text over red background
?>
More info here : http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html
06-Mar-2007 05:03
python coders might miss this construct when working in PHP:
if __name__=='__main__':
# handle direct invocation from command line
it's a great way to embed little bits of test code (or a full-on cli for that matter),
while keeping the source file usable in other contexts.
Far as I can tell, this is the closest approximation available in PHP5:
if ('cli'===php_sapi_name() &&
__FILE__===realpath(
getcwd().DIRECTORY_SEPARATOR.$_SERVER['argv'][0]
)) {
// handle direct invocation from command line
}
26-Nov-2006 05:46
Hi,
This function clears the screen, like "clear screen"
<?php
function clearscreen($out = TRUE) {
$clearscreen = chr(27)."[H".chr(27)."[2J";
if ($out) print $clearscreen;
else return $clearscreen;
}
?>
14-Nov-2006 09:57
An addition to my previous post (you can replace it)
If your php script doesn't run with shebang (#!/usr/bin/php),
and it issues the beautifull and informative error message:
"Command not found." just dos2unix yourscript.php
et voila.
If you still get the "Command not found."
Just try to run it as ./myscript.php , with the "./"
if it works - it means your current directory is not in the executable search path.
If your php script doesn't run with shebang (#/usr/bin/php),
and it issues the beautifull and informative message:
"Invalid null command." it's probably because the "!" is missing in the the shebang line (like what's above) or something else in that area.
\Alon
It seems like 'max_execution_time' doesn't work on CLI.
<?php
php -d max_execution_time=20
-r '$foo = ini_get("max_execution_time"); var_dump($foo);'
?>
will print string(2) "20", but if you'l run infinity while: while(true) for example, it wouldn't stop after 20 seconds.
Testes on Linux Gentoo, PHP 5.1.6.
16-Sep-2006 12:59
On windows, you can simulate a cls by echoing out just \r. This will keep the cursor on the same line and overwrite what was on the line.
for example:
<?php
echo "Starting Iteration" . "\n\r";
for ($i=0;$i<10000;$i++) {
echo "\r" . $i;
}
echo "Ending Iteration" . "\n\r";
?>
21-Aug-2006 09:20
If your php script doesn't run with shebang (#!/usr/bin/php),
and it issues the beautifull and informative error message:
"Command not found." just dos2unix yourscript.php
et voila.
If your php script doesn't run with shebang (#/usr/bin/php),
and it issues the beautifull and informative message:
"Invalid null command." it's probably because the "!" is missing in the the shebang line (like what's above) or something else in that area.
\Alon
21-Feb-2006 07:27
Spawning php-win.exe as a child process to handle scripting in Windows applications has a few quirks (all having to do with pipes between Windows apps and console apps).
To do this in C++:
// We will run php.exe as a child process after creating
// two pipes and attaching them to stdin and stdout
// of the child process
// Define sa struct such that child inherits our handles
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES) };
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
// Create the handles for our two pipes (two handles per pipe, one for each end)
// We will have one pipe for stdin, and one for stdout, each with a READ and WRITE end
HANDLE hStdoutRd, hStdoutWr, hStdinRd, hStdinWr;
// Now create the pipes, and make them inheritable
CreatePipe (&hStdoutRd, &hStdoutWr, &sa, 0))
SetHandleInformation(hStdoutRd, HANDLE_FLAG_INHERIT, 0);
CreatePipe (&hStdinRd, &hStdinWr, &sa, 0)
SetHandleInformation(hStdinWr, HANDLE_FLAG_INHERIT, 0);
// Now we have two pipes, we can create the process
// First, fill out the usage structs
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi;
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = hStdoutWr;
si.hStdInput = hStdinRd;
// And finally, create the process
CreateProcess (NULL, "c:\\php\\php-win.exe", NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
// Close the handles we aren't using
CloseHandle(hStdoutWr);
CloseHandle(hStdinRd);
// Now that we have the process running, we can start pushing PHP at it
WriteFile(hStdinWr, "<?php echo 'test'; ?>", 9, &dwWritten, NULL);
// When we're done writing to stdin, we close that pipe
CloseHandle(hStdinWr);
// Reading from stdout is only slightly more complicated
int i;
std::string processed("");
char buf[128];
while ( (ReadFile(hStdoutRd, buf, 128, &dwRead, NULL) && (dwRead != 0)) ) {
for (i = 0; i < dwRead; i++)
processed += buf[i];
}
// Done reading, so close this handle too
CloseHandle(hStdoutRd);
A full implementation (implemented as a C++ class) is available at http://www.stromcode.com
25-Sep-2005 09:08
When you're writing one line php scripts remember that 'php://stdin' is your friend. Here's a simple program I use to format PHP code for inclusion on my blog:
UNIX:
cat test.php | php -r "print htmlentities(file_get_contents('php://stdin'));"
DOS/Windows:
type test.php | php -r "print htmlentities(file_get_contents('php://stdin'));"
19-Sep-2005 09:27
I needed this, you proly wont tho.
puts the exicution args into $_GET
<?php
if ($argv) {
foreach ($argv as $k=>$v)
{
if ($k==0) continue;
$it = explode("=",$argv[$i]);
if (isset($it[1])) $_GET[$it[0]] = $it[1];
}
}
?>
16-Sep-2005 06:06
To pass more than 9 arguments to your php-script on Windows, you can use the 'shift'-command in a batch file. After using 'shift', %1 becomes %0, %2 becomes %1 and so on - so you can fetch argument 10 etc.
Here's an example - hopefully ready-to-use - batch file:
foo.bat:
---------
@echo off
:init_arg
set args=
:get_arg
shift
if "%0"=="" goto :finish_arg
set args=%args% %0
goto :get_arg
:finish_arg
set php=C:\path\to\php.exe
set ini=C:\path\to\php.ini
%php% -c %ini% foo.php %args%
---------
Usage on commandline:
foo -1 -2 -3 -4 -5 -6 -7 -8 -9 -foo -bar
A print_r($argv) will give you all of the passed arguments.
18-Aug-2005 10:53
Hi, parsing the commandline (argv) can be very simple in PHP.
If you use keyword parms like:
script.php parm1=value parm3=value
All you have to do in script.php is:
for ($i=1; $i < $argc; $i++) {parse_str($argv[$i]);}
$startup=compact('parm1', 'parm2', 'parm3');
14-Jul-2005 02:44
dunno if this is on linux the same but on windows evertime
you send somthing to the console screen php is waiting for
the console to return. therefor if you send a lot of small
short amounts of text, the console is starting to be using
more cpu-cycles then php and thus slowing the script.
take a look at this sheme:
cpu-cycle:1 ->php: print("a");
cpu-cycle:2 ->cmd: output("a");
cpu-cycle:3 ->php: print("b");
cpu-cycle:4 ->cmd: output("b");
cpu-cycle:5 ->php: print("c");
cpu-cycle:6 ->cmd: output("c");
cpu-cylce:7 ->php: print("d");
cpu-cycle:8 ->cmd: output("d");
cpu-cylce:9 ->php: print("e");
cpu-cycle:0 ->cmd: output("e");
on the screen just appears "abcde". but if you write
your script this way it will be far more faster:
cpu-cycle:1 ->php: ob_start();
cpu-cycle:2 ->php: print("abc");
cpu-cycle:3 ->php: print("de");
cpu-cycle:4 ->php: $data = ob_get_contents();
cpu-cycle:5 ->php: ob_end_clean();
cpu-cycle:6 ->php: print($data);
cpu-cycle:7 ->cmd: output("abcde");
now this is just a small example but if you are writing an
app that is outputting a lot to the console, i.e. a text
based screen with frequent updates, then its much better
to first cach all output, and output is as one big chunk of
text instead of one char a the time.
ouput buffering is ideal for this. in my script i outputted
almost 4000chars of info and just by caching it first, it
speeded up by almost 400% and dropped cpu-usage.
because what is being displayed doesn't matter, be it 2
chars or 40.0000 chars, just the call to output takes a
great deal of time. remeber that.
maybe someone can test if this is the same on unix-based
systems. it seems that the STDOUT stream just waits for
the console to report ready, before continueing execution.
24-Jun-2005 05:07
For windows clearing the screen using "system('cls');" does not work (at least for me)...
Although this is not pretty it works... Simply send 24 newlines after the output (for one line of output, 23 for two, etc
Here is a sample function and usage:
function CLS($lines){ // $lines = number of lines of output to keep
for($i=24;$i>=$lines;$i--) @$return.="\n";
return $return;
}
fwrite(STDOUT,"Still Processing: Total Time ".$i." Minutes so far..." . CLS(1));
Hope This Helps,
Wallacebw
30-May-2005 04:32
If you are using Windows XP (I think this works on 2000, too) and you want to be able to right-click a .php file and run it from the command line, follow these steps:
1. Run regedit.exe and *back up the registry.*
2. Open HKEY_CLASSES_ROOT and find the ".php" key.
IF IT EXISTS:
------------------
3. Look at the "(Default)" value inside it and find the key in HKEY_CLASSES_ROOT with that name.
4. Open the "shell" key inside that key. Skip to 8.
IF IT DOESN'T:
------------------
5. Add a ".php" key and set the "(Default)" value