xref: /plugin/deletepageguard/admin.php (revision 1a97af9eab9d5c777e1efac4ced808b8ed81e4af)
1*1a97af9eSJohann Duscher<?php
2*1a97af9eSJohann Duscher/**
3*1a97af9eSJohann Duscher * Admin interface for Delete Page Guard pattern validation
4*1a97af9eSJohann Duscher *
5*1a97af9eSJohann Duscher * @license GPL 2 (https://www.gnu.org/licenses/gpl-2.0.html) - see LICENSE.md
6*1a97af9eSJohann Duscher * @author  Johann Duscher <jonny.dee@posteo.net>
7*1a97af9eSJohann Duscher * @copyright 2025 Johann Duscher
8*1a97af9eSJohann Duscher */
9*1a97af9eSJohann Duscher
10*1a97af9eSJohann Duscheruse dokuwiki\Extension\AdminPlugin;
11*1a97af9eSJohann Duscher
12*1a97af9eSJohann Duscher// Protect against direct call
13*1a97af9eSJohann Duscherif (!defined('DOKU_INC')) die();
14*1a97af9eSJohann Duscher
15*1a97af9eSJohann Duscher/**
16*1a97af9eSJohann Duscher * Class admin_plugin_deletepageguard
17*1a97af9eSJohann Duscher *
18*1a97af9eSJohann Duscher * Provides an admin interface for validating Delete Page Guard patterns
19*1a97af9eSJohann Duscher * and offering configuration guidance to administrators.
20*1a97af9eSJohann Duscher */
21*1a97af9eSJohann Duscherclass admin_plugin_deletepageguard extends AdminPlugin {
22*1a97af9eSJohann Duscher
23*1a97af9eSJohann Duscher    /**
24*1a97af9eSJohann Duscher     * Return sort order for position in admin menu
25*1a97af9eSJohann Duscher     * @return int
26*1a97af9eSJohann Duscher     */
27*1a97af9eSJohann Duscher    public function getMenuSort() {
28*1a97af9eSJohann Duscher        return 200;
29*1a97af9eSJohann Duscher    }
30*1a97af9eSJohann Duscher
31*1a97af9eSJohann Duscher    /**
32*1a97af9eSJohann Duscher     * Return true if access to this admin plugin is allowed
33*1a97af9eSJohann Duscher     * @return bool
34*1a97af9eSJohann Duscher     */
35*1a97af9eSJohann Duscher    public function forAdminOnly() {
36*1a97af9eSJohann Duscher        return true;
37*1a97af9eSJohann Duscher    }
38*1a97af9eSJohann Duscher
39*1a97af9eSJohann Duscher    /**
40*1a97af9eSJohann Duscher     * Handle user request
41*1a97af9eSJohann Duscher     * @return void
42*1a97af9eSJohann Duscher     */
43*1a97af9eSJohann Duscher    public function handle() {
44*1a97af9eSJohann Duscher        if (isset($_POST['validate_patterns'])) {
45*1a97af9eSJohann Duscher            $this->validatePatternsFromPost();
46*1a97af9eSJohann Duscher        }
47*1a97af9eSJohann Duscher    }
48*1a97af9eSJohann Duscher
49*1a97af9eSJohann Duscher    /**
50*1a97af9eSJohann Duscher     * Render HTML output
51*1a97af9eSJohann Duscher     * @return void
52*1a97af9eSJohann Duscher     */
53*1a97af9eSJohann Duscher    public function html() {
54*1a97af9eSJohann Duscher        echo '<h1>' . $this->getLang('admin_title') . '</h1>';
55*1a97af9eSJohann Duscher        echo '<div class="level1">';
56*1a97af9eSJohann Duscher
57*1a97af9eSJohann Duscher        // Show current patterns and validation results
58*1a97af9eSJohann Duscher        $patterns = $this->getConf('patterns');
59*1a97af9eSJohann Duscher        $this->showPatternValidation($patterns);
60*1a97af9eSJohann Duscher
61*1a97af9eSJohann Duscher        // Add validation form
62*1a97af9eSJohann Duscher        echo '<h2>' . $this->getLang('test_patterns_title') . '</h2>';
63*1a97af9eSJohann Duscher        echo '<form method="post" accept-charset="utf-8">';
64*1a97af9eSJohann Duscher        echo '<p>' . $this->getLang('test_patterns_help') . '</p>';
65*1a97af9eSJohann Duscher        echo '<textarea name="test_patterns" rows="10" cols="80" class="edit">' . hsc($patterns) . '</textarea><br>';
66*1a97af9eSJohann Duscher        echo '<input type="submit" name="validate_patterns" value="' . $this->getLang('validate_button') . '" class="button">';
67*1a97af9eSJohann Duscher        echo '</form>';
68*1a97af9eSJohann Duscher
69*1a97af9eSJohann Duscher        echo '</div>';
70*1a97af9eSJohann Duscher    }
71*1a97af9eSJohann Duscher
72*1a97af9eSJohann Duscher    /**
73*1a97af9eSJohann Duscher     * Validate patterns from POST data
74*1a97af9eSJohann Duscher     * @return void
75*1a97af9eSJohann Duscher     */
76*1a97af9eSJohann Duscher    private function validatePatternsFromPost() {
77*1a97af9eSJohann Duscher        $patterns = $_POST['test_patterns'] ?? '';
78*1a97af9eSJohann Duscher        echo '<h2>' . $this->getLang('validation_results_title') . '</h2>';
79*1a97af9eSJohann Duscher        $this->showPatternValidation($patterns);
80*1a97af9eSJohann Duscher    }
81*1a97af9eSJohann Duscher
82*1a97af9eSJohann Duscher    /**
83*1a97af9eSJohann Duscher     * Display pattern validation results
84*1a97af9eSJohann Duscher     * @param string $patterns The patterns to validate
85*1a97af9eSJohann Duscher     * @return void
86*1a97af9eSJohann Duscher     */
87*1a97af9eSJohann Duscher    private function showPatternValidation($patterns) {
88*1a97af9eSJohann Duscher        if (empty(trim($patterns))) {
89*1a97af9eSJohann Duscher            echo '<div class="info">' . $this->getLang('no_patterns') . '</div>';
90*1a97af9eSJohann Duscher            return;
91*1a97af9eSJohann Duscher        }
92*1a97af9eSJohann Duscher
93*1a97af9eSJohann Duscher        $lines = preg_split('/\R+/', $patterns, -1, PREG_SPLIT_NO_EMPTY);
94*1a97af9eSJohann Duscher        $hasErrors = false;
95*1a97af9eSJohann Duscher        $validCount = 0;
96*1a97af9eSJohann Duscher
97*1a97af9eSJohann Duscher        echo '<div class="level2">';
98*1a97af9eSJohann Duscher        echo '<h3>' . $this->getLang('validation_results') . '</h3>';
99*1a97af9eSJohann Duscher        echo '<ul>';
100*1a97af9eSJohann Duscher
101*1a97af9eSJohann Duscher        foreach ($lines as $i => $line) {
102*1a97af9eSJohann Duscher            $pattern = trim($line);
103*1a97af9eSJohann Duscher            if ($pattern === '') continue;
104*1a97af9eSJohann Duscher
105*1a97af9eSJohann Duscher            $lineNum = $i + 1;
106*1a97af9eSJohann Duscher            $status = $this->validateSinglePattern($pattern);
107*1a97af9eSJohann Duscher
108*1a97af9eSJohann Duscher            if ($status === true) {
109*1a97af9eSJohann Duscher                echo '<li><span style="color: green; font-weight: bold;">✓</span> ';
110*1a97af9eSJohann Duscher                echo '<strong>Line ' . $lineNum . ':</strong> <code>' . hsc($pattern) . '</code></li>';
111*1a97af9eSJohann Duscher                $validCount++;
112*1a97af9eSJohann Duscher            } else {
113*1a97af9eSJohann Duscher                echo '<li><span style="color: red; font-weight: bold;">✗</span> ';
114*1a97af9eSJohann Duscher                echo '<strong>Line ' . $lineNum . ':</strong> <code>' . hsc($pattern) . '</code><br>';
115*1a97af9eSJohann Duscher                echo '&nbsp;&nbsp;&nbsp;<em style="color: red;">' . hsc($status) . '</em></li>';
116*1a97af9eSJohann Duscher                $hasErrors = true;
117*1a97af9eSJohann Duscher            }
118*1a97af9eSJohann Duscher        }
119*1a97af9eSJohann Duscher
120*1a97af9eSJohann Duscher        echo '</ul>';
121*1a97af9eSJohann Duscher
122*1a97af9eSJohann Duscher        if (!$hasErrors && $validCount > 0) {
123*1a97af9eSJohann Duscher            echo '<div class="success">' . sprintf($this->getLang('all_patterns_valid'), $validCount) . '</div>';
124*1a97af9eSJohann Duscher        } elseif ($hasErrors) {
125*1a97af9eSJohann Duscher            echo '<div class="error">' . $this->getLang('some_patterns_invalid') . '</div>';
126*1a97af9eSJohann Duscher        }
127*1a97af9eSJohann Duscher
128*1a97af9eSJohann Duscher        echo '</div>';
129*1a97af9eSJohann Duscher    }
130*1a97af9eSJohann Duscher
131*1a97af9eSJohann Duscher    /**
132*1a97af9eSJohann Duscher     * Validate a single pattern and return detailed error message
133*1a97af9eSJohann Duscher     * @param string $pattern The pattern to validate
134*1a97af9eSJohann Duscher     * @return string|true True if valid, error message if invalid
135*1a97af9eSJohann Duscher     */
136*1a97af9eSJohann Duscher    private function validateSinglePattern($pattern) {
137*1a97af9eSJohann Duscher        // Same validation logic as in action.php but with more detailed messages
138*1a97af9eSJohann Duscher        if (strlen($pattern) > 1000) {
139*1a97af9eSJohann Duscher            return $this->getLang('error_pattern_too_long');
140*1a97af9eSJohann Duscher        }
141*1a97af9eSJohann Duscher
142*1a97af9eSJohann Duscher        if (preg_match('/(\(.*\).*\+.*\(.*\).*\+)|(\(.*\).*\*.*\(.*\).*\*)/', $pattern)) {
143*1a97af9eSJohann Duscher            return $this->getLang('error_pattern_redos');
144*1a97af9eSJohann Duscher        }
145*1a97af9eSJohann Duscher
146*1a97af9eSJohann Duscher        $escapedPattern = '/' . str_replace('/', '\/', $pattern) . '/u';
147*1a97af9eSJohann Duscher        $test = @preg_match($escapedPattern, '');
148*1a97af9eSJohann Duscher        if ($test === false) {
149*1a97af9eSJohann Duscher            $error = error_get_last();
150*1a97af9eSJohann Duscher            $errorMsg = $error && isset($error['message']) ? $error['message'] : 'Unknown error';
151*1a97af9eSJohann Duscher            return $this->getLang('error_pattern_syntax') . ': ' . $errorMsg;
152*1a97af9eSJohann Duscher        }
153*1a97af9eSJohann Duscher
154*1a97af9eSJohann Duscher        return true;
155*1a97af9eSJohann Duscher    }
156*1a97af9eSJohann Duscher}