Completed
Push — fix/backendModuleUrl ( a3b276 )
by Tomas Norre
17:39
created

BackendModule::getModuleUrl()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 10
ccs 0
cts 10
cp 0
crap 6
rs 9.9332
c 0
b 0
f 0
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\BackendModuleUtility;
37
use AOE\Crawler\Utility\CsvUtility;
38
use AOE\Crawler\Utility\ExtensionSettingUtility;
39
use AOE\Crawler\Utility\IconUtility;
40
use TYPO3\CMS\Backend\Module\AbstractFunctionModule;
41
use TYPO3\CMS\Backend\Tree\View\PageTreeView;
42
use TYPO3\CMS\Backend\Utility\BackendUtility;
43
use TYPO3\CMS\Beuser\Domain\Model\BackendUser;
44
use TYPO3\CMS\Beuser\Domain\Model\Demand;
45
use TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository;
46
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
47
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
48
use TYPO3\CMS\Core\Database\ConnectionPool;
49
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
50
use TYPO3\CMS\Core\Imaging\Icon;
51
use TYPO3\CMS\Core\Messaging\FlashMessage;
52
use TYPO3\CMS\Core\Messaging\FlashMessageService;
53
use TYPO3\CMS\Core\Utility\DebugUtility;
54
use TYPO3\CMS\Core\Utility\GeneralUtility;
55
use TYPO3\CMS\Core\Utility\MathUtility;
56
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
57
use TYPO3\CMS\Extbase\Object\ObjectManager;
58
use TYPO3\CMS\Extbase\Persistence\Generic\QueryResult;
59
use TYPO3\CMS\Backend\Routing\UriBuilder;
60
61
/**
62
 * Class BackendModule
63
 *
64
 * @package AOE\Crawler\Backend
65
 */
66
class BackendModule extends AbstractFunctionModule
0 ignored issues
show
Deprecated Code introduced by
The class TYPO3\CMS\Backend\Module\AbstractFunctionModule has been deprecated with message: since TYPO3 v9, will be removed in TYPO3 v10.0

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
67
{
68
    // Internal, dynamic:
69
    public $duplicateTrack = [];
70
    public $submitCrawlUrls = false;
71
    public $downloadCrawlUrls = false;
72
73
    public $scheduledTime = 0;
74
    public $reqMinute = 0;
75
76
    const STATUS_ICON_ERROR = 3;
77
    const STATUS_ICON_WARNING = 2;
78
    const STATUS_ICON_NOTIFICATION = 1;
79
    const STATUS_ICON_OK = -1;
80
81
    /**
82
     * @var array holds the selection of configuration from the configuration selector box
83
     */
84
    public $incomingConfigurationSelection = [];
85
86
    /**
87
     * @var CrawlerController
88
     */
89
    public $crawlerController;
90
91
    public $CSVaccu = [];
92
93
    /**
94
     * If true the user requested a CSV export of the queue
95
     *
96
     * @var boolean
97
     */
98
    public $CSVExport = false;
99
100
    public $downloadUrls = [];
101
102
    /**
103
     * Holds the configuration from ext_conf_template loaded by loadExtensionSettings()
104
     *
105
     * @var array
106
     */
107
    protected $extensionSettings = [];
108
109
    /**
110
     * Indicate that an flash message with an error is present.
111
     *
112
     * @var boolean
113
     */
114
    protected $isErrorDetected = false;
115
116
    /**
117
     * @var ProcessService
118
     */
119
    protected $processManager;
120
121
    /**
122
     * @var BackendUserRepository
123
     */
124
    protected $backendUserRepository;
125
126
    /**
127
     * @var QueryBuilder
128
     */
129
    protected $queryBuilder;
130
131
    /**
132
     * @var QueueRepository
133
     */
134
    protected $queueRepository;
135
136
    /**
137
     * the constructor
138
     */
139
    public function __construct()
140
    {
141
        $objectManger = GeneralUtility::makeInstance(ObjectManager::class);
142
        $this->processManager = new ProcessService();
143
        $this->backendUserRepository = $objectManger->get(BackendUserRepository::class);
144
        $this->queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_crawler_queue');
145
        $this->queueRepository = $objectManger->get(QueueRepository::class);
146
    }
147
148
    /**
149
     * Additions to the function menu array
150
     *
151
     * @return array Menu array
152
     */
153
    public function modMenu()
154
    {
155
        global $LANG;
156
157
        return [
158
            'depth' => [
159
                0 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
160
                1 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
161
                2 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
162
                3 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
163
                4 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
164
                99 => $LANG->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi'),
165
            ],
166
            'crawlaction' => [
167
                'start' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.start'),
168
                'log' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.log'),
169
                'multiprocess' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.multiprocess')
170
            ],
171
            'log_resultLog' => '',
172
            'log_feVars' => '',
173
            'processListMode' => '',
174
            'log_display' => [
175
                'all' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.all'),
176
                'pending' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.pending'),
177
                'finished' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.finished')
178
            ],
179
            'itemsPerPage' => [
180
                '5' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.5'),
181
                '10' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.10'),
182
                '50' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.50'),
183
                '0' => $LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage.0')
184
            ]
185
        ];
186
    }
187
188
    /**
189
     * Load extension settings
190
     *
191
     * @return void
192
     *
193
     * @deprecated since crawler v7.0.0, will be removed in crawler v8.0.0.
194
     */
195
    protected function loadExtensionSettings()
196
    {
197
        $isVersionLowerThan9 = \TYPO3\CMS\Core\Utility\VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version) < 9000000;
198
        if ($isVersionLowerThan9) {
199
            $this->extensionSettings = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['crawler']);
200
        } else {
201
            $this->extensionSettings = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('crawler');
202
        }
203
    }
204
205
    /**
206
     * Main function
207
     *
208
     * @return	string		HTML output
209
     */
210
    public function main()
