1<?php 2 3require_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 4 5use ComboStrap\ExceptionBadSyntax; 6use ComboStrap\Identity; 7use ComboStrap\Index; 8use ComboStrap\LogUtility; 9use ComboStrap\LinkMarkup; 10use ComboStrap\Message; 11use ComboStrap\MarkupPath; 12use dokuwiki\Extension\ActionPlugin; 13 14 15/** 16 * 17 * To show a message after redirection or rewriting 18 * 19 * 20 * 21 */ 22class action_plugin_combo_routermessage extends ActionPlugin 23{ 24 25 // a class can not start with a number then webcomponent is not a valid class name 26 const REDIRECT_MANAGER_BOX_CLASS = "redirect-manager"; 27 28 // Property key 29 const ORIGIN_PAGE = 'redirectId'; 30 const ORIGIN_TYPE = 'redirectOrigin'; 31 const CONF_SHOW_PAGE_NAME_IS_NOT_UNIQUE = 'ShowPageNameIsNotUnique'; 32 const CONF_SHOW_MESSAGE_CLASSIC = 'ShowMessageClassic'; 33 const CONF_SHOW_MESSAGE_CLASSIC_DEFAULT = 1; 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(): array 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 $pageIdOrigin = null; 90 $redirectSource = null; 91 92 $messageQueryStringProperties = self::getMessageQueryStringProperties(); 93 if (!empty($messageQueryStringProperties)) { 94 list($pageIdOrigin, $redirectSource) = $messageQueryStringProperties; 95 } 96 97 if ($pageIdOrigin) { 98 99 switch ($redirectSource) { 100 101 case action_plugin_combo_router::TARGET_ORIGIN_PAGE_RULES: 102 if (!$this->showMessageIfPublicAndPlanned()) { 103 return; 104 } 105 $message = Message::createInfoMessage() 106 ->addHtmlContent("<p>" . sprintf($this->getLang('message_redirected_by_redirect'), hsc($pageIdOrigin)) . "</p>"); 107 break; 108 109 case action_plugin_combo_router::TARGET_ORIGIN_START_PAGE: 110 $message = Message::createWarningMessage() 111 ->addHtmlContent("<p>" . sprintf($this->lang['message_redirected_to_startpage'], hsc($pageIdOrigin)) . "</p>"); 112 break; 113 case action_plugin_combo_router::TARGET_ORIGIN_BEST_PAGE_NAME: 114 $message = Message::createWarningMessage() 115 ->addHtmlContent("<p>" . sprintf($this->lang['message_redirected_to_bestpagename'], hsc($pageIdOrigin)) . "</p>"); 116 break; 117 case action_plugin_combo_router::TARGET_ORIGIN_BEST_NAMESPACE: 118 $message = Message::createWarningMessage() 119 ->addHtmlContent("<p>" . sprintf($this->lang['message_redirected_to_bestnamespace'], hsc($pageIdOrigin)) . "</p>"); 120 break; 121 122 case action_plugin_combo_router::TARGET_ORIGIN_SEARCH_ENGINE: 123 $message = Message::createWarningMessage() 124 ->addHtmlContent("<p>" . sprintf($this->lang['message_redirected_to_searchengine'], hsc($pageIdOrigin)) . "</p>"); 125 break; 126 127 case action_plugin_combo_router::GO_TO_EDIT_MODE: 128 $message = Message::createInfoMessage() 129 ->addHtmlContent("<p>" . $this->lang['message_redirected_to_edit_mode'] . "</p>"); 130 break; 131 case action_plugin_combo_router::TARGET_ORIGIN_PERMALINK_EXTENDED: 132 case action_plugin_combo_router::TARGET_ORIGIN_PERMALINK: 133 $message = Message::createInfoMessage() 134 ->addHtmlContent("<p>" . $this->lang['message_redirected_from_permalink'] . "</p>"); 135 break; 136 case action_plugin_combo_router::TARGET_ORIGIN_CANONICAL: 137 if (!$this->showMessageIfPublicAndPlanned()) { 138 return; 139 } 140 $message = Message::createInfoMessage() 141 ->addHtmlContent("<p>" . $this->lang['message_redirected_from_canonical'] . "</p>"); 142 break; 143 default: 144 LogUtility::msg("The redirection source ($redirectSource) is unknown. It was not expected", LogUtility::LVL_MSG_ERROR, action_plugin_combo_router::CANONICAL); 145 return; 146 147 } 148 149 150 // Add a list of page with the same name to the message 151 // if the redirections is not planned 152 if ($redirectSource != action_plugin_combo_router::TARGET_ORIGIN_PAGE_RULES) { 153 $pageOrigin = MarkupPath::createMarkupFromId($pageIdOrigin); 154 $this->addToMessagePagesWithSameName($message, $pageOrigin); 155 } 156 157 if ($event->data === 'show' || $event->data === 'edit' || $event->data === 'search') { 158 $html = $message 159 ->setPlugin($this) 160 ->setClass(action_plugin_combo_routermessage::REDIRECT_MANAGER_BOX_CLASS) 161 ->setCanonical(action_plugin_combo_router::CANONICAL) 162 ->setSignatureName(action_plugin_combo_router::URL_MANAGER_NAME) 163 ->toHtmlBox(); 164 LogUtility::infoToPublic($html, action_plugin_combo_router::CANONICAL); 165 } 166 167 168 } 169 170 171 } 172 173 174 /** 175 * Add the page with the same page name but in an other location 176 * @param Message $message 177 * @param MarkupPath $pageOrigin 178 */ 179 function addToMessagePagesWithSameName(Message $message, MarkupPath $pageOrigin) 180 { 181 182 if (!$this->getConf(self::CONF_SHOW_PAGE_NAME_IS_NOT_UNIQUE) == 1) { 183 return; 184 } 185 186 global $ID; 187 // The page name 188 $pageName = $pageOrigin->getNameOrDefault(); 189 $pagesWithSameName = Index::getOrCreate()->getPagesWithSameLastName($pageOrigin); 190 191 if (count($pagesWithSameName) === 1) { 192 $page = $pagesWithSameName[0]; 193 if ($page->getWikiId() === $ID) { 194 // the page itself 195 return; 196 } 197 } 198 199 if (count($pagesWithSameName) > 0) { 200 201 $message->setType(Message::TYPE_WARNING); 202 203 // Assign the value to a variable to be able to use the construct .= 204 if ($message->getPlainTextContent() <> '') { 205 $message->addHtmlContent('<br/><br/>'); 206 } 207 $message->addHtmlContent($this->lang['message_pagename_exist_one']); 208 $message->addHtmlContent('<ul>'); 209 210 $i = 0; 211 $listPagesHtml = ""; 212 foreach ($pagesWithSameName as $page) { 213 214 if ($page->getWikiId() === $ID) { 215 continue; 216 } 217 $i++; 218 if ($i > 10) { 219 $listPagesHtml .= '<li>' . 220 tpl_link( 221 "?do=search&q=" . rawurldecode($pageName), 222 "More ...", 223 'class="" rel="nofollow" title="More..."', 224 $return = true 225 ) . '</li>'; 226 break; 227 } 228 229 try { 230 $markupRef = LinkMarkup::createFromPageIdOrPath($page->getWikiId()); 231 $tagAttributes = $markupRef 232 ->toAttributes() 233 ->addOutputAttributeValue("rel", "nofollow"); 234 $listPagesHtml .= "<li>{$tagAttributes->toHtmlEnterTag("a")}{$markupRef->getDefaultLabel()}</a></li>"; 235 } catch (ExceptionBadSyntax $e) { 236 LogUtility::internalError("Internal Error: Unable to get a markup ref for the page ($page). Error: {$e->getMessage()}"); 237 } 238 239 } 240 $message->addHtmlContent($listPagesHtml); 241 $message->addHtmlContent('</ul>'); 242 243 } 244 } 245 246 247 /** 248 * Set the redirect in a session that will be be read after the redirect 249 * in order to show a message to the user 250 * @param string $id 251 * @param string $redirectSource 252 */ 253 static function notify($id, $redirectSource) 254 { 255 // Msg via session 256 if (!defined('NOSESSION')) { 257 //reopen session, store data and close session again 258 self::sessionStart(); 259 $_SESSION[DOKU_COOKIE][self::ORIGIN_PAGE] = $id; 260 $_SESSION[DOKU_COOKIE][self::ORIGIN_TYPE] = $redirectSource; 261 self::sessionClose(); 262 263 } 264 } 265 266 267 private static function sessionStart() 268 { 269 $sessionStatus = session_status(); 270 switch ($sessionStatus) { 271 case PHP_SESSION_DISABLED: 272 throw new RuntimeException("Sessions are disabled"); 273 274 case PHP_SESSION_NONE: 275 $result = @session_start(); 276 if (!$result) { 277 throw new RuntimeException("The session was not successfully started"); 278 } 279 break; 280 case PHP_SESSION_ACTIVE: 281 break; 282 } 283 } 284 285 private static function sessionClose() 286 { 287 // Close the session 288 $phpVersion = phpversion(); 289 if ($phpVersion > "7.2.0") { 290 $result = session_write_close(); 291 if (!$result) { 292 // Session is really not a well known mechanism 293 // Set this error in a info level to not fail the test 294 LogUtility::msg("Failure to write the session", LogUtility::LVL_MSG_INFO); 295 } 296 } else { 297 session_write_close(); 298 } 299 300 } 301 302 /** 303 * We don't saw the message if it was planned and 304 * it's a reader 305 * @return bool 306 */ 307 private function showMessageIfPublicAndPlanned(): bool 308 { 309 if (Identity::isWriter()){ 310 return true; 311 } 312 return $this->getConf(self::CONF_SHOW_MESSAGE_CLASSIC, self::CONF_SHOW_MESSAGE_CLASSIC_DEFAULT) == 1; 313 } 314 315} 316