PluginProbe
User Access Manager / 2.2.13
User Access Manager v2.2.13
2.3.20 2.3.19 2.3.18 2.3.17 2.3.16 2.3.15 2.3.14 2.3.13 trunk 0.6 0.6.1 0.6.2 0.7 0.7 Beta 0.7.0.1 0.8 0.8.0.1 0.8.0.2 0.9 0.9.1 0.9.1.1 0.9.1.2 0.9.1.3 0.9.1.4 1.0 All 136 releases
← All changes | src/Controller/Frontend/RedirectController.php +186 -148 trunk2.2.13 View file →
@@ -1,21 +1,32 @@
1 1 <?php
2 +/**
3 + * FrontendRedirectController.php
4 + *
5 + * The FrontendRedirectController class file.
6 + *
7 + * PHP versions 5
8 + *
9 + * @author Alexander Schneider <alexanderschneider85@gmail.com>
10 + * @copyright 2008-2017 Alexander Schneider
11 + * @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2
12 + * @version SVN: $id$
13 + * @link http://wordpress.org/extend/plugins/user-access-manager/
14 + */
2 15
3 16 declare(strict_types=1);
4 17
5 18 namespace UserAccessManager\Controller\Frontend;
6 19
7 -use JetBrains\PhpStorm\NoReturn;
8 20 use UserAccessManager\Access\AccessHandler;
9 21 use UserAccessManager\Cache\Cache;
10 22 use UserAccessManager\Config\MainConfig;
11 23 use UserAccessManager\Config\WordpressConfig;
12 24 use UserAccessManager\Controller\Controller;
13 -use UserAccessManager\Controller\Frontend\Authentication\LoginControllerTrait;
14 25 use UserAccessManager\Database\Database;
15 26 use UserAccessManager\File\FileHandler;
16 -use UserAccessManager\File\Delivery\FileObject;
17 -use UserAccessManager\File\Delivery\FileObjectFactory;
27 +use UserAccessManager\File\FileObject;
28 +use UserAccessManager\File\FileObjectFactory;
18 29 use UserAccessManager\Object\ObjectHandler;
19 30 use UserAccessManager\UserGroup\UserGroupTypeException;
20 31 use UserAccessManager\Util\Util;
21 32 use UserAccessManager\Wrapper\Php;
@@ -20,36 +31,110 @@
20 31 use UserAccessManager\Util\Util;
21 32 use UserAccessManager\Wrapper\Php;
22 33 use UserAccessManager\Wrapper\Wordpress;
23 34
35 +/**
36 + * Class FrontendRedirectController
37 + *
38 + * @package UserAccessManager\Controller
39 + */
24 40 class RedirectController extends Controller
25 41 {
26 42 use LoginControllerTrait;
27 43
28 - public const POST_URL_CACHE_KEY = 'PostUrls';
29 - public const REDIRECT_TO_PARAMETER = 'redirect_to';
44 + const POST_URL_CACHE_KEY = 'PostUrls';
30 45
46 + /**
47 + * @var MainConfig
48 + */
49 + private $mainConfig;
50 +
51 + /**
52 + * @var Database
53 + */
54 + private $database;
55 +
56 + /**
57 + * @var Cache
58 + */
59 + private $cache;
60 +
61 + /**
62 + * @var Util
63 + */
64 + private $util;
65 +
66 + /**
67 + * @var ObjectHandler
68 + */
69 + private $objectHandler;
70 +
71 + /**
72 + * @var AccessHandler
73 + */
74 + private $accessHandler;
75 +
76 + /**
77 + * @var FileHandler
78 + */
79 + private $fileHandler;
80 +
81 + /**
82 + * @var FileObjectFactory
83 + */
84 + private $fileObjectFactory;
85 +
86 + /**
87 + * RedirectController constructor.
88 + * @param Php $php
89 + * @param Wordpress $wordpress
90 + * @param WordpressConfig $wordpressConfig
91 + * @param MainConfig $mainConfig
92 + * @param Database $database
93 + * @param Util $util
94 + * @param Cache $cache
95 + * @param ObjectHandler $objectHandler
96 + * @param AccessHandler $accessHandler
97 + * @param FileHandler $fileHandler
98 + * @param FileObjectFactory $fileObjectFactory
99 + */
31 100 public function __construct(
32 101 Php $php,
33 102 Wordpress $wordpress,
34 103 WordpressConfig $wordpressConfig,
35 - private MainConfig $mainConfig,
36 - private Database $database,
37 - private Util $util,
38 - private Cache $cache,
39 - private ObjectHandler $objectHandler,
40 - private AccessHandler $accessHandler,
41 - private FileHandler $fileHandler,
42 - private FileObjectFactory $fileObjectFactory
104 + MainConfig $mainConfig,
105 + Database $database,
106 + Util $util,
107 + Cache $cache,
108 + ObjectHandler $objectHandler,
109 + AccessHandler $accessHandler,
110 + FileHandler $fileHandler,
111 + FileObjectFactory $fileObjectFactory
43 112 ) {
44 113 parent::__construct($php, $wordpress, $wordpressConfig);
114 + $this->mainConfig = $mainConfig;
115 + $this->database = $database;
116 + $this->util = $util;
117 + $this->cache = $cache;
118 + $this->objectHandler = $objectHandler;
119 + $this->accessHandler = $accessHandler;
120 + $this->fileHandler = $fileHandler;
121 + $this->fileObjectFactory = $fileObjectFactory;
45 122 }
46 123
124 + /**
125 + * @return Wordpress
126 + */
47 127 protected function getWordpress(): Wordpress
48 128 {
49 129 return $this->wordpress;
50 130 }
51 131
132 + /**
133 + * Returns the post by the given url.
134 + * @param string $url The url of the post(attachment).
135 + * @return int
136 + */
52 137 public function getPostIdByUrl(string $url): int
53 138 {
54 139 $postUrls = (array)$this->cache->getFromRuntimeCache(self::POST_URL_CACHE_KEY);
55 140
@@ -61,143 +146,67 @@
61 146 $newUrlPieces = preg_split('/-[0-9]+x[0-9]+(_[a-z])?/', $url);
62 147 $newUrl = (count($newUrlPieces) === 2) ? $newUrlPieces[0] . $newUrlPieces[1] : $newUrlPieces[0];
63 148 $newUrl = preg_replace('/-pdf\.jpg$/', '.pdf', $newUrl);
64 149
65 - $postId = $this->wordpress->attachmentUrlToPostId($newUrl);
66 -
67 - if ($postId === 0) {
68 - $newUrl = preg_replace('/(\\.[^.\\s]{3,4})$/', '-scaled$1', $newUrl);
69 - $postId = $this->wordpress->attachmentUrlToPostId($newUrl);
70 - }
71 -
72 - $postUrls[$url] = $postId;
150 + $postUrls[$url] = $this->wordpress->attachmentUrlToPostId($newUrl);
73 151 $this->cache->addToRuntimeCache(self::POST_URL_CACHE_KEY, $postUrls);
74 152
75 153 return $postUrls[$url];
76 154 }
77 155
78 - private function normalizeAttachmentUrl(array $uploadDirs, string $objectUrl): string
79 - {
80 - $uploadDir = str_replace(ABSPATH, '/', $uploadDirs['basedir']);
81 - $regex = '/.*' . str_replace('/', '\/', $uploadDir) . '\//i';
82 - $cleanObjectUrl = preg_replace($regex, '', $objectUrl);
83 - $uploadUrl = str_replace('/files', $uploadDir, $uploadDirs['baseurl']);
84 -
85 - return rtrim($uploadUrl, '/') . '/' . ltrim($cleanObjectUrl, '/');
86 - }
87 -
88 - private function isRegisteredSize(int $attachmentId, string $fileName): bool
89 - {
90 - $metaData = $this->wordpress->getAttachmentMetadata($attachmentId);
91 - $sizes = is_array($metaData) === true ? (array) ($metaData['sizes'] ?? []) : [];
92 -
93 - return in_array($fileName, array_column($sizes, 'file'), true);
94 - }
95 -
96 156 /**
97 - * Returns the file the request asks for and tells through $isImage whether it can be shown as image.
98 - * A requested generated size is only used if it is registered at the attachment and stored inside the
99 - * upload directory, so no arbitrary and no missing file becomes reachable. Generated sizes are always
100 - * images, also for documents like PDFs, where they are the preview images shown in the media library.
157 + * Returns the file object by the given type and url.
158 + * @param string $objectType The type of the requested file.
159 + * @param string $objectUrl The file url.
160 + * @return null|FileObject
101 161 */
102 - private function getAttachmentFile(
103 - int $attachmentId,
104 - string $attachedFile,
105 - string $requestedUrl,
106 - string $uploadBaseDir,
107 - ?bool &$isImage
108 - ): string {
109 - $requestedFileName = basename((string) parse_url($requestedUrl, PHP_URL_PATH));
110 - $sizeFile = dirname($attachedFile) . DIRECTORY_SEPARATOR . $requestedFileName;
111 -
112 - if ($requestedFileName !== basename($attachedFile)
113 - && $this->isRegisteredSize($attachmentId, $requestedFileName) === true
114 - && $this->isInsideUploadDirectory($sizeFile, $uploadBaseDir) === true
115 - ) {
116 - $isImage = true;
117 -
118 - return $sizeFile;
119 - }
120 -
121 - $isImage = $this->wordpress->attachmentIsImage($attachmentId);
122 -
123 - return $attachedFile;
124 - }
125 -
126 - private function getAttachmentFileObject(string $objectUrl): ?FileObject
162 + private function getFileSettingsByType(string $objectType, string $objectUrl): ?FileObject
127 163 {
128 - $uploadDirs = $this->wordpress->getUploadDir();
129 - $requestedUrl = $this->normalizeAttachmentUrl($uploadDirs, $objectUrl);
130 - $postId = $this->getPostIdByUrl($requestedUrl);
164 + $fileObject = null;
131 165
132 - if ($postId < 1) {
133 - return null;
134 - }
166 + if ($objectType === ObjectHandler::ATTACHMENT_OBJECT_TYPE) {
167 + $uploadDirs = $this->wordpress->getUploadDir();
168 + $uploadDir = str_replace(ABSPATH, '/', $uploadDirs['basedir']);
169 + $regex = '/.*' . str_replace('/', '\/', $uploadDir) . '\//i';
170 + $cleanObjectUrl = preg_replace($regex, '', $objectUrl);
171 + $uploadUrl = str_replace('/files', $uploadDir, $uploadDirs['baseurl']);
172 + $objectUrl = rtrim($uploadUrl, '/') . '/' . ltrim($cleanObjectUrl, '/');
135 173
136 - $post = $this->objectHandler->getPost($postId);
174 + $post = $this->objectHandler->getPost($this->getPostIdByUrl($objectUrl));
175 + $postType = $post->post_type ?? '';
137 176
138 - if (($post->post_type ?? '') !== ObjectHandler::ATTACHMENT_OBJECT_TYPE) {
139 - return null;
140 - }
177 + if ($postType === ObjectHandler::ATTACHMENT_OBJECT_TYPE) {
178 + $multiPath = str_replace('/files', $uploadDir, $uploadDirs['baseurl']);
141 179
142 - // Unfiltered, because the plugin denies the path through the get_attached_file filter for
143 - // users without access. Filtered it would hide the file from the access check below, which
144 - // then could not answer the request with the no rights page any more.
145 - $attachedFile = $this->wordpress->getAttachedFile($post->ID, true);
180 + $fileObject = $this->fileObjectFactory->createFileObject(
181 + $post->ID,
182 + $objectType,
183 + $uploadDirs['basedir'] . str_replace($multiPath, '', $objectUrl),
184 + $this->wordpress->attachmentIsImage($post->ID)
185 + );
186 + }
187 + } else {
188 + $extraParameter = $this->getRequestParameter('uamextra');
146 189
147 - if ($attachedFile === false
148 - || $this->isInsideUploadDirectory($attachedFile, $uploadDirs['basedir']) === false
149 - ) {
150 - return null;
190 + $fileObject = $this->wordpress->applyFilters(
191 + 'uam_get_file_settings_by_type',
192 + $fileObject,
193 + $objectType,
194 + $objectUrl,
195 + $extraParameter
196 + );
151 197 }
152 198
153 - $file = $this->getAttachmentFile(
154 - $post->ID,
155 - $attachedFile,
156 - $requestedUrl,
157 - $uploadDirs['basedir'],
158 - $isImage
159 - );
160 -
161 - return $this->fileObjectFactory->createFileObject(
162 - $post->ID,
163 - ObjectHandler::ATTACHMENT_OBJECT_TYPE,
164 - $file,
165 - $isImage
166 - );
199 + return $fileObject;
167 200 }
168 201
169 - private function isInsideUploadDirectory(string $file, string $uploadBaseDir): bool
170 - {
171 - $realFile = $this->php->realpath($file);
172 - $realUploadBaseDir = $this->php->realpath($uploadBaseDir);
173 -
174 - return $realFile !== false
175 - && $realUploadBaseDir !== false
176 - && str_starts_with($realFile, $realUploadBaseDir . DIRECTORY_SEPARATOR);
177 - }
178 -
179 - private function getFileSettingsByType(string $objectType, string $objectUrl): ?FileObject
180 - {
181 - if ($objectType === ObjectHandler::ATTACHMENT_OBJECT_TYPE) {
182 - return $this->getAttachmentFileObject($objectUrl);
183 - }
184 -
185 - $extraParameter = $this->getRequestParameter('uamextra');
186 -
187 - return $this->wordpress->applyFilters(
188 - 'uam_get_file_settings_by_type',
189 - null,
190 - $objectType,
191 - $objectUrl,
192 - $extraParameter
193 - );
194 - }
195 -
196 202 /**
203 + * Delivers the content of the requested file.
204 + * @param string $objectType The type of the requested file.
205 + * @param string $objectUrl The file url.
197 206 * @throws UserGroupTypeException
198 207 */
199 - public function getFile(string $objectType, string $objectUrl): void
208 + public function getFile(string $objectType, string $objectUrl)
200 209 {
201 210 $fileObject = $this->getFileSettingsByType($objectType, $objectUrl);
202 211
203 212 if ($fileObject === null) {
@@ -220,8 +229,13 @@
220 229
221 230 $this->fileHandler->getFile($file, $fileObject->isImage());
222 231 }
223 232
233 + /**
234 + * Returns the redirect url and the permalink of the post if exists.
235 + * @param null|string $permalink
236 + * @return null|string
237 + */
224 238 private function getRedirectUrlAndPermalink(?string &$permalink): ?string
225 239 {
226 240 $permalink = null;
227 241 $redirect = $this->mainConfig->getRedirect();
@@ -238,11 +252,8 @@
238 252 } elseif ($redirect === 'custom_url') {
239 253 $url = $this->mainConfig->getRedirectCustomUrl();
240 254 } elseif ($redirect === 'login') {
241 255 $url = $this->getLoginUrl();
242 - } elseif ($redirect === 'origin') {
243 - $referer = $this->wordpress->getReferer();
244 - $url = $referer !== false ? $referer : $this->wordpress->getHomeUrl('/');
245 256 } else {
246 257 $url = $this->wordpress->getHomeUrl('/');
247 258 }
248 259
@@ -249,14 +260,16 @@
249 260 return $url;
250 261 }
251 262
252 263 /**
264 + * Redirects the user to his destination.
265 + * @param bool $checkPosts
253 266 * @throws UserGroupTypeException
254 267 */
255 - public function redirectUser(bool $checkPosts = true): void
268 + public function redirectUser($checkPosts = true)
256 269 {
257 270 if ($checkPosts === true) {
258 - $posts = $this->wordpress->getWpQuery()->get_posts();
271 + $posts = (array)$this->wordpress->getWpQuery()->get_posts();
259 272
260 273 foreach ($posts as $post) {
261 274 if ($this->accessHandler->checkObjectAccess($post->post_type, $post->ID)) {
262 275 return;
@@ -267,26 +280,27 @@
267 280 $url = $this->getRedirectUrlAndPermalink($permalink);
268 281 $currentUrl = $this->util->getCurrentUrl();
269 282
270 283 if ($url !== null && $url !== $currentUrl && $permalink !== $currentUrl) {
271 - if ($this->mainConfig->appendRedirectToParameter() === true) {
272 - $url = $this->wordpress->addQueryArg([self::REDIRECT_TO_PARAMETER => $currentUrl], $url);
273 - }
274 -
275 284 $this->wordpress->wpRedirect($url);
276 285 $this->php->callExit();
277 286 }
278 287 }
279 288
289 + /**
290 + * Returns the post id by the post name.
291 + * @param string $name
292 + * @return int
293 + */
280 294 private function getPostIdByName(string $name): int
281 295 {
282 296 $postableTypes = implode('\',\'', $this->objectHandler->getPostTypes());
283 297
284 298 $query = $this->database->prepare(
285 - "SELECT `ID`
286 - FROM `{$this->database->getPostsTable()}`
287 - WHERE `post_name` = %s
288 - AND `post_type` IN ('$postableTypes')",
299 + "SELECT ID
300 + FROM {$this->database->getPostsTable()}
301 + WHERE post_name = %s
302 + AND post_type IN ('{$postableTypes}')",
289 303 $name
290 304 );
291 305
292 306 return (int) $this->database->getVariable($query);
@@ -291,9 +305,15 @@
291 305
292 306 return (int) $this->database->getVariable($query);
293 307 }
294 308
295 - private function extractObjectTypeAndId(mixed $pageParams, ?string &$objectType, int|string|null &$objectId): void
309 + /**
310 + * Extracts the object type and id.
311 + * @param object $pageParams
312 + * @param null|string $objectType
313 + * @param null|int|string $objectId
314 + */
315 + private function extractObjectTypeAndId(object $pageParams, ?string &$objectType, ?string &$objectId)
296 316 {
297 317 $objectType = null;
298 318 $objectId = null;
299 319
@@ -323,11 +343,15 @@
323 343 }
324 344 }
325 345
326 346 /**
347 + * Redirects to a page or to content.
348 + * @param array $headers The headers which are given from wordpress.
349 + * @param object $pageParams The params of the current page.
350 + * @return array
327 351 * @throws UserGroupTypeException
328 352 */
329 - public function redirect(?array $headers, mixed $pageParams): ?array
353 + public function redirect(array $headers, object $pageParams): array
330 354 {
331 355 $fileUrl = $this->getRequestParameter('uamgetfile');
332 356 $fileType = $this->getRequestParameter('uamfiletype');
333 357
@@ -345,9 +369,15 @@
345 369
346 370 return $headers;
347 371 }
348 372
349 - public function getFileUrl(string $url, int|string|null $id): string
373 + /**
374 + * Returns the url for a locked file.
375 + * @param string $url The base url.
376 + * @param int|string $id The id of the file.
377 + * @return string
378 + */
379 + public function getFileUrl(string $url, $id): string
350 380 {
351 381 // Nginx always supports real urls so we need the new urls only
352 382 // if we don't use nginx and mod_rewrite is disabled
353 383 if ($this->mainConfig->lockFile() === true
@@ -355,9 +385,9 @@
355 385 && $this->wordpress->gotModRewrite() === false
356 386 ) {
357 387 $post = $this->objectHandler->getPost($id);
358 388
359 - if ($post !== false) {
389 + if ($post !== null) {
360 390 $type = explode('/', $post->post_mime_type);
361 391 $type = $type[1] ?? $type[0];
362 392
363 393 $lockedFileTypes = $this->mainConfig->getLockedFiles();
@@ -371,8 +401,14 @@
371 401
372 402 return $url;
373 403 }
374 404
405 + /**
406 + * Caches the urls for the post for a later lookup.
407 + * @param string $url The url of the post.
408 + * @param object $post The post object.
409 + * @return string
410 + */
375 411 public function cachePostLinks(string $url, object $post): string
376 412 {
377 413 $postUrls = (array) $this->cache->getFromRuntimeCache(self::POST_URL_CACHE_KEY);
378 414 $postUrls[$url] = $post->ID;
@@ -379,10 +415,12 @@
379 415 $this->cache->addToRuntimeCache(self::POST_URL_CACHE_KEY, $postUrls);
380 416 return $url;
381 417 }
382 418
383 - #[NoReturn]
384 - public function testXSendFile(): void
419 + /**
420 + * Tries to load the file via x send file
421 + */
422 + public function testXSendFile()
385 423 {
386 424 $this->fileHandler->deliverXSendFileTestFile();
387 425 }
388 426 }