Failed Conditions
Push — master ( 8a0050...038768 )
by Andreas
08:58 queued 05:45
created

Doku_Handler::doublequoteopening()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 3
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
if(!defined('DOKU_INC')) die('meh.');
3
if (!defined('DOKU_PARSER_EOL')) define('DOKU_PARSER_EOL',"\n");   // add this to make handling test cases simpler
4
5
class Doku_Handler {
6
7
    var $Renderer = null;
8
9
    var $CallWriter = null;
10
11
    var $calls = array();
12
13
    var $status = array(
14
        'section' => false,
15
        'doublequote' => 0,
16
    );
17
18
    var $rewriteBlocks = true;
19
20
    function __construct() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
21
        $this->CallWriter = new Doku_Handler_CallWriter($this);
22
    }
23
24
    /**
25
     * @param string $handler
26
     * @param mixed $args
27
     * @param integer|string $pos
28
     */
29
    function _addCall($handler, $args, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
30
        $call = array($handler,$args, $pos);
31
        $this->CallWriter->writeCall($call);
32
    }
33
34
    function addPluginCall($plugin, $args, $state, $pos, $match) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
35
        $call = array('plugin',array($plugin, $args, $state, $match), $pos);
36
        $this->CallWriter->writeCall($call);
37
    }
38
39
    function _finalize(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
40
41
        $this->CallWriter->finalise();
42
43
        if ( $this->status['section'] ) {
44
            $last_call = end($this->calls);
45
            array_push($this->calls,array('section_close',array(), $last_call[2]));
46
        }
47
48
        if ( $this->rewriteBlocks ) {
49
            $B = new Doku_Handler_Block();
50
            $this->calls = $B->process($this->calls);
51
        }
52
53
        trigger_event('PARSER_HANDLER_DONE',$this);
54
55
        array_unshift($this->calls,array('document_start',array(),0));
56
        $last_call = end($this->calls);
57
        array_push($this->calls,array('document_end',array(),$last_call[2]));
58
    }
59
60
    /**
61
     * fetch the current call and advance the pointer to the next one
62
     *
63
     * @return bool|mixed
64
     */
65
    function fetch() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
66
        $call = current($this->calls);
67
        if($call !== false) {
68
            next($this->calls); //advance the pointer
69
            return $call;
70
        }
71
        return false;
72
    }
73
74
75
    /**
76
     * Special plugin handler
77
     *
78
     * This handler is called for all modes starting with 'plugin_'.
79
     * An additional parameter with the plugin name is passed
80
     *
81
     * @author Andreas Gohr <[email protected]>
82
     *
83
     * @param string|integer $match
84
     * @param string|integer $state
85
     * @param integer $pos
86
     * @param $pluginname
87
     *
88
     * @return bool
89
     */
90
    function plugin($match, $state, $pos, $pluginname){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
91
        $data = array($match);
92
        /** @var DokuWiki_Syntax_Plugin $plugin */
93
        $plugin = plugin_load('syntax',$pluginname);
94
        if($plugin != null){
95
            $data = $plugin->handle($match, $state, $pos, $this);
96
        }
97
        if ($data !== false) {
98
            $this->addPluginCall($pluginname,$data,$state,$pos,$match);
99
        }
100
        return true;
101
    }
102
103
    function base($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
104
        switch ( $state ) {
105
            case DOKU_LEXER_UNMATCHED:
106
                $this->_addCall('cdata',array($match), $pos);
107
                return true;
108
            break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
109
        }
110
    }
111
112
    function header($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
113
        // get level and title
114
        $title = trim($match);
115
        $level = 7 - strspn($title,'=');
116
        if($level < 1) $level = 1;
117
        $title = trim($title,'=');
118
        $title = trim($title);
119
120
        if ($this->status['section']) $this->_addCall('section_close',array(),$pos);
121
122
        $this->_addCall('header',array($title,$level,$pos), $pos);
123
124
        $this->_addCall('section_open',array($level),$pos);
125
        $this->status['section'] = true;
126
        return true;
127
    }
128
129
    function notoc($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
130
        $this->_addCall('notoc',array(),$pos);
131
        return true;
132
    }
133
134
    function nocache($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
135
        $this->_addCall('nocache',array(),$pos);
136
        return true;
137
    }
138
139
    function linebreak($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
140
        $this->_addCall('linebreak',array(),$pos);
141
        return true;
142
    }
143
144
    function eol($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
145
        $this->_addCall('eol',array(),$pos);
146
        return true;
147
    }
148
149
    function hr($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
150
        $this->_addCall('hr',array(),$pos);
151
        return true;
152
    }
153
154
    /**
155
     * @param string|integer $match
156
     * @param string|integer $state
157
     * @param integer $pos
158
     * @param string $name
159
     */
160
    function _nestingTag($match, $state, $pos, $name) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
161
        switch ( $state ) {
162
            case DOKU_LEXER_ENTER:
163
                $this->_addCall($name.'_open', array(), $pos);
164
            break;
165
            case DOKU_LEXER_EXIT:
166
                $this->_addCall($name.'_close', array(), $pos);
167
            break;
168
            case DOKU_LEXER_UNMATCHED:
169
                $this->_addCall('cdata',array($match), $pos);
170
            break;
171
        }
172
    }
173
174
    function strong($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
175
        $this->_nestingTag($match, $state, $pos, 'strong');
176
        return true;
177
    }
178
179
    function emphasis($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
180
        $this->_nestingTag($match, $state, $pos, 'emphasis');
181
        return true;
182
    }
183
184
    function underline($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
185
        $this->_nestingTag($match, $state, $pos, 'underline');
186
        return true;
187
    }
188
189
    function monospace($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
190
        $this->_nestingTag($match, $state, $pos, 'monospace');
191
        return true;
192
    }
193
194
    function subscript($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
195
        $this->_nestingTag($match, $state, $pos, 'subscript');
196
        return true;
197
    }
198
199
    function superscript($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
200
        $this->_nestingTag($match, $state, $pos, 'superscript');
201
        return true;
202
    }
203
204
    function deleted($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
205
        $this->_nestingTag($match, $state, $pos, 'deleted');
206
        return true;
207
    }
208
209
210
    function footnote($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
211
//        $this->_nestingTag($match, $state, $pos, 'footnote');
212
        if (!isset($this->_footnote)) $this->_footnote = false;
0 ignored issues
show
Bug introduced by
The property _footnote does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
213
214
        switch ( $state ) {
215
            case DOKU_LEXER_ENTER:
216
                // footnotes can not be nested - however due to limitations in lexer it can't be prevented
217
                // we will still enter a new footnote mode, we just do nothing
218
                if ($this->_footnote) {
219
                    $this->_addCall('cdata',array($match), $pos);
220
                    break;
221
                }
222
223
                $this->_footnote = true;
224
225
                $ReWriter = new Doku_Handler_Nest($this->CallWriter,'footnote_close');
226
                $this->CallWriter = & $ReWriter;
227
                $this->_addCall('footnote_open', array(), $pos);
228
            break;
229
            case DOKU_LEXER_EXIT:
230
                // check whether we have already exitted the footnote mode, can happen if the modes were nested
231
                if (!$this->_footnote) {
232
                    $this->_addCall('cdata',array($match), $pos);
233
                    break;
234
                }
235
236
                $this->_footnote = false;
237
238
                $this->_addCall('footnote_close', array(), $pos);
239
                $this->CallWriter->process();
0 ignored issues
show
Bug introduced by
The method process() does not seem to exist on object<Doku_Handler_CallWriter>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
240
                $ReWriter = & $this->CallWriter;
241
                $this->CallWriter = & $ReWriter->CallWriter;
0 ignored issues
show
Bug introduced by
The property CallWriter does not seem to exist in Doku_Handler_CallWriter.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
242
            break;
243
            case DOKU_LEXER_UNMATCHED:
244
                $this->_addCall('cdata', array($match), $pos);
245
            break;
246
        }
247
        return true;
248
    }
