Completed
Push — master ( 06e57a...6ca61e )
by Stefan
13:45 queued 05:04
created

BackendModule::getResStatus()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 14
nc 4
nop 1
dl 0
loc 19
ccs 0
cts 19
cp 0
crap 20
rs 9.2
c 0
b 0
f 0
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
     * @var ProcessService
98
     */
99
    protected $processManager;
100
101
    /**
102
     * the constructor
103
     */
104
    public function __construct()
105
    {
106
        $this->processManager = new ProcessService();
107
    }
108
109
    /**
110
     * Additions to the function menu array
111
     *
112
     * @return array Menu array
113
     */
114
    public function modMenu()
115
    {
116
        global $LANG;
117
118
        return [
119
            'depth' => [
120
                0 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
121
                1 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
122
                2 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
123
                3 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
124
                4 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
125
                99 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi'),
126
            ],
127
            'crawlaction' => [
128
                'start' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.start'),
129
                'log' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.log'),
130
                'multiprocess' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.multiprocess')
131
            ],
132
            'log_resultLog' => '',
133
            'log_feVars' => '',
134
            'processListMode' => '',
135
            'log_display' => [
136
                'all' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.all'),
137
                'pending' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.pending'),
138
                'finished' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.finished')
139
            ],
140
            'itemsPerPage' => [
141
                '5' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.5'),
142
                '10' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.10'),
143
                '50' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.50'),
144
                '0' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.0')
145
            ]
146
        ];
147
    }
148
149
    /**
150
     * Load extension settings
151
     *
152
     * @return void
153
     */
154
    protected function loadExtensionSettings()
155
    {
156
        $this->extensionSettings = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['crawler']);
157
    }
158
159
    /**
160
     * Main function
161
     *
162
     * @return	string		HTML output
163
     */
164
    public function main()
165
    {
166
        global $LANG, $BACK_PATH;
167
168
        $this->incLocalLang();
169
170
        $this->loadExtensionSettings();
171
        if (empty($this->pObj->MOD_SETTINGS['processListMode'])) {
172
            $this->pObj->MOD_SETTINGS['processListMode'] = 'simple';
173
        }
174
175
        // Set CSS styles specific for this document:
176
        $this->pObj->content = str_replace('/*###POSTCSSMARKER###*/', '
177
			TABLE.c-list TR TD { white-space: nowrap; vertical-align: top; }
178
		', $this->pObj->content);
179
180
        $this->pObj->content .= '<style type="text/css"><!--
181
			table.url-table,
182
			table.param-expanded,
183
			table.crawlerlog {
184
				border-bottom: 1px solid grey;
185
				border-spacing: 0;
186
				border-collapse: collapse;
187
			}
188
			table.crawlerlog td,
189
			table.url-table td {
190
				border: 1px solid lightgrey;
191
				border-bottom: 1px solid grey;
192
				 white-space: nowrap; vertical-align: top;
193
			}
194
		--></style>
195
		<link rel="stylesheet" type="text/css" href="' . $BACK_PATH . '../typo3conf/ext/crawler/template/res.css" />
196
		';
197
198
        // Type function menu:
199
        $h_func = BackendUtility::getFuncMenu(
200
            $this->pObj->id,
201
            'SET[crawlaction]',
202
            $this->pObj->MOD_SETTINGS['crawlaction'],
203
            $this->pObj->MOD_MENU['crawlaction'],
204
            'index.php'
205
        );
206
207
        // Additional menus for the log type:
208
        if ($this->pObj->MOD_SETTINGS['crawlaction'] === 'log') {
209
            $h_func .= BackendUtility::getFuncMenu(
210
                $this->pObj->id,
211
                'SET[depth]',
212
                $this->pObj->MOD_SETTINGS['depth'],
213
                $this->pObj->MOD_MENU['depth'],
214
                'index.php'
215
            );
216
217
            $quiPart = GeneralUtility::_GP('qid_details') ? '&qid_details=' . intval(GeneralUtility::_GP('qid_details')) : '';
218
219
            $setId = intval(GeneralUtility::_GP('setID'));
220
221
            $h_func .= '<hr/>' .
222
                    $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) . ' - ' .
223
                    $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) . ' - ' .
224
                    $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) . ' - ' .
225
                    $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage') . ': ' .
226
                    BackendUtility::getFuncMenu(
227
                        $this->pObj->id,
228
                        'SET[itemsPerPage]',
229
                        $this->pObj->MOD_SETTINGS['itemsPerPage'],
230
                        $this->pObj->MOD_MENU['itemsPerPage'],
231
                        'index.php'
232
                    );
233
        }
234
235
        $theOutput = $this->pObj->doc->section($LANG->getLL('title'), $h_func, false, true);
236
237
        // Branch based on type:
238
        switch ((string)$this->pObj->MOD_SETTINGS['crawlaction']) {
239
            case 'start':
240
                if (empty($this->pObj->id)) {
241
                    $this->addErrorMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noPageSelected'));
242
                } else {
243
                    $theOutput .= $this->pObj->doc->section('', $this->drawURLs(), false, true);
244
                }
245
                break;
246
            case 'log':
247
                if (empty($this->pObj->id)) {
248
                    $this->addErrorMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noPageSelected'));
249
                } else {
250
                    $theOutput .= $this->pObj->doc->section('', $this->drawLog(), false, true);
251
                }
252
                break;
253
            case 'cli':
254
                // TODO: drawCLIstatus is not defined, why did we refactor it away?
255
                $theOutput .= $this->pObj->doc->section('', $this->drawCLIstatus(), false, true);
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...
256
                break;
257
            case 'multiprocess':
258
                $theOutput .= $this->pObj->doc->section('', $this->drawProcessOverviewAction(), false, true);
259
                break;
260
        }
261
262
        return $theOutput;
263
    }
264
265
    /*******************************
266
     *
267
     * Generate URLs for crawling:
268
     *
269
     ******************************/
270
271
    /**
272
     * Produces a table with overview of the URLs to be crawled for each page
273
     *
274
     * @return	string		HTML output
275
     */
276
    public function drawURLs()
277
    {
278
        global $BACK_PATH, $BE_USER;
279
280
        $crawlerParameter = GeneralUtility::_GP('_crawl');
281
        $downloadParameter = GeneralUtility::_GP('_download');
282
283
        // Init:
284
        $this->duplicateTrack = [];
285
        $this->submitCrawlUrls = isset($crawlerParameter);
286
        $this->downloadCrawlUrls = isset($downloadParameter);
287
        $this->makeCrawlerProcessableChecks();
288
289
        switch ((string) GeneralUtility::_GP('tstamp')) {
290
            case 'midnight':
291
                $this->scheduledTime = mktime(0, 0, 0);
292
            break;
293
            case '04:00':
294
                $this->scheduledTime = mktime(0, 0, 0) + 4 * 3600;
295
            break;
296
            case 'now':
297
            default:
298
                $this->scheduledTime = time();
299
            break;
300
        }
301
        // $this->reqMinute = \TYPO3\CMS\Core\Utility\GeneralUtility::intInRange(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('perminute'),1,10000);
302
        // TODO: check relevance
303
        $this->reqMinute = 1000;
304
305
        $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...
306
        $this->incomingConfigurationSelection = is_array($this->incomingConfigurationSelection) ? $this->incomingConfigurationSelection : [];
307
308
        $this->crawlerObj = GeneralUtility::makeInstance(CrawlerController::class);
309
        $this->crawlerObj->setAccessMode('gui');
310
        $this->crawlerObj->setID = GeneralUtility::md5int(microtime());
311
312
        if (empty($this->incomingConfigurationSelection)
313
            || (count($this->incomingConfigurationSelection) == 1 && empty($this->incomingConfigurationSelection[0]))
314
            ) {
315
            $code = '
316
			<tr>
317
				<td colspan="7"><b>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noConfigSelected') . '</b></td>
318
			</tr>';
319
        } else {
320
            if ($this->submitCrawlUrls) {
321
                $reason = new Reason();
322
                $reason->setReason(Reason::REASON_GUI_SUBMIT);
323
324
                if ($BE_USER instanceof BackendUserAuthentication) {
325
                    $username = $BE_USER->user['username'];
326
                    $reason->setDetailText('The user ' . $username . ' added pages to the crawler queue manually ');
327
                }
328
329
                EventDispatcher::getInstance()->post(
330
                    'invokeQueueChange',
331
                    $this->findCrawler()->setID,
332
                    ['reason' => $reason]
333
                );
334
            }
335
336
            $code = $this->crawlerObj->getPageTreeAndUrls(
337
                $this->pObj->id,
338
                $this->pObj->MOD_SETTINGS['depth'],
339
                $this->scheduledTime,
340
                $this->reqMinute,
341
                $this->submitCrawlUrls,
342
                $this->downloadCrawlUrls,
343
                [], // Do not filter any processing instructions
344
                $this->incomingConfigurationSelection
345
            );
346
        }
347
348
        $this->downloadUrls = $this->crawlerObj->downloadUrls;
349
        $this->duplicateTrack = $this->crawlerObj->duplicateTrack;
350
351
        $output = '';
352
        if ($code) {
353
            $output .= '<h3>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.configuration') . ':</h3>';
354
            $output .= '<input type="hidden" name="id" value="' . intval($this->pObj->id) . '" />';
355
356
            if (!$this->submitCrawlUrls) {
357
                $output .= $this->drawURLs_cfgSelectors() . '<br />';
358
                $output .= '<input type="submit" name="_update" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.triggerUpdate') . '" /> ';
359
                $output .= '<input type="submit" name="_crawl" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.triggerCrawl') . '" /> ';
360
                $output .= '<input type="submit" name="_download" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.triggerDownload') . '" /><br /><br />';
361
                $output .= $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.count') . ': ' . count(array_keys($this->duplicateTrack)) . '<br />';
362
                $output .= $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.curtime') . ': ' . date('H:i:s', time()) . '<br />';
