--- /dev/null
+# Generated automatically from Makefile.in by configure.
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+SHELL = /bin/sh
+
+srcdir = .
+top_srcdir = ../..
+prefix = /usr/local
+exec_prefix = ${prefix}
+
+bindir = ${exec_prefix}/bin
+sbindir = ${exec_prefix}/sbin
+libexecdir = ${exec_prefix}/libexec
+datadir = ${prefix}/share
+sysconfdir = ${prefix}/etc
+sharedstatedir = ${prefix}/com
+localstatedir = ${prefix}/var
+libdir = ${exec_prefix}/lib
+infodir = ${prefix}/info
+mandir = ${prefix}/man
+includedir = ${prefix}/include
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/php
+pkglibdir = $(libdir)/php
+pkgincludedir = $(includedir)/php
+
+top_builddir = ../..
+
+ACLOCAL = aclocal
+AUTOCONF = autoconf
+AUTOMAKE = automake
+AUTOHEADER = autoheader
+
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_FLAG =
+transform = s,x,x,
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = i686-pc-linux-gnu
+host_triplet = i686-pc-linux-gnu
+AMTAR = gtar
+AMTARFLAGS = o
+AS = @AS@
+CC = gcc
+CFLAGS = -g -O2 -g -O2
+DEBUG_CFLAGS = -g
+DLLTOOL = @DLLTOOL@
+EXTRA_LDFLAGS = -avoid-version
+EXTRA_LIBS = -ldl -lgd -lm -lresolv -lnsl -lcrypt -lgdbm -lttf -L/usr/lib/mysql -lmysqlclient -lpam
+EXT_LIBS = db/libphpext_db.a gd/libphpext_gd.a mysql/libphpext_mysql.a pcre/libphpext_pcre.a session/libphpext_session.a standard/libphpext_standard.a
+EXT_LTLIBS = ext/db/libphpext_db.la ext/gd/libphpext_gd.la ext/mysql/libphpext_mysql.la ext/pcre/libphpext_pcre.la ext/session/libphpext_session.la ext/standard/libphpext_standard.la
+EXT_SHARED =
+EXT_STATIC = db gd mysql pcre session standard
+EXT_SUBDIRS = db gd mysql pcre session standard
+HSREGEX =
+INCLUDES = -I$(top_builddir)/libzend -I$(top_srcdir) -I$(top_srcdir)/libzend -I/tmp/dmalloc-pike//pike/0.7.79/include/pike/ -I/usr/include/mysql
+INSTALL_IT = $(SHELL) $(srcdir)/install-sh -m 0755 libs/libphp4.so /tmp/dmalloc-pike//pike/0.7.79/lib/modules/PHP4.so
+LD = /usr/bin/ld
+LEX = flex
+LEX_CFLAGS = -DYY_USE_CONST
+LIBTOOL = $(SHELL) $(top_builddir)/libtool --silent
+LN_S = ln -s
+MAINT = #
+MAKEINFO = makeinfo
+NATIVE_RPATHS = -Wl,-rpath,/usr/lib/mysql
+NM = /usr/bin/nm -B
+OBJDUMP = @OBJDUMP@
+PACKAGE = php
+PERL_PATH = /usr/bin/perl
+PHP_BUILD_DATE = 1999-11-23
+PHP_DEBUG = 1
+PHP_LIBS =
+PHP_PROGRAM =
+PHP_RPATHS = -R /usr/lib/mysql
+PHP_SAPI = roxen
+PHP_VERSION = 4.0b4-dev
+PROG_SENDMAIL = /usr/sbin/sendmail
+RANLIB = ranlib
+REGEX_DIR = regex
+REGEX_LIB = regex/libregex.la
+TSRM_DIR =
+TSRM_LIB =
+VERSION = 4.0b4-dev
+WARNING_LEVEL =
+YACC = bison -y
+abs_builddir = /home/neotron/src/php4
+abs_srcdir = /home/neotron/src/php4
+phplibdir = /home/neotron/src/php4/modules
+phptempdir = /home/neotron/src/php4/libs
+
+
+noinst_LTLIBRARIES = libphpsapi_roxen.la
+libphpsapi_roxen_la_SOURCES = roxen.c
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../../php_config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+
+DEFS = -DHAVE_CONFIG_H -I. -I$(srcdir) -I../..
+CPPFLAGS =
+LDFLAGS =
+LIBS =
+libphpsapi_roxen_la_LDFLAGS =
+libphpsapi_roxen_la_LIBADD =
+am_libphpsapi_roxen_la_OBJECTS = roxen.lo
+libphpsapi_roxen_la_OBJECTS = $(am_libphpsapi_roxen_la_OBJECTS)
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(libphpsapi_roxen_la_SOURCES)
+DIST_COMMON = README Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+SOURCES = $(libphpsapi_roxen_la_SOURCES)
+OBJECTS = $(am_libphpsapi_roxen_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .c .lo .o
+$(srcdir)/Makefile.in: # Makefile.am $(top_srcdir)/$(altdir)configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps sapi/roxen/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLTLIBRARIES:
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+
+distclean-noinstLTLIBRARIES:
+
+maintainer-clean-noinstLTLIBRARIES:
+
+.c.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.c.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+roxen.lo:
+
+libphpsapi_roxen.la: $(libphpsapi_roxen_la_OBJECTS) $(libphpsapi_roxen_la_DEPENDENCIES)
+ $(LINK) $(libphpsapi_roxen_la_LDFLAGS) $(libphpsapi_roxen_la_OBJECTS) $(libphpsapi_roxen_la_LIBADD) $(LIBS)
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = sapi/roxen
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLTLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLTLIBRARIES clean-compile clean-libtool \
+ clean-tags clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLTLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-generic \
+ clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLTLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-generic \
+ distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \
+clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all install-strip \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+/* Roxen PHP module based of the Roxen PHP module for Roxen 1.4. */
+
+#include <roxen.h>
+#include <module.h>
+inherit "module";
+inherit "roxenlib";
+
+constant cvs_version = "$Id$";
+constant thread_safe = 1;
+
+string trim( string what )
+{
+ sscanf(what, "%*[ \t]%s", what);
+ what = reverse(what);
+ sscanf(what, "%*[ \t]%s", what);
+ what = reverse(what);
+ return what;
+}
+//#define PHP_DEBUG
+#ifdef PHP_DEBUG
+#define DWERROR(X) report_debug(X)
+#else /* !PHP_DEBUG */
+#define DWERROR(X)
+#endif /* PHP_DEBUG */
+
+array register_module()
+{
+ return
+ ({
+ MODULE_FILE_EXTENSION | MODULE_PARSER,
+ "PHP Script Support",
+ "This module allows Roxen users to run PHP scripts, optionally in "
+ "combination with RXML. ",
+ });
+}
+
+class PHPScript
+{
+ object interpretor;
+ string command;
+ string buffer="";
+ // stderr is handled by run().
+ mapping (string:string) environment;
+ int blocking, written, close_when_done;
+ object mid;
+ void done() {
+ if(strlen(buffer)) {
+ close_when_done = 1;
+ if(QUERY(rxml)) {
+ buffer = parse_rxml(buffer, mid);
+ write_callback();
+ }
+ } else
+ destruct();
+ }
+
+ void destroy() {
+ mid->do_not_disconnect = 0;
+ // destruct(interpretor);
+ mid->file = ([ "len": written, "raw":1 ]);
+ mid->do_log();
+ }
+ void write_callback()
+ {
+ DWERROR("PHP:Wrapper::write_callback()\n");
+ if(!strlen(buffer))
+ return;
+ // int nelems = tofd->write( buffer );
+ int nelems;
+ array err = catch { nelems = mid->my_fd->write(buffer); };
+ DWERROR(sprintf("PHP:Wrapper::write_callback(): write(%O) => %d\n",
+ buffer, nelems));
+ if( err || nelems < 0 )
+ // if nelems == 0, network buffer is full. We still want to continue.
+ {
+ buffer="";
+ close_when_done = -1;
+ } else {
+ written += nelems;
+ buffer = buffer[nelems..];
+ DWERROR(sprintf("Done: %d %d...\n", strlen(buffer), close_when_done));
+ if(close_when_done && !strlen(buffer)) {
+ destruct();
+ }
+ }
+ }
+
+ int write( string what )
+ {
+ DWERROR(sprintf("PHP:Wrapper::write(%O)\n", what));
+ if(close_when_done == -1) // Remote closed
+ return -1;
+ if(buffer == "" )
+ {
+ buffer = what;
+ if(!QUERY(rxml)) write_callback();
+ } else
+ buffer += what;
+ return strlen(what);
+ }
+
+ void send_headers(int code, mapping headers)
+ {
+ DWERROR(sprintf("PHP:PHPWrapper::send_headers(%d,%O)\n", code, headers));
+ string result = "", post="";
+ string code = mid->errors[code||200];
+ int ct_received = 0, sv_received = 0;
+ if(headers)
+ foreach(indices(headers), string header)
+ {
+ string value = headers[header];
+ if(!header || !value)
+ {
+ // Heavy DWIM. For persons who forget about headers altogether.
+ continue;
+ }
+ header = trim(header);
+ value = trim(value);
+ switch(lower_case( header ))
+ {
+ case "status":
+ code = value;
+ break;
+
+ case "content-type":
+ ct_received=1;
+ result += header+": "+value+"\r\n";
+ break;
+
+ case "server":
+ sv_received=1;
+ result += header+": "+value+"\r\n";
+ break;
+
+ case "location":
+ code = "302 Redirection";
+ result += header+": "+value+"\r\n";
+ break;
+
+ default:
+ result += header+": "+value+"\r\n";
+ break;
+ }
+ }
+ if(!sv_received)
+ result += "Server: "+roxen.version()+"/PHP\r\n";
+ if(!ct_received)
+ result += "Content-Type: text/html\r\n";
+ write("HTTP/1.0 "+code+"\r\n"+result+"\r\n");
+ }
+
+ PHPScript run()
+ {
+ DWERROR("PHP:PHPScript::run()\n");
+ // if( QUERY(rxml) )
+ // stdout = (wrapper = RXMLWrapper( stdout, mid ))->get_fd();
+ mapping options = ([
+ "env":environment,
+ ]);
+ thread_create(interpretor->run, command, options, this_object(), done);
+ mid->my_fd->set_close_callback(done);
+ return this_object();
+ }
+
+
+ void create( object id )
+ {
+ DWERROR("PHP:PHPScript()\n");
+ interpretor = PHP4.Interpretor();
+ mid = id;
+
+#ifndef THREADS
+ if(id->misc->orig) // An <insert file=...> operation, and we have no threads.
+ blocking = 1;
+#else
+ if(id->misc->orig && this_thread() == roxen.backend_thread)
+ blocking = 1;
+ // An <insert file=...> and we are
+ // currently in the backend thread.
+#endif
+ if(!id->realfile)
+ {
+ id->realfile = id->conf->real_file( id->not_query, id );
+ if(!id->realfile)
+ error("No real file associated with "+id->not_query+
+ ", thus it's not possible to run it as a PHP script.\n");
+ }
+ command = id->realfile;
+
+ environment =(QUERY(env)?getenv():([]));
+ environment |= global_env;
+ environment |= build_env_vars( id->realfile, id, id->misc->path_info );
+ environment |= build_roxen_env_vars(id);
+ if(id->misc->ssi_env) environment |= id->misc->ssi_env;
+ if(id->misc->is_redirected) environment["REDIRECT_STATUS"] = "1";
+ if(id->rawauth && QUERY(rawauth))
+ environment["HTTP_AUTHORIZATION"] = (string)id->rawauth;
+ else
+ m_delete(environment, "HTTP_AUTHORIZATION");
+ if(QUERY(clearpass) && id->auth && id->realauth ) {
+ environment["REMOTE_USER"] = (id->realauth/":")[0];
+ environment["REMOTE_PASSWORD"] = (id->realauth/":")[1];
+ } else {
+ m_delete(environment, "REMOTE_PASSWORD");
+ }
+ if (id->rawauth) {
+ environment["AUTH_TYPE"] = (id->rawauth/" ")[0];
+ }
+ // DWERROR(sprintf("%O\n", environment));
+ // ffd = id->my_fd;
+ }
+}
+
+mapping(string:string) global_env = ([]);
+void start(int n, object conf)
+{
+ DWERROR("PHP:start()\n");
+
+ module_dependencies(conf, ({ "pathinfo" }));
+ if(conf)
+ {
+ string tmp=conf->query("MyWorldLocation");
+ sscanf(tmp, "%*s//%s", tmp);
+ sscanf(tmp, "%s:", tmp);
+ sscanf(tmp, "%s/", tmp);
+ global_env["SERVER_NAME"]=tmp;
+ global_env["SERVER_SOFTWARE"]=roxen.version();
+ global_env["GATEWAY_INTERFACE"]="PHP/1.1";
+ global_env["SERVER_PROTOCOL"]="HTTP/1.0";
+ global_env["SERVER_URL"]=conf->query("MyWorldLocation");
+
+ array us = ({0,0});
+ foreach(query("extra_env")/"\n", tmp)
+ if(sscanf(tmp, "%s=%s", us[0], us[1])==2)
+ global_env[us[0]] = us[1];
+ }
+}
+mapping handle_file_extension(object o, string e, object id)
+{
+ DWERROR("PHP:handle_file_extension()\n");
+ id->do_not_disconnect = 1;
+ PHPScript( id )->run();
+ return http_pipe_in_progress();
+}
+/*
+** Variables et. al.
+*/
+array (string) query_file_extensions()
+{
+ return QUERY(ext);
+}
+
+
+void create(object conf)
+{
+ defvar("env", 0, "Pass environment variables", TYPE_FLAG,
+ "If this is set, all environment variables roxen has will be "
+ "passed to PHP scripts, not only those defined in the PHP/1.1 standard. "
+ "This includes PATH. (For a quick test, try this script with "
+ "and without this variable set:"
+ "<pre>"
+ "#!/bin/sh\n\n"
+ "echo Content-type: text/plain\n"
+ "echo ''\n"
+ "env\n"
+ "</pre>)");
+
+ defvar("rxml", 0, "Parse RXML in PHP-scripts", TYPE_FLAG,
+ "If this is set, the output from PHP-scripts handled by this "
+ "module will be RXMl parsed. NOTE: No data will be returned to the "
+ "client until the PHP-script is fully parsed.");
+
+ defvar("extra_env", "", "Extra environment variables", TYPE_TEXT_FIELD,
+ "Extra variables to be sent to the script, format:<pre>"
+ "NAME=value\n"
+ "NAME=value\n"
+ "</pre>Please note that the standard variables will have higher "
+ "priority.");
+
+ defvar("ext",
+ ({"php", "php3", "php4"
+ }), "PHP-script extensions", TYPE_STRING_LIST,
+ "All files ending with these extensions, will be parsed as "+
+ "PHP-scripts.");
+
+ defvar("rawauth", 0, "Raw user info", TYPE_FLAG|VAR_MORE,
+ "If set, the raw, unparsed, user info will be sent to the script, "
+ " in the HTTP_AUTHORIZATION environment variable. This is not "
+ "recommended, but some scripts need it. Please note that this "
+ "will give the scripts access to the password used.");
+
+ defvar("clearpass", 0, "Send decoded password", TYPE_FLAG|VAR_MORE,
+ "If set, the variable REMOTE_PASSWORD will be set to the decoded "
+ "password value.");
+
+ defvar( "cgi_tag", 1, "Provide the <cgi> tag", TYPE_FLAG,
+ "If set, the <cgi> tag will be available" );
+}
+
+int|string tag_cgi( string tag, mapping args, object id )
+{
+ DWERROR("PHP:tag_cgi()\n");
+
+ if(!query("cgi_tag"))
+ return 0;
+
+ if(args->help)
+ return ("<b><"+tag+" script=path [cache=seconds] [default-argument=value] "
+ "[argument=value]>:</b>");
+
+ if(!args->cache)
+ NOCACHE();
+ else
+ CACHE( (int)args->cache || 60 );
+
+
+ object fid = id->clone_me();
+ string file = args->script;
+ if(!file)
+ return "No 'script' argument to the PHP tag";
+ fid->not_query = fix_relative( file, id );
+ foreach(indices(args), string arg )
+ {
+ if(arg == "script")
+ continue;
+ if(arg == "cache")
+ continue;
+ if(arg[..7] == "default-")
+ {
+ if(!id->variables[arg[8..]])
+ fid->variables[arg[8..]] = args[arg];
+ }
+ else
+ fid->variables[arg] = args[arg];
+ }
+ fid->realfile=0;
+ fid->method = "GET";
+ mixed e = catch
+ {
+ string data=handle_file_extension( 0, "cgi", fid )->file->read();
+ if(!sscanf(data, "%*s\r\n\r\n%s", data))
+ sscanf(data, "%*s\n\n%s", data);
+ return data;
+ };
+ return ("Failed to run PHP script: <font color=red><pre>"+
+ (html_encode_string(describe_backtrace(e))/"\n")[0]+
+ "</pre></font>");
+}
+
+
+mapping query_tag_callers()
+{
+ return ([
+ "cgi":tag_cgi,
+ ]);
+}
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.0 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_0.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. |
+ +----------------------------------------------------------------------+
+ | Author: David Hedbor <neotron@php.net> |
+ | Based on aolserver SAPI by Sascha Schumann <sascha@schumann.cx> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include "php.h"
+#ifdef HAVE_ROXEN
+
+#include "php_ini.h"
+#include "php_globals.h"
+#include "SAPI.h"
+#include "main.h"
+
+#include "php_version.h"
+
+/* Pike Include Files
+ *
+ * conflicts with pike avoided by only using long names. Requires a new
+ * Pike 0.7 since it was implemented for this interface only.
+ */
+#define NO_PIKE_SHORTHAND
+
+#ifdef ZTS
+#error Roxen PHP module isnt thread safe at the moment.
+#endif
+
+#include <fdlib.h>
+#include <program.h>
+#include <pike_types.h>
+#include <interpret.h>
+#include <module_support.h>
+#include <error.h>
+#include <array.h>
+#include <backend.h>
+#include <stralloc.h>
+#include <mapping.h>
+#include <object.h>
+#include <threads.h>
+#include <builtin_functions.h>
+#include <operators.h>
+
+#ifdef _REENTRANT
+static PIKE_MUTEX_T roxen_php_execution_lock;
+#define PHP_INIT_LOCK() mt_init(&roxen_php_execution_lock)
+#define PHP_LOCK() fprintf(stderr, "*** php lock.\n");THREADS_ALLOW();mt_lock(&roxen_php_execution_lock);fprintf(stderr, "*** php locked.\n");THREADS_DISALLOW()
+#define PHP_UNLOCK() mt_unlock(&roxen_php_execution_lock);fprintf(stderr, "*** php unlocked.\n");
+#define PHP_DESTROY() mt_destroy(&roxen_php_execution_lock)
+#else /* !_REENTRANT */
+#define PHP_INIT_LOCK()
+#define PHP_LOCK()
+#define PHP_UNLOCK()
+#define PHP_DESTROY()
+#endif /* _REENTRANT */
+
+extern int fd_from_object(struct object *o);
+static unsigned char roxen_php_initialized;
+
+#define REALTHIS ((php_roxen_request *)fp->current_storage)
+#define GET_THIS() current_request = REALTHIS
+#define THIS current_request
+#define MY_FD ((struct object *)(THIS->my_fd))
+#define REQUEST_DATA ((struct mapping *)(THIS->request_data))
+
+#define THREAD_SAFE_RUN(COMMAND, what) do {\
+ struct thread_state *state;\
+ fprintf(stderr,"threads: %d disabled: %d id: %d\n",num_threads, threads_disabled, th_self());\
+ if((state = thread_state_for_id(th_self()))!=NULL) {\
+ if(!state->swapped) {\
+ fprintf(stderr, "MT lock (%s).\n", what);\
+ COMMAND;\
+ } else {\
+ fprintf(stderr, "MT nonlock (%s).\n", what); \
+ mt_lock(&interpreter_lock);\
+ SWAP_IN_THREAD(state);\
+ fprintf(stderr, "MT locked.\n", what); \
+ COMMAND;\
+ fprintf(stderr, "MT locked done.\n", what); \
+ SWAP_OUT_THREAD(state);\
+ mt_unlock(&interpreter_lock);\
+ fprintf(stderr, "MT unlocked.\n", what); \
+ }\
+ }\
+} while(0)
+
+#ifndef MUCH_DEBUG
+void no_fprintf(){}
+#define fprintf no_fprintf
+#endif
+
+/* php_roxen_context is per-server (thus only once at all) */
+
+struct program *php_program;
+
+/* roxen_globals_struct is per-request */
+
+typedef struct {
+ struct mapping *request_data;
+ struct object *my_fd;
+ char *filename;
+} php_roxen_request;
+
+static php_roxen_request *current_request = NULL;
+static int current_thread = -1;
+
+INLINE struct svalue *lookup_header(char *headername)
+{
+ struct svalue *headers, *value;
+ struct pike_string *sind;
+ sind = make_shared_string("env");
+ headers = low_mapping_string_lookup(REQUEST_DATA, sind);
+ free_string(sind);
+ if(!headers || headers->type != PIKE_T_MAPPING) return NULL;
+ sind = make_shared_string(headername);
+ value = low_mapping_string_lookup(headers->u.mapping, sind);
+ free_string(sind);
+ if(!value) return NULL;
+ return value;
+}
+
+/* Lookup a header in the mapping and return the value as a string, or
+ * return the default if it's missing
+ */
+INLINE char *lookup_string_header(char *headername, char *default_value)
+{
+ struct svalue *head;
+ THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
+ if(!head || head->type != PIKE_T_STRING) {
+ fprintf(stderr, "Header lookup for %s: default (%s)\n", headername,
+ default_value);
+ return default_value;
+ }
+ fprintf(stderr, "Header lookup for %s: %s(%d)\n", headername,
+ head->u.string->str, head->u.string->len);
+ return head->u.string->str;
+}
+
+/* Lookup a header in the mapping and return the value as if it's an integer
+ * and otherwise return the default.
+ */
+INLINE int lookup_integer_header(char *headername, int default_value)
+{
+ struct svalue *head;
+ THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
+ if(!head || head->type != PIKE_T_INT) {
+ fprintf(stderr, "Header lookup for %s: default (%d)\n", headername,
+ default_value);
+ return default_value;
+ }
+ fprintf(stderr, "Header lookup for %s: %d \n", headername,
+ head->u.integer);
+ return head->u.integer;
+}
+
+/*
+ * php_roxen_low_ub_write() writes data to the client connection.
+ */
+
+static int
+php_roxen_low_ub_write(const char *str, uint str_length) {
+ int sent_bytes = 0;
+ struct pike_string *to_write;
+ to_write = make_shared_binary_string(str, str_length);
+ push_string(to_write);
+ safe_apply(MY_FD, "write", 1);
+ if(sp[-1].type == PIKE_T_INT)
+ sent_bytes = sp[-1].u.integer;
+ //free_string(to_write);
+ pop_stack();
+ if(sent_bytes != str_length) {
+ /* This means the connection is closed. Dead. Gone. *sniff* */
+ PG(connection_status) = PHP_CONNECTION_ABORTED;
+ zend_bailout();
+ }
+ fprintf(stderr, "low_write done.\n");
+}
+
+/*
+ * php_roxen_sapi_ub_write() calls php_roxen_low_ub_write in a Pike thread
+ * safe manner.
+ */
+
+static int
+php_roxen_sapi_ub_write(const char *str, uint str_length)
+{
+ int sent_bytes = 0;
+ THREAD_SAFE_RUN(sent_bytes = php_roxen_low_ub_write(str, str_length), "write");
+ fprintf(stderr, "write done.\n");
+ return sent_bytes;
+}
+
+/* php_roxen_set_header() sets a header in the header mapping.
+ Set Header
+*/
+static void php_roxen_set_header(char *header_name, char *value, char *p)
+{
+ struct svalue hsval;
+ struct pike_string *hval, *ind, *hind;
+ struct mapping *headermap;
+ struct svalue *s_headermap;
+ hval = make_shared_string(value);
+ ind = make_shared_string(" _headers");
+ hind = make_shared_binary_string(header_name,
+ (int)(p - header_name));
+
+ s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind);
+ if(!s_headermap)
+ {
+ struct svalue mappie;
+ mappie.type = PIKE_T_MAPPING;
+ headermap = allocate_mapping(1);
+ mappie.u.mapping = headermap;
+ mapping_string_insert(REQUEST_DATA, ind, &mappie);
+ free_mapping(headermap);
+ } else
+ headermap = s_headermap->u.mapping;
+
+ hsval.type = PIKE_T_STRING;
+ hsval.u.string = hval;
+ mapping_string_insert(headermap, hind, &hsval);
+
+ fprintf(stderr, "Setting header %s to %s\n", hind->str, value);
+ free_string(hval);
+ free_string(ind);
+ free_string(hind);
+}
+
+/*
+ * php_roxen_sapi_header_handler() sets a HTTP reply header to be
+ * sent to the client.
+ */
+
+static int
+php_roxen_sapi_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers SLS_DC)
+{
+ char *header_name, *header_content;
+ char *p;
+ struct pike_string *hind;
+ header_name = sapi_header->header;
+ header_content = p = strchr(header_name, ':');
+
+ if(!p) return 0;
+ do {
+ header_content++;
+ } while(*header_content == ' ');
+ THREAD_SAFE_RUN(php_roxen_set_header(header_name, header_content, p), "header handler");
+ efree(sapi_header->header);
+ return 1;
+}
+
+/*
+ * php_roxen_sapi_send_headers() flushes the headers to the client.
+ * Called before real content is sent by PHP.
+ */
+
+static int
+php_roxen_low_send_headers(sapi_headers_struct *sapi_headers SLS_DC)
+{
+ struct pike_string *ind;
+ struct svalue *s_headermap;
+ ind = make_shared_string(" _headers");
+ s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind);
+ free_string(ind);
+ fprintf(stderr, "Send Headers (%d)...\n", SG(sapi_headers).http_response_code);
+
+ push_int(SG(sapi_headers).http_response_code);
+ if(s_headermap && s_headermap->type == PIKE_T_MAPPING)
+ ref_push_mapping(s_headermap->u.mapping);
+ else
+ push_int(0);
+ fprintf(stderr, "Send Headers 1 (%d)...\n", SG(sapi_headers).http_response_code);
+ safe_apply(MY_FD, "send_headers", 2);
+ fprintf(stderr, "Send Headers 1 (%d)...\n", SG(sapi_headers).http_response_code);
+ pop_stack();
+ fprintf(stderr, "Send Headers 2 (%d)...\n", SG(sapi_headers).http_response_code);
+
+ /*
+ if(SG(sapi_headers).send_default_content_type) {
+ Ns_ConnSetRequiredHeaders(NSG(conn), "text/html", 0);
+ }
+ Ns_ConnFlushHeaders(NSG(conn), SG(sapi_headers).http_response_code);
+ */
+ return SAPI_HEADER_SENT_SUCCESSFULLY;
+}
+
+static int
+php_roxen_sapi_send_headers(sapi_headers_struct *sapi_headers SLS_DC)
+{
+ THREAD_SAFE_RUN(php_roxen_low_send_headers(sapi_headers SLS_CC), "send headers");
+ return SAPI_HEADER_SENT_SUCCESSFULLY;
+}
+
+/*
+ * php_roxen_sapi_read_post() reads a specified number of bytes from
+ * the client. Used for POST/PUT requests.
+ */
+
+INLINE static int php_roxen_low_read_post(char *buf, uint count_bytes)
+{
+ uint max_read;
+ uint total_read = 0;
+ fprintf(stderr, "read post (%d bytes max)\n", count_bytes);
+
+ push_int(count_bytes);
+ safe_apply(MY_FD, "read_post", 1);
+ if(sp[-1].type == T_STRING) {
+ MEMCPY(buf, sp[-1].u.string->str, total_read = sp[-1].u.string->len);
+ buf[total_read] = '\0';
+ } else
+ total_read = -1;
+ pop_stack();
+ return total_read;
+}
+
+static int
+php_roxen_sapi_read_post(char *buf, uint count_bytes SLS_DC)
+{
+ uint total_read;
+ THREAD_SAFE_RUN(total_read = php_roxen_low_read_post(buf, count_bytes), "read post");
+ return total_read;
+}
+
+/*
+ * php_roxen_sapi_read_cookies() returns the Cookie header from
+ * the HTTP request header
+ */
+
+static char *
+php_roxen_sapi_read_cookies(SLS_D)
+{
+ int i;
+ char *cookies;
+ cookies = lookup_string_header("HTTP_COOKIE", NULL);
+ return cookies;
+}
+
+static void php_info_roxen(ZEND_MODULE_INFO_FUNC_ARGS)
+{
+ char buf[512];
+ // int uptime = Ns_InfoUptime();
+
+ PUTS("<table border=5 width=600>\n");
+ php_info_print_table_row(2, "SAPI module version", "$Id$");
+ /* php_info_print_table_row(2, "Build date", Ns_InfoBuildDate());
+ php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile());
+ php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog());
+ php_info_print_table_row(2, "Installation path", Ns_InfoHomePath());
+ php_info_print_table_row(2, "Hostname of server", Ns_InfoHostname());
+ php_info_print_table_row(2, "Source code label", Ns_InfoLabel());
+ php_info_print_table_row(2, "Server platform", Ns_InfoPlatform());
+ snprintf(buf, 511, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion());
+ php_info_print_table_row(2, "Server version", buf);
+ snprintf(buf, 511, "%d day(s), %02d:%02d:%02d",
+ uptime / 86400,
+ (uptime / 3600) % 24,
+ (uptime / 60) % 60,
+ uptime % 60);
+ php_info_print_table_row(2, "Server uptime", buf);
+ */
+ PUTS("</table>");
+}
+
+static zend_module_entry php_roxen_module = {
+ "Roxen",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ php_info_roxen,
+ STANDARD_MODULE_PROPERTIES
+};
+
+static int php_roxen_startup(sapi_module_struct *sapi_module)
+{
+ if(php_module_startup(sapi_module) == FAILURE
+ || zend_register_module(&php_roxen_module) == FAILURE) {
+ return FAILURE;
+ } else {
+ return SUCCESS;
+ }
+}
+
+/* this structure is static (as in "it does not change") */
+
+void pike_module_exit(void);
+
+static sapi_module_struct sapi_module = {
+ "PHP Language",
+
+ php_module_startup, /* startup */
+ pike_module_exit, /* shutdown */
+
+ php_roxen_sapi_ub_write, /* unbuffered write */
+
+ php_error, /* error handler */
+
+ php_roxen_sapi_header_handler, /* header handler */
+ php_roxen_sapi_send_headers, /* send headers handler */
+ NULL, /* send header handler */
+
+ php_roxen_sapi_read_post, /* read POST data */
+ php_roxen_sapi_read_cookies, /* read Cookies */
+
+ STANDARD_SAPI_MODULE_PROPERTIES
+};
+
+/*
+ * php_roxen_hash_environment() populates the php script environment
+ * with a number of variables. HTTP_* variables are created for
+ * the HTTP header data, so that a script can access these.
+ */
+#define ADD_STRING(name) \
+ MAKE_STD_ZVAL(pval); \
+ pval->type = IS_STRING; \
+ pval->value.str.len = strlen(buf); \
+ pval->value.str.val = estrndup(buf, pval->value.str.len); \
+ zend_hash_update(&EG(symbol_table), name, sizeof(name), \
+ &pval, sizeof(zval *), NULL)
+
+static void
+php_roxen_hash_environment(CLS_D ELS_DC PLS_DC SLS_DC)
+{
+ int i;
+ char buf[512];
+ zval *pval;
+ struct svalue *headers;
+ struct pike_string *sind;
+ struct array *indices;
+ struct svalue *ind, *val;
+ sind = make_shared_string("env");
+ headers = low_mapping_string_lookup(REQUEST_DATA, sind);
+ free_string(sind);
+ if(headers && headers->type == PIKE_T_MAPPING) {
+ indices = mapping_indices(headers->u.mapping);
+ for(i = 0; i < indices->size; i++) {
+ ind = &indices->item[i];
+ val = low_mapping_lookup(headers->u.mapping, ind);
+ if(ind && ind->type == PIKE_T_STRING &&
+ val && val->type == PIKE_T_STRING) {
+ char *p;
+ char c;
+ int buf_len;
+ buf_len = MIN(511, ind->u.string->len);
+ strncpy(buf, ind->u.string->str, buf_len);
+ buf[buf_len] = '\0'; /* Terminate correctly */
+ MAKE_STD_ZVAL(pval);
+ pval->type = IS_STRING;
+ pval->value.str.len = val->u.string->len;
+ pval->value.str.val = estrndup(val->u.string->str, pval->value.str.len);
+ /* fprintf(stderr, "Header: %s(%d)=%s\n", buf, buf_len, val->u.string->str);*/
+
+ zend_hash_update(&EG(symbol_table), buf, buf_len + 1, &pval, sizeof(zval *), NULL);
+ }
+ }
+ free_array(indices);
+ }
+
+ // MAKE_STD_ZVAL(pval);
+ // pval->type = IS_LONG;
+ // pval->value.lval = Ns_InfoBootTime();
+ // zend_hash_update(&EG(symbol_table), "SERVER_BOOTTIME", sizeof("SERVER_BOOTTIME"), &pval, sizeof(zval *), NULL);
+
+ // fprintf(stderr, "Set up header environment.\n");
+}
+
+/*
+ * php_roxen_module_main() is called by the per-request handler and
+ * "executes" the script
+ */
+
+int php_roxen_module_main(SLS_D)
+{
+ zend_file_handle file_handle;
+ file_handle.type = ZEND_HANDLE_FILENAME;
+ file_handle.filename = THIS->filename;
+ if(php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC) == FAILURE) {
+ return 0;
+ }
+ php_roxen_hash_environment(CLS_C ELS_CC PLS_CC SLS_CC);
+ THREADS_ALLOW();
+ php_execute_script(&file_handle CLS_CC ELS_CC PLS_CC);
+ php_request_shutdown(NULL);
+ THREADS_DISALLOW();
+ return 1;
+}
+
+/*
+ * php_roxen_request_ctor() initializes the per-request data structure
+ * and fills it with data provided by the web server
+ */
+
+static void
+php_roxen_request_ctor(SLS_D)
+{
+ char *server;
+ char *root;
+ int index;
+ char *tmp;
+
+ SG(request_info).auth_user = NULL;
+ SG(request_info).auth_password = NULL;
+ /*
+ tmp = Ns_ConnAuthPasswd(NSG(conn));
+ if(tmp) {
+ tmp = estrdup(tmp);
+ }
+ SG(request_info).auth_password = tmp;
+
+ NSG(data_avail) = SG(request_info).content_length;
+ */
+}
+
+/*
+ * php_roxen_request_dtor() destroys all data associated with
+ * the per-request structure
+ */
+
+static void
+php_roxen_request_dtor(SLS_D)
+{
+ // free(SG(request_info).path_translated);
+}
+
+/*
+ * The php_roxen_request_handler() is called per request and handles
+ * everything for one request.
+ */
+
+void f_php_roxen_request_handler(INT32 args)
+{
+ struct object *my_fd;
+ struct mapping *request_data;
+ struct svalue *done_callback;
+ struct pike_string *script;
+ int opened_fd = 1, status = 1;
+ int f = 0;
+
+ if(current_thread == th_self())
+ error("PHP4.Interpetor->run: Tried to run a PHP-script from a PHP "
+ "callback!");
+ SLS_FETCH();
+ get_all_args("PHP4.Interpretor->run", args, "%S%m%O%*", &script,
+ &request_data, &my_fd, &done_callback);
+ REALTHIS->request_data = request_data;
+ REALTHIS->my_fd = my_fd;
+ REALTHIS->filename = script->str;
+ if(done_callback->type != PIKE_T_FUNCTION)
+ error("PHP4.Interpretor->run: Bad argument 4, expected function.\n");
+ PHP_LOCK();
+ current_thread = th_self();
+ GET_THIS();
+ SG(request_info).query_string = lookup_string_header("QUERY_STRING", 0);;
+ SG(server_context) = (void *)1; // avoid server_context == NULL
+ /* path_translated is the absolute path to the file */
+ SG(request_info).path_translated =
+ lookup_string_header("PATH_TRANSLATED", NULL);
+ SG(request_info).request_uri = lookup_string_header("DOCUMENT_URI", NULL);
+ if(!SG(request_info).request_uri)
+ SG(request_info).request_uri = lookup_string_header("SCRIPT_NAME", NULL);
+ SG(request_info).request_method = lookup_string_header("REQUEST_METHOD", "GET");
+ SG(request_info).content_length = lookup_integer_header("CONTENT_LENGTH", 0);
+ SG(request_info).content_type = "text/html";
+ SG(request_info).auth_user = NULL;
+ SG(request_info).auth_password = NULL;
+ status = php_roxen_module_main(SLS_C);
+
+ php_roxen_request_dtor(SLS_C);
+ current_thread = -1;
+ PHP_UNLOCK();
+
+ apply_svalue(done_callback, 0);
+ pop_stack();
+ pop_n_elems(args);
+ push_int(status);
+
+}
+
+void clear_struct(struct object *o)
+{
+ MEMSET(fp->current_storage, 0, sizeof(php_roxen_request));
+}
+
+/*
+ * pike_module_init() is called by Pike once at startup
+ *
+ * This functions allocates basic structures
+ */
+
+void pike_module_init()
+{
+ if (!roxen_php_initialized) {
+ sapi_startup(&sapi_module);
+ sapi_module.startup(&sapi_module);
+ roxen_php_initialized = 1;
+ PHP_INIT_LOCK();
+ }
+ start_new_program(); /* Text */
+ ADD_STORAGE(php_roxen_request);
+ set_init_callback(clear_struct);
+ pike_add_function("run", f_php_roxen_request_handler,
+ "function(string,mapping,object,function:int)", 0);
+ add_program_constant("Interpretor", (php_program = end_program()), 0);
+
+ /* TSRM is used to allocate a per-thread structure */
+ /* read the configuration */
+ //php_roxen_config(ctx);
+
+}
+
+/*
+ * pike_module_exit() performs the last steps before the
+ * server exists. Shutdowns basic services and frees memory
+ */
+
+void pike_module_exit(void)
+{
+ roxen_php_initialized = 0;
+ sapi_module.shutdown(&sapi_module);
+ if(php_program) free_program(php_program);
+ PHP_DESTROY();
+}
+#endif