Failed Conditions
Pull Request — master (#3361)
by
unknown
03:23
created

MediaDiff::showImageDiff()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 6
nop 5
dl 0
loc 29
rs 9.456
c 0
b 0
f 0
1
<?php
2
3
namespace dokuwiki\Ui;
4
5
use dokuwiki\ChangeLog\MediaChangeLog;
6
use dokuwiki\Extension\Event;
7
use dokuwiki\Form\Form;
8
use JpegMeta;
9
10
/**
11
 * DokuWiki MediaDiff Interface
12
 *
13
 * @package dokuwiki\Ui
14
 */
15
class MediaDiff extends Diff
16
{
17
    /**
18
     * MediaDiff Ui constructor
19
     *
20
     * @param string $id  media id
21
     */
22
    public function __construct($id)
23
    {
24
        if ($id) {
25
            throw new \InvalidArgumentException('media id should not be empty!');
26
        }
27
        $this->item = 'media';
28
29
        // init preference
30
        $this->preference['fromAjax'] = false; // see doluwiki\Ajax::callMediadiff()
31
        $this->preference['showIntro'] = false;
32
        $this->preference['difftype'] = 'both';  // media diff view type: both, opacity or portions
33
34
        parent::__construct($id);
35
    }
36
37
    /** @inheritdoc */
38
    protected function setChangeLog()
39
    {
40
        $this->changelog = new MediaChangeLog($this->id);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \dokuwiki\ChangeLog\MediaChangeLog($this->id) of type object<dokuwiki\ChangeLog\MediaChangeLog> is incompatible with the declared type object<dokuwiki\Ui\ChangeLog> of property $changelog.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
41
    }
42
43
    /** @inheritdoc */
44
    protected function preProcess()
45
    {
46
        parent::preProcess();
47
        if (!isset($this->oldRev, $this->newRev)) {
48
            // no revision was given, compare previous to current
49
            $revs = $this->changelog->getRevisions(0, 1);
50
            $this->oldRev = file_exists(mediaFN($this->id, $revs[0])) ? $revs[0] : '';
51
            $this->newRev = '';
52
        }
53
    }
54
55
    /**
56
     * Shows difference between two revisions of media
57
     *
58
     * @author Kate Arzamastseva <[email protected]>
59
     */
60
    public function show()
61
    {
62
        global $conf;
63
64
        $ns = getNS($this->id);
65
        $auth = auth_quickaclcheck("$ns:*");
66
67
        if ($auth < AUTH_READ || !$this->id || !$conf['mediarevisions']) return '';
68
69
       // determine left and right revision
70
        if (!isset($this->oldRev, $this->newRev)) $this->preProcess();
71
        [$oldRev, $newRev] = [$this->oldRev, $this->newRev];
0 ignored issues
show
Bug introduced by
The variable $oldRev seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
Bug introduced by
The variable $newRev seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
72
73
        // prepare event data
74
        // NOTE: MEDIA_DIFF event does not found in DokuWiki Event List?
75
        $data = array();
76
        $data[0] = $this->id;
77
        $data[1] = $oldRev;
0 ignored issues
show
Bug introduced by
The variable $oldRev seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
78
        $data[2] = $newRev;
0 ignored issues
show
Bug introduced by
The variable $newRev seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
79
        $data[3] = $ns;
80
        $data[4] = $auth; // permission level
81
        $data[5] = $this->preference['fromAjax'];
82
83
        // trigger event
84
        Event::createAndTrigger('MEDIA_DIFF', $data, null, false);
85
86
        if (is_array($data) && count($data) === 6) {
87
            $this->id = $data[0];
88
            $oldRev = $data[1];
89
            $newRev = $data[2];
90
            $ns     = $data[3];
0 ignored issues
show
Unused Code introduced by
$ns is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
91
            $auth   = $data[4];
92
            $this->preference['fromAjax'] = $data[5];
93
        } else {
94
            return '';
95
        }
96
97
        $oldRevMeta = new JpegMeta(mediaFN($this->id, $oldRev));
98
        $newRevMeta = new JpegMeta(mediaFN($this->id, $newRev));
99
100
        $is_img = preg_match('/\.(jpe?g|gif|png)$/', $this->id);
101
        if ($is_img) {
102
            // get image width and height for the mediamanager preview panel
103
            $oldRevSize = media_image_preview_size($this->id, $oldRev, $oldRevMeta);
104
            $newRevSize = media_image_preview_size($this->id, $newRev, $newRevMeta);
105
            // re-check image, ensure minimum image width for showImageDiff()
106
            $is_img = ($oldRevSize && $newRevSize && ($oldRevSize[0] >= 30 || $newRevSize[0] >= 30));
107
        }
108
109
        // determine requested diff view type
110
        if (!$is_img) {
111
            $this->preference['difftype'] = 'both';
112
        }
113
114
        // display intro
115
        if ($this->preference['showIntro']) echo p_locale_xhtml('diff');
116
117
        // print form to choose diff view type
118
        if ($is_img && !$this->preference['fromAjax']) {
119
            $this->showDiffViewSelector();
120
            echo '<div id="mediamanager__diff" >';
121
        }
122
123
        switch ($this->preference['difftype']) {
124
            case 'opacity':
125
            case 'portions':
126
                $this->showImageDiff($oldRev, $newRev, $oldRevSize, $newRevSize);
0 ignored issues
show
Bug introduced by
The variable $oldRevSize does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $newRevSize does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Security Bug introduced by
It seems like $oldRevSize defined by media_image_preview_size..., $oldRev, $oldRevMeta) on line 103 can also be of type false; however, dokuwiki\Ui\MediaDiff::showImageDiff() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
Security Bug introduced by
It seems like $newRevSize defined by media_image_preview_size..., $newRev, $newRevMeta) on line 104 can also be of type false; however, dokuwiki\Ui\MediaDiff::showImageDiff() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
127
                break;
128
            case 'both':
129
            default:
130
                $this->showFileDiff($oldRev, $newRev, $oldRevMeta, $newRevMeta, $auth);
131
                break;
132
        }
133
134
        if ($is_img && !$this->preference['fromAjax']) {
135
            echo '</div>';
136
        }
137
    }