363
                $output .= '<br />
364
					<table class="lrPadding c-list url-table">' .
365
                        $this->drawURLs_printTableHeader() .
366
                        $code .
367
                    '</table>';
368
            } else {
369
                $output .= count(array_keys($this->duplicateTrack)) . ' ' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.submitted') . '. <br /><br />';
370
                $output .= '<input type="submit" name="_" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.continue') . '" />';
371
                $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') . '" />';
372
            }
373
        }
374
375
        // Download Urls to crawl:
376
        if ($this->downloadCrawlUrls) {
377
378
                // Creating output header:
379
            $mimeType = 'application/octet-stream';
380
            Header('Content-Type: ' . $mimeType);
381
            Header('Content-Disposition: attachment; filename=CrawlerUrls.txt');
382
383
            // Printing the content of the CSV lines:
384
            echo implode(chr(13) . chr(10), $this->downloadUrls);
385
386
            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...
387
        }
388
389
        return 	$output;
390
    }
391
392
    /**
393
     * Draws the configuration selectors for compiling URLs:
394
     *
395
     * @return	string		HTML table
396
     */
397
    public function drawURLs_cfgSelectors()
398
    {
399
        $cell = [];
400
401
        // depth
402
        $cell[] = $this->selectorBox(
403
            [
404
                0 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
405
                1 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
406
                2 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
407
                3 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
408
                4 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
409
                99 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi'),
410
            ],
411
            'SET[depth]',
412
            $this->pObj->MOD_SETTINGS['depth'],
413
            false
414
        );
415
        $availableConfigurations = $this->crawlerObj->getConfigurationsForBranch($this->pObj->id, $this->pObj->MOD_SETTINGS['depth'] ? $this->pObj->MOD_SETTINGS['depth'] : 0);
416
417
        // Configurations
418
        $cell[] = $this->selectorBox(
419
            empty($availableConfigurations) ? [] : array_combine($availableConfigurations, $availableConfigurations),
420
            'configurationSelection',
421
            $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...
422
            true
423
        );
424
425
        // Scheduled time:
426
        $cell[] = $this->selectorBox(
427
            [
428
                'now' => $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time.now'),
429
                'midnight' => $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time.midnight'),
430
                '04:00' => $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time.4am'),
431
            ],
432
            'tstamp',
433
            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...
434
            false
435
        );
436
437
        $output = '
438
			<table class="lrPadding c-list">
439
				<tr class="bgColor5 tableheader">
440
					<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.depth') . ':</td>
441
					<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.configurations') . ':</td>
442
					<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.scheduled') . ':</td>
443
				</tr>
444
				<tr class="bgColor4">
445
					<td valign="top">' . implode('</td>
446
					<td valign="top">', $cell) . '</td>
447
				</tr>
448
			</table>';
449
450
        return $output;
451
    }
452
453
    /**
454
     * Create Table header row for URL display
455
     *
456
     * @return	string		Table header
457
     */
458
    public function drawURLs_printTableHeader()
459
    {
460
        $content = '
461
			<tr class="bgColor5 tableheader">
462
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.pagetitle') . ':</td>
463
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.key') . ':</td>
464
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.parametercfg') . ':</td>
465
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.values') . ':</td>
466
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.urls') . ':</td>
467
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.options') . ':</td>
468
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.parameters') . ':</td>
469
			</tr>';
470
471
        return $content;
472
    }
473
474
    /*******************************
475
     *
476
     * Shows log of indexed URLs
477
     *
478
     ******************************/
479
480
    /**
481
     * Shows the log of indexed URLs
482
     *
483
     * @return	string		HTML output
484
     */
485
    public function drawLog()
