76
76
77
77
#include "php_getopt.h"
78
78
79
- #define PHP_MODE_STANDARD 1
80
- #define PHP_MODE_HIGHLIGHT 2
81
- #define PHP_MODE_INDENT 3
82
- #define PHP_MODE_LINT 4
83
- #define PHP_MODE_STRIP 5
84
- #define PHP_MODE_CLI_DIRECT 6
79
+ #define PHP_MODE_STANDARD 1
80
+ #define PHP_MODE_HIGHLIGHT 2
81
+ #define PHP_MODE_INDENT 3
82
+ #define PHP_MODE_LINT 4
83
+ #define PHP_MODE_STRIP 5
84
+ #define PHP_MODE_CLI_DIRECT 6
85
+ #define PHP_MODE_PROCESS_STDIN 7
85
86
86
87
extern char * ap_php_optarg ;
87
88
extern int ap_php_optind ;
88
89
89
- #define OPTSTRING "aCc:d:ef:g:hilmnqr :sw?vz:"
90
+ #define OPTSTRING "aB:Cc:d:E:eF:f:g:hilmnqR:r :sw?vz:"
90
91
91
92
static int print_module_info (zend_module_entry * module , void * arg TSRMLS_DC )
92
93
{
@@ -295,9 +296,12 @@ static void php_cli_usage(char *argv0)
295
296
prog = "php" ;
296
297
}
297
298
298
- php_printf ( "Usage: %s [options] [-f] <file> [args...]\n"
299
- " %s [options] -r <code> [args...]\n"
300
- " %s [options] [-- args...]\n"
299
+ php_printf ( "Usage: %s [options] [-f] <file> [--] [args...]\n"
300
+ " %s [options] -r <code> [--] [args...]\n"
301
+ " %s [options] [-B <begin_code>] -R <code> [-E <end_code>] [--] [args...]\n"
302
+ " %s [options] [-B <begin_code>] -F <file> [-E <end_code>] [--] [args...]\n"
303
+ " %s [options] [--] [args...]\n"
304
+ "\n"
301
305
" -a Run interactively\n"
302
306
" -c <path>|<file> Look for php.ini file in this directory\n"
303
307
" -n No php.ini file will be used\n"
@@ -309,14 +313,38 @@ static void php_cli_usage(char *argv0)
309
313
" -l Syntax check only (lint)\n"
310
314
" -m Show compiled in modules\n"
311
315
" -r <code> Run PHP <code> without using script tags <?..?>\n"
316
+ " -B <begin_code> Run PHP <begin_code> before processing input lines\n"
317
+ " -R <code> Run PHP <code> for every input line\n"
318
+ " -F <file> Parse and execute <file> for every input line\n"
319
+ " -E <end_code> Run PHP <end_code> after processing all input lines\n"
312
320
" -s Display colour syntax highlighted source.\n"
313
321
" -v Version number\n"
314
322
" -w Display source with stripped comments and whitespace.\n"
315
323
" -z <file> Load Zend extension <file>.\n"
316
324
"\n"
317
- " args... Arguments passed to script. Use -- args when first argument \n"
325
+ " args... Arguments passed to script. Use -- args when first argument\n"
318
326
" starts with - or script is read from stdin\n"
319
- , prog , prog , prog );
327
+ "\n"
328
+ "The PHP Command Line Interface 'CLI' supports the following operation modes:\n"
329
+ "\n"
330
+ " You can parse and execute files by using parameter -f followed by the\n"
331
+ " name of the file to be executed.\n"
332
+ "\n"
333
+ " Using parameter -r you can directly execute PHP code simply as you would\n"
334
+ " do inside a php file when using the eval() function.\n"
335
+ "\n"
336
+ " It is also possible to process the standard input line by line using either\n"
337
+ " the parameter -R or -F. In this mode each separate input line causes the\n"
338
+ " code specified by -R (see -r) or the file specified by -F to be executed.\n"
339
+ " You can access the input line by $argn. While processing the input lines\n"
340
+ " $argi contains the number of the actual line being processed. Further more\n"
341
+ " the paramters -B and -E can be used to execute code (see -r) before and\n"
342
+ " after input line processing respectively.\n"
343
+ "\n"
344
+ " If none of -r -f -B -R -F and -E is present but a single parameter is given\n"
345
+ " then this parameter is taken as the filename to process (same as with -f)\n"
346
+ " If no parameter is present then the standard input is read and executed.\n"
347
+ , prog , prog , prog , prog , prog );
320
348
}
321
349
/* }}} */
322
350
@@ -397,6 +425,44 @@ static void cli_register_file_handles(TSRMLS_D)
397
425
FREE_ZVAL (zerr );
398
426
}
399
427
428
+ static const char * param_mode_conflict = "Either execute direct code, process stdin or use a file.\n" ;
429
+
430
+ /* {{{ cli_seek_file_begin
431
+ */
432
+ static int cli_seek_file_begin (zend_file_handle * file_handle , char * script_file , int * lineno )
433
+ {
434
+ int c ;
435
+
436
+ * lineno = 1 ;
437
+
438
+ if (!(file_handle -> handle .fp = VCWD_FOPEN (script_file , "rb" ))) {
439
+ SG (headers_sent ) = 1 ;
440
+ SG (request_info ).no_headers = 1 ;
441
+ php_printf ("Could not open input file: %s.\n" , script_file );
442
+ return FAILURE ;
443
+ }
444
+ file_handle -> filename = script_file ;
445
+ /* #!php support */
446
+ c = fgetc (file_handle -> handle .fp );
447
+ if (c == '#' ) {
448
+ while (c != 10 && c != 13 ) {
449
+ c = fgetc (file_handle -> handle .fp ); /* skip to end of line */
450
+ }
451
+ /* handle situations where line is terminated by \r\n */
452
+ if (c == 13 ) {
453
+ if (fgetc (file_handle -> handle .fp ) != 10 ) {
454
+ long pos = ftell (file_handle -> handle .fp );
455
+ fseek (file_handle -> handle .fp , pos - 1 , SEEK_SET );
456
+ }
457
+ }
458
+ * lineno = 2 ;
459
+ } else {
460
+ rewind (file_handle -> handle .fp );
461
+ }
462
+ return SUCCESS ;
463
+ }
464
+ /* }} */
465
+
400
466
/* {{{ main
401
467
*/
402
468
int main (int argc , char * argv [])
@@ -415,8 +481,9 @@ int main(int argc, char *argv[])
415
481
int interactive = 0 ;
416
482
int module_started = 0 ;
417
483
int lineno = 0 ;
418
- char * exec_direct = NULL ;
419
- char * param_error = NULL ;
484
+ char * exec_direct = NULL , * exec_run = NULL , * exec_begin = NULL , * exec_end = NULL ;
485
+ const char * param_error = NULL ;
486
+ int scan_input = 0 ;
420
487
/* end of temporary locals */
421
488
#ifdef ZTS
422
489
zend_compiler_globals * compiler_globals ;
@@ -542,9 +609,27 @@ int main(int argc, char *argv[])
542
609
CG (extended_info ) = 1 ;
543
610
break ;
544
611
612
+ case 'F' :
613
+ if (behavior == PHP_MODE_PROCESS_STDIN ) {
614
+ if (exec_run || script_file ) {
615
+ param_error = "You can use -R or -F only once.\n" ;
616
+ break ;
617
+ }
618
+ } else if (behavior != PHP_MODE_STANDARD ) {
619
+ param_error = param_mode_conflict ;
620
+ break ;
621
+ }
622
+ behavior = PHP_MODE_PROCESS_STDIN ;
623
+ script_file = ap_php_optarg ;
624
+ no_headers = 1 ;
625
+ break ;
626
+
545
627
case 'f' : /* parse file */
546
- if (behavior == PHP_MODE_CLI_DIRECT ) {
547
- param_error = "Either execute direct code or use a file.\n" ;
628
+ if (behavior == PHP_MODE_CLI_DIRECT || behavior == PHP_MODE_PROCESS_STDIN ) {
629
+ param_error = param_mode_conflict ;
630
+ break ;
631
+ } else if (script_file ) {
632
+ param_error = "You can use -f only once.\n" ;
548
633
break ;
549
634
}
550
635
script_file = ap_php_optarg ;
@@ -606,7 +691,7 @@ int main(int argc, char *argv[])
606
691
607
692
#if 0 /* not yet operational, see also below ... */
608
693
case '': /* generate indented source mode*/
609
- if (behavior == PHP_MODE_CLI_DIRECT ) {
694
+ if (behavior == PHP_MODE_CLI_DIRECT || behavior == PHP_MODE_PROCESS_STDIN ) {
610
695
param_error = "Source indenting only works for files.\n" ;
611
696
break ;
612
697
}
@@ -619,16 +704,64 @@ int main(int argc, char *argv[])
619
704
break ;
620
705
621
706
case 'r' : /* run code from command line */
622
- if (behavior != PHP_MODE_STANDARD ) {
623
- param_error = "Either execute direct code or use a file.\n" ;
707
+ if (behavior == PHP_MODE_CLI_DIRECT ) {
708
+ if (exec_direct || script_file ) {
709
+ param_error = "You can use -r only once.\n" ;
710
+ break ;
711
+ }
712
+ } else if (behavior != PHP_MODE_STANDARD ) {
713
+ param_error = param_mode_conflict ;
624
714
break ;
625
715
}
626
716
behavior = PHP_MODE_CLI_DIRECT ;
627
717
exec_direct = ap_php_optarg ;
628
718
break ;
719
+
720
+ case 'R' :
721
+ if (behavior == PHP_MODE_PROCESS_STDIN ) {
722
+ if (exec_run || script_file ) {
723
+ param_error = "You can use -R or -F only once.\n" ;
724
+ break ;
725
+ }
726
+ } else if (behavior != PHP_MODE_STANDARD ) {
727
+ param_error = param_mode_conflict ;
728
+ break ;
729
+ }
730
+ behavior = PHP_MODE_PROCESS_STDIN ;
731
+ exec_run = ap_php_optarg ;
732
+ break ;
733
+
734
+ case 'B' :
735
+ if (behavior == PHP_MODE_PROCESS_STDIN ) {
736
+ if (exec_begin ) {
737
+ param_error = "You can use -B only once.\n" ;
738
+ break ;
739
+ }
740
+ } else if (behavior != PHP_MODE_STANDARD ) {
741
+ param_error = param_mode_conflict ;
742
+ break ;
743
+ }
744
+ behavior = PHP_MODE_PROCESS_STDIN ;
745
+ exec_begin = ap_php_optarg ;
746
+ break ;
747
+
748
+ case 'E' :
749
+ if (behavior == PHP_MODE_PROCESS_STDIN ) {
750
+ if (exec_end ) {
751
+ param_error = "You can use -E only once.\n" ;
752
+ break ;
753
+ }
754
+ } else if (behavior != PHP_MODE_STANDARD ) {
755
+ param_error = param_mode_conflict ;
756
+ break ;
757
+ }
758
+ scan_input = 1 ;
759
+ behavior = PHP_MODE_PROCESS_STDIN ;
760
+ exec_end = ap_php_optarg ;
761
+ break ;
629
762
630
763
case 's' : /* generate highlighted HTML from source */
631
- if (behavior == PHP_MODE_CLI_DIRECT ) {
764
+ if (behavior == PHP_MODE_CLI_DIRECT || behavior == PHP_MODE_PROCESS_STDIN ) {
632
765
param_error = "Source highlighting only works for files.\n" ;
633
766
break ;
634
767
}
@@ -650,7 +783,7 @@ int main(int argc, char *argv[])
650
783
break ;
651
784
652
785
case 'w' :
653
- if (behavior == PHP_MODE_CLI_DIRECT ) {
786
+ if (behavior == PHP_MODE_CLI_DIRECT || behavior == PHP_MODE_PROCESS_STDIN ) {
654
787
param_error = "Source stripping only works for files.\n" ;
655
788
break ;
656
789
}
@@ -676,38 +809,26 @@ int main(int argc, char *argv[])
676
809
CG (interactive ) = interactive ;
677
810
678
811
/* only set script_file if not set already and not in direct mode and not at end of parameter list */
679
- if (argc > ap_php_optind && !script_file && behavior != PHP_MODE_CLI_DIRECT && strcmp (argv [ap_php_optind - 1 ],"--" )) {
812
+ if (argc > ap_php_optind
813
+ && !script_file
814
+ && behavior != PHP_MODE_CLI_DIRECT
815
+ && behavior != PHP_MODE_PROCESS_STDIN
816
+ && strcmp (argv [ap_php_optind - 1 ],"--" ))
817
+ {
680
818
no_headers = 1 ;
681
819
script_file = argv [ap_php_optind ];
682
820
ap_php_optind ++ ;
683
821
}
684
822
if (script_file ) {
685
- if (!(file_handle .handle .fp = VCWD_FOPEN (script_file , "rb" ))) {
686
- SG (headers_sent ) = 1 ;
687
- SG (request_info ).no_headers = 1 ;
688
- php_printf ("Could not open input file: %s.\n" , script_file );
823
+ if (cli_seek_file_begin (& file_handle , script_file , & lineno ) != SUCCESS ) {
689
824
goto err ;
690
825
}
691
- file_handle .filename = script_file ;
692
826
script_filename = script_file ;
693
- /* #!php support */
694
- c = fgetc (file_handle .handle .fp );
695
- if (c == '#' ) {
696
- while (c != 10 && c != 13 ) {
697
- c = fgetc (file_handle .handle .fp ); /* skip to end of line */
698
- }
699
- /* handle situations where line is terminated by \r\n */
700
- if (c == 13 ) {
701
- if (fgetc (file_handle .handle .fp ) != 10 ) {
702
- long pos = ftell (file_handle .handle .fp );
703
- fseek (file_handle .handle .fp , pos - 1 , SEEK_SET );
704
- }
705
- }
706
- lineno = 2 ;
707
- } else {
708
- rewind (file_handle .handle .fp );
709
- }
710
827
} else {
828
+ /* We could handle PHP_MODE_PROCESS_STDIN in a different manner */
829
+ /* here but this would make things only more complicated. And it */
830
+ /* is consitent with the way -R works where the stdin file handle*/
831
+ /* is also accessible. */
711
832
file_handle .filename = "-" ;
712
833
file_handle .handle .fp = stdin ;
713
834
}
@@ -716,7 +837,7 @@ int main(int argc, char *argv[])
716
837
file_handle .free_filename = 0 ;
717
838
php_self = file_handle .filename ;
718
839
719
- /* before registering argv to modulule exchange the *new* argv[0] */
840
+ /* before registering argv to module exchange the *new* argv[0] */
720
841
/* we can achieve this without allocating more memory */
721
842
SG (request_info ).argc = argc - ap_php_optind + 1 ;
722
843
arg_excp = argv + ap_php_optind - 1 ;
@@ -796,6 +917,59 @@ int main(int argc, char *argv[])
796
917
exit_status = 254 ;
797
918
}
798
919
break ;
920
+
921
+ case PHP_MODE_PROCESS_STDIN :
922
+ {
923
+ char input [4096 ];
924
+ size_t len , index = 0 ;
925
+ php_stream_context * sc_in = php_stream_context_alloc ();
926
+ php_stream * s_in = php_stream_open_wrapper_ex ("php://stdin" , "rb" , 0 , NULL , sc_in );
927
+ pval * argn , * argi ;
928
+
929
+ if (exec_begin && zend_eval_string (exec_begin , NULL , "Command line begin code" TSRMLS_CC ) == FAILURE ) {
930
+ exit_status = 254 ;
931
+ }
932
+ ALLOC_ZVAL (argi );
933
+ Z_TYPE_P (argi ) = IS_LONG ;
934
+ Z_LVAL_P (argi ) = index ;
935
+ INIT_PZVAL (argi );
936
+ zend_hash_update (& EG (symbol_table ), "argi" , sizeof ("argi" ), & argi , sizeof (pval * ), NULL );
937
+ while (exit_status == SUCCESS && php_stream_gets (s_in , input , sizeof (input ))) {
938
+ len = strlen (input );
939
+ while (len -- && (input [len ]== '\n' || input [len ]== '\r' )) {
940
+ input [len ] = '\0' ;
941
+ }
942
+ ALLOC_ZVAL (argn );
943
+ Z_TYPE_P (argn ) = IS_STRING ;
944
+ Z_STRLEN_P (argn ) = ++ len ;
945
+ Z_STRVAL_P (argn ) = estrndup (input , len );
946
+ INIT_PZVAL (argn );
947
+ zend_hash_update (& EG (symbol_table ), "argn" , sizeof ("argn" ), & argn , sizeof (pval * ), NULL );
948
+ Z_LVAL_P (argi ) = ++ index ;
949
+ if (exec_run ) {
950
+ if (zend_eval_string (exec_run , NULL , "Command line run code" TSRMLS_CC ) == FAILURE ) {
951
+ exit_status = 254 ;
952
+ }
953
+ } else {
954
+ if (script_file ) {
955
+ if (cli_seek_file_begin (& file_handle , script_file , & lineno ) != SUCCESS ) {
956
+ exit_status = 1 ;
957
+ } else {
958
+ CG (start_lineno ) = lineno ;
959
+ php_execute_script (& file_handle TSRMLS_CC );
960
+ exit_status = EG (exit_status );
961
+ }
962
+ }
963
+ }
964
+ }
965
+ if (exec_end && zend_eval_string (exec_end , NULL , "Command line end code" TSRMLS_CC ) == FAILURE ) {
966
+ exit_status = 254 ;
967
+ }
968
+
969
+ php_stream_close (s_in );
970
+ php_stream_context_free (sc_in );
971
+ break ;
972
+ }
799
973
}
800
974
801
975
if (cli_sapi_module .php_ini_path_override ) {
0 commit comments