Wikitext redirects should work again + get_redirect() added to Namespace_* to allow plugins to extend
authorDan
Sun, 10 May 2009 15:52:53 -0400
changeset 963 b572ce1114f1
parent 962 ceeecb160aec
child 964 a0add54d9795
Wikitext redirects should work again + get_redirect() added to Namespace_* to allow plugins to extend
ajax.php
includes/functions.php
includes/namespaces/default.php
includes/pageprocess.php
index.php
--- a/ajax.php	Sun May 10 14:47:14 2009 -0400
+++ b/ajax.php	Sun May 10 15:52:53 2009 -0400
@@ -175,6 +175,7 @@
       
       $pagepass = ( isset($_REQUEST['pagepass']) ) ? $_REQUEST['pagepass'] : '';
       $page->password = $pagepass;
+      $page->allow_redir = ( !isset($_GET['redirect']) || (isset($_GET['redirect']) && $_GET['redirect'] !== 'no') );
             
       $page->send();
       break;
--- a/includes/functions.php	Sun May 10 14:47:14 2009 -0400
+++ b/includes/functions.php	Sun May 10 15:52:53 2009 -0400
@@ -921,6 +921,44 @@
 }
 
 /**
+ * Show the "this is a redirector" notice
+ * @param string Target Page ID
+ * @param string Target Namespace
+ */
+
+function display_redirect_notice($page_id, $namespace)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  global $lang, $output;
+  
+  $url = makeUrlNS($namespace, $page_id, false, true);
+  $ns = namespace_factory($page_id, $namespace);
+  $page_data = $ns->get_cdata();
+  
+  $title = $page_data['name'];
+  
+  $cls = $ns->exists() ? '' : 'class="wikilink-nonexistent" ';
+    
+  $a = '<a ' . $cls . 'href="' . $url . '">' . $title . '</a>';
+  $redir_html = '<br /><div class="mdg-infobox">
+          <table border="0" width="100%" cellspacing="0" cellpadding="0">
+            <tr>
+              <td valign="top">
+                <img alt="Cute wet-floor icon" src="' . cdnPath . '/images/redirector.png" />
+              </td>
+              <td valign="top" style="padding-left: 10px;">
+                ' . $lang->get('page_msg_this_is_a_redirector', array( 'redirect_target' => $a )) . '
+              </td>
+            </tr>
+          </table>
+        </div>
+        <br />
+        <hr style="margin-left: 1em; width: 200px;" />';
+  
+  $output->add_after_header($redir_html);
+}
+
+/**
  * Essentially an return code reader for a socket. Don't use this unless you're writing mail code and smtp_send_email doesn't cut it. Ported from phpBB's smtp.php.
  * @param socket A socket resource
  * @param string The expected response from the server, this needs to be exactly three characters.
--- a/includes/namespaces/default.php	Sun May 10 14:47:14 2009 -0400
+++ b/includes/namespaces/default.php	Sun May 10 15:52:53 2009 -0400
@@ -324,6 +324,25 @@
       }
     }
   }
+  
+  /**
+   * Get a redirect, if there is one.
+   * @return mixed Array: Page ID and namespace, associative; bool: false (no redirect)
+   */
+  
+  public function get_redirect()
+  {
+    $text = $this->fetch_text();
+    if ( preg_match('/^#redirect \[\[([^\]]+?)\]\]/i', $text, $match ) )
+    {
+      list($page_id, $namespace) = RenderMan::strToPageID($match[1]);
+      return array(
+          'page_id' => $page_id,
+          'namespace' => $namespace
+        );
+    }
+    return false;
+  }
    
   /**
    * The "real" send-the-page function. The reason for this is so other namespaces can re-use the code
@@ -342,44 +361,7 @@
     
     $text = preg_replace('/([\s]*)__NOBREADCRUMBS__([\s]*)/', '', $text);
     $text = preg_replace('/([\s]*)__NOTOC__([\s]*)/', '', $text);
-    
-    $redir_enabled = false;
-    if ( preg_match('/^#redirect \[\[([^\]]+?)\]\]/i', $text, $match ) )
-    {
-      $redir_enabled = true;
-      
-      $oldtarget = RenderMan::strToPageID($match[1]);
-      $oldtarget[0] = sanitize_page_id($oldtarget[0]);
-      
-      $url = makeUrlNS($oldtarget[1], $oldtarget[0], false, true);
-      $page_data = $paths->get_cdata($oldtarget[0], $oldtarget[1]);
-      $title = ( isset($page_data['name']) ) ? $page_data['name'] : $paths->nslist[$oldtarget[1]] . htmlspecialchars( str_replace('_', ' ', dirtify_page_id( $oldtarget[0] ) ) );
-      if ( !isset($page_data['name']) )
-      {
-        $cls = 'class="wikilink-nonexistent"';
-      }
-      else
-      {
-        $cls = '';
-      }
-      $a = '<a ' . $cls . ' href="' . $url . '">' . $title . '</a>';
-      $redir_html = '<br /><div class="mdg-infobox">
-              <table border="0" width="100%" cellspacing="0" cellpadding="0">
-                <tr>
-                  <td valign="top">
-                    <img alt="Cute wet-floor icon" src="'.scriptPath.'/images/redirector.png" />
-                  </td>
-                  <td valign="top" style="padding-left: 10px;">
-                    ' . $lang->get('page_msg_this_is_a_redirector', array( 'redirect_target' => $a )) . '
-                  </td>
-                </tr>
-              </table>
-            </div>
-            <br />
-            <hr style="margin-left: 1em; width: 200px;" />';
-      $text = str_replace($match[0], '', $text);
-      $text = trim($text);
-    }
+    $text = preg_replace('/^#redirect \[\[.+?\]\]\s*/i', '', $text);
     
     if ( $send_headers )
     {
@@ -433,11 +415,6 @@
       $page_format = $this->cdata['page_format'];
     }
     
