XSLHandler.php
This file (via modrewrite or a custom 404) handles all incoming requests to this website.
It finds an XSL file under the /easyethical folder that can satisfy the request and
matches it up with a database stored procedure of the same name that returns the required
XML.
<?
/*
Architecturally this file mimicks WebServer functionality
modrewrite based PostGRES -> XML -> XSL loader system
the request_uri is encoded and translated into a DB call for XML data and an XSL file to translate it
every XSL file has a ppp_* SPROC with the same name (including directories) which returns the required XML
for example: a request URI of /example/search?term=harrods translates to
get the XML data from ppp_example_search($sessionid, $schema, $version, $term, ...)
get the XSL translation stylesheet from /basesite/example/search.xsl
$sessionid is the PHP session id (sessions are created, stored and deleted by the database)
$schema is the type of XML schema required (can be controlled with ?schema=<schema name>)
$version is always 1
.htaccess using Apache mod_rewrite (required):
RewriteEngine on
# if the request is for a file or directory that exists already on the server, index.php isn't served.
# equivalent of using the 404
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# [L] = last, do not apply any more Rewrite rules
RewriteRule . /XSLHandler.php [L]
Failover for opening the XSL transform file
/companies/harrods?schema=minimal
try to open /basesite/companies/harrods as a directory (fail)
try to open /basesite/companies/harrods/index.xsl if was a directory
try to open /basesite/companies/harrods.xsl (fail)
try to open /basesite/companies/all.xsl?term=harrods&schema=minimal
System can return special XML indicators to the XSL:
<root><noproc></root> means that the ppp_* DB procedure was not found (non dynamic pages)
<root><noxml></root> means that the ppp_* DB procedure returned null or zero string (can happen with invalid ids for objects in the DB)
*/
//system wide implementation specific variables like development mode
ini_set('include_path', ini_get('include_path') . ':' . dirname(__FILE__) . '/includes/pear' . ':' . dirname(__FILE__) . '/includes');
require("define.php");
date_default_timezone_set('UTC');
//these are external required dependencies
//part of the functionality of this loader system
require_once('includes/phpsniff/phpSniff.class.php');
require_once('includes/email.php');
require_once('includes/recaptchalib.php'); //http://recaptcha.net/plugins/php/ (anewholm/fryace4)
require_once('includes/flickr/functions.php');
//these XML namespaces are built into and required by the system
define('NAMESPACE_DIRECTIVES', 'http://www.xsearchservices.com/namespaces/directives');
define('NAMESPACE_SENDMAIL', 'http://www.xsearchservices.com/namespaces/sendmail');
define('NAMESPACE_RSS', 'http://www.xsearchservices.com/namespaces/rss');
define('NAMESPACE_KML', 'http://earth.google.com/kml/2.0');
define('XML_DECL', "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
//base header and session setup
header("Pragma: no-cache", true);
header('Content-type: text/html; charset=utf-8'); //default content-type (changed below sometimes)
//------------------------------------------- inputs ---------------------------------------------------
//GoogleBot useragents
// * Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
// * Googlebot/2.1 (+http://www.googlebot.com/bot.html)
// * Googlebot/2.1 (+http://www.google.com/bot.html)
$client = & new phpSniff();
$is_googlebot = preg_match('/googlebot/i', $client->property('ua'));
$uri_request = utf8_encode(urldecode($_SERVER['REQUEST_URI'])); //can include utf-8 characters (e.g. Nestlé)
$remote_addr = $_SERVER["REMOTE_ADDR"];
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$referer = $_SERVER['HTTP_REFERER'];
$domain = $_SERVER['HTTP_HOST'];
$domainstem = domainstem($domain); //e.g. carrotmobuk instead of www.carrotmobuk.org
$thisdir = dirname(__FILE__);
$version = 1;
$schema = 'standard';
$clientXSLT = false;
$debug = '';
session_start();
$session = session_id();
//work on a directory array so that we can pop and shift easily
$uri_parts = explode('?', $uri_request);
$uri_path = str_replace('//', '/', strtolower($uri_parts[0]));
$uri_query = $uri_parts[1];
$args = array();
$argso = array();
//------------------------------------------- virtual hosts ---------------------------------------------------
//virtual hosts setup the recaptcha keys, site root directory and any site dependent variables
//beyond this system
$virtualhostfile = "$thisdir/virtualhosts/$domainstem.php";
if (is_file($virtualhostfile)) include($virtualhostfile);
if (!$siteroot ) $siteroot = $domainstem;
if (!$procprefix) $procprefix = $siteroot.'_'; //network/site/mySite -> ppp_network_site_mySite_*
//------------------------------------------- db connection ---------------------------------------------------
//can be defined in the virtual host file
if (defined('LINK_BASE')) $link_base = LINK_BASE;
if (defined('RESOURCE_BASE')) $resource_base = RESOURCE_BASE;
if (defined('DBHOST')) $dbhost = DBHOST;
if (defined('DBNAME')) $dbname = DBNAME;
if (defined('DBUSER')) $dbuser = DBUSER;
if (defined('DBPWD')) $password = DBPWD;
//query string overrides
if ($_GET['DBHOST']) $dbhost = $_GET['DBHOST'];
if ($_GET['DBNAME']) $dbname = $_GET['DBNAME'];
if ($_GET['DBUSER']) $dbuser = $_GET['DBUSER'];
if ($_GET['DBPWD']) $password = $_GET['DBPWD'];
//------------------------------------------- administrator monitoring ---------------------------------------------------
if (GOOGLED_EMAILS && $is_googlebot && $uri_path == '/') sendEmail('annesley.newholm@gmail.com', 'admin@xsearchservices.com', 'Googled:'.$domainstem, $user_agent, $user_agent);
if (LOG404) $log = fopen('404log.txt', 'a');
log404("-------------------------------- $uri_path\n");
//debug
if (DEBUG) {
$debug .= "################## defines\n";
$debug .= "DEVSERVER: ".DEVSERVER."\n";
$debug .= "DEBUG: ".DEBUG."\n";
$debug .= "LOG404: ".LOG404."\n";
$debug .= "FORCE_SERVER_XSLT: ".FORCE_SERVER_XSLT."\n";
$debug .= "DBHOST: $dbhost\n";
$debug .= "DBNAME: $dbname\n";
$debug .= "DBUSER: $dbuser\n";
$debug .= "################## php.ini\n";
$debug .= "magic_quotes_gpc: ".ini_get('magic_quotes_gpc')."\n"; //handled manually by the DB engine
$debug .= "################## inputs\n";
if (is_file("$siteroot/define.php")) $debug .= "(using site specific define)\n";
foreach($HTTP_POST_VARS as $k => $v) $debug .= "POST: $k=$v\n";
$debug .= "uri_request: $uri_request\n";
$debug .= "user_agent: $user_agent\n";
$debug .= "domainstem: $domainstem\n";
$debug .= "thisdir: $thisdir\n";
$debug .= "virtualhostfile: $virtualhostfile\n";
$debug .= "siteroot: $siteroot (".is_dir($siteroot).")\n";
$debug .= "procprefix: $procprefix\n";
$debug .= "################## path\n";
$debug .= "uri_path: $uri_path\n";
$debug .= "uri_query: $uri_query\n";
$debug .= "link_base: $link_base\n";
$debug .= "resource_base: $resource_base\n";
}
//------------------------------------------- find directives in URI ---------------------------------------------------
$dirs = explode('/', $uri_path);
array_shift($dirs); //remove initial /
if ($dirs[count($dirs) - 1] == '') array_pop($dirs); //remove trailing / if there
//format requests (.json)
//must always be on the last part of the url
$dir_last = array_pop($dirs);
$file_parts = explode('.', $dir_last);
if (count($file_parts) > 1) $extension = array_pop($file_parts);
array_push($dirs, implode($file_parts));
//directives
$dir_first = $dirs[0];
$dir_second = $dirs[1];
$api_mode = ($dir_first == 'api');
$has_directive = ($api_mode); //for more directives
if ($has_directive) array_shift($dirs); //remove initial element
//------------------------------------------- find files or directories ---------------------------------------------------
//we do not care if uri looks like a file or a directory
//just check to see which it is
$localpath = "$thisdir/$siteroot/".implode('/', $dirs);
$localxsl = "$localpath.xsl";
$havefile = is_file($localxsl);
//look for index files and all files
if ($havefile) {
$filename = array_pop($dirs);
$localpath = "$thisdir/$siteroot/".implode('/', $dirs).'/';
} else {
$is_dir = is_dir($localpath);
if ($is_dir) {
//uri points directly to an existing directory
//may need to redirect to place a / on the end if there is not one
//otherwise relative links will not work
//not using relative links in this site
/*
if ($uri_path... == '') {
header("Location: $localpath/", true);
header("HTTP/1.1 302 Moved", true, 302);
exit();
};
*/
$localpath = "$localpath/";
$localxsl = $localpath.'index.xsl';
$filename = 'index';
$havefile = is_file($localxsl);
} else {
//not a valid xsl file or directory
//pop the last part and send it as a parameter
$directive_last = array_pop($dirs);
array_unshift($args, $directive_last);
$localpath = "$thisdir/$siteroot/".implode('/', $dirs).'/';
$localxsl = $localpath.'all.xsl';
$filename = 'all';
$havefile = is_file($localxsl);
}
}
//debug
if (DEBUG) {
$debug .= "################## inputs\n";
$debug .= "api_mode: $api_mode\n";
$debug .= "localpath: $localpath\n";
$debug .= "filename: $filename\n";
$debug .= "localxsl: $localxsl\n";
$debug .= "localphp: $localphp\n";
$debug .= "extension: $extension\n";
$debug .= 'havefile: '.($havefile?'true':'false')."\n";
$debug .= "dir_first: $dir_first\n";
$debug .= "dir_second: $dir_second\n";
$debug .= "directive_last: $directive_last\n";
$debug .= "uri_xslpath: $uri_xslpath\n";
}
//------------------------------------------- xsl file directives ---------------------------------------------------
//our xsl files can contain more language constructs that control the server
//load the found xsl file here because it may contain special directives
//these directives should all be in the http://www.xsearchservices.com/namespaces/directives namespace
//MIMEType: set an alternate MIMEType for this standard transform
//transform: server or auto
//proc: procedure name (ppp_*), none or auto
//schema: comma delimited controls for turning off parts of the XML to wrap around the proc response:
// noparams, noclient, noextinfo, nopathinfo, baresession, barexml, etc.
//sendmail: parse - instruction to parse the resultant XML for diretives to send an email
//porder: explicitly state the order of the parameters
//jsdocwrite: page uses document.write during parse (not compatible with FF client XSLT)
//setcookies: which cookies to query and provide as parameters and in the XML
//getcookies: which cookies to set
//referal: do not include this page in the last referer list (take the one from the session)
//link_base: the base domain for all a hrefs
//resource_base: the base for all resources (using a base tag)
//compatability: uses different file according to certain named condition sets like 'notIE6'
//redirect: immediate redirect to another page (no show)
//execute: execute another xsl file instead (server.execute)
$xslDoc = new DOMDocument('1.0', 'utf-8'); //some of the plugins check the XSL file for directives
if ($havefile) {
$xslDoc->load($localxsl);
$xsldir_startpoint = $xslDoc;
$xsldir_block = $xslDoc->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'block');
if ($xsldir_block->length) $xsldir_startpoint = $xsldir_block->item(0);
if (!($xsldir_mimetype = $_GET['dir:MIMEType'])) $xsldir_mimetype = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'MIMEType' ));
if (!($xsldir_transform = $_GET['dir:transform'])) $xsldir_transform = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'transform' ));
if (!($xsldir_proc = $_GET['dir:proc'])) $xsldir_proc = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'proc' ));
if (!($xsldir_schema = $_GET['dir:schema'])) $xsldir_schema = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'schema' ));
if (!($xsldir_sendmail = $_GET['dir:sendmail'])) $xsldir_sendmail = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'sendmail' ));
if (!($xsldir_porder = $_GET['dir:porder'])) $xsldir_porder = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'porder' ));
if (!($xsldir_jsdocwrite = $_GET['dir:jsdocwrite'])) $xsldir_jsdocwrite = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'jsdocwrite'));
if (!($xsldir_getcookies = $_GET['dir:getcookies'])) $xsldir_getcookies = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'getcookies'));
if (!($xsldir_setcookies = $_GET['dir:setcookies'])) $xsldir_setcookies = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'setcookies'));
if (!($xsldir_referal = $_GET['dir:referal'])) $xsldir_referal = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'referal'));
if (!($xsldir_link_base = $_GET['dir:link_base'])) $xsldir_link_base = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'link_base'));
if ($xsldir_link_base) $link_base = $xsldir_link_base;
if (!($xsldir_resource_base = $_GET['dir:resource_base'])) $xsldir_resource_base = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'resource_base'));
if ($xsldir_resource_base) $resource_base = $xsldir_resource_base;
if (!($xsldir_compatability = $_GET['dir:compatability'])) $xsldir_compatability = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'compatability'));
if (!($xsldir_redirect = $_GET['dir:redirect'])) $xsldir_redirect = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'redirect'));
if (!($xsldir_execute = $_GET['dir:execute'])) $xsldir_execute = firstitemtext($xsldir_startpoint->getElementsByTagNameNS(NAMESPACE_DIRECTIVES, 'execute'));
if (DEBUG) {
$debug .= "################## directives\n";
if ($xsldir_block->length) $debug .= "(USING dir:block)\n";
$debug .= "forceMIMEType: $forceMIMEType\n";
$debug .= "xsldir_mimetype: $xsldir_mimetype\n";
$debug .= "xsldir_transform: $xsldir_transform\n";
$debug .= "xsldir_proc: $xsldir_proc\n";
$debug .= "xsldir_schema: $xsldir_schema\n";
$debug .= "xsldir_sendmail: $xsldir_sendmail\n";
$debug .= "xsldir_porder: $xsldir_porder\n";
$debug .= "xsldir_jsdocwrite: $xsldir_jsdocwrite\n";
$debug .= "xsldir_getcookies: $xsldir_getcookies\n";
$debug .= "xsldir_setcookies: $xsldir_setcookies\n";
$debug .= "xsldir_referal: $xsldir_referal\n";
$debug .= "xsldir_link_base: $xsldir_link_base\n";
$debug .= "xsldir_resource_base: $xsldir_resource_base\n";
$debug .= "xsldir_compatability: $xsldir_compatability\n";
$debug .= "xsldir_redirect: $xsldir_redirect\n";
$debug .= "xsldir_execute: $xsldir_execute\n";
}
}
//------------------------------------------- execute ---------------------------------------------------
//load other file
if ($xsldir_execute) {
$dirs = explode('/', $xsldir_execute);
$filename = array_pop($dirs);
$localpath = "$thisdir/$siteroot/".implode('/', $dirs).'/';
$localxsl = "$localpath$filename.xsl";
$havefile = is_file($localxsl);
if ($havefile) $xslDoc->load($localxsl);
$debug .= "################ xsldir_execute:\n";
$debug .= "filename: $filename\n";
$debug .= "localpath: $localpath\n";
$debug .= "localxsl: $localxsl\n";
$debug .= 'havefile: '.($havefile?'true':'false')."\n";
$debug .= "\n";
}
//------------------------------------------- redirect ---------------------------------------------------
//directly return a 302 - resource moved
if ($xsldir_redirect) {
header("HTTP/1.1 302 Moved", true, 302);
header("Location: $xsldir_redirect", true);
exit();
}
//------------------------------------------- referer re-process ---------------------------------------------------
$referer = $_SESSION['referer'];
if ($xsldir_referal != 'exclude') $_SESSION['referer'] = $uri_request;
//------------------------------------------- browser compatability ---------------------------------------------------
if ($xsldir_compatability == 'notIE6' && $client->property('browser') == 'ie' and $client->property('maj_ver') == 6) {
$filename = $xsldir_compatability;
$localpath = "$thisdir/$siteroot/".implode('/', $dirs).'/';
$localxsl = "$localpath$xsldir_compatability.xsl";
$havefile = is_file($localxsl);
if ($havefile) $xslDoc->load($localxsl);
}
//------------------------------------------- query args ---------------------------------------------------
//done here because the ordering may be affected by the directives
//system uses POST *or* GET. There are extra GET options to control the system
//the order of arguments is important for the procedure
//note that $_GET is lost because the origonal query is held in $_SERVER[REQUEST_URI]
//we need to ignore the PHPSESSID that can be added automatically to pass session in some PHP setups
$queryargs = explode('&', $uri_query);
if ($xsldir_porder) {
//a specific ordering and/or selection has been requested
//comma delimited form names
$ordering = explode(',', $xsldir_porder);
foreach($ordering as $key) {
$key = trim($key);
$value = $_POST[$key];
if (is_array($value)) $value = implode(',', $value);
array_push($args, $value);
$argso[$key] = $value;
}
} else {
foreach($_POST as $key => $value) {
if (is_array($value)) $value = implode(',', $value); //PHP auto-creates arrays for field[] names
if ($key != 'PHPSESSID') {
array_push($args, $value);
$argso[$key] = $value;
}
}
foreach($queryargs as $nv) {
$nva = explode('=', $nv);
if (count($nva) == 2) {
$key = $nva[0];
$value = $nva[1];
if ($key != 'PHPSESSID') {
array_push($args, $value);
$argso[$key] = $value;
}
}
}
}
$submission = $argso['submit'];
$customxml = '';
$headxml = '';
$cookiexml = '';
$xml = '<root/>';
$statuses = '';
//------------------------------------------- cookies (XSL directives) ---------------------------------------------------
if ($xsldir_getcookies) {
$cookiexml = '<cookies>';
foreach(explode(',', $xsldir_getcookies) as $name) {
$value = $_COOKIE[$name];
$name_esc = escapeForElementName($name);
$cookiexml .= "<$name_esc><![CDATA[".escapeForCDATA($value)."]]></$name_esc>";
array_push($args, $value);
$argso[$name] = $value;
$debug .= "got [$name] cookie = [$value]\n";
}
$cookiexml .= '</cookies>';
}
if ($xsldir_setcookies) {
foreach(explode(',', $xsldir_setcookies) as $key) {
$namevalue = explode('=', $key);
$name = $namevalue[0];
$value = $namevalue[1];
$debug .= "setting [$name] cookie to [$value]\n";
if (!setcookie($name, $value)) $debug .= '*** FAILED ***';
}
}
//------------------------------------------- plugins pre ---------------------------------------------------
//all connections are the same: use one persistent connection
if ($dbhost && $dbname)
$conn = pg_connect("host=$dbhost dbname=$dbname user=$dbuser password=$password");
require_once('includes/404plugins/404plugins_pre.php');
//------------------------------------------- 404 handling ---------------------------------------------------
//note that the plugins may change $havefile and $proc in order to use a special XSL and PROC, e.g. CMS
if (!$havefile) {
if (is_dir($siteroot)) {
//look for 404 handlers
header("HTTP/1.1 404 Not Found", true, 404);
if (is_file("$siteroot/404.xsl")) {
$havefile = true;
$filename = '404';
$dirs = array();
$xslDoc->load("$siteroot/404.xsl");
} else {
if (is_file('404.html')) print(file_get_contents('404.html'));
else print('Page Not Found (404)');
}
} else {
//the actual site root is not found, thus is an invalid sub-domain
header("HTTP/1.1 404 Not Found", true, 404);
if (is_file("nosite.html")) {
print(file_get_contents('nosite.html'));
} else print('Website Not Found (404)');
}
}
//------------------------------------------- data retrieval ---------------------------------------------------
if ($havefile && $conn) {
//------------------------------------------- call proc in DB ---------------------------------------------------
//construct proc name, connect and query
$user_agent_esc = pg_escape_string($user_agent);
$session_esc = pg_escape_string($session);
if ($xsldir_proc == 'none') {
$statuses .= '<noproc/>';
$xml = '<root />';
} else {
if ($xsldir_proc == '' || $xsldir_proc == 'auto') {
$proc = "ppp_$procprefix".implode('_', $dirs);
if (count($dirs) && $dirs[0] != '') $proc .= '_'; //need to account for a blank root directory call
$proc .= $filename;
} else $proc = $xsldir_proc;
//get the argument types for the call
$sql = "select proargtypes from pg_proc where proname = '$proc'";
$rset = pg_query($conn, $sql);
$sargs = pg_fetch_result($rset, 'proargtypes');
if ($sargs == null) {
$statuses .= '<noproc/>';
} else {
$arg_types = explode(' ', $sargs);
pg_free_result($rset);
//assemble DB call
$sql = "select $proc('$session_esc'::text, '$schema'::text, $version";
$count_args = count($arg_types);
for($i = 3; $i < $count_args; $i++) {
$arg = $args[$i-3];
switch ($arg_types[$i]) {
case 16: { //bool
$sql .= ', '.($arg == 'on' || $arg === true || $arg == 'true'? 'true' : 'false');
break;
}
case 23: { //number
$arg = (int)$arg;
$sql .= ", $arg::integer";
break;
}
case 25: //text: note that magic_quotes should be Off because we bring in items from custom PHP files
default: {
$sql .= ", '".pg_escape_string($arg)."'::text";
break;
}
}
}
//make the call
$sql .= ') as xml';
$rset = pg_query($conn, $sql);
$xml = pg_fetch_result($rset, 'xml');
if ($xml == null || $xml == '') $statuses .= '<noxml/>';
pg_free_result($rset);
}
if (DEBUG) {
$debug .= "################## sql\n";
$debug .= "submission: $submission (".($submission ? 'true' : 'false').")\n";
$debug .= "proc: $proc\n";
$debug .= "$count_args proc arguments (including session \$1, schema \$2, version \$3 -> \$$count_args)\n";
if ($submission) {
if ($submission == $args[$count_args-4]) $debug .= "successful submit [submit] == [last]\n";
else $debug .= "******************************* failed attempted submission [submit] != [last]\n";
}
$debug .= "argso (pre-plugins bare form inputs):\n";
foreach($argso as $k => $v) $debug .= " $k= $v\n";
$debug .= "args (post-plugins with geo, recaptcha etc.):\n";
$debug .= " \$1 session, \$2 schema, \$3 version\n";
foreach($args as $k => $v) $debug .= " \$".($k+4)."($k)= $v\n";
if ($k+4 < $count_args) $debug .= " (arguments unaccounted for up to \$$count_args)\n";
$debug .= "sql: $sql\n";
}
}
//$xml = utf8_encode($xml); //DB outputs utf-8
//------------------------------------------- session ---------------------------------------------------
//done after proc in case it affects the session information
//includes any session information like login status into the response xml
$session_schema = '';
$sql = "select proargtypes from pg_proc where proname = 'ppp_$procprefix"."session'";
$rset = pg_query($conn, $sql);
$sargs = pg_fetch_result($rset, 'proargtypes');
if ($sargs == null) {
$sessionxml = '<nosession />';
} else {
pg_free_result($rset);
if (stripos($xsldir_schema, 'baresession') !== FALSE) $session_schema = 'bare';
$rset = pg_query($conn, "select ppp_$procprefix"."session('$session_esc', '$session_schema', 1, '$siteroot', '$user_agent_esc')");
$sessionxml = pg_fetch_result($rset, 0);
pg_free_result($rset);
}
//------------------------------------------- plugins post ---------------------------------------------------
require_once('includes/404plugins/404plugins_post.php');
//------------------------------------------- base xml details? ---------------------------------------------------
//this is extra server information passed to the HTML webpage via the XML
//for example:
// * availability of an RSS transform for this file
// * time and date
// * parameters passed in
//it is done here rather than being passed through to the SPROC and out again because there may not be a proc
//the API transforms will usually remove this and return only the <procxml> node
//note that $procxml will have a single root element so that it is also standalone
$relativedirectory = implode('/', $dirs);
$relativepath = "$relativedirectory/$filename";
$relativequery = '';
$responsexml = '<response transform=""'; //note that the transform attribute is filled out later
$responsexml .= ' xmlns:dir="'.NAMESPACE_DIRECTIVES.'"';
$responsexml .= ' xmlns:sendmail="'.NAMESPACE_SENDMAIL.'"';
$responsexml .= ' xmlns:rss="'.NAMESPACE_RSS.'"';
$responsexml .= '>';
$responsexml .= '<request>';
if (stripos($xsldir_schema, 'noclient') === FALSE) {
$responsexml .= '<client>';
if ($is_googlebot) $browser = 'googlebot';
else $browser = $client->property('browser');
$responsexml .= '<browser><![CDATA['.escapeForCDATA($browser).']]></browser>';
$responsexml .= '<version>
<major><![CDATA['.escapeForCDATA($client->property('maj_ver')).']]></major>
<minor><![CDATA['.escapeForCDATA($client->property('min_ver')).']]></minor>
</version>';
$responsexml .= '<platform><![CDATA['.escapeForCDATA($client->property('platform')).']]></platform>';
$responsexml .= '<os><![CDATA['.escapeForCDATA($client->property('os')).']]></os>';
$responsexml .= '</client>';
}
$responsexml .= $recaptchaxml;
$responsexml .= $geoxml;
if (stripos($xsldir_schema, 'noparams') === FALSE) {
$responsexml .= '<params>';
if (count($args)) {
foreach ($args as $name => $value) {
$relativequery .= "$name=$value&";
$responsexml .= "<p index=\"$name\"><![CDATA[$value]]></p>";
}
$relativequery = '?'.substr($relativequery, 0, -5);
}
$responsexml .= '</params>';
}
$responsexml .= $cookiexml;
if ($submission) $responsexml .= "<submit>$submission</submit>"; //indicates a form submission (always name submit buttons submit!)
$responsexml .= '<server>';
if ($link_base || $resource_base) {
$responsexml .= '<distributed>';
if ($link_base) $responsexml .= '<link_base><![CDATA['.escapeForCDATA($link_base).']]></link_base>';
if ($resource_base) $responsexml .= '<resource_base><![CDATA['.escapeForCDATA($resource_base).']]></resource_base>';
$responsexml .= '</distributed>';
}
if (defined('GOOGLEAPIKEY')) $responsexml .= '<google_api><![CDATA['.GOOGLEAPIKEY.']]></google_api>';
if ($email_result) $responsexml .= '<sendmail:result><![CDATA['.escapeForCDATA($email_result).']]></sendmail:result>';
$responsexml .= $sessionxml;
if (stripos($xsldir_schema, 'noextinfo') === FALSE) {
$responsexml .= "<referer><![CDATA[$referer]]></referer>";
$responsexml .= datexml(time());
$responsexml .= "<domain><![CDATA[$domain]]></domain>";
$responsexml .= '<stage>'.(DEVSERVER?'dev':'live').'</stage>';
$responsexml .= "<siteroot><![CDATA[$siteroot]]></siteroot>";
$responsexml .= "<domainstem><![CDATA[$domainstem]]></domainstem>";
}
if (stripos($xsldir_schema, 'nopathinfo') === FALSE) {
$responsexml .= '<pathinfo>';
$responsexml .= '<relativepath><![CDATA['.escapeForCDATA($relativepath).']]></relativepath>';
$responsexml .= '<relativedirectory><![CDATA['.escapeForCDATA($relativedirectory).']]></relativedirectory>';
$responsexml .= '<relativequery><![CDATA['.escapeForCDATA($relativequery).']]></relativequery>';
$responsexml .= '</pathinfo>';
}
$responsexml .= '</server>';
$responsexml .= '</request>';
if ($headxml) $responsexml .= "<head>$headxml</head>";
if ($customxml) $responsexml .= "<custom>$customxml</custom>";
if ($statuses) $responsexml .= "<status>$statuses</status>";
$responsexml .= "<procxml>$xml</procxml>";
$responsexml .= '</response>';
if ($api_mode && $extension != 'html') {
//------------------------------------------- api mode ---------------------------------------------------
//this is always a server transform
//formatting (based on extension) only allowed in api mode (otherwise ignored)
//thus, the main xsl file is now ignored and an xsl file capable of transforming the xml
//into the required format is looked for
//essentially the main xsl file was really a placeholder to say that the function (and ppp_*) is available
if (!$extension) $extension = 'xml';
$responsexml = str_replace(' transform=""', ' transform="apimode"', $responsexml);
$xmlDoc = new DOMDocument('1.0', 'utf-8');
$xmlDoc->loadXML(&$responsexml);
$xslDoc = new DOMDocument('1.0', 'utf-8');
$transform_local = "$localpath$filename"."_$extension.xsl"; //e.g. all_json.xsl custom transform
$transform_standard = "$thisdir/formats/$extension.xsl";
$loaded = false;
if (is_file($transform_local)) $loaded = $xslDoc->load($transform_local);
else if (is_file($transform_standard)) $loaded = $xslDoc->load($transform_standard);
if ($loaded) {
//work out the relevant content-type for the result
//the format XSL file can contain the MIMEType that it creates:
$mimetype = firstitemtext($xslDoc->getelementsByTagNameNS(NAMESPACE_DIRECTIVES, 'MIMEType'));
if (!$mimetype) {
switch ($extension) {
//standard types:
case 'xml': {$mimetype = 'text/xml'; break;} //just the <procxml> element
case 'fxml': {$mimetype = 'text/xml'; break;} //full response
//case 'rss': {$mimetype = 'text/rss+xml'; break;}
case 'rss': {$mimetype = 'application/xhtml+xml'; break;}
case 'json': {$mimetype = 'application/json'; break;}
case 'js': {$mimetype = 'application/x-javascript'; break;}
default: {$mimetype = 'text/html'; break;}
}
}
header("Content-Type: $mimetype; charset=utf-8", true);
$oXSLT = new XSLTProcessor();
$oXSLT->importStyleSheet($xslDoc);
$output = $oXSLT->transformToXML($xmlDoc);
} else {
//show error if can not find handler
header("Content-Type: text/html; charset=utf-8", true);
$output = "cannot find a handler for [$extension]";
}
if (DEBUG) {
$debug .= "################## api\n";
$debug .= "transform_local: $transform_local\n";
$debug .= "transform_standard: $transform_standard\n";
$debug .= "loaded: $loaded\n";
}
} else {
//------------------------------------------- normal HTML conditional output ---------------------------------------------------
if (stripos($xsldir_schema, 'barexml') !== FALSE) $responsexml = $xml;
//client-server switch
if ($client->has_feature('xml') //browser sniff: can process XSLT
&& $xsldir_transform != 'server' //explicit server transform request by the XSL DIR
&& !$is_googlebot //googlebot masquerades as Firefox
&& !$xsldir_jsdocwrite //page uses document.write during parse (not compatible with FF client XSLT)
&& !FORCE_SERVER_XSLT //define.php
&& $extension != 'html' //special request for a server side transform
) {
//CLIENT transform - indicate MIME type and disable cacheing
$clientXSLT = true;
$responsexml = str_replace(' transform=""', ' transform="client"', $responsexml);
header("Content-Type: application/xml; charset=utf-8", true);
$uri_xslpath = "$resource_base/$siteroot/".implode('/', $dirs);
if (count($dirs) && $dirs[0] != '') $uri_xslpath .= '/'; //need to account for a blank root directory call
$uri_xslpath .= "$filename.xsl";
$xml_ss = "<?xml-stylesheet charset=\"utf-8\" type=\"text/xsl\" href=\"$uri_xslpath\"?>\n";
//the xml decleration overrides the MIMEType in Firefox
//so when we are trying to force the MIMEType, remove the xml decl
if ($xsldir_mimetype) $output = $responsexml;
else $output = XML_DECL.$xml_ss.$responsexml;
if (DEBUG) {
$debug .= "################## output (client side transform)\n";
$debug .= "uri_xslpath: $uri_xslpath\n";
}
} else {
//SERVER transform (can be requested by using a .html extension without the api)
//the xsl file is loaded already because the directives needed to be read
$responsexml = str_replace(' transform=""', ' transform="server"', $responsexml);
header("Content-Type: text/html; charset=utf-8", true);
$xmlDoc = new DOMDocument('1.0', 'utf-8');
$xmlDoc->loadXML(&$responsexml);
$oxslt = new XSLTProcessor();
$oxslt->importStyleSheet($xslDoc);
$output = $oxslt->transformToXML($xmlDoc);
if (DEBUG) {
$debug .= "################## output (server side transform)\n";
}
}
}
//output
header("HTTP/1.1 200 OK", true, 200);
if ($xsldir_mimetype) header("Content-Type: $xsldir_mimetype; charset=utf-8", true);
$forceMIMEType = $argso['forceMIMEType'];
if ($forceMIMEType) header("Content-Type: $forceMIMEType; charset=utf-8", true);
print($output);
}
//------------------------------------------- debug ---------------------------------------------------
if (DEBUG && (!$extension || $extension == 'php')) {
print("\n<!-- \n");
print($debug);
print(' -->');
}
log404($debug);
log404("\n\n");
if (LOG404) fclose($log);
//------------------------------------------- functions ---------------------------------------------------
function log404($string) {
global $log;
if (LOG404) fwrite($log, $string);
}
function escapeForCDATA($in) {
return preg_replace('/&(?!amp;)/', '&', str_replace(']]>', ' ', $in));
}
function escapeForElementName($in) {
return preg_replace('/[^a-zA-Z_]/i', '', $in);
}
function escapeForAttributeValue($in) {
return preg_replace('/&(?!amp;)/', '&', $in);
}
function domainstem($domain) {
return preg_replace('/^www\.|\.org$|\.co\.uk$|\.com$|\.dev$|\.net$|\.org\.uk|\.dev2|\.eval$/i', '', $domain);
}
function firstitemtext($nodelist) {
$text = NULL;
if (is_object($nodelist) && $nodelist->length > 0) {
$firstnode = $nodelist->item(0);
$text = $firstnode->textContent;
}
return $text;
}
function datexml($d) {
return '<date RFC2822="'.date('r', $d).'" ISO8601="'.date('c', $d).'" year="'.date('o', $d).'" month="'.date('m', $d).'" monthname="'.date('F', $d).'" date="'.date('d', $d).'" day="'.date('l', $d).'" hour="'.date('H', $d).'" minute="'.date('i', $d).'" second="'.date('s', $d).'" tz="'.date('O', $d).'"><![CDATA['.date('c', $d).']]></date>';
}
//This function exploits preg_match behaviour (since PHP 4.3.5) when used
//with the u modifier, as a fast way to find invalid UTF-8. When the matched
//string contains an invalid byte sequence, it will fail silently.
function validate_utf8($text) {
return (strlen($text) == 0 ? true : (preg_match('/^./us', $text) == 1) );
}
?>