File: html.php

package info (click to toggle)
horde3 3.1.3-4etch7
  • links: PTS
  • area: main
  • in suites: etch
  • size: 22,876 kB
  • ctags: 18,071
  • sloc: php: 75,151; xml: 2,979; sql: 1,069; makefile: 79; sh: 64
file content (153 lines) | stat: -rw-r--r-- 6,473 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
<?php
/**
 * The MIME_Viewer_html class renders out HTML text with an effort to
 * remove potentially malicious code.
 *
 * $Horde: framework/MIME/MIME/Viewer/html.php,v 1.14.4.20 2006/06/07 13:34:16 jan Exp $
 *
 * Copyright 1999-2006 Anil Madhavapeddy <anil@recoil.org>
 * Copyright 1999-2006 Jon Parise <jon@horde.org>
 * Copyright 2002-2006 Michael Slusarz <slusarz@horde.org>
 *
 * See the enclosed file COPYING for license information (GPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
 *
 * @author  Anil Madhavapeddy <anil@recoil.org>
 * @author  Jon Parise <jon@horde.org>
 * @author  Michael Slusarz <slusarz@horde.org>
 * @since   Horde 3.0
 * @package Horde_MIME_Viewer
 */
class MIME_Viewer_html extends MIME_Viewer {

    /**
     * Render out the currently set contents.
     *
     * @param array $params  Any parameters the viewer may need.
     *
     * @return string  The rendered text.
     */
    function render($params = null)
    {
        return $this->_cleanHTML($this->mime_part->getContents());
    }

    /**
     * Filters active content, dereferences external links, detects phishing,
     * etc.
     *
     * @access private
     *
     * @param string $data  The HTML data.
     *
     * @return string  The cleaned HTML data.
     */
    function _cleanHTML($data)
    {
        global $browser, $prefs;

        $phish_warn = false;

        require_once 'Horde/MIME/Contents.php';
        $attachment = MIME_Contents::viewAsAttachment();

        /* Deal with <base> tags in the HTML, since they will screw up our own
         * relative paths. */
        if (preg_match('/<base href="?([^"> ]*)"? ?\/?>/i', $data, $matches)) {
            $base = $matches[1];
            if (substr($base, -1, 1) != '/') {
                $base .= '/';
            }

            /* Recursively call _cleanHTML() to prevent clever fiends from
             * sneaking nasty things into the page via $base. */
            $base = $this->_cleanHTML($base);
        }

        /* Attempt to fix paths that were relying on a <base> tag. */
        if (!empty($base)) {
            $pattern = array('|src=(["\'])([^:"\']+)\1|i',
                             '|src=([^: >"\']+)|i',
                             '|href= *(["\'])([^:"\']+)\1|i',
                             '|href=([^: >"\']+)|i');
            $replace = array('src=\1' . $base . '\2\1',
                             'src=' . $base . '\1',
                             'href=\1' . $base . '\2\1',
                             'href=' . $base . '\1');
            $data = preg_replace($pattern, $replace, $data);
        }

        require_once 'Horde/Text/Filter.php';
        $strip_styles = !$attachment ||
            ($browser->isBrowser('mozilla') &&
             $browser->getMajor() == 4) ||
            $browser->isBrowser('msie');
        $data = Text_Filter::filter($data, 'xss',
                                    array('body_only' => !$attachment,
                                          'strip_styles' => $strip_styles));

        /* Check for phishing exploits. */
        if (preg_match('/href\s*=\s*["\']?\s*(http|https|ftp):\/\/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/i', $data)) {
            /* Check 1: Check for IP address links. */
            $phish_warn = true;
        } elseif (preg_match_all('/href\s*=\s*["\']?\s*(?:http|https|ftp):\/\/([^\s"\'>]+)["\']?[^>]*>\s*(?:(?:http|https|ftp):\/\/)?(.*?)<\/a/is', $data, $m)) {
            /* $m[1] = Link; $m[2] = Target
             * Check 2: Check for links that point to a different host than
             * the target url; if target looks like a domain name, check it
             * against the link. */
            $links = count($m[0]);
            for ($i = 0; $i < $links; $i++) {
                $m[1][$i] = strtolower(urldecode($m[1][$i]));
                $m[2][$i] = strtolower(preg_replace('/^(http|https|ftp):\/\//', '', strip_tags($m[2][$i])));
                if (preg_match('/^[-._\da-z]+\.[a-z]{2,}/i', $m[2][$i]) &&
                    strpos($m[1][$i], $m[2][$i]) !== 0 &&
                    strpos($m[2][$i], $m[1][$i]) !== 0) {
                    /* Don't consider the link a phishing link if the domain
                     * is the same on both links (e.g. adtracking.example.com
                     * & www.example.com). */
                    preg_match('/\.?([^\.\/]+\.[^\.\/]+)\//', $m[1][$i], $host1);
                    preg_match('/\.?([^\.\/]+\.[^\.\/]+)(\/.*)?$/', $m[2][$i], $host2);
                    if (!(count($host1) && count($host2)) ||
                        strcasecmp($host1[1], $host2[1]) !== 0) {
                        $phish_warn = true;
                    }
                }
            }
        }

        /* Try to derefer all external references. */
        $data = preg_replace_callback('/href\s*=\s*(["\'])?((?(1)[^\1]*?|[^\s>]+))(?(1)\1|)/i',
                                      create_function('$m', 'return \'href="\' . (strlen($m[2]) && $m[2]{0} == \'#\' ? $m[2] : Horde::externalUrl($m[2])) . \'"\';'),
                                      $data);

        /* Prepend phishing warning. */
        if ($phish_warn) {
            require_once 'Horde/MIME/Contents.php';
            $contents = &new MIME_Contents(new MIME_Part());
            $phish_warning = sprintf(_("%s: This message may not be from whom it claims to be. Beware of following any links in it or of providing the sender with any personal information."), _("Warning"));
            if ($contents->viewAsAttachment()) {
                $phish_warning = '<span style="background-color:#ffd0af;color:black">' . String::convertCharset($phish_warning, NLS::getCharset(), $this->mime_part->getCharset()) . '</span><br />';
            }
            $phish_warning = $contents->formatStatusMsg($phish_warning, null, true, 'mimeStatusWarning');
            if (stristr($data, '<body') === false) {
                $data = $phish_warning . $data;
            } else {
                $data = preg_replace('/(.*<body.*?>)(.*)/i', '$1' . $phish_warning . '$2', $data);
            }
        }

        return $data;
    }

    /**
     * Return the content-type of the rendered text.
     *
     * @return string  The MIME Content-Type.
     */
    function getType()
    {
        require_once 'Horde/MIME/Contents.php';
        return MIME_Contents::viewAsAttachment() ? $this->mime_part->getType(true) : 'text/html; charset=' . NLS::getCharset();
    }

}