1<?php
2
3use ComboStrap\LogUtility;
4use ComboStrap\Message;
5use ComboStrap\PagesIndex;
6use dokuwiki\Extension\ActionPlugin;
7
8if (!defined('DOKU_INC')) die();
9if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/');
10
11
12require_once(__DIR__ . '/../ComboStrap/PageRules.php');
13require_once(__DIR__ . '/../ComboStrap/Page.php');
14require_once(__DIR__ . '/urlmanager.php');
15require_once(__DIR__ . '/../ComboStrap/Message.php');
16
17/**
18 *
19 * To show a message after redirection or rewriting
20 *
21 *
22 *
23 */
24class action_plugin_combo_urlmessage extends ActionPlugin
25{
26
27    // a class can not start with a number then webcomponent is not a valid class name
28    const REDIRECT_MANAGER_BOX_CLASS = "redirect-manager";
29
30    // Property key
31    const ORIGIN_PAGE = 'redirectId';
32    const ORIGIN_TYPE = 'redirectOrigin';
33    const CONF_SHOW_PAGE_NAME_IS_NOT_UNIQUE = 'ShowPageNameIsNotUnique';
34
35    function __construct()
36    {
37        // enable direct access to language strings
38        // ie $this->lang
39        $this->setupLocale();
40    }
41
42    /**
43     *
44     * Return the message properties from a query string
45     *
46     * An internal HTTP redirect pass them via query string
47     */
48    private static function getMessageQueryStringProperties()
49    {
50
51        $returnValues = array();
52
53        global $INPUT;
54        $origin = $INPUT->str(self::ORIGIN_PAGE, null);
55        if ($origin != null) {
56            $returnValues = array(
57                $origin,
58                $INPUT->str(self::ORIGIN_TYPE, null)
59            );
60        }
61        return $returnValues;
62
63    }
64
65
66    function register(Doku_Event_Handler $controller)
67    {
68
69        /* This will call the function _displayRedirectMessage */
70        $controller->register_hook(
71            'TPL_ACT_RENDER',
72            'BEFORE',
73            $this,
74            '_displayRedirectMessage',
75            array()
76        );
77
78
79    }
80
81
82    /**
83     * Main function; dispatches the visual comment actions
84     * @param   $event Doku_Event
85     */
86    function _displayRedirectMessage(&$event, $param)
87    {
88
89
90        // Message
91        $message = new Message($this);
92        $message->setClass(action_plugin_combo_urlmessage::REDIRECT_MANAGER_BOX_CLASS);
93        $message->setSignatureCanonical(action_plugin_combo_urlmanager::CANONICAL);
94        $message->setSignatureName("Url Manager");
95
96        $pageIdOrigin = null;
97        $redirectSource = null;
98        $messageSessionProperties = self::getMessageSessionProperties();
99        if (!empty($messageSessionProperties)) {
100            list($pageIdOrigin, $redirectSource) = $messageSessionProperties;
101        } else {
102            $messageQueryStringProperties = self::getMessageQueryStringProperties();
103            if(!empty($messageQueryStringProperties)) {
104                list($pageIdOrigin, $redirectSource) = $messageQueryStringProperties;
105            }
106        }
107
108
109        // Are we a test call
110        // The redirection does not exist the process otherwise the test fails
111        global $ID;
112        if ($ID == $pageIdOrigin && action_plugin_combo_urlmanager::GO_TO_EDIT_MODE != $redirectSource) {
113            return;
114        }
115
116        if ($pageIdOrigin) {
117
118            switch ($redirectSource) {
119
120                case action_plugin_combo_urlmanager::TARGET_ORIGIN_PAGE_RULES:
121                    $message->addContent(sprintf($this->getLang('message_redirected_by_redirect'), hsc($pageIdOrigin)));
122                    $message->setType(Message::TYPE_CLASSIC);
123                    break;
124
125                case action_plugin_combo_urlmanager::TARGET_ORIGIN_START_PAGE:
126                    $message->addContent(sprintf($this->lang['message_redirected_to_startpage'], hsc($pageIdOrigin)));
127                    $message->setType(Message::TYPE_WARNING);
128                    break;
129
130                case  action_plugin_combo_urlmanager::TARGET_ORIGIN_BEST_PAGE_NAME:
131                    $message->addContent(sprintf($this->lang['message_redirected_to_bestpagename'], hsc($pageIdOrigin)));
132                    $message->setType(Message::TYPE_WARNING);
133                    break;
134
135                case action_plugin_combo_urlmanager::TARGET_ORIGIN_BEST_NAMESPACE:
136                    $message->addContent(sprintf($this->lang['message_redirected_to_bestnamespace'], hsc($pageIdOrigin)));
137                    $message->setType(Message::TYPE_WARNING);
138                    break;
139
140                case action_plugin_combo_urlmanager::TARGET_ORIGIN_SEARCH_ENGINE:
141                    $message->addContent(sprintf($this->lang['message_redirected_to_searchengine'], hsc($pageIdOrigin)));
142                    $message->setType(Message::TYPE_WARNING);
143                    break;
144
145                case action_plugin_combo_urlmanager::GO_TO_EDIT_MODE:
146                    $message->addContent($this->lang['message_redirected_to_edit_mode']);
147                    $message->setType(Message::TYPE_CLASSIC);
148                    break;
149
150            }
151
152            // Add a list of page with the same name to the message
153            // if the redirections is not planned
154            if ($redirectSource != action_plugin_combo_urlmanager::TARGET_ORIGIN_PAGE_RULES) {
155                $this->addToMessagePagesWithSameName($message, $pageIdOrigin);
156            }
157
158        }
159
160        if ($event->data == 'show' || $event->data == 'edit' || $event->data == 'search') {
161
162            ptln($message->toHtml());
163
164        }
165
166    }
167
168
169    /**
170     * Add the page with the same page name but in an other location
171     * @param $message
172     * @param $pageId
173     */
174    function addToMessagePagesWithSameName($message, $pageId)
175    {
176
177        if ($this->getConf(self::CONF_SHOW_PAGE_NAME_IS_NOT_UNIQUE) == 1) {
178
179            global $ID;
180            // The page name
181            $pageName = noNS($pageId);
182            $pagesWithSameName = PagesIndex::pagesWithSameName($pageName, $ID);
183
184            if (count($pagesWithSameName) > 0) {
185
186                $message->setType(Message::TYPE_WARNING);
187
188                // Assign the value to a variable to be able to use the construct .=
189                if ($message->getContent() <> '') {
190                    $message->addContent('<br/><br/>');
191                }
192                $message->addContent($this->lang['message_pagename_exist_one']);
193                $message->addContent('<ul>');
194
195                $i = 0;
196                foreach ($pagesWithSameName as $PageId => $title) {
197                    $i++;
198                    if ($i > 10) {
199                        $message->addContent('<li>' .
200                            tpl_link(
201                                wl($pageId) . "?do=search&q=" . rawurldecode($pageName),
202                                "More ...",
203                                'class="" rel="nofollow" title="More..."',
204                                $return = true
205                            ) . '</li>');
206                        break;
207                    }
208                    if ($title == null) {
209                        $title = $PageId;
210                    }
211                    $message->addContent('<li>' .
212                        tpl_link(
213                            wl($PageId),
214                            $title,
215                            'class="" rel="nofollow" title="' . $title . '"',
216                            $return = true
217                        ) . '</li>');
218                }
219                $message->addContent('</ul>');
220            }
221        }
222    }
223
224
225    /**
226     * Set the redirect in a session that will be be read after the redirect
227     * in order to show a message to the user
228     * @param string $id
229     * @param string $redirectSource
230     */
231    static function notify($id, $redirectSource)
232    {
233        // Msg via session
234        if (!defined('NOSESSION')) {
235            //reopen session, store data and close session again
236            self::sessionStart();
237            $_SESSION[DOKU_COOKIE][self::ORIGIN_PAGE] = $id;
238            $_SESSION[DOKU_COOKIE][self::ORIGIN_TYPE] = $redirectSource;
239            self::sessionClose();
240
241        }
242    }
243
244    /**
245     * You can't unset when rendering because the write
246     * of a session may fail because some data may have already been send
247     * during the rendering process
248     * Unset is done at the start of the 404 manager
249     */
250    static function unsetNotification()
251    {
252
253        // Open session
254        self::sessionStart();
255
256        // Read the data and unset
257        if (isset($_SESSION[DOKU_COOKIE][self::ORIGIN_PAGE])) {
258            unset($_SESSION[DOKU_COOKIE][self::ORIGIN_PAGE]);
259        }
260        if (isset($_SESSION[DOKU_COOKIE][self::ORIGIN_TYPE])) {
261            unset($_SESSION[DOKU_COOKIE][self::ORIGIN_TYPE]);
262        }
263    }
264
265    /**
266     * Return notification data or an empty array
267     * @return array - of the source id and of the type of redirect if a redirect has occurs otherwise an empty array
268     */
269    static function getMessageSessionProperties()
270    {
271        $returnArray = array();
272        if (!defined('NOSESSION')) {
273
274            $pageIdOrigin = null;
275            $redirectSource = null;
276
277            // Read the data and unset
278            if (isset($_SESSION[DOKU_COOKIE][self::ORIGIN_PAGE])) {
279                $pageIdOrigin = $_SESSION[DOKU_COOKIE][self::ORIGIN_PAGE];
280            }
281            if (isset($_SESSION[DOKU_COOKIE][self::ORIGIN_TYPE])) {
282                $redirectSource = $_SESSION[DOKU_COOKIE][self::ORIGIN_TYPE];
283            }
284
285
286            if ($pageIdOrigin) {
287                $returnArray = array($pageIdOrigin, $redirectSource);
288            }
289
290        }
291        return $returnArray;
292
293    }
294
295    private static function sessionStart()
296    {
297        $sessionStatus = session_status();
298        switch ($sessionStatus) {
299            case PHP_SESSION_DISABLED:
300                throw new RuntimeException("Sessions are disabled");
301                break;
302            case PHP_SESSION_NONE:
303                $result = @session_start();
304                if (!$result) {
305                    throw new RuntimeException("The session was not successfully started");
306                }
307                break;
308            case PHP_SESSION_ACTIVE:
309                break;
310        }
311    }
312
313    private static function sessionClose()
314    {
315        // Close the session
316        $phpVersion =  phpversion();
317        if ($phpVersion>"7.2.0") {
318            /** @noinspection PhpVoidFunctionResultUsedInspection */
319            $result = session_write_close();
320            if (!$result) {
321                // Session is really not a well known mechanism
322                // Set this error in a info level to not fail the test
323                LogUtility::msg("Failure to write the session", LogUtility::LVL_MSG_INFO);
324            }
325        } else {
326            session_write_close();
327        }
328
329    }
330
331}
332