249
250
    function listblock($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
251
        switch ( $state ) {
252
            case DOKU_LEXER_ENTER:
253
                $ReWriter = new Doku_Handler_List($this->CallWriter);
254
                $this->CallWriter = & $ReWriter;
255
                $this->_addCall('list_open', array($match), $pos);
256
            break;
257
            case DOKU_LEXER_EXIT:
258
                $this->_addCall('list_close', array(), $pos);
259
                $this->CallWriter->process();
0 ignored issues
show
Bug introduced by
The method process does only exist in Doku_Handler_Nest, but not in Doku_Handler_CallWriter.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
260
                $ReWriter = & $this->CallWriter;
261
                $this->CallWriter = & $ReWriter->CallWriter;
262
            break;
263
            case DOKU_LEXER_MATCHED:
264
                $this->_addCall('list_item', array($match), $pos);
265
            break;
266
            case DOKU_LEXER_UNMATCHED:
267
                $this->_addCall('cdata', array($match), $pos);
268
            break;
269
        }
270
        return true;
271
    }
272
273
    function unformatted($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
274
        if ( $state == DOKU_LEXER_UNMATCHED ) {
275
            $this->_addCall('unformatted',array($match), $pos);
276
        }
277
        return true;
278
    }
279
280
    function php($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
281
        global $conf;
282
        if ( $state == DOKU_LEXER_UNMATCHED ) {
283
            $this->_addCall('php',array($match), $pos);
284
        }
285
        return true;
286
    }
287
288
    function phpblock($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
289
        global $conf;
290
        if ( $state == DOKU_LEXER_UNMATCHED ) {
291
            $this->_addCall('phpblock',array($match), $pos);
292
        }
293
        return true;
294
    }
295
296
    function html($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
297
        global $conf;
298
        if ( $state == DOKU_LEXER_UNMATCHED ) {
299
            $this->_addCall('html',array($match), $pos);
300
        }
301
        return true;
302
    }
303
304
    function htmlblock($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
305
        global $conf;
306
        if ( $state == DOKU_LEXER_UNMATCHED ) {
307
            $this->_addCall('htmlblock',array($match), $pos);
308
        }
309
        return true;
310
    }
311
312
    function preformatted($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
313
        switch ( $state ) {
314
            case DOKU_LEXER_ENTER:
315
                $ReWriter = new Doku_Handler_Preformatted($this->CallWriter);
316
                $this->CallWriter = $ReWriter;
317
                $this->_addCall('preformatted_start',array(), $pos);
318
            break;
319
            case DOKU_LEXER_EXIT:
320
                $this->_addCall('preformatted_end',array(), $pos);
321
                $this->CallWriter->process();
0 ignored issues
show
Bug introduced by
The method process does only exist in Doku_Handler_List and Doku_Handler_Nest, but not in Doku_Handler_CallWriter.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
322
                $ReWriter = & $this->CallWriter;
323
                $this->CallWriter = & $ReWriter->CallWriter;
324
            break;
325
            case DOKU_LEXER_MATCHED:
326
                $this->_addCall('preformatted_newline',array(), $pos);
327
            break;
328
            case DOKU_LEXER_UNMATCHED:
329
                $this->_addCall('preformatted_content',array($match), $pos);
330
            break;
331
        }
332
333
        return true;
334
    }
335
336
    function quote($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
337
338
        switch ( $state ) {
339
340
            case DOKU_LEXER_ENTER:
341
                $ReWriter = new Doku_Handler_Quote($this->CallWriter);
342
                $this->CallWriter = & $ReWriter;
343
                $this->_addCall('quote_start',array($match), $pos);
344
            break;
345
346
            case DOKU_LEXER_EXIT:
347
                $this->_addCall('quote_end',array(), $pos);
348
                $this->CallWriter->process();
0 ignored issues
show
Bug introduced by
The method process does only exist in Doku_Handler_List and Do...ku_Handler_Preformatted, but not in Doku_Handler_CallWriter.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
349
                $ReWriter = & $this->CallWriter;
350
                $this->CallWriter = & $ReWriter->CallWriter;
351
            break;
352
353
            case DOKU_LEXER_MATCHED:
354
                $this->_addCall('quote_newline',array($match), $pos);
355
            break;
356
357
            case DOKU_LEXER_UNMATCHED:
358
                $this->_addCall('cdata',array($match), $pos);
359
            break;
360
361
        }
362
363
        return true;
364
    }
365
366
    /**
367
     * Internal function for parsing highlight options.
368
     * $options is parsed for key value pairs separated by commas.
369
     * A value might also be missing in which case the value will simple
370
     * be set to true. Commas in strings are ignored, e.g. option="4,56"
371
     * will work as expected and will only create one entry.
372
     *
373
     * @param string $options space separated list of key-value pairs,
374
     *                        e.g. option1=123, option2="456"
375
     * @return array|null     Array of key-value pairs $array['key'] = 'value';
376
     *                        or null if no entries found
377
     */
378
    protected function parse_highlight_options ($options) {
379
        $result = array();
380
        preg_match_all('/(\w+(?:="[^"]*"))|(\w+(?:=[^\s]*))|(\w+[^=\s\]])(?:\s*)/', $options, $matches, PREG_SET_ORDER);
381
        foreach ($matches as $match) {
0 ignored issues
show
Bug introduced by
The expression $matches of type null|array<integer,array<integer,string>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
382
            $equal_sign = strpos($match [0], '=');
383
            if ($equal_sign === false) {
384
                $key = trim($match[0]);
385
                $result [$key] = 1;
386
            } else {
387
                $key = substr($match[0], 0, $equal_sign);
388
                $value = substr($match[0], $equal_sign+1);
389
                $value = trim($value, '"');
390
                if (strlen($value) > 0) {
391
                    $result [$key] = $value;
392
                } else {
393
                    $result [$key] = 1;
394
                }
395
            }
396
        }
397
398
        // Check for supported options
399
        $result = array_intersect_key(
400
            $result,
401
            array_flip(array(
402
                'enable_line_numbers',
403
                'start_line_numbers_at',
404
                'highlight_lines_extra',
405
                'enable_keyword_links')
406
            )
407
        );
408
409
        // Sanitize values
410
        if(isset($result['enable_line_numbers'])) {
411
            if($result['enable_line_numbers'] === 'false') {
412
                $result['enable_line_numbers'] = false;
413
            }
414
            $result['enable_line_numbers'] = (bool) $result['enable_line_numbers'];
415
        }
416
        if(isset($result['highlight_lines_extra'])) {
417
            $result['highlight_lines_extra'] = array_map('intval', explode(',', $result['highlight_lines_extra']));
418
            $result['highlight_lines_extra'] = array_filter($result['highlight_lines_extra']);
419
            $result['highlight_lines_extra'] = array_unique($result['highlight_lines_extra']);
420
        }
421
        if(isset($result['start_line_numbers_at'])) {
422
            $result['start_line_numbers_at'] = (int) $result['start_line_numbers_at'];
423
        }
424
        if(isset($result['enable_keyword_links'])) {
425
            if($result['enable_keyword_links'] === 'false') {
426
                $result['enable_keyword_links'] = false;
427
            }
428
            $result['enable_keyword_links'] = (bool) $result['enable_keyword_links'];
429
        }
430
        if (count($result) == 0) {
431
            return null;
432
        }
433
434
        return $result;
435
    }
436
437
    function file($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
438
        return $this->code($match, $state, $pos, 'file');
439
    }
440
441
    function code($match, $state, $pos, $type='code') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
442
        if ( $state == DOKU_LEXER_UNMATCHED ) {
443
            $matches = explode('>',$match,2);
444
            // Cut out variable options enclosed in []
445
            preg_match('/\[.*\]/', $matches[0], $options);
446
            if (!empty($options[0])) {
447
                $matches[0] = str_replace($options[0], '', $matches[0]);
448
            }
449
            $param = preg_split('/\s+/', $matches[0], 2, PREG_SPLIT_NO_EMPTY);
450
            while(count($param) < 2) array_push($param, null);
451
            // We shortcut html here.
452
            if ($param[0] == 'html') $param[0] = 'html4strict';
453
            if ($param[0] == '-') $param[0] = null;
454
            array_unshift($param, $matches[1]);
455
            if (!empty($options[0])) {
456
                $param [] = $this->parse_highlight_options ($options[0]);
457
            }
458
            $this->_addCall($type, $param, $pos);
459
        }