486
    {
487
        global $BACK_PATH;
488
        $output = '';
489
490
        // Init:
491
        $this->crawlerObj = GeneralUtility::makeInstance(CrawlerController::class);
492
        $this->crawlerObj->setAccessMode('gui');
493
        $this->crawlerObj->setID = GeneralUtility::md5int(microtime());
494
495
        $csvExport = GeneralUtility::_POST('_csv');
496
        $this->CSVExport = isset($csvExport);
497
498
        // Read URL:
499
        if (GeneralUtility::_GP('qid_read')) {
500
            $this->crawlerObj->readUrl(intval(GeneralUtility::_GP('qid_read')), true);
501
        }
502
503
        // Look for set ID sent - if it is, we will display contents of that set:
504
        $showSetId = intval(GeneralUtility::_GP('setID'));
505
506
        // Show details:
507
        if (GeneralUtility::_GP('qid_details')) {
508
509
                // Get entry record:
510
            list($q_entry) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'tx_crawler_queue', 'qid=' . intval(GeneralUtility::_GP('qid_details')));
511
512
            // Explode values:
513
            $resStatus = $this->getResStatus($q_entry);
514
            $q_entry['parameters'] = unserialize($q_entry['parameters']);
515
            $q_entry['result_data'] = unserialize($q_entry['result_data']);
516
            if (is_array($q_entry['result_data'])) {
517
                $q_entry['result_data']['content'] = unserialize($q_entry['result_data']['content']);
518
            }
519
520
            if (!$this->pObj->MOD_SETTINGS['log_resultLog']) {
521
                unset($q_entry['result_data']['content']['log']);
522
            }
523
524
            // Print rudimentary details:
525
            $output .= '
526
				<br /><br />
527
				<input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.back') . '" name="_back" />
528
				<input type="hidden" value="' . $this->pObj->id . '" name="id" />
529
				<input type="hidden" value="' . $showSetId . '" name="setID" />
530
				<br />
531
				Current server time: ' . date('H:i:s', time()) . '<br />' .
532
                'Status: ' . $resStatus . '<br />' .
533
                DebugUtility::viewArray($q_entry);
534
        } else {	// Show list:
535
536
            // If either id or set id, show list:
537
            if ($this->pObj->id || $showSetId) {
538
                if ($this->pObj->id) {
539
                    // Drawing tree:
540
                    $tree = GeneralUtility::makeInstance('TYPO3\CMS\Backend\Tree\View\PageTreeView');
541
                    $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
542
                    $tree->init('AND ' . $perms_clause);
543
544
                    // Set root row:
545
                    $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...
546
                    $tree->tree[] = [
547
                        'row' => $this->pObj->pageinfo,
548
                        'HTML' => $HTML
549
                    ];
550
551
                    // Get branch beneath:
552
                    if ($this->pObj->MOD_SETTINGS['depth']) {
553
                        $tree->getTree($this->pObj->id, $this->pObj->MOD_SETTINGS['depth'], '');
554
                    }
555
556
                    // Traverse page tree:
557
                    $code = '';
558
                    $count = 0;
559
                    foreach ($tree->tree as $data) {
560
                        $code .= $this->drawLog_addRows(
561
                                    $data['row'],
562
                                    $data['HTML'] . BackendUtility::getRecordTitle('pages', $data['row'], true),
563
                                    intval($this->pObj->MOD_SETTINGS['itemsPerPage'])
564
                                );
565
                        if (++$count == 1000) {
566
                            break;
567
                        }
568
                    }
569
                } else {
570
                    $code = '';
571
                    $code .= $this->drawLog_addRows(
572
                                $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...
573
                                'Set ID: ' . $showSetId
574
                            );
575
                }
576
577
                if ($code) {
578
                    $output .= '
579
						<br /><br />
580
						<input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.reloadlist') . '" name="_reload" />
581
						<input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.downloadcsv') . '" name="_csv" />
582
						<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') . '\');" />
583
						<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') . '\');" />
584
						<input type="hidden" value="' . $this->pObj->id . '" name="id" />
585
						<input type="hidden" value="' . $showSetId . '" name="setID" />
586
						<br />
587
						' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.curtime') . ': ' . date('H:i:s', time()) . '
588
						<br /><br />
589
590
591
						<table class="lrPadding c-list crawlerlog">' .
592
                            $this->drawLog_printTableHeader() .
593
                            $code .
594
                        '</table>';
595
                }
596
            } else {	// Otherwise show available sets:
597
                $setList = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
598
                                'set_id, count(*) as count_value, scheduled',
599
                                'tx_crawler_queue',
600
                                '',
601
                                'set_id, scheduled',
602
                                'scheduled DESC'
603
                            );
604
605
                $code = '
606
					<tr class="bgColor5 tableheader">
607
						<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.setid') . ':</td>
608
						<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.count') . 't:</td>
609
						<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time') . ':</td>
610
					</tr>
611
				';
612
613
                $cc = 0;
614
                foreach ($setList as $set) {
615
                    $code .= '
616
						<tr class="bgColor' . ($cc % 2 ? '-20' : '-10') . '">
617
							<td><a href="' . htmlspecialchars('index.php?setID=' . $set['set_id']) . '">' . $set['set_id'] . '</a></td>
618
							<td>' . $set['count_value'] . '</td>
619
							<td>' . BackendUtility::dateTimeAge($set['scheduled']) . '</td>
620
						</tr>
621
					';
622
623
                    $cc++;
624
                }
625
626
                $output .= '
627
					<br /><br />
628
					<table class="lrPadding c-list">' .
629
                        $code .
630
                    '</table>';
631
            }
632
        }
633
634
        if ($this->CSVExport) {
635
            $this->outputCsvFile();
636
        }
637
638
        // Return output
639
        return 	$output;
640
    }
641
642
    /**
643
     * Outputs the CSV file and sets the correct headers
644
     */
645
    protected function outputCsvFile()
