Completed
Branch master (b7ffcb)
by Tomas Norre
17:57
created

BackendModule::drawURLs()   D

Complexity

Conditions 13
Paths 192

Size

Total Lines 112
Code Lines 74

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 74
nc 192
nop 0
dl 0
loc 112
rs 4.6605
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace AOE\Crawler\Backend;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2017 AOE GmbH <[email protected]>
8
 *
9
 *  All rights reserved
10
 *
11
 *  This script is part of the TYPO3 project. The TYPO3 project is
12
 *  free software; you can redistribute it and/or modify
13
 *  it under the terms of the GNU General Public License as published by
14
 *  the Free Software Foundation; either version 3 of the License, or
15
 *  (at your option) any later version.
16
 *
17
 *  The GNU General Public License can be found at
18
 *  http://www.gnu.org/copyleft/gpl.html.
19
 *
20
 *  This script is distributed in the hope that it will be useful,
21
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 *  GNU General Public License for more details.
24
 *
25
 *  This copyright notice MUST APPEAR in all copies of the script!
26
 ***************************************************************/
27
28
use AOE\Crawler\Backend\View\PaginationView;
29
use AOE\Crawler\Backend\View\ProcessListView;
30
use AOE\Crawler\Controller\CrawlerController;
31
use AOE\Crawler\Domain\Model\Reason;
32
use AOE\Crawler\Domain\Repository\ProcessRepository;
33
use AOE\Crawler\Domain\Repository\QueueRepository;
34
use AOE\Crawler\Event\EventDispatcher;
35
use AOE\Crawler\Service\ProcessService;
36
use AOE\Crawler\Utility\IconUtility;
37
use TYPO3\CMS\Backend\Module\AbstractFunctionModule;
38
use TYPO3\CMS\Backend\Utility\BackendUtility;
39
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
40
use TYPO3\CMS\Core\Messaging\FlashMessage;
41
use TYPO3\CMS\Core\Messaging\FlashMessageService;
42
use TYPO3\CMS\Core\Utility\DebugUtility;
43
use TYPO3\CMS\Core\Utility\GeneralUtility;
44
use TYPO3\CMS\Core\Utility\MathUtility;
45
46
/**
47
 * Class BackendModule
48
 *
49
 * @package AOE\Crawler\Backend
50
 */
51
class BackendModule extends AbstractFunctionModule
52
{
53
    // Internal, dynamic:
54
    public $duplicateTrack = [];
55
    public $submitCrawlUrls = false;
56
    public $downloadCrawlUrls = false;
57
58
    public $scheduledTime = 0;
59
    public $reqMinute = 0;
60
61
    /**
62
     * @var array holds the selection of configuration from the configuration selector box
63
     */
64
    public $incomingConfigurationSelection = [];
65
66
    /**
67
     * @var CrawlerController
68
     */
69
    public $crawlerObj;
70
71
    public $CSVaccu = [];
72
73
    /**
74
     * If true the user requested a CSV export of the queue
75
     *
76
     * @var boolean
77
     */
78
    public $CSVExport = false;
79
80
    public $downloadUrls = [];
81
82
    /**
83
     * Holds the configuration from ext_conf_template loaded by loadExtensionSettings()
84
     *
85
     * @var array
86
     */
87
    protected $extensionSettings = [];
88
89
    /**
90
     * Indicate that an flash message with an error is present.
91
     *
92
     * @var boolean
93
     */
94
    protected $isErrorDetected = false;
95
96
    /**
97
     * the constructor
98
     */
99
    public function __construct()
100
    {
101
        $this->processManager = new ProcessService();
0 ignored issues
show
Bug introduced by
The property processManager 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...
102
    }
103
104
    /**
105
     * Additions to the function menu array
106
     *
107
     * @return	array		Menu array
108
     */
109
    public function modMenu()
110
    {
111
        global $LANG;
112
113
        return [
114
            'depth' => [
115
                0 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
116
                1 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
117
                2 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
118
                3 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
119
                4 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
120
                99 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi'),
121
            ],
122
            'crawlaction' => [
123
                'start' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.start'),
124
                'log' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.log'),
125
                'multiprocess' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.multiprocess')
126
            ],
127
            'log_resultLog' => '',
128
            'log_feVars' => '',
129
            'processListMode' => '',
130
            'log_display' => [
131
                'all' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.all'),
132
                'pending' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.pending'),
133
                'finished' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.finished')
134
            ],
135
            'itemsPerPage' => [
136
                '5' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.5'),
137
                '10' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.10'),
138
                '50' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.50'),
139
                '0' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.0')
140
            ]
141
        ];
142
    }
143
144
    /**
145
     * Load extension settings
146
     *
147
     * @return void
148
     */
149
    protected function loadExtensionSettings()
150
    {
151
        $this->extensionSettings = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['crawler']);
152
    }
153
154
    /**
155
     * Main function
156
     *
157
     * @return	string		HTML output
158
     */
159
    public function main()
