Completed
Push — master ( 1b04e6...82e336 )
by Tomas Norre
08:07
created

Classes/Backend/BackendModule.php (10 issues)

Upgrade to new PHP Analysis Engine

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

1
<?php
2
namespace AOE\Crawler\Backend;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2018 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\Tree\View\PageTreeView;
39
use TYPO3\CMS\Backend\Utility\BackendUtility;
40
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
41
use TYPO3\CMS\Core\Imaging\Icon;
42
use TYPO3\CMS\Core\Messaging\FlashMessage;
43
use TYPO3\CMS\Core\Messaging\FlashMessageService;
44
use TYPO3\CMS\Core\Utility\DebugUtility;
45
use TYPO3\CMS\Core\Utility\GeneralUtility;
46
use TYPO3\CMS\Core\Utility\MathUtility;
47
48
/**
49
 * Class BackendModule
50
 *
51
 * @package AOE\Crawler\Backend
52
 */
53
class BackendModule extends AbstractFunctionModule
54
{
55
    // Internal, dynamic:
56
    public $duplicateTrack = [];
57
    public $submitCrawlUrls = false;
58
    public $downloadCrawlUrls = false;
59
60
    public $scheduledTime = 0;
61
    public $reqMinute = 0;
62
63
    /**
64
     * @var array holds the selection of configuration from the configuration selector box
65
     */
66
    public $incomingConfigurationSelection = [];
67
68
    /**
69
     * @var CrawlerController
70
     */
71
    public $crawlerController;
72
73
    public $CSVaccu = [];
74
75
    /**
76
     * If true the user requested a CSV export of the queue
77
     *
78
     * @var boolean
79
     */
80
    public $CSVExport = false;
81
82
    public $downloadUrls = [];
83
84
    /**
85
     * Holds the configuration from ext_conf_template loaded by loadExtensionSettings()
86
     *
87
     * @var array
88
     */
89
    protected $extensionSettings = [];
90
91
    /**
92
     * Indicate that an flash message with an error is present.
93
     *
94
     * @var boolean
95
     */
96
    protected $isErrorDetected = false;
97
98
    /**
99
     * @var ProcessService
100
     */
101
    protected $processManager;
102
103
    /**
104
     * the constructor
105
     */
106
    public function __construct()
107
    {
108
        $this->processManager = new ProcessService();
109
    }
110
111
    /**
112
     * Additions to the function menu array
113
     *
114
     * @return array Menu array
115
     */
116
    public function modMenu()
117
    {
118
        global $LANG;
119
120
        return [
121
            'depth' => [
122
                0 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
123
                1 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
124
                2 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
125
                3 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
126
                4 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
127
                99 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi'),
128
            ],
129
            'crawlaction' => [
130
                'start' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.start'),
131
                'log' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.log'),
132
                'multiprocess' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.multiprocess')
133
            ],
134
            'log_resultLog' => '',
135
            'log_feVars' => '',
136
            'processListMode' => '',
137
            'log_display' => [
138
                'all' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.all'),
139
                'pending' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.pending'),
140
                'finished' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.finished')
141
            ],
142
            'itemsPerPage' => [
143
                '5' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.5'),
144
                '10' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.10'),
145
                '50' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.50'),
146
                '0' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.0')
147
            ]
148
        ];
149
    }
150
151
    /**
152
     * Load extension settings
153
     *
154
     * @return void
155
     */
156
    protected function loadExtensionSettings()
157
    {
158
        $this->extensionSettings = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['crawler']);
159
    }
160
161
    /**
162
     * Main function
163
     *
164
     * @return	string		HTML output
165
     */
166
    public function main()
167
    {
168
        global $LANG, $BACK_PATH;
169
170
        $this->incLocalLang();
171
172
        $this->loadExtensionSettings();
173
        if (empty($this->pObj->MOD_SETTINGS['processListMode'])) {
174
            $this->pObj->MOD_SETTINGS['processListMode'] = 'simple';
175
        }
176
177
        // Set CSS styles specific for this document:
178
        $this->pObj->content = str_replace('/*###POSTCSSMARKER###*/', '
179
			TABLE.c-list TR TD { white-space: nowrap; vertical-align: top; }
180
		', $this->pObj->content);
181
182
        $this->pObj->content .= '<style type="text/css"><!--
183
			table.url-table,
184
			table.param-expanded,
185
			table.crawlerlog {
186
				border-bottom: 1px solid grey;
187
				border-spacing: 0;
188
				border-collapse: collapse;
189
			}
190
			table.crawlerlog td,
191
			table.url-table td {
192
				border: 1px solid lightgrey;
193
				border-bottom: 1px solid grey;
194
				 white-space: nowrap; vertical-align: top;
195
			}
196
		--></style>
197
		<link rel="stylesheet" type="text/css" href="' . $BACK_PATH . '../typo3conf/ext/crawler/template/res.css" />
198
		';
199
200
        // Type function menu:
201
        $h_func = BackendUtility::getFuncMenu(
202
            $this->pObj->id,
203
            'SET[crawlaction]',
204
            $this->pObj->MOD_SETTINGS['crawlaction'],
205
            $this->pObj->MOD_MENU['crawlaction'],
206
            'index.php'
207
        );
208
209
        // Additional menus for the log type:
210
        if ($this->pObj->MOD_SETTINGS['crawlaction'] === 'log') {
211
            $h_func .= BackendUtility::getFuncMenu(
212
                $this->pObj->id,
213
                'SET[depth]',
214
                $this->pObj->MOD_SETTINGS['depth'],
215
                $this->pObj->MOD_MENU['depth'],
216
                'index.php'
217
            );
218
219
            $quiPart = GeneralUtility::_GP('qid_details') ? '&qid_details=' . intval(GeneralUtility::_GP('qid_details')) : '';
220
221
            $setId = intval(GeneralUtility::_GP('setID'));
222
223
            $h_func .= '<hr/>' .
224
                    $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) . ' - ' .
225
                    $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) . ' - ' .
226
                    $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) . ' - ' .
