a97a65edeeff89303309f5dfb4c2726b1b68ec1a
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / io / RemoteFile.class.php
1 <?php
2 namespace wcf\system\io;
3 use wcf\system\exception\SystemException;
4
5 /**
6 * The RemoteFile class opens a connection to a remote host as a file.
7 *
8 * @author Marcel Werk
9 * @copyright 2001-2019 WoltLab GmbH
10 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
11 * @package WoltLabSuite\Core\System\Io
12 */
13 class RemoteFile extends File {
14 /**
15 * host address
16 * @var string
17 */
18 protected $host = '';
19
20 /**
21 * port
22 * @var integer
23 */
24 protected $port = 0;
25
26 /**
27 * error number
28 * @var integer
29 */
30 protected $errorNumber = 0;
31
32 /**
33 * error description
34 * @var string
35 */
36 protected $errorDesc = '';
37
38 /**
39 * true if PHP supports SSL/TLS
40 * @var boolean
41 */
42 private static $hasSSLSupport = null;
43
44 /** @noinspection PhpMissingParentConstructorInspection */
45 /**
46 * Opens a new connection to a remote host.
47 *
48 * @param string $host
49 * @param integer $port
50 * @param integer $timeout
51 * @param array $options
52 * @throws SystemException
53 */
54 public function __construct($host, $port, $timeout = 30, $options = []) {
55 $this->host = $host;
56 $this->port = $port;
57
58 if (!preg_match('/^[a-z0-9]+:/', $this->host)) $this->host = 'tcp://'.$this->host;
59
60 $context = stream_context_create($options);
61 $this->resource = @stream_socket_client($this->host.':'.$this->port, $this->errorNumber, $this->errorDesc, $timeout, STREAM_CLIENT_CONNECT, $context);
62 if ($this->resource === false) {
63 throw new SystemException('Can not connect to ' . $host, 0, $this->errorDesc);
64 }
65
66 stream_set_timeout($this->resource, $timeout);
67 }
68
69 /**
70 * Returns the error number of the last error.
71 *
72 * @return integer
73 */
74 public function getErrorNumber() {
75 return $this->errorNumber;
76 }
77
78 /**
79 * Returns the error description of the last error.
80 *
81 * @return string
82 */
83 public function getErrorDesc() {
84 return $this->errorDesc;
85 }
86
87 /**
88 * Switches TLS support for this connection.
89 * Usually used in combination with 'STARTTLS'
90 *
91 * @param boolean $enable Whether TLS support should be enabled
92 * @return boolean True on success, false otherwise
93 */
94 public function setTLS($enable) {
95 if (!$this->hasTLSSupport()) return false;
96
97 $cryptoType = STREAM_CRYPTO_METHOD_TLS_CLIENT;
98
99 // PHP 5.6.8+ defines STREAM_CRYPTO_METHOD_TLS_CLIENT as STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT for BC reasons.
100 // STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT was introduced in PHP 5.6.8, but is not exposed to userland. Try to use
101 // it for forward compatibility.
102 if (defined('STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT')) $cryptoType = STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT;
103
104 // Add bits for all known TLS versions for the reasons above.
105 if (defined('STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT')) $cryptoType |= STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT;
106 if (defined('STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT')) $cryptoType |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
107 if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) $cryptoType |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
108
109 return stream_socket_enable_crypto($this->resource, $enable, $cryptoType);
110 }
111
112 /**
113 * Returns whether TLS support is available.
114 *
115 * @return boolean
116 */
117 public function hasTLSSupport() {
118 return function_exists('stream_socket_enable_crypto');
119 }
120
121 /**
122 * Returns true if PHP supports SSL/TLS.
123 *
124 * @return boolean
125 */
126 public static function supportsSSL() {
127 if (static::$hasSSLSupport === null) {
128 static::$hasSSLSupport = false;
129
130 $transports = stream_get_transports();
131 foreach ($transports as $transport) {
132 if (preg_match('~^(ssl(v[23])?|tls(v[0-9\.]+)?)$~', $transport)) {
133 static::$hasSSLSupport = true;
134 break;
135 }
136 }
137 }
138
139 return static::$hasSSLSupport;
140 }
141
142 /**
143 * Disables SSL/TLS support on runtime regardless if PHP is theoretically capable of it.
144 */
145 public static function disableSSL() {
146 static::$hasSSLSupport = false;
147 }
148 }