Release 0.7.1
[shpub.git] / src / shpub / Config / Endpoints.php
1 <?php
2 namespace shpub;
3
4 class Config_Endpoints
5 {
6     /**
7      * Micropub endpoint URL
8      *
9      * @var string
10      */
11     public $micropub;
12
13     /**
14      * Micropub media endpoint URL
15      *
16      * @var string
17      */
18     public $media;
19
20     /**
21      * Access token endpoint URL
22      *
23      * @var string
24      */
25     public $token;
26
27     /**
28      * Authorization endpoint URL
29      *
30      * @var string
31      */
32     public $authorization;
33
34     public function incomplete()
35     {
36         return $this->authorization === null
37             || $this->token === null
38             || $this->micropub === null;
39     }
40
41     public function discover($server)
42     {
43         //TODO: discovery via link headers
44         $baseUrl = new \Net_URL2($server);
45
46         $doc = new \DOMDocument();
47         @$doc->loadHTMLFile($server);
48         $sx = simplexml_import_dom($doc);
49         if ($sx === false) {
50             Log::err('Error loading URL: ' . $server);
51             exit(1);
52         }
53         //$sx->registerXPathNamespace('h', 'http://www.w3.org/1999/xhtml');
54
55         $auths = $sx->xpath(
56             '/html/head/link[@rel="authorization_endpoint" and @href]'
57         );
58         if (!count($auths)) {
59             Log::err('No authorization endpoint found at ' . $server);
60             exit(1);
61         }
62         $this->authorization = (string) $baseUrl->resolve(
63             (string) $auths[0]['href']
64         );
65
66         $tokens = $sx->xpath(
67             '/html/head/link[@rel="token_endpoint" and @href]'
68         );
69         if (!count($tokens)) {
70             Log::err('No token endpoint found');
71             exit(1);
72         }
73         $this->token = (string) $baseUrl->resolve(
74             (string) $tokens[0]['href']
75         );
76
77         $mps = $sx->xpath(
78             '/html/head/link[@rel="micropub" and @href]'
79         );
80         if (!count($mps)) {
81             Log::err('No micropub endpoint found');
82             exit(1);
83         }
84         $this->micropub = (string) $baseUrl->resolve(
85             (string) $mps[0]['href']
86         );
87     }
88
89     public function discoverMedia($accessToken)
90     {
91         $configUrl = $this->micropub;
92         if (strpos($configUrl, '?') === false) {
93             $configUrl .= '?q=config';
94         } else {
95             $configUrl .= '&q=config';
96         }
97
98         $ctx = stream_context_create(
99             [
100                 'http' => [
101                     'header' => [
102                         'Accept: application/json',
103                         'Authorization: Bearer ' . $accessToken
104                     ],
105                 ]
106             ]
107         );
108         $json = @file_get_contents($configUrl, false, $ctx);
109         if ($json === false) {
110             //does not exist
111             return;
112         }
113         $configData = json_decode($json);
114         if ($configData === null) {
115             //json could not be decoded
116             Log::err('micropub configuration is invalid');
117             return;
118         }
119         if (isset($configData->{'media-endpoint'})) {
120             $configUrlObj = new \Net_URL2($configUrl);
121             $this->media = (string) $configUrlObj->resolve(
122                 $configData->{'media-endpoint'}
123             );
124         }
125     }
126
127     public function load($server)
128     {
129         $file = $this->getCacheFilePath($server, false);
130         if ($file === false || !file_exists($file)) {
131             return false;
132         }
133         $data = parse_ini_file($file);
134         foreach ($data as $prop => $val) {
135             if (!property_exists($this, $prop)) {
136                 Log::err('Invalid cache config key "' . $prop . '"');
137                 exit(1);
138             }
139             $this->$prop = $val;
140         }
141         return true;
142     }
143
144     public function save($server)
145     {
146         $file = $this->getCacheFilePath($server, true);
147         if ($file === false) {
148             return false;
149         }
150
151         file_put_contents(
152             $file,
153             'micropub=' . Config::quoteIniValue($this->micropub) . "\n"
154             . 'media=' . Config::quoteIniValue($this->media) . "\n"
155             . 'token=' . Config::quoteIniValue($this->token) . "\n"
156             . 'authorization='
157             . Config::quoteIniValue($this->authorization) . "\n"
158         );
159     }
160
161     public function getCacheFilePath($server, $create = false)
162     {
163         if (isset($_SERVER['XDG_CACHE_HOME'])
164             && $_SERVER['XDG_CACHE_HOME'] != ''
165         ) {
166             $cacheBaseDir = $_SERVER['XDG_CACHE_HOME'];
167         } else {
168             if (!isset($_SERVER['HOME']) || $_SERVER['HOME'] == '') {
169                 Log::err('Cannot determine home directory');
170                 return false;
171             }
172             $cacheBaseDir = $_SERVER['HOME'] . '/.cache';
173         }
174
175         $cacheDir = $cacheBaseDir . '/shpub';
176         if (!is_dir($cacheDir) && $create) {
177             mkdir($cacheDir, 0700, true);
178         }
179         $file = $cacheDir . '/' . urlencode($server) . '.ini';
180         return $file;
181     }
182 }
183 ?>