160
    {
161
        global $LANG, $BACK_PATH;
162
163
        $this->incLocalLang();
164
165
        $this->loadExtensionSettings();
166
        if (empty($this->pObj->MOD_SETTINGS['processListMode'])) {
167
            $this->pObj->MOD_SETTINGS['processListMode'] = 'simple';
168
        }
169
170
        // Set CSS styles specific for this document:
171
        $this->pObj->content = str_replace('/*###POSTCSSMARKER###*/', '
172
			TABLE.c-list TR TD { white-space: nowrap; vertical-align: top; }
173
		', $this->pObj->content);
174
175
        $this->pObj->content .= '<style type="text/css"><!--
176
			table.url-table,
177
			table.param-expanded,
178
			table.crawlerlog {
179
				border-bottom: 1px solid grey;
180
				border-spacing: 0;
181
				border-collapse: collapse;
182
			}
183
			table.crawlerlog td,
184
			table.url-table td {
185
				border: 1px solid lightgrey;
186
				border-bottom: 1px solid grey;
187
				 white-space: nowrap; vertical-align: top;
188
			}
189
		--></style>
190
		<link rel="stylesheet" type="text/css" href="' . $BACK_PATH . '../typo3conf/ext/crawler/template/res.css" />
191
		';
192
193
        // Type function menu:
194
        $h_func = BackendUtility::getFuncMenu(
195
            $this->pObj->id,
196
            'SET[crawlaction]',
197
            $this->pObj->MOD_SETTINGS['crawlaction'],
198
            $this->pObj->MOD_MENU['crawlaction'],
199
            'index.php'
200
        );
201
202
        // Additional menus for the log type:
203
        if ($this->pObj->MOD_SETTINGS['crawlaction'] === 'log') {
204
            $h_func .= BackendUtility::getFuncMenu(
205
                $this->pObj->id,
206
                'SET[depth]',
207
                $this->pObj->MOD_SETTINGS['depth'],
208
                $this->pObj->MOD_MENU['depth'],
209
                'index.php'
210
            );
211
212
            $quiPart = GeneralUtility::_GP('qid_details') ? '&qid_details=' . intval(GeneralUtility::_GP('qid_details')) : '';
213
214
            $setId = intval(GeneralUtility::_GP('setID'));
215
216
            $h_func .= '<hr/>' .
217
                    $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.display') . ': ' . BackendUtility::getFuncMenu($this->pObj->id, 'SET[log_display]', $this->pObj->MOD_SETTINGS['log_display'], $this->pObj->MOD_MENU['log_display'], 'index.php', '&setID=' . $setId) . ' - ' .
218
                    $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.showresultlog') . ': ' . BackendUtility::getFuncCheck($this->pObj->id, 'SET[log_resultLog]', $this->pObj->MOD_SETTINGS['log_resultLog'], 'index.php', '&setID=' . $setId . $quiPart) . ' - ' .
219
                    $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.showfevars') . ': ' . BackendUtility::getFuncCheck($this->pObj->id, 'SET[log_feVars]', $this->pObj->MOD_SETTINGS['log_feVars'], 'index.php', '&setID=' . $setId . $quiPart) . ' - ' .
220
                    $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage') . ': ' .
221
                    BackendUtility::getFuncMenu(
222
                        $this->pObj->id,
223
                        'SET[itemsPerPage]',
224
                        $this->pObj->MOD_SETTINGS['itemsPerPage'],
225
                        $this->pObj->MOD_MENU['itemsPerPage'],
226
                        'index.php'
227
                    );
228
        }
229
230
        $theOutput = $this->pObj->doc->section($LANG->getLL('title'), $h_func, 0, 1);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
231
232
        // Branch based on type:
233
        switch ((string)$this->pObj->MOD_SETTINGS['crawlaction']) {
234
            case 'start':
235
                if (empty($this->pObj->id)) {
236
                    $this->addErrorMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noPageSelected'));
237
                } else {
238
                    $theOutput .= $this->pObj->doc->section('', $this->drawURLs(), 0, 1);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
239
                }
240
                break;
241
            case 'log':
242
                if (empty($this->pObj->id)) {
243
                    $this->addErrorMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noPageSelected'));
244
                } else {
245
                    $theOutput .= $this->pObj->doc->section('', $this->drawLog(), 0, 1);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
246
                }
247
                break;
248
            case 'cli':
249
                $theOutput .= $this->pObj->doc->section('', $this->drawCLIstatus(), 0, 1);
0 ignored issues
show
Bug introduced by
The method drawCLIstatus() does not seem to exist on object<AOE\Crawler\Backend\BackendModule>.

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...
Documentation introduced by
0 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
250
                break;
251
            case 'multiprocess':
252
                $theOutput .= $this->pObj->doc->section('', $this->drawProcessOverviewAction(), 0, 1);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
253
                break;
254
        }
255
256
        return $theOutput;
257
    }
258
259
    /*******************************
260
     *
261
     * Generate URLs for crawling:
262
     *
263
     ******************************/
264
265
    /**
266
     * Produces a table with overview of the URLs to be crawled for each page
267
     *
268
     * @return	string		HTML output
269
     */
270
    public function drawURLs()
271
    {
272
        global $BACK_PATH, $BE_USER;
273
274
        // Init:
275
        $this->duplicateTrack = [];
276
        $this->submitCrawlUrls = GeneralUtility::_GP('_crawl');
0 ignored issues
show
Documentation Bug introduced by
It seems like \TYPO3\CMS\Core\Utility\...lUtility::_GP('_crawl') can also be of type array or string. However, the property $submitCrawlUrls is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
277
        $this->downloadCrawlUrls = GeneralUtility::_GP('_download');
0 ignored issues
show
Documentation Bug introduced by
It seems like \TYPO3\CMS\Core\Utility\...ility::_GP('_download') can also be of type array or string. However, the property $downloadCrawlUrls is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
278
        $this->makeCrawlerProcessableChecks();
279
280
        switch ((string) GeneralUtility::_GP('tstamp')) {
281
            case 'midnight':
282
                $this->scheduledTime = mktime(0, 0, 0);
283
            break;
284
            case '04:00':
285
                $this->scheduledTime = mktime(0, 0, 0) + 4 * 3600;
286
            break;
287
            case 'now':
288
            default:
289
                $this->scheduledTime = time();
290
            break;
291
        }
292
        // $this->reqMinute = \TYPO3\CMS\Core\Utility\GeneralUtility::intInRange(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('perminute'),1,10000);
293
        // TODO: check relevance
294
        $this->reqMinute = 1000;
295
296
        $this->incomingConfigurationSelection = GeneralUtility::_GP('configurationSelection');
0 ignored issues
show
Documentation Bug introduced by
It seems like \TYPO3\CMS\Core\Utility\...onfigurationSelection') can also be of type null or string. However, the property $incomingConfigurationSelection is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
297
        $this->incomingConfigurationSelection = is_array($this->incomingConfigurationSelection) ? $this->incomingConfigurationSelection : [''];
298
299
        $this->crawlerObj = GeneralUtility::makeInstance(CrawlerController::class);
300
        $this->crawlerObj->setAccessMode('gui');
301
        $this->crawlerObj->setID = GeneralUtility::md5int(microtime());
302
303
        if (empty($this->incomingConfigurationSelection)
304
            || (count($this->incomingConfigurationSelection) == 1 && empty($this->incomingConfigurationSelection[0]))
305
            ) {
306
            $code = '
307
			<tr>
308
				<td colspan="7"><b>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noConfigSelected') . '</b></td>
309
			</tr>';
310
        } else {
311
            if ($this->submitCrawlUrls) {
312
                $reason = new Reason();
313
                $reason->setReason(Reason::REASON_GUI_SUBMIT);
314
315
                if ($BE_USER instanceof BackendUserAuthentication) {
316
                    $username = $BE_USER->user['username'];
317
                }
318
                $reason->setDetailText('The user ' . $username . ' added pages to the crawler queue manually ');
0 ignored issues
show
Bug introduced by
The variable $username 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...
319
320
                EventDispatcher::getInstance()->post(
321
                    'invokeQueueChange',
322
                    $this->findCrawler()->setID,
323
                    ['reason' => $reason]
324
                );
325
            }
326
327
            $code = $this->crawlerObj->getPageTreeAndUrls(
328
                $this->pObj->id,
329
                $this->pObj->MOD_SETTINGS['depth'],
330
                $this->scheduledTime,
331
                $this->reqMinute,
332
                $this->submitCrawlUrls,
333
                $this->downloadCrawlUrls,
334
                [], // Do not filter any processing instructions
335
                $this->incomingConfigurationSelection
336
            );
337
        }
338
339
        $this->downloadUrls = $this->crawlerObj->downloadUrls;
340
        $this->duplicateTrack = $this->crawlerObj->duplicateTrack;
341
342
        $output = '';
343
        if ($code) {
344
            $output .= '<h3>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.configuration') . ':</h3>';
345
            $output .= '<input type="hidden" name="id" value="' . intval($this->pObj->id) . '" />';
346
347
            if (!$this->submitCrawlUrls) {
348
                $output .= $this->drawURLs_cfgSelectors() . '<br />';
349
                $output .= '<input type="submit" name="_update" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.triggerUpdate') . '" /> ';
350
                $output .= '<input type="submit" name="_crawl" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.triggerCrawl') . '" /> ';
351
                $output .= '<input type="submit" name="_download" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.triggerDownload') . '" /><br /><br />';
