Completed
Push — cli ( eb8d78 )
by Andreas
03:57
created

lib/plugins/extension/helper/list.php (1 issue)

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
<?php
2
/**
3
 * DokuWiki Plugin extension (Helper Component)
4
 *
5
 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6
 * @author  Michael Hamann <[email protected]>
7
 */
8
9
// must be run within Dokuwiki
10
if(!defined('DOKU_INC')) die();
11
12
/**
13
 * Class helper_plugin_extension_list takes care of creating a HTML list of extensions
14
 */
15
class helper_plugin_extension_list extends DokuWiki_Plugin {
16
    protected $form = '';
17
    /** @var  helper_plugin_extension_gui */
18
    protected $gui;
19
20
    /**
21
     * Constructor
22
     *
23
     * loads additional helpers
24
     */
25
    public function __construct(){
26
        $this->gui = plugin_load('helper', 'extension_gui');
0 ignored issues
show
Documentation Bug introduced by
It seems like plugin_load('helper', 'extension_gui') can also be of type object<DokuWiki_PluginInterface>. However, the property $gui is declared as type object<helper_plugin_extension_gui>. 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 $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account 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.

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;
}
Loading history...
27
    }
28
29
    function start_form() {
30
        $this->form .= '<form id="extension__list" accept-charset="utf-8" method="post" action="">';
31
        $hidden = array(
32
            'do'=>'admin',
33
            'page'=>'extension',
34
            'sectok'=>getSecurityToken()
35
        );
36
        $this->add_hidden($hidden);
37
        $this->form .= '<ul class="extensionList">';
38
    }
39
    /**
40
     * Build single row of extension table
41
     * @param helper_plugin_extension_extension  $extension The extension that shall be added
42
     * @param bool                               $showinfo  Show the info area
43
     */
44
    function add_row(helper_plugin_extension_extension $extension, $showinfo = false) {
45
        $this->start_row($extension);
46
        $this->populate_column('legend', $this->make_legend($extension, $showinfo));
47
        $this->populate_column('actions', $this->make_actions($extension));
48
        $this->end_row();
49
    }
50
51
    /**
52
     * Adds a header to the form
53
     *
54
     * @param string $id     The id of the header
55
     * @param string $header The content of the header
56
     * @param int    $level  The level of the header
57
     */
58
    function add_header($id, $header, $level = 2) {
59
        $this->form .='<h'.$level.' id="'.$id.'">'.hsc($header).'</h'.$level.'>'.DOKU_LF;
60
    }
61
62
    /**
63
     * Adds a paragraph to the form
64
     *
65
     * @param string $data The content
66
     */
67
    function add_p($data) {
68
        $this->form .= '<p>'.hsc($data).'</p>'.DOKU_LF;
69
    }
70
71
    /**
72
     * Add hidden fields to the form with the given data
73
     * @param array $array
74
     */
75
    function add_hidden(array $array) {
76
        $this->form .= '<div class="no">';
77
        foreach ($array as $key => $value) {
78
            $this->form .= '<input type="hidden" name="'.hsc($key).'" value="'.hsc($value).'" />';
79
        }
80
        $this->form .= '</div>'.DOKU_LF;
81
    }
82
83
    /**
84
     * Add closing tags
85
     */
86
    function end_form() {
87
        $this->form .= '</ul>';
88
        $this->form .= '</form>'.DOKU_LF;
89
    }
90
91
    /**
92
     * Show message when no results are found
93
     */
94
    function nothing_found() {
95
        global $lang;
96
        $this->form .= '<li class="notfound">'.$lang['nothingfound'].'</li>';
97
    }
98
99
    /**
100
     * Print the form
101
     */
102
    function render() {
103
        echo $this->form;
104
    }
105
106
    /**
107
     * Start the HTML for the row for the extension
108
     *
109
     * @param helper_plugin_extension_extension $extension The extension
110
     */
