Failed Conditions
Push — master ( 5c0b2e...874fc8 )
by Andreas
32:37 queued 29:04
created

bin/dwpage.php (2 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
#!/usr/bin/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
123
    /**
124
     * Your main program
125
     *
126
     * Arguments and options have been parsed when this is run
127
     *
128
     * @param Options $options
129
     * @return void
130
     */
131
    protected function main(Options $options) {
132
        $this->force = $options->getOpt('force', false);
133
        $this->username = $options->getOpt('user', $this->getUser());
134
135
        $command = $options->getCmd();
136
        $args = $options->getArgs();
137
        switch($command) {
138
            case 'checkout':
139
                $wiki_id = array_shift($args);
140
                $localfile = array_shift($args);
141
                $this->commandCheckout($wiki_id, $localfile);
142
                break;
143
            case 'commit':
144
                $localfile = array_shift($args);
145
                $wiki_id = array_shift($args);
146
                $this->commandCommit(
147
                    $localfile,
148
                    $wiki_id,
149
                    $options->getOpt('message', ''),
0 ignored issues
show
It seems like $options->getOpt('message', '') targeting splitbrain\phpcli\Options::getOpt() can also be of type boolean; however, PageCLI::commandCommit() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
150
                    $options->getOpt('trivial', false)
0 ignored issues
show
It seems like $options->getOpt('trivial', false) targeting splitbrain\phpcli\Options::getOpt() can also be of type string; however, PageCLI::commandCommit() does only seem to accept boolean, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
151
                );
152
                break;
153
            case 'lock':
154
                $wiki_id = array_shift($args);
155
                $this->obtainLock($wiki_id);
156
                $this->success("$wiki_id locked");
157
                break;
158
            case 'unlock':
159
                $wiki_id = array_shift($args);
160
                $this->clearLock($wiki_id);
161
                $this->success("$wiki_id unlocked");
162
                break;
163
            default:
164
                echo $options->help();
165
        }
166
    }
167
168
    /**
169
     * Check out a file
170
     *
171
     * @param string $wiki_id
172
     * @param string $localfile
173
     */
174
    protected function commandCheckout($wiki_id, $localfile) {
175
        global $conf;
176
177
        $wiki_id = cleanID($wiki_id);
178
        $wiki_fn = wikiFN($wiki_id);
179
180
        if(!file_exists($wiki_fn)) {
181
            $this->fatal("$wiki_id does not yet exist");
182
        }
183
184
        if(empty($localfile)) {
185
            $localfile = getcwd() . '/' . utf8_basename($wiki_fn);
186
        }
187
188
        if(!file_exists(dirname($localfile))) {
189
            $this->fatal("Directory " . dirname($localfile) . " does not exist");
190
        }
191
192
        if(stristr(realpath(dirname($localfile)), realpath($conf['datadir'])) !== false) {
193
            $this->fatal("Attempt to check out file into data directory - not allowed");
194
        }
195
196
        $this->obtainLock($wiki_id);
197
198
        if(!copy($wiki_fn, $localfile)) {
199
            $this->clearLock($wiki_id);
200
            $this->fatal("Unable to copy $wiki_fn to $localfile");
201
        }
202
203
        $this->success("$wiki_id > $localfile");
204
    }
205
206
    /**
207
     * Save a file as a new page revision
208
     *
209
     * @param string $localfile
210
     * @param string $wiki_id
211
     * @param string $message
212
     * @param bool $minor
213
     */
214
    protected function commandCommit($localfile, $wiki_id, $message, $minor) {
215
        $wiki_id = cleanID($wiki_id);
216
        $message = trim($message);
217
218
        if(!file_exists($localfile)) {
219
            $this->fatal("$localfile does not exist");
220
        }
221
222
        if(!is_readable($localfile)) {
223
            $this->fatal("Cannot read from $localfile");
224
        }
225
226
        if(!$message) {
227
            $this->fatal("Summary message required");
228
        }
229
230
        $this->obtainLock($wiki_id);
231
232
        saveWikiText($wiki_id, file_get_contents($localfile), $message, $minor);
233
234
        $this->clearLock($wiki_id);
235
236
        $this->success("$localfile > $wiki_id");
237
    }
238
239
    /**
240
     * Lock the given page or exit
241
     *
242
     * @param string $wiki_id
243
     */
244
    protected function obtainLock($wiki_id) {
245
        if($this->force) $this->deleteLock($wiki_id);
246
247
        $_SERVER['REMOTE_USER'] = $this->username;
248
249
        if(checklock($wiki_id)) {
250
            $this->error("Page $wiki_id is already locked by another user");
251
            exit(1);
252
        }
253
254
        lock($wiki_id);
255
256
        if(checklock($wiki_id)) {
257
            $this->error("Unable to obtain lock for $wiki_id ");
258
            var_dump(checklock($wiki_id));
259
            exit(1);
260
        }
261
    }
262
263
    /**
264
     * Clear the lock on the given page
265
     *
266
     * @param string $wiki_id
267
     */
268
    protected function clearLock($wiki_id) {
269
        if($this->force) $this->deleteLock($wiki_id);
270
271
        $_SERVER['REMOTE_USER'] = $this->username;
272
        if(checklock($wiki_id)) {
273
            $this->error("Page $wiki_id is locked by another user");
274
            exit(1);
275
        }
276
277
        unlock($wiki_id);
278
279
        if(file_exists(wikiLockFN($wiki_id))) {
280
            $this->error("Unable to clear lock for $wiki_id");
281
            exit(1);
282
        }
283
    }
284
285
    /**
286
     * Forcefully remove a lock on the page given
287
     *
288
     * @param string $wiki_id
289
     */
290
    protected function deleteLock($wiki_id) {
291
        $wikiLockFN = wikiLockFN($wiki_id);
292
293
        if(file_exists($wikiLockFN)) {
294
            if(!unlink($wikiLockFN)) {
295
                $this->error("Unable to delete $wikiLockFN");
296
                exit(1);
297
            }
298
        }
299
    }
300
301
    /**
302
     * Get the current user's username from the environment
303
     *
304
     * @return string
305
     */
306
    protected function getUser() {
307
        $user = getenv('USER');
308
        if(empty ($user)) {
309
            $user = getenv('USERNAME');
310
        } else {
311
            return $user;
312
        }
313
        if(empty ($user)) {
314
            $user = 'admin';
315
        }
316
        return $user;
317
    }
318
}
319
320
// Main
321
$cli = new PageCLI();
322
$cli->run();
323