460
        return true;
461
    }
462
463
    function acronym($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
464
        $this->_addCall('acronym',array($match), $pos);
465
        return true;
466
    }
467
468
    function smiley($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
469
        $this->_addCall('smiley',array($match), $pos);
470
        return true;
471
    }
472
473
    function wordblock($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
474
        $this->_addCall('wordblock',array($match), $pos);
475
        return true;
476
    }
477
478
    function entity($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
479
        $this->_addCall('entity',array($match), $pos);
480
        return true;
481
    }
482
483
    function multiplyentity($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
484
        preg_match_all('/\d+/',$match,$matches);
485
        $this->_addCall('multiplyentity',array($matches[0][0],$matches[0][1]), $pos);
486
        return true;
487
    }
488
489
    function singlequoteopening($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
490
        $this->_addCall('singlequoteopening',array(), $pos);
491
        return true;
492
    }
493
494
    function singlequoteclosing($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
495
        $this->_addCall('singlequoteclosing',array(), $pos);
496
        return true;
497
    }
498
499
    function apostrophe($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
500
        $this->_addCall('apostrophe',array(), $pos);
501
        return true;
502
    }
503
504
    function doublequoteopening($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
505
        $this->_addCall('doublequoteopening',array(), $pos);
506
        $this->status['doublequote']++;
507
        return true;
508
    }
509
510
    function doublequoteclosing($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
511
        if ($this->status['doublequote'] <= 0) {
512
            $this->doublequoteopening($match, $state, $pos);
513
        } else {
514
            $this->_addCall('doublequoteclosing',array(), $pos);
515
            $this->status['doublequote'] = max(0, --$this->status['doublequote']);
516
        }
517
        return true;
518
    }
519
520
    function camelcaselink($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
521
        $this->_addCall('camelcaselink',array($match), $pos);
522
        return true;
523
    }
524
525
    /*
526
    */
527
    function internallink($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
528
        // Strip the opening and closing markup
529
        $link = preg_replace(array('/^\[\[/','/\]\]$/u'),'',$match);
530
531
        // Split title from URL
532
        $link = explode('|',$link,2);
533
        if ( !isset($link[1]) ) {
534
            $link[1] = null;
535
        } else if ( preg_match('/^\{\{[^\}]+\}\}$/',$link[1]) ) {
536
            // If the title is an image, convert it to an array containing the image details
537
            $link[1] = Doku_Handler_Parse_Media($link[1]);
538
        }
539
        $link[0] = trim($link[0]);
540
541
        //decide which kind of link it is
542
543
        if ( link_isinterwiki($link[0]) ) {
544
            // Interwiki
545
            $interwiki = explode('>',$link[0],2);
546
            $this->_addCall(
547
                'interwikilink',
548
                array($link[0],$link[1],strtolower($interwiki[0]),$interwiki[1]),
549
                $pos
550
                );
551
        }elseif ( preg_match('/^\\\\\\\\[^\\\\]+?\\\\/u',$link[0]) ) {
552
            // Windows Share
553
            $this->_addCall(
554
                'windowssharelink',
555
                array($link[0],$link[1]),
556
                $pos
557
                );
558
        }elseif ( preg_match('#^([a-z0-9\-\.+]+?)://#i',$link[0]) ) {
559
            // external link (accepts all protocols)
560
            $this->_addCall(
561
                    'externallink',
562
                    array($link[0],$link[1]),
563
                    $pos
564
                    );
565
        }elseif ( preg_match('<'.PREG_PATTERN_VALID_EMAIL.'>',$link[0]) ) {
566
            // E-Mail (pattern above is defined in inc/mail.php)
567
            $this->_addCall(
568
                'emaillink',
569
                array($link[0],$link[1]),
570
                $pos
571
                );
572
        }elseif ( preg_match('!^#.+!',$link[0]) ){
573
            // local link
574
            $this->_addCall(
575
                'locallink',
576
                array(substr($link[0],1),$link[1]),
577
                $pos
578
                );
579
        }else{
580
            // internal link
581
            $this->_addCall(
582
                'internallink',
583
                array($link[0],$link[1]),
584
                $pos
585
                );
586
        }
587
588
        return true;
589
    }
590
591
    function filelink($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
592
        $this->_addCall('filelink',array($match, null), $pos);
593
        return true;
594
    }
595
596
    function windowssharelink($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
597
        $this->_addCall('windowssharelink',array($match, null), $pos);
598
        return true;
599
    }
600
601
    function media($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
602
        $p = Doku_Handler_Parse_Media($match);
603
604
        $this->_addCall(
605
              $p['type'],
606
              array($p['src'], $p['title'], $p['align'], $p['width'],
607
                     $p['height'], $p['cache'], $p['linking']),
608
              $pos
609
             );
610
        return true;
611
    }
612
613
    function rss($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
614
        $link = preg_replace(array('/^\{\{rss>/','/\}\}$/'),'',$match);
615
616
        // get params
617
        list($link,$params) = explode(' ',$link,2);
618
619
        $p = array();
620
        if(preg_match('/\b(\d+)\b/',$params,$match)){
621
            $p['max'] = $match[1];
622
        }else{
623
            $p['max'] = 8;
624
        }
625
        $p['reverse'] = (preg_match('/rev/',$params));
626
        $p['author']  = (preg_match('/\b(by|author)/',$params));
627
        $p['date']    = (preg_match('/\b(date)/',$params));
628
        $p['details'] = (preg_match('/\b(desc|detail)/',$params));
629
        $p['nosort']  = (preg_match('/\b(nosort)\b/',$params));
630
631
        if (preg_match('/\b(\d+)([dhm])\b/',$params,$match)) {
632
            $period = array('d' => 86400, 'h' => 3600, 'm' => 60);
633
            $p['refresh'] = max(600,$match[1]*$period[$match[2]]);  // n * period in seconds, minimum 10 minutes
634
        } else {
635
            $p['refresh'] = 14400;   // default to 4 hours
636
        }
637
638
        $this->_addCall('rss',array($link,$p),$pos);
639
        return true;
640
    }
641
642
    function externallink($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
643
        $url   = $match;
644
        $title = null;
645
646
        // add protocol on simple short URLs
647
        if(substr($url,0,3) == 'ftp' && (substr($url,0,6) != 'ftp://')){
648
            $title = $url;
649
            $url   = 'ftp://'.$url;
650
        }
651
        if(substr($url,0,3) == 'www' && (substr($url,0,7) != 'http://')){
652
            $title = $url;
653
            $url = 'http://'.$url;
654
        }
655
656
        $this->_addCall('externallink',array($url, $title), $pos);
657
        return true;
658
    }
659
660
    function emaillink($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
661
        $email = preg_replace(array('/^</','/>$/'),'',$match);
662
        $this->_addCall('emaillink',array($email, null), $pos);
663
        return true;
664
    }