111
    private function start_row(helper_plugin_extension_extension $extension) {
112
        $this->form .= '<li id="extensionplugin__'.hsc($extension->getID()).'" class="'.$this->make_class($extension).'">';
113
    }
114
115
    /**
116
     * Add a column with the given class and content
117
     * @param string $class The class name
118
     * @param string $html  The content
119
     */
120
    private function populate_column($class, $html) {
121
        $this->form .= '<div class="'.$class.' col">'.$html.'</div>'.DOKU_LF;
122
    }
123
124
    /**
125
     * End the row
126
     */
127
    private function end_row() {
128
        $this->form .= '</li>'.DOKU_LF;
129
    }
130
131
    /**
132
     * Generate the link to the plugin homepage
133
     *
134
     * @param helper_plugin_extension_extension $extension The extension
135
     * @return string The HTML code
136
     */
137
    function make_homepagelink(helper_plugin_extension_extension $extension) {
138
        $text = $this->getLang('homepage_link');
139
        $url = hsc($extension->getURL());
140
        return '<a href="'.$url.'" title="'.$url.'" class ="urlextern">'.$text.'</a> ';
141
    }
142
143
    /**
144
     * Generate the class name for the row of the extensio
145
     *
146
     * @param helper_plugin_extension_extension $extension The extension object
147
     * @return string The class name
148
     */
149
    function make_class(helper_plugin_extension_extension $extension) {
150
        $class = ($extension->isTemplate()) ? 'template' : 'plugin';
151
        if($extension->isInstalled()) {
152
            $class.=' installed';
153
            $class.= ($extension->isEnabled()) ? ' enabled':' disabled';
154
            if($extension->updateAvailable()) $class .= ' updatable';
155
        }
156
        if(!$extension->canModify()) $class.= ' notselect';
157
        if($extension->isProtected()) $class.=  ' protected';
158
        //if($this->showinfo) $class.= ' showinfo';
159
        return $class;
160
    }
161
162
    /**
163
     * Generate a link to the author of the extension
164
     *
165
     * @param helper_plugin_extension_extension $extension The extension object
166
     * @return string The HTML code of the link
167
     */
168
    function make_author(helper_plugin_extension_extension $extension) {
169
        global $ID;
170
171
        if($extension->getAuthor()) {
172
173
            $mailid = $extension->getEmailID();
174
            if($mailid){
175
                $url = $this->gui->tabURL('search', array('q' => 'authorid:'.$mailid));
176
                return '<bdi><a href="'.$url.'" class="author" title="'.$this->getLang('author_hint').'" ><img src="//www.gravatar.com/avatar/'.$mailid.'?s=20&amp;d=mm" width="20" height="20" alt="" /> '.hsc($extension->getAuthor()).'</a></bdi>';
177
178
            }else{
179
                return '<bdi><span class="author">'.hsc($extension->getAuthor()).'</span></bdi>';
180
            }
181
        }
182
        return "<em class=\"author\">".$this->getLang('unknown_author')."</em>".DOKU_LF;
183
    }
184
185
    /**
186
     * Get the link and image tag for the screenshot/thumbnail
187
     *
188
     * @param helper_plugin_extension_extension $extension The extension object
189
     * @return string The HTML code
190
     */
191
    function make_screenshot(helper_plugin_extension_extension $extension) {
192
        $screen = $extension->getScreenshotURL();
193
        $thumb = $extension->getThumbnailURL();
194
195
        if($screen) {
196
            // use protocol independent URLs for images coming from us #595
197
            $screen = str_replace('http://www.dokuwiki.org', '//www.dokuwiki.org', $screen);
198
            $thumb = str_replace('http://www.dokuwiki.org', '//www.dokuwiki.org', $thumb);
199
200
            $title = sprintf($this->getLang('screenshot'), hsc($extension->getDisplayName()));
201
            $img = '<a href="'.hsc($screen).'" target="_blank" class="extension_screenshot">'.
202
                '<img alt="'.$title.'" width="120" height="70" src="'.hsc($thumb).'" />'.
203
                '</a>';
204
        } elseif($extension->isTemplate()) {
205
            $img = '<img alt="" width="120" height="70" src="'.DOKU_BASE.'lib/plugins/extension/images/template.png" />';
206
207
        } else {
208
            $img = '<img alt="" width="120" height="70" src="'.DOKU_BASE.'lib/plugins/extension/images/plugin.png" />';
209
        }
210
        return '<div class="screenshot" >'.$img.'<span></span></div>'.DOKU_LF;
211
    }
