PluginProbe
404 Solution / trunk
404 Solution vtrunk
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / matching / RedirectCandidateEvaluator.php

RedirectCandidateEvaluator.php in 404 Solution trunk, at includes/matching/RedirectCandidateEvaluator.php

91 lines 3.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) {
4 exit;
5 }
6
7 /**
8 * Decides whether an already-fetched redirect row is actionable. Three checks:
9 * 1. Row well-formed (id != 0, final_dest != 0 unless type=HOME).
10 * 2. Destination not dead -- a bounded on-demand check asks the
11 * redirect_dead_destination_checker whether THIS redirect's destination
12 * shows recent failed hits in the logs_hits rollup.
13 * 3. RedirectConditionEvaluator passes (any per-row conditions like
14 * time-of-day, country, user-agent, referrer rules).
15 *
16 * Records a trace step at each step so the debug interstitial can show why
17 * an existing redirect was skipped.
18 */
19 class ABJ_404_Solution_RedirectCandidateEvaluator {
20
21 /** @var ABJ_404_Solution_RedirectsRepository */
22 private $redirectsRepository;
23
24 /**
25 * @param ABJ_404_Solution_RedirectsRepository $redirectsRepository
26 */
27 function __construct($redirectsRepository) {
28 $this->redirectsRepository = $redirectsRepository;
29 }
30
31 /**
32 * @param array<string, mixed>|null $redirect
33 * @param string $labelSuffix Appended to trace step labels (e.g. ' (without comments)').
34 * @param array<string, mixed> $options
35 * @param ABJ_404_Solution_FrontendPipelineTrace $trace
36 * @return array<string, mixed>|null The redirect row if actionable, null otherwise.
37 */
38 function evaluate(?array $redirect, string $labelSuffix, array $options, ABJ_404_Solution_FrontendPipelineTrace $trace): ?array {
39 if ($redirect === null) {
40 if ($labelSuffix === '') {
41 $trace->add('Redirect lookup', 'No matching redirect');
42 }
43 return null;
44 }
45
46 $typeHomeInt = (int)ABJ404_TYPE_HOME;
47 $redirectType = isset($redirect['type']) && is_scalar($redirect['type']) ? (int)$redirect['type'] : 0;
48
49 if ($redirect['id'] == '0' || ($redirect['final_dest'] == '0' && $redirectType !== $typeHomeInt)) {
50 if ($labelSuffix === '') {
51 $trace->add('Redirect lookup', 'No matching redirect');
52 }
53 return null;
54 }
55
56 $trace->add('Redirect lookup' . $labelSuffix, 'Found existing redirect',
57 'rule #' . (is_scalar($redirect['id']) ? (string)$redirect['id'] : '?'));
58
59 $redirectIdForCheck = is_scalar($redirect['id']) ? (int) $redirect['id'] : 0;
60 $deadIds = abj_service('redirect_dead_destination_checker')->findDeadDestinationIds(array($redirectIdForCheck));
61 if (!empty($deadIds)) {
62 $trace->add('Health check' . $labelSuffix, 'Destination unreachable - skipped');
63 return null;
64 }
65
66 $condEvaluator = new ABJ_404_Solution_RedirectConditionEvaluator($this->redirectsRepository);
67 $redirectIdForCond = is_scalar($redirect['id']) ? (int)$redirect['id'] : 0;
68 if ($condEvaluator->shouldApplyRedirect($redirectIdForCond)) {
69 $trace->add('Conditions' . $labelSuffix, 'All conditions met');
70 return $redirect;
71 }
72
73 $condTrace = $condEvaluator->getLastEvaluationTrace();
74 $condDetail = implode(', ', array_map(function ($c) {
75 $label = str_replace('_', ' ', $c['type']);
76 return $label . ': ' . ($c['result'] ? 'passed' : 'failed');
77 }, $condTrace));
78 $trace->add('Conditions' . $labelSuffix, 'Blocked by conditions', $condDetail);
79 return null;
80 }
81
82 /**
83 * @param array<string, mixed> $redirect
84 * @return bool
85 */
86 function isAutoRedirect(array $redirect): bool {
87 return isset($redirect['status']) && is_scalar($redirect['status']) &&
88 (int)$redirect['status'] === (int)ABJ404_STATUS_AUTO;
89 }
90 }
91