DokuWiki

It's better when it's simple

User Tools

Site Tools


plugin:source:mod_rules

Plugin:Source rule modifications

The below source is a modification to the 2005-08-23 version of the plugin to support more complex rules for determination of whether or not the source file can be included. It was contributed by E-Razor

note: basic rules have been added to the latest release of the source plugin

<?php
/**
 * Source Plugin: includes a source file using the geshi highlighter
 *
 * Syntax:     <source filename lang|title/>
 *   filename  (required) can be a local path/file name or a remote file uri
 *             to use remote file uri, allow_url_fopen=On must be set in the server's php.ini
 *             filenames with spaces must be surrounded by matched pairs of quotes (" or ')
 *   lang      (optional) programming language name, is passed to geshi for code highlighting
 *             if not provided, the plugin will attempt to derive a value from the file name
 *             (refer $extensions in render() method)
 *   title     (optional) all text after '|' will be rendered above the main code text with a
 *             different style. If no title is present, it will be set to "file: filename"
 *
 *  *** WARNING ***
 *
 *  Unless configured correctly this plugin can be a huge security risk.
 *  Please review/consider
 *    - users who have access to the wiki
 *    - php.ini setting, allow_url_fopen
 *    - php.ini setting, base_dir
 *    - $location, $allow & $deny settings below.
 * 
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Christopher Smith <chris@jalakai.co.uk>
 */
 
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');
 
 
//------------------------[ Security settings ] ---------------------------------------------
// $location is prepended to all file names, restricting the filespace exposed to the plugin
$location = '';
 
// if $allow array contains any elements, ONLY files with the extensions listed will be allowed
$allow = array();
 
// if the $allow array is empty, any file with an extension listed in $deny array will be denied $deny = array('php');
 
//------------------------[ Other settings ] ---------------------------------------------
// list of common file extensions and their language equivalent
// (required only where the extension and the language are not the same)
 
/**
 * All DokuWiki plugins to extend the parser/rendering mechanism
 * need to inherit from this class
 */
class syntax_plugin_source extends DokuWiki_Syntax_Plugin {
    var $my_conf = array(
      //map file extensions to languages
      'mapping' => array(
        'htm' => 'html4strict',
        'html' => 'html4strict',
        'js' => 'javascript'
      ),
      //what path do we have to translate (local paths only)
      'translate' => '/^\/|^(\.\.\/)|^(file:\/\/)/',
      'rules' => array(
        //first rule: deny everything
        array(
          'allow' => '',
          'deny' => '/^./'
        ),
        //second rule, allow all remote files
        array(
          'allow' => '/^(ftp:\/\/)|^(http:\/\/)|^(https:\/\/)/',
          'deny' => ''
        ),
        //third rule, allow all .html files
        array(
          'allow' => '/(\.html)$|(\.htm)$/',
          'deny' => ''
        )
      )
    );
 
    /**
     * check if we are allowed to view the file
     * @author  Alexander 'E-Razor' Krause <alexander.krause@erazor-zone.de>
     * @date    23.08.2005
     */
    function is_allowed($url) {
       $allowed=false;
 
      reset($this->my_conf['rules']);
      while (list($rule_nr, $rule) = each($this->my_conf['rules'])) {
        if ($rule['allow']!='')
          $allowed|=preg_match($rule['allow'],$url);
 
        if ($rule['deny']!='')
          $allowed&= !preg_match($rule['deny'],$url);
      }
      return $allowed;
    }
 
    /**
     * return some info
     */
    function getInfo(){
      return array(
        'author' => 'Christopher Smith',
        'email'  => 'chris@jalakai.co.uk',
        'date'   => '2005-08-23',
        'name'   => 'Source Plugin',
        'desc'   => 'Include a remote source file
                     Syntax: <source filename language|title>',
        'url'    => 'http://www.dokuwiki.org/plugin:source',
      );
    }
 
    function getType(){ return 'substition'; }
    function getPType(){ return 'block'; }
    function getSort(){ return 330; }
 
    /**
     * Connect pattern to lexer
     */
    function connectTo($mode) {
      $this->Lexer->addSpecialPattern('<source.*?/>',$mode,substr(get_class($this), 7));
    }
 
    /**
     * Handle the match
     */
    function handle($match, $state, $pos, &$handler){
      $match = trim(substr($match,7,-2));                    //strip <source from start and /> from end
      list($attr, $title) = preg_split('/\|/u', $match, 2);  //split out title
//    list($file, $lang) = preg_split('/\s+/',$attr, 3);     //split out file name and language
 
// alternate method to get $file & $lang allowing for filenames with spaces
      $attr = trim($attr);
      $pattern = ($attr{0} == '"' || $attr{0} == "'") ? $attr{0} : '\s';
      list($file, $lang) = preg_split("/$pattern/u", $attr, 3, PREG_SPLIT_NO_EMPTY);
 
      return array(trim($file), (isset($lang)?trim($lang):''), (isset($title)?trim($title):''));
    }
 
    /**
     * Create output
     */
    function render($mode, &$renderer, $data) {
      //merge my_conf defaults with values in $conf['plugin']['source']
      global $conf;
      $this->my_conf = array_merge($this->my_conf,$conf['plugin']['source']);
      if($mode == 'xhtml'){
        list($file, $lang, $title) = $data;
        $ext = substr(strrchr($file, '.'),1);
        //translate file to absolute path
        if (preg_match($this->my_conf['translate'],$file)) $url=realpath($file);
 
        $ok = $this->is_allowed($file);
 
        if ($ok && ($source = @file_get_contents($file))) {
 
          if (!$lang) {
            $lang = isset($this->my_conf['mapping'][$ext]) ? $this->my_conf['mapping'][$ext] : $ext;
          }
 
          $title = ($title) ? ("<span>".$renderer->_xmlEntities($title)."</span>"):
                              ("file: <span>".$renderer->_xmlEntities($file)."</span>");
 
          $renderer->doc .= "<div class='source'><p>$title</p>";
          $renderer->code($source, $lang);
          $renderer->doc .= "</div>";
          return true;
        } else {
          $renderer->doc .= "<div class='source'><p><span>Unable to display file &quot;".
                            $renderer->_xmlEntities($file)."&quot;: It may not exist, or permission may be denied.</span></p></div>";
        }
      }
      return false;
    }
}
 
//Setup VIM: ex: et ts=4 enc=utf-8 :
?>
plugin/source/mod_rules.txt · Last modified: 2006-12-24 03:14 by ChrisS