352
                $output .= $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.count') . ': ' . count(array_keys($this->duplicateTrack)) . '<br />';
353
                $output .= $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.curtime') . ': ' . date('H:i:s', time()) . '<br />';
354
                $output .= '<br />
355
					<table class="lrPadding c-list url-table">' .
356
                        $this->drawURLs_printTableHeader() .
357
                        $code .
358
                    '</table>';
359
            } else {
360
                $output .= count(array_keys($this->duplicateTrack)) . ' ' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.submitted') . '. <br /><br />';
361
                $output .= '<input type="submit" name="_" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.continue') . '" />';
362
                $output .= '<input type="submit" onclick="this.form.elements[\'SET[crawlaction]\'].value=\'log\';" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.continueinlog') . '" />';
363
            }
364
        }
365
366
        // Download Urls to crawl:
367
        if ($this->downloadCrawlUrls) {
368
369
                // Creating output header:
370
            $mimeType = 'application/octet-stream';
371
            Header('Content-Type: ' . $mimeType);
372
            Header('Content-Disposition: attachment; filename=CrawlerUrls.txt');
373
374
            // Printing the content of the CSV lines:
375
            echo implode(chr(13) . chr(10), $this->downloadUrls);
376
377
            exit;
378
        }
379
380
        return 	$output;
381
    }
382
383
    /**
384
     * Draws the configuration selectors for compiling URLs:
385
     *
386
     * @return	string		HTML table
387
     */
388
    public function drawURLs_cfgSelectors()
389
    {
390
391
            // depth
392
        $cell[] = $this->selectorBox(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$cell was never initialized. Although not strictly required by PHP, it is generally a good practice to add $cell = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
393
            [
394
                0 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
395
                1 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
396
                2 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
397
                3 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
398
                4 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
399
                99 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi'),
400
            ],
401
            'SET[depth]',
402
            $this->pObj->MOD_SETTINGS['depth'],
403
            0
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
404
        );
405
        $availableConfigurations = $this->crawlerObj->getConfigurationsForBranch($this->pObj->id, $this->pObj->MOD_SETTINGS['depth'] ? $this->pObj->MOD_SETTINGS['depth'] : 0);
406
407
        // Configurations
408
        $cell[] = $this->selectorBox(
409
            empty($availableConfigurations) ? [] : array_combine($availableConfigurations, $availableConfigurations),
410
            'configurationSelection',
411
            $this->incomingConfigurationSelection,
0 ignored issues
show
Documentation introduced by
$this->incomingConfigurationSelection is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
412
            1
0 ignored issues
show
Documentation introduced by
1 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
413
        );
414
415
        // Scheduled time:
416
        $cell[] = $this->selectorBox(
417
            [
418
                'now' => $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time.now'),
419
                'midnight' => $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time.midnight'),
420
                '04:00' => $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time.4am'),
421
            ],
422
            'tstamp',
423
            GeneralUtility::_POST('tstamp'),
0 ignored issues
show
Bug introduced by
It seems like \TYPO3\CMS\Core\Utility\...tility::_POST('tstamp') targeting TYPO3\CMS\Core\Utility\GeneralUtility::_POST() can also be of type array or null; however, AOE\Crawler\Backend\BackendModule::selectorBox() does only seem to accept string, maybe add an additional type check?

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

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

An additional type check may prevent trouble.

Loading history...
424
            0
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
425
        );
426
427
        $output = '
428
			<table class="lrPadding c-list">
429
				<tr class="bgColor5 tableheader">
430
					<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.depth') . ':</td>
431
					<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.configurations') . ':</td>
432
					<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.scheduled') . ':</td>
433
				</tr>
434
				<tr class="bgColor4">
435
					<td valign="top">' . implode('</td>
436
					<td valign="top">', $cell) . '</td>
437
				</tr>
438
			</table>';
439
440
        return $output;
441
    }