211
    {
212
        global $LANG, $BACK_PATH;
213
214
        //$this->incLocalLang();
215
216
        $this->extensionSettings = ExtensionSettingUtility::loadExtensionSettings();
217
        if (empty($this->pObj->MOD_SETTINGS['processListMode'])) {
218
            $this->pObj->MOD_SETTINGS['processListMode'] = 'simple';
219
        }
220
221
        // Set CSS styles specific for this document:
222
        $this->pObj->content = str_replace('/*###POSTCSSMARKER###*/', '
223
			TABLE.c-list TR TD { white-space: nowrap; vertical-align: top; }
224
		', $this->pObj->content);
225
226
        $this->pObj->content .= '<style type="text/css"><!--
227
			table.url-table,
228
			table.param-expanded,
229
			table.crawlerlog {
230
				border-bottom: 1px solid grey;
231
				border-spacing: 0;
232
				border-collapse: collapse;
233
			}
234
			table.crawlerlog td,
235
			table.url-table td {
236
				border: 1px solid lightgrey;
237
				border-bottom: 1px solid grey;
238
				 white-space: nowrap; vertical-align: top;
239
			}
240
		--></style>
241
		<link rel="stylesheet" type="text/css" href="' . $BACK_PATH . '../typo3conf/ext/crawler/template/res.css" />
242
		';
243
244
        // Type function menu:
245
        $h_func = BackendUtility::getFuncMenu(
246
            $this->pObj->id,
247
            'SET[crawlaction]',
248
            $this->pObj->MOD_SETTINGS['crawlaction'],
249
            $this->pObj->MOD_MENU['crawlaction'],
250
            'index.php'
251
        );
252
253
        // Additional menus for the log type:
254
        if ($this->pObj->MOD_SETTINGS['crawlaction'] === 'log') {
255
            $h_func .= BackendUtility::getFuncMenu(
256
                $this->pObj->id,
257
                'SET[depth]',
258
                $this->pObj->MOD_SETTINGS['depth'],
259
                $this->pObj->MOD_MENU['depth'],
260
                'index.php'
261
            );
262
263
            $quiPart = GeneralUtility::_GP('qid_details') ? '&qid_details=' . intval(GeneralUtility::_GP('qid_details')) : '';
264
265
            $setId = intval(GeneralUtility::_GP('setID'));
266
267
            $h_func .= '<hr/>' .
268
                    $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) . ' - ' .
269
                    $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) . ' - ' .
270
                    $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) . ' - ' .
271
                    $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.itemsPerPage') . ': ' .
272
                    BackendUtility::getFuncMenu(
273
                        $this->pObj->id,
274
                        'SET[itemsPerPage]',
275
                        $this->pObj->MOD_SETTINGS['itemsPerPage'],
276
                        $this->pObj->MOD_MENU['itemsPerPage'],
277
                        'index.php'
278
                    );
279
        }
280
281
        $theOutput = $this->section($LANG->getLL('title'), $h_func, false, true);
282
283
        // Branch based on type:
284
        switch ((string)$this->pObj->MOD_SETTINGS['crawlaction']) {
285
            case 'start':
286
                if (empty($this->pObj->id)) {
287
                    $this->addErrorMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noPageSelected'));
288
                } else {
289
                    $theOutput .= $this->section('', $this->drawURLs(), false, true);
290
                }
291
                break;
292
            case 'log':
293
                if (empty($this->pObj->id)) {
294
                    $this->addErrorMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noPageSelected'));
295
                } else {
296
                    $theOutput .= $this->section('', $this->drawLog(), false, true);
297
                }
298
                break;
299
            case 'cli':
300
                // TODO: drawCLIstatus is not defined, why did we refactor it away?
301
                $theOutput .= $this->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...
302
                break;
303
            case 'multiprocess':
304
                $theOutput .= $this->section('', $this->drawProcessOverviewAction(), false, true);
305
                break;
306
        }
307
308
        return $theOutput;
309
    }
310
311
    /*******************************
312
     *
313
     * Generate URLs for crawling:
314
     *
315
     ******************************/
316
317
    /**
318
     * Produces a table with overview of the URLs to be crawled for each page
319
     *
320
     * @return	string		HTML output
321
     */
322
    public function drawURLs()
323
    {
324
        global $BACK_PATH, $BE_USER;
325
326
        $crawlerParameter = GeneralUtility::_GP('_crawl');
327
        $downloadParameter = GeneralUtility::_GP('_download');
328
329
        // Init:
330
        $this->duplicateTrack = [];
331
        $this->submitCrawlUrls = isset($crawlerParameter);
332
        $this->downloadCrawlUrls = isset($downloadParameter);
333
        $this->makeCrawlerProcessableChecks();
334
335
        switch ((string) GeneralUtility::_GP('tstamp')) {
336
            case 'midnight':
337
                $this->scheduledTime = mktime(0, 0, 0);
338
            break;
339
            case '04:00':
340
                $this->scheduledTime = mktime(0, 0, 0) + 4 * 3600;
341
            break;
342
            case 'now':
343
            default:
344
                $this->scheduledTime = time();
345
            break;
346
        }
347
        // $this->reqMinute = \TYPO3\CMS\Core\Utility\GeneralUtility::intInRange(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('perminute'),1,10000);
348
        // TODO: check relevance
349
        $this->reqMinute = 1000;
350
351
        $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...
352
        $this->incomingConfigurationSelection = is_array($this->incomingConfigurationSelection) ? $this->incomingConfigurationSelection : [];
353
354
        $this->crawlerController = GeneralUtility::makeInstance(CrawlerController::class);
355
        $this->crawlerController->setAccessMode('gui');
356
        $this->crawlerController->setID = GeneralUtility::md5int(microtime());
357
358
        if (empty($this->incomingConfigurationSelection)
359
            || (count($this->incomingConfigurationSelection) == 1 && empty($this->incomingConfigurationSelection[0]))
360
            ) {
361
            $this->addWarningMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noConfigSelected'));
362
            $code = '
363
			<tr>
364
				<td colspan="7"><b>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noConfigSelected') . '</b></td>
365
			</tr>';
366
        } else {
367
            if ($this->submitCrawlUrls) {
368
                $reason = new Reason();
369
                $reason->setReason(Reason::REASON_GUI_SUBMIT);
370
371
                if ($BE_USER instanceof BackendUserAuthentication) {
372
                    $username = $BE_USER->user['username'];
373
                    $reason->setDetailText('The user ' . $username . ' added pages to the crawler queue manually ');
374
                }
375
376
                EventDispatcher::getInstance()->post(
377
                    'invokeQueueChange',
378
                    $this->findCrawler()->setID,
379
                    ['reason' => $reason]
380
                );
381
            }
382
383
            $code = $this->crawlerController->getPageTreeAndUrls(
384
                $this->pObj->id,
385
                $this->pObj->MOD_SETTINGS['depth'],
386
                $this->scheduledTime,
387
                $this->reqMinute,
388
                $this->submitCrawlUrls,
389
                $this->downloadCrawlUrls,
390
                [], // Do not filter any processing instructions
391
                $this->incomingConfigurationSelection
392
            );
393
        }
394
395
        $this->downloadUrls = $this->crawlerController->downloadUrls;
396
        $this->duplicateTrack = $this->crawlerController->duplicateTrack;
397
398
        $output = '';
399
        if ($code) {
400
            $output .= '<h3>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.configuration') . ':</h3>';
401
            $output .= '<input type="hidden" name="id" value="' . intval($this->pObj->id) . '" />';
402
403
            if (!$this->submitCrawlUrls) {
404
                $output .= $this->drawURLs_cfgSelectors() . '<br />';
405
                $output .= '<input type="submit" name="_update" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.triggerUpdate') . '" /> ';
406
                $output .= '<input type="submit" name="_crawl" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.triggerCrawl') . '" /> ';
407
                $output .= '<input type="submit" name="_download" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.triggerDownload') . '" /><br /><br />';
408
                $output .= $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.count') . ': ' . count(array_keys($this->duplicateTrack)) . '<br />';
409
                $output .= $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.curtime') . ': ' . date('H:i:s', time()) . '<br />';
410
                $output .= '<br />
411
					<table class="lrPadding c-list url-table">' .
412
                        $this->drawURLs_printTableHeader() .
413
                        $code .
414
                    '</table>';
415
            } else {
416
                $output .= count(array_keys($this->duplicateTrack)) . ' ' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.submitted') . '. <br /><br />';
417
                $output .= '<input type="submit" name="_" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.continue') . '" />';
418
                $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') . '" />';
419
            }
420
        }
421
422
        // Download Urls to crawl:
423
        if ($this->downloadCrawlUrls) {
424
425
                // Creating output header:
426
            $mimeType = 'application/octet-stream';
427
            Header('Content-Type: ' . $mimeType);
428
            Header('Content-Disposition: attachment; filename=CrawlerUrls.txt');
429
430
            // Printing the content of the CSV lines:
431
            echo implode(chr(13) . chr(10), $this->downloadUrls);
432
433
            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...
434
        }
435
436
        return 	$output;
437
    }
438
439
    /**
440
     * Draws the configuration selectors for compiling URLs:
441
     *
442
     * @return	string		HTML table
443
     */
444
    public function drawURLs_cfgSelectors()
445
    {
446
        $cell = [];
447
448
        // depth
449
        $cell[] = $this->selectorBox(
450
            [
451
                0 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
452
                1 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
453
                2 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
454
                3 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
455
                4 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
456
                99 => $GLOBALS['LANG']->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi'),
457
            ],
458
            'SET[depth]',
459
            $this->pObj->MOD_SETTINGS['depth'],
460
            false
461
        );
462
        $availableConfigurations = $this->crawlerController->getConfigurationsForBranch($this->pObj->id, $this->pObj->MOD_SETTINGS['depth'] ? $this->pObj->MOD_SETTINGS['depth'] : 0);
463
464
        // Configurations
465
        $cell[] = $this->selectorBox(
466
            empty($availableConfigurations) ? [] : array_combine($availableConfigurations, $availableConfigurations),
467
            'configurationSelection',
468
            $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...
469
            true
470
        );
471
472
        // Scheduled time:
473
        $cell[] = $this->selectorBox(
474
            [
475
                'now' => $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time.now'),
476
                'midnight' => $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time.midnight'),
477
                '04:00' => $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time.4am'),
478
            ],
479
            'tstamp',
480
            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...
481
            false
482
        );
483
484
        $output = '
485
			<table class="lrPadding c-list">
486
				<tr class="bgColor5 tableheader">
487
					<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.depth') . ':</td>
488
					<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.configurations') . ':</td>
489
					<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.scheduled') . ':</td>
490
				</tr>
491
				<tr class="bgColor4">
492
					<td valign="top">' . implode('</td>
493
					<td valign="top">', $cell) . '</td>
494
				</tr>
495
			</table>';
496
497
        return $output;
498
    }
499
500
    /**
501
     * Create Table header row for URL display
502
     *
503
     * @return	string		Table header
504
     */
505
    public function drawURLs_printTableHeader()
506
    {
507
        $content = '
508
			<tr class="bgColor5 tableheader">
509
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.pagetitle') . ':</td>
510
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.key') . ':</td>
511
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.parametercfg') . ':</td>
512
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.values') . ':</td>
513
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.urls') . ':</td>
514
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.options') . ':</td>
515
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.parameters') . ':</td>
516
			</tr>';
517
518
        return $content;
519
    }
520
521
522
523
    /**
524
     * Begins an output section and sets header and content
525
     *
526
     * @param string $label The header
527
     * @param string $text The HTML-content
528
     * @param bool $nostrtoupper	A flag that will prevent the header from being converted to uppercase
529
     * @param bool $sH Defines the type of header (if set, "<h3>" rather than the default "h4")
530
     * @param int $type The number of an icon to show with the header (see the icon-function). -1,1,2,3
531
     * @param bool $allowHTMLinHeader If set, HTML tags are allowed in $label (otherwise this value is by default htmlspecialchars()'ed)
532
     * @return string HTML content
533
     * @see icons(), sectionHeader()
534
     */
535
    public function section($label, $text, $nostrtoupper = false, $sH = false, $type = 0, $allowHTMLinHeader = false)
536
    {
537
        $str = '';
538
        // Setting header
539
        if ($label) {
540
            if (!$allowHTMLinHeader) {
541
                $label = htmlspecialchars($label);
542
            }
543
            $str .= $this->sectionHeader($this->icons($type) . $label, $sH, $nostrtoupper ? '' : ' class="uppercase"');
544
        }
545
        // Setting content
546
        $str .= '
547
548
	<!-- Section content -->
549
' . $text;
550
        return $this->sectionBegin() . $str;
551
    }
552
553
    /**
554
     * Inserts a divider image
555
     * Ends a section (if open) before inserting the image
556
     *
557
     * @param int $dist The margin-top/-bottom of the <hr> ruler.
558
     * @return string HTML content
559
     */
560
    public function divider($dist)
