Skip to content

Instantly share code, notes, and snippets.

@carschrotter
Created August 14, 2021 19:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save carschrotter/4d3d26867edbf254097cd72fbf21a67f to your computer and use it in GitHub Desktop.
Save carschrotter/4d3d26867edbf254097cd72fbf21a67f to your computer and use it in GitHub Desktop.
myopenhab.org status grabber
<?php
return [
"username" => "MYUSERNAME",
"password" => "MYPASSWORD",
];
#!/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