This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | #!/usr/bin/env php |
||
2 | <?php |
||
3 | |||
4 | use splitbrain\phpcli\CLI; |
||
5 | use splitbrain\phpcli\Options; |
||
6 | |||
7 | if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/'); |
||
8 | define('NOSESSION', 1); |
||
9 | require_once(DOKU_INC . 'inc/init.php'); |
||
10 | |||
11 | /** |
||
12 | * Checkout and commit pages from the command line while maintaining the history |
||
13 | */ |
||
14 | class PageCLI extends CLI { |
||
15 | |||
16 | protected $force = false; |
||
17 | protected $username = ''; |
||
18 | |||
19 | /** |
||
20 | * Register options and arguments on the given $options object |
||
21 | * |
||
22 | * @param Options $options |
||
23 | * @return void |
||
24 | */ |
||
25 | protected function setup(Options $options) { |
||
26 | /* global */ |
||
27 | $options->registerOption( |
||
28 | 'force', |
||
29 | 'force obtaining a lock for the page (generally bad idea)', |
||
30 | 'f' |
||
31 | ); |
||
32 | $options->registerOption( |
||
33 | 'user', |
||
34 | 'work as this user. defaults to current CLI user', |
||
35 | 'u', |
||
36 | 'username' |
||
37 | ); |
||
38 | $options->setHelp( |
||
39 | 'Utility to help command line Dokuwiki page editing, allow ' . |
||
40 | 'pages to be checked out for editing then committed after changes' |
||
41 | ); |
||
42 | |||
43 | /* checkout command */ |
||
44 | $options->registerCommand( |
||
45 | 'checkout', |
||
46 | 'Checks out a file from the repository, using the wiki id and obtaining ' . |
||
47 | 'a lock for the page. ' . "\n" . |
||
48 | 'If a working_file is specified, this is where the page is copied to. ' . |
||
49 | 'Otherwise defaults to the same as the wiki page in the current ' . |
||
50 | 'working directory.' |
||
51 | ); |
||
52 | $options->registerArgument( |
||
53 | 'wikipage', |
||
54 | 'The wiki page to checkout', |
||
55 | true, |
||
56 | 'checkout' |
||
57 | ); |
||
58 | $options->registerArgument( |
||
59 | 'workingfile', |
||
60 | 'How to name the local checkout', |
||
61 | false, |
||
62 | 'checkout' |
||
63 | ); |
||
64 | |||
65 | /* commit command */ |
||
66 | $options->registerCommand( |
||
67 | 'commit', |
||
68 | 'Checks in the working_file into the repository using the specified ' . |
||
69 | 'wiki id, archiving the previous version.' |
||
70 | ); |
||
71 | $options->registerArgument( |
||
72 | 'workingfile', |
||
73 | 'The local file to commit', |
||
74 | true, |
||
75 | 'commit' |
||
76 | ); |
||
77 | $options->registerArgument( |
||
78 | 'wikipage', |
||
79 | 'The wiki page to create or update', |
||
80 | true, |
||
81 | 'commit' |
||
82 | ); |
||
83 | $options->registerOption( |
||
84 | 'message', |
||
85 | 'Summary describing the change (required)', |
||
86 | 'm', |
||
87 | 'summary', |
||
88 | 'commit' |
||
89 | ); |
||
90 | $options->registerOption( |
||
91 | 'trivial', |
||
92 | 'minor change', |
||
93 | 't', |
||
94 | false, |
||
95 | 'commit' |
||
96 | ); |
||
97 | |||
98 | /* lock command */ |
||
99 | $options->registerCommand( |
||
100 | 'lock', |
||
101 | 'Obtains or updates a lock for a wiki page' |
||
102 | ); |
||
103 | $options->registerArgument( |
||
104 | 'wikipage', |
||
105 | 'The wiki page to lock', |
||
106 | true, |
||
107 | 'lock' |
||
108 | ); |
||
109 | |||
110 | /* unlock command */ |
||
111 | $options->registerCommand( |
||
112 | 'unlock', |
||
113 | 'Removes a lock for a wiki page.' |
||
114 | ); |
||
115 | $options->registerArgument( |
||
116 | 'wikipage', |
||
117 | 'The wiki page to unlock', |
||
118 | true, |
||
119 | 'unlock' |
||
120 | ); |
||
121 | |||
122 | /* gmeta command */ |
||
123 | $options->registerCommand( |
||
124 | 'getmeta', |
||
125 | 'Prints metadata value for a page to stdout.' |
||
126 | ); |
||
127 | $options->registerArgument( |
||
128 | 'wikipage', |
||
129 | 'The wiki page to get the metadata for', |
||
130 | true, |
||
131 | 'getmeta' |
||
132 | ); |
||
133 | $options->registerArgument( |
||
134 | 'key', |
||
135 | 'The name of the metadata item to be retrieved.' . "\n" . |
||
136 | 'If empty, an array of all the metadata items is returned.' ."\n" . |
||
137 | 'For retrieving items that are stored in sub-arrays, separate the ' . |
||
138 | 'keys of the different levels by spaces, in quotes, eg "date modified".', |
||
139 | false, |
||
140 | 'getmeta' |
||
141 | ); |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * Your main program |
||
146 | * |
||
147 | * Arguments and options have been parsed when this is run |
||
148 | * |
||
149 | * @param Options $options |
||
150 | * @return void |
||
151 | */ |
||
152 | protected function main(Options $options) { |
||
153 | $this->force = $options->getOpt('force', false); |
||
154 | $this->username = $options->getOpt('user', $this->getUser()); |
||
155 | |||
156 | $command = $options->getCmd(); |
||
157 | $args = $options->getArgs(); |
||
158 | switch($command) { |
||
159 | case 'checkout': |
||
160 | $wiki_id = array_shift($args); |
||
161 | $localfile = array_shift($args); |
||
162 | $this->commandCheckout($wiki_id, $localfile); |
||
163 | break; |
||
164 | case 'commit': |
||
165 | $localfile = array_shift($args); |
||
166 | $wiki_id = array_shift($args); |
||
167 | $this->commandCommit( |
||
168 | $localfile, |
||
169 | $wiki_id, |
||
170 | $options->getOpt('message', ''), |
||
171 | $options->getOpt('trivial', false) |
||
172 | ); |
||
173 | break; |
||
174 | case 'lock': |
||
175 | $wiki_id = array_shift($args); |
||
176 | $this->obtainLock($wiki_id); |
||
177 | $this->success("$wiki_id locked"); |
||
178 | break; |
||
179 | case 'unlock': |
||
180 | $wiki_id = array_shift($args); |
||
181 | $this->clearLock($wiki_id); |
||
182 | $this->success("$wiki_id unlocked"); |
||
183 | break; |
||
184 | case 'getmeta': |
||
185 | $wiki_id = array_shift($args); |
||
186 | $key = trim(array_shift($args)); |
||
187 | $meta = p_get_metadata($wiki_id, $key, METADATA_RENDER_UNLIMITED); |
||
188 | echo trim(json_encode($meta, JSON_PRETTY_PRINT)); |
||
189 | echo "\n"; |
||
190 | break; |
||
191 | default: |
||
192 | echo $options->help(); |
||
193 | } |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * Check out a file |
||
198 | * |
||
199 | * @param string $wiki_id |
||
200 | * @param string $localfile |
||
201 | */ |
||
202 | protected function commandCheckout($wiki_id, $localfile) { |
||
203 | global $conf; |
||
204 | |||
205 | $wiki_id = cleanID($wiki_id); |
||
206 | $wiki_fn = wikiFN($wiki_id); |
||
207 | |||
208 | if(!file_exists($wiki_fn)) { |
||
209 | $this->fatal("$wiki_id does not yet exist"); |
||
210 | } |
||
211 | |||
212 | if(empty($localfile)) { |
||
213 | $localfile = getcwd() . '/' . \dokuwiki\Utf8\PhpString::basename($wiki_fn); |
||
214 | } |
||
215 | |||
216 | if(!file_exists(dirname($localfile))) { |
||
217 | $this->fatal("Directory " . dirname($localfile) . " does not exist"); |
||
218 | } |
||
219 | |||
220 | if(stristr(realpath(dirname($localfile)), realpath($conf['datadir'])) !== false) { |
||
221 | $this->fatal("Attempt to check out file into data directory - not allowed"); |
||
222 | } |
||
223 | |||
224 | $this->obtainLock($wiki_id); |
||
225 | |||
226 | if(!copy($wiki_fn, $localfile)) { |
||
227 | $this->clearLock($wiki_id); |
||
228 | $this->fatal("Unable to copy $wiki_fn to $localfile"); |
||
229 | } |
||
230 | |||
231 | $this->success("$wiki_id > $localfile"); |
||
232 | } |
||
233 | |||
234 | /** |
||
235 | * Save a file as a new page revision |
||
236 | * |
||
237 | * @param string $localfile |
||
238 | * @param string $wiki_id |
||
239 | * @param string $message |
||
240 | * @param bool $minor |
||
241 | */ |
||
242 | protected function commandCommit($localfile, $wiki_id, $message, $minor) { |
||
243 | $wiki_id = cleanID($wiki_id); |
||
244 | $message = trim($message); |
||
245 | |||
246 | if(!file_exists($localfile)) { |
||
247 | $this->fatal("$localfile does not exist"); |
||
248 | } |
||
249 | |||
250 | if(!is_readable($localfile)) { |
||
251 | $this->fatal("Cannot read from $localfile"); |
||
252 | } |
||
253 | |||
254 | if(!$message) { |
||
255 | $this->fatal("Summary message required"); |
||
256 | } |
||
257 | |||
258 | $this->obtainLock($wiki_id); |
||
259 | |||
260 | saveWikiText($wiki_id, file_get_contents($localfile), $message, $minor); |
||
261 | |||
262 | $this->clearLock($wiki_id); |
||
263 | |||
264 | $this->success("$localfile > $wiki_id"); |
||
265 | } |
||
266 | |||
267 | /** |
||
268 | * Lock the given page or exit |
||
269 | * |
||
270 | * @param string $wiki_id |
||
271 | */ |
||
272 | protected function obtainLock($wiki_id) { |
||
273 | if($this->force) $this->deleteLock($wiki_id); |
||
274 | |||
275 | $_SERVER['REMOTE_USER'] = $this->username; |
||
276 | |||
277 | if(checklock($wiki_id)) { |
||
278 | $this->error("Page $wiki_id is already locked by another user"); |
||
279 | exit(1); |
||
280 | } |
||
281 | |||
282 | lock($wiki_id); |
||
283 | |||
284 | if(checklock($wiki_id)) { |
||
285 | $this->error("Unable to obtain lock for $wiki_id "); |
||
286 | var_dump(checklock($wiki_id)); |
||
0 ignored issues
–
show
Security
Debugging Code
introduced
by
![]() |
|||
287 | exit(1); |
||
288 | } |
||
289 | } |
||
290 | |||
291 | /** |
||
292 | * Clear the lock on the given page |
||
293 | * |
||
294 | * @param string $wiki_id |
||
295 | */ |
||
296 | protected function clearLock($wiki_id) { |
||
297 | if($this->force) $this->deleteLock($wiki_id); |
||
298 | |||
299 | $_SERVER['REMOTE_USER'] = $this->username; |
||
300 | if(checklock($wiki_id)) { |
||
301 | $this->error("Page $wiki_id is locked by another user"); |
||
302 | exit(1); |
||
303 | } |
||
304 | |||
305 | unlock($wiki_id); |
||
306 | |||
307 | if(file_exists(wikiLockFN($wiki_id))) { |
||
308 | $this->error("Unable to clear lock for $wiki_id"); |
||
309 | exit(1); |
||
310 | } |
||
311 | } |
||
312 | |||
313 | /** |
||
314 | * Forcefully remove a lock on the page given |
||
315 | * |
||
316 | * @param string $wiki_id |
||
317 | */ |
||
318 | protected function deleteLock($wiki_id) { |
||
319 | $wikiLockFN = wikiLockFN($wiki_id); |
||
320 | |||
321 | if(file_exists($wikiLockFN)) { |
||
322 | if(!unlink($wikiLockFN)) { |
||
323 | $this->error("Unable to delete $wikiLockFN"); |
||
324 | exit(1); |
||
325 | } |
||
326 | } |
||
327 | } |
||
328 | |||
329 | /** |
||
330 | * Get the current user's username from the environment |
||
331 | * |
||
332 | * @return string |
||
333 | */ |
||
334 | protected function getUser() { |
||
335 | $user = getenv('USER'); |
||
336 | if(empty ($user)) { |
||
337 | $user = getenv('USERNAME'); |
||
338 | } else { |
||
339 | return $user; |
||
340 | } |
||
341 | if(empty ($user)) { |
||
342 | $user = 'admin'; |
||
343 | } |
||
344 | return $user; |
||
345 | } |
||
346 | } |
||
347 | |||
348 | // Main |
||
349 | $cli = new PageCLI(); |
||
350 | $cli->run(); |
||
351 |