442
443
    /**
444
     * Create Table header row for URL display
445
     *
446
     * @return	string		Table header
447
     */
448
    public function drawURLs_printTableHeader()
449
    {
450
        $content = '
451
			<tr class="bgColor5 tableheader">
452
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.pagetitle') . ':</td>
453
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.key') . ':</td>
454
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.parametercfg') . ':</td>
455
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.values') . ':</td>
456
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.urls') . ':</td>
457
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.options') . ':</td>
458
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.parameters') . ':</td>
459
			</tr>';
460
461
        return $content;
462
    }
463
464
    /*******************************
465
     *
466
     * Shows log of indexed URLs
467
     *
468
     ******************************/
469
470
    /**
471
     * Shows the log of indexed URLs
472
     *
473
     * @return	string		HTML output
474
     */
475
    public function drawLog()
476
    {
477
        global $BACK_PATH;
478
        $output = '';
479
480
        // Init:
481
        $this->crawlerObj = GeneralUtility::makeInstance(CrawlerController::class);
482
        $this->crawlerObj->setAccessMode('gui');
483
        $this->crawlerObj->setID = GeneralUtility::md5int(microtime());
484
485
        $this->CSVExport = GeneralUtility::_POST('_csv');
0 ignored issues
show
Documentation Bug introduced by
It seems like \TYPO3\CMS\Core\Utility\...lUtility::_POST('_csv') can also be of type array or string. However, the property $CSVExport is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
486
487
        // Read URL:
488
        if (GeneralUtility::_GP('qid_read')) {
489
            $this->crawlerObj->readUrl(intval(GeneralUtility::_GP('qid_read')), true);
490
        }
491
492
        // Look for set ID sent - if it is, we will display contents of that set:
493
        $showSetId = intval(GeneralUtility::_GP('setID'));
494
495
        // Show details:
496
        if (GeneralUtility::_GP('qid_details')) {
497
498
                // Get entry record:
499
            list($q_entry) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'tx_crawler_queue', 'qid=' . intval(GeneralUtility::_GP('qid_details')));
500
501
            // Explode values:
502
            $resStatus = $this->getResStatus($q_entry);
503
            $q_entry['parameters'] = unserialize($q_entry['parameters']);
504
            $q_entry['result_data'] = unserialize($q_entry['result_data']);
505
            if (is_array($q_entry['result_data'])) {
506
                $q_entry['result_data']['content'] = unserialize($q_entry['result_data']['content']);
507
            }
508
509
            if (!$this->pObj->MOD_SETTINGS['log_resultLog']) {
510
                unset($q_entry['result_data']['content']['log']);
511
            }
512
513
            // Print rudimentary details:
514
            $output .= '
515
				<br /><br />
516
				<input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.back') . '" name="_back" />
517
				<input type="hidden" value="' . $this->pObj->id . '" name="id" />
518
				<input type="hidden" value="' . $showSetId . '" name="setID" />
519
				<br />
520
				Current server time: ' . date('H:i:s', time()) . '<br />' .
521
                'Status: ' . $resStatus . '<br />' .
522
                DebugUtility::viewArray($q_entry);
523
        } else {	// Show list:
524
525
            // If either id or set id, show list:
526
            if ($this->pObj->id || $showSetId) {
527
                if ($this->pObj->id) {
528
                    // Drawing tree:
529
                    $tree = GeneralUtility::makeInstance('TYPO3\CMS\Backend\Tree\View\PageTreeView');
530
                    $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
531
                    $tree->init('AND ' . $perms_clause);
532
533
                    // Set root row:
534
                    $HTML = IconUtility::getIconForRecord('pages', $this->pObj->pageinfo);
0 ignored issues
show
Bug introduced by
The property pageinfo does not seem to exist in TYPO3\CMS\Backend\Module\BaseScriptClass.

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...
535
                    $tree->tree[] = [
536
                        'row' => $this->pObj->pageinfo,
537
                        'HTML' => $HTML
538
                    ];
539
540
                    // Get branch beneath:
541
                    if ($this->pObj->MOD_SETTINGS['depth']) {
542
                        $tree->getTree($this->pObj->id, $this->pObj->MOD_SETTINGS['depth'], '');
543
                    }
544
545
                    // Traverse page tree:
546
                    $code = '';
547
                    $count = 0;
548
                    foreach ($tree->tree as $data) {
549
                        $code .= $this->drawLog_addRows(
550
                                    $data['row'],
551
                                    $data['HTML'] . BackendUtility::getRecordTitle('pages', $data['row'], true),
552
                                    intval($this->pObj->MOD_SETTINGS['itemsPerPage'])
553
                                );
554
                        if (++$count == 1000) {
555
                            break;
556
                        }
557
                    }
558
                } else {
559
                    $code = '';
560
                    $code .= $this->drawLog_addRows(
561
                                $showSetId,
0 ignored issues
show
Documentation introduced by
$showSetId is of type integer, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
562
                                'Set ID: ' . $showSetId
563
                            );
564
                }
565
566
                if ($code) {
567
                    $output .= '
568
						<br /><br />
569
						<input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.reloadlist') . '" name="_reload" />
570
						<input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.downloadcsv') . '" name="_csv" />
571
						<input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.flushvisiblequeue') . '" name="_flush" onclick="return confirm(\'' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.confirmyouresure') . '\');" />
572
						<input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.flushfullqueue') . '" name="_flush_all" onclick="return confirm(\'' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.confirmyouresure') . '\');" />
573
						<input type="hidden" value="' . $this->pObj->id . '" name="id" />
574
						<input type="hidden" value="' . $showSetId . '" name="setID" />
575
						<br />
576
						' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.curtime') . ': ' . date('H:i:s', time()) . '
577
						<br /><br />
578
579
580
						<table class="lrPadding c-list crawlerlog">' .
581
                            $this->drawLog_printTableHeader() .
582
                            $code .
583
                        '</table>';
584
                }
585
            } else {	// Otherwise show available sets:
586
                $setList = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
587
                                'set_id, count(*) as count_value, scheduled',
588
                                'tx_crawler_queue',
589
                                '',
590
                                'set_id, scheduled',
591
                                'scheduled DESC'
592
                            );
593
594
                $code = '
595
					<tr class="bgColor5 tableheader">
596
						<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.setid') . ':</td>
597
						<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.count') . 't:</td>
598
						<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time') . ':</td>
599
					</tr>
600
				';
601
602
                $cc = 0;
603
                foreach ($setList as $set) {
604
                    $code .= '
605
						<tr class="bgColor' . ($cc % 2 ? '-20' : '-10') . '">
606
							<td><a href="' . htmlspecialchars('index.php?setID=' . $set['set_id']) . '">' . $set['set_id'] . '</a></td>
607
							<td>' . $set['count_value'] . '</td>
608
							<td>' . BackendUtility::dateTimeAge($set['scheduled']) . '</td>
609
						</tr>
610
					';
611
612
                    $cc++;
613
                }
614
615
                $output .= '
616
					<br /><br />
617
					<table class="lrPadding c-list">' .
618
                        $code .
619
                    '</table>';
620
            }
621
        }
