PluginProbe
User Access Manager / 2.1.11
User Access Manager v2.1.11
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/PostController.php +208 -174 2.3.14 → 2.1.11 View file →
@@ -1,49 +1,79 @@
1 1 <?php
2 -
3 -declare(strict_types=1);
4 -
2 +/**
3 + * FrontendPostController.php
4 + *
5 + * The FrontendPostController class file.
6 + *
7 + * PHP versions 5
8 + *
9 + * @author Alexander Schneider <[email protected]>
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 + */
5 15 namespace UserAccessManager\Controller\Frontend;
6 16
7 -use stdClass;
8 17 use UserAccessManager\Access\AccessHandler;
9 18 use UserAccessManager\Config\MainConfig;
10 19 use UserAccessManager\Config\WordpressConfig;
11 20 use UserAccessManager\Database\Database;
12 21 use UserAccessManager\Object\ObjectHandler;
22 +use UserAccessManager\UserGroup\AbstractUserGroup;
13 23 use UserAccessManager\User\UserHandler;
14 -use UserAccessManager\UserGroup\AbstractUserGroup;
15 24 use UserAccessManager\UserGroup\UserGroupHandler;
16 -use UserAccessManager\UserGroup\UserGroupTypeException;
17 25 use UserAccessManager\Util\Util;
18 26 use UserAccessManager\Wrapper\Php;
19 27 use UserAccessManager\Wrapper\Wordpress;
20 -use WeakMap;
21 -use WP_Comment;
22 -use WP_Hook;
23 -use WP_Post;
24 -use WP_Query;
25 -use WP_REST_Request;
26 -use WP_REST_Response;
27 28
29 +/**
30 + * Class FrontendPostController
31 + *
32 + * @package UserAccessManager\Controller
33 + */
28 34 class PostController extends ContentController
29 35 {
30 - private array $wordpressFilters = [];
31 - private stdClass|array|null $cachedCounts = [];
36 + /**
37 + * @var Database
38 + */
39 + private $database;
32 40
33 - private WeakMap $posts;
41 + /**
42 + * @var array
43 + */
44 + private $wordpressFilters = [];
34 45
46 + /**
47 + * @var null|\stdClass
48 + */
49 + private $cachedCounts = [];
50 +
51 + /**
52 + * PostController constructor.
53 + *
54 + * @param Php $php
55 + * @param Wordpress $wordpress
56 + * @param WordpressConfig $wordpressConfig
57 + * @param MainConfig $mainConfig
58 + * @param Database $database
59 + * @param Util $util
60 + * @param ObjectHandler $objectHandler
61 + * @param UserHandler $userHandler
62 + * @param UserGroupHandler $userGroupHandler
63 + * @param AccessHandler $accessHandler
64 + */
35 65 public function __construct(
36 66 Php $php,
37 67 Wordpress $wordpress,
38 68 WordpressConfig $wordpressConfig,
39 69 MainConfig $mainConfig,
70 + Database $database,
40 71 Util $util,
41 72 ObjectHandler $objectHandler,
42 73 UserHandler $userHandler,
43 74 UserGroupHandler $userGroupHandler,
44 - AccessHandler $accessHandler,
45 - private Database $database
75 + AccessHandler $accessHandler
46 76 ) {
47 77 parent::__construct(
48 78 $php,
49 79 $wordpress,
@@ -54,40 +84,42 @@
54 84 $userHandler,
55 85 $userGroupHandler,
56 86 $accessHandler
57 87 );
88 + $this->database = $database;
89 + }
58 90
59 - $this->posts = new WeakMap();
60 - }
61 91
62 - public function getWordpressFilters(): array
63 - {
64 - return $this->wordpressFilters;
65 - }
66 92
67 - private function filtersSuppressed(WP_Query $wpQuery): bool
93 + /**
94 + * Returns true if the filters are suppressed.
95 + *
96 + * @param \WP_Query $wpQuery
97 + *
98 + * @return bool
99 + */
100 + private function filtersSuppressed($wpQuery)
68 101 {
69 102 return isset($wpQuery->query_vars['suppress_filters']) === true
70 103 && $wpQuery->query_vars['suppress_filters'] === true;
71 104 }
72 105
73 - private function addExcludedPosts(mixed $postsNotIn, array $excludedPosts): array
74 - {
75 - return array_unique(array_merge((array) $postsNotIn, $excludedPosts));
76 - }
77 -
78 106 /**
79 - * @throws UserGroupTypeException
107 + * Manipulates the wordpress query object to filter content.
108 + *
109 + * @param \WP_Query $wpQuery The wordpress query object.
80 110 */
81 - public function parseQuery(WP_Query $wpQuery): void
111 + public function parseQuery($wpQuery)
82 112 {
83 113 if ($this->filtersSuppressed($wpQuery) === true) {
84 114 $excludedPosts = $this->accessHandler->getExcludedPosts();
85 115
86 116 if ($excludedPosts !== []) {
87 - $wpQuery->query_vars['post__not_in'] = $this->addExcludedPosts(
88 - $wpQuery->query_vars['post__not_in'] ?? [],
89 - $excludedPosts
117 + $postsNotIn = (isset($wpQuery->query_vars['post__not_in']) === true) ?
118 + $wpQuery->query_vars['post__not_in'] : [];
119 +
120 + $wpQuery->query_vars['post__not_in'] = array_unique(
121 + array_merge($postsNotIn, $excludedPosts)
90 122 );
91 123 }
92 124 }
93 125 }
@@ -92,11 +124,15 @@
92 124 }
93 125 }
94 126
95 127 /**
96 - * @param WP_Hook[] $filters
128 + * Extracts the user access manager filters and returns true if it was successful.
129 + *
130 + * @param \WP_Hook[] $filters
131 + *
132 + * @return bool
97 133 */
98 - private function extractOwnFilters(array $filters): bool
134 + private function extractOwnFilters(array &$filters)
99 135 {
100 136 if (isset($filters['the_posts']->callbacks[10]) === true) {
101 137 foreach ($filters['the_posts']->callbacks[10] as $postFilter) {
102 138 if (is_array($postFilter['function']) === true
@@ -112,9 +148,19 @@
112 148
113 149 return false;
114 150 }
115 151
116 - public function postsPreQuery(?array $posts, WP_Query $query): ?array
152 + /**
153 + * If filters are suppressed we still want to filter posts, so we have to turn the suppression off,
154 + * remove all other filters than the ones from the user access manager and store them to restore
155 + * them later.
156 + *
157 + * @param array $posts
158 + * @param \WP_Query $query
159 + *
160 + * @return mixed
161 + */
162 + public function postsPreQuery($posts, \WP_Query $query)
117 163 {
118 164 if ($this->filtersSuppressed($query) === true) {
119 165 $filters = $this->wordpress->getFilters();
120 166
@@ -133,9 +179,12 @@
133 179
134 180 return $posts;
135 181 }
136 182
137 - private function restoreFilters(): void
183 + /**
184 + * Restores the filters to normal.
185 + */
186 + private function restoreFilters()
138 187 {
139 188 if (count($this->wordpressFilters) > 0) {
140 189 $filters = $this->wordpress->getFilters();
141 190
@@ -147,11 +196,18 @@
147 196 $this->wordpressFilters = [];
148 197 }
149 198 }
150 199
151 - private function getPost(mixed $post): bool|WP_Post
200 + /**
201 + * Tries to get the post from the given mixed data.
202 + *
203 + * @param mixed $post
204 + *
205 + * @return false|\WP_Post
206 + */
207 + private function getPost($post)
152 208 {
153 - if ($post instanceof WP_post) {
209 + if ($post instanceof \WP_post) {
154 210 return $post;
155 211 } elseif (is_int($post) === true) {
156 212 return $this->objectHandler->getPost($post);
157 213 } elseif (isset($post->ID) === true) {
@@ -160,9 +216,16 @@
160 216
161 217 return false;
162 218 }
163 219
164 - private function processPostContent(WP_Post $post): string
220 + /**
221 + * Processes the post content and searches for the more tag.
222 + *
223 + * @param \WP_Post $post
224 + *
225 + * @return string
226 + */
227 + private function processPostContent(\WP_Post $post)
165 228 {
166 229 $uamPostContent = htmlspecialchars_decode($this->mainConfig->getPostTypeContent($post->post_type));
167 230
168 231 if ($this->mainConfig->showPostTypeContentBeforeMore($post->post_type) === true
@@ -167,9 +230,9 @@
167 230
168 231 if ($this->mainConfig->showPostTypeContentBeforeMore($post->post_type) === true
169 232 && preg_match('/<!--more(.*?)?-->/', $post->post_content, $matches)
170 233 ) {
171 - $uamPostContent = explode($matches[0], $post->post_content)[0] . ' ' . $uamPostContent;
234 + $uamPostContent = explode($matches[0], $post->post_content)[0].' '.$uamPostContent;
172 235 }
173 236
174 237 return stripslashes($uamPostContent);
175 238 }
@@ -174,17 +237,21 @@
174 237 return stripslashes($uamPostContent);
175 238 }
176 239
177 240 /**
178 - * @throws UserGroupTypeException
241 + * Modifies the content of the post by the given settings.
242 + *
243 + * @param \WP_Post $post The current post.
244 + *
245 + * @return null|\WP_Post
179 246 */
180 - private function processPost(WP_Post $post): WP_Post|bool
247 + private function processPost(\WP_Post $post)
181 248 {
182 249 $post->post_title .= $this->adminOutput($post->post_type, $post->ID);
183 250
184 251 if ($this->accessHandler->checkObjectAccess($post->post_type, $post->ID) === false) {
185 252 if ($this->removePostFromList($post->post_type) === true) {
186 - return false;
253 + return null;
187 254 }
188 255
189 256 $post->post_content = $this->processPostContent($post);
190 257
@@ -200,21 +267,16 @@
200 267 return $post;
201 268 }
202 269
203 270 /**
204 - * @throws UserGroupTypeException
271 + * Filters the raw posts.
272 + *
273 + * @param array $rawPosts
274 + *
275 + * @return array
205 276 */
206 - private function getProcessedPost(WP_Post $post): ?WP_Post
277 + private function filterRawPosts(array $rawPosts)
207 278 {
208 - $post = $this->posts[$post] ??= $this->processPost($post);
209 - return $post === false ? null : $post;
210 - }
211 -
212 - /**
213 - * @throws UserGroupTypeException
214 - */
215 - private function filterRawPosts(array $rawPosts): array
216 - {
217 279 $filteredPosts = [];
218 280
219 281 foreach ($rawPosts as $rawPost) {
220 282 $post = $this->getPost($rawPost);
@@ -219,9 +281,9 @@
219 281 foreach ($rawPosts as $rawPost) {
220 282 $post = $this->getPost($rawPost);
221 283
222 284 if ($post !== false) {
223 - $post = $this->getProcessedPost($post);
285 + $post = $this->processPost($post);
224 286
225 287 if ($post !== null) {
226 288 $filteredPosts[] = $post;
227 289 }
@@ -233,14 +295,18 @@
233 295 return $filteredPosts;
234 296 }
235 297
236 298 /**
237 - * @throws UserGroupTypeException
299 + * The function for the the_posts filter.
300 + *
301 + * @param array $showPosts The posts.
302 + *
303 + * @return array
238 304 */
239 - public function showPosts(?array $showPosts = []): ?array
305 + public function showPosts($showPosts = [])
240 306 {
241 307 if ($this->wordpress->isFeed() === false || $this->mainConfig->protectFeed() === true) {
242 - $showPosts = $this->filterRawPosts((array) $showPosts);
308 + $showPosts = $this->filterRawPosts($showPosts);
243 309 }
244 310
245 311 $this->restoreFilters();
246 312
@@ -247,108 +313,32 @@
247 313 return $showPosts;
248 314 }
249 315
250 316 /**
251 - * @param WP_Post[] $rawPages The pages.
252 - * @throws UserGroupTypeException
317 + * The function for the get_pages filter.
318 + *
319 + * @param \WP_Post[] $rawPages The pages.
320 + *
321 + * @return array
253 322 */
254 - public function showPages(array $rawPages = []): array
323 + public function showPages($rawPages = [])
255 324 {
256 325 return $this->filterRawPosts($rawPages);
257 326 }
258 327
259 - private function isSingleObjectRestRequest(mixed $request, WP_Post $post): bool
260 - {
261 - return $request instanceof WP_REST_Request
262 - && $request->get_param('id') !== null
263 - && (int) $request->get_param('id') === (int) $post->ID;
264 - }
265 -
266 - private function setRestField(array &$data, string $field, string $value): void
267 - {
268 - if (array_key_exists($field, $data) === false) {
269 - return;
270 - }
271 -
272 - if (is_array($data[$field]) === true) {
273 - if (array_key_exists('rendered', $data[$field]) === true) {
274 - $data[$field]['rendered'] = $value;
275 - }
276 -
277 - if (array_key_exists('raw', $data[$field]) === true) {
278 - $data[$field]['raw'] = $value;
279 - }
280 -
281 - if (array_key_exists('protected', $data[$field]) === true) {
282 - $data[$field]['protected'] = false;
283 - }
284 - } else {
285 - $data[$field] = $value;
286 - }
287 - }
288 -
289 328 /**
290 - * The_posts / posts_where_paged never run for REST single-item requests,
291 - * which resolve through get_post() directly, so access is enforced here too.
329 + * Checks the access of the attached file.
292 330 *
293 - * @throws UserGroupTypeException
331 + * @param string $file
332 + * @param int $attachmentId
333 + *
334 + * @return string|false
294 335 */
295 - public function restrictRestResponse(mixed $response, mixed $post = null, mixed $request = null): mixed
336 + public function getAttachedFile($file, $attachmentId)
296 337 {
297 - if (($response instanceof WP_REST_Response) === false
298 - || ($post instanceof WP_Post) === false
299 - || $this->accessHandler->checkObjectAccess($post->post_type, $post->ID) === true
300 - ) {
301 - return $response;
302 - }
303 -
304 - if ($this->removePostFromList($post->post_type) === true
305 - && $this->isSingleObjectRestRequest($request, $post) === true
306 - ) {
307 - return $this->wordpress->getWpError(
308 - 'uam_rest_access_denied',
309 - TXT_UAM_REST_ACCESS_DENIED,
310 - ['status' => $this->wordpress->isUserLoggedIn() === true ? 403 : 401]
311 - );
312 - }
313 -
314 - $restrictedContent = $this->processPostContent($post);
315 - $data = (array) $response->get_data();
316 -
317 - $this->setRestField($data, 'content', $restrictedContent);
318 - $this->setRestField($data, 'excerpt', $restrictedContent);
319 -
320 - if ($this->mainConfig->hidePostTypeTitle($post->post_type) === true) {
321 - $this->setRestField($data, 'title', $this->mainConfig->getPostTypeTitle($post->post_type));
322 - }
323 -
324 - $response->set_data($data);
325 -
326 - return $response;
327 - }
328 -
329 - /**
330 - * @throws UserGroupTypeException
331 - */
332 - public function excludeRestrictedPostsFromRestQuery(array $queryArgs): array
333 - {
334 - $excludedPosts = $this->accessHandler->getExcludedPosts();
335 -
336 - if ($excludedPosts !== []) {
337 - $queryArgs['post__not_in'] = $this->addExcludedPosts($queryArgs['post__not_in'] ?? [], $excludedPosts);
338 - }
339 -
340 - return $queryArgs;
341 - }
342 -
343 - /**
344 - * @throws UserGroupTypeException
345 - */
346 - public function getAttachedFile(string $file, int|string|null $attachmentId): bool|string
347 - {
348 338 $isImage = (bool) preg_match('/(?i)\.(jpg|jpeg|jpe|png|gif)$/', $file);
349 339
350 - if ($isImage === false && $this->mainConfig->lockFile() === true) {
340 + if ($this->mainConfig->lockFile() === true && $isImage === false) {
351 341 $hasAccess = $this->accessHandler->checkObjectAccess(ObjectHandler::ATTACHMENT_OBJECT_TYPE, $attachmentId);
352 342 return ($hasAccess === true) ? $file : false;
353 343 }
354 344
@@ -355,17 +345,22 @@
355 345 return $file;
356 346 }
357 347
358 348 /**
359 - * @throws UserGroupTypeException
349 + * Adds the excluded posts filter to the given query.
350 + *
351 + * @param string $query
352 + * @param string $table
353 + *
354 + * @return string
360 355 */
361 - private function addQueryExcludedPostFilter(string $query, string $table): string
356 + private function addQueryExcludedPostFilter($query, $table)
362 357 {
363 358 $excludedPosts = $this->accessHandler->getExcludedPosts();
364 359
365 360 if ($excludedPosts !== []) {
366 - $excludedPostsStr = implode(', ', array_map('intval', $excludedPosts));
367 - $query .= " AND $table.ID NOT IN ($excludedPostsStr) ";
361 + $excludedPostsStr = implode(', ', $excludedPosts);
362 + $query .= " AND {$table}.ID NOT IN ($excludedPostsStr) ";
368 363 }
369 364
370 365 return $query;
371 366 }
@@ -370,30 +365,48 @@
370 365 return $query;
371 366 }
372 367
373 368 /**
374 - * @throws UserGroupTypeException
369 + * The function for the posts_where_paged filter.
370 + *
371 + * @param string $query The where sql statement.
372 + *
373 + * @return string
375 374 */
376 - public function showPostSql(string $query): string
375 + public function showPostSql($query)
377 376 {
378 377 return $this->addQueryExcludedPostFilter($query, $this->database->getPostsTable());
379 378 }
380 379
381 380 /**
382 - * @throws UserGroupTypeException
381 + * The function for the get_previous_post_where and
382 + * the get_next_post_where filter.
383 + *
384 + * @param string $query The current sql string.
385 + *
386 + * @return string
383 387 */
384 - public function showNextPreviousPost(string $query): string
388 + public function showNextPreviousPost($query)
385 389 {
386 390 return $this->addQueryExcludedPostFilter($query, 'p');
387 391 }
388 392
389 - private function getPostCountQuery(array $excludedPosts, string $type, string $perm): string
393 + /**
394 + * Returns the post count query.
395 + *
396 + * @param array $excludedPosts
397 + * @param string $type
398 + * @param string $perm
399 + *
400 + * @return string
401 + */
402 + private function getPostCountQuery(array $excludedPosts, $type, $perm)
390 403 {
391 - $excludedPosts = implode(', ', array_map('intval', $excludedPosts));
392 - $query = "SELECT post_status, COUNT(*) AS num_posts
393 - FROM {$this->database->getPostsTable()}
404 + $excludedPosts = implode('\', \'', $excludedPosts);
405 + $query = "SELECT post_status, COUNT(*) AS num_posts
406 + FROM {$this->database->getPostsTable()}
394 407 WHERE post_type = %s
395 - AND ID NOT IN ($excludedPosts)";
408 + AND ID NOT IN ('{$excludedPosts}')";
396 409
397 410 if ('readable' === $perm
398 411 && $this->wordpress->isUserLoggedIn() === true
399 412 && $this->wordpress->currentUserCan(
@@ -410,11 +423,17 @@
410 423 return $query;
411 424 }
412 425
413 426 /**
414 - * @throws UserGroupTypeException
427 + * Function for the wp_count_posts filter.
428 + *
429 + * @param \stdClass $counts
430 + * @param string $type
431 + * @param string $perm
432 + *
433 + * @return \stdClass
415 434 */
416 - public function showPostCount(stdClass $counts, string $type, string $perm): stdClass
435 + public function showPostCount($counts, $type, $perm)
417 436 {
418 437 if (isset($this->cachedCounts[$type]) === false) {
419 438 $excludedPosts = $this->accessHandler->getExcludedPosts();
420 439
@@ -419,9 +438,9 @@
419 438 $excludedPosts = $this->accessHandler->getExcludedPosts();
420 439
421 440 if ($excludedPosts !== []) {
422 441 $query = $this->getPostCountQuery($excludedPosts, $type, $perm);
423 - $results = (array) $this->database->getResults(
442 + $results = (array)$this->database->getResults(
424 443 $this->database->prepare($query, $type),
425 444 ARRAY_A
426 445 );
427 446
@@ -437,9 +456,16 @@
437 456
438 457 return $this->cachedCounts[$type];
439 458 }
440 459
441 - private function hidePostComment(string $postType): bool
460 + /**
461 + * Checks if the post comment should be completely hidden.
462 + *
463 + * @param string $postType
464 + *
465 + * @return bool
466 + */
467 + private function hidePostComment($postType)
442 468 {
443 469 return $this->mainConfig->lockPostTypeComments($postType) === true
444 470 || $this->mainConfig->hidePostType($postType) === true
445 471 || $this->wordpressConfig->atAdminPanel() === true;
@@ -445,12 +471,15 @@
445 471 || $this->wordpressConfig->atAdminPanel() === true;
446 472 }
447 473
448 474 /**
449 - * @param WP_Comment[] $comments The comments.
450 - * @throws UserGroupTypeException
475 + * The function for the comments_array filter.
476 + *
477 + * @param \WP_Comment[] $comments The comments.
478 + *
479 + * @return array
451 480 */
452 - public function showComment(array $comments = []): array
481 + public function showComment($comments = [])
453 482 {
454 483 $showComments = [];
455 484
456 485 foreach ($comments as $comment) {
@@ -474,11 +503,16 @@
474 503 return $showComments;
475 504 }
476 505
477 506 /**
478 - * @throws UserGroupTypeException
507 + * The function for the edit_post_link filter.
508 + *
509 + * @param string $link The edit link.
510 + * @param integer $postId The _iId of the post.
511 + *
512 + * @return string
479 513 */
480 - public function showEditLink(?string $link, int|string|null $postId): string
514 + public function showEditLink($link, $postId)
481 515 {
482 516 if ($this->mainConfig->hideEditLinkOnNoAccess() === true
483 517 && $this->accessHandler->checkObjectAccess(ObjectHandler::GENERAL_POST_OBJECT_TYPE, $postId, true) === false
484 518 ) {
@@ -499,11 +533,11 @@
499 533 $userGroups
500 534 );
501 535
502 536 $link .= $link !== '' ? ' | ' : ' ';
503 - $link .= TXT_UAM_ASSIGNED_GROUPS . ': ' . implode(', ', $escapedGroups);
537 + $link .= TXT_UAM_ASSIGNED_GROUPS.': '.implode(', ', $escapedGroups);
504 538 }
505 539 }
506 540
507 - return (string) $link;
541 + return $link;
508 542 }
509 543 }