From: Stricted Date: Sat, 27 Jun 2015 22:16:32 +0000 (+0200) Subject: initial commit X-Git-Tag: 1.0.0~26 X-Git-Url: https://git.stricted.de/?p=GitHub%2FStricted%2Fspeedport-hybrid-php-api.git;a=commitdiff_plain;h=a91317a68a3c172af2da00ba3eecd8ff70f1b8fd initial commit --- a91317a68a3c172af2da00ba3eecd8ff70f1b8fd diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..34848f3 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +*.php text eol=lf +*.tpl text eol=lf +*.js text eol=lf +*.css text eol=lf +*.sql text eol=lf diff --git a/README.md b/README.md new file mode 100644 index 0000000..99b3af0 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +## speedport hybrid php api + +Access Speedport Hybrid Router through PHP \ No newline at end of file diff --git a/speedport.class.php b/speedport.class.php new file mode 100644 index 0000000..7f38aa0 --- /dev/null +++ b/speedport.class.php @@ -0,0 +1,233 @@ +getChallenge(); + + if (empty($this->challenge)) { + throw new Exception('unable to get the challenge from the router'); + } + + $login = $this->login($password); + + if ($login === false) { + throw new Exception('unable to login'); + } + } + + /** + * Requests the password-challenge from the router. + */ + public function getChallenge () { + $url = 'data/Login.json'; + $fields = array('csrf_token' => 'nulltoken', 'showpw' => 0, 'challengev' => 'null'); + $data = $this->sentRequest($url, $fields); + $data = json_decode($data['body'], true); + if ($data[1]['varid'] == 'challengev') { + $this->challenge = $data[1]['varvalue']; + } + } + + /** + * login into the router with the given password + * + * @param string $password + * @return boolean + */ + public function login ($password) { + $url = 'data/Login.json'; + $this->hash = hash('sha256', $this->challenge.':'.$password); + $fields = array('csrf_token' => 'nulltoken', 'showpw' => 0, 'password' => $this->hash); + $data = $this->sentRequest($url, $fields); + $json = json_decode($data['body'], true); + if ($json[15]['varid'] == 'login' && $json[15]['varvalue'] == 'success') { + if (isset($data['header']['Set-Cookie']) && !empty($data['header']['Set-Cookie'])) { + preg_match('/^.*(SessionID_R3=[a-z0-9]*).*/i', $data['header']['Set-Cookie'], $match); + if (isset($match[1]) && !empty($match[1])) { + $this->session = $match[1]; + } + else { + throw new Exception('unable to get the session cookie from the router'); + } + + return true; + } + } + + return false; + } + + /** + * logout + * + * @return array + */ + public function logout () { + $url = 'data/Login.json'; + $fields = array('logout' => 'byby'); + $data = $this->sentRequest($url, $fields); + // reset challenge and session + $this->challenge = ''; + $this->session = ''; + + $json = json_decode($data['body'], true); + + return $json; + } + + /** + * reboot the router + * + * @return array + */ + public function reboot () { + $url = 'data/Reboot.json'; + $fields = array('csrf_token' => 'nulltoken', 'showpw' => 0, 'password' => $this->hash, 'reboot_device' => 'true'); + $cookie = 'challengev='.$this->challenge.'; '.$this->session; + $data = $this->sentRequest($url, $fields, $cookie); + $json = json_decode($data['body'], true); + + return $json; + } + + /** + * return the given json as array + * + * the following paths are known to be valid: + * /data/dsl.json + * /data/interfaces.json + * /data/arp.json + * /data/session.json + * /data/dhcp_client.json + * /data/dhcp_server.json + * /data/ipv6.json + * /data/dns.json + * /data/routing.json + * /data/igmp_proxy.json + * /data/igmp_snooping.json + * /data/wlan.json + * /data/module.json + * /data/memory.json + * /data/speed.json + * /data/webdav.json + * /data/bonding_client.json + * /data/bonding_tunnel.json + * /data/filterlist.json + * /data/bonding_tr181.json + * /data/letinfo.json + * + * /data/Status.json (No login needed) + * + * @param string $file + * @return array + */ + public function getData ($file) { + $url = 'data/'.$file.'.json'; + $fields = array(); + $cookie = 'challengev='.$this->challenge.'; '.$this->session; + $data = $this->sentRequest($url, $fields, $cookie); + + if (empty($data['body'])) { + throw new Exception('unable to get '.$file.' data'); + } + + $json = json_decode($data['body'], true); + + return $json; + } + + /** + * sends the request to router + * + * @param string $url + * @param array $fields + * @param string $cookie + * @return array + */ + private function sentRequest ($url, $fields = array(), $cookie = '') { + $url = $this->url.$url; + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + + if (!empty($fields)) { + curl_setopt($ch, CURLOPT_POST, count($fields)); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields)); + } + + if (!empty($cookie)) { + curl_setopt($ch, CURLOPT_COOKIE, $cookie); + } + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HEADER, true); + + + if ($cookie) { + + } + + $result = curl_exec($ch); + + $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $header = substr($result, 0, $header_size); + $body = substr($result, $header_size); + curl_close($ch); + + // fix invalid json + $body = preg_replace("/(\r\n)|(\r)/", "\n", $body); + $body = preg_replace('/\'/i', '"', $body); + $body = preg_replace("/},\n\n]/", "}\n]", $body); + $body = preg_replace('/\s+/', ' ', $body); + $body = preg_replace("/\[ \]/i", '[ {} ]', $body); + $body = preg_replace("/}, ]/", "} ]", $body); + $body = preg_replace("/\n/", " ", $body); + + return array('header' => $this->parse_headers($header), 'body' => $body); + } + + /** + * parse the curl return header into an array + * + * @param string $response + * @return array + */ + private function parse_headers($response) { + $headers = array(); + $header_text = substr($response, 0, strpos($response, "\r\n\r\n")); + + foreach (explode("\r\n", $header_text) as $i => $line) { + if ($i === 0) { + $headers['http_code'] = $line; + } + else { + list ($key, $value) = explode(': ', $line); + $headers[$key] = $value; + } + } + + return $headers; + } +} \ No newline at end of file