646
    {
647
        if (!count($this->CSVaccu)) {
648
            $this->addWarningMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.canNotExportEmptyQueueToCsvText'));
649
            return;
650
        }
651
652
        $csvLines = [];
653
654
        // Field names:
655
        reset($this->CSVaccu);
656
        $fieldNames = array_keys(current($this->CSVaccu));
657
        $csvLines[] = GeneralUtility::csvValues($fieldNames);
658
659
        // Data:
660
        foreach ($this->CSVaccu as $row) {
661
            $csvLines[] = GeneralUtility::csvValues($row);
662
        }
663
664
        // Creating output header:
665
        $mimeType = 'application/octet-stream';
666
        Header('Content-Type: ' . $mimeType);
667
        Header('Content-Disposition: attachment; filename=CrawlerLog.csv');
668
669
        // Printing the content of the CSV lines:
670
        echo implode(chr(13) . chr(10), $csvLines);
671
672
        // Exits:
673
        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...
674
    }
675
676
    /**
677
     * Create the rows for display of the page tree
678
     * For each page a number of rows are shown displaying GET variable configuration
679
     *
680
     * @param array $pageRow_setId Page row or set-id
681
     * @param string $titleString Title string
682
     * @param int $itemsPerPage Items per Page setting
683
     *
684
     * @return string HTML <tr> content (one or more)
685
     */
686
    public function drawLog_addRows($pageRow_setId, $titleString, $itemsPerPage = 10)
687
    {
688
689
            // If Flush button is pressed, flush tables instead of selecting entries:
690
691
        if (GeneralUtility::_POST('_flush')) {
692
            $doFlush = true;
693
            $doFullFlush = false;
694
        } elseif (GeneralUtility::_POST('_flush_all')) {
695
            $doFlush = true;
696
            $doFullFlush = true;
697
        } else {
698
            $doFlush = false;
699
            $doFullFlush = false;
700
        }
701
702
        // Get result:
703
        if (is_array($pageRow_setId)) {
704
            $res = $this->crawlerObj->getLogEntriesForPageId($pageRow_setId['uid'], $this->pObj->MOD_SETTINGS['log_display'], $doFlush, $doFullFlush, intval($itemsPerPage));
705
        } else {
706
            $res = $this->crawlerObj->getLogEntriesForSetId($pageRow_setId, $this->pObj->MOD_SETTINGS['log_display'], $doFlush, $doFullFlush, intval($itemsPerPage));
707
        }
708
709
        // Init var:
710
        $colSpan = 9
711
                + ($this->pObj->MOD_SETTINGS['log_resultLog'] ? -1 : 0)
712
                + ($this->pObj->MOD_SETTINGS['log_feVars'] ? 3 : 0);
713
714
        if (count($res)) {
715
            // Traverse parameter combinations:
716
            $c = 0;
717
            $content = '';
718
            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...
719
720
                    // Title column:
721
                if (!$c) {
722
                    $titleClm = '<td rowspan="' . count($res) . '">' . $titleString . '</td>';
723
                } else {
724
                    $titleClm = '';
725
                }
726
727
                // Result:
728
                $resLog = $this->getResultLog($vv);
729
730
                $resStatus = $this->getResStatus($vv);
731
                $resFeVars = $this->getResFeVars($vv);
732
733
                // Compile row:
734
                $parameters = unserialize($vv['parameters']);
735
736
                // Put data into array:
737
                $rowData = [];
738
                if ($this->pObj->MOD_SETTINGS['log_resultLog']) {
739
                    $rowData['result_log'] = $resLog;
740
                } else {
741
                    $rowData['scheduled'] = ($vv['scheduled'] > 0) ? BackendUtility::datetime($vv['scheduled']) : ' ' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.immediate');
742
                    $rowData['exec_time'] = $vv['exec_time'] ? BackendUtility::datetime($vv['exec_time']) : '-';
743
                }
744
                $rowData['result_status'] = GeneralUtility::fixed_lgd_cs($resStatus, 50);
745
                $rowData['url'] = '<a href="' . htmlspecialchars($parameters['url']) . '" target="_newWIndow">' . htmlspecialchars($parameters['url']) . '</a>';
746
                $rowData['feUserGroupList'] = $parameters['feUserGroupList'];
747
                $rowData['procInstructions'] = is_array($parameters['procInstructions']) ? implode('; ', $parameters['procInstructions']) : '';
748
                $rowData['set_id'] = $vv['set_id'];
749
750
                if ($this->pObj->MOD_SETTINGS['log_feVars']) {
751
                    $rowData['tsfe_id'] = $resFeVars['id'];
752
                    $rowData['tsfe_gr_list'] = $resFeVars['gr_list'];
753
                    $rowData['tsfe_no_cache'] = $resFeVars['no_cache'];
754
                }
755
756
                $setId = intval(GeneralUtility::_GP('setID'));
757
                $refreshIcon = $GLOBALS['BACK_PATH'] . 'sysext/t3skin/extjs/images/grid/refresh.gif';
758
759
                // Put rows together:
760
                $content .= '
761
					<tr class="bgColor' . ($c % 2 ? '-20' : '-10') . '">
762
						' . $titleClm . '
763
						<td><a href="' . $this->getModuleUrl(['qid_details' => $vv['qid'], 'setID' => $setId]) . '">' . htmlspecialchars($vv['qid']) . '</a></td>
764
						<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>';
765
                foreach ($rowData as $fKey => $value) {
766
                    if (GeneralUtility::inList('url', $fKey)) {
767
                        $content .= '
768
						<td>' . $value . '</td>';
769
                    } else {
770
                        $content .= '
771
						<td>' . nl2br(htmlspecialchars($value)) . '</td>';
772
                    }
773
                }
774
                $content .= '
775
					</tr>';
776
                $c++;
777
778
                if ($this->CSVExport) {
779
                    // Only for CSV (adding qid and scheduled/exec_time if needed):
780
                    $rowData['result_log'] = implode('// ', explode(chr(10), $resLog));
781
                    $rowData['qid'] = $vv['qid'];
782
                    $rowData['scheduled'] = BackendUtility::datetime($vv['scheduled']);
783
                    $rowData['exec_time'] = $vv['exec_time'] ? BackendUtility::datetime($vv['exec_time']) : '-';
784
                    $this->CSVaccu[] = $rowData;
785
                }
786
            }
787
        } else {
788
789
                // Compile row:
790
            $content = '
791
				<tr class="bgColor-20">
792
					<td>' . $titleString . '</td>
793
					<td colspan="' . $colSpan . '"><em>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noentries') . '</em></td>
794
				</tr>';
795
        }