622
623
        if ($this->CSVExport) {
624
            $this->outputCsvFile();
625
        }
626
627
        // Return output
628
        return 	$output;
629
    }
630
631
    /**
632
     * Outputs the CSV file and sets the correct headers
633
     */
634
    protected function outputCsvFile()
635
    {
636
        if (!count($this->CSVaccu)) {
637
            $this->addWarningMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.canNotExportEmptyQueueToCsvText'));
638
            return;
639
        }
640
641
        $csvLines = [];
642
643
        // Field names:
644
        reset($this->CSVaccu);
645
        $fieldNames = array_keys(current($this->CSVaccu));
646
        $csvLines[] = GeneralUtility::csvValues($fieldNames);
647
648
        // Data:
649
        foreach ($this->CSVaccu as $row) {
650
            $csvLines[] = GeneralUtility::csvValues($row);
651
        }
652
653
        // Creating output header:
654
        $mimeType = 'application/octet-stream';
655
        Header('Content-Type: ' . $mimeType);
656
        Header('Content-Disposition: attachment; filename=CrawlerLog.csv');
657
658
        // Printing the content of the CSV lines:
659
        echo implode(chr(13) . chr(10), $csvLines);
660
661
        // Exits:
662
        exit;
663
    }
664
665
    /**
666
     * Create the rows for display of the page tree
667
     * For each page a number of rows are shown displaying GET variable configuration
668
     *
669
     * @param array $pageRow_setId Page row or set-id
670
     * @param string $titleString Title string
671
     * @param int $itemsPerPage Items per Page setting
672
     *
673
     * @return string HTML <tr> content (one or more)
674
     */
675
    public function drawLog_addRows($pageRow_setId, $titleString, $itemsPerPage = 10)
