Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 liveuser 1
<?php
2
 
3
namespace React\Dns\Config;
4
 
5
use RuntimeException;
6
 
7
/**
8
 * Represents a static hosts file which maps hostnames to IPs
9
 *
10
 * Hosts files are used on most systems to avoid actually hitting the DNS for
11
 * certain common hostnames.
12
 *
13
 * Most notably, this file usually contains an entry to map "localhost" to the
14
 * local IP. Windows is a notable exception here, as Windows does not actually
15
 * include "localhost" in this file by default. To compensate for this, this
16
 * class may explicitly be wrapped in another HostsFile instance which
17
 * hard-codes these entries for Windows (see also Factory).
18
 *
19
 * This class mostly exists to abstract the parsing/extraction process so this
20
 * can be replaced with a faster alternative in the future.
21
 */
22
class HostsFile
23
{
24
    /**
25
     * Returns the default path for the hosts file on this system
26
     *
27
     * @return string
28
     * @codeCoverageIgnore
29
     */
30
    public static function getDefaultPath()
31
    {
32
        // use static path for all Unix-based systems
33
        if (DIRECTORY_SEPARATOR !== '\\') {
34
            return '/etc/hosts';
35
        }
36
 
37
        // Windows actually stores the path in the registry under
38
        // \HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DataBasePath
39
        $path = '%SystemRoot%\\system32\drivers\etc\hosts';
40
 
41
        $base = getenv('SystemRoot');
42
        if ($base === false) {
43
            $base = 'C:\\Windows';
44
        }
45
 
46
        return str_replace('%SystemRoot%', $base, $path);
47
    }
48
 
49
    /**
50
     * Loads a hosts file (from the given path or default location)
51
     *
52
     * Note that this method blocks while loading the given path and should
53
     * thus be used with care! While this should be relatively fast for normal
54
     * hosts file, this may be an issue if this file is located on a slow device
55
     * or contains an excessive number of entries. In particular, this method
56
     * should only be executed before the loop starts, not while it is running.
57
     *
58
     * @param ?string $path (optional) path to hosts file or null=load default location
59
     * @return self
60
     * @throws RuntimeException if the path can not be loaded (does not exist)
61
     */
62
    public static function loadFromPathBlocking($path = null)
63
    {
64
        if ($path === null) {
65
            $path = self::getDefaultPath();
66
        }
67
 
68
        $contents = @file_get_contents($path);
69
        if ($contents === false) {
70
            throw new RuntimeException('Unable to load hosts file "' . $path . '"');
71
        }
72
 
73
        return new self($contents);
74
    }
75
 
76
    private $contents;
77
 
78
    /**
79
     * Instantiate new hosts file with the given hosts file contents
80
     *
81
     * @param string $contents
82
     */
83
    public function __construct($contents)
84
    {
85
        // remove all comments from the contents
86
        $contents = preg_replace('/[ \t]*#.*/', '', strtolower($contents));
87
 
88
        $this->contents = $contents;
89
    }
90
 
91
    /**
92
     * Returns all IPs for the given hostname
93
     *
94
     * @param string $name
95
     * @return string[]
96
     */
97
    public function getIpsForHost($name)
98
    {
99
        $name = strtolower($name);
100
 
101
        $ips = array();
102
        foreach (preg_split('/\r?\n/', $this->contents) as $line) {
103
            $parts = preg_split('/\s+/', $line);
104
            $ip = array_shift($parts);
105
            if ($parts && array_search($name, $parts) !== false) {
106
                // remove IPv6 zone ID (`fe80::1%lo0` => `fe80:1`)
107
                if (strpos($ip, ':') !== false && ($pos = strpos($ip, '%')) !== false) {
108
                    $ip = substr($ip, 0, $pos);
109
                }
110
 
111
                if (@inet_pton($ip) !== false) {
112
                    $ips[] = $ip;
113
                }
114
            }
115
        }
116
 
117
        return $ips;
118
    }
119
 
120
    /**
121
     * Returns all hostnames for the given IPv4 or IPv6 address
122
     *
123
     * @param string $ip
124
     * @return string[]
125
     */
126
    public function getHostsForIp($ip)
127
    {
128
        // check binary representation of IP to avoid string case and short notation
129
        $ip = @inet_pton($ip);
130
        if ($ip === false) {
131
            return array();
132
        }
133
 
134
        $names = array();
135
        foreach (preg_split('/\r?\n/', $this->contents) as $line) {
136
            $parts = preg_split('/\s+/', $line, null, PREG_SPLIT_NO_EMPTY);
137
            $addr = array_shift($parts);
138
 
139
            // remove IPv6 zone ID (`fe80::1%lo0` => `fe80:1`)
140
            if (strpos($addr, ':') !== false && ($pos = strpos($addr, '%')) !== false) {
141
                $addr = substr($addr, 0, $pos);
142
            }
143
 
144
            if (@inet_pton($addr) === $ip) {
145
                foreach ($parts as $part) {
146
                    $names[] = $part;
147
                }
148
            }
149
        }
150
 
151
        return $names;
152
    }
153
}