227
                    $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage') . ': ' .
228
                    BackendUtility::getFuncMenu(
229
                        $this->pObj->id,
230
                        'SET[itemsPerPage]',
231
                        $this->pObj->MOD_SETTINGS['itemsPerPage'],
232
                        $this->pObj->MOD_MENU['itemsPerPage'],
233
                        'index.php'
234
                    );
235
        }
236
237
        $theOutput = $this->pObj->doc->section($LANG->getLL('title'), $h_func, false, true);
238
239
        // Branch based on type:
240
        switch ((string)$this->pObj->MOD_SETTINGS['crawlaction']) {
241
            case 'start':
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->drawURLs(), false, true);
246
                }
247
                break;
248
            case 'log':
249
                if (empty($this->pObj->id)) {
250
                    $this->addErrorMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noPageSelected'));
251
                } else {
252
                    $theOutput .= $this->pObj->doc->section('', $this->drawLog(), false, true);
253
                }
254
                break;
255
            case 'cli':
256
                // TODO: drawCLIstatus is not defined, why did we refactor it away?
257
                $theOutput .= $this->pObj->doc->section('', $this->drawCLIstatus(), false, true);
0 ignored issues
show
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...
258
                break;
259
            case 'multiprocess':
260
                $theOutput .= $this->pObj->doc->section('', $this->drawProcessOverviewAction(), false, true);
261
                break;
262
        }
263
264
        return $theOutput;
265
    }
266
267
    /*******************************
268
     *
269
     * Generate URLs for crawling:
270
     *
271
     ******************************/
272
273
    /**
274
     * Produces a table with overview of the URLs to be crawled for each page
275
     *
276
     * @return	string		HTML output
277
     */
278
    public function drawURLs()
279
    {
280
        global $BACK_PATH, $BE_USER;
281
282
        $crawlerParameter = GeneralUtility::_GP('_crawl');
283
        $downloadParameter = GeneralUtility::_GP('_download');
284
285
        // Init:
286
        $this->duplicateTrack = [];
287
        $this->submitCrawlUrls = isset($crawlerParameter);
288
        $this->downloadCrawlUrls = isset($downloadParameter);
289
        $this->makeCrawlerProcessableChecks();
290
291
        switch ((string) GeneralUtility::_GP('tstamp')) {
292
            case 'midnight':
293
                $this->scheduledTime = mktime(0, 0, 0);
294
            break;
295
            case '04:00':
296
                $this->scheduledTime = mktime(0, 0, 0) + 4 * 3600;
297
            break;
298
            case 'now':
299
            default:
300
                $this->scheduledTime = time();
301
            break;
302
        }
303
        // $this->reqMinute = \TYPO3\CMS\Core\Utility\GeneralUtility::intInRange(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('perminute'),1,10000);
304
        // TODO: check relevance
305
        $this->reqMinute = 1000;
306
307
        $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...
308
        $this->incomingConfigurationSelection = is_array($this->incomingConfigurationSelection) ? $this->incomingConfigurationSelection : [];
309
310
        $this->crawlerController = GeneralUtility::makeInstance(CrawlerController::class);
311
        $this->crawlerController->setAccessMode('gui');
312
        $this->crawlerController->setID = GeneralUtility::md5int(microtime());
313
314
        if (empty($this->incomingConfigurationSelection)
315
            || (count($this->incomingConfigurationSelection) == 1 && empty($this->incomingConfigurationSelection[0]))
316
            ) {
317
            $this->addWarningMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noConfigSelected'));
318
            $code = '
319
			<tr>
320
				<td colspan="7"><b>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noConfigSelected') . '</b></td>
321
			</tr>';
322
        } else {
323
            if ($this->submitCrawlUrls) {
324
                $reason = new Reason();
325
                $reason->setReason(Reason::REASON_GUI_SUBMIT);
326
327
                if ($BE_USER instanceof BackendUserAuthentication) {
328
                    $username = $BE_USER->user['username'];
329
                    $reason->setDetailText('The user ' . $username . ' added pages to the crawler queue manually ');
330
                }
331
332
                EventDispatcher::getInstance()->post(
333
                    'invokeQueueChange',
334
                    $this->findCrawler()->setID,
335
                    ['reason' => $reason]
336
                );
337
            }
338
339
            $code = $this->crawlerController->getPageTreeAndUrls(
340
                $this->pObj->id,
341
                $this->pObj->MOD_SETTINGS['depth'],
342
                $this->scheduledTime,
343
                $this->reqMinute,
344
                $this->submitCrawlUrls,
345
                $this->downloadCrawlUrls,
346
                [], // Do not filter any processing instructions
347
                $this->incomingConfigurationSelection
348
            );
349
        }
350
351
        $this->downloadUrls = $this->crawlerController->downloadUrls;
352
        $this->duplicateTrack = $this->crawlerController->duplicateTrack;
353
354
        $output = '';
355
        if ($code) {
356
            $output .= '<h3>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.configuration') . ':</h3>';
357
            $output .= '<input type="hidden" name="id" value="' . intval($this->pObj->id) . '" />';
358
359
            if (!$this->submitCrawlUrls) {
360
                $output .= $this->drawURLs_cfgSelectors() . '<br />';
361
                $output .= '<input type="submit" name="_update" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.triggerUpdate') . '" /> ';
362
                $output .= '<input type="submit" name="_crawl" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.triggerCrawl') . '" /> ';