676
    {
677
678
            // If Flush button is pressed, flush tables instead of selecting entries:
679
680
        if (GeneralUtility::_POST('_flush')) {
681
            $doFlush = true;
682
            $doFullFlush = false;
683
        } elseif (GeneralUtility::_POST('_flush_all')) {
684
            $doFlush = true;
685
            $doFullFlush = true;
686
        } else {
687
            $doFlush = false;
688
            $doFullFlush = false;
689
        }
690
691
        // Get result:
692
        if (is_array($pageRow_setId)) {
693
            $res = $this->crawlerObj->getLogEntriesForPageId($pageRow_setId['uid'], $this->pObj->MOD_SETTINGS['log_display'], $doFlush, $doFullFlush, intval($itemsPerPage));
694
        } else {
695
            $res = $this->crawlerObj->getLogEntriesForSetId($pageRow_setId, $this->pObj->MOD_SETTINGS['log_display'], $doFlush, $doFullFlush, intval($itemsPerPage));
696
        }
697
698
        // Init var:
699
        $colSpan = 9
700
                + ($this->pObj->MOD_SETTINGS['log_resultLog'] ? -1 : 0)
701
                + ($this->pObj->MOD_SETTINGS['log_feVars'] ? 3 : 0);
702
703
        if (count($res)) {
704
            // Traverse parameter combinations:
705
            $c = 0;
706
            $content = '';
707
            foreach ($res as $kk => $vv) {
0 ignored issues
show
Bug introduced by
The expression $res of type array|null 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...
708
709
                    // Title column:
710
                if (!$c) {
711
                    $titleClm = '<td rowspan="' . count($res) . '">' . $titleString . '</td>';
712
                } else {
713
                    $titleClm = '';
714
                }
715
716
                // Result:
717
                $resLog = $this->getResultLog($vv);
718
719
                $resStatus = $this->getResStatus($vv);
720
                $resFeVars = $this->getResFeVars($vv);
721
722
                // Compile row:
723
                $parameters = unserialize($vv['parameters']);
724
725
                // Put data into array:
726
                $rowData = [];
727
                if ($this->pObj->MOD_SETTINGS['log_resultLog']) {
728
                    $rowData['result_log'] = $resLog;
729
                } else {
730
                    $rowData['scheduled'] = ($vv['scheduled'] > 0) ? BackendUtility::datetime($vv['scheduled']) : ' ' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.immediate');
731
                    $rowData['exec_time'] = $vv['exec_time'] ? BackendUtility::datetime($vv['exec_time']) : '-';
732
                }
733
                $rowData['result_status'] = GeneralUtility::fixed_lgd_cs($resStatus, 50);
734
                $rowData['url'] = '<a href="' . htmlspecialchars($parameters['url']) . '" target="_newWIndow">' . htmlspecialchars($parameters['url']) . '</a>';
735
                $rowData['feUserGroupList'] = $parameters['feUserGroupList'];
736
                $rowData['procInstructions'] = is_array($parameters['procInstructions']) ? implode('; ', $parameters['procInstructions']) : '';
737
                $rowData['set_id'] = $vv['set_id'];
738
739
                if ($this->pObj->MOD_SETTINGS['log_feVars']) {
740
                    $rowData['tsfe_id'] = $resFeVars['id'];
741
                    $rowData['tsfe_gr_list'] = $resFeVars['gr_list'];
742
                    $rowData['tsfe_no_cache'] = $resFeVars['no_cache'];
743
                }
744
745
                $setId = intval(GeneralUtility::_GP('setID'));
746
                $refreshIcon = $GLOBALS['BACK_PATH'] . 'sysext/t3skin/extjs/images/grid/refresh.gif';
747
748
                // Put rows together:
749
                $content .= '
750
					<tr class="bgColor' . ($c % 2 ? '-20' : '-10') . '">
751
						' . $titleClm . '
752
						<td><a href="' . $this->getModuleUrl(['qid_details' => $vv['qid'], 'setID' => $setId]) . '">' . htmlspecialchars($vv['qid']) . '</a></td>
753
						<td><a href="' . $this->getModuleUrl(['qid_read' => $vv['qid'], 'setID' => $setId]) . '"><img src="' . $refreshIcon . '" width="14" hspace="1" vspace="2" height="14" border="0" title="' . htmlspecialchars('Read') . '" alt="" /></a></td>';
754
                foreach ($rowData as $fKey => $value) {
755
                    if (GeneralUtility::inList('url', $fKey)) {
756
                        $content .= '
757
						<td>' . $value . '</td>';
758
                    } else {
759
                        $content .= '
760
						<td>' . nl2br(htmlspecialchars($value)) . '</td>';
761
                    }
762
                }
763
                $content .= '
764
					</tr>';
765
                $c++;
766
767
                if ($this->CSVExport) {
768
                    // Only for CSV (adding qid and scheduled/exec_time if needed):
769
                    $rowData['result_log'] = implode('// ', explode(chr(10), $resLog));
770
                    $rowData['qid'] = $vv['qid'];
771
                    $rowData['scheduled'] = BackendUtility::datetime($vv['scheduled']);
772
                    $rowData['exec_time'] = $vv['exec_time'] ? BackendUtility::datetime($vv['exec_time']) : '-';
773
                    $this->CSVaccu[] = $rowData;
774
                }
775
            }
776
        } else {
777
778
                // Compile row:
779
            $content = '
780
				<tr class="bgColor-20">
781
					<td>' . $titleString . '</td>
782
					<td colspan="' . $colSpan . '"><em>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noentries') . '</em></td>
783
				</tr>';
784
        }
785
786
        return $content;
787
    }
788
789
    /**
790
     * Find Fe vars
791
     *
792
     * @param array $row
793
     * @return array
794
     */
795
    public function getResFeVars($row)
796
    {
797
        $feVars = [];
798
799
        if ($row['result_data']) {
800
            $resultData = unserialize($row['result_data']);
801
            $requestResult = unserialize($resultData['content']);
802
            $feVars = $requestResult['vars'];
803
        }
804
805
        return $feVars;
806
    }
807
808
    /**
809
     * Create Table header row (log)
810
     *
811
     * @return	string		Table header
812
     */
813
    public function drawLog_printTableHeader()
