From 06fdaf88cb1a355e445294beba4a89d0209ac71e Mon Sep 17 00:00:00 2001
From: Thomas Bruederli <thomas@roundcube.net>
Date: Wed, 13 Aug 2014 13:15:12 -0400
Subject: [PATCH] Extend rcmail::url() to produce absolute and fully qualified URLs

---
 tests/RcmailFunc.php       |   85 ++++++++++++++++++++++++++++
 program/include/rcmail.php |   45 ++++++++++++--
 tests/phpunit.xml          |    1 
 3 files changed, 123 insertions(+), 8 deletions(-)

diff --git a/program/include/rcmail.php b/program/include/rcmail.php
index ceb369a..bb2346f 100644
--- a/program/include/rcmail.php
+++ b/program/include/rcmail.php
@@ -789,11 +789,13 @@
     /**
      * Build a valid URL to this instance of Roundcube
      *
-     * @param mixed Either a string with the action or url parameters as key-value pairs
+     * @param mixed   Either a string with the action or url parameters as key-value pairs
+     * @param boolean Build an URL absolute to document root
+     * @param boolean Create fully qualified URL including http(s):// and hostname
      *
      * @return string Valid application URL
      */
-    public function url($p)
+    public function url($p, $absolute = false, $full = false)
     {
         if (!is_array($p)) {
             if (strpos($p, 'http') === 0) {
@@ -803,14 +805,15 @@
             $p = array('_action' => @func_get_arg(0));
         }
 
-        $task = $p['_task'] ? $p['_task'] : ($p['task'] ? $p['task'] : $this->task);
-        $p['_task'] = $task;
-        unset($p['task']);
+        $pre = array();
+        $task = $p['_task'] ?: ($p['task'] ?: $this->task);
+        $pre['_task'] = $task;
+        unset($p['task'], $p['_task']);
 
-        $url  = './' . $this->filename;
+        $url  = $this->filename;
         $delm = '?';
 
-        foreach (array_reverse($p) as $key => $val) {
+        foreach (array_merge($pre, $p) as $key => $val) {
             if ($val !== '' && $val !== null) {
                 $par  = $key[0] == '_' ? $key : '_'.$key;
                 $url .= $delm.urlencode($par).'='.urlencode($val);
@@ -818,7 +821,33 @@
             }
         }
 
-        return $url;
+        if ($absolute || $full) {
+            $prefix = '';
+
+            // prepend protocol://hostname:port
+            if ($full) {
+                $schema = 'http';
+                $default_port = 80;
+                if (rcube_utils::https_check()) {
+                    $schema = 'https';
+                    $default_port = 443;
+                }
+                $prefix = $schema . '://' . preg_replace('/:\d+$/', '', $_SERVER['HTTP_HOST']);
+                if ($_SERVER['SERVER_PORT'] != $default_port) {
+                  $prefix .= ':' . $_SERVER['SERVER_PORT'];
+                }
+            }
+
+            // add base path to this Roundcube installation
+            $base_path = preg_replace('![^/]+$!', '', strval($_SERVER['SCRIPT_NAME']));
+            if ($base_path == '') $base_path = '/';
+            $prefix .= $base_path;
+        }
+        else {
+            $prefix = './';
+        }
+
+        return $prefix . $url;
     }
 
     /**
diff --git a/tests/RcmailFunc.php b/tests/RcmailFunc.php
new file mode 100644
index 0000000..09b54b2
--- /dev/null
+++ b/tests/RcmailFunc.php
@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * Test class to test rcmail class
+ *
+ * @package Tests
+ */
+class RcmailFunc extends PHPUnit_Framework_TestCase
+{
+    function setUp()
+    {
+        // set some HTTP env vars
+        $_SERVER['HTTP_HOST'] = 'mail.example.org';
+        $_SERVER['SERVER_PORT'] = '443';
+        $_SERVER['SCRIPT_NAME'] = '/sub/index.php';
+        $_SERVER['HTTPS'] = true;
+
+        rcmail::get_instance()->filename = '';
+    }
+
+    /**
+     * Class constructor
+     */
+    function test_class()
+    {
+        $object = rcmail::get_instance();
+        $this->assertInstanceOf('rcmail', $object, "Class singleton");
+    }
+
+    /**
+     * Test rcmail::url()
+     */
+    function test_url()
+    {
+        $rcmail = rcmail::get_instance();
+        $this->assertEquals(
+            './?_task=cli&_action=test',
+            $rcmail->url('test'),
+            "Action only"
+        );
+        $this->assertEquals(
+            './?_task=cli&_action=test&_a=AA',
+            $rcmail->url(array('action' => 'test', 'a' => 'AA')),
+            "Unprefixed parameters"
+        );
+        $this->assertEquals(
+            './?_task=cli&_action=test&_b=BB',
+            $rcmail->url(array('_action' => 'test', '_b' => 'BB', '_c' => null)),
+            "Prefixed parameters (skip empty)"
+        );
+        $this->assertEquals(
+            '/sub/?_task=cli&_action=test&_mode=ABS',
+            $rcmail->url(array('_action' => 'test', '_mode' => 'ABS'), true),
+            "Absolute URL"
+        );
+
+        $this->assertEquals(
+            'https://mail.example.org/sub/?_task=calendar&_action=test&_mode=FQ',
+            $rcmail->url(array('task' => 'calendar', '_action' => 'test', '_mode' => 'FQ'), true, true),
+            "Fully Qualified URL"
+        );
+
+        // with different SCRIPT_NAME values
+        $_SERVER['SCRIPT_NAME'] = 'index.php';
+        $this->assertEquals(
+            '/?_task=cli&_action=test&_mode=ABS',
+            $rcmail->url(array('_action' => 'test', '_mode' => 'ABS'), true),
+            "Absolute URL (root)"
+        );
+        $_SERVER['SCRIPT_NAME'] = '';
+        $this->assertEquals(
+            '/?_task=cli&_action=test&_mode=ABS',
+            $rcmail->url(array('_action' => 'test', '_mode' => 'ABS'), true),
+            "Absolute URL (root)"
+        );
+
+        $_SERVER['HTTPS'] = false;
+        $_SERVER['SERVER_PORT'] = '8080';
+        $this->assertEquals(
+            'http://mail.example.org:8080/?_task=cli&_action=test&_mode=ABS',
+            $rcmail->url(array('_action' => 'test', '_mode' => 'ABS'), true, true),
+            "Full URL with port"
+        );
+    }
+}
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
index 4d50ad6..5c27d0e 100644
--- a/tests/phpunit.xml
+++ b/tests/phpunit.xml
@@ -46,6 +46,7 @@
             <file>Framework/VCard.php</file>
             <file>Framework/Washtml.php</file>
             <file>MailFunc.php</file>
+            <file>RcmailFunc.php</file>
         </testsuite>
         <testsuite name="Plugins Tests">
             <file>./../plugins/acl/tests/Acl.php</file>

--
Gitblit v1.9.1