212
213
    /**
214
     * Extension main description
215
     *
216
     * @param helper_plugin_extension_extension $extension The extension object
217
     * @param bool                              $showinfo  Show the info section
218
     * @return string The HTML code
219
     */
220
    function make_legend(helper_plugin_extension_extension $extension, $showinfo = false) {
221
        $return  = '<div>';
222
        $return .= '<h2>';
223
        $return .= sprintf($this->getLang('extensionby'), '<bdi>'.hsc($extension->getDisplayName()).'</bdi>', $this->make_author($extension));
224
        $return .= '</h2>'.DOKU_LF;
225
226
        $return .= $this->make_screenshot($extension);
227
228
        $popularity = $extension->getPopularity();
229
        if ($popularity !== false && !$extension->isBundled()) {
230
            $popularityText = sprintf($this->getLang('popularity'), round($popularity*100, 2));
231
            $return .= '<div class="popularity" title="'.$popularityText.'"><div style="width: '.($popularity * 100).'%;"><span class="a11y">'.$popularityText.'</span></div></div>'.DOKU_LF;
232
        }
233
234
        if($extension->getDescription()) {
235
            $return .= '<p><bdi>';
236
            $return .=  hsc($extension->getDescription()).' ';
237
            $return .= '</bdi></p>'.DOKU_LF;
238
        }
239
240
        $return .= $this->make_linkbar($extension);
241
242
        if($showinfo){
243
            $url = $this->gui->tabURL('');
244
            $class = 'close';
245
        }else{
246
            $url = $this->gui->tabURL('', array('info' => $extension->getID()));
247
            $class = '';
248
        }
249
        $return .= ' <a href="'.$url.'#extensionplugin__'.$extension->getID().'" class="info '.$class.'" title="'.$this->getLang('btn_info').'" data-extid="'.$extension->getID().'">'.$this->getLang('btn_info').'</a>';
250
251
        if ($showinfo) {
252
            $return .= $this->make_info($extension);
253
        }
254
        $return .= $this->make_noticearea($extension);
255
        $return .= '</div>'.DOKU_LF;
256
        return $return;
257
    }
258
259
    /**
260
     * Generate the link bar HTML code
261
     *
262
     * @param helper_plugin_extension_extension $extension The extension instance
263
     * @return string The HTML code
264
     */
265
    function make_linkbar(helper_plugin_extension_extension $extension) {
266
        $return  = '<div class="linkbar">';
267
        $return .= $this->make_homepagelink($extension);
268
        if ($extension->getBugtrackerURL()) {
269
            $return .= ' <a href="'.hsc($extension->getBugtrackerURL()).'" title="'.hsc($extension->getBugtrackerURL()).'" class ="bugs">'.$this->getLang('bugs_features').'</a> ';
270
        }
271
        if ($extension->getTags()){
272
            $first = true;
273
            $return .= '<span class="tags">'.$this->getLang('tags').' ';
274
            foreach ($extension->getTags() as $tag) {
275
                if (!$first){
276
                    $return .= ', ';
277
                } else {
278
                    $first = false;
279
                }
280
                $url = $this->gui->tabURL('search', array('q' => 'tag:'.$tag));
281
                $return .= '<bdi><a href="'.$url.'">'.hsc($tag).'</a></bdi>';
282
            }
283
            $return .= '</span>';
284
        }
285
        $return .= '</div>'.DOKU_LF;
286
        return $return;
287
    }
