44fc3b370832d9bb4ef0792e66a24afead9b07b8
[Packages/TYPO3.CMS.git] / typo3 / sysext / linkvalidator / Classes / Linktype / ExternalLinktype.php
1 <?php
2 namespace TYPO3\CMS\Linkvalidator\Linktype;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 /**
18 * This class provides Check External Links plugin implementation
19 *
20 * @author Dimitri K├Ânig <dk@cabag.ch>
21 * @author Michael Miousse <michael.miousse@infoglobe.ca>
22 * @author Philipp Gampe <typo3.dev@philippgampe.info>
23 */
24 class ExternalLinktype extends \TYPO3\CMS\Linkvalidator\Linktype\AbstractLinktype {
25
26 /**
27 * Cached list of the URLs, which were already checked for the current processing
28 *
29 * @var array $urlReports
30 */
31 protected $urlReports = array();
32
33 /**
34 * Cached list of all error parameters of the URLs, which were already checked for the current processing
35 *
36 * @var array $urlErrorParams
37 */
38 protected $urlErrorParams = array();
39
40 /**
41 * List of headers to be used for matching an URL for the current processing
42 *
43 * @var array $additionalHeaders
44 */
45 protected $additionalHeaders = array();
46
47 /**
48 * Checks a given URL for validity
49 *
50 * @param string $url The URL to check
51 * @param array $softRefEntry The soft reference entry which builds the context of that URL
52 * @param \TYPO3\CMS\Linkvalidator\LinkAnalyzer $reference Parent instance
53 * @return bool TRUE on success or FALSE on error
54 */
55 public function checkLink($url, $softRefEntry, $reference) {
56 $errorParams = array();
57 $isValidUrl = TRUE;
58 if (isset($this->urlReports[$url])) {
59 if (!$this->urlReports[$url]) {
60 if (is_array($this->urlErrorParams[$url])) {
61 $this->setErrorParams($this->urlErrorParams[$url]);
62 }
63 }
64 return $this->urlReports[$url];
65 }
66 $config = array(
67 'follow_redirects' => TRUE,
68 'strict_redirects' => TRUE
69 );
70 /** @var $request \TYPO3\CMS\Core\Http\HttpRequest */
71 $request = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Http\HttpRequest::class, $url, 'HEAD', $config);
72 // Observe cookies
73 $request->setCookieJar(TRUE);
74 try {
75 /** @var $response \HTTP_Request2_Response */
76 $response = $request->send();
77 $status = isset($response) ? $response->getStatus() : 0;
78 // HEAD was not allowed or threw an error, now trying GET
79 if ($status >= 400) {
80 $request->setMethod('GET');
81 $request->setHeader('Range', 'bytes = 0 - 4048');
82 /** @var $response \HTTP_Request2_Response */
83 $response = $request->send();
84 }
85 } catch (\Exception $e) {
86 $isValidUrl = FALSE;
87 // A redirect loop occurred
88 if ($e->getCode() === 40) {
89 // Parse the exception for more information
90 $trace = $e->getTrace();
91 $traceUrl = $trace[0]['args'][0]->getUrl()->getUrl();
92 $traceCode = $trace[0]['args'][1]->getStatus();
93 $errorParams['errorType'] = 'loop';
94 $errorParams['location'] = $traceUrl;
95 $errorParams['errorCode'] = $traceCode;
96 } else {
97 $errorParams['errorType'] = 'exception';
98 }
99 $errorParams['message'] = $e->getMessage();
100 }
101 $status = isset($response) ? $response->getStatus() : 0;
102 if ($status >= 300) {
103 $isValidUrl = FALSE;
104 $errorParams['errorType'] = $status;
105 $errorParams['message'] = $response->getReasonPhrase();
106 }
107 if (!$isValidUrl) {
108 $this->setErrorParams($errorParams);
109 }
110 $this->urlReports[$url] = $isValidUrl;
111 $this->urlErrorParams[$url] = $errorParams;
112 return $isValidUrl;
113 }
114
115 /**
116 * Generate the localized error message from the error params saved from the parsing
117 *
118 * @param array $errorParams All parameters needed for the rendering of the error message
119 * @return string Validation error message
120 */
121 public function getErrorMessage($errorParams) {
122 $errorType = $errorParams['errorType'];
123 switch ($errorType) {
124 case 300:
125 $response = sprintf($GLOBALS['LANG']->getLL('list.report.externalerror'), $errorType);
126 break;
127 case 403:
128 $response = $GLOBALS['LANG']->getLL('list.report.pageforbidden403');
129 break;
130 case 404:
131 $response = $GLOBALS['LANG']->getLL('list.report.pagenotfound404');
132 break;
133 case 500:
134 $response = $GLOBALS['LANG']->getLL('list.report.internalerror500');
135 break;
136 case 'loop':
137 $response = sprintf($GLOBALS['LANG']->getLL('list.report.redirectloop'), $errorParams['errorCode'], $errorParams['location']);
138 break;
139 case 'exception':
140 $response = sprintf($GLOBALS['LANG']->getLL('list.report.httpexception'), $errorParams['message']);
141 break;
142 default:
143 $response = sprintf($GLOBALS['LANG']->getLL('list.report.otherhttpcode'), $errorType, $errorParams['message']);
144 }
145 return $response;
146 }
147
148 /**
149 * Get the external type from the softRefParserObj result
150 *
151 * @param array $value Reference properties
152 * @param string $type Current type
153 * @param string $key Validator hook name
154 * @return string Fetched type
155 */
156 public function fetchType($value, $type, $key) {
157 preg_match_all('/((?:http|https))(?::\\/\\/)(?:[^\\s<>]+)/i', $value['tokenValue'], $urls, PREG_PATTERN_ORDER);
158 if (!empty($urls[0][0])) {
159 $type = 'external';
160 }
161 return $type;
162 }
163
164 }