665
666
    function table($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
667
        switch ( $state ) {
668
669
            case DOKU_LEXER_ENTER:
670
671
                $ReWriter = new Doku_Handler_Table($this->CallWriter);
672
                $this->CallWriter = & $ReWriter;
673
674
                $this->_addCall('table_start', array($pos + 1), $pos);
675
                if ( trim($match) == '^' ) {
676
                    $this->_addCall('tableheader', array(), $pos);
677
                } else {
678
                    $this->_addCall('tablecell', array(), $pos);
679
                }
680
            break;
681
682
            case DOKU_LEXER_EXIT:
683
                $this->_addCall('table_end', array($pos), $pos);
684
                $this->CallWriter->process();
0 ignored issues
show
Bug introduced by
The method process does only exist in Doku_Handler_List and Do... and Doku_Handler_Quote, but not in Doku_Handler_CallWriter.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
685
                $ReWriter = & $this->CallWriter;
686
                $this->CallWriter = & $ReWriter->CallWriter;
687
            break;
688
689
            case DOKU_LEXER_UNMATCHED:
690
                if ( trim($match) != '' ) {
691
                    $this->_addCall('cdata',array($match), $pos);
692
                }
693
            break;
694
695
            case DOKU_LEXER_MATCHED:
696
                if ( $match == ' ' ){
697
                    $this->_addCall('cdata', array($match), $pos);
698
                } else if ( preg_match('/:::/',$match) ) {
699
                    $this->_addCall('rowspan', array($match), $pos);
700
                } else if ( preg_match('/\t+/',$match) ) {
701
                    $this->_addCall('table_align', array($match), $pos);
702
                } else if ( preg_match('/ {2,}/',$match) ) {
703
                    $this->_addCall('table_align', array($match), $pos);
704
                } else if ( $match == "\n|" ) {
705
                    $this->_addCall('table_row', array(), $pos);
706
                    $this->_addCall('tablecell', array(), $pos);
707
                } else if ( $match == "\n^" ) {
708
                    $this->_addCall('table_row', array(), $pos);
709
                    $this->_addCall('tableheader', array(), $pos);
710
                } else if ( $match == '|' ) {
711
                    $this->_addCall('tablecell', array(), $pos);
712
                } else if ( $match == '^' ) {
713
                    $this->_addCall('tableheader', array(), $pos);
714
                }
715
            break;
716
        }
717
        return true;
718
    }
719
}
720
721
//------------------------------------------------------------------------
722
function Doku_Handler_Parse_Media($match) {
723
724
    // Strip the opening and closing markup
725
    $link = preg_replace(array('/^\{\{/','/\}\}$/u'),'',$match);
726
727
    // Split title from URL
728
    $link = explode('|',$link,2);
729
730
    // Check alignment
731
    $ralign = (bool)preg_match('/^ /',$link[0]);
732
    $lalign = (bool)preg_match('/ $/',$link[0]);
733
734
    // Logic = what's that ;)...
735
    if ( $lalign & $ralign ) {
736
        $align = 'center';
737
    } else if ( $ralign ) {
738
        $align = 'right';
739
    } else if ( $lalign ) {
740
        $align = 'left';
741
    } else {
742
        $align = null;
743
    }
744
745
    // The title...
746
    if ( !isset($link[1]) ) {
747
        $link[1] = null;
748
    }
749
750
    //remove aligning spaces
751
    $link[0] = trim($link[0]);
752
753
    //split into src and parameters (using the very last questionmark)
754
    $pos = strrpos($link[0], '?');
755
    if($pos !== false){
756
        $src   = substr($link[0],0,$pos);
757
        $param = substr($link[0],$pos+1);
758
    }else{
759
        $src   = $link[0];
760
        $param = '';
761
    }
762
763
    //parse width and height
764
    if(preg_match('#(\d+)(x(\d+))?#i',$param,$size)){
765
        !empty($size[1]) ? $w = $size[1] : $w = null;
766
        !empty($size[3]) ? $h = $size[3] : $h = null;
767
    } else {
768
        $w = null;
769
        $h = null;
770
    }
771
772
    //get linking command
773
    if(preg_match('/nolink/i',$param)){
774
        $linking = 'nolink';
775
    }else if(preg_match('/direct/i',$param)){
776
        $linking = 'direct';
777
    }else if(preg_match('/linkonly/i',$param)){
778
        $linking = 'linkonly';
779
    }else{
780
        $linking = 'details';
781
    }
782
783
    //get caching command
784
    if (preg_match('/(nocache|recache)/i',$param,$cachemode)){
785
        $cache = $cachemode[1];
786
    }else{
787
        $cache = 'cache';
788
    }
789
790
    // Check whether this is a local or remote image or interwiki
791
    if (media_isexternal($src) || link_isinterwiki($src)){
792
        $call = 'externalmedia';
793
    } else {
794
        $call = 'internalmedia';
795
    }
796
797
    $params = array(
798
        'type'=>$call,
799
        'src'=>$src,
800
        'title'=>$link[1],
801
        'align'=>$align,
802
        'width'=>$w,
803
        'height'=>$h,
804
        'cache'=>$cache,
805
        'linking'=>$linking,
806
    );
807
808
    return $params;
809
}
810
811
//------------------------------------------------------------------------
812
interface Doku_Handler_CallWriter_Interface {
813
    public function writeCall($call);
814
    public function writeCalls($calls);
815
    public function finalise();
816
}
817
818
class Doku_Handler_CallWriter implements Doku_Handler_CallWriter_Interface {
819
820
    var $Handler;
821
822
    /**
823
     * @param Doku_Handler $Handler
824
     */
825
    function __construct(Doku_Handler $Handler) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
826
        $this->Handler = $Handler;
827
    }
828
829
    function writeCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
830
        $this->Handler->calls[] = $call;
831
    }
832
833
    function writeCalls($calls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
834
        $this->Handler->calls = array_merge($this->Handler->calls, $calls);
835
    }
836
837
    // function is required, but since this call writer is first/highest in
838
    // the chain it is not required to do anything
839
    function finalise() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
840
        unset($this->Handler);
841
    }
842
}
843
844
//------------------------------------------------------------------------
845
/**
846
 * Generic call writer class to handle nesting of rendering instructions
847
 * within a render instruction. Also see nest() method of renderer base class
848
 *
849
 * @author    Chris Smith <[email protected]>
850
 */
851
class Doku_Handler_Nest implements Doku_Handler_CallWriter_Interface {
852
853
    var $CallWriter;
854
    var $calls = array();
855
856
    var $closingInstruction;
857
858
    /**
859
     * constructor
860
     *
861
     * @param  Doku_Handler_CallWriter $CallWriter     the renderers current call writer
862
     * @param  string     $close          closing instruction name, this is required to properly terminate the
863
     *                                    syntax mode if the document ends without a closing pattern
864
     */
865
    function __construct(Doku_Handler_CallWriter_Interface $CallWriter, $close="nest_close") {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
866
        $this->CallWriter = $CallWriter;
867
868
        $this->closingInstruction = $close;
869
    }
870
871
    function writeCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
872
        $this->calls[] = $call;
873
    }
874
875
    function writeCalls($calls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
876
        $this->calls = array_merge($this->calls, $calls);
877
    }
878
879
    function finalise() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
880
        $last_call = end($this->calls);
881
        $this->writeCall(array($this->closingInstruction,array(), $last_call[2]));
882
883
        $this->process();
884
        $this->CallWriter->finalise();
885
        unset($this->CallWriter);
886
    }
887
888
    function process() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
889
        // merge consecutive cdata
890
        $unmerged_calls = $this->calls;
891
        $this->calls = array();
892
893
        foreach ($unmerged_calls as $call) $this->addCall($call);
894
895
        $first_call = reset($this->calls);
896
        $this->CallWriter->writeCall(array("nest", array($this->calls), $first_call[2]));
897
    }
898
899
    function addCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
900
        $key = count($this->calls);
901
        if ($key and ($call[0] == 'cdata') and ($this->calls[$key-1][0] == 'cdata')) {
902
            $this->calls[$key-1][1][0] .= $call[1][0];
903
        } else if ($call[0] == 'eol') {
904
            // do nothing (eol shouldn't be allowed, to counter preformatted fix in #1652 & #1699)
905
        } else {
906
            $this->calls[] = $call;
907
        }
908
    }
909
}
910
911
class Doku_Handler_List implements Doku_Handler_CallWriter_Interface {
912
913
    var $CallWriter;
914
915
    var $calls = array();
916
    var $listCalls = array();
917
    var $listStack = array();
918
919
    const NODE = 1;
920
921
    function __construct(Doku_Handler_CallWriter_Interface $CallWriter) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
922
        $this->CallWriter = $CallWriter;
923
    }
924
925
    function writeCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
926
        $this->calls[] = $call;
927
    }
928
929
    // Probably not needed but just in case...
930
    function writeCalls($calls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
931
        $this->calls = array_merge($this->calls, $calls);
932
#        $this->CallWriter->writeCalls($this->calls);
933
    }
934
935
    function finalise() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