-    if ( $redir_enabled )
-    {
-      echo $redir_html;
-    }
-    
     $code = $plugins->setHook('pageprocess_render_head');
     foreach ( $code as $cmd )
     {
--- a/includes/pageprocess.php	Sun May 10 14:47:14 2009 -0400
+++ b/includes/pageprocess.php	Sun May 10 15:52:53 2009 -0400
@@ -104,6 +104,13 @@
   var $allow_redir = true;
   
   /**
+   * Holds any error message from redirection code. Defaults to false (no error).
+   * @var mixed
+   */
+   
+  var $redir_error = false;
+  
+  /**
    * If this is set to true, this will call the header and footer funcs on $template when render() is called.
    * @var bool
    */
@@ -175,7 +182,7 @@
   function send( $do_stats = false )
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
-    global $lang;
+    global $lang, $output;
     
     profiler_log('PageProcessor: send() called');
     
@@ -278,6 +285,40 @@
     
     // We are all done. Ship off the page.
     
+    if ( !$this->allow_redir )
+    {
+      if ( method_exists($this->ns, 'get_redirect') )
+      {
+        if ( $result = $this->ns->get_redirect() )
+          display_redirect_notice($result['page_id'], $result['namespace']);
+      }
+    }
+    else
+    {
+      $this->process_redirects();
+      
+      if ( count($this->redirect_stack) > 0 )
+      {
+        $stack = array_reverse($this->redirect_stack);
+        foreach ( $stack as $stackel )
+        {
+          $url = makeUrlNS($stackel['old_namespace'], $stackel['old_page_id'], 'redirect=no', true);
+          $page_data = $this->ns->get_cdata();
+          $title = $stackel['old_title'];
+          $a = '<a href="' . $url . '">' . htmlspecialchars($title) . '</a>';
+          $output->add_after_header('<small>' . $lang->get('page_msg_redirected_from', array('from' => $a)) . '<br /></small>');
+        }
+        $template->set_page($this);
+      }
+      
+      if ( $this->redir_error )
+      {
+        $output->add_after_header('<div class="usermessage"><b>' . $this->redir_error . '</b></div>');
+        $result = $this->ns->get_redirect();
+        display_redirect_notice($result['page_id'], $result['namespace']);
+      }
+    }
+    
     $this->ns->send();
   }
   
@@ -942,15 +983,15 @@
     
     $page_id_cleaned = sanitize_page_id($page_id);
     
-    $this->page_id = $page_id_cleaned;
-    $this->namespace = $namespace;
     $this->revision_id = $revision_id;
     $this->page_id_unclean = dirtify_page_id($page_id);
     
-    $this->perms = $session->fetch_page_acl( $page_id, $namespace );
+    // resolve namespace
+    $this->ns = namespace_factory($page_id, $namespace, $this->revision_id);
+    $this->page_id =& $this->ns->page_id;
+    $this->namespace =& $this->ns->namespace;
     
-    // resolve namespace
-    $this->ns = namespace_factory($this->page_id, $this->namespace, $this->revision_id);
+    $this->perms = $session->fetch_page_acl( $page_id, $namespace );
     
     $this->page_exists = $this->ns->exists();
     $this->title = get_page_title_ns($this->page_id, $this->namespace);
@@ -959,30 +1000,85 @@
   }
   
   /**
-   * Renders it all in one go, and echoes it out. This assumes that the text is in the DB.
+   * Processes any redirects.
    * @access private
    */
   
