1 <?php
2
3 /*
4 * DirectAdmin API Client
5 * (c) Omines Internetbureau B.V. - https://omines.nl/
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11 namespace Omines\DirectAdmin;
12
13 use GuzzleHttp\Client;
14 use GuzzleHttp\Exception\TransferException;
15 use Omines\DirectAdmin\Context\AdminContext;
16 use Omines\DirectAdmin\Context\ResellerContext;
17 use Omines\DirectAdmin\Context\UserContext;
18 use Omines\DirectAdmin\Utility\Conversion;
19
20 /**
21 * DirectAdmin API main class, encapsulating a specific account connection to a single server.
22 *
23 * @author Niels Keurentjes <niels.keurentjes@omines.com>
24 */
25 class DirectAdmin
26 {
27 const ACCOUNT_TYPE_ADMIN = 'admin';
28 const ACCOUNT_TYPE_RESELLER = 'reseller';
29 const ACCOUNT_TYPE_USER = 'user';
30
31 /** @var string */
32 private $authenticatedUser;
33
34 /** @var string */
35 private $username;
36
37 /** @var string */
38 private $password;
39
40 /** @var string */
41 private $baseUrl;
42
43 /** @var Client */
44 private $connection;
45
46 /**
47 * Connects to DirectAdmin with an admin account.
48 *
49 * @param string $url The base URL of the DirectAdmin server
50 * @param string $username The username of the account
51 * @param string $password The password of the account
52 * @param bool $validate Whether to ensure the account exists and is of the correct type
53 * @return AdminContext
54 */
55 public static function connectAdmin($url, $username, $password, $validate = false)
56 {
57 return new AdminContext(new self($url, $username, $password), $validate);
58 }
59
60 /**
61 * Connects to DirectAdmin with a reseller account.
62 *
63 * @param string $url The base URL of the DirectAdmin server
64 * @param string $username The username of the account
65 * @param string $password The password of the account
66 * @param bool $validate Whether to ensure the account exists and is of the correct type
67 * @return ResellerContext
68 */
69 public static function connectReseller($url, $username, $password, $validate = false)
70 {
71 return new ResellerContext(new self($url, $username, $password), $validate);
72 }
73
74 /**
75 * Connects to DirectAdmin with a user account.
76 *
77 * @param string $url The base URL of the DirectAdmin server
78 * @param string $username The username of the account
79 * @param string $password The password of the account
80 * @param bool $validate Whether to ensure the account exists and is of the correct type
81 * @return UserContext
82 */
83 public static function connectUser($url, $username, $password, $validate = false)
84 {
85 return new UserContext(new self($url, $username, $password), $validate);
86 }
87
88 /**
89 * Creates a connection wrapper to DirectAdmin as the specified account.
90 *
91 * @param string $url The base URL of the DirectAdmin server
92 * @param string $username The username of the account
93 * @param string $password The password of the account
94 */
95 protected function __construct($url, $username, $password)
96 {
97 $accounts = explode('|', $username);
98 $this->authenticatedUser = current($accounts);
99 $this->username = end($accounts);
100 $this->password = $password;
101 $this->baseUrl = rtrim($url, '/') . '/';
102 $this->connection = new Client([
103 'base_uri' => $this->baseUrl,
104 'auth' => [$username, $password],
105 ]);
106 }
107
108 /**
109 * Returns the username behind the current connection.
110 *
111 * @return string Currently logged in user's username
112 */
113 public function getUsername()
114 {
115 return $this->username;
116 }
117
118 /**
119 * Invokes the DirectAdmin API with specific options.
120 *
121 * @param string $method HTTP method to use (ie. GET or POST)
122 * @param string $command DirectAdmin API command to invoke
123 * @param array $options Guzzle options to use for the call
124 * @return array The unvalidated response
125 * @throws DirectAdminException If anything went wrong on the network level
126 */
127 public function invokeApi($method, $command, $options = [])
128 {
129 $result = $this->rawRequest($method, '/CMD_API_' . $command, $options);
130 if (!empty($result['error'])) {
131 throw new DirectAdminException("$method to $command failed: $result[details] ($result[text])");
132 }
133 return Conversion::sanitizeArray($result);
134 }
135
136 /**
137 * Returns a clone of the connection logged in as a managed user or reseller.
138 *
139 * @param string $username
140 * @return DirectAdmin
141 */
142 public function loginAs($username)
143 {
144 // DirectAdmin format is to just pipe the accounts together under the master password
145 return new self($this->baseUrl, $this->authenticatedUser . "|{$username}", $this->password);
146 }
147
148 /**
149 * Sends a raw request to DirectAdmin.
150 *
151 * @param string $method
152 * @param string $uri
153 * @param array $options
154 * @return array
155 */
156 private function rawRequest($method, $uri, $options)
157 {
158 try {
159 $response = $this->connection->request($method, $uri, $options);
160 if ($response->getHeader('Content-Type')[0] == 'text/html') {
161 throw new DirectAdminException(sprintf('DirectAdmin API returned text/html to %s %s containing "%s"', $method, $uri, strip_tags($response->getBody()->getContents())));
162 }
163 $body = $response->getBody()->getContents();
164 return Conversion::responseToArray($body);
165 } catch (TransferException $exception) {
166 // Rethrow anything that causes a network issue
167 throw new DirectAdminException(sprintf('%s request to %s failed', $method, $uri), 0, $exception);
168 }
169 }
170 }
171