Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
903d3e47d5 | ||
|
|
e72dea7357 | ||
|
|
17d895076f | ||
|
|
961d692125 | ||
|
|
796ad9a82d | ||
|
|
a3fc0732e2 |
12
README.md
12
README.md
@@ -1,15 +1,21 @@
|
|||||||
## UniFi Controller API client class
|
## UniFi Controller API client class
|
||||||
|
|
||||||
A PHP class which 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). It's a standalone version of the class which 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.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).
|
||||||
|
|
||||||
This class can be installed manually or using composer/[packagist](https://packagist.org/packages/art-of-wifi/unifi-api-client) for easy inclusion in your projects.
|
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.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- 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)
|
- 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
|
- network connectivity between this web server and the server and port (normally TCP port 8443) where the UniFi Controller is running
|
||||||
|
|
||||||
## Installation ##
|
## UniFi OS 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.
|
||||||
|
|
||||||
|
Please test all methods you plan on using thoroughly before using the API Client with UniFi OS devices in a production environment.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
You can use [Composer](#composer), [Git](#git) or simply [Download the Release](#download-the-release) to install the API client class.
|
You can use [Composer](#composer), [Git](#git) or simply [Download the Release](#download-the-release) to install the API client class.
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
$controlleruser = ''; // the user name for access to the UniFi Controller
|
$controlleruser = ''; // the user name for access to the UniFi Controller
|
||||||
$controllerpassword = ''; // the password for access to the UniFi Controller
|
$controllerpassword = ''; // the password for access to the UniFi Controller
|
||||||
$controllerurl = ''; // full url to the UniFi Controller, eg. 'https://22.22.11.11:8443'
|
$controllerurl = ''; // full url to the UniFi Controller, eg. 'https://22.22.11.11:8443', for UniFi OS-based
|
||||||
$controllerversion = ''; // the version of the Controller software, eg. '4.6.6' (must be at least 4.0.0)
|
// controllers a port suffix isn't required, no trailing slashes should be added
|
||||||
|
$controllerversion = ''; // the version of the Controller software, e.g. '4.6.6' (must be at least 4.0.0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set to true (without quotes) to enable debug output to the browser and the PHP error log
|
* set to true (without quotes) to enable debug output to the browser and the PHP error log
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ require_once('config.php');
|
|||||||
* Check whether the cURL module supports SSL
|
* Check whether the cURL module supports SSL
|
||||||
*/
|
*/
|
||||||
if (!curl_version()['features'] & CURL_VERSION_SSL) {
|
if (!curl_version()['features'] & CURL_VERSION_SSL) {
|
||||||
print 'SSL is not supported with this cURL installation!' . PHP_EOL;
|
print PHP_EOL . 'SSL is not supported with this cURL installation!' . PHP_EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,44 +25,48 @@ if (!curl_version()['features'] & CURL_VERSION_SSL) {
|
|||||||
*/
|
*/
|
||||||
$ch = curl_init();
|
$ch = curl_init();
|
||||||
|
|
||||||
/**
|
if (is_resource($ch)) {
|
||||||
* Set the required cURL options
|
/**
|
||||||
*/
|
* If we have a resource, we proceed and set the required cURL options
|
||||||
curl_setopt($ch, CURLOPT_URL, $controllerurl);
|
*/
|
||||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
|
curl_setopt($ch, CURLOPT_URL, $controllerurl);
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This cURL option can have a value of 0-6
|
* This cURL option can have a value of 0-6
|
||||||
* see this URL for more details:
|
* see this URL for more details:
|
||||||
* http://php.net/manual/en/function.curl-setopt.php
|
* http://php.net/manual/en/function.curl-setopt.php
|
||||||
* 0 is the default value and is used by the PHP API client class
|
* 0 is the default value and is used by the PHP API client class
|
||||||
*/
|
*/
|
||||||
curl_setopt($ch, CURLOPT_SSLVERSION, 0);
|
curl_setopt($ch, CURLOPT_SSLVERSION, 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Be more verbose
|
* Be more verbose
|
||||||
*/
|
*/
|
||||||
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* $results contains the output as returned by the cURL request,
|
* $results contains the output as returned by the cURL request,
|
||||||
* returns true when successful, else returns false
|
* returns true when successful, else returns false
|
||||||
*/
|
*/
|
||||||
print 'verbose output from the cURL request:' . PHP_EOL;
|
print PHP_EOL . 'verbose output from the cURL request:' . PHP_EOL;
|
||||||
$results = curl_exec($ch);
|
$results = curl_exec($ch);
|
||||||
|
|
||||||
print PHP_EOL . 'curl_getinfo output:' . PHP_EOL;
|
print PHP_EOL . 'curl_getinfo output:' . PHP_EOL;
|
||||||
print_r(curl_getinfo($ch));
|
print_r(curl_getinfo($ch));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If we receive a cURL error, output it before the results
|
* If we receive a cURL error, output it before the results
|
||||||
*/
|
*/
|
||||||
if (curl_errno($ch)) {
|
if (curl_errno($ch)) {
|
||||||
print PHP_EOL . 'cURL error: ' . curl_error($ch) . PHP_EOL;
|
print PHP_EOL . 'cURL error: ' . curl_error($ch) . PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
print PHP_EOL . '$results:' . PHP_EOL;
|
||||||
|
print_r($results);
|
||||||
|
print PHP_EOL;
|
||||||
|
} else {
|
||||||
|
print PHP_EOL . 'ERROR: cURL could not be initialized!' . PHP_EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
print PHP_EOL . '$results:' . PHP_EOL;
|
|
||||||
print_r($results);
|
|
||||||
print PHP_EOL;
|
|
||||||
@@ -43,7 +43,8 @@ function update_ports($running_config, $ports, $poe_mode){
|
|||||||
/**
|
/**
|
||||||
* Update already non-default ports
|
* Update already non-default ports
|
||||||
*/
|
*/
|
||||||
for($i = 0; $i < count($running_config); $i++){
|
$running_config_count = count($running_config);
|
||||||
|
for($i = 0; $i < $running_config_count; $i++){
|
||||||
if(in_array($running_config[$i]->port_idx, $ports)){
|
if(in_array($running_config[$i]->port_idx, $ports)){
|
||||||
$running_config[$i]->poe_mode = $poe_mode;
|
$running_config[$i]->poe_mode = $poe_mode;
|
||||||
unset($ports[array_search($running_config[$i]->port_idx, $ports)]);
|
unset($ports[array_search($running_config[$i]->port_idx, $ports)]);
|
||||||
@@ -71,8 +72,8 @@ $current_conf = $data[0]->port_overrides;
|
|||||||
/**
|
/**
|
||||||
* This reads in the values provided via URL or in the command line, if nothing is set than it will poe_mode will be set to "auto"
|
* This reads in the values provided via URL or in the command line, if nothing is set than it will poe_mode will be set to "auto"
|
||||||
*/
|
*/
|
||||||
if (isset($_GET[poe_mode])) {
|
if (isset($_GET['poe_mode'])) {
|
||||||
$poe_mode = $_GET[poe_mode];
|
$poe_mode = $_GET['poe_mode'];
|
||||||
} elseif (isset($argv[1])) {
|
} elseif (isset($argv[1])) {
|
||||||
$poe_mode = $argv[1];
|
$poe_mode = $argv[1];
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
554
src/Client.php
554
src/Client.php
@@ -2,7 +2,7 @@
|
|||||||
/**
|
/**
|
||||||
* This file is part of the art-of-wifi/unifi-api-client package
|
* This file is part of the art-of-wifi/unifi-api-client package
|
||||||
*
|
*
|
||||||
* This UniFi API client is based on the work done by the following developers:
|
* This UniFi API client Class is based on the work done by the following developers:
|
||||||
* domwo: http://community.ubnt.com/t5/UniFi-Wireless/little-php-class-for-unifi-api/m-p/603051
|
* domwo: http://community.ubnt.com/t5/UniFi-Wireless/little-php-class-for-unifi-api/m-p/603051
|
||||||
* fbagnol: https://github.com/fbagnol/class.unifi.php
|
* fbagnol: https://github.com/fbagnol/class.unifi.php
|
||||||
* and the API as published by Ubiquiti:
|
* and the API as published by Ubiquiti:
|
||||||
@@ -17,40 +17,44 @@
|
|||||||
namespace UniFi_API;
|
namespace UniFi_API;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the UniFi API client class
|
* the UniFi API client Class
|
||||||
*/
|
*/
|
||||||
class Client
|
class Client
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* private properties
|
* private and protected properties
|
||||||
*/
|
*/
|
||||||
protected $baseurl = 'https://127.0.0.1:8443';
|
protected $baseurl = 'https://127.0.0.1:8443';
|
||||||
protected $user = '';
|
protected $user = '';
|
||||||
protected $password = '';
|
protected $password = '';
|
||||||
protected $site = 'default';
|
protected $site = 'default';
|
||||||
protected $version = '5.6.39';
|
protected $version = '5.6.39';
|
||||||
protected $debug = false;
|
protected $debug = false;
|
||||||
protected $is_loggedin = false;
|
protected $is_loggedin = false;
|
||||||
private $cookies = '';
|
protected $is_unifi_os = false;
|
||||||
private $request_type = 'POST';
|
private $cookies = '';
|
||||||
private $connect_timeout = 10;
|
private $request_type = 'GET';
|
||||||
private $last_results_raw = null;
|
private $request_types_allowed = ['GET', 'POST', 'PUT', 'DELETE'];
|
||||||
private $last_error_message = null;
|
private $connect_timeout = 10;
|
||||||
private $curl_ssl_verify_peer = false;
|
private $last_results_raw = null;
|
||||||
private $curl_ssl_verify_host = false;
|
private $last_error_message = null;
|
||||||
|
private $curl_ssl_verify_peer = false;
|
||||||
|
private $curl_ssl_verify_host = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct an instance of the UniFi API client class
|
* Construct an instance of the UniFi API client Class
|
||||||
* ---------------------------------------------------
|
* ---------------------------------------------------
|
||||||
* return a new class instance
|
* return a new class instance
|
||||||
* required parameter <user> = string; user name to use when connecting to the UniFi controller
|
* required parameter <user> = string; user name to use when connecting to the UniFi controller
|
||||||
* required parameter <password> = string; password to use when connecting to the UniFi controller
|
* required parameter <password> = string; password to use when connecting to the UniFi controller
|
||||||
* optional parameter <baseurl> = string; base URL of the UniFi controller, *must* include "https://" prefix and port suffix (:8443)
|
* optional parameter <baseurl> = string; base URL of the UniFi controller which *must* include "https://" prefix,
|
||||||
|
* a port suffix (e.g. :8443) is required for non-UniFi OS controllers,
|
||||||
|
* do not add trailing slashes
|
||||||
* optional parameter <site> = string; short site name to access, defaults to "default"
|
* optional parameter <site> = string; short site name to access, defaults to "default"
|
||||||
* optional parameter <version> = string; the version number of the controller, defaults to "5.4.16"
|
* optional parameter <version> = string; the version number of the controller, defaults to "5.4.16"
|
||||||
* optional parameter <ssl_verify> = boolean; whether to validate the controller's SSL certificate or not, a value of true is
|
* optional parameter <ssl_verify> = boolean; whether to validate the controller's SSL certificate or not, a value of true is
|
||||||
* recommended for production environments to prevent potential MitM attacks, default value (false)
|
* recommended for production environments to prevent potential MitM attacks, default value (false)
|
||||||
* is to not validate the controller certificate
|
* disables validation of the controller certificate
|
||||||
*/
|
*/
|
||||||
public function __construct($user, $password, $baseurl = '', $site = '', $version = '', $ssl_verify = false)
|
public function __construct($user, $password, $baseurl = '', $site = '', $version = '', $ssl_verify = false)
|
||||||
{
|
{
|
||||||
@@ -80,13 +84,20 @@ class Client
|
|||||||
|
|
||||||
$this->check_base_url();
|
$this->check_base_url();
|
||||||
$this->check_site($this->site);
|
$this->check_site($this->site);
|
||||||
$this->update_unificookie();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is be called as soon as there are no other references to the Class instance
|
||||||
|
* https://www.php.net/manual/en/language.oop5.decon.php
|
||||||
|
*
|
||||||
|
* NOTES:
|
||||||
|
* to force the Class instance to log out automatically upon destruct, simply call logout() or unset
|
||||||
|
* $_SESSION['unificookie'] at the end of your code
|
||||||
|
*/
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* if user has $_SESSION['unificookie'] set, do not logout here
|
* if $_SESSION['unificookie'] is set, do not logout here
|
||||||
*/
|
*/
|
||||||
if (isset($_SESSION['unificookie'])) {
|
if (isset($_SESSION['unificookie'])) {
|
||||||
return;
|
return;
|
||||||
@@ -101,39 +112,73 @@ class Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Login to UniFi Controller
|
* Login to the UniFi controller
|
||||||
* -------------------------
|
* -----------------------------
|
||||||
* returns true upon success
|
* returns true upon success
|
||||||
*/
|
*/
|
||||||
public function login()
|
public function login()
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* if $_SESSION['unificookie'] is set, skip the login
|
* if already logged in we skip the login process
|
||||||
*/
|
*/
|
||||||
if (isset($_SESSION['unificookie'])) {
|
if ($this->is_loggedin === true) {
|
||||||
return $this->is_loggedin = true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_resource($ch = $this->get_curl_resource())) {
|
if ($this->update_unificookie()) {
|
||||||
|
$this->is_loggedin = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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');
|
trigger_error('$ch as returned by get_curl_resource() is not a resource');
|
||||||
} else {
|
} else {
|
||||||
curl_setopt($ch, CURLOPT_HEADER, 1);
|
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||||
curl_setopt($ch, CURLOPT_REFERER, $this->baseurl . '/login');
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
curl_setopt($ch, CURLOPT_URL, $this->baseurl . '/api/login');
|
curl_setopt($ch, CURLOPT_NOBODY, true);
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['username' => $this->user, 'password' => $this->password]));
|
curl_setopt($ch, CURLOPT_URL, $this->baseurl . '/');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* execute the cURL request
|
* execute the cURL request and get the HTTP response code
|
||||||
*/
|
*/
|
||||||
$content = curl_exec($ch);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
|
||||||
|
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']);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute the cURL request and get the HTTP response code
|
||||||
|
*/
|
||||||
|
$content = curl_exec($ch);
|
||||||
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
|
||||||
if (curl_errno($ch)) {
|
if (curl_errno($ch)) {
|
||||||
trigger_error('cURL error: ' . curl_error($ch));
|
trigger_error('cURL error: ' . curl_error($ch));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->debug) {
|
if ($this->debug) {
|
||||||
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
|
||||||
|
|
||||||
print PHP_EOL . '<pre>';
|
print PHP_EOL . '<pre>';
|
||||||
print PHP_EOL . '-----------LOGIN-------------' . PHP_EOL;
|
print PHP_EOL . '-----------LOGIN-------------' . PHP_EOL;
|
||||||
print_r(curl_getinfo($ch));
|
print_r(curl_getinfo($ch));
|
||||||
@@ -143,28 +188,39 @@ class Client
|
|||||||
print '</pre>' . PHP_EOL;
|
print '</pre>' . PHP_EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||||
$headers = substr($content, 0, $header_size);
|
$headers = substr($content, 0, $header_size);
|
||||||
$body = trim(substr($content, $header_size));
|
$body = trim(substr($content, $header_size));
|
||||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
||||||
|
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
|
|
||||||
preg_match_all('|Set-Cookie: (.*);|Ui', $headers, $results);
|
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]);
|
||||||
|
|
||||||
if (isset($results[1])) {
|
/**
|
||||||
$this->cookies = implode(';', $results[1]);
|
* accept cookies from regular UniFI controllers or from UniFi OS
|
||||||
if (!empty($body)) {
|
*/
|
||||||
if (($http_code >= 200) && ($http_code < 400)) {
|
if (strpos($this->cookies, 'unifises') !== false || strpos($this->cookies, 'TOKEN') !== false) {
|
||||||
if (strpos($this->cookies, 'unifises') !== false) {
|
/**
|
||||||
return $this->is_loggedin = true;
|
* update the cookie value in $_SESSION['unificookie'], if it exists
|
||||||
|
*/
|
||||||
|
if (isset($_SESSION['unificookie'])) {
|
||||||
|
$_SESSION['unificookie'] = $this->cookies;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($http_code === 400) {
|
return $this->is_loggedin = true;
|
||||||
trigger_error('We have received an HTTP response status: 400. Probably a controller login failure');
|
|
||||||
|
|
||||||
return $http_code;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,8 +230,8 @@ class Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logout from UniFi Controller
|
* Logout from the UniFi controller
|
||||||
* ----------------------------
|
* --------------------------------
|
||||||
* returns true upon success
|
* returns true upon success
|
||||||
*/
|
*/
|
||||||
public function logout()
|
public function logout()
|
||||||
@@ -184,7 +240,14 @@ class Client
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->exec_curl('/logout');
|
if ($this->is_unifi_os) {
|
||||||
|
$logout_url = '/api/auth/logout';
|
||||||
|
} else {
|
||||||
|
$logout_url = '/logout';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->exec_curl($logout_url, []);
|
||||||
|
|
||||||
$this->is_loggedin = false;
|
$this->is_loggedin = false;
|
||||||
$this->cookies = '';
|
$this->cookies = '';
|
||||||
|
|
||||||
@@ -317,7 +380,8 @@ class Client
|
|||||||
* required parameter <macs> = array of client MAC addresses
|
* required parameter <macs> = array of client MAC addresses
|
||||||
*
|
*
|
||||||
* NOTE:
|
* NOTE:
|
||||||
* only supported with controller versions 5.9.X and higher
|
* only supported with controller versions 5.9.X and higher, can be
|
||||||
|
* slow (up to 5 minutes) on larger controllers
|
||||||
*/
|
*/
|
||||||
public function forget_sta($macs)
|
public function forget_sta($macs)
|
||||||
{
|
{
|
||||||
@@ -341,15 +405,16 @@ class Client
|
|||||||
* can be obtained from the output of list_usergroups()
|
* can be obtained from the output of list_usergroups()
|
||||||
* optional parameter <name> = name to be given to the new user/client-device
|
* optional parameter <name> = name to be given to the new user/client-device
|
||||||
* optional parameter <note> = note to be applied to the new user/client-device
|
* optional parameter <note> = note to be applied to the new user/client-device
|
||||||
|
* optional parameter <is_guest> = boolean; defines whether the new user/client-device is a guest or not
|
||||||
|
* optional parameter <is_wired> = boolean; defines whether the new user/client-device is wired or not
|
||||||
*/
|
*/
|
||||||
public function create_user($mac, $user_group_id, $name = null, $note = null)
|
public function create_user($mac, $user_group_id, $name = null, $note = null, $is_guest = null, $is_wired = null)
|
||||||
{
|
{
|
||||||
if (!$this->is_loggedin) {
|
if (!$this->is_loggedin) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->request_type = 'POST';
|
$new_user = ['mac' => strtolower($mac), 'usergroup_id' => $user_group_id];
|
||||||
$new_user = ['mac' => strtolower($mac), 'usergroup_id' => $user_group_id];
|
|
||||||
if (!is_null($name)) {
|
if (!is_null($name)) {
|
||||||
$new_user['name'] = $name;
|
$new_user['name'] = $name;
|
||||||
}
|
}
|
||||||
@@ -359,6 +424,14 @@ class Client
|
|||||||
$new_user['noted'] = true;
|
$new_user['noted'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!is_null($is_guest) && is_bool($is_guest)) {
|
||||||
|
$new_user['is_guest'] = $is_guest;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($is_wired) && is_bool($is_wired)) {
|
||||||
|
$new_user['is_wired'] = $is_wired;
|
||||||
|
}
|
||||||
|
|
||||||
$payload = ['objects' => [['data' => $new_user]]];
|
$payload = ['objects' => [['data' => $new_user]]];
|
||||||
$response = $this->exec_curl('/api/s/' . $this->site . '/group/user', $payload);
|
$response = $this->exec_curl('/api/s/' . $this->site . '/group/user', $payload);
|
||||||
|
|
||||||
@@ -1091,9 +1164,8 @@ class Client
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->request_type = 'POST';
|
$payload = ['name' => $group_name, 'qos_rate_max_down' => intval($group_dn), 'qos_rate_max_up' => intval($group_up)];
|
||||||
$payload = ['name' => $group_name, 'qos_rate_max_down' => intval($group_dn), 'qos_rate_max_up' => intval($group_up)];
|
$response = $this->exec_curl('/api/s/' . $this->site . '/rest/usergroup', $payload);
|
||||||
$response = $this->exec_curl('/api/s/' . $this->site . '/rest/usergroup', $payload);
|
|
||||||
|
|
||||||
return $this->process_response($response);
|
return $this->process_response($response);
|
||||||
}
|
}
|
||||||
@@ -1182,7 +1254,6 @@ class Client
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->request_type = 'POST';
|
|
||||||
$payload = ['name' => $group_name, 'group_type' => $group_type, 'group_members' => $group_members];
|
$payload = ['name' => $group_name, 'group_type' => $group_type, 'group_members' => $group_members];
|
||||||
$response = $this->exec_curl('/api/s/' . $this->site . '/rest/firewallgroup', $payload);
|
$response = $this->exec_curl('/api/s/' . $this->site . '/rest/firewallgroup', $payload);
|
||||||
|
|
||||||
@@ -1763,12 +1834,8 @@ class Client
|
|||||||
* restart devices, default value is false. With versions < 5.9.X this only applies
|
* restart devices, default value is false. With versions < 5.9.X this only applies
|
||||||
* when readonly is true.
|
* when readonly is true.
|
||||||
*/
|
*/
|
||||||
public function assign_existing_admin(
|
public function assign_existing_admin($admin_id, $readonly = false, $device_adopt = false, $device_restart = false)
|
||||||
$admin_id,
|
{
|
||||||
$readonly = false,
|
|
||||||
$device_adopt = false,
|
|
||||||
$device_restart = false
|
|
||||||
) {
|
|
||||||
if (!$this->is_loggedin) {
|
if (!$this->is_loggedin) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1929,8 +1996,7 @@ class Client
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->request_type = 'POST';
|
$payload = ['name' => $name, 'x_password' => $x_password];
|
||||||
$payload = ['name' => $name, 'x_password' => $x_password];
|
|
||||||
if (isset($note)) {
|
if (isset($note)) {
|
||||||
$payload['note'] = trim($note);
|
$payload['note'] = trim($note);
|
||||||
}
|
}
|
||||||
@@ -2079,6 +2145,32 @@ class Client
|
|||||||
return $this->process_response($response);
|
return $this->process_response($response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List filtered DPI stats
|
||||||
|
* -----------------------
|
||||||
|
* returns an array of fileterd DPI stats
|
||||||
|
* optional parameter <type> = whether to returns stats by app or by category, valid values:
|
||||||
|
* 'by_cat' or 'by_app'
|
||||||
|
* optional parameter <cat_filter> = an array containing numeric category ids to filter by,
|
||||||
|
* only to be combined with a "by_app" value for $type
|
||||||
|
*/
|
||||||
|
public function list_dpi_stats_filtered($type = 'by_cat', $cat_filter = null)
|
||||||
|
{
|
||||||
|
if (!$this->is_loggedin || !in_array($type, ['by_cat', 'by_app'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = ['type' => $type];
|
||||||
|
|
||||||
|
if ($cat_filter !== null && $type == 'by_app' && is_array($cat_filter)) {
|
||||||
|
$payload['cats'] = $cat_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->exec_curl('/api/s/' . $this->site . '/stat/sitedpi', $payload);
|
||||||
|
|
||||||
|
return $this->process_response($response);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List current channels
|
* List current channels
|
||||||
* ---------------------
|
* ---------------------
|
||||||
@@ -2424,23 +2516,23 @@ class Client
|
|||||||
* Assign access point to another WLAN group
|
* Assign access point to another WLAN group
|
||||||
* -----------------------------------------
|
* -----------------------------------------
|
||||||
* return true on success
|
* return true on success
|
||||||
* required parameter <wlantype_id> = string; WLAN type, can be either 'ng' (for WLANs 2G (11n/b/g)) or 'na' (WLANs 5G (11n/a/ac))
|
* required parameter <type_id> = string; WLAN type, can be either 'ng' (for WLANs 2G (11n/b/g)) or 'na' (WLANs 5G (11n/a/ac))
|
||||||
* required parameter <device_id> = string; _id value of the access point to be modified
|
* required parameter <device_id> = string; _id value of the access point to be modified
|
||||||
* required parameter <wlangroup_id> = string; _id value of the WLAN group to assign device to
|
* required parameter <group_id> = string; _id value of the WLAN group to assign device to
|
||||||
*/
|
*/
|
||||||
public function set_ap_wlangroup($wlantype_id, $device_id, $wlangroup_id)
|
public function set_ap_wlangroup($type_id, $device_id, $group_id)
|
||||||
{
|
{
|
||||||
if (!$this->is_loggedin) {
|
if (!$this->is_loggedin) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!in_array($wlantype_id, ['ng', 'na'])) {
|
if (!in_array($type_id, ['ng', 'na'])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$payload = [
|
$payload = [
|
||||||
'wlan_overrides' => [],
|
'wlan_overrides' => [],
|
||||||
'wlangroup_id_' . $wlantype_id => $wlangroup_id
|
'wlangroup_id_' . $type_id => $group_id
|
||||||
];
|
];
|
||||||
|
|
||||||
$response = $this->exec_curl('/api/s/' . $this->site . '/upd/device/' . trim($device_id), $payload);
|
$response = $this->exec_curl('/api/s/' . $this->site . '/upd/device/' . trim($device_id), $payload);
|
||||||
@@ -2474,7 +2566,8 @@ class Client
|
|||||||
$expire_number,
|
$expire_number,
|
||||||
$expire_unit,
|
$expire_unit,
|
||||||
$section_id
|
$section_id
|
||||||
) {
|
)
|
||||||
|
{
|
||||||
if (!$this->is_loggedin) {
|
if (!$this->is_loggedin) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2678,8 +2771,7 @@ class Client
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->request_type = 'POST';
|
$response = $this->exec_curl('/api/s/' . $this->site . '/rest/networkconf', $payload);
|
||||||
$response = $this->exec_curl('/api/s/' . $this->site . '/rest/networkconf', $payload);
|
|
||||||
|
|
||||||
return $this->process_response($response);
|
return $this->process_response($response);
|
||||||
}
|
}
|
||||||
@@ -2779,7 +2871,8 @@ class Client
|
|||||||
$uapsd_enabled = false,
|
$uapsd_enabled = false,
|
||||||
$schedule_enabled = false,
|
$schedule_enabled = false,
|
||||||
$schedule = []
|
$schedule = []
|
||||||
) {
|
)
|
||||||
|
{
|
||||||
if (!$this->is_loggedin) {
|
if (!$this->is_loggedin) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2998,8 +3091,7 @@ class Client
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->request_type = 'POST';
|
$payload = ['cmd' => 'archive-all-alarms'];
|
||||||
$payload = ['cmd' => 'archive-all-alarms'];
|
|
||||||
if (!is_null($alarm_id)) {
|
if (!is_null($alarm_id)) {
|
||||||
$payload = ['_id' => $alarm_id, 'cmd' => 'archive-alarm'];
|
$payload = ['_id' => $alarm_id, 'cmd' => 'archive-alarm'];
|
||||||
}
|
}
|
||||||
@@ -3259,7 +3351,6 @@ class Client
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->request_type = 'POST';
|
|
||||||
$payload = [
|
$payload = [
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
'x_password' => $x_password,
|
'x_password' => $x_password,
|
||||||
@@ -3465,6 +3556,10 @@ class Client
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!in_array($request_type, $this->request_types_allowed)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$this->request_type = $request_type;
|
$this->request_type = $request_type;
|
||||||
$response = $this->exec_curl($path, $payload);
|
$response = $this->exec_curl($path, $payload);
|
||||||
|
|
||||||
@@ -3543,7 +3638,7 @@ class Client
|
|||||||
* --------------------
|
* --------------------
|
||||||
* returns the raw results of the last method called, returns false if unavailable
|
* returns the raw results of the last method called, returns false if unavailable
|
||||||
* optional parameter <return_json> = boolean; true will return the results in "pretty printed" json format,
|
* optional parameter <return_json> = boolean; true will return the results in "pretty printed" json format,
|
||||||
* PHP stdClass Object format is returned by default
|
* false returns PHP stdClass Object format (default)
|
||||||
*/
|
*/
|
||||||
public function get_last_results_raw($return_json = false)
|
public function get_last_results_raw($return_json = false)
|
||||||
{
|
{
|
||||||
@@ -3573,15 +3668,17 @@ class Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Cookie from UniFi Controller
|
* Get Cookie from UniFi controller
|
||||||
* --------------------------------
|
* --------------------------------
|
||||||
* returns the UniFi controller cookie
|
* returns the UniFi controller cookie
|
||||||
*
|
*
|
||||||
* NOTES:
|
* NOTES:
|
||||||
* - when the results from this method are stored in $_SESSION['unificookie'], the class will initially not
|
* - when the results from this method are stored in $_SESSION['unificookie'], the Class will initially not
|
||||||
* log in to the controller when a subsequent request is made using a new instance. This speeds up the
|
* log in to the controller when a subsequent request is made using a new instance. This speeds up the
|
||||||
* overall request considerably. If that subsequent request fails (e.g. cookies have expired), a new login
|
* overall request considerably. Only when a subsequent request fails (e.g. cookies have expired) is a new login
|
||||||
* is executed automatically and the value of $_SESSION['unificookie'] is updated.
|
* executed and the value of $_SESSION['unificookie'] updated.
|
||||||
|
* - to force the Class instance to log out automatically upon destruct, simply call logout() or unset
|
||||||
|
* $_SESSION['unificookie'] at the end of your code
|
||||||
*/
|
*/
|
||||||
public function get_cookie()
|
public function get_cookie()
|
||||||
{
|
{
|
||||||
@@ -3622,7 +3719,14 @@ class Client
|
|||||||
|
|
||||||
public function set_request_type($request_type)
|
public function set_request_type($request_type)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (!in_array($request_type, $this->request_types_allowed)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$this->request_type = $request_type;
|
$this->request_type = $request_type;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function set_connection_timeout($timeout)
|
public function set_connection_timeout($timeout)
|
||||||
@@ -3640,17 +3744,34 @@ class Client
|
|||||||
$this->last_error_message = $last_error_message;
|
$this->last_error_message = $last_error_message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the value for cURL option CURLOPT_SSL_VERIFYPEER, should be 0/false or 1/true
|
||||||
|
* https://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYPEER.html
|
||||||
|
*/
|
||||||
public function set_ssl_verify_peer($ssl_verify_peer)
|
public function set_ssl_verify_peer($ssl_verify_peer)
|
||||||
{
|
{
|
||||||
|
if (!in_array($ssl_verify_peer, [0, false, 1, true])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$this->curl_ssl_verify_peer = $ssl_verify_peer;
|
$this->curl_ssl_verify_peer = $ssl_verify_peer;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the value for cURL option CURLOPT_SSL_VERIFYHOST, should be 0/false or 2
|
* 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
|
||||||
*/
|
*/
|
||||||
public function set_ssl_verify_host($ssl_verify_host)
|
public function set_ssl_verify_host($ssl_verify_host)
|
||||||
{
|
{
|
||||||
|
if (!in_array($ssl_verify_host, [0, false, 2])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$this->curl_ssl_verify_host = $ssl_verify_host;
|
$this->curl_ssl_verify_host = $ssl_verify_host;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************
|
/****************************************************************
|
||||||
@@ -3735,13 +3856,13 @@ class Client
|
|||||||
$error = 'The maximum stack depth has been exceeded';
|
$error = 'The maximum stack depth has been exceeded';
|
||||||
break;
|
break;
|
||||||
case JSON_ERROR_STATE_MISMATCH:
|
case JSON_ERROR_STATE_MISMATCH:
|
||||||
$error = 'Invalid or malformed JSON.';
|
$error = 'Invalid or malformed JSON';
|
||||||
break;
|
break;
|
||||||
case JSON_ERROR_CTRL_CHAR:
|
case JSON_ERROR_CTRL_CHAR:
|
||||||
$error = 'Control character error, possibly incorrectly encoded';
|
$error = 'Control character error, possibly incorrectly encoded';
|
||||||
break;
|
break;
|
||||||
case JSON_ERROR_SYNTAX:
|
case JSON_ERROR_SYNTAX:
|
||||||
$error = 'Syntax error, malformed JSON.';
|
$error = 'Syntax error, malformed JSON';
|
||||||
break;
|
break;
|
||||||
case JSON_ERROR_UTF8:
|
case JSON_ERROR_UTF8:
|
||||||
// PHP >= 5.3.3
|
// PHP >= 5.3.3
|
||||||
@@ -3768,7 +3889,7 @@ class Client
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// we have an unknown error
|
// we have an unknown error
|
||||||
$error = 'Unknown JSON error occured.';
|
$error = 'Unknown JSON error occured';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3783,7 +3904,7 @@ class Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the submitted base URL
|
* validate the submitted base URL
|
||||||
*/
|
*/
|
||||||
private function check_base_url()
|
private function check_base_url()
|
||||||
{
|
{
|
||||||
@@ -3794,13 +3915,6 @@ class Client
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$base_url_components = parse_url($this->baseurl);
|
|
||||||
if (empty($base_url_components['port'])) {
|
|
||||||
trigger_error('The URL provided does not have a port suffix, normally this is :8443');
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3810,52 +3924,123 @@ class Client
|
|||||||
private function check_site($site)
|
private function check_site($site)
|
||||||
{
|
{
|
||||||
if ($this->debug && preg_match("/\s/", $site)) {
|
if ($this->debug && preg_match("/\s/", $site)) {
|
||||||
error_log('The provided (short) site name may not contain spaces');
|
trigger_error('The provided (short) site name may not contain any spaces');
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the unificookie
|
* Update the unificookie if sessions are enabled
|
||||||
*/
|
*/
|
||||||
private function update_unificookie()
|
private function update_unificookie()
|
||||||
{
|
{
|
||||||
if (isset($_SESSION['unificookie'])) {
|
if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['unificookie']) && !empty($_SESSION['unificookie'])) {
|
||||||
$this->cookies = $_SESSION['unificookie'];
|
$this->cookies = $_SESSION['unificookie'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if we have a JWT in our cookie we know we're dealing with a UniFi OS controller
|
||||||
|
*/
|
||||||
|
if (strpos($this->cookies, 'TOKEN') !== false) {
|
||||||
|
$this->is_unifi_os = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the CSRF token from our Cookie string
|
||||||
|
*/
|
||||||
|
private function extract_csrf_token_from_cookie()
|
||||||
|
{
|
||||||
|
if ($this->cookies !== '') {
|
||||||
|
$cookie_bits = explode('=', $this->cookies);
|
||||||
|
if (!empty($cookie_bits) && array_key_exists(1, $cookie_bits)) {
|
||||||
|
$jwt = $cookie_bits[1];
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$jwt_components = explode('.', $jwt);
|
||||||
|
if (!empty($jwt_components) && array_key_exists(1, $jwt_components)) {
|
||||||
|
$jwt_payload = $jwt_components[1];
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_decode(base64_decode($jwt_payload))->csrfToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the cURL request
|
* Execute the cURL request
|
||||||
*/
|
*/
|
||||||
protected function exec_curl($path, $payload = '')
|
protected function exec_curl($path, $payload = null)
|
||||||
{
|
{
|
||||||
if (!is_resource($ch = $this->get_curl_resource())) {
|
if (!in_array($this->request_type, $this->request_types_allowed)) {
|
||||||
|
trigger_error('an invalid HTTP request type was used: ' . $this->request_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($ch = $this->get_curl_resource())) {
|
||||||
trigger_error('$ch as returned by get_curl_resource() is not a resource');
|
trigger_error('$ch as returned by get_curl_resource() is not a resource');
|
||||||
} else {
|
} else {
|
||||||
$json_payload = '';
|
$json_payload = '';
|
||||||
$url = $this->baseurl . $path;
|
|
||||||
|
if ($this->is_unifi_os) {
|
||||||
|
$url = $this->baseurl . '/proxy/network' . $path;
|
||||||
|
} else {
|
||||||
|
$url = $this->baseurl . $path;
|
||||||
|
}
|
||||||
|
|
||||||
curl_setopt($ch, CURLOPT_URL, $url);
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
|
|
||||||
if (!empty($payload)) {
|
if ($payload !== null) {
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
$json_payload = json_encode($payload, JSON_UNESCAPED_SLASHES);
|
$json_payload = json_encode($payload, JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $json_payload);
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $json_payload);
|
||||||
|
|
||||||
|
$headers = [
|
||||||
|
'Content-Type: application/json;charset=UTF-8',
|
||||||
|
'Content-Length: ' . strlen($json_payload)
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($this->is_unifi_os) {
|
||||||
|
$csrf_token = $this->extract_csrf_token_from_cookie();
|
||||||
|
if ($csrf_token) {
|
||||||
|
$headers[] = 'x-csrf-token: ' . $csrf_token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* we shouldn't be using GET (the default request type) or DELETE when passing a payload,
|
||||||
|
* we switch to POST instead
|
||||||
|
*/
|
||||||
|
if ($this->request_type === 'GET' || $this->request_type === 'DELETE') {
|
||||||
|
$this->request_type = 'POST';
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->request_type === 'PUT') {
|
if ($this->request_type === 'PUT') {
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER,
|
|
||||||
['Content-Type: application/json', 'Content-Length: ' . strlen($json_payload)]);
|
|
||||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
|
||||||
} else {
|
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
curl_setopt($ch, CURLOPT_POST, false);
|
if ($this->request_type === 'POST') {
|
||||||
if ($this->request_type === 'DELETE') {
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
|
||||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->request_type === 'DELETE') {
|
||||||
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* execute the cURL request
|
* execute the cURL request
|
||||||
*/
|
*/
|
||||||
@@ -3865,76 +4050,63 @@ class Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* has the session timed out? If so, we need to login again.
|
* an HTTP response code 401 (Unauthorized) indicates the Cookie/Token has expired in which case
|
||||||
|
* we need to login again.
|
||||||
*/
|
*/
|
||||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
|
||||||
if ($http_code == 401) {
|
if ($http_code == 401) {
|
||||||
$json_decoded_content = json_decode($content, true);
|
curl_close($ch);
|
||||||
|
if ($this->debug) {
|
||||||
if (isset($json_decoded_content['meta']['msg']) && $json_decoded_content['meta']['msg'] === 'api.err.LoginRequired') {
|
error_log('cURL debug: needed to reconnect to UniFi controller');
|
||||||
if ($this->debug) {
|
|
||||||
error_log('cURL debug: Needed to reconnect to UniFi Controller');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* explicitly unset the old cookie now
|
|
||||||
*/
|
|
||||||
if (isset($_SESSION['unificookie'])) {
|
|
||||||
unset($_SESSION['unificookie']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* then login again
|
|
||||||
*/
|
|
||||||
$this->login();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* when login was successful, execute the same command again
|
|
||||||
*/
|
|
||||||
if ($this->is_loggedin) {
|
|
||||||
curl_close($ch);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* setup the cookie for the user within $_SESSION, if $_SESSION['unificookie'] does not exist
|
|
||||||
*/
|
|
||||||
if (!isset($_SESSION['unificookie']) && session_status() != PHP_SESSION_DISABLED) {
|
|
||||||
$_SESSION['unificookie'] = $this->cookies;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->exec_curl($path, $payload);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($json_decoded_content);
|
/**
|
||||||
}
|
* explicitly clear the expired Cookie/Token before logging in again
|
||||||
|
*/
|
||||||
if ($this->debug) {
|
if (isset($_SESSION['unificookie'])) {
|
||||||
print PHP_EOL . '<pre>';
|
$_SESSION['unificookie'] = '';
|
||||||
print PHP_EOL . '---------cURL INFO-----------' . PHP_EOL;
|
$this->is_loggedin = false;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
print PHP_EOL . '----------RESPONSE-----------' . PHP_EOL;
|
/**
|
||||||
print $content;
|
* then login again
|
||||||
print PHP_EOL . '-----------------------------' . PHP_EOL;
|
*/
|
||||||
print '</pre>' . PHP_EOL;
|
$this->login();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* when login was successful, execute the same command 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_close($ch);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set request_type value back to default, just in case
|
|
||||||
*/
|
|
||||||
$this->request_type = 'POST';
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -3947,22 +4119,24 @@ class Client
|
|||||||
protected function get_curl_resource()
|
protected function get_curl_resource()
|
||||||
{
|
{
|
||||||
$ch = curl_init();
|
$ch = curl_init();
|
||||||
curl_setopt($ch, CURLOPT_POST, true);
|
if (is_resource($ch)) {
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->curl_ssl_verify_peer);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->curl_ssl_verify_peer);
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $this->curl_ssl_verify_host);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $this->curl_ssl_verify_host);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout);
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout);
|
||||||
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
|
|
||||||
|
|
||||||
if ($this->debug) {
|
if ($this->debug) {
|
||||||
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->cookies != '') {
|
||||||
|
curl_setopt($ch, CURLOPT_COOKIESESSION, true);
|
||||||
|
curl_setopt($ch, CURLOPT_COOKIE, $this->cookies);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->cookies != '') {
|
return false;
|
||||||
curl_setopt($ch, CURLOPT_COOKIESESSION, true);
|
|
||||||
curl_setopt($ch, CURLOPT_COOKIE, $this->cookies);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $ch;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user