936
        $last_call = end($this->calls);
937
        $this->writeCall(array('list_close',array(), $last_call[2]));
938
939
        $this->process();
940
        $this->CallWriter->finalise();
941
        unset($this->CallWriter);
942
    }
943
944
    //------------------------------------------------------------------------
945
    function process() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
946
947
        foreach ( $this->calls as $call ) {
948
            switch ($call[0]) {
949
                case 'list_item':
950
                    $this->listOpen($call);
951
                break;
952
                case 'list_open':
953
                    $this->listStart($call);
954
                break;
955
                case 'list_close':
956
                    $this->listEnd($call);
957
                break;
958
                default:
959
                    $this->listContent($call);
960
                break;
961
            }
962
        }
963
964
        $this->CallWriter->writeCalls($this->listCalls);
965
    }
966
967
    //------------------------------------------------------------------------
968
    function listStart($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
969
        $depth = $this->interpretSyntax($call[1][0], $listType);
970
971
        $this->initialDepth = $depth;
0 ignored issues
show
Bug introduced by
The property initialDepth does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
972
        //                   array(list type, current depth, index of current listitem_open)
973
        $this->listStack[] = array($listType, $depth, 1);
974
975
        $this->listCalls[] = array('list'.$listType.'_open',array(),$call[2]);
976
        $this->listCalls[] = array('listitem_open',array(1),$call[2]);
977
        $this->listCalls[] = array('listcontent_open',array(),$call[2]);
978
    }
979
980
    //------------------------------------------------------------------------
981
    function listEnd($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
982
        $closeContent = true;
983
984
        while ( $list = array_pop($this->listStack) ) {
985
            if ( $closeContent ) {
986
                $this->listCalls[] = array('listcontent_close',array(),$call[2]);
987
                $closeContent = false;
988
            }
989
            $this->listCalls[] = array('listitem_close',array(),$call[2]);
990
            $this->listCalls[] = array('list'.$list[0].'_close', array(), $call[2]);
991
        }
992
    }
993
994
    //------------------------------------------------------------------------
995
    function listOpen($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
996
        $depth = $this->interpretSyntax($call[1][0], $listType);
997
        $end = end($this->listStack);
998
        $key = key($this->listStack);
999
1000
        // Not allowed to be shallower than initialDepth
1001
        if ( $depth < $this->initialDepth ) {
1002
            $depth = $this->initialDepth;
1003
        }
1004
1005
        //------------------------------------------------------------------------
1006
        if ( $depth == $end[1] ) {
1007
1008
            // Just another item in the list...
1009
            if ( $listType == $end[0] ) {
1010
                $this->listCalls[] = array('listcontent_close',array(),$call[2]);
1011
                $this->listCalls[] = array('listitem_close',array(),$call[2]);
1012
                $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]);
1013
                $this->listCalls[] = array('listcontent_open',array(),$call[2]);
1014
1015
                // new list item, update list stack's index into current listitem_open
1016
                $this->listStack[$key][2] = count($this->listCalls) - 2;
1017
1018
            // Switched list type...
1019
            } else {
1020
1021
                $this->listCalls[] = array('listcontent_close',array(),$call[2]);
1022
                $this->listCalls[] = array('listitem_close',array(),$call[2]);
1023
                $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]);
1024
                $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
1025
                $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
1026
                $this->listCalls[] = array('listcontent_open',array(),$call[2]);
1027
1028
                array_pop($this->listStack);
1029
                $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
1030
            }
1031
1032
        //------------------------------------------------------------------------
1033
        // Getting deeper...
1034
        } else if ( $depth > $end[1] ) {
1035
1036
            $this->listCalls[] = array('listcontent_close',array(),$call[2]);
1037
            $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
1038
            $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
1039
            $this->listCalls[] = array('listcontent_open',array(),$call[2]);
1040
1041
            // set the node/leaf state of this item's parent listitem_open to NODE
1042
            $this->listCalls[$this->listStack[$key][2]][1][1] = self::NODE;
1043
1044
            $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
1045
1046
        //------------------------------------------------------------------------
1047
        // Getting shallower ( $depth < $end[1] )
1048
        } else {
1049
            $this->listCalls[] = array('listcontent_close',array(),$call[2]);
1050
            $this->listCalls[] = array('listitem_close',array(),$call[2]);
1051
            $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]);
1052
1053
            // Throw away the end - done
1054
            array_pop($this->listStack);
1055
1056
            while (1) {
1057
                $end = end($this->listStack);
1058
                $key = key($this->listStack);
1059
1060
                if ( $end[1] <= $depth ) {
1061
1062
                    // Normalize depths
1063
                    $depth = $end[1];
1064
1065
                    $this->listCalls[] = array('listitem_close',array(),$call[2]);
1066
1067
                    if ( $end[0] == $listType ) {
1068
                        $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]);
1069
                        $this->listCalls[] = array('listcontent_open',array(),$call[2]);
1070
1071
                        // new list item, update list stack's index into current listitem_open
1072
                        $this->listStack[$key][2] = count($this->listCalls) - 2;
1073
1074
                    } else {
1075
                        // Switching list type...
1076
                        $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]);
1077
                        $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
1078
                        $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
1079
                        $this->listCalls[] = array('listcontent_open',array(),$call[2]);
1080
1081
                        array_pop($this->listStack);
1082
                        $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
1083
                    }
1084
1085
                    break;
1086
1087
                // Haven't dropped down far enough yet.... ( $end[1] > $depth )
1088
                } else {
1089
1090
                    $this->listCalls[] = array('listitem_close',array(),$call[2]);
1091
                    $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]);
1092
1093
                    array_pop($this->listStack);
1094
1095
                }
1096
1097
            }
1098
1099
        }
1100
    }
1101
1102
    //------------------------------------------------------------------------
1103
    function listContent($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1104
        $this->listCalls[] = $call;
1105
    }
1106
1107
    //------------------------------------------------------------------------
1108
    function interpretSyntax($match, & $type) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1109
        if ( substr($match,-1) == '*' ) {
1110
            $type = 'u';
1111
        } else {
1112
            $type = 'o';
1113
        }
1114
        // Is the +1 needed? It used to be count(explode(...))
1115
        // but I don't think the number is seen outside this handler
1116
        return substr_count(str_replace("\t",'  ',$match), '  ') + 1;
1117
    }
1118
}
1119
1120
//------------------------------------------------------------------------
1121
class Doku_Handler_Preformatted implements Doku_Handler_CallWriter_Interface {
1122
1123
    var $CallWriter;
1124
1125
    var $calls = array();
1126
    var $pos;
1127
    var $text ='';
1128
1129
1130
1131
    function __construct(Doku_Handler_CallWriter_Interface $CallWriter) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1132
        $this->CallWriter = $CallWriter;
1133
    }
1134
1135
    function writeCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1136
        $this->calls[] = $call;
1137
    }
1138
1139
    // Probably not needed but just in case...
1140
    function writeCalls($calls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1141
        $this->calls = array_merge($this->calls, $calls);
1142
#        $this->CallWriter->writeCalls($this->calls);
1143
    }
1144
1145
    function finalise() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1146
        $last_call = end($this->calls);
1147
        $this->writeCall(array('preformatted_end',array(), $last_call[2]));
1148
1149
        $this->process();
1150
        $this->CallWriter->finalise();
1151
        unset($this->CallWriter);
1152
    }
1153
1154
    function process() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1155
        foreach ( $this->calls as $call ) {
1156
            switch ($call[0]) {
1157
                case 'preformatted_start':
1158
                    $this->pos = $call[2];
1159
                break;
1160
                case 'preformatted_newline':
1161
                    $this->text .= "\n";
1162
                break;
1163
                case 'preformatted_content':
1164
                    $this->text .= $call[1][0];
1165
                break;
1166
                case 'preformatted_end':
1167
                    if (trim($this->text)) {
1168
                        $this->CallWriter->writeCall(array('preformatted',array($this->text),$this->pos));
1169
                    }
1170
                    // see FS#1699 & FS#1652, add 'eol' instructions to ensure proper triggering of following p_open
1171
                    $this->CallWriter->writeCall(array('eol',array(),$this->pos));
1172
                    $this->CallWriter->writeCall(array('eol',array(),$this->pos));
1173
                break;
1174
            }
1175
        }