288
289
    /**
290
     * Notice area
291
     *
292
     * @param helper_plugin_extension_extension $extension The extension
293
     * @return string The HTML code
294
     */
295
    function make_noticearea(helper_plugin_extension_extension $extension) {
296
        $return = '';
297
        $missing_dependencies = $extension->getMissingDependencies();
298
        if(!empty($missing_dependencies)) {
299
            $return .= '<div class="msg error">'.
300
                sprintf($this->getLang('missing_dependency'), '<bdi>'.implode(', ', /*array_map(array($this->helper, 'make_extensionsearchlink'),*/ $missing_dependencies).'</bdi>').
301
                '</div>';
302
        }
303
        if($extension->isInWrongFolder()) {
304
            $return .= '<div class="msg error">'.
305
                sprintf($this->getLang('wrong_folder'), '<bdi>'.hsc($extension->getInstallName()).'</bdi>', '<bdi>'.hsc($extension->getBase()).'</bdi>').
306
                '</div>';
307
        }
308
        if(($securityissue = $extension->getSecurityIssue()) !== false) {
309
            $return .= '<div class="msg error">'.
310
                sprintf($this->getLang('security_issue'), '<bdi>'.hsc($securityissue).'</bdi>').
311
                '</div>';
312
        }
313
        if(($securitywarning = $extension->getSecurityWarning()) !== false) {
314
            $return .= '<div class="msg notify">'.
315
                sprintf($this->getLang('security_warning'), '<bdi>'.hsc($securitywarning).'</bdi>').
316
                '</div>';
317
        }
318
        if($extension->updateAvailable()) {
319
            $return .=  '<div class="msg notify">'.
320
                sprintf($this->getLang('update_available'), hsc($extension->getLastUpdate())).
321
                '</div>';
322
        }
323
        if($extension->hasDownloadURLChanged()) {
324
            $return .=  '<div class="msg notify">'.
325
                sprintf($this->getLang('url_change'), '<bdi>'.hsc($extension->getDownloadURL()).'</bdi>', '<bdi>'.hsc($extension->getLastDownloadURL()).'</bdi>').
326
                '</div>';
327
        }
328
        return $return.DOKU_LF;
329
    }
330
331
    /**
332
     * Create a link from the given URL
333
     *
334
     * Shortens the URL for display
335
     *
336
     * @param string $url
337
     * @return string  HTML link
338
     */
339
    function shortlink($url){
340
        $link = parse_url($url);
341
342
        $base = $link['host'];
343
        if(!empty($link['port'])) $base .= $base.':'.$link['port'];
344
        $long = $link['path'];
345
        if(!empty($link['query'])) $long .= $link['query'];
346
347
        $name = shorten($base, $long, 55);
348
349
        return '<a href="'.hsc($url).'" class="urlextern">'.hsc($name).'</a>';
350
    }
351
352
    /**
353
     * Plugin/template details
354
     *
355
     * @param helper_plugin_extension_extension $extension The extension
356
     * @return string The HTML code
357
     */