363
                $output .= '<input type="submit" name="_download" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.triggerDownload') . '" /><br /><br />';
364
                $output .= $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.count') . ': ' . count(array_keys($this->duplicateTrack)) . '<br />';
365
                $output .= $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.curtime') . ': ' . date('H:i:s', time()) . '<br />';
366
                $output .= '<br />
367
					<table class="lrPadding c-list url-table">' .
368
                        $this->drawURLs_printTableHeader() .
369
                        $code .
370
                    '</table>';
371
            } else {
372
                $output .= count(array_keys($this->duplicateTrack)) . ' ' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.submitted') . '. <br /><br />';
373
                $output .= '<input type="submit" name="_" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.continue') . '" />';
374
                $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') . '" />';
375
            }
376
        }
377
378
        // Download Urls to crawl:
379
        if ($this->downloadCrawlUrls) {
380
381
                // Creating output header:
382
            $mimeType = 'application/octet-stream';
383
            Header('Content-Type: ' . $mimeType);
384
            Header('Content-Disposition: attachment; filename=CrawlerUrls.txt');
385
386
            // Printing the content of the CSV lines:
387
            echo implode(chr(13) . chr(10), $this->downloadUrls);
388
389
            exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method drawURLs() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
390
        }
391
392
        return 	$output;
393
    }
394
395
    /**
396
     * Draws the configuration selectors for compiling URLs:
397
     *
398
     * @return	string		HTML table
399
     */
400
    public function drawURLs_cfgSelectors()
401
    {
402
        $cell = [];
403
404
        // depth
405
        $cell[] = $this->selectorBox(
406
            [
407
                0 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
408
                1 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
409
                2 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
410
                3 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
411
                4 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
412
                99 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi'),
413
            ],
414
            'SET[depth]',
415
            $this->pObj->MOD_SETTINGS['depth'],
416
            false
417
        );
418
        $availableConfigurations = $this->crawlerController->getConfigurationsForBranch($this->pObj->id, $this->pObj->MOD_SETTINGS['depth'] ? $this->pObj->MOD_SETTINGS['depth'] : 0);
419
420
        // Configurations
421
        $cell[] = $this->selectorBox(
422
            empty($availableConfigurations) ? [] : array_combine($availableConfigurations, $availableConfigurations),
423
            'configurationSelection',
424
            $this->incomingConfigurationSelection,
0 ignored issues
show
$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...
425
            true
426
        );
427
428
        // Scheduled time:
429
        $cell[] = $this->selectorBox(
430
            [
431
                'now' => $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time.now'),
432
                'midnight' => $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time.midnight'),
433
                '04:00' => $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time.4am'),
434
            ],
435
            'tstamp',
436
            GeneralUtility::_POST('tstamp'),
0 ignored issues
show
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...
437
            false
438
        );
439
440
        $output = '
441
			<table class="lrPadding c-list">
442
				<tr class="bgColor5 tableheader">
443
					<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.depth') . ':</td>
444
					<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.configurations') . ':</td>
445
					<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.scheduled') . ':</td>
446
				</tr>
447
				<tr class="bgColor4">
448
					<td valign="top">' . implode('</td>
449
					<td valign="top">', $cell) . '</td>
450
				</tr>
451
			</table>';
452
453
        return $output;
454
    }
455
456
    /**
457
     * Create Table header row for URL display
458
     *
459
     * @return	string		Table header
460
     */
461
    public function drawURLs_printTableHeader()
462
    {
463
        $content = '
464
			<tr class="bgColor5 tableheader">
465
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.pagetitle') . ':</td>
466
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.key') . ':</td>
467
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.parametercfg') . ':</td>
468
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.values') . ':</td>
469
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.urls') . ':</td>
470
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.options') . ':</td>
471
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.parameters') . ':</td>
472
			</tr>';
473
474
        return $content;
475
    }
476
477
    /*******************************
478
     *
479
     * Shows log of indexed URLs
480
     *
481
     ******************************/
482
483
    /**
484
     * Shows the log of indexed URLs
485
     *
486
     * @return	string		HTML output
487
     */
488
    public function drawLog()