138
139
    /**
140
     * Print form to choose diff view type
141
     * the dropdown is to be added through JavaScript, see lib/scripts/media.js
142
     */
143
    protected function showDiffViewSelector()
144
    {
145
        echo '<div class="diffoptions group">';
146
147
        $form = new Form([
148
            'id' => 'mediamanager__form_diffview',
149
            'action' => media_managerURL([], '&'),
150
            'method' => 'get',
151
            'class' => 'diffView',
152
        ]);
153
        $form->addTagOpen('div')->addClass('no');
154
        $form->setHiddenField('sectok', null);
155
        $form->setHiddenField('mediado', 'diff');
156
        $form->setHiddenField('rev2[0]', $this->oldRev ?: 'current');
157
        $form->setHiddenField('rev2[1]', $this->newRev ?: 'current');
158
        $form->addTagClose('div');
159
        echo $form->toHTML();
160
161
        echo '</div>'; // .diffoptions
162
    }
163
164
    /**
165
     * Prints two images side by side
166
     * and slider
167
     *
168
     * @author Kate Arzamastseva <[email protected]>
169
     *
170
     * @param string|int $oldRev revision timestamp, or empty string
171
     * @param string|int $newRev revision timestamp, or empty string
172
     * @param array  $oldRevSize  array with width and height
173
     * @param array  $newRevSize  array with width and height
174
     * @param string $type    diff view type: opacity or portions
175
     */
176
    protected function showImageDiff($oldRev, $newRev, $oldRevSize, $newRevSize, $type = null)
177
    {
178
        if (!isset($type)) {
179
            $type = $this->preference['difftype'];
180
        }
181
182
        // adjust image width, right side (newer) has priority
183
        if ($oldRevSize != $newRevSize) {
184
            if ($newRevSize[0] > $oldRevSize[0]) {
185
                $oldRevSize = $newRevSize;
186
            }
187
        }
188
189
        $oldRevSrc = ml($this->id, ['rev' => $oldRev, 'h' => $oldRevSize[1], 'w' => $oldRevSize[0]]);
190
        $newRevSrc = ml($this->id, ['rev' => $newRev, 'h' => $oldRevSize[1], 'w' => $oldRevSize[0]]);
191
192
        // slider
193
        echo '<div class="slider" style="max-width: '.($oldRevSize[0]-20).'px;" ></div>';
194
195
        // two images in divs
196
        echo '<div class="imageDiff '.$type.'">';
197
        echo '<div class="image1" style="max-width: '.$oldRevSize[0].'px;">';
198
        echo '<img src="'.$oldRevSrc.'" alt="" />';
199
        echo '</div>';
200
        echo '<div class="image2" style="max-width: '.$oldRevSize[0].'px;">';
201
        echo '<img src="'.$newRevSrc.'" alt="" />';
202
        echo '</div>';
203
        echo '</div>';
204
    }