814
    {
815
        $content = '
816
			<tr class="bgColor5 tableheader">
817
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.pagetitle') . ':</td>
818
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.qid') . ':</td>
819
				<td>&nbsp;</td>' .
820
                ($this->pObj->MOD_SETTINGS['log_resultLog'] ? '
821
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.resultlog') . ':</td>' : '
822
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.scheduledtime') . ':</td>
823
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.runtime') . ':</td>') . '
824
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.status') . ':</td>
825
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.url') . ':</td>
826
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.groups') . ':</td>
827
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.procinstr') . ':</td>
828
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.setid') . ':</td>' .
829
                ($this->pObj->MOD_SETTINGS['log_feVars'] ? '
830
				<td>' . htmlspecialchars('TSFE->id') . '</td>
831
				<td>' . htmlspecialchars('TSFE->gr_list') . '</td>
832
				<td>' . htmlspecialchars('TSFE->no_cache') . '</td>' : '') . '
833
			</tr>';
834
835
        return $content;
836
    }
837
838
    /**
839
     * Extract the log information from the current row and retrive it as formatted string.
840
     *
841
     * @param array $resultRow
842
     *
843
     * @return string
844
     */
845
    protected function getResultLog($resultRow)
846
    {
847
        $content = '';
848
849
        if (is_array($resultRow) && array_key_exists('result_data', $resultRow)) {
850
            $requestContent = unserialize($resultRow['result_data']);
851
            $requestResult = unserialize($requestContent['content']);
852
853
            if (is_array($requestResult) && array_key_exists('log', $requestResult)) {
854
                $content = implode(chr(10), $requestResult['log']);
855
            }
856
        }
857
858
        return $content;
859
    }
860
861
    public function getResStatus($vv)
862
    {
863
        if ($vv['result_data']) {
864
            $requestContent = unserialize($vv['result_data']);
865
            $requestResult = unserialize($requestContent['content']);
866
            if (is_array($requestResult)) {
867
                if (empty($requestResult['errorlog'])) {
868
                    $resStatus = 'OK';
869
                } else {
870
                    $resStatus = implode("\n", $requestResult['errorlog']);
871
                }
872
                $resLog = is_array($requestResult['log']) ? implode(chr(10), $requestResult['log']) : '';
0 ignored issues
show
Unused Code introduced by
$resLog is not used, you could remove the assignment.

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

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

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

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

Loading history...
873
            } else {
874
                $resStatus = 'Error: ' . substr(preg_replace('/\s+/', ' ', strip_tags($requestContent['content'])), 0, 10000) . '...';
875
            }
876
        } else {
877
            $resStatus = '-';
878
        }
879
        return $resStatus;
880
    }
881
882
    /*****************************
883
     *
884
     * CLI status display
885
     *
886
     *****************************/
887
888
    /**
889
     * This method is used to show an overview about the active an the finished crawling processes
890
     *
891
     * @param void
892
     * @return string
893
     */
894
    protected function drawProcessOverviewAction()
895
    {
896
        $this->runRefreshHooks();
897
898
        global $BACK_PATH;
899
        $this->makeCrawlerProcessableChecks();
900
901
        $crawler = $this->findCrawler();
902
        try {
903
            $this->handleProcessOverviewActions();
904
        } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class AOE\Crawler\Backend\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
905
            $this->addErrorMessage($e->getMessage());
906
        }
907
908
        $offset = intval(GeneralUtility::_GP('offset'));
909
        $perpage = 20;
910
911
        $processRepository = new ProcessRepository();
912
        $queueRepository = new QueueRepository();
913
914
        $mode = $this->pObj->MOD_SETTINGS['processListMode'];
915
        if ($mode == 'detail') {
916
            $where = '';
917
        } elseif ($mode == 'simple') {
918
            $where = 'active = 1';
919
        }
920
921
        $allProcesses = $processRepository->findAll('ttl', 'DESC', $perpage, $offset, $where);
0 ignored issues
show
Bug introduced by
The variable $where 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...
922
        $allCount = $processRepository->countAll($where);
923
924
        $listView = new ProcessListView();
925
        $listView->setPageId($this->pObj->id);
926
        $listView->setIconPath($BACK_PATH . '../typo3conf/ext/crawler/template/process/res/img/');
927
        $listView->setProcessCollection($allProcesses);
928
        $listView->setCliPath($this->processManager->getCrawlerCliPath());
929
        $listView->setIsCrawlerEnabled(!$crawler->getDisabled() && !$this->isErrorDetected);
930
        $listView->setTotalUnprocessedItemCount($queueRepository->countAllPendingItems());
931
        $listView->setAssignedUnprocessedItemCount($queueRepository->countAllAssignedPendingItems());
932
        $listView->setActiveProcessCount($processRepository->countActive());
933
        $listView->setMaxActiveProcessCount(MathUtility::forceIntegerInRange($this->extensionSettings['processLimit'], 1, 99, 1));
934
        $listView->setMode($mode);
935
936
        $paginationView = new PaginationView();
937
        $paginationView->setCurrentOffset($offset);
938
        $paginationView->setPerPage($perpage);
939
        $paginationView->setTotalItemCount($allCount);
940
941
        $output = $listView->render();
942
943
        if ($paginationView->getTotalPagesCount() > 1) {
944
            $output .= ' <br />' . $paginationView->render();
945
        }
946
947
        return $output;
948
    }
949
950
    /**
951
     * Verify that the crawler is exectuable.
952
     *
953
     * @return void
954
     */
955
    protected function makeCrawlerProcessableChecks()
956
    {
957
        global $LANG;
958
959
        if ($this->isCrawlerUserAvailable() === false) {
960
            $this->addErrorMessage($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.noBeUserAvailable'));
961
        } elseif ($this->isCrawlerUserNotAdmin() === false) {
962
            $this->addErrorMessage($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.beUserIsAdmin'));
963
        }
964
965
        if ($this->isPhpForkAvailable() === false) {
966
            $this->addErrorMessage($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.noPhpForkAvailable'));
967
        }
968
969
        $exitCode = 0;
970
        $out = [];
971
        exec(escapeshellcmd($this->extensionSettings['phpPath'] . ' -v'), $out, $exitCode);
972
        if ($exitCode > 0) {
973
            $this->addErrorMessage(sprintf($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.phpBinaryNotFound'), htmlspecialchars($this->extensionSettings['phpPath'])));
974
        }
975
    }
976
977
    /**
978
     * Indicate that the required PHP method "popen" is
979
     * available in the system.
980
     *
981
     * @return boolean
982
     */
983
    protected function isPhpForkAvailable()
984
    {
985
        return function_exists('popen');
986
    }
987
988
    /**
989
     * Indicate that the required be_user "_cli_crawler" is
990
     * global available in the system.
991
     *
992
     * @return boolean
993
     */
994
    protected function isCrawlerUserAvailable()
995
    {
996
        $isAvailable = false;
997
        $userArray = BackendUtility::getRecordsByField('be_users', 'username', '_cli_crawler');
998
999
        if (is_array($userArray)) {
1000
            $isAvailable = true;
1001
        }
1002
1003
        return $isAvailable;
1004
    }
1005
1006
    /**
1007
     * Indicate that the required be_user "_cli_crawler" is
1008
     * has no admin rights.
1009
     *
1010
     * @return boolean
1011
     */
1012
    protected function isCrawlerUserNotAdmin()
1013
    {
1014
        $isAvailable = false;
1015
        $userArray = BackendUtility::getRecordsByField('be_users', 'username', '_cli_crawler');
1016
1017
        if (is_array($userArray) && $userArray[0]['admin'] == 0) {
1018
            $isAvailable = true;
1019
        }
1020
1021
        return $isAvailable;
1022
    }
1023
1024
    /**
1025
     * Method to handle incomming actions of the process overview
1026
     *
1027
     * @throws \Exception
1028
     *
1029
     * @return void
1030
     */
1031
    protected function handleProcessOverviewActions()
1032
    {
1033
        $crawler = $this->findCrawler();
1034
1035
        switch (GeneralUtility::_GP('action')) {
1036
            case 'stopCrawling':
1037
                //set the cli status to disable (all processes will be terminated)
1038
                $crawler->setDisabled(true);
1039
                break;
1040
            case 'resumeCrawling':
1041
                //set the cli status to end (all processes will be terminated)
1042
                $crawler->setDisabled(false);
1043
                break;
1044
            case 'addProcess':
1045
                $handle = $this->processManager->startProcess();
1046
                if ($handle === false) {
1047
                    throw new \Exception($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.newprocesserror'));
1048
                }
1049
                $this->addNoticeMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.newprocess'));
1050
                break;
1051
        }
1052
    }
1053
1054
    /**
1055
     * Returns the singleton instance of the crawler.
1056
     *
1057
     * @param void
1058
     * @return CrawlerController crawler object
1059
     */
1060
    protected function findCrawler()
1061
    {
1062
        if (!$this->crawlerObj instanceof CrawlerController) {
1063
            $this->crawlerObj = GeneralUtility::makeInstance(CrawlerController::class);
1064
        }
1065
        return $this->crawlerObj;
1066
    }
1067
1068
    /*****************************
1069
     *
1070
     * General Helper Functions
1071
     *
1072
     *****************************/
1073
1074
    /**
1075
     * This method is used to add a message to the internal queue
1076
     *
1077
     * @param  string  the message itself
1078
     * @param  integer message level (-1 = success (default), 0 = info, 1 = notice, 2 = warning, 3 = error)
1079
     *
1080
     * @return void
1081
     */
1082
    private function addMessage($message, $severity = FlashMessage::OK)
1083
    {
1084
        $message = GeneralUtility::makeInstance(
1085
            FlashMessage::class,
1086
            $message,
1087
            '',
1088
            $severity
1089
        );
1090
1091
        // TODO:
1092
        /** @var FlashMessageService $flashMessageService */
1093
        $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
1094
        $flashMessageService->getMessageQueueByIdentifier()->addMessage($message);
1095
    }
1096
1097
    /**
1098
     * Add notice message to the user interface.
1099
     *
1100
     * @param string The message
1101
     *
1102
     * @return void
1103
     */
1104
    protected function addNoticeMessage($message)
1105
    {
1106
        $this->addMessage($message, FlashMessage::NOTICE);
1107
    }
1108
1109
    /**
1110
     * Add error message to the user interface.
1111
     *
1112
     * @param string The message
1113
     *
1114
     * @return void
1115
     */
1116
    protected function addErrorMessage($message)
1117
    {
1118
        $this->isErrorDetected = true;
1119
        $this->addMessage($message, FlashMessage::ERROR);
1120
    }
1121
1122
    /**
1123
     * Add error message to the user interface.
1124
     *
1125
     * NOTE:
1126
     * This method is basesd on TYPO3 4.3 or higher!
1127
     *
1128
     * @param string The message
1129
     *
1130
     * @return void
1131
     */
1132
    protected function addWarningMessage($message)
1133
    {
1134
        $this->addMessage($message, FlashMessage::WARNING);
1135
    }
1136
1137
    /**
1138
     * Create selector box
1139
     *
1140
     * @param	array		$optArray Options key(value) => label pairs
1141
     * @param	string		$name Selector box name
1142
     * @param	string		$value Selector box value (array for multiple...)
1143
     * @param	boolean		$multiple If set, will draw multiple box.
1144
     *
1145
     * @return	string		HTML select element
1146
     */
1147
    public function selectorBox($optArray, $name, $value, $multiple)
1148
    {
1149
        $options = [];
1150
        foreach ($optArray as $key => $val) {
1151
            $options[] = '
1152
				<option value="' . htmlspecialchars($key) . '"' . ((!$multiple && !strcmp($value, $key)) || ($multiple && in_array($key, (array)$value)) ? ' selected="selected"' : '') . '>' . htmlspecialchars($val) . '</option>';
1153
        }
1154
1155
        $output = '<select name="' . htmlspecialchars($name . ($multiple ? '[]' : '')) . '"' . ($multiple ? ' multiple="multiple" size="' . count($options) . '"' : '') . '>' . implode('', $options) . '</select>';
1156
1157
        return $output;
1158
    }
1159
1160
    /**
1161
     * Activate hooks
1162
     *
1163
     * @return	void
1164
     */
1165
    public function runRefreshHooks()
1166
    {
1167
        $crawlerLib = GeneralUtility::makeInstance(CrawlerController::class);
1168
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['crawler']['refresh_hooks'])) {
1169
            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['crawler']['refresh_hooks'] as $objRef) {
1170
                $hookObj = &GeneralUtility::getUserObj($objRef);
1171
                if (is_object($hookObj)) {
1172
                    $hookObj->crawler_init($crawlerLib);
1173
                }
1174
            }
1175
        }
1176
    }
1177
1178
    /**
1179
     * Returns the URL to the current module, including $_GET['id'].
1180
     *
1181
     * @param array $urlParameters optional parameters to add to the URL
1182
     * @return string
1183
     */
1184
    protected function getModuleUrl(array $urlParameters = [])
1185
    {
1186
        if ($this->pObj->id) {
1187
            $urlParameters = array_merge($urlParameters, [
1188
                'id' => $this->pObj->id
1189
            ]);
1190
        }
1191
        return BackendUtility::getModuleUrl(GeneralUtility::_GP('M'), $urlParameters);
0 ignored issues
show
Bug introduced by
It seems like \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('M') targeting TYPO3\CMS\Core\Utility\GeneralUtility::_GP() can also be of type array or null; however, TYPO3\CMS\Backend\Utilit...Utility::getModuleUrl() does only seem to accept string, maybe add an additional type check?

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

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

An additional type check may prevent trouble.

Loading history...
1192
    }
1193
}
1194