dokuwiki-source-plugin – Blame information for rev 4

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 1 <?php
2 /**
3 * Source Plugin: includes a source file using the geshi highlighter
4 *
5 * Syntax: <source filename lang|title>
6 * filename (required) can be a local path/file name or a remote file uri
7 * to use remote file uri, allow_url_fopen=On must be set in the server's php.ini
8 * filenames with spaces must be surrounded by matched pairs of quotes (" or ')
9 * lang (optional) programming language name, is passed to geshi for code highlighting
10 * if not provided, the plugin will attempt to derive a value from the file name
11 * (refer $extensions in render() method)
12 * title (optional) all text after '|' will be rendered above the main code text with a
13 * different style. If no title is present, it will be set to "file: filename"
14 *
15 * *** WARNING ***
16 *
17 * Unless configured correctly this plugin can be a huge security risk.
18 * Please review/consider
19 * - users who have access to the wiki
20 * - php.ini setting, allow_url_fopen
21 * - php.ini setting, open_basedir
22 * - this plugin's location, allow & deny settings.
23 *
24 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
4 office 25 * @author Christopher Smith <chris@jalakai.co.uk>
1 eva 26 */
27 if(!defined('DOKU_INC')) die(); // no Dokuwiki, no go
4 office 28  
1 eva 29 if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
30 require_once(DOKU_PLUGIN.'syntax.php');
4 office 31  
1 eva 32 /**
33 * All DokuWiki plugins to extend the parser/rendering mechanism
34 * need to inherit from this class
35 */
36 class syntax_plugin_source extends DokuWiki_Syntax_Plugin {
4 office 37  
1 eva 38 //------------------- [ Security settings ] ---------------------------------------------
39 var $location = ''; // prepended to all file names, restricting the filespace exposed to the plugin
40 var $allow = array(); // if not empty, ONLY files with the extensions listed will be allowed
41 var $deny = array(); // if $allow array is empty, any file with an extension listed in $deny array will be denied
42 var $rules = array(); // more complex allow/deny rules, refer documentation
4 office 43  
1 eva 44 //------------------------[ Other settings ] ---------------------------------------------
45 var $extensions = array(
46 'htm' => 'html4strict',
47 'html' => 'html4strict',
48 'js' => 'javascript'
49 );
4 office 50  
1 eva 51 /**
52 * return some info
53 */
54 function getInfo(){
55 return array(
56 'author' => 'Christopher Smith',
57 'email' => 'chris@jalakai.co.uk',
58 'date' => '2008-08-13',
59 'name' => 'Source Plugin',
60 'desc' => 'Include a remote source file
61 Syntax: <source filename #startline-endline language|title>',
62 'url' => 'http://www.dokuwiki.org/plugin:source',
63 );
64 }
4 office 65  
1 eva 66 function getType() { return 'substition'; }
67 function getPType() { return 'block'; }
68 function getSort() { return 330; }
4 office 69  
1 eva 70 /**
71 * Connect pattern to lexer
72 */
73 function connectTo($mode) {
74 $this->Lexer->addSpecialPattern('<source.*?>',$mode,substr(get_class($this), 7));
75 }
4 office 76  
1 eva 77 /**
78 * Handle the match
79 */
3 office 80 function handle($match, $state, $pos, Doku_Handler $handler){
1 eva 81 $match = trim(substr($match,7,-1)); //strip <source from start and > from end
4 office 82  
1 eva 83 // ['|"]?<filename>[\1] [#<line#>-<line#>] <lang> | <title>
84 list($attr, $title) = preg_split('/\|/u', $match, 2); //split out title
4 office 85  
1 eva 86 $attr = trim($attr);
4 office 87 $pattern = ($attr[0] == '"' || $attr[0] == "'") ? $attr[0] : '\s';
1 eva 88 list($file, $prop) = preg_split("/$pattern/u", $attr, 3, PREG_SPLIT_NO_EMPTY);
4 office 89  
1 eva 90 if (isset($prop) && trim($prop)) {
91 $matches = array();
92 if (preg_match('/\s*(?:(?:#(\d+)-(\d+))\s*)?(\w+)?/',$prop,$matches)) {
93 list(,$start,$end,$lang) = $matches;
94 if (!isset($lang)) $lang = '';
95 }
96 } else {
97 $start = $end = $lang = '';
98 }
4 office 99  
1 eva 100 return array(trim($file), $lang, (isset($title)?trim($title):''), $start, $end);
101 }
4 office 102  
1 eva 103 /**
104 * Create output
105 */
3 office 106 function render($format, Doku_Renderer $renderer, $data) {
4 office 107  
1 eva 108 $this->_loadSettings();
4 office 109  
1 eva 110 list($file, $lang, $title, $start, $end) = $data;
111 $ext = substr(strrchr($file, '.'),1);
4 office 112  
1 eva 113 $ok = false;
114 if (count($this->allow)) {
115 if (in_array($ext, $this->allow)) $ok = true;
116 } else {
117 if (!in_array($ext, $this->deny)) $ok = true;
118 }
4 office 119  
1 eva 120 // prevent filenames which attempt to move up directory tree by using ".."
121 if ($ok && $this->location && preg_match('/(?:^|\/)\.\.(?:\/|$)/', $file)) $ok = false;
122 if ($ok && $this->rules) $ok = $this->_checkRules($file);
4 office 123  
1 eva 124 if (!$lang) { $lang = isset($this->extensions[$ext]) ? $this->extensions[$ext] : $ext; }
4 office 125  
1 eva 126 switch ($format) {
127 case 'xhtml' :
4 office 128  
1 eva 129 if ($ok && ($source = $this->_getSource($file,$start,$end))) {
4 office 130  
1 eva 131 $title = ($title) ? "<span>".hsc($title)."</span>"
132 : $this->_makeTitle($file, $start, $end);
4 office 133  
134 $renderer->doc .= "<div class='source'><p>$title</p>";
1 eva 135 $renderer->code($source, $lang);
136 $renderer->doc .= "</div>";
137 } else {
138 $error = sprintf($this->getLang('error_file'),hsc($file));
139 $renderer->doc .= '<div class="source"><p><span>'.$error.'</span></p></div>';
140 }
141 break;
4 office 142  
1 eva 143 case 'metadata' :
144 if ($ok) {
145 $renderer->meta['relation']['haspart'][$file] = array('owner'=>$this->getPluginName());
146 }
147 break;
4 office 148  
1 eva 149 default :
150 if ($ok) {
151 $renderer->code($this->_getSource($file,$start,$end), $lang);
152 }
153 }
4 office 154  
1 eva 155 }
4 office 156  
1 eva 157 function _makeTitle($file,$start,$end) {
158 $lines = $start ? sprintf($this->getLang('lines'),$start,$end) : '';
159 $title = sprintf($this->getLang('title'),hsc($file),$lines);
4 office 160  
1 eva 161 return $title;
162 }
4 office 163  
1 eva 164 function _getSource($file,$start,$end) {
4 office 165  
1 eva 166 $source = @file($this->location.$file);
167 if (empty($source)) return '';
4 office 168  
1 eva 169 // $start is a 1 based index, need to correct to 0 based when slicing arrray
170 if (!empty($start)) {
171 $lines = count($source);
172 if ($start > $lines) {
173 $source = $this->getLang('error_start');
174 } else if ($end < $start) {
175 $source = $this->getLang('error_end');
176 } else if ($end > $lines) {
177 $source = join('',array_slice($source,$start-1));
178 } else {
179 $source = join('',array_slice($source,$start-1,$end-$start));
180 }
181 } else {
182 $source = join('',$source);
183 }
4 office 184  
1 eva 185 return $source;
186 }
4 office 187  
1 eva 188 function _checkRules($file) {
189 $permit = true;
190 foreach ($this->rules as $rule) {
191 list($allow_deny, $pattern) = $rule;
192 if ($allow_deny == 'allow') {
193 if (preg_match($pattern,$file)) $permit = true;
194 } else {
195 if (preg_match($pattern,$file)) $permit = false;
196 }
197 }
4 office 198  
1 eva 199 return $permit;
200 }
4 office 201  
1 eva 202 function _loadSettings() {
203 static $loaded = false;
4 office 204  
1 eva 205 if ($loaded) return;
4 office 206  
1 eva 207 $this->location = $this->getConf('location');
4 office 208  
1 eva 209 $allow = $this->getConf('allow');
210 $this->allow = !empty($allow) ? explode('|',$allow) : array();
4 office 211  
1 eva 212 $deny = $this->getConf('deny');
213 $this->deny = !empty($deny) ? explode('|',$deny) : array();
4 office 214  
1 eva 215 $rules = $this->getConf('rules');
216 if (!empty($rules)) $this->_parseRules($rules);
4 office 217  
1 eva 218 $loaded = true;
219 }
4 office 220  
1 eva 221 function _parseRules($rules) {
222 $rules = explode("\n",$rules);
223 foreach ($rules as $rule) {
224 $rule = trim($rule);
4 office 225 if (!$rule || $rule[0] == ';') continue;
226  
1 eva 227 $match = array();
228 if (!preg_match('/^(allow|deny)\s+(.+)$/i',$rule,$match)) continue;
4 office 229  
1 eva 230 $this->rules[] = array(strtolower($match[1]),$match[2]);
231 }
232 }
233 }
4 office 234  
235 //Setup VIM: ex: et ts=4 enc=utf-8 :