489
    {
490
        global $BACK_PATH;
491
        $output = '';
492
493
        // Init:
494
        $this->crawlerController = GeneralUtility::makeInstance(CrawlerController::class);
495
        $this->crawlerController->setAccessMode('gui');
496
        $this->crawlerController->setID = GeneralUtility::md5int(microtime());
497
498
        $csvExport = GeneralUtility::_POST('_csv');
499
        $this->CSVExport = isset($csvExport);
500
501
        // Read URL:
502
        if (GeneralUtility::_GP('qid_read')) {
503
            $this->crawlerController->readUrl(intval(GeneralUtility::_GP('qid_read')), true);
504
        }
505
506
        // Look for set ID sent - if it is, we will display contents of that set:
507
        $showSetId = intval(GeneralUtility::_GP('setID'));
508
509
        // Show details:
510
        if (GeneralUtility::_GP('qid_details')) {
511
512
                // Get entry record:
513
            list($q_entry) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'tx_crawler_queue', 'qid=' . intval(GeneralUtility::_GP('qid_details')));
514
515
            // Explode values:
516
            $resStatus = $this->getResStatus($q_entry);
517
            $q_entry['parameters'] = unserialize($q_entry['parameters']);
518
            $q_entry['result_data'] = unserialize($q_entry['result_data']);
519
            if (is_array($q_entry['result_data'])) {
520
                $q_entry['result_data']['content'] = unserialize($q_entry['result_data']['content']);
521
522
                if (!$this->pObj->MOD_SETTINGS['log_resultLog']) {
523
                    unset($q_entry['result_data']['content']['log']);
524
                }
525
            }
526
527
            // Print rudimentary details:
528
            $output .= '
529
				<br /><br />
530
				<input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.back') . '" name="_back" />
531
				<input type="hidden" value="' . $this->pObj->id . '" name="id" />
532
				<input type="hidden" value="' . $showSetId . '" name="setID" />
533
				<br />
534
				Current server time: ' . date('H:i:s', time()) . '<br />' .
535
                'Status: ' . $resStatus . '<br />' .
536
                DebugUtility::viewArray($q_entry);
537
        } else {	// Show list:
538
539
            // If either id or set id, show list:
540
            if ($this->pObj->id || $showSetId) {
541
                if ($this->pObj->id) {
542
                    // Drawing tree:
543
                    $tree = GeneralUtility::makeInstance(PageTreeView::class);
544
                    $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
545
                    $tree->init('AND ' . $perms_clause);
546
547
                    // Set root row:
548
                    $HTML = IconUtility::getIconForRecord('pages', $this->pObj->pageinfo);
0 ignored issues
show
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...
549
                    $tree->tree[] = [
550
                        'row' => $this->pObj->pageinfo,
551
                        'HTML' => $HTML
552
                    ];
553
554
                    // Get branch beneath:
555
                    if ($this->pObj->MOD_SETTINGS['depth']) {
556
                        $tree->getTree($this->pObj->id, $this->pObj->MOD_SETTINGS['depth'], '');
557
                    }
558
559
                    // Traverse page tree:
560
                    $code = '';
561
                    $count = 0;
562
                    foreach ($tree->tree as $data) {
563
                        $code .= $this->drawLog_addRows(
564
                                    $data['row'],
565
                                    $data['HTML'] . BackendUtility::getRecordTitle('pages', $data['row'], true),
566
                                    intval($this->pObj->MOD_SETTINGS['itemsPerPage'])
567
                                );
568
                        if (++$count == 1000) {
569
                            break;
570
                        }
571
                    }
572
                } else {
573
                    $code = '';
574
                    $code .= $this->drawLog_addRows(
575
                                $showSetId,
0 ignored issues
show
$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...
576
                                'Set ID: ' . $showSetId
577
                            );
578
                }
579
580
                if ($code) {
581
                    $output .= '
582
						<br /><br />
583
						<input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.reloadlist') . '" name="_reload" />
584
						<input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.downloadcsv') . '" name="_csv" />
585
						<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') . '\');" />
586
						<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') . '\');" />
587
						<input type="hidden" value="' . $this->pObj->id . '" name="id" />
588
						<input type="hidden" value="' . $showSetId . '" name="setID" />
589
						<br />
590
						' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.curtime') . ': ' . date('H:i:s', time()) . '
591
						<br /><br />
592
593
594
						<table class="lrPadding c-list crawlerlog">' .
595
                            $this->drawLog_printTableHeader() .
596
                            $code .
597
                        '</table>';
598
                }
599
            } else {	// Otherwise show available sets:
600
                $setList = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
601
                                'set_id, count(*) as count_value, scheduled',
602
                                'tx_crawler_queue',
603
                                '',
604
                                'set_id, scheduled',
605
                                'scheduled DESC'
606
                            );
607
608
                $code = '
609
					<tr class="bgColor5 tableheader">
610
						<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.setid') . ':</td>
611
						<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.count') . 't:</td>
612
						<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time') . ':</td>
613
					</tr>
614
				';
615
616
                $cc = 0;
617
                foreach ($setList as $set) {
618
                    $code .= '
619
						<tr class="bgColor' . ($cc % 2 ? '-20' : '-10') . '">
620
							<td><a href="' . htmlspecialchars('index.php?setID=' . $set['set_id']) . '">' . $set['set_id'] . '</a></td>
621
							<td>' . $set['count_value'] . '</td>
622
							<td>' . BackendUtility::dateTimeAge($set['scheduled']) . '</td>
623
						</tr>
624
					';
625
626
                    $cc++;
627
                }
628
629
                $output .= '
630
					<br /><br />