205
206
    /**
207
     * Shows difference between two revisions of media file
208
     *
209
     * @author Kate Arzamastseva <[email protected]>
210
     *
211
     * @param string|int $oldRev revision timestamp, or empty string
212
     * @param string|int $newRev revision timestamp, or empty string
213
     * @param JpegMeta $oldRevMeta
214
     * @param JpegMeta $newRevMeta
215
     * @param int $auth permission level
216
     */
217
    protected function showFileDiff($oldRev, $newRev, $oldRevMeta, $newRevMeta, $auth)
218
    {
219
        global $lang;
220
221
        // revison info of older file (left side)
222
        $oldRevInfo = $this->getExtendedRevisionInfo($oldRev);
223
        // revison info of newer file (right side)
224
        $newRevInfo = $this->getExtendedRevisionInfo($newRev);
225
226
        // display diff view table
227
        echo '<div class="table">';
228
        echo '<table>';
229
        echo '<tr>';
230
        echo '<th>'. $this->revisionTitle($oldRevInfo) .'</th>';
231
        echo '<th>'. $this->revisionTitle($newRevInfo) .'</th>';
232
        echo '</tr>';
233
234
        echo '<tr class="image">';
235
        echo '<td>';
236
        media_preview($this->id, $auth, $oldRev, $oldRevMeta); // $auth not used in media_preview()?
237
        echo '</td>';
238
239
        echo '<td>';
240
        media_preview($this->id, $auth, $newRev, $newRevMeta);
241
        echo '</td>';
242
        echo '</tr>';
243
244
        echo '<tr class="actions">';
245
        echo '<td>';
246
        media_preview_buttons($this->id, $auth, $oldRev); // $auth used in media_preview_buttons()
247
        echo '</td>';
248
249
        echo '<td>';
250
        media_preview_buttons($this->id, $auth, $newRev);
251
        echo '</td>';
252
        echo '</tr>';
253
254
        $l_tags = media_file_tags($oldRevMeta);
255
        $r_tags = media_file_tags($newRevMeta);
256
        // FIXME r_tags-only stuff
257
        foreach ($l_tags as $key => $l_tag) {
258
            if ($l_tag['value'] != $r_tags[$key]['value']) {
259
                $r_tags[$key]['highlighted'] = true;
260
                $l_tags[$key]['highlighted'] = true;
261
            } elseif (!$l_tag['value'] || !$r_tags[$key]['value']) {
262
                unset($r_tags[$key]);
263
                unset($l_tags[$key]);
264
            }
265
        }
266
267
        echo '<tr>';
268
        foreach (array($l_tags, $r_tags) as $tags) {
269
            echo '<td>';
270
271
            echo '<dl class="img_tags">';
272
            foreach ($tags as $tag) {
273
                $value = cleanText($tag['value']);
274
                if (!$value) $value = '-';
275
                echo '<dt>'.$lang[$tag['tag'][1]].'</dt>';
276
                echo '<dd>';
277
                if ($tag['highlighted']) echo '<strong>';
278
                if ($tag['tag'][2] == 'date') {
279
                    echo dformat($value);
280
                } else {
281
                    echo hsc($value);
282
                }
283
                if ($tag['highlighted']) echo '</strong>';
284
                echo '</dd>';
285
            }
286
            echo '</dl>';
287
288
            echo '</td>';
289
        }
290
        echo '</tr>';
291
292
        echo '</table>';
293
        echo '</div>';
294
    }
295
296
    /**
297
     * Revision Title for MediaDiff table headline
298
     *
299
     * @param array $info  Revision info structure of a media file
300
     * @return string
301
     */
302
    protected function revisionTitle(array $info)
303
    {
304
        global $lang, $INFO;
305
306
        if (isset($info['date'])) {
307
            $rev = $info['date'];
308
            $title = '<bdi><a class="wikilink1" href="'.ml($this->id, ['rev' => $rev]).'">'
309
                   . dformat($rev).'</a></bdi>';
310
        } else {
311
            $rev = false;
312
            $title = '&mdash;';
313
        }
314
        if (isset($info['current']) || ($rev && $rev == $INFO['currentrev'])) {
315
            $title .= '&nbsp;('.$lang['current'].')';
316
        }
317
318
        // append separator
319
        $title .= ($this->preference['difftype'] === 'inline') ? ' ' : '<br />';
320
321
        // supplement
322
        if (isset($info['date'])) {
323
            $objRevInfo = (new MediaRevisions($this->id))->getObjRevInfo($info);
324
            $title .= $objRevInfo->editSummary().' '.$objRevInfo->editor();
325
        }
326
        return $title;
327
    }
328
329
}
330