796
797
        return $content;
798
    }
799
800
    /**
801
     * Find Fe vars
802
     *
803
     * @param array $row
804
     * @return array
805
     */
806
    public function getResFeVars($row)
807
    {
808
        $feVars = [];
809
810
        if ($row['result_data']) {
811
            $resultData = unserialize($row['result_data']);
812
            $requestResult = unserialize($resultData['content']);
813
            $feVars = $requestResult['vars'];
814
        }
815
816
        return $feVars;
817
    }
818
819
    /**
820
     * Create Table header row (log)
821
     *
822
     * @return	string		Table header
823
     */
824
    public function drawLog_printTableHeader()
825
    {
826
        $content = '
827
			<tr class="bgColor5 tableheader">
828
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.pagetitle') . ':</td>
829
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.qid') . ':</td>
830
				<td>&nbsp;</td>' .
831
                ($this->pObj->MOD_SETTINGS['log_resultLog'] ? '
832
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.resultlog') . ':</td>' : '
833
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.scheduledtime') . ':</td>
834
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.runtime') . ':</td>') . '
835
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.status') . ':</td>
836
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.url') . ':</td>
837
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.groups') . ':</td>
838
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.procinstr') . ':</td>
839
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.setid') . ':</td>' .
840
                ($this->pObj->MOD_SETTINGS['log_feVars'] ? '
841
				<td>' . htmlspecialchars('TSFE->id') . '</td>
842
				<td>' . htmlspecialchars('TSFE->gr_list') . '</td>
843
				<td>' . htmlspecialchars('TSFE->no_cache') . '</td>' : '') . '
844
			</tr>';
845
846
        return $content;
847
    }
848
849
    /**
850
     * Extract the log information from the current row and retrive it as formatted string.
851
     *
852
     * @param array $resultRow
853
     *
854
     * @return string
855
     */
856
    protected function getResultLog($resultRow)
857
    {
858
        $content = '';
859
860
        if (is_array($resultRow) && array_key_exists('result_data', $resultRow)) {
861
            $requestContent = unserialize($resultRow['result_data']);
862
            $requestResult = unserialize($requestContent['content']);
863
864
            if (is_array($requestResult) && array_key_exists('log', $requestResult)) {
865
                $content = implode(chr(10), $requestResult['log']);
866
            }
867
        }
868
869
        return $content;
870
    }
871
872
    public function getResStatus($vv)
873
    {
874
        if ($vv['result_data']) {
875
            $requestContent = unserialize($vv['result_data']);
876
            $requestResult = unserialize($requestContent['content']);
877
            if (is_array($requestResult)) {
878
                if (empty($requestResult['errorlog'])) {
879
                    $resStatus = 'OK';
880
                } else {
881
                    $resStatus = implode("\n", $requestResult['errorlog']);
882
                }
883
            } else {
884
                $resStatus = 'Error: ' . substr(preg_replace('/\s+/', ' ', strip_tags($requestContent['content'])), 0, 10000) . '...';
885
            }
886
        } else {
887
            $resStatus = '-';
888
        }
889
        return $resStatus;
890
    }
891
892
    /*****************************
893
     *
894
     * CLI status display
895
     *
896
     *****************************/
897
898
    /**
899
     * This method is used to show an overview about the active an the finished crawling processes
900
     *
901
     * @param void
902
     * @return string
903
     */
904
    protected function drawProcessOverviewAction()
905
    {
906
        $this->runRefreshHooks();
907
908
        global $BACK_PATH;
909
        $this->makeCrawlerProcessableChecks();
910
911
        $crawler = $this->findCrawler();
912
        try {
913
            $this->handleProcessOverviewActions();
914
        } catch (\Exception $e) {
915
            $this->addErrorMessage($e->getMessage());
916
        }
917
918
        $offset = intval(GeneralUtility::_GP('offset'));
919
        $perpage = 20;
920
921
        $processRepository = new ProcessRepository();
922
        $queueRepository = new QueueRepository();
923
924
        $mode = $this->pObj->MOD_SETTINGS['processListMode'];
925
        $where = '';
926
        if ($mode == 'simple') {
927
            $where = 'active = 1';
928
        }
929
930
        $allProcesses = $processRepository->findAll('ttl', 'DESC', $perpage, $offset, $where);
931
        $allCount = $processRepository->countAll($where);
932
933
        $listView = new ProcessListView();
934
        $listView->setPageId($this->pObj->id);
935
        $listView->setIconPath($BACK_PATH . '../typo3conf/ext/crawler/template/process/res/img/');
936
        $listView->setProcessCollection($allProcesses);
937
        $listView->setCliPath($this->processManager->getCrawlerCliPath());
938
        $listView->setIsCrawlerEnabled(!$crawler->getDisabled() && !$this->isErrorDetected);
939
        $listView->setTotalUnprocessedItemCount($queueRepository->countAllPendingItems());
940
        $listView->setAssignedUnprocessedItemCount($queueRepository->countAllAssignedPendingItems());
941
        $listView->setActiveProcessCount($processRepository->countActive());
942
        $listView->setMaxActiveProcessCount(MathUtility::forceIntegerInRange($this->extensionSettings['processLimit'], 1, 99, 1));
943
        $listView->setMode($mode);
944
945
        $paginationView = new PaginationView();
946
        $paginationView->setCurrentOffset($offset);
947
        $paginationView->setPerPage($perpage);
948
        $paginationView->setTotalItemCount($allCount);
949
950
        $output = $listView->render();
951
952
        if ($paginationView->getTotalPagesCount() > 1) {
953
            $output .= ' <br />' . $paginationView->render();
954
        }
955
956
        return $output;
957
    }
958
959
    /**
960
     * Verify that the crawler is exectuable.
961
     *
962
     * @return void
963
     */
964
    protected function makeCrawlerProcessableChecks()
965
    {
966
        global $LANG;
967
968
        if ($this->isCrawlerUserAvailable() === false) {
969
            $this->addErrorMessage($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.noBeUserAvailable'));
970
        } elseif ($this->isCrawlerUserNotAdmin() === false) {
971
            $this->addErrorMessage($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.beUserIsAdmin'));
972
        }
973
974
        if ($this->isPhpForkAvailable() === false) {
975
            $this->addErrorMessage($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.noPhpForkAvailable'));
976
        }
977
978
        $exitCode = 0;
979
        $out = [];
980
        exec(escapeshellcmd($this->extensionSettings['phpPath'] . ' -v'), $out, $exitCode);
981
        if ($exitCode > 0) {
982
            $this->addErrorMessage(sprintf($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.phpBinaryNotFound'), htmlspecialchars($this->extensionSettings['phpPath'])));
983
        }
984
    }
985
986
    /**
987
     * Indicate that the required PHP method "popen" is
988
     * available in the system.
989
     *
990
     * @return boolean
991
     */
992
    protected function isPhpForkAvailable()
993
    {
994
        return function_exists('popen');
995
    }
996
997
    /**
998
     * Indicate that the required be_user "_cli_crawler" is
999
     * global available in the system.
1000
     *
1001
     * @return boolean
1002
     */
1003
    protected function isCrawlerUserAvailable()
1004
    {
1005
        $isAvailable = false;
1006
        $userArray = BackendUtility::getRecordsByField('be_users', 'username', '_cli_crawler');
1007
1008
        if (is_array($userArray)) {
1009
            $isAvailable = true;
1010
        }
1011
1012
        return $isAvailable;
1013
    }
1014
1015
    /**
1016
     * Indicate that the required be_user "_cli_crawler" is
1017
     * has no admin rights.
1018
     *
1019
     * @return boolean
1020
     */
1021
    protected function isCrawlerUserNotAdmin()
1022
    {
1023
        $isAvailable = false;
1024
        $userArray = BackendUtility::getRecordsByField('be_users', 'username', '_cli_crawler');
1025
1026
        if (is_array($userArray) && $userArray[0]['admin'] == 0) {
1027
            $isAvailable = true;
1028
        }
1029
1030
        return $isAvailable;
1031
    }
1032
1033
    /**
1034
     * Method to handle incomming actions of the process overview
1035
     *
1036
     * @throws \Exception
1037
     *
1038
     * @return void
1039
     */
1040
    protected function handleProcessOverviewActions()
1041
    {
1042
        $crawler = $this->findCrawler();
1043
1044
        switch (GeneralUtility::_GP('action')) {
1045
            case 'stopCrawling':
1046
                //set the cli status to disable (all processes will be terminated)
1047
                $crawler->setDisabled(true);
1048
                break;
1049
            case 'resumeCrawling':
1050
                //set the cli status to end (all processes will be terminated)
1051
                $crawler->setDisabled(false);
1052
                break;
1053
            case 'addProcess':
1054
                $handle = $this->processManager->startProcess();
1055
                if ($handle === false) {
1056
                    throw new \Exception($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.newprocesserror'));
1057
                }
1058
                $this->addNoticeMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.newprocess'));
1059
                break;
1060
        }
1061
    }
1062
1063
    /**
1064
     * Returns the singleton instance of the crawler.
1065
     *
1066
     * @param void
1067
     * @return CrawlerController crawler object
1068
     */
1069
    protected function findCrawler()
1070
    {
1071
        if (!$this->crawlerObj instanceof CrawlerController) {
1072
            $this->crawlerObj = GeneralUtility::makeInstance(CrawlerController::class);
1073
        }
1074
        return $this->crawlerObj;
1075
    }
1076
1077
    /*****************************
1078
     *
1079
     * General Helper Functions
1080
     *
1081
     *****************************/
1082
1083
    /**
1084
     * This method is used to add a message to the internal queue
1085
     *
1086
     * @param  string  the message itself
1087
     * @param  integer message level (-1 = success (default), 0 = info, 1 = notice, 2 = warning, 3 = error)
1088
     *
1089
     * @return void
1090
     */
1091
    private function addMessage($message, $severity = FlashMessage::OK)
1092
    {
1093
        $message = GeneralUtility::makeInstance(
1094
            FlashMessage::class,
1095
            $message,
1096
            '',
1097
            $severity
1098
        );
1099
1100
        // TODO:
1101
        /** @var FlashMessageService $flashMessageService */
1102
        $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
1103
        $flashMessageService->getMessageQueueByIdentifier()->addMessage($message);
1104
    }
1105
1106
    /**
1107
     * Add notice message to the user interface.
1108
     *
1109
     * @param string The message
1110
     *
1111
     * @return void
1112
     */
1113
    protected function addNoticeMessage($message)
1114
    {
1115
        $this->addMessage($message, FlashMessage::NOTICE);
1116
    }
1117
1118
    /**
1119
     * Add error message to the user interface.
1120
     *
1121
     * @param string The message
1122
     *
1123
     * @return void
1124
     */
1125
    protected function addErrorMessage($message)
1126
    {
1127
        $this->isErrorDetected = true;
1128
        $this->addMessage($message, FlashMessage::ERROR);
1129
    }
1130
1131
    /**
1132
     * Add error message to the user interface.
1133
     *
1134
     * NOTE:
1135
     * This method is basesd on TYPO3 4.3 or higher!
1136
     *
1137
     * @param string The message
1138
     *
1139
     * @return void
1140
     */
1141
    protected function addWarningMessage($message)
1142
    {
1143
        $this->addMessage($message, FlashMessage::WARNING);
1144
    }
1145
1146
    /**
1147
     * Create selector box
1148
     *
1149
     * @param	array		$optArray Options key(value) => label pairs
1150
     * @param	string		$name Selector box name
1151
     * @param	string		$value Selector box value (array for multiple...)
1152
     * @param	boolean		$multiple If set, will draw multiple box.
1153
     *
1154
     * @return	string		HTML select element
1155
     */
1156
    public function selectorBox($optArray, $name, $value, $multiple)
1157
    {
1158
        $options = [];
1159
        foreach ($optArray as $key => $val) {
1160
            $options[] = '
1161
				<option value="' . htmlspecialchars($key) . '"' . ((!$multiple && !strcmp($value, $key)) || ($multiple && in_array($key, (array)$value)) ? ' selected="selected"' : '') . '>' . htmlspecialchars($val) . '</option>';
1162
        }
1163
1164
        $output = '<select name="' . htmlspecialchars($name . ($multiple ? '[]' : '')) . '"' . ($multiple ? ' multiple="multiple" size="' . count($options) . '"' : '') . '>' . implode('', $options) . '</select>';
1165
1166
        return $output;
1167
    }
1168
1169
    /**
1170
     * Activate hooks
1171
     *
1172
     * @return	void
1173
     */
1174
    public function runRefreshHooks()
1175
    {
1176
        $crawlerLib = GeneralUtility::makeInstance(CrawlerController::class);
1177
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['crawler']['refresh_hooks'])) {
1178
            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['crawler']['refresh_hooks'] as $objRef) {
1179
                $hookObj = &GeneralUtility::getUserObj($objRef);
1180
                if (is_object($hookObj)) {
1181
                    $hookObj->crawler_init($crawlerLib);
1182
                }
1183
            }
1184
        }
1185
    }
1186
1187
    /**
1188
     * Returns the URL to the current module, including $_GET['id'].
1189
     *
1190
     * @param array $urlParameters optional parameters to add to the URL
1191
     * @return string
1192
     */
1193
    protected function getModuleUrl(array $urlParameters = [])
1194
    {
1195
        if ($this->pObj->id) {
1196
            $urlParameters = array_merge($urlParameters, [
1197
                'id' => $this->pObj->id
1198
            ]);
1199
        }
1200
        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...
1201
    }
1202
}
1203