631
					<table class="lrPadding c-list">' .
632
                        $code .
633
                    '</table>';
634
            }
635
        }
636
637
        if ($this->CSVExport) {
638
            $this->outputCsvFile();
639
        }
640
641
        // Return output
642
        return 	$output;
643
    }
644
645
    /**
646
     * Outputs the CSV file and sets the correct headers
647
     */
648
    protected function outputCsvFile()
649
    {
650
        if (!count($this->CSVaccu)) {
651
            $this->addWarningMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.canNotExportEmptyQueueToCsvText'));
652
            return;
653
        }
654
655
        $csvLines = [];
656
657
        // Field names:
658
        reset($this->CSVaccu);
659
        $fieldNames = array_keys(current($this->CSVaccu));
660
        $csvLines[] = GeneralUtility::csvValues($fieldNames);
661
662
        // Data:
663
        foreach ($this->CSVaccu as $row) {
664
            $csvLines[] = GeneralUtility::csvValues($row);
665
        }
666
667
        // Creating output header:
668
        $mimeType = 'application/octet-stream';
669
        Header('Content-Type: ' . $mimeType);
670
        Header('Content-Disposition: attachment; filename=CrawlerLog.csv');
671
672
        // Printing the content of the CSV lines:
673
        echo implode(chr(13) . chr(10), $csvLines);
674
675
        // Exits:
676
        exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method outputCsvFile() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
677
    }
678
679
    /**
680
     * Create the rows for display of the page tree
681
     * For each page a number of rows are shown displaying GET variable configuration
682
     *
683
     * @param array $pageRow_setId Page row or set-id
684
     * @param string $titleString Title string
685
     * @param int $itemsPerPage Items per Page setting
686
     *
687
     * @return string HTML <tr> content (one or more)
688
     */
689
    public function drawLog_addRows($pageRow_setId, $titleString, $itemsPerPage = 10)
690
    {
691
692
            // If Flush button is pressed, flush tables instead of selecting entries:
693
694
        if (GeneralUtility::_POST('_flush')) {
695
            $doFlush = true;
696
            $doFullFlush = false;
697
        } elseif (GeneralUtility::_POST('_flush_all')) {
698
            $doFlush = true;
699
            $doFullFlush = true;
700
        } else {
701
            $doFlush = false;
702
            $doFullFlush = false;
703
        }
704
705
        // Get result:
706
        if (is_array($pageRow_setId)) {
707
            $res = $this->crawlerController->getLogEntriesForPageId($pageRow_setId['uid'], $this->pObj->MOD_SETTINGS['log_display'], $doFlush, $doFullFlush, intval($itemsPerPage));
708
        } else {
709
            $res = $this->crawlerController->getLogEntriesForSetId($pageRow_setId, $this->pObj->MOD_SETTINGS['log_display'], $doFlush, $doFullFlush, intval($itemsPerPage));
710
        }
711
712
        // Init var:
713
        $colSpan = 9
714
                + ($this->pObj->MOD_SETTINGS['log_resultLog'] ? -1 : 0)
715
                + ($this->pObj->MOD_SETTINGS['log_feVars'] ? 3 : 0);
716
717
        if (count($res)) {
718
            // Traverse parameter combinations:
719
            $c = 0;
720
            $content = '';
721
            foreach ($res as $kk => $vv) {
0 ignored issues
show
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...
722
723
                    // Title column:
724
                if (!$c) {
725
                    $titleClm = '<td rowspan="' . count($res) . '">' . $titleString . '</td>';
726
                } else {
727
                    $titleClm = '';
728
                }
729
730
                // Result:
731
                $resLog = $this->getResultLog($vv);
732
733
                $resStatus = $this->getResStatus($vv);
734
                $resFeVars = $this->getResFeVars($vv);
735
736
                // Compile row:
737
                $parameters = unserialize($vv['parameters']);
738
739
                // Put data into array:
740
                $rowData = [];
741
                if ($this->pObj->MOD_SETTINGS['log_resultLog']) {
742
                    $rowData['result_log'] = $resLog;
743
                } else {
744
                    $rowData['scheduled'] = ($vv['scheduled'] > 0) ? BackendUtility::datetime($vv['scheduled']) : ' ' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.immediate');
745
                    $rowData['exec_time'] = $vv['exec_time'] ? BackendUtility::datetime($vv['exec_time']) : '-';
746
                }
747
                $rowData['result_status'] = GeneralUtility::fixed_lgd_cs($resStatus, 50);
748
                $rowData['url'] = '<a href="' . htmlspecialchars($parameters['url']) . '" target="_newWIndow">' . htmlspecialchars($parameters['url']) . '</a>';
749
                $rowData['feUserGroupList'] = $parameters['feUserGroupList'];
750
                $rowData['procInstructions'] = is_array($parameters['procInstructions']) ? implode('; ', $parameters['procInstructions']) : '';
751
                $rowData['set_id'] = $vv['set_id'];
752
753
                if ($this->pObj->MOD_SETTINGS['log_feVars']) {
754
                    $rowData['tsfe_id'] = $resFeVars['id'];
755
                    $rowData['tsfe_gr_list'] = $resFeVars['gr_list'];
756
                    $rowData['tsfe_no_cache'] = $resFeVars['no_cache'];
757
                }
758
759
                $setId = intval(GeneralUtility::_GP('setID'));
760
                $refreshIcon = IconUtility::getIcon('actions-system-refresh', Icon::SIZE_SMALL);
761
762
                // Put rows together:
763
                $content .= '
764
					<tr class="bgColor' . ($c % 2 ? '-20' : '-10') . '">
765
						' . $titleClm . '
766
						<td><a href="' . $this->getModuleUrl(['qid_details' => $vv['qid'], 'setID' => $setId]) . '">' . htmlspecialchars($vv['qid']) . '</a></td>
767
						<td><a href="' . $this->getModuleUrl(['qid_read' => $vv['qid'], 'setID' => $setId]) . '">' . $refreshIcon . '</a></td>';
768
                foreach ($rowData as $fKey => $value) {
769
                    if (GeneralUtility::inList('url', $fKey)) {
770
                        $content .= '
771
						<td>' . $value . '</td>';
772
                    } else {
773
                        $content .= '
774
						<td>' . nl2br(htmlspecialchars($value)) . '</td>';
775
                    }
776
                }
777
                $content .= '
778
					</tr>';
779
                $c++;
780
781
                if ($this->CSVExport) {
782
                    // Only for CSV (adding qid and scheduled/exec_time if needed):
783
                    $rowData['result_log'] = implode('// ', explode(chr(10), $resLog));
784
                    $rowData['qid'] = $vv['qid'];
785
                    $rowData['scheduled'] = BackendUtility::datetime($vv['scheduled']);
786
                    $rowData['exec_time'] = $vv['exec_time'] ? BackendUtility::datetime($vv['exec_time']) : '-';
787
                    $this->CSVaccu[] = $rowData;
788
                }
789
            }
790
        } else {
791
792
                // Compile row:
793
            $content = '
794
				<tr class="bgColor-20">
795
					<td>' . $titleString . '</td>
796
					<td colspan="' . $colSpan . '"><em>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noentries') . '</em></td>
797
				</tr>';
798
        }
799
800
        return $content;
801
    }
