PluginProbe
User Access Manager / 2.2.23
User Access Manager v2.2.23
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 +185 -140 trunk2.2.23 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
@@ -74,130 +159,61 @@
74 159
75 160 return $postUrls[$url];
76 161 }
77 162
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 163 /**
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.
164 + * Returns the file object by the given type and url.
165 + * @param string $objectType The type of the requested file.
166 + * @param string $objectUrl The file url.
167 + * @return null|FileObject
101 168 */
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
169 + private function getFileSettingsByType(string $objectType, string $objectUrl): ?FileObject
127 170 {
128 - $uploadDirs = $this->wordpress->getUploadDir();
129 - $requestedUrl = $this->normalizeAttachmentUrl($uploadDirs, $objectUrl);
130 - $postId = $this->getPostIdByUrl($requestedUrl);
171 + $fileObject = null;
131 172
132 - if ($postId < 1) {
133 - return null;
134 - }
173 + if ($objectType === ObjectHandler::ATTACHMENT_OBJECT_TYPE) {
174 + $uploadDirs = $this->wordpress->getUploadDir();
175 + $uploadDir = str_replace(ABSPATH, '/', $uploadDirs['basedir']);
176 + $regex = '/.*' . str_replace('/', '\/', $uploadDir) . '\//i';
177 + $cleanObjectUrl = preg_replace($regex, '', $objectUrl);
178 + $uploadUrl = str_replace('/files', $uploadDir, $uploadDirs['baseurl']);
179 + $objectUrl = rtrim($uploadUrl, '/') . '/' . ltrim($cleanObjectUrl, '/');
135 180
136 - $post = $this->objectHandler->getPost($postId);
181 + $post = $this->objectHandler->getPost($this->getPostIdByUrl($objectUrl));
182 + $postType = $post->post_type ?? '';
137 183
138 - if (($post->post_type ?? '') !== ObjectHandler::ATTACHMENT_OBJECT_TYPE) {
139 - return null;
140 - }
184 + if ($postType === ObjectHandler::ATTACHMENT_OBJECT_TYPE) {
185 + $multiPath = str_replace('/files', $uploadDir, $uploadDirs['baseurl']);
141 186
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);
187 + $fileObject = $this->fileObjectFactory->createFileObject(
188 + $post->ID,
189 + $objectType,
190 + $uploadDirs['basedir'] . str_replace($multiPath, '', $objectUrl),
191 + $this->wordpress->attachmentIsImage($post->ID)
192 + );
193 + }
194 + } else {
195 + $extraParameter = $this->getRequestParameter('uamextra');
146 196
147 - if ($attachedFile === false
148 - || $this->isInsideUploadDirectory($attachedFile, $uploadDirs['basedir']) === false
149 - ) {
150 - return null;
197 + $fileObject = $this->wordpress->applyFilters(
198 + 'uam_get_file_settings_by_type',
199 + $fileObject,
200 + $objectType,
201 + $objectUrl,
202 + $extraParameter
203 + );
151 204 }
152 205
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 - );
206 + return $fileObject;
167 207 }
168 208
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 209 /**
210 + * Delivers the content of the requested file.
211 + * @param string $objectType The type of the requested file.
212 + * @param string $objectUrl The file url.
197 213 * @throws UserGroupTypeException
198 214 */
199 - public function getFile(string $objectType, string $objectUrl): void
215 + public function getFile(string $objectType, string $objectUrl)
200 216 {
201 217 $fileObject = $this->getFileSettingsByType($objectType, $objectUrl);
202 218
203 219 if ($fileObject === null) {
@@ -220,8 +236,13 @@
220 236
221 237 $this->fileHandler->getFile($file, $fileObject->isImage());
222 238 }
223 239
240 + /**
241 + * Returns the redirect url and the permalink of the post if exists.
242 + * @param null|string $permalink
243 + * @return null|string
244 + */
224 245 private function getRedirectUrlAndPermalink(?string &$permalink): ?string
225 246 {
226 247 $permalink = null;
227 248 $redirect = $this->mainConfig->getRedirect();
@@ -238,11 +259,8 @@
238 259 } elseif ($redirect === 'custom_url') {
239 260 $url = $this->mainConfig->getRedirectCustomUrl();
240 261 } elseif ($redirect === 'login') {
241 262 $url = $this->getLoginUrl();
242 - } elseif ($redirect === 'origin') {
243 - $referer = $this->wordpress->getReferer();
244 - $url = $referer !== false ? $referer : $this->wordpress->getHomeUrl('/');
245 263 } else {
246 264 $url = $this->wordpress->getHomeUrl('/');
247 265 }
248 266
@@ -249,14 +267,16 @@
249 267 return $url;
250 268 }
251 269
252 270 /**
271 + * Redirects the user to his destination.
272 + * @param bool $checkPosts
253 273 * @throws UserGroupTypeException
254 274 */
255 - public function redirectUser(bool $checkPosts = true): void
275 + public function redirectUser($checkPosts = true)
256 276 {
257 277 if ($checkPosts === true) {
258 - $posts = $this->wordpress->getWpQuery()->get_posts();
278 + $posts = (array)$this->wordpress->getWpQuery()->get_posts();
259 279
260 280 foreach ($posts as $post) {
261 281 if ($this->accessHandler->checkObjectAccess($post->post_type, $post->ID)) {
262 282 return;
@@ -267,26 +287,27 @@
267 287 $url = $this->getRedirectUrlAndPermalink($permalink);
268 288 $currentUrl = $this->util->getCurrentUrl();
269 289
270 290 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 291 $this->wordpress->wpRedirect($url);
276 292 $this->php->callExit();
277 293 }
278 294 }
279 295
296 + /**
297 + * Returns the post id by the post name.
298 + * @param string $name
299 + * @return int
300 + */
280 301 private function getPostIdByName(string $name): int
281 302 {
282 303 $postableTypes = implode('\',\'', $this->objectHandler->getPostTypes());
283 304
284 305 $query = $this->database->prepare(
285 - "SELECT `ID`
286 - FROM `{$this->database->getPostsTable()}`
287 - WHERE `post_name` = %s
288 - AND `post_type` IN ('$postableTypes')",
306 + "SELECT ID
307 + FROM {$this->database->getPostsTable()}
308 + WHERE post_name = %s
309 + AND post_type IN ('{$postableTypes}')",
289 310 $name
290 311 );
291 312
292 313 return (int) $this->database->getVariable($query);
@@ -291,9 +312,15 @@
291 312
292 313 return (int) $this->database->getVariable($query);
293 314 }
294 315
295 - private function extractObjectTypeAndId(mixed $pageParams, ?string &$objectType, int|string|null &$objectId): void
316 + /**
317 + * Extracts the object type and id.
318 + * @param mixed $pageParams
319 + * @param null|string $objectType
320 + * @param null|int|string $objectId
321 + */
322 + private function extractObjectTypeAndId($pageParams, ?string &$objectType, ?string &$objectId)
296 323 {
297 324 $objectType = null;
298 325 $objectId = null;
299 326
@@ -323,11 +350,15 @@
323 350 }
324 351 }
325 352
326 353 /**
354 + * Redirects to a page or to content.
355 + * @param array|null $headers The headers which are given from wordpress.
356 + * @param mixed $pageParams The params of the current page.
357 + * @return array|null
327 358 * @throws UserGroupTypeException
328 359 */
329 - public function redirect(?array $headers, mixed $pageParams): ?array
360 + public function redirect(?array $headers, $pageParams): ?array
330 361 {
331 362 $fileUrl = $this->getRequestParameter('uamgetfile');
332 363 $fileType = $this->getRequestParameter('uamfiletype');
333 364
@@ -345,9 +376,15 @@
345 376
346 377 return $headers;
347 378 }
348 379
349 - public function getFileUrl(string $url, int|string|null $id): string
380 + /**
381 + * Returns the url for a locked file.
382 + * @param string $url The base url.
383 + * @param int|string $id The id of the file.
384 + * @return string
385 + */
386 + public function getFileUrl(string $url, $id): string
350 387 {
351 388 // Nginx always supports real urls so we need the new urls only
352 389 // if we don't use nginx and mod_rewrite is disabled
353 390 if ($this->mainConfig->lockFile() === true
@@ -355,9 +392,9 @@
355 392 && $this->wordpress->gotModRewrite() === false
356 393 ) {
357 394 $post = $this->objectHandler->getPost($id);
358 395
359 - if ($post !== false) {
396 + if ($post !== null) {
360 397 $type = explode('/', $post->post_mime_type);
361 398 $type = $type[1] ?? $type[0];
362 399
363 400 $lockedFileTypes = $this->mainConfig->getLockedFiles();
@@ -371,8 +408,14 @@
371 408
372 409 return $url;
373 410 }
374 411
412 + /**
413 + * Caches the urls for the post for a later lookup.
414 + * @param string $url The url of the post.
415 + * @param object $post The post object.
416 + * @return string
417 + */
375 418 public function cachePostLinks(string $url, object $post): string
376 419 {
377 420 $postUrls = (array) $this->cache->getFromRuntimeCache(self::POST_URL_CACHE_KEY);
378 421 $postUrls[$url] = $post->ID;
@@ -379,10 +422,12 @@
379 422 $this->cache->addToRuntimeCache(self::POST_URL_CACHE_KEY, $postUrls);
380 423 return $url;
381 424 }
382 425
383 - #[NoReturn]
384 - public function testXSendFile(): void
426 + /**
427 + * Tries to load the file via x send file
428 + */
429 + public function testXSendFile()
385 430 {
386 431 $this->fileHandler->deliverXSendFileTestFile();
387 432 }
388 433 }