-  function render($incl_inner_headers = true, $_errormsg = false)
+  function process_redirects()
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
     global $output, $lang;
     
-    if ( count($this->redirect_stack) > 0 )
+    $this->redirect_stack = array();
+    
+    if ( !method_exists($this->ns, 'get_redirect') )
+      return true;
+    
+    if ( !$this->allow_redir )
+      return true;
+    
+    $redirect_count = 0;
+    
+    while ( $result = $this->ns->get_redirect() )
     {
-      $stack = array_reverse($this->redirect_stack);
-      foreach ( $stack as $oldtarget )
+      if ( $result['namespace'] == 'Special' || $result['namespace'] == 'Admin' )
+      {
+        // Can't redirect to special/admin page
+        $this->redir_error = $lang->get('page_err_redirect_to_special');
+        break;
+      }
+      if ( $redirect_count == 3 )
+      {
+        // max of 3 internal redirects exceeded
+        $this->redir_error = $lang->get('page_err_redirects_exceeded');
+        break;
+      }
+      
+      $loop = false;
+      foreach ( $this->redirect_stack as $stackel )
       {
-        $url = makeUrlNS($oldtarget[1], $oldtarget[0], 'redirect=no', true);
-        $page_data = $this->ns->get_cdata();
-        $title = ( isset($page_data['name']) ) ? $page_data['name'] : $paths->nslist[$oldtarget[1]] . htmlspecialchars( str_replace('_', ' ', dirtify_page_id( $oldtarget[0] ) ) );
-        $a = '<a href="' . $url . '">' . $title . '</a>';
-        $output->add_after_header('<small>' . $lang->get('page_msg_redirected_from', array('from' => $a)) . '<br /></small>');
+        if ( $result['page_id'] == $stackel['old_page_id'] && $result['namespace'] == $stackel['old_namespace'] )
+        {
+          $loop = true;
+          break;
+        }
+      }
+      
+      if ( $loop )
+      {
+        // redirect loop
+        $this->redir_error = $lang->get('page_err_redirect_infinite_loop');
+        break;
+      }
+      $new_ns = namespace_factory($result['page_id'], $result['namespace']);
+      if ( !$new_ns->exists() )
+      {
+        // new page doesn't exist
+        $this->redir_error = $lang->get('page_err_redirect_to_nonexistent');
+        break;
       }
+      
+      // build stack entry
+      $stackel = array(
+          'page_id' => $result['page_id'],
+          'namespace' => $result['namespace'],
+          'old_page_id' => $this->page_id,
+          'old_namespace' => $this->namespace,
+          'old_title' => $this->ns->title
+        );
+      
+      // replace everything (perform the actual redirect)
+      $this->ns = $new_ns;
+      
+      $this->page_id =& $this->ns->page_id;
+      $this->namespace =& $this->ns->namespace;
+      
+      $this->redirect_stack[] = $stackel;
+      
+      $redirect_count++;
     }
-    $this->ns->send($incl_inner_headers, $_errormsg);
   }
-  
+    
   /**
    * Sends the page header, dependent on, of course, whether we're supposed to.
    */
@@ -1032,6 +1128,7 @@
    * @access private
    */
   
+  /*
   function _handle_redirect($page_id, $namespace)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
@@ -1039,7 +1136,7 @@
     $arr_pid = array($this->page_id, $this->namespace);
     if ( $namespace == 'Special' || $namespace == 'Admin' )
     {
-      return $lang->get('page_err_redirect_to_special');
+      return ;
     }
     $looped = false;
     foreach ( $this->redirect_stack as $page )
@@ -1052,7 +1149,7 @@
     }
     if ( $looped )
     {
-      return $lang->get('page_err_redirect_infinite_loop');
+      return ;
     }
     $page_id_key = $paths->nslist[ $namespace ] . sanitize_page_id($page_id);
     if ( !isPage($page_id_key) )
@@ -1068,6 +1165,7 @@
     $this->send();
     return true;
   }
+  */
   
   /**
    * Send the error message to the user that the access to this page is denied.
--- a/index.php	Sun May 10 14:47:14 2009 -0400
+++ b/index.php	Sun May 10 15:52:53 2009 -0400
@@ -75,6 +75,7 @@
       // PageProcessor when we already have one going.
       $template->set_page($page);
       $page->send_headers = true;
+      $page->allow_redir = ( !isset($_GET['redirect']) || (isset($_GET['redirect']) && $_GET['redirect'] !== 'no') );
       $pagepass = ( isset($_REQUEST['pagepass']) ) ? sha1($_REQUEST['pagepass']) : '';
       $page->password = $pagepass;
       $page->send(true);