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); |
||
0 ignored issues
–
show
|
|||
154 | $this->username = $options->getOpt('user', $this->getUser()); |
||
0 ignored issues
–
show
It seems like
$options->getOpt('user', $this->getUser()) can also be of type boolean or array<integer,string> . However, the property $username is declared as type string . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
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
|
|||
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 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.