<?php if (!defined('PmWiki')) exit(); /* * IncludeXML - Include processed XML into PmWiki 2.x pages * Copyright 2005-2007 by D.Faure (dfaure@cpan.org) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * See http://www.pmwiki.org/wiki/Cookbook/IncludeXML for info. */ $RecipeInfo['IncludeXML']['Version'] = '20070621'; include_once("$FarmD/cookbook/extlinkedres.php"); if($RecipeInfo['LinkedResourceExtras']['Version'] < '20070215') Abort('?IncludeXML requires an updated LinkedResourceExtras'); Markup('includexml', 'directives', "/\\(:includexml(\\s+.*)?\\s*:\\)/e", "IncludeXMLTransform(\$pagename,'',PSS('$1'),'')"); Markup('xsl', '>[=', "/\\(:xsl(\\s+.*)?\\s*:\\)\\s*$KeepToken(\\d.*?)$KeepToken/e", "IncludeXMLTransform(\$pagename,'xsl',PSS('$1'),\$GLOBALS['KPV']['$2'])"); Markup('xslend', '>xsl', "/\\(:xsl(\\s+.*)?\\s*:\\)\n(?s:(.*?))\\(:xslend:\\)/e", "IncludeXMLTransform(\$pagename,'xsl',PSS('$1'),PSS('$2'))"); Markup('xml', '>[=', "/\\(:xml(\\s+.*)?\\s*:\\)\\s*$KeepToken(\\d.*?)$KeepToken/e", "IncludeXMLTransform(\$pagename,'xml',PSS('$1'),\$GLOBALS['KPV']['$2'])"); Markup('xmlend', '>xml', "/\\(:xml(\\s+.*)?\\s*:\\)\n(?s:(.*?))\\(:xmlend:\\)/e", "IncludeXMLTransform(\$pagename,'xml',PSS('$1'),PSS('$2'))"); SDVA($IncludeXMLMsgFmt, array( 'denied' => "<h3 class='wikimessage'>$[Unable to bind to denied resource.]</h3>", 'notfound' => "<h3 class='wikimessage'>$[XML data not found]</h3>", )); SDVA($IncludeXMLOptions, array( 'xml' => array('inc' => false, 'ctx' => null), 'xsl' => array('inc' => false, 'ctx' => null), 'markup' => true, )); SDV($IncludeXMLDecodeFunc, create_function('$data', 'return $data;')); function IncludeXMLTransform($pagename, $type, $args, $data = '') { global $IncludeXMLMsgFmt, $IncludeXMLDecodeFunc, $IncludeXMLOptions; $opt = ParseArgs($args); $xslt_args = array(); if($type) { $o = array_flip(array('xml', 'xsl')); unset($o[$type]); $opt[$type] = '-'; $xslt_args["/_$type"] = # undo PmWiki's htmlspecialchars conversion and trim str_replace(array('<:vspace>', '<', '>', '&'), array('', '<', '>', '&'), trim($data)); $rsc = key($o); if(IncludeXMLReadData($pagename, $data2, $opt[$rsc], $IncludeXMLOptions[$rsc]['inc'], $IncludeXMLOptions[$rsc]['ctx'])) $xslt_args["/_$rsc"] = $data2; else return $data2; } else { if(!isset($opt['xml'])) { $opt['xml'] = $opt['src']; unset($opt['src']); } if(IncludeXMLReadData($pagename, $data, $opt['xml'], $IncludeXMLOptions['xml']['inc'], $IncludeXMLOptions['xml']['ctx'])) $xslt_args['/_xml'] = $data; else return $data; if(IncludeXMLReadData($pagename, $data, $opt['xsl'], $IncludeXMLOptions['xsl']['inc'], $IncludeXMLOptions['xsl']['ctx'])) $xslt_args['/_xsl'] = $data; else return $data; } if(!$xslt_args['/_xml']) return FmtPageName($IncludeXMLMsgFmt['notfound'], $pagename); if(!$xslt_args['/_xsl']) return Keep("<code><pre>" . htmlentities($xslt_args['/_xml']) . "</pre></code>"); $redoMarkup = ! @in_array('markup', $opt['-']) && $IncludeXMLOptions['markup']; $debug = @in_array('debug', $opt['+']); unset($opt['#'], $opt['+'], $opt['-']); $xh = xslt_create(); $result = $IncludeXMLDecodeFunc(xslt_process($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $xslt_args, $opt)); xslt_free($xh); if($debug) return Keep("<code><pre>" . htmlentities($result) . "</pre></code>"); if($redoMarkup) return PRR(PVSE($result)); return Keep($result); } function IncludeXMLReadData($pagename, &$data, $tgt, $inc, $ctx) { global $EnableExternalResource, $IncludeXMLMsgFmt, $IncludeXMLUseIncludePath; if(!ResolveLinkResource($pagename, $tgt, $url, $txt, $upname, $filepath, $size, $mime)) { $data = isset($filepath) ? Keep($url) : ''; return false; } if(!$filepath) { if(!IsEnabled($EnableExternalResource, true)) { $data = FmtPageName($IncludeXMLMsgFmt['denied'], $pagename); return false; } $filepath = $url; } $data = IncludeXML_file_get_contents($filepath, $inc, $ctx); return true; } // Emulate potentially missing functions and old xslt library functions // // xslt_* functions from jw@jwscripts.com's php manual notes. // // file_get_contents: PHP 4 >= 4.3.0, PHP 5 - file_put_contents: PHP 5 // functions adapted from http://pear.php.net/package/PHP_Compat code. See there // for original credits. // if(PHP_VERSION >= 5) { function xslt_create() { return new XsltProcessor(); } function xslt_free($xsltproc) { unset($xsltproc); } function xslt_process($xsltproc, $xml_arg, $xsl_arg, $xslcontainer = null, $args = null, $params = null) { // Start with preparing the arguments $xml_arg = str_replace('arg:', '', $xml_arg); $xsl_arg = str_replace('arg:', '', $xsl_arg); // Load the xml document and the xsl template // creating instances of the DomDocument class $xml = DOMDocument::loadXML($args[$xml_arg]); $xsl = DOMDocument::loadXML($args[$xsl_arg]); // Load the xsl template $xsltproc->importStyleSheet($xsl); // Set parameters when defined if($params) foreach($params as $param => $value) $xsltproc->setParameter("", $param, $value); // Start the transformation $processed = $xsltproc->transformToXML($xml); // Put the result in a file when specified if($xslcontainer) return IncludeXML_file_put_contents($xslcontainer, $processed); else return $processed; } function IncludeXML_file_get_contents($filename, $incpath = false, $resource_context = null) { return file_get_contents($filename, $incpath, $resource_context); } function IncludeXML_file_put_contents($filename, $content, $flags = null, $resource_context = null) { return file_put_contents($filename, $content, $flags, $resource_context); } } else { define('INCLUDEXML_FILE_GET_CONTENTS_MAX_REDIRECTS', 5); function IncludeXML_file_get_contents($filename, $incpath = false, $resource_context = null) { $opts = is_resource($resource_context) && function_exists('stream_context_get_options') ? stream_context_get_options($resource_context) : null; $colon_pos = strpos($filename, '://'); $wrapper = $colon_pos === false ? 'file' : substr($filename, 0, $colon_pos); $opts = (empty($opts) || empty($opts[$wrapper])) ? array() : $opts[$wrapper]; switch($wrapper) { case 'http': $max_redirects = (isset($opts[$wrapper]['max_redirects']) ? $opts[$proto]['max_redirects'] : INCLUDEXML_FILE_GET_CONTENTS_MAX_REDIRECTS); for($i = 0; $i < $max_redirects; $i++) { $contents = IncludeXML_file_get_contents_http_get_contents_helper($filename, $opts); if(is_array($contents)) { // redirected $filename = rtrim($contents[1]); $contents = ''; continue; } return $contents; } user_error('redirect limit exceeded', E_USER_WARNING); return; case 'ftp': case 'https': case 'ftps': case 'socket': // tbc } if(false === $fh = fopen($filename, 'rb', $incpath)) { user_error('failed to open stream: No such file or directory', E_USER_WARNING); return false; } clearstatcache(); if($fsize = @filesize($filename)) $data = fread($fh, $fsize); else { $data = ''; while (!feof($fh)) $data .= fread($fh, 8192); } fclose($fh); return $data; } function IncludeXML_file_get_contents_http_get_contents_helper($filename, $opts) { $path = parse_url($filename); if(!isset($path['host'])) return ''; $fp = fsockopen($path['host'], 80, $errno, $errstr, 4); if(!$fp) return ''; if(!isset($path['path'])) $path['path'] = '/'; $headers = array('Host' => $path['host'], 'Conection' => 'close'); // enforce some options (proxy isn't supported) $opts_defaults = array('method' => 'GET', 'header' => null, 'user_agent' => ini_get('user_agent'), 'content' => null, 'request_fulluri' => false); foreach($opts_defaults as $key => $value) if(!isset($opts[$key])) $opts[$key] = $value; $opts['path'] = $opts['request_fulluri'] ? $filename : $path['path']; // build request $request = $opts['method'] . ' ' . $opts['path'] . " HTTP/1.0\r\n"; // build headers if(isset($opts['header'])) { $optheaders = explode("\r\n", $opts['header']); for($i = count($optheaders); $i--;) { $sep_pos = strpos($optheaders[$i], ': '); $headers[substr($optheaders[$i], 0, $sep_pos)] = substr($optheaders[$i], $sep_pos + 2); } } foreach($headers as $key => $value) $request .= "$key: $value\r\n"; $request .= "\r\n" . $opts['content']; // make request fputs($fp, $request); $response = ''; while(!feof($fp)) $response .= fgets($fp, 8192); fclose($fp); $content_pos = strpos($response, "\r\n\r\n"); // recurse for redirects if(preg_match('/^Location: (.*)$/mi', $response, $matches)) return $matches; return ($content_pos != -1 ? substr($response, $content_pos + 4) : $response); } if(!defined('FILE_USE_INCLUDE_PATH')) define('FILE_USE_INCLUDE_PATH', 1); if(!defined('LOCK_EX')) define('LOCK_EX', 2); if(!defined('FILE_APPEND')) define('FILE_APPEND', 8); function IncludeXML_file_put_contents($filename, $content, $flags = null, $resource_context = null) { if(!is_scalar($content)) { user_error('file_put_contents() The 2nd parameter should be either a string or an array', E_USER_WARNING); return false; } $fh = @fopen($filename, ($flags & FILE_APPEND) ? 'a' : 'wb', ($flags & FILE_USE_INCLUDE_PATH) ? true : false, $resource_context); if(!$fh) { user_error('file_put_contents() failed to open stream: Permission denied', E_USER_WARNING); return false; } // Attempt to get an exclusive lock if(($flags & LOCK_EX) && !flock($fh, LOCK_EX)) return false; // Write to the file if(is_array($content)) $content = implode('', $content); $length = strlen($content); if(($bytes = @fwrite($fh, $content)) === false) { user_error(sprintf('file_put_contents() Failed to write %d bytes to %s', $length, $filename), E_USER_WARNING); return false; } @fclose($fh); // Check all the data was written if($bytes != $length) { user_error(sprintf('file_put_contents() Only %d of %d bytes written, possibly out of free disk space.', $bytes, $length), E_USER_WARNING); return false; } return $bytes; } }