802
803
    /**
804
     * Find Fe vars
805
     *
806
     * @param array $row
807
     * @return array
808
     */
809
    public function getResFeVars($row)
810
    {
811
        $feVars = [];
812
813
        if ($row['result_data']) {
814
            $resultData = unserialize($row['result_data']);
815
            $requestResult = unserialize($resultData['content']);
816
            $feVars = $requestResult['vars'];
817
        }
818
819
        return $feVars;
820
    }
821
822
    /**
823
     * Create Table header row (log)
824
     *
825
     * @return	string		Table header
826
     */
827
    public function drawLog_printTableHeader()
828
    {
829
        $content = '
830
			<tr class="bgColor5 tableheader">
831
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.pagetitle') . ':</td>
832
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.qid') . ':</td>
833
				<td>&nbsp;</td>' .
834
                ($this->pObj->MOD_SETTINGS['log_resultLog'] ? '
835
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.resultlog') . ':</td>' : '
836
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.scheduledtime') . ':</td>
837
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.runtime') . ':</td>') . '
838
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.status') . ':</td>
839
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.url') . ':</td>
840
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.groups') . ':</td>
841
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.procinstr') . ':</td>
842
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.setid') . ':</td>' .
843
                ($this->pObj->MOD_SETTINGS['log_feVars'] ? '
844
				<td>' . htmlspecialchars('TSFE->id') . '</td>
845
				<td>' . htmlspecialchars('TSFE->gr_list') . '</td>
846
				<td>' . htmlspecialchars('TSFE->no_cache') . '</td>' : '') . '
847
			</tr>';
848
849
        return $content;
850
    }
851
852
    /**
853
     * Extract the log information from the current row and retrive it as formatted string.
854
     *
855
     * @param array $resultRow
856
     *
857
     * @return string
858
     */
859
    protected function getResultLog($resultRow)
860
    {
861
        $content = '';
862
863
        if (is_array($resultRow) && array_key_exists('result_data', $resultRow)) {
864
            $requestContent = unserialize($resultRow['result_data']);
865
            $requestResult = unserialize($requestContent['content']);
866
867
            if (is_array($requestResult) && array_key_exists('log', $requestResult)) {
868
                $content = implode(chr(10), $requestResult['log']);
869
            }
870
        }
871
872
        return $content;
873
    }
874
875
    public function getResStatus($vv)
876
    {
877
        if ($vv['result_data']) {
878
            $requestContent = unserialize($vv['result_data']);
879
            $requestResult = unserialize($requestContent['content']);
880
            if (is_array($requestResult)) {
881
                if (empty($requestResult['errorlog'])) {
882
                    $resStatus = 'OK';
883
                } else {
884
                    $resStatus = implode("\n", $requestResult['errorlog']);
885
                }
886
            } else {
887
                $resStatus = 'Error: ' . substr(preg_replace('/\s+/', ' ', strip_tags($requestContent['content'])), 0, 10000) . '...';
888
            }
889
        } else {
890
            $resStatus = '-';
891
        }
892
        return $resStatus;
893
    }
894
895
    /*****************************
896
     *
897
     * CLI status display
898
     *
899
     *****************************/
900
901
    /**
902
     * This method is used to show an overview about the active an the finished crawling processes
903
     *
904
     * @param void
905
     * @return string
906
     */
907
    protected function drawProcessOverviewAction()
908
    {
909
        $this->runRefreshHooks();
910
911
        global $BACK_PATH;
912
        $this->makeCrawlerProcessableChecks();
913
914
        $crawler = $this->findCrawler();
915
        try {
916
            $this->handleProcessOverviewActions();
917
        } catch (\Exception $e) {
918
            $this->addErrorMessage($e->getMessage());
919
        }
920
921
        $offset = intval(GeneralUtility::_GP('offset'));
922
        $perpage = 20;
923
924
        $processRepository = new ProcessRepository();
925
        $queueRepository = new QueueRepository();
926
927
        $mode = $this->pObj->MOD_SETTINGS['processListMode'];
928
        $where = '';
929
        if ($mode == 'simple') {
930
            $where = 'active = 1';
931
        }
932
933
        $allProcesses = $processRepository->findAll('ttl', 'DESC', $perpage, $offset, $where);
934
        $allCount = $processRepository->countAll($where);
935
936
        $listView = new ProcessListView();
937
        $listView->setPageId($this->pObj->id);
938
        $listView->setIconPath($BACK_PATH . '../typo3conf/ext/crawler/template/process/res/img/');
939
        $listView->setProcessCollection($allProcesses);
940
        $listView->setCliPath($this->processManager->getCrawlerCliPath());
941
        $listView->setIsCrawlerEnabled(!$crawler->getDisabled() && !$this->isErrorDetected);
942
        $listView->setTotalUnprocessedItemCount($queueRepository->countAllPendingItems());
943
        $listView->setAssignedUnprocessedItemCount($queueRepository->countAllAssignedPendingItems());
944
        $listView->setActiveProcessCount($processRepository->countActive());
945
        $listView->setMaxActiveProcessCount(MathUtility::forceIntegerInRange($this->extensionSettings['processLimit'], 1, 99, 1));
946
        $listView->setMode($mode);
947
948
        $paginationView = new PaginationView();
949
        $paginationView->setCurrentOffset($offset);
950
        $paginationView->setPerPage($perpage);
951
        $paginationView->setTotalItemCount($allCount);
952
953
        $output = $listView->render();
954
955
        if ($paginationView->getTotalPagesCount() > 1) {
956
            $output .= ' <br />' . $paginationView->render();
957
        }
958
959
        return $output;
960
    }
961
962
    /**
963
     * Verify that the crawler is exectuable.
964
     *
965
     * @return void
966
     */
967
    protected function makeCrawlerProcessableChecks()
968
    {
969
        global $LANG;
970
971
        if ($this->isCrawlerUserAvailable() === false) {
972
            $this->addErrorMessage($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.noBeUserAvailable'));
973
        } elseif ($this->isCrawlerUserNotAdmin() === false) {
974
            $this->addErrorMessage($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.beUserIsAdmin'));
975
        }
976
977
        if ($this->isPhpForkAvailable() === false) {
978
            $this->addErrorMessage($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.noPhpForkAvailable'));
979
        }
980
981
        $exitCode = 0;
982
        $out = [];
983
        exec(escapeshellcmd($this->extensionSettings['phpPath'] . ' -v'), $out, $exitCode);
984
        if ($exitCode > 0) {
985
            $this->addErrorMessage(sprintf($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.phpBinaryNotFound'), htmlspecialchars($this->extensionSettings['phpPath'])));
986
        }
987
    }
988
989
    /**
990
     * Indicate that the required PHP method "popen" is
991
     * available in the system.
992
     *
993
     * @return boolean
994
     */
995
    protected function isPhpForkAvailable()
996
    {
997
        return function_exists('popen');
998
    }
999
1000
    /**
1001
     * Indicate that the required be_user "_cli_crawler" is
1002
     * global available in the system.
1003
     *
1004
     * @return boolean
1005
     */
1006
    protected function isCrawlerUserAvailable()
1007
    {
1008
        $isAvailable = false;
1009
        $userArray = BackendUtility::getRecordsByField('be_users', 'username', '_cli_crawler');
1010
1011
        if (is_array($userArray)) {
1012
            $isAvailable = true;
1013
        }
1014
1015
        return $isAvailable;
1016
    }
1017
1018
    /**
1019
     * Indicate that the required be_user "_cli_crawler" is
1020
     * has no admin rights.
1021
     *
1022
     * @return boolean
1023
     */
1024
    protected function isCrawlerUserNotAdmin()
1025
    {
1026
        $isAvailable = false;
1027
        $userArray = BackendUtility::getRecordsByField('be_users', 'username', '_cli_crawler');
1028
1029
        if (is_array($userArray) && $userArray[0]['admin'] == 0) {
1030
            $isAvailable = true;
1031
        }
1032
1033
        return $isAvailable;
1034
    }
1035
1036
    /**
1037
     * Method to handle incomming actions of the process overview
1038
     *
1039
     * @throws \Exception
1040
     *
1041
     * @return void
1042
     */
1043
    protected function handleProcessOverviewActions()
1044
    {
1045
        $crawler = $this->findCrawler();
1046
1047
        switch (GeneralUtility::_GP('action')) {
1048
            case 'stopCrawling':
1049
                //set the cli status to disable (all processes will be terminated)
1050
                $crawler->setDisabled(true);
1051
                break;
1052
            case 'resumeCrawling':
1053
                //set the cli status to end (all processes will be terminated)
1054
                $crawler->setDisabled(false);
1055
                break;
1056
            case 'addProcess':
1057
                $handle = $this->processManager->startProcess();
1058
                if ($handle === false) {
1059
                    throw new \Exception($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.newprocesserror'));
1060
                }
1061
                $this->addNoticeMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.newprocess'));
1062
                break;
1063
        }
1064
    }
1065
1066
    /**
1067
     * Returns the singleton instance of the crawler.
1068
     *
1069
     * @param void
1070
     * @return CrawlerController crawler object
1071
     */
1072
    protected function findCrawler()
1073
    {
1074
        if (!$this->crawlerController instanceof CrawlerController) {
1075
            $this->crawlerController = GeneralUtility::makeInstance(CrawlerController::class);
1076
        }
1077
        return $this->crawlerController;
1078
    }
1079
1080
    /*****************************
1081
     *
1082
     * General Helper Functions
1083
     *
1084
     *****************************/
1085
1086
    /**
1087
     * This method is used to add a message to the internal queue
1088
     *
1089
     * @param  string  the message itself
1090
     * @param  integer message level (-1 = success (default), 0 = info, 1 = notice, 2 = warning, 3 = error)
1091
     *
1092
     * @return void
1093
     */
1094
    private function addMessage($message, $severity = FlashMessage::OK)
1095
    {
1096
        $message = GeneralUtility::makeInstance(
1097
            FlashMessage::class,
1098
            $message,
1099
            '',
1100
            $severity
1101
        );
1102
1103
        // TODO:
1104
        /** @var FlashMessageService $flashMessageService */
1105
        $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
1106
        $flashMessageService->getMessageQueueByIdentifier()->addMessage($message);
1107
    }
1108
1109
    /**
1110
     * Add notice message to the user interface.
1111
     *
1112
     * @param string The message
1113
     *
1114
     * @return void
1115
     */
1116
    protected function addNoticeMessage($message)
1117
    {
1118
        $this->addMessage($message, FlashMessage::NOTICE);
1119
    }
1120
1121
    /**
1122
     * Add error message to the user interface.
1123
     *
1124
     * @param string The message
1125
     *
1126
     * @return void
1127
     */
1128
    protected function addErrorMessage($message)
1129
    {
1130
        $this->isErrorDetected = true;
1131
        $this->addMessage($message, FlashMessage::ERROR);
1132
    }
1133
1134
    /**
1135
     * Add error message to the user interface.
1136
     *
1137
     * NOTE:
1138
     * This method is basesd on TYPO3 4.3 or higher!
1139
     *
1140
     * @param string The message
1141
     *
1142
     * @return void
1143
     */
1144
    protected function addWarningMessage($message)
1145
    {
1146
        $this->addMessage($message, FlashMessage::WARNING);
1147
    }
1148
1149
    /**
1150
     * Create selector box
1151
     *
1152
     * @param	array		$optArray Options key(value) => label pairs
1153
     * @param	string		$name Selector box name
1154
     * @param	string		$value Selector box value (array for multiple...)
1155
     * @param	boolean		$multiple If set, will draw multiple box.
1156
     *
1157
     * @return	string		HTML select element
1158
     */
1159
    public function selectorBox($optArray, $name, $value, $multiple)
1160
    {
1161
        $options = [];
1162
        foreach ($optArray as $key => $val) {
1163
            $options[] = '
1164
				<option value="' . htmlspecialchars($key) . '"' . ((!$multiple && !strcmp($value, $key)) || ($multiple && in_array($key, (array)$value)) ? ' selected="selected"' : '') . '>' . htmlspecialchars($val) . '</option>';
1165
        }
1166
1167
        $output = '<select name="' . htmlspecialchars($name . ($multiple ? '[]' : '')) . '"' . ($multiple ? ' multiple="multiple" size="' . count($options) . '"' : '') . '>' . implode('', $options) . '</select>';
1168
1169
        return $output;
1170
    }
1171
1172
    /**
1173
     * Activate hooks
1174
     *
1175
     * @return	void
1176
     */
1177
    public function runRefreshHooks()
1178
    {
1179
        $crawlerLib = GeneralUtility::makeInstance(CrawlerController::class);
1180
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['crawler']['refresh_hooks'])) {
1181
            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['crawler']['refresh_hooks'] as $objRef) {
1182
                $hookObj = &GeneralUtility::getUserObj($objRef);
1183
                if (is_object($hookObj)) {
1184
                    $hookObj->crawler_init($crawlerLib);
1185
                }
1186
            }
1187
        }
1188
    }
1189
1190
    /**
1191
     * Returns the URL to the current module, including $_GET['id'].
1192
     *
1193
     * @param array $urlParameters optional parameters to add to the URL
1194
     * @return string
1195
     */
1196
    protected function getModuleUrl(array $urlParameters = [])
1197
    {
1198
        if ($this->pObj->id) {
1199
            $urlParameters = array_merge($urlParameters, [
1200
                'id' => $this->pObj->id
1201
            ]);
1202
        }
1203
        return BackendUtility::getModuleUrl(GeneralUtility::_GP('M'), $urlParameters);
0 ignored issues
show
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...
1204
    }
1205
}
1206