1176
    }
1177
1178
}
1179
1180
//------------------------------------------------------------------------
1181
class Doku_Handler_Quote implements Doku_Handler_CallWriter_Interface {
1182
1183
    var $CallWriter;
1184
1185
    var $calls = array();
1186
1187
    var $quoteCalls = array();
1188
1189
    function __construct(Doku_Handler_CallWriter_Interface $CallWriter) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1190
        $this->CallWriter = $CallWriter;
1191
    }
1192
1193
    function writeCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1194
        $this->calls[] = $call;
1195
    }
1196
1197
    // Probably not needed but just in case...
1198
    function writeCalls($calls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1199
        $this->calls = array_merge($this->calls, $calls);
1200
    }
1201
1202
    function finalise() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1203
        $last_call = end($this->calls);
1204
        $this->writeCall(array('quote_end',array(), $last_call[2]));
1205
1206
        $this->process();
1207
        $this->CallWriter->finalise();
1208
        unset($this->CallWriter);
1209
    }
1210
1211
    function process() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1212
1213
        $quoteDepth = 1;
1214
1215
        foreach ( $this->calls as $call ) {
1216
            switch ($call[0]) {
1217
1218
                case 'quote_start':
1219
1220
                    $this->quoteCalls[] = array('quote_open',array(),$call[2]);
1221
1222
                case 'quote_newline':
1223
1224
                    $quoteLength = $this->getDepth($call[1][0]);
1225
1226
                    if ( $quoteLength > $quoteDepth ) {
1227
                        $quoteDiff = $quoteLength - $quoteDepth;
1228
                        for ( $i = 1; $i <= $quoteDiff; $i++ ) {
1229
                            $this->quoteCalls[] = array('quote_open',array(),$call[2]);
1230
                        }
1231
                    } else if ( $quoteLength < $quoteDepth ) {
1232
                        $quoteDiff = $quoteDepth - $quoteLength;
1233
                        for ( $i = 1; $i <= $quoteDiff; $i++ ) {
1234
                            $this->quoteCalls[] = array('quote_close',array(),$call[2]);
1235
                        }
1236
                    } else {
1237
                        if ($call[0] != 'quote_start') $this->quoteCalls[] = array('linebreak',array(),$call[2]);
1238
                    }
1239
1240
                    $quoteDepth = $quoteLength;
1241
1242
                break;
1243
1244
                case 'quote_end':
1245
1246
                    if ( $quoteDepth > 1 ) {
1247
                        $quoteDiff = $quoteDepth - 1;
1248
                        for ( $i = 1; $i <= $quoteDiff; $i++ ) {
1249
                            $this->quoteCalls[] = array('quote_close',array(),$call[2]);
1250
                        }
1251
                    }
1252
1253
                    $this->quoteCalls[] = array('quote_close',array(),$call[2]);
1254
1255
                    $this->CallWriter->writeCalls($this->quoteCalls);
1256
                break;
1257
1258
                default:
1259
                    $this->quoteCalls[] = $call;
1260
                break;
1261
            }
1262
        }
1263
    }
1264
1265
    function getDepth($marker) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1266
        preg_match('/>{1,}/', $marker, $matches);
1267
        $quoteLength = strlen($matches[0]);
1268
        return $quoteLength;
1269
    }
1270
}
1271
1272
//------------------------------------------------------------------------
1273
class Doku_Handler_Table implements Doku_Handler_CallWriter_Interface {
1274
1275
    var $CallWriter;
1276
1277
    var $calls = array();
1278
    var $tableCalls = array();
1279
    var $maxCols = 0;
1280
    var $maxRows = 1;
1281
    var $currentCols = 0;
1282
    var $firstCell = false;
1283
    var $lastCellType = 'tablecell';
1284
    var $inTableHead = true;
1285
    var $currentRow = array('tableheader' => 0, 'tablecell' => 0);
1286
    var $countTableHeadRows = 0;
1287
1288
    function __construct(Doku_Handler_CallWriter_Interface $CallWriter) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1289
        $this->CallWriter = $CallWriter;
1290
    }
1291
1292
    function writeCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1293
        $this->calls[] = $call;
1294
    }
1295
1296
    // Probably not needed but just in case...
1297
    function writeCalls($calls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1298
        $this->calls = array_merge($this->calls, $calls);
1299
    }
1300
1301
    function finalise() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1302
        $last_call = end($this->calls);
1303
        $this->writeCall(array('table_end',array(), $last_call[2]));
1304
1305
        $this->process();
1306
        $this->CallWriter->finalise();
1307
        unset($this->CallWriter);
1308
    }
1309
1310
    //------------------------------------------------------------------------
1311
    function process() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1312
        foreach ( $this->calls as $call ) {
1313
            switch ( $call[0] ) {
1314
                case 'table_start':
1315
                    $this->tableStart($call);
1316
                break;
1317
                case 'table_row':
1318
                    $this->tableRowClose($call);
1319
                    $this->tableRowOpen(array('tablerow_open',$call[1],$call[2]));
1320
                break;
1321
                case 'tableheader':
1322
                case 'tablecell':
1323
                    $this->tableCell($call);
1324
                break;
1325
                case 'table_end':
1326
                    $this->tableRowClose($call);
1327
                    $this->tableEnd($call);
1328
                break;
1329
                default:
1330
                    $this->tableDefault($call);
1331
                break;
1332
            }
1333
        }
1334
        $this->CallWriter->writeCalls($this->tableCalls);
1335
    }
1336
1337
    function tableStart($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1338
        $this->tableCalls[] = array('table_open',$call[1],$call[2]);
1339
        $this->tableCalls[] = array('tablerow_open',array(),$call[2]);
1340
        $this->firstCell = true;
1341
    }
1342
1343
    function tableEnd($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1344
        $this->tableCalls[] = array('table_close',$call[1],$call[2]);
1345
        $this->finalizeTable();
1346
    }
1347
1348
    function tableRowOpen($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1349
        $this->tableCalls[] = $call;
1350
        $this->currentCols = 0;
1351
        $this->firstCell = true;
1352
        $this->lastCellType = 'tablecell';
1353
        $this->maxRows++;
1354
        if ($this->inTableHead) {
1355
            $this->currentRow = array('tablecell' => 0, 'tableheader' => 0);
1356
        }
1357
    }
1358
1359
    function tableRowClose($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1360
        if ($this->inTableHead && ($this->inTableHead = $this->isTableHeadRow())) {
1361
            $this->countTableHeadRows++;
1362
        }
1363
        // Strip off final cell opening and anything after it
1364
        while ( $discard = array_pop($this->tableCalls ) ) {
1365
1366
            if ( $discard[0] == 'tablecell_open' || $discard[0] == 'tableheader_open') {
1367
                break;
1368
            }
1369
            if (!empty($this->currentRow[$discard[0]])) {
1370
                $this->currentRow[$discard[0]]--;
1371
            }
1372
        }
1373
        $this->tableCalls[] = array('tablerow_close', array(), $call[2]);
1374
1375
        if ( $this->currentCols > $this->maxCols ) {
1376
            $this->maxCols = $this->currentCols;
1377
        }
1378
    }
1379
1380
    function isTableHeadRow() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1381
        $td = $this->currentRow['tablecell'];
1382
        $th = $this->currentRow['tableheader'];
1383
1384
        if (!$th || $td > 2) return false;
1385
        if (2*$td > $th) return false;
1386
1387
        return true;
1388
    }