561
    {
562
        $dist = (int)$dist;
563
        $str = '
564
565
	<!-- DIVIDER -->
566
	<hr style="margin-top: ' . $dist . 'px; margin-bottom: ' . $dist . 'px;" />
567
';
568
        return $this->sectionEnd() . $str;
569
    }
570
571
    /**
572
     * Make a section header.
573
     * Begins a section if not already open.
574
     *
575
     * @param string $label The label between the <h3> or <h4> tags. (Allows HTML)
576
     * @param bool $sH If set, <h3> is used, otherwise <h4>
577
     * @param string $addAttrib Additional attributes to h-tag, eg. ' class=""'
578
     * @return string HTML content
579
     */
580
    public function sectionHeader($label, $sH = false, $addAttrib = '')
581
    {
582
        $tag = $sH ? 'h2' : 'h3';
583
        if ($addAttrib && $addAttrib[0] !== ' ') {
584
            $addAttrib = ' ' . $addAttrib;
585
        }
586
        $str = '
587
588
	<!-- Section header -->
589
	<' . $tag . $addAttrib . '>' . $label . '</' . $tag . '>
590
';
591
        return $this->sectionBegin() . $str;
592
    }
593
594
    /**
595
     * Begins an output section.
596
     * Returns the <div>-begin tag AND sets the ->sectionFlag TRUE (if the ->sectionFlag is not already set!)
597
     * You can call this function even if a section is already begun since the function will only return something if the sectionFlag is not already set!
598
     *
599
     * @return string HTML content
600
     */
601
    public function sectionBegin()
602
    {
603
        if (!$this->sectionFlag) {
604
            $this->sectionFlag = 1;
0 ignored issues
show
Bug introduced by
The property sectionFlag does not exist. Did you maybe forget to declare it?

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

class MyClass { }

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

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

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
605
            $str = '
606
607
	<!-- ***********************
608
	      Begin output section.
609
	     *********************** -->
610
	<div>
611
';
612
            return $str;
613
        }
614
        return '';
615
    }
616
617
    /**
618
     * Ends and output section
619
     * Returns the </div>-end tag AND clears the ->sectionFlag (but does so only IF the sectionFlag is set - that is a section is 'open')
620
     * See sectionBegin() also.
621
     *
622
     * @return string HTML content
623
     */
624
    public function sectionEnd()
625
    {
626
        if ($this->sectionFlag) {
627
            $this->sectionFlag = 0;
628
            return '
629
	</div>
630
	<!-- *********************
631
	      End output section.
632
	     ********************* -->
633
';
634
        }
635
        return '';
636
    }
637
638
    /**
639
     * Returns an image-tag with an 18x16 icon of the following types:
640
     *
641
     * $type:
642
     * -1:	OK icon (Check-mark)
643
     * 1:	Notice (Speach-bubble)
644
     * 2:	Warning (Yellow triangle)
645
     * 3:	Fatal error (Red stop sign)
646
     *
647
     * @param int $type See description
648
     * @param string $styleAttribValue Value for style attribute
649
     * @return string HTML image tag (if applicable)
650
     */
651
    public function icons($type, $styleAttribValue = '')
0 ignored issues
show
Unused Code introduced by
The parameter $styleAttribValue is not used and could be removed.

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

Loading history...
652
    {
653
        switch ($type) {
654
            case self::STATUS_ICON_ERROR:
655
                $icon = 'status-dialog-error';
656
                break;
657
            case self::STATUS_ICON_WARNING:
658
                $icon = 'status-dialog-warning';
659
                break;
660
            case self::STATUS_ICON_NOTIFICATION:
661
                $icon = 'status-dialog-notification';
662
                break;
663
            case self::STATUS_ICON_OK:
664
                $icon = 'status-dialog-ok';
665
                break;
666
            default:
667
                // Do nothing
668
        }
669
        if ($icon) {
670
            return $this->iconFactory->getIcon($icon, Icon::SIZE_SMALL)->render();
0 ignored issues
show
Bug introduced by
The property iconFactory does not exist. Did you maybe forget to declare it?

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

class MyClass { }

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

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

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Bug introduced by
The variable $icon does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
671
        }
672
    }
673
674
    /*******************************
675
     *
676
     * Shows log of indexed URLs
677
     *
678
     ******************************/
679
680
    /**
681
     * Shows the log of indexed URLs
682
     *
683
     * @return	string		HTML output
684
     */
685
    public function drawLog()
