mirror of
https://github.com/php/php-src.git
synced 2024-12-13 20:05:26 +08:00
618 lines
16 KiB
C
618 lines
16 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| PHP version 4.0 |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 1997, 1998, 1999, 2000 The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 2.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available at through the world-wide-web at |
|
|
| http://www.php.net/license/2_01.txt. |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
|
|
| Stig Bakken <ssb@fast.no> |
|
|
| Zeev Suraski <zeev@zend.com> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
|
|
#include "php.h"
|
|
#include "php_globals.h"
|
|
#include "php_variables.h"
|
|
|
|
#include "SAPI.h"
|
|
|
|
#include <stdio.h>
|
|
#include "php.h"
|
|
#ifdef PHP_WIN32
|
|
#include "win32/time.h"
|
|
#include "win32/signal.h"
|
|
#include <process.h>
|
|
#else
|
|
#include "build-defs.h"
|
|
#endif
|
|
#if HAVE_SYS_TIME_H
|
|
#include <sys/time.h>
|
|
#endif
|
|
#if HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#if HAVE_SIGNAL_H
|
|
#include <signal.h>
|
|
#endif
|
|
#if HAVE_SETLOCALE
|
|
#include <locale.h>
|
|
#endif
|
|
#include "zend.h"
|
|
#include "php_ini.h"
|
|
#include "php_globals.h"
|
|
#include "main.h"
|
|
#include "fopen-wrappers.h"
|
|
#include "ext/standard/php_standard.h"
|
|
#if WIN32|WINNT
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
#include "win32/syslog.h"
|
|
#include "win32/php_registry.h"
|
|
#else
|
|
#include <syslog.h>
|
|
#endif
|
|
|
|
#include "zend_compile.h"
|
|
#include "zend_execute.h"
|
|
#include "zend_highlight.h"
|
|
#include "zend_indent.h"
|
|
|
|
|
|
#include "php_getopt.h"
|
|
|
|
PHPAPI extern char *php_ini_path;
|
|
|
|
#define PHP_MODE_STANDARD 1
|
|
#define PHP_MODE_HIGHLIGHT 2
|
|
#define PHP_MODE_INDENT 3
|
|
|
|
extern char *ap_php_optarg;
|
|
extern int ap_php_optind;
|
|
|
|
|
|
static int sapi_cgibin_ub_write(const char *str, uint str_length)
|
|
{
|
|
return fwrite(str, 1, str_length, stdout);
|
|
}
|
|
|
|
|
|
static void sapi_cgibin_flush(void *server_context)
|
|
{
|
|
fflush(stdout);
|
|
}
|
|
|
|
|
|
static void sapi_cgi_send_header(sapi_header_struct *sapi_header, void *server_context)
|
|
{
|
|
if (sapi_header) {
|
|
PHPWRITE_H(sapi_header->header, sapi_header->header_len);
|
|
}
|
|
PHPWRITE_H("\r\n", 2);
|
|
}
|
|
|
|
|
|
static int sapi_cgi_read_post(char *buffer, uint count_bytes SLS_DC)
|
|
{
|
|
uint read_bytes=0, tmp_read_bytes;
|
|
|
|
count_bytes = MIN(count_bytes, SG(request_info).content_length-SG(read_post_bytes));
|
|
while (read_bytes < count_bytes) {
|
|
tmp_read_bytes = read(0, buffer+read_bytes, count_bytes-read_bytes);
|
|
if (tmp_read_bytes<=0) {
|
|
break;
|
|
}
|
|
read_bytes += tmp_read_bytes;
|
|
}
|
|
return read_bytes;
|
|
}
|
|
|
|
|
|
static char *sapi_cgi_read_cookies(SLS_D)
|
|
{
|
|
return getenv("HTTP_COOKIE");
|
|
}
|
|
|
|
|
|
static void sapi_cgi_register_variables(zval *track_vars_array ELS_DC SLS_DC PLS_DC)
|
|
{
|
|
char *pi;
|
|
|
|
/* Build the special-case PHP_SELF variable for the CGI version */
|
|
#if FORCE_CGI_REDIRECT
|
|
php_register_variable("PHP_SELF", (SG(request_info).request_uri ? SG(request_info).request_uri:""), track_vars_array ELS_CC PLS_CC);
|
|
#else
|
|
{
|
|
char *sn;
|
|
char *val;
|
|
int l=0;
|
|
|
|
sn = getenv("SCRIPT_NAME");
|
|
pi = SG(request_info).request_uri;
|
|
if (sn)
|
|
l += strlen(sn);
|
|
if (pi)
|
|
l += strlen(pi);
|
|
if (pi && sn && !strcmp(pi, sn)) {
|
|
l -= strlen(pi);
|
|
pi = NULL;
|
|
}
|
|
val = emalloc(l + 1);
|
|
sprintf(val, "%s%s", (sn ? sn : ""), (pi ? pi : "")); /* SAFE */
|
|
php_register_variable("PHP_SELF", val, track_vars_array ELS_CC PLS_CC);
|
|
efree(val);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
static void sapi_cgi_log_message(char *message)
|
|
{
|
|
if (php_header()) {
|
|
fprintf(stderr, message);
|
|
fprintf(stderr, "\n");
|
|
}
|
|
}
|
|
|
|
static int sapi_cgi_deactivate(SLS_D)
|
|
{
|
|
fflush(stdout);
|
|
if(SG(request_info).argv0) {
|
|
free(SG(request_info).argv0);
|
|
SG(request_info).argv0 = NULL;
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
static sapi_module_struct sapi_module = {
|
|
"CGI", /* name */
|
|
|
|
php_module_startup, /* startup */
|
|
php_module_shutdown_wrapper, /* shutdown */
|
|
|
|
NULL, /* activate */
|
|
sapi_cgi_deactivate, /* deactivate */
|
|
|
|
sapi_cgibin_ub_write, /* unbuffered write */
|
|
sapi_cgibin_flush, /* flush */
|
|
NULL, /* get uid */
|
|
NULL, /* getenv */
|
|
|
|
php_error, /* error handler */
|
|
|
|
NULL, /* header handler */
|
|
NULL, /* send headers handler */
|
|
sapi_cgi_send_header, /* send header handler */
|
|
|
|
sapi_cgi_read_post, /* read POST data */
|
|
sapi_cgi_read_cookies, /* read Cookies */
|
|
|
|
sapi_cgi_register_variables, /* register server variables */
|
|
sapi_cgi_log_message, /* Log message */
|
|
|
|
NULL, /* Block interruptions */
|
|
NULL, /* Unblock interruptions */
|
|
|
|
STANDARD_SAPI_MODULE_PROPERTIES
|
|
};
|
|
|
|
|
|
static void php_cgi_usage(char *argv0)
|
|
{
|
|
char *prog;
|
|
|
|
prog = strrchr(argv0, '/');
|
|
if (prog) {
|
|
prog++;
|
|
} else {
|
|
prog = "php";
|
|
}
|
|
|
|
php_printf("Usage: %s [-q] [-h]"
|
|
" [-s]"
|
|
" [-v] [-i] [-f <file>] | "
|
|
"{<file> [args...]}\n"
|
|
" -q Quiet-mode. Suppress HTTP Header output.\n"
|
|
" -s Display colour syntax highlighted source.\n"
|
|
" -f<file> Parse <file>. Implies `-q'\n"
|
|
" -v Version number\n"
|
|
" -c<path> Look for php.ini file in this directory\n"
|
|
#if SUPPORT_INTERACTIVE
|
|
" -a Run interactively\n"
|
|
#endif
|
|
" -d foo[=bar] Define INI entry foo with value 'bar'\n"
|
|
" -e Generate extended information for debugger/profiler\n"
|
|
" -i PHP information\n"
|
|
" -h This help\n", prog);
|
|
}
|
|
|
|
|
|
static void init_request_info(SLS_D)
|
|
{
|
|
char *content_length = getenv("CONTENT_LENGTH");
|
|
char *script_filename;
|
|
|
|
|
|
script_filename = getenv("SCRIPT_FILENAME");
|
|
/* Hack for annoying servers that do not set SCRIPT_FILENAME for us */
|
|
if (!script_filename) {
|
|
script_filename = SG(request_info).argv0;
|
|
}
|
|
#ifdef PHP_WIN32
|
|
/* FIXME WHEN APACHE NT IS FIXED */
|
|
/* a hack for apache nt because it does not appear to set argv[1] and sets
|
|
script filename to php.exe thus makes us parse php.exe instead of file.php
|
|
requires we get the info from path translated. This can be removed at
|
|
such a time taht apache nt is fixed */
|
|
if (script_filename) {
|
|
script_filename = getenv("PATH_TRANSLATED");
|
|
}
|
|
#endif
|
|
|
|
/* doc_root configuration variable is currently ignored,
|
|
as it is with every other access method currently also. */
|
|
|
|
/* We always need to emalloc() filename, since it gets placed into
|
|
the include file hash table, and gets freed with that table.
|
|
Notice that this means that we don't need to efree() it in
|
|
php_destroy_request_info()! */
|
|
#if DISCARD_PATH
|
|
if (script_filename) {
|
|
SLS_FETCH();
|
|
|
|
SG(request_info).path_translated = estrdup(script_filename);
|
|
} else {
|
|
SLS_FETCH();
|
|
|
|
SG(request_info).path_translated = NULL;
|
|
}
|
|
#endif
|
|
|
|
SG(request_info).request_method = getenv("REQUEST_METHOD");
|
|
SG(request_info).query_string = getenv("QUERY_STRING");
|
|
SG(request_info).request_uri = getenv("PATH_INFO");
|
|
SG(request_info).path_translated = NULL; /* we have to update it later, when we have that information */
|
|
SG(request_info).content_type = getenv("CONTENT_TYPE");
|
|
SG(request_info).content_length = (content_length?atoi(content_length):0);
|
|
|
|
/* CGI does not support HTTP authentication */
|
|
SG(request_info).auth_user = NULL;
|
|
SG(request_info).auth_password = NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
static void define_command_line_ini_entry(char *arg)
|
|
{
|
|
char *name, *value;
|
|
|
|
name = arg;
|
|
value = strchr(arg, '=');
|
|
if (value) {
|
|
*value = 0;
|
|
value++;
|
|
} else {
|
|
value = "1";
|
|
}
|
|
php_alter_ini_entry(name, strlen(name), value, strlen(value), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
|
|
}
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int cgi = 0, c, i, len;
|
|
zend_file_handle file_handle;
|
|
char *s;
|
|
/* temporary locals */
|
|
int cgi_started=0;
|
|
int behavior=PHP_MODE_STANDARD;
|
|
int no_headers=0;
|
|
int free_path_translated=0;
|
|
int orig_optind=ap_php_optind;
|
|
char *orig_optarg=ap_php_optarg;
|
|
char *argv0=NULL;
|
|
#if SUPPORT_INTERACTIVE
|
|
int interactive=0;
|
|
#endif
|
|
/* end of temporary locals */
|
|
#ifdef ZTS
|
|
zend_compiler_globals *compiler_globals;
|
|
zend_executor_globals *executor_globals;
|
|
php_core_globals *core_globals;
|
|
sapi_globals_struct *sapi_globals;
|
|
#endif
|
|
|
|
|
|
#ifndef ZTS
|
|
if (setjmp(EG(bailout))!=0) {
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
#ifdef ZTS
|
|
tsrm_startup(1,1,0);
|
|
#endif
|
|
|
|
sapi_startup(&sapi_module);
|
|
|
|
#if WIN32|WINNT
|
|
_fmode = _O_BINARY; /*sets default for file streams to binary */
|
|
setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */
|
|
setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */
|
|
setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
|
|
#endif
|
|
|
|
|
|
/* Make sure we detect we are a cgi - a bit redundancy here,
|
|
but the default case is that we have to check only the first one. */
|
|
if (getenv("SERVER_SOFTWARE")
|
|
|| getenv("SERVER_NAME")
|
|
|| getenv("GATEWAY_INTERFACE")
|
|
|| getenv("REQUEST_METHOD")) {
|
|
cgi = 1;
|
|
if (argc > 1) {
|
|
argv0 = strdup(argv[1]);
|
|
} else {
|
|
argv0 = NULL;
|
|
}
|
|
#if FORCE_CGI_REDIRECT
|
|
if (!getenv("REDIRECT_STATUS")) {
|
|
PUTS("<b>Security Alert!</b> PHP CGI cannot be accessed directly.\n\
|
|
\n\
|
|
<P>This PHP CGI binary was compiled with force-cgi-redirect enabled. This\n\
|
|
means that a page will only be served up if the REDIRECT_STATUS CGI variable is\n\
|
|
set. This variable is set, for example, by Apache's Action directive redirect.\n\
|
|
<P>You may disable this restriction by recompiling the PHP binary with the\n\
|
|
--disable-force-cgi-redirect switch. If you do this and you have your PHP CGI\n\
|
|
binary accessible somewhere in your web tree, people will be able to circumvent\n\
|
|
.htaccess security by loading files through the PHP parser. A good way around\n\
|
|
this is to define doc_root in your php.ini file to something other than your\n\
|
|
top-level DOCUMENT_ROOT. This way you can separate the part of your web space\n\n\
|
|
which uses PHP from the normal part using .htaccess security. If you do not have\n\
|
|
any .htaccess restrictions anywhere on your site you can leave doc_root undefined.\n\
|
|
\n");
|
|
|
|
/* remove that detailed explanation some time */
|
|
|
|
return FAILURE;
|
|
}
|
|
#endif /* FORCE_CGI_REDIRECT */
|
|
}
|
|
|
|
if (!cgi) {
|
|
while ((c=ap_php_getopt(argc, argv, "c:d:qvisnaeh?vf:"))!=-1) {
|
|
switch (c) {
|
|
case 'c':
|
|
php_ini_path = strdup(ap_php_optarg); /* intentional leak */
|
|
break;
|
|
}
|
|
}
|
|
ap_php_optind = orig_optind;
|
|
ap_php_optarg = orig_optarg;
|
|
}
|
|
|
|
|
|
if (php_module_startup(&sapi_module)==FAILURE) {
|
|
return FAILURE;
|
|
}
|
|
#ifdef ZTS
|
|
compiler_globals = ts_resource(compiler_globals_id);
|
|
executor_globals = ts_resource(executor_globals_id);
|
|
core_globals = ts_resource(core_globals_id);
|
|
sapi_globals = ts_resource(sapi_globals_id);
|
|
if (setjmp(EG(bailout))!=0) {
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
init_request_info(SLS_C);
|
|
SG(server_context) = (void *) 1; /* avoid server_context==NULL checks */
|
|
CG(extended_info) = 0;
|
|
|
|
SG(request_info).argv0 = argv0;
|
|
|
|
if (!cgi) { /* never execute the arguments if you are a CGI */
|
|
SG(request_info).argv0 = NULL;
|
|
while ((c = ap_php_getopt(argc, argv, "c:d:qvisnaeh?vf:")) != -1) {
|
|
switch (c) {
|
|
case 'f':
|
|
if (!cgi_started){
|
|
if (php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC)==FAILURE) {
|
|
php_module_shutdown();
|
|
return FAILURE;
|
|
}
|
|
}
|
|
if (no_headers) {
|
|
SG(headers_sent) = 1;
|
|
}
|
|
cgi_started=1;
|
|
SG(request_info).path_translated = estrdup(ap_php_optarg);
|
|
free_path_translated=1;
|
|
/* break missing intentionally */
|
|
case 'q':
|
|
no_headers = 1;
|
|
break;
|
|
case 'v':
|
|
if (!cgi_started) {
|
|
if (php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC)==FAILURE) {
|
|
php_module_shutdown();
|
|
return FAILURE;
|
|
}
|
|
}
|
|
if (no_headers) {
|
|
SG(headers_sent) = 1;
|
|
}
|
|
php_printf("%s\n", PHP_VERSION);
|
|
exit(1);
|
|
break;
|
|
case 'i':
|
|
if (!cgi_started) {
|
|
if (php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC)==FAILURE) {
|
|
php_module_shutdown();
|
|
return FAILURE;
|
|
}
|
|
}
|
|
if (no_headers) {
|
|
SG(headers_sent) = 1;
|
|
}
|
|
cgi_started=1;
|
|
php_print_info(0xFFFFFFFF);
|
|
exit(1);
|
|
break;
|
|
case 's':
|
|
behavior=PHP_MODE_HIGHLIGHT;
|
|
break;
|
|
case 'n':
|
|
behavior=PHP_MODE_INDENT;
|
|
break;
|
|
case 'a':
|
|
#if SUPPORT_INTERACTIVE
|
|
printf("Interactive mode enabled\n\n");
|
|
interactive=1;
|
|
#else
|
|
printf("Interactive mode not supported!\n\n");
|
|
#endif
|
|
break;
|
|
case 'e':
|
|
CG(extended_info) = 1;
|
|
break;
|
|
case 'h':
|
|
case '?':
|
|
php_output_startup();
|
|
SG(headers_sent) = 1;
|
|
php_cgi_usage(argv[0]);
|
|
exit(1);
|
|
break;
|
|
case 'd':
|
|
define_command_line_ini_entry(ap_php_optarg);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
} /* not cgi */
|
|
|
|
#if SUPPORT_INTERACTIVE
|
|
EG(interactive) = interactive;
|
|
#endif
|
|
|
|
if (!cgi_started) {
|
|
if (php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC)==FAILURE) {
|
|
php_module_shutdown();
|
|
return FAILURE;
|
|
}
|
|
}
|
|
if (no_headers) {
|
|
SG(headers_sent) = 1;
|
|
}
|
|
file_handle.filename = "-";
|
|
file_handle.type = ZEND_HANDLE_FP;
|
|
file_handle.handle.fp = stdin;
|
|
|
|
|
|
if (!cgi) {
|
|
if (!SG(request_info).query_string) {
|
|
for (i = ap_php_optind, len = 0; i < argc; i++)
|
|
len += strlen(argv[i]) + 1;
|
|
|
|
s = malloc(len + 1); /* leak - but only for command line version, so ok */
|
|
*s = '\0'; /* we are pretending it came from the environment */
|
|
for (i = ap_php_optind, len = 0; i < argc; i++) {
|
|
strcat(s, argv[i]);
|
|
if (i < (argc - 1))
|
|
strcat(s, "+");
|
|
}
|
|
SG(request_info).query_string = s;
|
|
}
|
|
if (!SG(request_info).path_translated && argc > ap_php_optind)
|
|
SG(request_info).path_translated = argv[ap_php_optind];
|
|
}
|
|
/* If for some reason the CGI interface is not setting the
|
|
PATH_TRANSLATED correctly, SG(request_info).path_translated is NULL.
|
|
We still call php_fopen_primary_script, because if you set doc_root
|
|
or user_dir configuration directives, PATH_INFO is used to construct
|
|
the filename as a side effect of php_fopen_primary_script.
|
|
*/
|
|
if(cgi) {
|
|
SG(request_info).path_translated = getenv("PATH_TRANSLATED");
|
|
}
|
|
if (cgi || SG(request_info).path_translated) {
|
|
file_handle.handle.fp = php_fopen_primary_script();
|
|
file_handle.filename = SG(request_info).path_translated;
|
|
}
|
|
|
|
if (cgi && !file_handle.handle.fp) {
|
|
PUTS("No input file specified.\n");
|
|
#if 0 /* this is here for debuging under windows */
|
|
if (argc) {
|
|
i = 0;
|
|
php_printf("\nargc %d\n",argc);
|
|
while (i <= argc) {
|
|
php_printf("%s\n",argv[i]);
|
|
i++;
|
|
}
|
|
}
|
|
#endif
|
|
php_request_shutdown((void *) 0);
|
|
php_module_shutdown();
|
|
return FAILURE;
|
|
} else if (file_handle.handle.fp && file_handle.handle.fp!=stdin) {
|
|
/* #!php support */
|
|
c = fgetc(file_handle.handle.fp);
|
|
if (c == '#') {
|
|
while (c != 10 && c != 13) {
|
|
c = fgetc(file_handle.handle.fp); /* skip to end of line */
|
|
}
|
|
CG(zend_lineno)++;
|
|
} else {
|
|
rewind(file_handle.handle.fp);
|
|
}
|
|
}
|
|
|
|
file_handle.free_filename = 0;
|
|
switch (behavior) {
|
|
case PHP_MODE_STANDARD:
|
|
php_execute_script(&file_handle CLS_CC ELS_CC PLS_CC);
|
|
break;
|
|
case PHP_MODE_HIGHLIGHT: {
|
|
zend_syntax_highlighter_ini syntax_highlighter_ini;
|
|
|
|
if (open_file_for_scanning(&file_handle CLS_CC)==SUCCESS) {
|
|
php_get_highlight_struct(&syntax_highlighter_ini);
|
|
zend_highlight(&syntax_highlighter_ini);
|
|
fclose(file_handle.handle.fp);
|
|
}
|
|
return 0;
|
|
}
|
|
break;
|
|
case PHP_MODE_INDENT:
|
|
open_file_for_scanning(&file_handle CLS_CC);
|
|
zend_indent();
|
|
fclose(file_handle.handle.fp);
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
php_header(); /* Make sure headers have been sent */
|
|
if (free_path_translated)
|
|
efree(SG(request_info).path_translated);
|
|
php_request_shutdown((void *) 0);
|
|
php_module_shutdown();
|
|
#ifdef ZTS
|
|
tsrm_shutdown();
|
|
#endif
|
|
return SUCCESS;
|
|
}
|
|
|