1389
1390
    function tableCell($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1391
        if ($this->inTableHead) {
1392
            $this->currentRow[$call[0]]++;
1393
        }
1394
        if ( !$this->firstCell ) {
1395
1396
            // Increase the span
1397
            $lastCall = end($this->tableCalls);
1398
1399
            // A cell call which follows an open cell means an empty cell so span
1400
            if ( $lastCall[0] == 'tablecell_open' || $lastCall[0] == 'tableheader_open' ) {
1401
                 $this->tableCalls[] = array('colspan',array(),$call[2]);
1402
1403
            }
1404
1405
            $this->tableCalls[] = array($this->lastCellType.'_close',array(),$call[2]);
1406
            $this->tableCalls[] = array($call[0].'_open',array(1,null,1),$call[2]);
1407
            $this->lastCellType = $call[0];
1408
1409
        } else {
1410
1411
            $this->tableCalls[] = array($call[0].'_open',array(1,null,1),$call[2]);
1412
            $this->lastCellType = $call[0];
1413
            $this->firstCell = false;
1414
1415
        }
1416
1417
        $this->currentCols++;
1418
    }
1419
1420
    function tableDefault($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1421
        $this->tableCalls[] = $call;
1422
    }
1423
1424
    function finalizeTable() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1425
1426
        // Add the max cols and rows to the table opening
1427
        if ( $this->tableCalls[0][0] == 'table_open' ) {
1428
            // Adjust to num cols not num col delimeters
1429
            $this->tableCalls[0][1][] = $this->maxCols - 1;
1430
            $this->tableCalls[0][1][] = $this->maxRows;
1431
            $this->tableCalls[0][1][] = array_shift($this->tableCalls[0][1]);
1432
        } else {
1433
            trigger_error('First element in table call list is not table_open');
1434
        }
1435
1436
        $lastRow = 0;
1437
        $lastCell = 0;
1438
        $cellKey = array();
1439
        $toDelete = array();
1440
1441
        // if still in tableheader, then there can be no table header
1442
        // as all rows can't be within <THEAD>
1443
        if ($this->inTableHead) {
1444
            $this->inTableHead = false;
1445
            $this->countTableHeadRows = 0;
1446
        }
1447
1448
        // Look for the colspan elements and increment the colspan on the
1449
        // previous non-empty opening cell. Once done, delete all the cells
1450
        // that contain colspans
1451
        for ($key = 0 ; $key < count($this->tableCalls) ; ++$key) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1452
            $call = $this->tableCalls[$key];
1453
1454
            switch ($call[0]) {
1455
                case 'table_open' :
1456
                    if($this->countTableHeadRows) {
1457
                        array_splice($this->tableCalls, $key+1, 0, array(
1458
                              array('tablethead_open', array(), $call[2]))
1459
                        );
1460
                    }
1461
                    break;
1462
1463
                case 'tablerow_open':
1464
1465
                    $lastRow++;
1466
                    $lastCell = 0;
1467
                    break;
1468
1469
                case 'tablecell_open':
1470
                case 'tableheader_open':
1471
1472
                    $lastCell++;
1473
                    $cellKey[$lastRow][$lastCell] = $key;
1474
                    break;
1475
1476
                case 'table_align':
1477
1478
                    $prev = in_array($this->tableCalls[$key-1][0], array('tablecell_open', 'tableheader_open'));
1479
                    $next = in_array($this->tableCalls[$key+1][0], array('tablecell_close', 'tableheader_close'));
1480
                    // If the cell is empty, align left
1481
                    if ($prev && $next) {
1482
                        $this->tableCalls[$key-1][1][1] = 'left';
1483
1484
                    // If the previous element was a cell open, align right
1485
                    } elseif ($prev) {
1486
                        $this->tableCalls[$key-1][1][1] = 'right';
1487
1488
                    // If the next element is the close of an element, align either center or left
1489
                    } elseif ( $next) {
1490
                        if ( $this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] == 'right' ) {
1491
                            $this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] = 'center';
1492
                        } else {
1493
                            $this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] = 'left';
1494
                        }
1495
1496
                    }
1497
1498
                    // Now convert the whitespace back to cdata
1499
                    $this->tableCalls[$key][0] = 'cdata';
1500
                    break;
1501
1502
                case 'colspan':
1503
1504
                    $this->tableCalls[$key-1][1][0] = false;
1505
1506
                    for($i = $key-2; $i >= $cellKey[$lastRow][1]; $i--) {
1507
1508
                        if ( $this->tableCalls[$i][0] == 'tablecell_open' || $this->tableCalls[$i][0] == 'tableheader_open' ) {
1509
1510
                            if ( false !== $this->tableCalls[$i][1][0] ) {
1511
                                $this->tableCalls[$i][1][0]++;
1512
                                break;
1513
                            }
1514
1515
                        }
1516
                    }
1517
1518
                    $toDelete[] = $key-1;
1519
                    $toDelete[] = $key;
1520
                    $toDelete[] = $key+1;
1521
                    break;
1522
1523
                case 'rowspan':
1524
1525
                    if ( $this->tableCalls[$key-1][0] == 'cdata' ) {
1526
                        // ignore rowspan if previous call was cdata (text mixed with :::) we don't have to check next call as that wont match regex
1527
                        $this->tableCalls[$key][0] = 'cdata';
1528
1529
                    } else {
1530
1531
                        $spanning_cell = null;
1532
1533
                        // can't cross thead/tbody boundary
1534
                        if (!$this->countTableHeadRows || ($lastRow-1 != $this->countTableHeadRows)) {
1535
                            for($i = $lastRow-1; $i > 0; $i--) {
1536
1537
                                if ( $this->tableCalls[$cellKey[$i][$lastCell]][0] == 'tablecell_open' || $this->tableCalls[$cellKey[$i][$lastCell]][0] == 'tableheader_open' ) {
1538
1539
                                    if ($this->tableCalls[$cellKey[$i][$lastCell]][1][2] >= $lastRow - $i) {
1540
                                        $spanning_cell = $i;
1541
                                        break;
1542
                                    }
1543
1544
                                }
1545
                            }
1546
                        }
1547
                        if (is_null($spanning_cell)) {
1548
                            // No spanning cell found, so convert this cell to
1549
                            // an empty one to avoid broken tables
1550
                            $this->tableCalls[$key][0] = 'cdata';
1551
                            $this->tableCalls[$key][1][0] = '';
1552
                            continue;
1553
                        }
1554
                        $this->tableCalls[$cellKey[$spanning_cell][$lastCell]][1][2]++;
1555
1556
                        $this->tableCalls[$key-1][1][2] = false;
1557
1558
                        $toDelete[] = $key-1;
1559
                        $toDelete[] = $key;
1560
                        $toDelete[] = $key+1;
1561
                    }
1562
                    break;
1563
1564
                case 'tablerow_close':
1565
1566
                    // Fix broken tables by adding missing cells
1567
                    $moreCalls = array();
1568
                    while (++$lastCell < $this->maxCols) {
1569
                        $moreCalls[] = array('tablecell_open', array(1, null, 1), $call[2]);
1570
                        $moreCalls[] = array('cdata', array(''), $call[2]);
1571
                        $moreCalls[] = array('tablecell_close', array(), $call[2]);
1572
                    }
1573
                    $moreCallsLength = count($moreCalls);
1574
                    if($moreCallsLength) {
1575
                        array_splice($this->tableCalls, $key, 0, $moreCalls);
1576
                        $key += $moreCallsLength;
1577
                    }
1578
1579
                    if($this->countTableHeadRows == $lastRow) {
1580
                        array_splice($this->tableCalls, $key+1, 0, array(
1581
                              array('tablethead_close', array(), $call[2])));
1582
                    }
1583
                    break;
1584
1585
            }
1586
        }
1587
1588
        // condense cdata
1589
        $cnt = count($this->tableCalls);
1590
        for( $key = 0; $key < $cnt; $key++){
1591
            if($this->tableCalls[$key][0] == 'cdata'){
1592
                $ckey = $key;
1593
                $key++;
1594
                while($this->tableCalls[$key][0] == 'cdata'){
1595
                    $this->tableCalls[$ckey][1][0] .= $this->tableCalls[$key][1][0];
1596
                    $toDelete[] = $key;
1597
                    $key++;
1598
                }
1599
                continue;
1600
            }
1601
        }
1602
1603
        foreach ( $toDelete as $delete ) {
1604
            unset($this->tableCalls[$delete]);
1605
        }