686
    {
687
        global $BACK_PATH;
688
        $output = '';
689
690
        // Init:
691
        $this->crawlerController = GeneralUtility::makeInstance(CrawlerController::class);
692
        $this->crawlerController->setAccessMode('gui');
693
        $this->crawlerController->setID = GeneralUtility::md5int(microtime());
694
695
        $csvExport = GeneralUtility::_POST('_csv');
696
        $this->CSVExport = isset($csvExport);
697
698
        // Read URL:
699
        if (GeneralUtility::_GP('qid_read')) {
700
            $this->crawlerController->readUrl(intval(GeneralUtility::_GP('qid_read')), true);
701
        }
702
703
        // Look for set ID sent - if it is, we will display contents of that set:
704
        $showSetId = intval(GeneralUtility::_GP('setID'));
705
706
        // Show details:
707
        if (GeneralUtility::_GP('qid_details')) {
708
709
                // Get entry record:
710
            $q_entry = $this->queryBuilder
711
                ->from('tx_crawler_queue')
712
                ->select('*')
713
                ->where(
714
                    $this->queryBuilder->expr()->eq('qid', $this->queryBuilder->createNamedParameter(GeneralUtility::_GP('qid_details')))
715
                )
716
                ->execute()
717
                ->fetch();
718
719
            // Explode values:
720
            $resStatus = $this->getResStatus($q_entry);
721
            $q_entry['parameters'] = unserialize($q_entry['parameters']);
722
            $q_entry['result_data'] = unserialize($q_entry['result_data']);
723
            if (is_array($q_entry['result_data'])) {
724
                $q_entry['result_data']['content'] = unserialize($q_entry['result_data']['content']);
725
726
                if (!$this->pObj->MOD_SETTINGS['log_resultLog']) {
727
                    unset($q_entry['result_data']['content']['log']);
728
                }
729
            }
730
731
            // Print rudimentary details:
732
            $output .= '
733
				<br /><br />
734
				<input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.back') . '" name="_back" />
735
				<input type="hidden" value="' . $this->pObj->id . '" name="id" />
736
				<input type="hidden" value="' . $showSetId . '" name="setID" />
737
				<br />
738
				Current server time: ' . date('H:i:s', time()) . '<br />' .
739
                'Status: ' . $resStatus . '<br />' .
740
                DebugUtility::viewArray($q_entry);
741
        } else {	// Show list:
742
743
            // If either id or set id, show list:
744
            if ($this->pObj->id || $showSetId) {
745
                if ($this->pObj->id) {
746
                    // Drawing tree:
747
                    $tree = GeneralUtility::makeInstance(PageTreeView::class);
748
                    $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
749
                    $tree->init('AND ' . $perms_clause);
750
751
                    // Set root row:
752
                    $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...
753
                    $tree->tree[] = [
754
                        'row' => $this->pObj->pageinfo,
755
                        'HTML' => $HTML
756
                    ];
757
758
                    // Get branch beneath:
759
                    if ($this->pObj->MOD_SETTINGS['depth']) {
760
                        $tree->getTree($this->pObj->id, $this->pObj->MOD_SETTINGS['depth'], '');
761
                    }
762
763
                    // Traverse page tree:
764
                    $code = '';
765
                    $count = 0;
766
                    foreach ($tree->tree as $data) {
767
                        $code .= $this->drawLog_addRows(
768
                                    $data['row'],
769
                                    $data['HTML'] . BackendUtility::getRecordTitle('pages', $data['row'], true),
770
                                    intval($this->pObj->MOD_SETTINGS['itemsPerPage'])
771
                                );
772
                        if (++$count == 1000) {
773
                            break;
774
                        }
775
                    }
776
                } else {
777
                    $code = '';
778
                    $code .= $this->drawLog_addRows(
779
                                $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...
780
                                'Set ID: ' . $showSetId
781
                            );
782
                }
783
784
                if ($code) {
785
                    $output .= '
786
						<br /><br />
787
						<input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.reloadlist') . '" name="_reload" />
788
						<input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.downloadcsv') . '" name="_csv" />
789
						<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') . '\');" />
790
						<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') . '\');" />
791
						<input type="hidden" value="' . $this->pObj->id . '" name="id" />
792
						<input type="hidden" value="' . $showSetId . '" name="setID" />
793
						<br />
794
						' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.curtime') . ': ' . date('H:i:s', time()) . '
795
						<br /><br />
796
797
798
						<table class="lrPadding c-list crawlerlog">' .
799
                            $this->drawLog_printTableHeader() .
800
                            $code .
801
                        '</table>';
802
                }
803
            } else {	// Otherwise show available sets:
804
                /*
805
                 $setList = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
806
                                'set_id, count(*) as count_value, scheduled',
807
                                'tx_crawler_queue',
808
                                '',
809
                                'set_id, scheduled',
810
                                'scheduled DESC'
811
                            );
812
                */
813
                $setList = $this->queueRepository->getAvailableSets();
814
815
                $code = '
816
					<tr class="bgColor5 tableheader">
817
						<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.setid') . ':</td>
818
						<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.count') . 't:</td>
819
						<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.time') . ':</td>
820
					</tr>
821
				';
822
823
                $cc = 0;
824
                foreach ($setList as $set) {
825
                    $code .= '
826
						<tr class="bgColor' . ($cc % 2 ? '-20' : '-10') . '">
827
							<td><a href="' . htmlspecialchars('index.php?setID=' . $set['set_id']) . '">' . $set['set_id'] . '</a></td>
828
							<td>' . $set['count_value'] . '</td>
829
							<td>' . BackendUtility::dateTimeAge($set['scheduled']) . '</td>
830
						</tr>
831
					';
832
833
                    $cc++;
834
                }
835
836
                $output .= '
837
					<br /><br />
838
					<table class="lrPadding c-list">' .
839
                        $code .
840
                    '</table>';
841
            }
842
        }
843
844
        if ($this->CSVExport) {
845
            $this->outputCsvFile();
846
        }
847
848
        // Return output
849
        return 	$output;
850
    }
851
852
    /**
853
     * Outputs the CSV file and sets the correct headers
854
     */
855
    protected function outputCsvFile()
856
    {
857
        if (!count($this->CSVaccu)) {
858
            $this->addWarningMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.canNotExportEmptyQueueToCsvText'));
859
            return;
860
        }
861
862
        $csvLines = [];
863
864
        // Field names:
865
        reset($this->CSVaccu);
866
        $fieldNames = array_keys(current($this->CSVaccu));
867
        $csvLines[] = CsvUtility::csvValues($fieldNames);
868
869
        // Data:
870
        foreach ($this->CSVaccu as $row) {
871
            $csvLines[] = CsvUtility::csvValues($row);
872
        }
873
874
        // Creating output header:
875
        $mimeType = 'application/octet-stream';
876
        Header('Content-Type: ' . $mimeType);
877
        Header('Content-Disposition: attachment; filename=CrawlerLog.csv');
878
879
        // Printing the content of the CSV lines:
880
        echo implode(chr(13) . chr(10), $csvLines);
881
882
        // Exits:
883
        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...
884
    }
885
886
    /**
887
     * Create the rows for display of the page tree
888
     * For each page a number of rows are shown displaying GET variable configuration
889
     *
890
     * @param array $pageRow_setId Page row or set-id
891
     * @param string $titleString Title string
892
     * @param int $itemsPerPage Items per Page setting
893
     *
894
     * @return string HTML <tr> content (one or more)
895
     */
896
    public function drawLog_addRows($pageRow_setId, $titleString, $itemsPerPage = 10)
