dokuwiki-source-plugin – Diff between revs 1 and 2

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