358
    function make_info(helper_plugin_extension_extension $extension) {
359
        $default = $this->getLang('unknown');
360
        $return = '<dl class="details">';
361
362
        $return .= '<dt>'.$this->getLang('status').'</dt>';
363
        $return .= '<dd>'.$this->make_status($extension).'</dd>';
364
365
        if ($extension->getDonationURL()) {
366
            $return .= '<dt>'.$this->getLang('donate').'</dt>';
367
            $return .= '<dd>';
368
            $return .= '<a href="'.$extension->getDonationURL().'" class="donate">'.$this->getLang('donate_action').'</a>';
369
            $return .= '</dd>';
370
        }
371
372
        if (!$extension->isBundled()) {
373
            $return .= '<dt>'.$this->getLang('downloadurl').'</dt>';
374
            $return .= '<dd><bdi>';
375
            $return .= ($extension->getDownloadURL() ? $this->shortlink($extension->getDownloadURL()) : $default);
376
            $return .= '</bdi></dd>';
377
378
            $return .= '<dt>'.$this->getLang('repository').'</dt>';
379
            $return .= '<dd><bdi>';
380
            $return .= ($extension->getSourcerepoURL() ? $this->shortlink($extension->getSourcerepoURL()) : $default);
381
            $return .= '</bdi></dd>';
382
        }
383
384
        if ($extension->isInstalled()) {
385
            if ($extension->getInstalledVersion()) {
386
                $return .= '<dt>'.$this->getLang('installed_version').'</dt>';
387
                $return .= '<dd>';
388
                $return .= hsc($extension->getInstalledVersion());
389
                $return .= '</dd>';
390
            }
391
            if (!$extension->isBundled()) {
392
                $return .= '<dt>'.$this->getLang('install_date').'</dt>';
393
                $return .= '<dd>';
394
                $return .= ($extension->getUpdateDate() ? hsc($extension->getUpdateDate()) : $this->getLang('unknown'));
395
                $return .= '</dd>';
396
            }
397
        }
398
        if (!$extension->isInstalled() || $extension->updateAvailable()) {
399
            $return .= '<dt>'.$this->getLang('available_version').'</dt>';
400
            $return .= '<dd>';
401
            $return .= ($extension->getLastUpdate() ? hsc($extension->getLastUpdate()) : $this->getLang('unknown'));
402
            $return .= '</dd>';
403
        }
404
405
        $return .= '<dt>'.$this->getLang('provides').'</dt>';
406
        $return .= '<dd><bdi>';
407
        $return .= ($extension->getTypes() ? hsc(implode(', ', $extension->getTypes())) : $default);
408
        $return .= '</bdi></dd>';
409
410
        if(!$extension->isBundled() && $extension->getCompatibleVersions()) {
411
            $return .= '<dt>'.$this->getLang('compatible').'</dt>';
412
            $return .= '<dd>';
413
            foreach ($extension->getCompatibleVersions() as $date => $version) {
414
                $return .= '<bdi>'.$version['label'].' ('.$date.')</bdi>, ';
415
            }
416
            $return = rtrim($return, ', ');
417
            $return .= '</dd>';
418
        }
419
        if($extension->getDependencies()) {
420
            $return .= '<dt>'.$this->getLang('depends').'</dt>';
421
            $return .= '<dd>';
422
            $return .= $this->make_linklist($extension->getDependencies());
423
            $return .= '</dd>';
424
        }
425
426
        if($extension->getSimilarExtensions()) {
427
            $return .= '<dt>'.$this->getLang('similar').'</dt>';
428
            $return .= '<dd>';
429
            $return .= $this->make_linklist($extension->getSimilarExtensions());
430
            $return .= '</dd>';
431
        }
432
433
        if($extension->getConflicts()) {
434
            $return .= '<dt>'.$this->getLang('conflicts').'</dt>';
435
            $return .= '<dd>';
436
            $return .= $this->make_linklist($extension->getConflicts());
437
            $return .= '</dd>';
438
        }
439
        $return .= '</dl>'.DOKU_LF;
440
        return $return;
441
    }
442
443
    /**
444
     * Generate a list of links for extensions
445
     *
446
     * @param array $ext The extensions
447
     * @return string The HTML code
448
     */
449
    function make_linklist($ext) {
450
        $return = '';
451
        foreach ($ext as $link) {
452
            $return .= '<bdi><a href="'.$this->gui->tabURL('search', array('q'=>'ext:'.$link)).'">'.hsc($link).'</a></bdi>, ';
453
        }
454
        return rtrim($return, ', ');
455
    }
456
457
    /**
458
     * Display the action buttons if they are possible
459
     *
460
     * @param helper_plugin_extension_extension $extension The extension
461
     * @return string The HTML code
462
     */
