diff --git a/README.md b/README.md index bccee60..1b9e642 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,9 @@ Provide a valid `load_callback` within you DataContainer field configuration. 'linkChecker' => array( 'label' => &$GLOBALS['TL_LANG']['tl_sample']['linkChecker'], 'inputType' => 'linkChecker', + 'eval' => array( + 'linkCheckerTimeout' => 10, + ), 'load_callback' => array( array('MyClass', 'getLinkCheckerHtml'), ), @@ -42,6 +45,7 @@ Provide a valid `load_callback` within you DataContainer field configuration. ``` You can return html-code with anchor tags, a single link or an array of links within your `load_callback`. +The `linkCheckerTimeout` eval option configures the timeout in seconds for the backend link check. If omitted or invalid, the default timeout is 10 seconds. ``` // MyClass diff --git a/src/EventListener/ExecutePreActionsListener.php b/src/EventListener/ExecutePreActionsListener.php index 6a1872c..28851a7 100644 --- a/src/EventListener/ExecutePreActionsListener.php +++ b/src/EventListener/ExecutePreActionsListener.php @@ -35,7 +35,10 @@ public function onExecutePreActions(string $action): void return; } - $strStatus = $this->linkChecker->test($request->request->get(LinkCheckerWidget::LINKCHECKER_PARAM)); + $strStatus = $this->linkChecker->test( + $request->request->get(LinkCheckerWidget::LINKCHECKER_PARAM), + $request->request->get(LinkCheckerWidget::LINKCHECKER_TIMEOUT_PARAM) + ); $objResponse = new ResponseSuccess(); $objResponse->setResult(new ResponseData($strStatus)); diff --git a/src/Manager/LinkChecker.php b/src/Manager/LinkChecker.php index bf72ae8..e57c4d0 100644 --- a/src/Manager/LinkChecker.php +++ b/src/Manager/LinkChecker.php @@ -13,6 +13,7 @@ use Contao\Validator; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; class LinkChecker @@ -20,6 +21,9 @@ class LinkChecker public const STATUS_MAILTO = 'mailto'; public const STATUS_INVALID = 'invalid'; public const STATUS_TIMEOUT = '408'; + public const STATUS_TRANSPORT_ERROR = 'transport_error'; + public const DEFAULT_TIMEOUT = 10; + public const MAX_TIMEOUT = 60; public const CLASS_DEFAULT = 'lc-default'; public const CLASS_INFO = 'lc-info'; @@ -39,13 +43,15 @@ public function __construct( * * @return array|bool|mixed */ - public function test($varLinks) + public function test($varLinks, int|string|null $timeout = null) { + $timeout = $this->normalizeTimeout($timeout); + if (!\is_array($varLinks)) { - return $this->testOne($varLinks); + return $this->testOne($varLinks, $timeout); } - return $this->testAll($varLinks); + return $this->testAll($varLinks, $timeout); } /** @@ -55,7 +61,7 @@ public function test($varLinks) * * @return string The translated status code, or false if the link was not tested */ - protected function testOne(string $url): string + protected function testOne(string $url, int $timeout): string { if (str_starts_with($url, 'mailto:')) { return $this->getResult(static::STATUS_MAILTO); @@ -65,9 +71,16 @@ protected function testOne(string $url): string return $this->getResult(static::STATUS_INVALID); } - $response = $this->client->request(Request::METHOD_GET, $url); + try { + $response = $this->client->request(Request::METHOD_GET, $url, [ + 'max_duration' => $timeout, + 'timeout' => $timeout, + ]); - return $this->getResult($response->getStatusCode()); + return $this->getResult($response->getStatusCode()); + } catch (TransportExceptionInterface) { + return $this->getResult(static::STATUS_TRANSPORT_ERROR); + } } /** @@ -77,18 +90,27 @@ protected function testOne(string $url): string * * @return array The list of tested links with translated status code, or false if the link was not tested */ - protected function testAll(array $arrLinks): array + protected function testAll(array $arrLinks, int $timeout): array { $arrResults = []; foreach ($arrLinks as $strKey => $strUrl) { - $arrResults[$strUrl] = $this->testOne($strUrl); + $arrResults[$strUrl] = $this->testOne($strUrl, $timeout); unset($arrLinks); } return $arrResults; } + protected function normalizeTimeout(int|string|null $timeout): int + { + if (null === $timeout || '' === $timeout || !is_numeric($timeout) || (int) $timeout < 1) { + return static::DEFAULT_TIMEOUT; + } + + return min((int) $timeout, static::MAX_TIMEOUT); + } + /** * Get the styled result. */ @@ -119,6 +141,10 @@ protected function getResult(string $result): string */ protected function getStatusClass(string $statusCode): string { + if (static::STATUS_TRANSPORT_ERROR === $statusCode) { + return static::CLASS_ERROR; + } + $intStart = null; if (\strlen($statusCode) > 0) { diff --git a/src/Resources/contao/languages/de/default.php b/src/Resources/contao/languages/de/default.php index 7d5829d..9828bd3 100644 --- a/src/Resources/contao/languages/de/default.php +++ b/src/Resources/contao/languages/de/default.php @@ -18,3 +18,5 @@ */ $arrLang['statusCodes'][LinkChecker::STATUS_MAILTO] = 'E-Mail Adressen werden nicht geprüft.'; $arrLang['statusCodes'][LinkChecker::STATUS_INVALID] = 'Ungültige URL, kann nicht geprüft werden.'; +$arrLang['statusCodes'][LinkChecker::STATUS_TIMEOUT] = 'Zeitüberschreitung bei der Anfrage.'; +$arrLang['statusCodes'][LinkChecker::STATUS_TRANSPORT_ERROR] = 'Anfrage fehlgeschlagen.'; diff --git a/src/Resources/contao/languages/en/default.php b/src/Resources/contao/languages/en/default.php index 3f17a34..21b5430 100644 --- a/src/Resources/contao/languages/en/default.php +++ b/src/Resources/contao/languages/en/default.php @@ -18,3 +18,5 @@ */ $arrLang['statusCodes'][LinkChecker::STATUS_MAILTO] = 'Email addresses are not checked.'; $arrLang['statusCodes'][LinkChecker::STATUS_INVALID] = 'Invalid URL, cannot be checked.'; +$arrLang['statusCodes'][LinkChecker::STATUS_TIMEOUT] = 'Request timed out.'; +$arrLang['statusCodes'][LinkChecker::STATUS_TRANSPORT_ERROR] = 'Request failed.'; diff --git a/src/Resources/contao/templates/backend/be_linkchecker.html5 b/src/Resources/contao/templates/backend/be_linkchecker.html5 index 0144e5a..d692a89 100644 --- a/src/Resources/contao/templates/backend/be_linkchecker.html5 +++ b/src/Resources/contao/templates/backend/be_linkchecker.html5 @@ -9,11 +9,11 @@ links as $objLink): ?>