Merge pull request #5987 from WoltLab/acp-dahsboard-box-hight
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / io / RemoteFile.class.php
CommitLineData
158bd3ca 1<?php
a9229942 2
158bd3ca 3namespace wcf\system\io;
a9229942 4
158bd3ca
TD
5use wcf\system\exception\SystemException;
6
7/**
8 * The RemoteFile class opens a connection to a remote host as a file.
a9229942
TD
9 *
10 * @author Marcel Werk
11 * @copyright 2001-2019 WoltLab GmbH
12 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
158bd3ca 13 */
a9229942
TD
14class RemoteFile extends File
15{
16 /**
17 * host address
18 * @var string
19 */
20 protected $host = '';
21
22 /**
23 * port
24 * @var int
25 */
26 protected $port = 0;
27
28 /**
29 * error number
30 * @var int
31 */
32 protected $errorNumber = 0;
33
34 /**
35 * error description
36 * @var string
37 */
38 protected $errorDesc = '';
39
40 /**
41 * true if PHP supports SSL/TLS
42 * @var bool
43 */
55a3a842 44 private static $hasSSLSupport;
a9229942
TD
45
46 /** @noinspection PhpMissingParentConstructorInspection */
47
48 /**
49 * Opens a new connection to a remote host.
50 *
51 * @param string $host
52 * @param int $port
53 * @param int $timeout
54 * @param array $options
55 * @throws SystemException
56 */
57 public function __construct($host, $port, $timeout = 30, $options = [])
58 {
59 $this->host = $host;
60 $this->port = $port;
61
62 if (!\preg_match('/^[a-z0-9]+:/', $this->host)) {
63 $this->host = 'tcp://' . $this->host;
64 }
65
66 $context = \stream_context_create($options);
67 try {
68 $this->resource = \stream_socket_client(
69 $this->host . ':' . $this->port,
70 $this->errorNumber,
71 $this->errorDesc,
72 $timeout,
73 \STREAM_CLIENT_CONNECT,
74 $context
75 );
76 if ($this->resource === false) {
77 throw new \Exception('stream_socket_client returned false: ' . $this->errorDesc, $this->errorNumber);
78 }
79 } catch (\Exception $e) {
80 throw new SystemException('Can not connect to ' . $host, 0, $this->errorDesc, $e);
81 }
82
83 \stream_set_timeout($this->resource, $timeout);
84 }
85
86 /**
87 * Returns the error number of the last error.
88 *
89 * @return int
90 */
91 public function getErrorNumber()
92 {
93 return $this->errorNumber;
94 }
95
96 /**
97 * Returns the error description of the last error.
98 *
99 * @return string
100 */
101 public function getErrorDesc()
102 {
103 return $this->errorDesc;
104 }
105
106 /**
107 * Switches TLS support for this connection.
108 * Usually used in combination with 'STARTTLS'
109 *
110 * @param bool $enable Whether TLS support should be enabled
111 * @return bool True on success, false otherwise
112 */
113 public function setTLS($enable)
114 {
115 if (!$this->hasTLSSupport()) {
116 return false;
117 }
118
119 $cryptoType = \STREAM_CRYPTO_METHOD_TLS_CLIENT;
120
121 // PHP 5.6.8+ defines STREAM_CRYPTO_METHOD_TLS_CLIENT as STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT for BC reasons.
122 // STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT was introduced in PHP 5.6.8, but is not exposed to userland. Try to use
123 // it for forward compatibility.
124 //
125 // As of PHP 7.2+ STREAM_CRYPTO_METHOD_TLS_CLIENT is equivalent to STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT.
126 // see: https://wiki.php.net/rfc/improved-tls-constants
127 // see: https://github.com/php/php-src/blob/197cac65fdf712effb19ad3e40688ceb7ebc7f7d/main/streams/php_stream_transport.h#L173-L175
128 if (\defined('STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT')) {
129 $cryptoType |= STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT;
130 }
131
132 // Add bits for all known TLS versions for the reasons above.
133 if (\defined('STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT')) {
134 $cryptoType |= \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT;
135 }
136 if (\defined('STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT')) {
137 $cryptoType |= \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
138 }
139 if (\defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
140 $cryptoType |= \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
141 }
142 if (\defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT')) {
143 $cryptoType |= \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT;
144 }
145
146 return \stream_socket_enable_crypto($this->resource, $enable, $cryptoType);
147 }
148
149 /**
150 * Returns whether TLS support is available.
151 *
152 * @return bool
153 */
154 public function hasTLSSupport()
155 {
156 return \function_exists('stream_socket_enable_crypto');
157 }
158
159 /**
3f25039e 160 * @deprecated 6.0 This method is effectively returning bogus data, because the majority of TLS communication uses Guzzle/cURL.
a9229942
TD
161 */
162 public static function supportsSSL()
163 {
164 if (static::$hasSSLSupport === null) {
165 static::$hasSSLSupport = false;
166
167 $transports = \stream_get_transports();
168 foreach ($transports as $transport) {
169 if (\preg_match('~^(ssl(v[23])?|tls(v[0-9\.]+)?)$~', $transport)) {
170 static::$hasSSLSupport = true;
171 break;
172 }
173 }
174 }
175
176 return static::$hasSSLSupport;
177 }
178
179 /**
3f25039e 180 * @deprecated 6.0 See RemoteFile::supportsSSL(). The implementation is a noop.
a9229942
TD
181 */
182 public static function disableSSL()
183 {
a9229942 184 }
dcb3a44c 185}