1606
        $this->tableCalls = array_values($this->tableCalls);
1607
    }
1608
}
1609
1610
1611
/**
1612
 * Handler for paragraphs
1613
 *
1614
 * @author Harry Fuecks <[email protected]>
1615
 */
1616
class Doku_Handler_Block {
1617
    var $calls = array();
1618
    var $skipEol = false;
1619
    var $inParagraph = false;
1620
1621
    // Blocks these should not be inside paragraphs
1622
    var $blockOpen = array(
1623
            'header',
1624
            'listu_open','listo_open','listitem_open','listcontent_open',
1625
            'table_open','tablerow_open','tablecell_open','tableheader_open','tablethead_open',
1626
            'quote_open',
1627
            'code','file','hr','preformatted','rss',
1628
            'htmlblock','phpblock',
1629
            'footnote_open',
1630
        );
1631
1632
    var $blockClose = array(
1633
            'header',
1634
            'listu_close','listo_close','listitem_close','listcontent_close',
1635
            'table_close','tablerow_close','tablecell_close','tableheader_close','tablethead_close',
1636
            'quote_close',
1637
            'code','file','hr','preformatted','rss',
1638
            'htmlblock','phpblock',
1639
            'footnote_close',
1640
        );
1641
1642
    // Stacks can contain paragraphs
1643
    var $stackOpen = array(
1644
        'section_open',
1645
        );
1646
1647
    var $stackClose = array(
1648
        'section_close',
1649
        );
1650
1651
1652
    /**
1653
     * Constructor. Adds loaded syntax plugins to the block and stack
1654
     * arrays
1655
     *
1656
     * @author Andreas Gohr <[email protected]>
1657
     */
1658
    function __construct(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1659
        global $DOKU_PLUGINS;
1660
        //check if syntax plugins were loaded
1661
        if(empty($DOKU_PLUGINS['syntax'])) return;
1662
        foreach($DOKU_PLUGINS['syntax'] as $n => $p){
1663
            $ptype = $p->getPType();
1664
            if($ptype == 'block'){
1665
                $this->blockOpen[]  = 'plugin_'.$n;
1666
                $this->blockClose[] = 'plugin_'.$n;
1667
            }elseif($ptype == 'stack'){
1668
                $this->stackOpen[]  = 'plugin_'.$n;
1669
                $this->stackClose[] = 'plugin_'.$n;
1670
            }
1671
        }
1672
    }
1673
1674
    function openParagraph($pos){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1675
        if ($this->inParagraph) return;
1676
        $this->calls[] = array('p_open',array(), $pos);
1677
        $this->inParagraph = true;
1678
        $this->skipEol = true;
1679
    }
1680
1681
    /**
1682
     * Close a paragraph if needed
1683
     *
1684
     * This function makes sure there are no empty paragraphs on the stack
1685
     *
1686
     * @author Andreas Gohr <[email protected]>
1687
     *
1688
     * @param string|integer $pos
1689
     */
1690
    function closeParagraph($pos){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1691
        if (!$this->inParagraph) return;
1692
        // look back if there was any content - we don't want empty paragraphs
1693
        $content = '';
1694
        $ccount = count($this->calls);
1695
        for($i=$ccount-1; $i>=0; $i--){
1696
            if($this->calls[$i][0] == 'p_open'){
1697
                break;
1698
            }elseif($this->calls[$i][0] == 'cdata'){
1699
                $content .= $this->calls[$i][1][0];
1700
            }else{
1701
                $content = 'found markup';
1702
                break;
1703
            }
1704
        }
1705
1706
        if(trim($content)==''){
1707
            //remove the whole paragraph
1708
            //array_splice($this->calls,$i); // <- this is much slower than the loop below
1709
            for($x=$ccount; $x>$i; $x--) array_pop($this->calls);
1710
        }else{
1711
            // remove ending linebreaks in the paragraph
1712
            $i=count($this->calls)-1;
1713
            if ($this->calls[$i][0] == 'cdata') $this->calls[$i][1][0] = rtrim($this->calls[$i][1][0],DOKU_PARSER_EOL);
1714
            $this->calls[] = array('p_close',array(), $pos);
1715
        }
1716
1717
        $this->inParagraph = false;
1718
        $this->skipEol = true;
1719
    }
1720
1721
    function addCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1722
        $key = count($this->calls);
1723
        if ($key and ($call[0] == 'cdata') and ($this->calls[$key-1][0] == 'cdata')) {
1724
            $this->calls[$key-1][1][0] .= $call[1][0];
1725
        } else {
1726
            $this->calls[] = $call;
1727
        }
1728
    }
1729
1730
    // simple version of addCall, without checking cdata
1731
    function storeCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1732
        $this->calls[] = $call;
1733
    }
1734
1735
    /**
1736
     * Processes the whole instruction stack to open and close paragraphs
1737
     *
1738
     * @author Harry Fuecks <[email protected]>
1739
     * @author Andreas Gohr <[email protected]>
1740
     *
1741
     * @param array $calls
1742
     *
1743
     * @return array
1744
     */
1745
    function process($calls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1746
        // open first paragraph
1747
        $this->openParagraph(0);
1748
        foreach ( $calls as $key => $call ) {
1749
            $cname = $call[0];
1750
            if ($cname == 'plugin') {
1751
                $cname='plugin_'.$call[1][0];
1752
                $plugin = true;
1753
                $plugin_open = (($call[1][2] == DOKU_LEXER_ENTER) || ($call[1][2] == DOKU_LEXER_SPECIAL));
1754
                $plugin_close = (($call[1][2] == DOKU_LEXER_EXIT) || ($call[1][2] == DOKU_LEXER_SPECIAL));
1755
            } else {
1756
                $plugin = false;
1757
            }
1758
            /* stack */
1759
            if ( in_array($cname,$this->stackClose ) && (!$plugin || $plugin_close)) {
0 ignored issues
show
Bug introduced by
The variable $plugin_close 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...
1760
                $this->closeParagraph($call[2]);
1761
                $this->storeCall($call);
1762
                $this->openParagraph($call[2]);
1763
                continue;
1764
            }
1765
            if ( in_array($cname,$this->stackOpen ) && (!$plugin || $plugin_open) ) {
0 ignored issues
show
Bug introduced by
The variable $plugin_open 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...
1766
                $this->closeParagraph($call[2]);
1767
                $this->storeCall($call);
1768
                $this->openParagraph($call[2]);
1769
                continue;
1770
            }
1771
            /* block */
1772
            // If it's a substition it opens and closes at the same call.
1773
            // To make sure next paragraph is correctly started, let close go first.
1774
            if ( in_array($cname, $this->blockClose) && (!$plugin || $plugin_close)) {
1775
                $this->closeParagraph($call[2]);
1776
                $this->storeCall($call);
1777
                $this->openParagraph($call[2]);
1778
                continue;
1779
            }
1780
            if ( in_array($cname, $this->blockOpen) && (!$plugin || $plugin_open)) {
1781
                $this->closeParagraph($call[2]);
1782
                $this->storeCall($call);
1783
                continue;
1784
            }
1785
            /* eol */
1786
            if ( $cname == 'eol' ) {
1787
                // Check this isn't an eol instruction to skip...
1788
                if ( !$this->skipEol ) {
1789
                    // Next is EOL => double eol => mark as paragraph
1790
                    if ( isset($calls[$key+1]) && $calls[$key+1][0] == 'eol' ) {
1791
                        $this->closeParagraph($call[2]);
1792
                        $this->openParagraph($call[2]);
1793
                    } else {
1794
                        //if this is just a single eol make a space from it
1795
                        $this->addCall(array('cdata',array(DOKU_PARSER_EOL), $call[2]));
1796
                    }
1797
                }
1798
                continue;
1799
            }
1800
            /* normal */
1801
            $this->addCall($call);
1802
            $this->skipEol = false;
1803
        }
1804
        // close last paragraph
1805
        $call = end($this->calls);
1806
        $this->closeParagraph($call[2]);
1807
        return $this->calls;
1808
    }
1809
}
1810
1811
//Setup VIM: ex: et ts=4 :
1812