897
    {
898
899
            // If Flush button is pressed, flush tables instead of selecting entries:
900
901
        if (GeneralUtility::_POST('_flush')) {
902
            $doFlush = true;
903
            $doFullFlush = false;
904
        } elseif (GeneralUtility::_POST('_flush_all')) {
905
            $doFlush = true;
906
            $doFullFlush = true;
907
        } else {
908
            $doFlush = false;
909
            $doFullFlush = false;
910
        }
911
912
        // Get result:
913
        if (is_array($pageRow_setId)) {
914
            $res = $this->crawlerController->getLogEntriesForPageId($pageRow_setId['uid'], $this->pObj->MOD_SETTINGS['log_display'], $doFlush, $doFullFlush, intval($itemsPerPage));
915
        } else {
916
            $res = $this->crawlerController->getLogEntriesForSetId($pageRow_setId, $this->pObj->MOD_SETTINGS['log_display'], $doFlush, $doFullFlush, intval($itemsPerPage));
917
        }
918
919
        // Init var:
920
        $colSpan = 9
921
                + ($this->pObj->MOD_SETTINGS['log_resultLog'] ? -1 : 0)
922
                + ($this->pObj->MOD_SETTINGS['log_feVars'] ? 3 : 0);
923
924
        if (count($res)) {
925
            // Traverse parameter combinations:
926
            $c = 0;
927
            $content = '';
928
            foreach ($res as $kk => $vv) {
929
930
                    // Title column:
931
                if (!$c) {
932
                    $titleClm = '<td rowspan="' . count($res) . '">' . $titleString . '</td>';
933
                } else {
934
                    $titleClm = '';
935
                }
936
937
                // Result:
938
                $resLog = $this->getResultLog($vv);
939
940
                $resStatus = $this->getResStatus($vv);
941
                $resFeVars = $this->getResFeVars($vv);
942
943
                // Compile row:
944
                $parameters = unserialize($vv['parameters']);
945
946
                // Put data into array:
947
                $rowData = [];
948
                if ($this->pObj->MOD_SETTINGS['log_resultLog']) {
949
                    $rowData['result_log'] = $resLog;
950
                } else {
951
                    $rowData['scheduled'] = ($vv['scheduled'] > 0) ? BackendUtility::datetime($vv['scheduled']) : ' ' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.immediate');
952
                    $rowData['exec_time'] = $vv['exec_time'] ? BackendUtility::datetime($vv['exec_time']) : '-';
953
                }
954
                $rowData['result_status'] = GeneralUtility::fixed_lgd_cs($resStatus, 50);
955
                $rowData['url'] = '<a href="' . htmlspecialchars($parameters['url']) . '" target="_newWIndow">' . htmlspecialchars($parameters['url']) . '</a>';
956
                $rowData['feUserGroupList'] = $parameters['feUserGroupList'];
957
                $rowData['procInstructions'] = is_array($parameters['procInstructions']) ? implode('; ', $parameters['procInstructions']) : '';
958
                $rowData['set_id'] = $vv['set_id'];
959
960
                if ($this->pObj->MOD_SETTINGS['log_feVars']) {
961
                    $rowData['tsfe_id'] = $resFeVars['id'];
962
                    $rowData['tsfe_gr_list'] = $resFeVars['gr_list'];
963
                    $rowData['tsfe_no_cache'] = $resFeVars['no_cache'];
964
                }
965
966
                $setId = intval(GeneralUtility::_GP('setID'));
967
                $refreshIcon = IconUtility::getIcon('actions-system-refresh', Icon::SIZE_SMALL);
968
969
                // Put rows together:
970
                $content .= '
971
					<tr class="bgColor' . ($c % 2 ? '-20' : '-10') . '">
972
						' . $titleClm . '
973
						<td><a href="' . BackendModuleUtility::getInfoModuleUrl(['qid_details' => $vv['qid'], 'setID' => $setId]) . '">' . htmlspecialchars($vv['qid']) . '</a></td>
974
						<td><a href="' . BackendModuleUtility::getInfoModuleUrl(['qid_read' => $vv['qid'], 'setID' => $setId]) . '">' . $refreshIcon . '</a></td>';
975
                foreach ($rowData as $fKey => $value) {
976
                    if (GeneralUtility::inList('url', $fKey)) {
977
                        $content .= '
978
						<td>' . $value . '</td>';
979
                    } else {
980
                        $content .= '
981
						<td>' . nl2br(htmlspecialchars($value)) . '</td>';
982
                    }
983
                }
984
                $content .= '
985
					</tr>';
986
                $c++;
987
988
                if ($this->CSVExport) {
989
                    // Only for CSV (adding qid and scheduled/exec_time if needed):
990
                    $rowData['result_log'] = implode('// ', explode(chr(10), $resLog));
991
                    $rowData['qid'] = $vv['qid'];
992
                    $rowData['scheduled'] = BackendUtility::datetime($vv['scheduled']);
993
                    $rowData['exec_time'] = $vv['exec_time'] ? BackendUtility::datetime($vv['exec_time']) : '-';
994
                    $this->CSVaccu[] = $rowData;
995
                }
996
            }
997
        } else {
998
999
                // Compile row:
1000
            $content = '
1001
				<tr class="bgColor-20">
1002
					<td>' . $titleString . '</td>
1003
					<td colspan="' . $colSpan . '"><em>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.noentries') . '</em></td>
1004
				</tr>';
1005
        }
1006
1007
        return $content;
1008
    }
1009
1010
    /**
1011
     * Find Fe vars
1012
     *
1013
     * @param array $row
1014
     * @return array
1015
     */
1016
    public function getResFeVars($row)
1017
    {
1018
        $feVars = [];
1019
1020
        if ($row['result_data']) {
1021
            $resultData = unserialize($row['result_data']);
1022
            $requestResult = unserialize($resultData['content']);
1023
            $feVars = $requestResult['vars'];
1024
        }
1025
1026
        return $feVars;
1027
    }
1028
1029
    /**
1030
     * Create Table header row (log)
1031
     *
1032
     * @return	string		Table header
1033
     */
1034
    public function drawLog_printTableHeader()
