|
#!/bin/env php |
|
<?php |
|
|
|
/** |
|
* @global array $options array with script options |
|
* needed struck like |
|
* <?php |
|
* [ |
|
* 'username' => 'USERNAME', |
|
* 'password' => 'PASSWORD', |
|
* 'cookie' => 'COOKIE.TXT' |
|
* ] |
|
*/ |
|
$options = getopt(null, ['username:', 'password:', 'cookie::', 'conf::', 'h', 'help', 'ignore-ssl']); |
|
|
|
if(count(array_intersect(['h', 'help'], array_keys($options))) > 0) { |
|
printf('Usage: %2$s %3$s --username "MyUsername" --password "MyPassword" (--cookie "/file/to/cookie") %1$sOptions:%1$22s--username The username of myopenhab account%1$s--password The password of myopenhab account%1$s--cookie (optional) The path to cookie file', PHP_EOL, PHP_BINARY, __FILE__); |
|
exit(0); |
|
} |
|
//convert php default behavior given parameter is explicitly false, to true if specified |
|
$options['ignore-ssl'] = (bool) (array_key_exists('ignore-ssl', $options) ? !$options['ignore-ssl'] : false); |
|
|
|
if( array_key_exists('conf', $options) ) { |
|
if(!file_exists($options['conf']) ){ |
|
printf('Conf file "%2$s" not found!%1$s', PHP_EOL, $options['conf'] ); |
|
exit(1); |
|
} |
|
$conf_file_content = @include($options['conf']); |
|
if(!is_array($conf_file_content)){ |
|
printf("Conf file has wrong format!%1\$sWrite as follow:%1\$s%1\$s<?php%1\$sreturn ['username' => 'MyUsername', 'password' => 'MyPassword'];%1\$s%1\$s", PHP_EOL); |
|
exit(1); |
|
} |
|
$options = array_merge($conf_file_content, $options); |
|
} |
|
|
|
//is not set on comandline or config file use default value |
|
$options['cookie'] = array_key_exists('cookie', $options) ? $options['cookie'] : "COOKIE.TXT"; |
|
|
|
//only for debuging |
|
//print_r($options); |
|
|
|
if( !array_key_exists('username', $options ) || !array_key_exists('password', $options ) ) { |
|
printf('Username and password neded using: %s %s --username "MyUsername" --password "MyPassword"' .PHP_EOL, PHP_BINARY, __FILE__); |
|
exit(1); |
|
} |
|
|
|
$timezone = (new DateTime())->getTimezone()->getName(); |
|
|
|
const headers = [ |
|
'Connection: keep-alive', |
|
'Cache-Control: max-age=0', |
|
'sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Microsoft Edge";v="92"', |
|
'sec-ch-ua-mobile: ?0', |
|
'Upgrade-Insecure-Requests: 1', |
|
'Origin: https://myopenhab.org', |
|
'User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36', |
|
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', |
|
'Sec-Fetch-Site: same-origin', |
|
'Sec-Fetch-Mode: navigate', |
|
'Sec-Fetch-User: ?1', |
|
'Sec-Fetch-Dest: document', |
|
'Accept-Language: en;q=0.9,en-GB;q=0.8,en-US;q=0.7' |
|
]; |
|
|
|
//check for runtime |
|
if(extension_loaded('curl') === false) |
|
die("extention curl is needed "); |
|
if(extension_loaded('dom') === false) |
|
die("extention dom is needed "); |
|
|
|
function bakingCurl($url, array $headers = null) { |
|
global $options; |
|
$ch = curl_init(); |
|
curl_setopt($ch, CURLOPT_URL, $url); |
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
|
curl_setopt($ch, CURLOPT_COOKIEFILE, $options['cookie']); |
|
curl_setopt($ch, CURLOPT_COOKIEJAR, $options['cookie']); |
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers ?: headers); |
|
if($options['ignore-ssl'] === true) { |
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); |
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); |
|
} |
|
|
|
return $ch; |
|
} |
|
|
|
function execCurl($ch) { |
|
$result = curl_exec($ch); |
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); |
|
|
|
if ($result === false || $http_code != 200) { |
|
$error = curl_error($ch); |
|
curl_close($ch); |
|
throw new Exception($error ?: 'HTTP Error: '. $http_code ); |
|
} |
|
|
|
return $result; |
|
} |
|
|
|
function startpage() { |
|
$result = execCurl(bakingCurl("https://myopenhab.org/")); |
|
return $result; |
|
} |
|
/** |
|
* Login into myopenhab.org |
|
* @param string $csrf the from page extracted csrf |
|
* @global string $options options like username, password or cookie |
|
*/ |
|
function login($csrf) { |
|
global $options; |
|
//send the form |
|
$ch = bakingCurl('https://myopenhab.org/login', headers + [ |
|
'Origin: https://myopenhab.org', |
|
'Content-Type: application/x-www-form-urlencoded', |
|
'Referer: https://myopenhab.org/', |
|
]); |
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
|
curl_setopt($ch, CURLINFO_HEADER_OUT, true); |
|
curl_setopt($ch, CURLOPT_POST, true); |
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); |
|
$qu = http_build_query( [ |
|
'username'=>$options['username'], |
|
'password'=>$options['password'], |
|
'_csrf' => $csrf, |
|
'submit'=>'', |
|
]); |
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $qu); |
|
|
|
return execCurl($ch); |
|
} |
|
|
|
function getCsrf(\DomXPath $domxpath){ |
|
/* xpath of csrf input element in login form*/ |
|
$csrf_nodes = $domxpath->query("//form[@action='/login']/input[@name='_csrf']/@value"); |
|
|
|
if($csrf_nodes->count() == 1){ |
|
return $csrf_nodes[0]->value; |
|
} |
|
return false; |
|
|
|
/* |
|
$csrf_nodes = $domxpath->query('/html/body/div/section/div/div/div[2]/div[2]/form/input[1]'); |
|
// Traverse the DOMNodeList object to output each DomNode's nodeValue |
|
foreach ($csrf_nodes as $node) { |
|
if ($node->hasAttributes()) { |
|
foreach ($node->attributes as $attr) { |
|
if('value' == $attr->nodeName){ |
|
return $attr->nodeValue; |
|
} |
|
} |
|
} |
|
} |
|
*/ |
|
} |
|
|
|
function getStateFromPage($document) { |
|
global $timezone; |
|
if(preg_match('/(Unknown user)|(incorrect password)/i', $document)) { |
|
throw new Exception("Wrong username or incorrect password"); |
|
} |
|
$dom = new DomDocument(); |
|
/* Load the HTML */ |
|
@$dom->loadHTML($document); |
|
/* Create a new XPath object */ |
|
$xpath = new DomXPath($dom); |
|
|
|
$csrf = getCsrf($xpath); |
|
|
|
//no csrf allredy logged in :-) |
|
if($csrf == false) { |
|
//using li[3] becaus class change on online/offline :-/ |
|
$status_nodes = $xpath->query('//*[@id="mainMenu"]/ul/li[3]/a'); |
|
if(count($status_nodes) == 0){ |
|
throw new Exception("Document structure not valid. Status not found!"); |
|
} |
|
foreach ($status_nodes as $i => $node) { |
|
$output['status'] = strtolower($node->textContent) ; |
|
if ($node->hasAttributes()) { |
|
foreach ($node->attributes as $attr) { |
|
if('title' == $attr->nodeName){ //@todo not working correkt :-( |
|
$output['since_hint'] = $attr->nodeValue; |
|
$sinceDateTime = new DateTimeImmutable(str_replace('Since ', '', $output['since_hint']), new DateTimeZone($timezone)); |
|
$output['state_since_seconds'] = (int) (new DateTime())->getTimestamp() - $sinceDateTime->getTimestamp(); |
|
$output['state_since_datetime'] = $sinceDateTime->format('Y-m-d H:i:s'); |
|
} |
|
} |
|
} |
|
} |
|
$output['timezone'] = $timezone; |
|
return $output; |
|
} else { |
|
|
|
execCurl( //set timezone for "since... " Value |
|
bakingCurl( 'https://myopenhab.org/setTimezone?' . http_build_query(['tz' => $timezone]) ) |
|
); |
|
|
|
//rerunn from login |
|
return getStateFromPage(login($csrf)); |
|
} |
|
throw new Exception("Document structure not valid"); |
|
} |
|
|
|
try { |
|
$document=startpage(); |
|
$state = getStateFromPage($document); |
|
echo json_encode($state); |
|
} catch (\Throwable $th) { |
|
die( json_encode( ['error' => $th->getMessage()] ) ); |
|
} |