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