1035
    {
1036
        $content = '
1037
			<tr class="bgColor5 tableheader">
1038
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.pagetitle') . ':</td>
1039
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.qid') . ':</td>
1040
				<td>&nbsp;</td>' .
1041
                ($this->pObj->MOD_SETTINGS['log_resultLog'] ? '
1042
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.resultlog') . ':</td>' : '
1043
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.scheduledtime') . ':</td>
1044
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.runtime') . ':</td>') . '
1045
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.status') . ':</td>
1046
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.url') . ':</td>
1047
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.groups') . ':</td>
1048
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.procinstr') . ':</td>
1049
				<td>' . $GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.setid') . ':</td>' .
1050
                ($this->pObj->MOD_SETTINGS['log_feVars'] ? '
1051
				<td>' . htmlspecialchars('TSFE->id') . '</td>
1052
				<td>' . htmlspecialchars('TSFE->gr_list') . '</td>
1053
				<td>' . htmlspecialchars('TSFE->no_cache') . '</td>' : '') . '
1054
			</tr>';
1055
1056
        return $content;
1057
    }
1058
1059
    /**
1060
     * Extract the log information from the current row and retrive it as formatted string.
1061
     *
1062
     * @param array $resultRow
1063
     *
1064
     * @return string
1065
     */
1066
    protected function getResultLog($resultRow)
1067
    {
1068
        $content = '';
1069
1070
        if (is_array($resultRow) && array_key_exists('result_data', $resultRow)) {
1071
            $requestContent = unserialize($resultRow['result_data']);
1072
            $requestResult = unserialize($requestContent['content']);
1073
1074
            if (is_array($requestResult) && array_key_exists('log', $requestResult)) {
1075
                $content = implode(chr(10), $requestResult['log']);
1076
            }
1077
        }
1078
1079
        return $content;
1080
    }
1081
1082
    public function getResStatus($vv)
1083
    {
1084
        if ($vv['result_data']) {
1085
            $requestContent = unserialize($vv['result_data']);
1086
            $requestResult = unserialize($requestContent['content']);
1087
            if (is_array($requestResult)) {
1088
                if (empty($requestResult['errorlog'])) {
1089
                    $resStatus = 'OK';
1090
                } else {
1091
                    $resStatus = implode("\n", $requestResult['errorlog']);
1092
                }
1093
            } else {
1094
                $resStatus = 'Error: ' . substr(preg_replace('/\s+/', ' ', strip_tags($requestContent['content'])), 0, 10000) . '...';
1095
            }
1096
        } else {
1097
            $resStatus = '-';
1098
        }
1099
        return $resStatus;
1100
    }
1101
1102
    /*****************************
1103
     *
1104
     * CLI status display
1105
     *
1106
     *****************************/
1107
1108
    /**
1109
     * This method is used to show an overview about the active an the finished crawling processes
1110
     *
1111
     * @param void
1112
     * @return string
1113
     */
1114
    protected function drawProcessOverviewAction()
1115
    {
1116
        $this->runRefreshHooks();
1117
1118
        global $BACK_PATH;
1119
        $this->makeCrawlerProcessableChecks();
1120
1121
        $crawler = $this->findCrawler();
1122
        try {
1123
            $this->handleProcessOverviewActions();
1124
        } catch (\Exception $e) {
1125
            $this->addErrorMessage($e->getMessage());
1126
        }
1127
1128
        $offset = intval(GeneralUtility::_GP('offset'));
1129
        $perpage = 20;
1130
1131
        $processRepository = new ProcessRepository();
1132
        $queueRepository = new QueueRepository();
1133
1134
        $mode = $this->pObj->MOD_SETTINGS['processListMode'];
1135
        $where = '';
1136
        if ($mode == 'simple') {
1137
            $where = 'active = 1';
1138
        }
1139
1140
        $allProcesses = $processRepository->findAll('ttl', 'DESC', $perpage, $offset, $where);
0 ignored issues
show
Unused Code introduced by
The call to ProcessRepository::findAll() has too many arguments starting with 'ttl'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
1141
        $allCount = $processRepository->countAll($where);
0 ignored issues
show
Unused Code introduced by
The call to ProcessRepository::countAll() has too many arguments starting with $where.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
1142
1143
        $listView = new ProcessListView();
1144
        $listView->setPageId($this->pObj->id);
1145
        $listView->setIconPath($BACK_PATH . '../typo3conf/ext/crawler/template/process/res/img/');
1146
        $listView->setProcessCollection($allProcesses);
1147
        $listView->setCliPath($this->processManager->getCrawlerCliPath());
1148
        $listView->setIsCrawlerEnabled(!$crawler->getDisabled() && !$this->isErrorDetected);
1149
        $listView->setTotalUnprocessedItemCount($queueRepository->countAllPendingItems());
1150
        $listView->setAssignedUnprocessedItemCount($queueRepository->countAllAssignedPendingItems());
1151
        $listView->setActiveProcessCount($processRepository->countActive());
1152
        $listView->setMaxActiveProcessCount(MathUtility::forceIntegerInRange($this->extensionSettings['processLimit'], 1, 99, 1));
1153
        $listView->setMode($mode);
1154
1155
        $paginationView = new PaginationView();
1156
        $paginationView->setCurrentOffset($offset);
1157
        $paginationView->setPerPage($perpage);
1158
        $paginationView->setTotalItemCount($allCount);
1159
1160
        $output = $listView->render();
1161
1162
        if ($paginationView->getTotalPagesCount() > 1) {
1163
            $output .= ' <br />' . $paginationView->render();
1164
        }
1165
1166
        return $output;
1167
    }
1168
1169
    /**
1170
     * Verify that the crawler is exectuable.
1171
     *
1172
     * @return void
1173
     */
1174
    protected function makeCrawlerProcessableChecks()
1175
    {
1176
        global $LANG;
1177
1178
        /*if ($this->isCrawlerUserAvailable() === false) {
1179
            $this->addErrorMessage($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.noBeUserAvailable'));
1180
        } elseif ($this->isCrawlerUserAdmin() === true) {
1181
            $this->addErrorMessage($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.beUserIsAdmin'));
1182
        }*/
1183
1184
        if ($this->isPhpForkAvailable() === false) {
1185
            $this->addErrorMessage($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.noPhpForkAvailable'));
1186
        }
1187
1188
        $exitCode = 0;
1189
        $out = [];
1190
        exec(escapeshellcmd($this->extensionSettings['phpPath'] . ' -v'), $out, $exitCode);
1191
        if ($exitCode > 0) {
1192
            $this->addErrorMessage(sprintf($LANG->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:message.phpBinaryNotFound'), htmlspecialchars($this->extensionSettings['phpPath'])));
1193
        }
1194
    }
1195
1196
    /**
1197
     * Indicate that the required PHP method "popen" is
1198
     * available in the system.
1199
     *
1200
     * @return boolean
1201
     */
1202
    protected function isPhpForkAvailable()
1203
    {
1204
        return function_exists('popen');
1205
    }
1206
1207
    /**
1208
     * Indicate that the required be_user "_cli_crawler" is
1209
     * global available in the system.
1210
     *
1211
     * @return boolean
1212
     */
1213
    protected function isCrawlerUserAvailable()
1214
    {
1215
        $isAvailable = false;
1216
1217
        $username = '_cli_crawler';
1218
        /** @var QueryResult $user */
1219
        $user = $this->backendUserRepository->findByUsername($username);
1220
1221
        if ($user->getFirst() instanceof BackendUser ) {
1222
            $isAvailable = true;
1223
        }
1224
1225
        return $isAvailable;
1226
    }
1227
1228
    /**
1229
     * Check is the Crawler user has admin rights or not
1230
     *
1231
     * @return boolean
1232
     */
1233
    protected function isCrawlerUserAdmin()
1234
    {
1235
        $isAdmin = false;
1236
1237
        $username = '_cli_crawler';
1238
        /** @var QueryResult $user */
1239
        $user = $this->backendUserRepository->findByUsername($username);
1240
        if ($user->getFirst() instanceof BackendUser && $user->getFirst()->getIsAdministrator()) {
1241
            $isAdmin = true;
1242
        }
1243
1244
        return $isAdmin;
1245
    }
1246
1247
    /**
1248
     * Method to handle incomming actions of the process overview
1249
     *
1250
     * @throws \Exception
1251
     *
1252
     * @return void
1253
     */
1254
    protected function handleProcessOverviewActions()
1255
    {
1256
        $crawler = $this->findCrawler();
1257
1258
        switch (GeneralUtility::_GP('action')) {
1259
            case 'stopCrawling':
1260
                //set the cli status to disable (all processes will be terminated)
1261
                $crawler->setDisabled(true);
1262
                break;
1263
            case 'resumeCrawling':
1264
                //set the cli status to end (all processes will be terminated)
1265
                $crawler->setDisabled(false);
1266
                break;
1267
            case 'addProcess':
1268
                $handle = $this->processManager->startProcess();
1269
                if ($handle === false) {
1270
                    throw new \Exception($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.newprocesserror'));
1271
                }
1272
                $this->addNoticeMessage($GLOBALS['LANG']->sL('LLL:EXT:crawler/Resources/Private/Language/locallang.xml:labels.newprocess'));
1273
                break;
1274
        }
1275
    }
1276
1277
    /**
1278
     * Returns the singleton instance of the crawler.
1279
     *
1280
     * @param void
1281
     * @return CrawlerController crawler object
1282
     */
1283
    protected function findCrawler()
1284
    {
1285
        if (!$this->crawlerController instanceof CrawlerController) {
1286
            $this->crawlerController = GeneralUtility::makeInstance(CrawlerController::class);
1287
        }
1288
        return $this->crawlerController;
1289
    }
1290
1291
    /*****************************
1292
     *
1293
     * General Helper Functions
1294
     *
1295
     *****************************/
1296
1297
    /**
1298
     * This method is used to add a message to the internal queue
1299
     *
1300
     * @param  string  the message itself
1301
     * @param  integer message level (-1 = success (default), 0 = info, 1 = notice, 2 = warning, 3 = error)
1302
     *
1303
     * @return void
1304
     */
1305
    private function addMessage($message, $severity = FlashMessage::OK)
1306
    {
1307
        $message = GeneralUtility::makeInstance(
1308
            FlashMessage::class,
1309
            $message,
1310
            '',
1311
            $severity
1312
        );
1313
1314
        // TODO:
1315
        /** @var FlashMessageService $flashMessageService */
1316
        $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
1317
        $flashMessageService->getMessageQueueByIdentifier()->addMessage($message);
1318
    }
1319
1320
    /**
1321
     * Add notice message to the user interface.
1322
     *
1323
     * @param string The message
1324
     *
1325
     * @return void
1326
     */
1327
    protected function addNoticeMessage($message)
1328
    {
1329
        $this->addMessage($message, FlashMessage::NOTICE);
1330
    }
1331
1332
    /**
1333
     * Add error message to the user interface.
1334
     *
1335
     * @param string The message
1336
     *
1337
     * @return void
1338
     */
1339
    protected function addErrorMessage($message)
1340
    {
1341
        $this->isErrorDetected = true;
1342
        $this->addMessage($message, FlashMessage::ERROR);
1343
    }
1344
1345
    /**
1346
     * Add error message to the user interface.
1347
     *
1348
     * NOTE:
1349
     * This method is basesd on TYPO3 4.3 or higher!
1350
     *
1351
     * @param string The message
1352
     *
1353
     * @return void
1354
     */
1355
    protected function addWarningMessage($message)
1356
    {
1357
        $this->addMessage($message, FlashMessage::WARNING);
1358
    }
1359
1360
    /**
1361
     * Create selector box
1362
     *
1363
     * @param	array		$optArray Options key(value) => label pairs
1364
     * @param	string		$name Selector box name
1365
     * @param	string		$value Selector box value (array for multiple...)
1366
     * @param	boolean		$multiple If set, will draw multiple box.
1367
     *
1368
     * @return	string		HTML select element
1369
     */
1370
    public function selectorBox($optArray, $name, $value, $multiple)
1371
    {
1372
        $options = [];
1373
        foreach ($optArray as $key => $val) {
1374
            $options[] = '
1375
				<option value="' . htmlspecialchars($key) . '"' . ((!$multiple && !strcmp($value, $key)) || ($multiple && in_array($key, (array)$value)) ? ' selected="selected"' : '') . '>' . htmlspecialchars($val) . '</option>';
1376
        }
1377
1378
        $output = '<select name="' . htmlspecialchars($name . ($multiple ? '[]' : '')) . '"' . ($multiple ? ' multiple="multiple" size="' . count($options) . '"' : '') . '>' . implode('', $options) . '</select>';
1379
1380
        return $output;
1381
    }
1382
1383
    /**
1384
     * Activate hooks
1385
     *
1386
     * @return	void
1387
     */
1388
    public function runRefreshHooks()
1389
    {
1390
        $crawlerLib = GeneralUtility::makeInstance(CrawlerController::class);
1391
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['crawler']['refresh_hooks'])) {
1392
            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['crawler']['refresh_hooks'] as $objRef) {
1393
                $hookObj = GeneralUtility::makeInstance($objRef);
1394
                if (is_object($hookObj)) {
1395
                    $hookObj->crawler_init($crawlerLib);
1396
                }
1397
            }
1398
        }
1399
    }
1400
}
1401