Created
August 14, 2021 19:20
-
-
Save carschrotter/4d3d26867edbf254097cd72fbf21a67f to your computer and use it in GitHub Desktop.
myopenhab.org status grabber
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
return [ | |
"username" => "MYUSERNAME", | |
"password" => "MYPASSWORD", | |
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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()] ) ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment