Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49d0986bd7 | ||
|
|
0ebbb4efac |
27
README.md
27
README.md
@@ -1,6 +1,6 @@
|
||||
## UniFi Controller API client class
|
||||
|
||||
A PHP class that provides access to Ubiquiti's [**UniFi SDN Controller**](https://unifi-sdn.ui.com/) API, versions 4.X.X and 5.X.X of the UniFi SDN Controller software are supported (version 5.12.35 has been confirmed to work) as well as UniFi OS-based controllers (version 5.12.59 has been confirmed to work). This class is used in our API browser tool which can be found [here](https://github.com/Art-of-WiFi/UniFi-API-browser).
|
||||
A PHP class that provides access to Ubiquiti's [**UniFi SDN Controller**](https://unifi-sdn.ui.com/) API, versions 4.X.X and 5.X.X of the UniFi SDN Controller software are supported (version 5.12.66 has been confirmed to work) as well as UbiOS-based controllers (version 5.12.59 has been confirmed to work). This class is used in our API browser tool which can be found [here](https://github.com/Art-of-WiFi/UniFi-API-browser).
|
||||
|
||||
The package can be installed manually or using composer/[packagist](https://packagist.org/packages/art-of-wifi/unifi-api-client) for easy inclusion in your projects.
|
||||
|
||||
@@ -9,11 +9,11 @@ The package can be installed manually or using composer/[packagist](https://pack
|
||||
- a web server with PHP and cURL modules installed (tested on Apache 2.4 with PHP Version 5.6.1 and cURL 7.42.1 and with PHP 7.2.24 and cURL 7.58.0)
|
||||
- network connectivity between this web server and the server and port (normally TCP port 8443) where the UniFi Controller is running
|
||||
|
||||
## UniFi OS Support
|
||||
## UbiOS Support
|
||||
|
||||
Support for UniFi OS-based controllers (UniFi Dream Machine Pro) has been added as of version 1.1.47. The class automatically detects UniFi OS devices and adjusts URLs and several functions/methods accordingly. If your own code applies strict validation of the URL that is passed to the constructor, please adapt your logic to allow URLs without a port suffix when dealing with a UniFi OS-based controller.
|
||||
Support for UbiOS-based controllers (UniFi Dream Machine Pro) has been added as of version 1.1.47. The class automatically detects UbiOS devices and adjusts URLs and several functions/methods accordingly. If your own code applies strict validation of the URL that is passed to the constructor, please adapt your logic to allow URLs without a port suffix when dealing with a UbiOS-based controller.
|
||||
|
||||
Please test all methods you plan on using thoroughly before using the API Client with UniFi OS devices in a production environment.
|
||||
Please test all methods you plan on using thoroughly before using the API Client with UbiOS devices in a production environment.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -100,7 +100,7 @@ Please refer to the `examples/` directory for some more detailed examples which
|
||||
|
||||
## Functions/methods supported
|
||||
|
||||
The class currently supports the following functions/methods to GET/POST/PUT/DELETE data through the UniFi Controller API. Please refer to the source code for more details on the functions/methods and their respective parameters.
|
||||
The class currently supports the following functions/methods to GET/POST/PUT/DELETE data through the UniFi Controller API. Please refer to the comments in the source code for more details on the functions/methods and their respective parameters.
|
||||
|
||||
- login()
|
||||
- logout()
|
||||
@@ -242,15 +242,28 @@ The class currently supports the following functions/methods to GET/POST/PUT/DEL
|
||||
- cancel_rolling_upgrade()
|
||||
- cmd_stat()
|
||||
|
||||
Internal functions, getters/setters:
|
||||
Other functions, getters/setters:
|
||||
|
||||
- set_debug()
|
||||
- get_debug()
|
||||
- set_site()
|
||||
- get_site()
|
||||
- get_cookie() (renamed from getcookie())
|
||||
- set_cookies()
|
||||
- get_cookies()
|
||||
- get_cookie() (renamed from getcookie(), deprecated but still available, use get_cookies() instead)
|
||||
- get_last_results_raw()
|
||||
- get_last_error_message()
|
||||
- set_request_type()
|
||||
- get_request_type()
|
||||
- set_ssl_verify_peer()
|
||||
- get_ssl_verify_peer()
|
||||
- set_ssl_verify_host()
|
||||
- get_ssl_verify_host()
|
||||
- set_connection_timeout()
|
||||
- get_connection_timeout()
|
||||
- set_is_unifi_os()
|
||||
- get_is_unifi_os()
|
||||
|
||||
|
||||
## Need help or have suggestions?
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ $unifi_connection = new UniFi_API\Client($controlleruser, $controllerpassword, $
|
||||
$set_debug_mode = $unifi_connection->set_debug($debug);
|
||||
$loginresults = $unifi_connection->login(); // always true regardless of site id
|
||||
|
||||
foreach ($macs_to_block as &$mac) {
|
||||
foreach ($macs_to_block as $mac) {
|
||||
// block_result is always true even if mac address does not exist :(
|
||||
$block_result = $unifi_connection->block_sta($mac);
|
||||
|
||||
|
||||
339
src/Client.php
339
src/Client.php
@@ -132,96 +132,93 @@ class Client
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether we have a "regular" controller or one based on UniFi OS
|
||||
* first we check whether we have a "regular" controller or one based on UniFi OS
|
||||
*/
|
||||
if (!($ch = $this->get_curl_resource())) {
|
||||
trigger_error('$ch as returned by get_curl_resource() is not a resource');
|
||||
$ch = $this->get_curl_resource();
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_NOBODY, true);
|
||||
curl_setopt($ch, CURLOPT_URL, $this->baseurl . '/');
|
||||
|
||||
/**
|
||||
* execute the cURL request and get the HTTP response code
|
||||
*/
|
||||
curl_exec($ch);
|
||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
trigger_error('cURL error: ' . curl_error($ch));
|
||||
}
|
||||
|
||||
if ($http_code === 200) {
|
||||
$this->is_unifi_os = true;
|
||||
curl_setopt($ch, CURLOPT_REFERER, $this->baseurl . '/login');
|
||||
curl_setopt($ch, CURLOPT_URL, $this->baseurl . '/api/auth/login');
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_NOBODY, true);
|
||||
curl_setopt($ch, CURLOPT_URL, $this->baseurl . '/');
|
||||
curl_setopt($ch, CURLOPT_REFERER, $this->baseurl . '/login');
|
||||
curl_setopt($ch, CURLOPT_URL, $this->baseurl . '/api/login');
|
||||
}
|
||||
|
||||
/**
|
||||
* execute the cURL request and get the HTTP response code
|
||||
*/
|
||||
curl_exec($ch);
|
||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_setopt($ch, CURLOPT_NOBODY, false);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['username' => $this->user, 'password' => $this->password]));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ['content-type: application/json; charset=utf-8']);
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
trigger_error('cURL error: ' . curl_error($ch));
|
||||
}
|
||||
/**
|
||||
* execute the cURL request and get the HTTP response code
|
||||
*/
|
||||
$content = curl_exec($ch);
|
||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
if ($http_code === 200) {
|
||||
$this->is_unifi_os = true;
|
||||
}
|
||||
if (curl_errno($ch)) {
|
||||
trigger_error('cURL error: ' . curl_error($ch));
|
||||
}
|
||||
|
||||
if ($this->is_unifi_os) {
|
||||
curl_setopt($ch, CURLOPT_REFERER, $this->baseurl . '/login');
|
||||
curl_setopt($ch, CURLOPT_URL, $this->baseurl . '/api/auth/login');
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_REFERER, $this->baseurl . '/login');
|
||||
curl_setopt($ch, CURLOPT_URL, $this->baseurl . '/api/login');
|
||||
}
|
||||
if ($this->debug) {
|
||||
print PHP_EOL . '<pre>';
|
||||
print PHP_EOL . '-----------LOGIN-------------' . PHP_EOL;
|
||||
print_r(curl_getinfo($ch));
|
||||
print PHP_EOL . '----------RESPONSE-----------' . PHP_EOL;
|
||||
print $content;
|
||||
print PHP_EOL . '-----------------------------' . PHP_EOL;
|
||||
print '</pre>' . PHP_EOL;
|
||||
}
|
||||
|
||||
curl_setopt($ch, CURLOPT_NOBODY, false);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['username' => $this->user, 'password' => $this->password]));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ['content-type: application/json; charset=utf-8']);
|
||||
/**
|
||||
* based on the HTTP response code we either trigger an error or
|
||||
* extract the cookie from the headers
|
||||
*/
|
||||
if ($http_code === 400 || $http_code === 401) {
|
||||
trigger_error("We received the following HTTP response status: $http_code. Probably a controller login failure");
|
||||
|
||||
/**
|
||||
* execute the cURL request and get the HTTP response code
|
||||
*/
|
||||
$content = curl_exec($ch);
|
||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
return $http_code;
|
||||
}
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
trigger_error('cURL error: ' . curl_error($ch));
|
||||
}
|
||||
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$headers = substr($content, 0, $header_size);
|
||||
$body = trim(substr($content, $header_size));
|
||||
|
||||
if ($this->debug) {
|
||||
print PHP_EOL . '<pre>';
|
||||
print PHP_EOL . '-----------LOGIN-------------' . PHP_EOL;
|
||||
print_r(curl_getinfo($ch));
|
||||
print PHP_EOL . '----------RESPONSE-----------' . PHP_EOL;
|
||||
print $content;
|
||||
print PHP_EOL . '-----------------------------' . PHP_EOL;
|
||||
print '</pre>' . PHP_EOL;
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
/**
|
||||
* based on the HTTP response code we either trigger an error or
|
||||
* extract the cookie from the headers
|
||||
*/
|
||||
if ($http_code === 400) {
|
||||
trigger_error('We received an HTTP response status: 400. Probably a controller login failure');
|
||||
|
||||
return $http_code;
|
||||
}
|
||||
|
||||
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$headers = substr($content, 0, $header_size);
|
||||
$body = trim(substr($content, $header_size));
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
if ($http_code >= 200 && $http_code < 400 && !empty($body)) {
|
||||
preg_match_all('|Set-Cookie: (.*);|Ui', $headers, $results);
|
||||
if (isset($results[1])) {
|
||||
$this->cookies = implode(';', $results[1]);
|
||||
/**
|
||||
* we are good to extract the cookies
|
||||
*/
|
||||
if ($http_code >= 200 && $http_code < 400 && !empty($body)) {
|
||||
preg_match_all('|Set-Cookie: (.*);|Ui', $headers, $results);
|
||||
if (isset($results[1])) {
|
||||
$this->cookies = implode(';', $results[1]);
|
||||
|
||||
/**
|
||||
* accept cookies from regular UniFI controllers or from UniFi OS
|
||||
*/
|
||||
if (strpos($this->cookies, 'unifises') !== false || strpos($this->cookies, 'TOKEN') !== false) {
|
||||
/**
|
||||
* accept cookies from regular UniFI controllers or from UniFi OS
|
||||
* update the cookie value in $_SESSION['unificookie'], if it exists
|
||||
*/
|
||||
if (strpos($this->cookies, 'unifises') !== false || strpos($this->cookies, 'TOKEN') !== false) {
|
||||
/**
|
||||
* update the cookie value in $_SESSION['unificookie'], if it exists
|
||||
*/
|
||||
if (isset($_SESSION['unificookie'])) {
|
||||
$_SESSION['unificookie'] = $this->cookies;
|
||||
}
|
||||
|
||||
return $this->is_loggedin = true;
|
||||
if (isset($_SESSION['unificookie'])) {
|
||||
$_SESSION['unificookie'] = $this->cookies;
|
||||
}
|
||||
|
||||
return $this->is_loggedin = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -240,13 +237,42 @@ class Client
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepare cURL
|
||||
*/
|
||||
$ch = $this->get_curl_resource();
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
|
||||
/**
|
||||
* constuct HTTP request headers as required
|
||||
*/
|
||||
$headers = ['Content-Length: 0'];
|
||||
if ($this->is_unifi_os) {
|
||||
$logout_url = '/api/auth/logout';
|
||||
$logout_path = '/api/auth/logout';
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
|
||||
|
||||
$csrf_token = $this->extract_csrf_token_from_cookie();
|
||||
if ($csrf_token) {
|
||||
$headers[] = 'x-csrf-token: ' . $csrf_token;
|
||||
}
|
||||
} else {
|
||||
$logout_url = '/logout';
|
||||
$logout_path = '/logout';
|
||||
}
|
||||
|
||||
$this->exec_curl($logout_url, []);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($ch, CURLOPT_URL, $this->baseurl . $logout_path);
|
||||
|
||||
/**
|
||||
* execute the cURL request to logout
|
||||
*/
|
||||
$logout = curl_exec($ch);
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
trigger_error('cURL error: ' . curl_error($ch));
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
$this->is_loggedin = false;
|
||||
$this->cookies = '';
|
||||
@@ -3668,8 +3694,8 @@ class Client
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Cookie from UniFi controller
|
||||
* --------------------------------
|
||||
* Get Cookie from UniFi controller (singular and plural)
|
||||
* ------------------------------------------------------
|
||||
* returns the UniFi controller cookie
|
||||
*
|
||||
* NOTES:
|
||||
@@ -3689,12 +3715,22 @@ class Client
|
||||
return $this->cookies;
|
||||
}
|
||||
|
||||
public function get_cookies()
|
||||
{
|
||||
if (!$this->is_loggedin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->cookies;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* other getter/setter functions/methods from here, use with care!
|
||||
******************************************************************/
|
||||
public function get_cookies()
|
||||
|
||||
public function set_cookies($cookies_value)
|
||||
{
|
||||
return $this->cookies;
|
||||
$this->cookies = $cookies_value;
|
||||
}
|
||||
|
||||
public function get_request_type()
|
||||
@@ -3702,21 +3738,6 @@ class Client
|
||||
return $this->request_type;
|
||||
}
|
||||
|
||||
public function get_ssl_verify_peer()
|
||||
{
|
||||
return $this->curl_ssl_verify_peer;
|
||||
}
|
||||
|
||||
public function get_ssl_verify_host()
|
||||
{
|
||||
return $this->curl_ssl_verify_host;
|
||||
}
|
||||
|
||||
public function set_cookies($cookies_value)
|
||||
{
|
||||
$this->cookies = $cookies_value;
|
||||
}
|
||||
|
||||
public function set_request_type($request_type)
|
||||
{
|
||||
|
||||
@@ -3729,19 +3750,9 @@ class Client
|
||||
return true;
|
||||
}
|
||||
|
||||
public function set_connection_timeout($timeout)
|
||||
public function get_ssl_verify_peer()
|
||||
{
|
||||
$this->connect_timeout = $timeout;
|
||||
}
|
||||
|
||||
public function set_last_results_raw($last_results)
|
||||
{
|
||||
$this->last_results_raw = $last_results;
|
||||
}
|
||||
|
||||
public function set_last_error_message($last_error_message)
|
||||
{
|
||||
$this->last_error_message = $last_error_message;
|
||||
return $this->curl_ssl_verify_peer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3759,6 +3770,11 @@ class Client
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_ssl_verify_host()
|
||||
{
|
||||
return $this->curl_ssl_verify_host;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the value for cURL option CURLOPT_SSL_VERIFYHOST, should be 0/false or 2
|
||||
* https://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html
|
||||
@@ -3774,6 +3790,42 @@ class Client
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_is_unifi_os()
|
||||
{
|
||||
return $this->is_unifi_os;
|
||||
}
|
||||
|
||||
public function set_is_unifi_os($is_unifi_os)
|
||||
{
|
||||
if (!in_array($is_unifi_os, [0, false, 1, true])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->is_unifi_os = $is_unifi_os;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function set_connection_timeout($timeout)
|
||||
{
|
||||
$this->connect_timeout = $timeout;
|
||||
}
|
||||
|
||||
public function get_connection_timeout()
|
||||
{
|
||||
return $this->connect_timeout;
|
||||
}
|
||||
|
||||
public function set_last_results_raw($last_results)
|
||||
{
|
||||
$this->last_results_raw = $last_results;
|
||||
}
|
||||
|
||||
public function set_last_error_message($last_error_message)
|
||||
{
|
||||
$this->last_error_message = $last_error_message;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* internal (private and protected) functions from here:
|
||||
****************************************************************/
|
||||
@@ -4055,58 +4107,69 @@ class Client
|
||||
*/
|
||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
if ($http_code == 401) {
|
||||
curl_close($ch);
|
||||
if ($this->debug) {
|
||||
error_log('cURL debug: needed to reconnect to UniFi controller');
|
||||
}
|
||||
|
||||
/**
|
||||
* explicitly clear the expired Cookie/Token before logging in again
|
||||
* explicitly clear the expired Cookie/Token and logging out before logging in again
|
||||
*/
|
||||
if (isset($_SESSION['unificookie'])) {
|
||||
$_SESSION['unificookie'] = '';
|
||||
$this->is_loggedin = false;
|
||||
}
|
||||
|
||||
$this->is_loggedin = false;
|
||||
|
||||
/**
|
||||
* then login again
|
||||
*/
|
||||
$this->login();
|
||||
|
||||
/**
|
||||
* when login was successful, execute the same command again
|
||||
* when login was successful, execute the same cURL request again
|
||||
*/
|
||||
if ($this->is_loggedin) {
|
||||
return $this->exec_curl($path, $payload);
|
||||
}
|
||||
} else {
|
||||
if ($this->debug) {
|
||||
print PHP_EOL . '<pre>';
|
||||
print PHP_EOL . '---------cURL INFO-----------' . PHP_EOL;
|
||||
print_r(curl_getinfo($ch));
|
||||
print PHP_EOL . '-------URL & PAYLOAD---------' . PHP_EOL;
|
||||
print $url . PHP_EOL;
|
||||
if (empty($json_payload)) {
|
||||
print 'empty payload';
|
||||
} else {
|
||||
print $json_payload;
|
||||
$content = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
trigger_error('cURL error: ' . curl_error($ch));
|
||||
curl_close($ch);
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
curl_close($ch);
|
||||
|
||||
print PHP_EOL . '----------RESPONSE-----------' . PHP_EOL;
|
||||
print $content;
|
||||
print PHP_EOL . '-----------------------------' . PHP_EOL;
|
||||
print '</pre>' . PHP_EOL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->debug) {
|
||||
print PHP_EOL . '<pre>';
|
||||
print PHP_EOL . '---------cURL INFO-----------' . PHP_EOL;
|
||||
print_r(curl_getinfo($ch));
|
||||
print PHP_EOL . '-------URL & PAYLOAD---------' . PHP_EOL;
|
||||
print $url . PHP_EOL;
|
||||
if (empty($json_payload)) {
|
||||
print 'empty payload';
|
||||
} else {
|
||||
print $json_payload;
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
/**
|
||||
* set request_type value back to default, just in case
|
||||
*/
|
||||
$this->request_type = 'GET';
|
||||
|
||||
return $content;
|
||||
print PHP_EOL . '----------RESPONSE-----------' . PHP_EOL;
|
||||
print $content;
|
||||
print PHP_EOL . '-----------------------------' . PHP_EOL;
|
||||
print '</pre>' . PHP_EOL;
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
/**
|
||||
* set request_type value back to default, just in case
|
||||
*/
|
||||
$this->request_type = 'GET';
|
||||
|
||||
return $content;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user