1<?php
2
3/**
4 * Validator for the components of a URI for a specific scheme
5 */
6abstract class HTMLPurifier_URIScheme
7{
8
9    /**
10     * Scheme's default port (integer). If an explicit port number is
11     * specified that coincides with the default port, it will be
12     * elided.
13     * @type int
14     */
15    public $default_port = null;
16
17    /**
18     * Whether or not URIs of this scheme are locatable by a browser
19     * http and ftp are accessible, while mailto and news are not.
20     * @type bool
21     */
22    public $browsable = false;
23
24    /**
25     * Whether or not data transmitted over this scheme is encrypted.
26     * https is secure, http is not.
27     * @type bool
28     */
29    public $secure = false;
30
31    /**
32     * Whether or not the URI always uses <hier_part>, resolves edge cases
33     * with making relative URIs absolute
34     * @type bool
35     */
36    public $hierarchical = false;
37
38    /**
39     * Whether or not the URI may omit a hostname when the scheme is
40     * explicitly specified, ala file:///path/to/file. As of writing,
41     * 'file' is the only scheme that browsers support his properly.
42     * @type bool
43     */
44    public $may_omit_host = false;
45
46    /**
47     * Validates the components of a URI for a specific scheme.
48     * @param HTMLPurifier_URI $uri Reference to a HTMLPurifier_URI object
49     * @param HTMLPurifier_Config $config
50     * @param HTMLPurifier_Context $context
51     * @return bool success or failure
52     */
53    abstract public function doValidate(&$uri, $config, $context);
54
55    /**
56     * Public interface for validating components of a URI.  Performs a
57     * bunch of default actions. Don't overload this method.
58     * @param HTMLPurifier_URI $uri Reference to a HTMLPurifier_URI object
59     * @param HTMLPurifier_Config $config
60     * @param HTMLPurifier_Context $context
61     * @return bool success or failure
62     */
63    public function validate(&$uri, $config, $context)
64    {
65        if ($this->default_port == $uri->port) {
66            $uri->port = null;
67        }
68        // kludge: browsers do funny things when the scheme but not the
69        // authority is set
70        if (!$this->may_omit_host &&
71            // if the scheme is present, a missing host is always in error
72            (!is_null($uri->scheme) && ($uri->host === '' || is_null($uri->host))) ||
73            // if the scheme is not present, a *blank* host is in error,
74            // since this translates into '///path' which most browsers
75            // interpret as being 'http://path'.
76            (is_null($uri->scheme) && $uri->host === '')
77        ) {
78            do {
79                if (is_null($uri->scheme)) {
80                    if (substr($uri->path, 0, 2) != '//') {
81                        $uri->host = null;
82                        break;
83                    }
84                    // URI is '////path', so we cannot nullify the
85                    // host to preserve semantics.  Try expanding the
86                    // hostname instead (fall through)
87                }
88                // first see if we can manually insert a hostname
89                $host = $config->get('URI.Host');
90                if (!is_null($host)) {
91                    $uri->host = $host;
92                } else {
93                    // we can't do anything sensible, reject the URL.
94                    return false;
95                }
96            } while (false);
97        }
98        return $this->doValidate($uri, $config, $context);
99    }
100}
101
102// vim: et sw=4 sts=4
103