datafile = '_site/error_data'; $this->error_data = \gp\tool\Files::Get($this->datafile,'error_data'); $this->error_data += array( 'redirects' => array( ) ); } public function __construct($args){ global $langmessage; parent::__construct($args); $this->Init(); $this->requested = $this->page->requested; } public function RunScript(){ $cmd = \gp\tool::GetCommand(); $this->RunCommands($cmd); } public function DefaultDisplay(){ if( $this->page->gp_index !== 'special_missing' ){ $this->CheckRedirect(); $this->CheckSimilar(); } $this->Get404(); } /** * Redirect the request if a redirection entry matches the requested page * */ public function CheckRedirect(){ if( is_null($this->requested) ){ return; } $parts = explode('/',$this->requested); $first_part = array_shift($parts); if( !isset($this->error_data['redirects'][$first_part]) ){ return; } $target = $this->error_data['redirects'][$first_part]['target']; $target = $this->GetTarget($target); if( $target === false ){ return; } if( !empty($parts) && is_string($target) ){ $target .= '/'.implode('/',$parts); } $code = $this->error_data['redirects'][$first_part]['code']; \gp\tool::Redirect($target,$code); } /** * Redirect the request if the requested page closely matches an existing page * If it's just a difference of case, then the similarity will be 100% * */ public function CheckSimilar(){ global $config; $requested = trim($this->requested,'/'); $similar = $this->SimilarTitleArray($requested); $first_title = key($similar); $first_percent = current($similar); if( $config['auto_redir'] > 0 && $first_percent >= $config['auto_redir'] ){ $redirect = \gp\tool::GetUrl($first_title,http_build_query($_GET),false); \gp\tool::Redirect($redirect); } } /** * Translate the $target url to a url that can be used with Header() or in a link * * @param string $target The user supplied value for redirection * @param boolean $get_final If true, GetTarget() will check for additional redirection and $target existence before returning the url. Maximum of 10 redirects. * @return string|false */ public function GetTarget($target,$get_final = true){ global $gp_index; static $redirects = 0; if( empty($target) ){ return \gp\tool::GetUrl(''); } if( !$this->isGPLink($target) ){ return $target; } if( !$get_final ){ return \gp\tool::GetUrl($target); } //check for more redirects if( isset($this->error_data['redirects'][$target]) ){ $redirects++; if( $redirects > 10 ){ return false; } $target = $this->error_data['redirects'][$target]['target']; return $this->GetTarget($target); } //check for target existence if( isset($gp_index[$target]) ){ return \gp\tool::GetUrl($target); } $scripts = \gp\admin\Tools::AdminScripts(); if( isset($scripts[$target]) ){ return \gp\tool::GetUrl($target); } return false; } public function isGPLink($target){ //has a url scheme (aka protocol) $reg = '#^[a-zA-Z][a-zA-Z0-9\+\.\-]+:#'; if( preg_match($reg,$target,$matches) ){ return false; } //strings beginning with / could be gplinks, they could also links to non-cms managed pages // we could do additional testing, but we could never be certain what the user intent is if( strpos($target,'/') === 0 ){ return false; } return true; } public function Get404(){ global $langmessage,$page; \gp\tool\Output::AddHeader('Not Found',true,404); $page->head .= ''; //this isn't getting to the template because $page isn't available yet //message for admins if( \gp\tool::LoggedIn() ){ if( $this->requested && \gp\tool::SpecialOrAdmin($this->requested) === false ){ $with_spaces = htmlspecialchars($this->requested); $link = \gp\tool::GetUrl('Admin/Menu/Ajax','cmd=AddHidden&redir=redir&title='.rawurlencode($this->requested)).'" title="'.$langmessage['create_new_file'].'" data-cmd="gpabox'; $message = sprintf($langmessage['DOESNT_EXIST'],$with_spaces,$link); msg($message); } } echo '
'; //Contents of 404 page $wrap = \gp\tool\Output::ShowEditLink('Admin/Missing'); if( $wrap ){ echo \gp\tool\Output::EditAreaLink($edit_index,'Admin/Missing',$langmessage['edit'],'cmd=edit404',' title="'.$langmessage['404_Page'].'" '); echo '
'; // class="edit_area" added by javascript } echo self::Get404Output(); if( $wrap ){ echo '
'; } echo '
'; } /** * Return the custom 404 page content if it exists, otherwise return the default content * */ public function Get404Output(){ if( isset($this->error_data['404_TEXT']) ){ $text = $this->error_data['404_TEXT']; }else{ $text = self::DefaultContent(); } return str_replace('{{Similar_Titles}}',$this->SimilarTitles(),$text); } /** * Get a comma separated list of links to titles similar to the requested page * @return string * */ public function SimilarTitles(){ $similar = $this->SimilarTitleArray($this->requested); $similar = array_slice($similar,0,7,true); $result = ''; foreach($similar as $title => $percent_similar){ if ( $title === key($similar) || $percent_similar > 10 ) { $result .= \gp\tool::Link_Page($title).', '; } } return rtrim($result,', '); } /** * Get a list of existing titles similar to the requested page * @param string $title of requested page * @return array of similar titles reverse-numerical sorted by similarity (percent) * */ public function SimilarTitleArray($title){ global $gp_index, $gp_titles; $similar_titles = []; $lower = str_replace(' ','_',strtolower($title)); foreach($gp_index as $title => $index){ //skip 'special_missing' page if( $index == 'special_missing' ){ continue; } //skip private pages when not logged-in if( !\gp\tool::LoggedIn() && isset($gp_titles[$index]['vis']) ){ continue; } similar_text($lower,mb_strtolower($title),$percent); $similar_titles[$index] = [ 'title' => $title, 'percent' => $percent, ]; } uasort($similar_titles, function($a, $b) { return $b['percent'] - $a['percent']; }); $similar_titles = \gp\tool\Plugins::Filter('SimilarTitles', [$similar_titles]); $similar = []; foreach( $similar_titles as $similar_title ){ $similar[$similar_title['title']] = $similar_title['percent']; } return $similar; } /** * Returnt the default content of the 404 page * */ public function DefaultContent(){ global $langmessage; $text = '

'.$langmessage['Not Found'].'

'; $text .= '

'; $text .= $langmessage['OOPS_TITLE']; $text .= '

'; $text .= '

'; $text .= ''.$langmessage['One of these titles?'].''; $text .= '

{{Similar_Titles}}
'; $text .= '

'; return $text; } }