]> git.mjollnir.org Git - moodle.git/commitdiff
lib MDL-19077 Created output redirect method and implemented against weblib redirect...
authorsamhemelryk <samhemelryk>
Mon, 29 Jun 2009 07:19:05 +0000 (07:19 +0000)
committersamhemelryk <samhemelryk>
Mon, 29 Jun 2009 07:19:05 +0000 (07:19 +0000)
This resolves the meta bug that was used when redirecting with a delay
Thanks Tim for the help with this one

lib/outputlib.php
lib/weblib.php

index b7bcb4d33cd6b162c2d122738a8c0f4720102cf4..7660c30cbf29e7a1207609f9625ed0fe9e11a772 100644 (file)
@@ -743,7 +743,7 @@ class moodle_core_renderer extends moodle_renderer_base {
     const MAIN_CONTENT_TOKEN = '[MAIN CONTENT GOES HERE]';
     protected $contenttype;
     protected $rendererfactory;
-
+    protected $metarefreshtag = '';
     /**
      * Constructor
      * @param $opencontainers the xhtml_container_stack to use.
@@ -805,6 +805,8 @@ class moodle_core_renderer extends moodle_renderer_base {
             $output .= '<meta http-equiv="pragma" content="no-cache" />' . "\n";
             $output .= '<meta http-equiv="expires" content="0" />' . "\n";
         }
+        // This is only set by the {@link redirect()} method
+        $output .= $this->metarefreshtag;
         ob_start();
         include($CFG->javascript);
         $output .= ob_get_contents();
@@ -896,6 +898,66 @@ class moodle_core_renderer extends moodle_renderer_base {
         }
     }
 
+    public function has_started() {
+        if ($this->page->stated >= moodle_page::STATE_IN_BODY) {
+            return true;
+        }
+        return false;
+    }
+
+    public function redirect($encodedurl, $message, $delay, $messageclass='notifyproblem') {
+        global $CFG;
+        $url = str_replace('&amp;', '&', $encodedurl);
+
+        $disableredirect = false;
+
+        if ($delay!=0) {
+            /// At developer debug level. Don't redirect if errors have been printed on screen.
+            /// Currenly only works in PHP 5.2+; we do not want strict PHP5 errors
+            $lasterror = error_get_last();
+            $error = defined('DEBUGGING_PRINTED') or (!empty($lasterror) && ($lasterror['type'] & DEBUG_DEVELOPER));
+            $errorprinted = debugging('', DEBUG_ALL) && $CFG->debugdisplay && $error;
+            if ($errorprinted) {
+                $disableredirect= true;
+                $message = "<strong>Error output, so disabling automatic redirect.</strong></p><p>" . $message;
+            }
+        }
+
+        switch ($this->page->state) {
+            case moodle_page::STATE_BEFORE_HEADER :
+                // No output yet it is safe to delivery the full arsenol of redirect methods
+                if (!$disableredirect) {
+                    @header($_SERVER['SERVER_PROTOCOL'] . ' 303 See Other'); //302 might not work for POST requests, 303 is ignored by obsolete clients
+                    @header('Location: '.$url);
+                    $this->metarefreshtag = '<meta http-equiv="refresh" content="'. $delay .'; url='. $encodedurl .'" />'."\n";
+                    $this->page->requires->js_function_call('document.location.replace', array($url))->after_delay($delay+3);
+                }
+                $output = $this->header();
+                $output .= $this->notification($message, $messageclass);
+                $output .= $this->footer();
+                break;
+            case moodle_page::STATE_PRINTING_HEADER :
+                // We should hopefully never get here
+                throw new coding_exception('You cannot redirect while printing the page header');
+                break;
+            case moodle_page::STATE_IN_BODY :
+                // We really shouldn't be here but we can deal with this
+                debugging("You should really redirect before you start page output");
+                if (!$disableredirect) {
+                    $this->page->requires->js_function_call('document.location.replace', array($url))->after_delay($delay+3);
+                }
+                $output = $this->opencontainers->pop_all_but_last();
+                $output .= $this->notification($message, $messageclass);
+                $output .= $this->footer();
+                break;
+            case moodle_page::STATE_DONE :
+                // Too late to be calling redirect now
+                throw new coding_exception('You cannot redirect after the entire page has been generated');
+                break;
+        }
+        return $output;
+    }
+
     // TODO remove $navigation and $menu arguments - replace with $PAGE->navigation
     public function header($navigation = '', $menu='') {
         global $USER, $CFG;
@@ -1170,13 +1232,13 @@ class moodle_core_renderer extends moodle_renderer_base {
 
         $output = '';
 
-        if ($this->opencontainers->count() == 0) {
+        if ($this->has_started()) {
+            $output .= $this->opencontainers->pop_all_but_last();
+        } else {
             // Header not yet printed
             @header('HTTP/1.0 404 Not Found');
             $this->page->set_title(get_string('error'));
             $output .= $this->header();
-        } else {
-            $output .= $this->opencontainers->pop_all_but_last();
         }
 
         $message = '<p class="errormessage">' . $message . '</p>'.
index 4aa9b3c5f2f1c909743590f8829b6ec869f491c1..689a193a4bd03ec7f435746639b2d94bbbdaa90c 100644 (file)
@@ -5654,61 +5654,40 @@ function notice_yesno ($message, $linkyes, $linkno, $optionsyes=NULL, $optionsno
 /**
  * Redirects the user to another page, after printing a notice
  *
-  * @todo '&' needs to be encoded into '&amp;' for XHTML compliance,
- *      however, this is not true for javascript. Therefore we
- *      first decode all entities in $url (since we cannot rely on)
- *      the correct input) and then encode for where it's needed
- *      echo "<script type='text/javascript'>alert('Redirect $url');</script>";
+ * This function calls the OUTPUT redirect method, echo's the output
+ * and then dies to ensure nothing else happens.
+ *
+ * <strong>Good practice:</strong> You should call this method before starting page
+ * output by using any of the OUTPUT methods.
  *
- * @global object
  * @global object
  * @global object
  * @global object
  * @uses $_COOKIE
  * @uses DEBUG_DEVELOPER
  * @uses DEBUG_ALL
- * @param string $url The url to take the user to
- * @param string $message The text message to display to the user about the redirect, if any
- * @param string $delay How long before refreshing to the new page at $url?
- * @return void Dies 
+ * @param string $url The URL to redirect to
+ * @param string $message The message to display to the user
+ * @param int $delay The delay before redirecting
+ * @return void
  */
 function redirect($url, $message='', $delay=-1) {
-    global $CFG, $THEME, $SESSION, $PAGE;
+    global $OUTPUT, $SESSION, $CFG;
 
     if (!empty($CFG->usesid) && !isset($_COOKIE[session_name()])) {
        $url = $SESSION->sid_process_url($url);
     }
 
-    $message = clean_text($message);
-
-    $encodedurl = preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&amp;", $url);
-    $encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text('<a href="'.$encodedurl.'" />'));
-    $url = str_replace('&amp;', '&', $encodedurl);
-
-/// At developer debug level. Don't redirect if errors have been printed on screen.
-/// Currenly only works in PHP 5.2+; we do not want strict PHP5 errors
-    $lasterror = error_get_last();
-    $error = defined('DEBUGGING_PRINTED') or (!empty($lasterror) && ($lasterror['type'] & DEBUG_DEVELOPER));
-    $errorprinted = debugging('', DEBUG_ALL) && $CFG->debugdisplay && $error;
-    if ($errorprinted) {
-        $message = "<strong>Error output, so disabling automatic redirect.</strong></p><p>" . $message;
-    }
-
-    $performanceinfo = '';
-    if (defined('MDL_PERF') || (!empty($CFG->perfdebug) and $CFG->perfdebug > 7)) {
-        if (defined('MDL_PERFTOLOG') && !function_exists('register_shutdown_function')) {
-            $perf = get_performance_info();
-            error_log("PERF: " . $perf['txt']);
+    $usingmsg = false;
+    if ($message!=='') {
+        $usingmsg = true;
+        if ($delay===-1 || !is_numeric($delay)) {
+            $delay = 3;
         }
-    }
-
-/// when no message and header printed yet, try to redirect
-    if (empty($message) and !$PAGE->headerprinted) {
-
-        // Technically, HTTP/1.1 requires Location: header to contain
-        // the absolute path. (In practice browsers accept relative
-        // paths - but still, might as well do it properly.)
-        // This code turns relative into absolute.
+        $message = clean_text($message);
+    } else {
+        $message = 'This page should redirect. If nothing is happening please click the continue button below.';
+        $delay = 0;
         if (!preg_match('|^[a-z]+:|', $url)) {
             // Get host name http://www.wherever.com
             $hostpart = preg_replace('|^(.*?[^:/])/.*$|', '$1', $CFG->wwwroot);
@@ -5728,39 +5707,24 @@ function redirect($url, $message='', $delay=-1) {
                 $url = $newurl;
             }
         }
-
-        $delay = 0;
-        //try header redirection first
-        @header($_SERVER['SERVER_PROTOCOL'] . ' 303 See Other'); //302 might not work for POST requests, 303 is ignored by obsolete clients
-        @header('Location: '.$url);
-        //another way for older browsers and already sent headers (eg trailing whitespace in config.php)
-        echo '<meta http-equiv="refresh" content="'. $delay .'; url='. $encodedurl .'" />';
-        echo $PAGE->requires->js_function_call('document.location.replace', array($url))->asap();
-        die;
     }
 
-    if ($delay == -1) {
-        $delay = 3;  // if no delay specified wait 3 seconds
-    }
-    if (!$PAGE->headerprinted) {
-        // this type of redirect might not be working in some browsers - such as lynx :-(
-        print_header('', '', '', '', $errorprinted ? '' : ('<meta http-equiv="refresh" content="'. $delay .'; url='. $encodedurl .'" />'));
-        $delay += 3; // double redirect prevention, it was sometimes breaking upgrades before 1.7
-    } else {
-        print_container_end_all(false, $THEME->open_header_containers);
+    $performanceinfo = '';
+    if (defined('MDL_PERF') || (!empty($CFG->perfdebug) and $CFG->perfdebug > 7)) {
+        if (defined('MDL_PERFTOLOG') && !function_exists('register_shutdown_function')) {
+            $perf = get_performance_info();
+            error_log("PERF: " . $perf['txt']);
+        }
     }
-    echo '<div id="redirect">';
-    echo '<div id="message">' . $message . '</div>';
-    echo '<div id="continue">( <a href="'. $encodedurl .'">'. get_string('continue') .'</a> )</div>';
-    echo '</div>';
 
-    if (!$errorprinted) {
-        $PAGE->requires->js_function_call('document.location.replace', array($url))->after_delay($delay);
-    }
+    $encodedurl = preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&amp;", $url);
+    $encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text('<a href="'.$encodedurl.'" />'));
 
+    $message .= '<a href="'. $encodedurl .'">'. get_string('continue') .'</a>';
+   
     $CFG->docroot = false; // to prevent the link to moodle docs from being displayed on redirect page.
-    print_footer('none');
-    die;
+    echo $OUTPUT->redirect($encodedurl, $message, $delay);
+    die();
 }
 
 /**