463
    function make_actions(helper_plugin_extension_extension $extension) {
464
        global $conf;
465
        $return = '';
466
        $errors = '';
467
468
        if ($extension->isInstalled()) {
469
            if (($canmod = $extension->canModify()) === true) {
470
                if (!$extension->isProtected()) {
471
                    $return .= $this->make_action('uninstall', $extension);
472
                }
473
                if ($extension->getDownloadURL()) {
474
                    if ($extension->updateAvailable()) {
475
                        $return .= $this->make_action('update', $extension);
476
                    } else {
477
                        $return .= $this->make_action('reinstall', $extension);
478
                    }
479
                }
480
            }else{
481
                $errors .= '<p class="permerror">'.$this->getLang($canmod).'</p>';
482
            }
483
484
            if (!$extension->isProtected() && !$extension->isTemplate()) { // no enable/disable for templates
485
                if ($extension->isEnabled()) {
486
                    $return .= $this->make_action('disable', $extension);
487
                } else {
488
                    $return .= $this->make_action('enable', $extension);
489
                }
490
            }
491
492
            if ($extension->isGitControlled()){
493
                $errors .= '<p class="permerror">'.$this->getLang('git').'</p>';
494
            }
495
496
            if ($extension->isEnabled() && in_array('Auth', $extension->getTypes()) && $conf['authtype'] != $extension->getID()) {
497
                $errors .= '<p class="permerror">'.$this->getLang('auth').'</p>';
498
            }
499
500
        }else{
501
            if (($canmod = $extension->canModify()) === true) {
502
                if ($extension->getDownloadURL()) {
503
                    $return .= $this->make_action('install', $extension);
504
                }
505
            }else{
506
                $errors .= '<div class="permerror">'.$this->getLang($canmod).'</div>';
507
            }
508
        }
509
510
        if (!$extension->isInstalled() && $extension->getDownloadURL()) {
511
            $return .= ' <span class="version">'.$this->getLang('available_version').' ';
512
            $return .= ($extension->getLastUpdate() ? hsc($extension->getLastUpdate()) : $this->getLang('unknown')).'</span>';
513
        }
514
515
        return $return.' '.$errors.DOKU_LF;
516
    }
517
518
    /**
519
     * Display an action button for an extension
520
     *
521
     * @param string                            $action    The action
522
     * @param helper_plugin_extension_extension $extension The extension
523
     * @return string The HTML code
524
     */
525
    function make_action($action, $extension) {
526
        $title = '';
527
528
        switch ($action) {
529
            case 'install':
530
            case 'reinstall':
531
                $title = 'title="'.hsc($extension->getDownloadURL()).'"';
532
                break;
533
        }
534
535
        $classes = 'button '.$action;
536
        $name    = 'fn['.$action.']['.hsc($extension->getID()).']';
537
538
        return '<button class="'.$classes.'" name="'.$name.'" type="submit" '.$title.'>'.$this->getLang('btn_'.$action).'</button> ';
539
    }
540
541
    /**
542
     * Plugin/template status
543
     *
544
     * @param helper_plugin_extension_extension $extension The extension
545
     * @return string The description of all relevant statusses
546
     */
547
    function make_status(helper_plugin_extension_extension $extension) {
548
        $status = array();
549
550
551
        if ($extension->isInstalled()) {
552
            $status[] = $this->getLang('status_installed');
553
            if ($extension->isProtected()) {
554
                $status[] = $this->getLang('status_protected');
555
            } else {
556
                $status[] = $extension->isEnabled() ? $this->getLang('status_enabled') : $this->getLang('status_disabled');
557
            }
558
        } else {
559
            $status[] = $this->getLang('status_not_installed');
560
        }
561
        if(!$extension->canModify()) $status[] = $this->getLang('status_unmodifiable');
562
        if($extension->isBundled()) $status[] = $this->getLang('status_bundled');
563
        $status[] = $extension->isTemplate() ? $this->getLang('status_template') : $this->getLang('status_plugin');
564
        return join(', ', $status);
565
    }
566
567
}
568