369 lines
12 KiB
PHP
369 lines
12 KiB
PHP
<?php
|
|
require 'config/application.php';
|
|
|
|
$session = null;
|
|
if (isset($_SERVER['REQUEST_URI'])) {
|
|
if (!isset($_COOKIE['_session']) || !file_exists('/tmp/apcontrol-sessions')) {
|
|
if (substr($_SERVER['REQUEST_URI'],0,5) === '/api/') {
|
|
http_response_code(403); die('<h3>403, API Forbidden</h3>');
|
|
}
|
|
header('Location: login.php'); die;
|
|
}
|
|
$session = trim($_COOKIE['_session']);
|
|
$sessions = explode("\n", trim(file_get_contents('/tmp/apcontrol-sessions')));
|
|
if (!in_array($session, $sessions)) {
|
|
if (substr($_SERVER['REQUEST_URI'],0,5) === '/api/') {
|
|
http_response_code(403); die('<h3>403, API Forbidden</h3>');
|
|
}
|
|
header('Location: login.php'); die;
|
|
}
|
|
unset($sessions);
|
|
}
|
|
|
|
if (!file_exists($GLOBALS['appconf']['data_dir']))
|
|
mkdir($GLOBALS['appconf']['data_dir']);
|
|
|
|
|
|
// global variables
|
|
$GLOBALS['_cache'] = [];
|
|
$GLOBALS['supported_ap_software'] = [
|
|
'mastodon',
|
|
];
|
|
|
|
// functions
|
|
function apiresult($data, $code=200) {
|
|
if (isset($GLOBALS['IS_PHP']) && $GLOBALS['IS_PHP']) {
|
|
$GLOBALS['api_data'] = $data;
|
|
return false;
|
|
}
|
|
if (isset($_SERVER['REQUEST_URI'])) {
|
|
if ($code !== 200) http_response_code($code);
|
|
header('Content-Type: application/json');
|
|
}
|
|
if (gettype($data) !== 'string')
|
|
echo json_encode($data);
|
|
else echo $data;
|
|
die;
|
|
}
|
|
|
|
function apimod($module_name) {
|
|
$GLOBALS['IS_PHP'] = true;
|
|
unset($GLOBALS['api_data']);
|
|
require $module_name.'/mod.php';
|
|
unset($GLOBALS['IS_PHP']);
|
|
return $GLOBALS['api_data'];
|
|
}
|
|
|
|
function instance_config($software, $instance=null) {
|
|
if (!in_array($software, $GLOBALS['supported_ap_software']))
|
|
return null;
|
|
|
|
if ($instance === null && isset($_GET['instance']))
|
|
$instance = trim($_GET['instance']);
|
|
|
|
if ($instance === null)
|
|
return apiresult(['error' => '<instance> GET argument must be provided'], 400);
|
|
|
|
$GLOBALS['ap_instance'] = $instance;
|
|
$GLOBALS['ap_software'] = $software;
|
|
if (isset($GLOBALS['_cache'][$software.$instance]))
|
|
return $GLOBALS['_cache'][$software.$instance];
|
|
|
|
apimod('api/v1/config/get');
|
|
if (!isset($GLOBALS['api_data']))
|
|
return null;
|
|
|
|
|
|
$found = false;
|
|
foreach ($GLOBALS['api_data']['hosts'][$software] as $ins_cfg) {
|
|
if ($ins_cfg['instance'] === $instance) {
|
|
$found = $ins_cfg;
|
|
}
|
|
}
|
|
if ($found === false)
|
|
return null;
|
|
|
|
$config = [];
|
|
$config_raw = explode("\n", trim($found['config']));
|
|
foreach ($config_raw as $ln) {
|
|
$k = substr($ln, 0, strpos($ln,'='));
|
|
$v = substr($ln, strpos($ln,'=')+1);
|
|
$config[$k] = $v;
|
|
}
|
|
|
|
$GLOBALS['_cache'][$software.$instance] = $config;
|
|
return $config;
|
|
}
|
|
|
|
function instance_config_require($software, $instance=null) {
|
|
$config = instance_config($software, $instance);
|
|
if ($config === null)
|
|
apiresult(['error' => 'instance parameter is incorrect. Does not exist'], 400);
|
|
return $config;
|
|
}
|
|
|
|
function instance_http_get($url) { return instance_http_request($url, 'GET'); }
|
|
function instance_http_post($url, $data=null) { return instance_http_request($url, 'POST', $data); }
|
|
function instance_http_request($url, $method, $data=null) {
|
|
$huri = substr(trim($_SERVER['REQUEST_URI']), 7);
|
|
$ps = explode('/', trim($huri, '/'));
|
|
if ($ps[0] !== 'http' || !in_array($ps[1], $GLOBALS['supported_ap_software']))
|
|
apiresult(['error' => 'this method can only be called from api/v1/http/<software> URIs'], 500);
|
|
|
|
$software = $ps[1];
|
|
$config = instance_config($software);
|
|
$url = $config['instance_url'].$url;
|
|
|
|
$ch = curl_init();
|
|
curl_setopt($ch, CURLOPT_URL, $url);
|
|
if ($method === 'POST') {
|
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
|
|
if ($data !== null)
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
|
}
|
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
|
|
if (isset($config['api_authkey'])) {
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
'Authorization: Bearer '.$config['api_authkey'],
|
|
]);
|
|
}
|
|
|
|
$output = curl_exec($ch);
|
|
curl_close($ch);
|
|
return $output;
|
|
}
|
|
|
|
function valid_mastodon_account_id($id) {
|
|
return preg_match('/^\d+$/', strval($id));
|
|
}
|
|
|
|
function remove_accents($string) {
|
|
if ( !preg_match('/[\x80-\xff]/', $string) )
|
|
return $string;
|
|
|
|
$chars = array(
|
|
// Decompositions for Latin-1 Supplement
|
|
chr(195).chr(128) => 'A', chr(195).chr(129) => 'A',
|
|
chr(195).chr(130) => 'A', chr(195).chr(131) => 'A',
|
|
chr(195).chr(132) => 'A', chr(195).chr(133) => 'A',
|
|
chr(195).chr(135) => 'C', chr(195).chr(136) => 'E',
|
|
chr(195).chr(137) => 'E', chr(195).chr(138) => 'E',
|
|
chr(195).chr(139) => 'E', chr(195).chr(140) => 'I',
|
|
chr(195).chr(141) => 'I', chr(195).chr(142) => 'I',
|
|
chr(195).chr(143) => 'I', chr(195).chr(145) => 'N',
|
|
chr(195).chr(146) => 'O', chr(195).chr(147) => 'O',
|
|
chr(195).chr(148) => 'O', chr(195).chr(149) => 'O',
|
|
chr(195).chr(150) => 'O', chr(195).chr(153) => 'U',
|
|
chr(195).chr(154) => 'U', chr(195).chr(155) => 'U',
|
|
chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y',
|
|
chr(195).chr(159) => 's', chr(195).chr(160) => 'a',
|
|
chr(195).chr(161) => 'a', chr(195).chr(162) => 'a',
|
|
chr(195).chr(163) => 'a', chr(195).chr(164) => 'a',
|
|
chr(195).chr(165) => 'a', chr(195).chr(167) => 'c',
|
|
chr(195).chr(168) => 'e', chr(195).chr(169) => 'e',
|
|
chr(195).chr(170) => 'e', chr(195).chr(171) => 'e',
|
|
chr(195).chr(172) => 'i', chr(195).chr(173) => 'i',
|
|
chr(195).chr(174) => 'i', chr(195).chr(175) => 'i',
|
|
chr(195).chr(177) => 'n', chr(195).chr(178) => 'o',
|
|
chr(195).chr(179) => 'o', chr(195).chr(180) => 'o',
|
|
chr(195).chr(181) => 'o', chr(195).chr(182) => 'o',
|
|
chr(195).chr(182) => 'o', chr(195).chr(185) => 'u',
|
|
chr(195).chr(186) => 'u', chr(195).chr(187) => 'u',
|
|
chr(195).chr(188) => 'u', chr(195).chr(189) => 'y',
|
|
chr(195).chr(191) => 'y',
|
|
// Decompositions for Latin Extended-A
|
|
chr(196).chr(128) => 'A', chr(196).chr(129) => 'a',
|
|
chr(196).chr(130) => 'A', chr(196).chr(131) => 'a',
|
|
chr(196).chr(132) => 'A', chr(196).chr(133) => 'a',
|
|
chr(196).chr(134) => 'C', chr(196).chr(135) => 'c',
|
|
chr(196).chr(136) => 'C', chr(196).chr(137) => 'c',
|
|
chr(196).chr(138) => 'C', chr(196).chr(139) => 'c',
|
|
chr(196).chr(140) => 'C', chr(196).chr(141) => 'c',
|
|
chr(196).chr(142) => 'D', chr(196).chr(143) => 'd',
|
|
chr(196).chr(144) => 'D', chr(196).chr(145) => 'd',
|
|
chr(196).chr(146) => 'E', chr(196).chr(147) => 'e',
|
|
chr(196).chr(148) => 'E', chr(196).chr(149) => 'e',
|
|
chr(196).chr(150) => 'E', chr(196).chr(151) => 'e',
|
|
chr(196).chr(152) => 'E', chr(196).chr(153) => 'e',
|
|
chr(196).chr(154) => 'E', chr(196).chr(155) => 'e',
|
|
chr(196).chr(156) => 'G', chr(196).chr(157) => 'g',
|
|
chr(196).chr(158) => 'G', chr(196).chr(159) => 'g',
|
|
chr(196).chr(160) => 'G', chr(196).chr(161) => 'g',
|
|
chr(196).chr(162) => 'G', chr(196).chr(163) => 'g',
|
|
chr(196).chr(164) => 'H', chr(196).chr(165) => 'h',
|
|
chr(196).chr(166) => 'H', chr(196).chr(167) => 'h',
|
|
chr(196).chr(168) => 'I', chr(196).chr(169) => 'i',
|
|
chr(196).chr(170) => 'I', chr(196).chr(171) => 'i',
|
|
chr(196).chr(172) => 'I', chr(196).chr(173) => 'i',
|
|
chr(196).chr(174) => 'I', chr(196).chr(175) => 'i',
|
|
chr(196).chr(176) => 'I', chr(196).chr(177) => 'i',
|
|
chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij',
|
|
chr(196).chr(180) => 'J', chr(196).chr(181) => 'j',
|
|
chr(196).chr(182) => 'K', chr(196).chr(183) => 'k',
|
|
chr(196).chr(184) => 'k', chr(196).chr(185) => 'L',
|
|
chr(196).chr(186) => 'l', chr(196).chr(187) => 'L',
|
|
chr(196).chr(188) => 'l', chr(196).chr(189) => 'L',
|
|
chr(196).chr(190) => 'l', chr(196).chr(191) => 'L',
|
|
chr(197).chr(128) => 'l', chr(197).chr(129) => 'L',
|
|
chr(197).chr(130) => 'l', chr(197).chr(131) => 'N',
|
|
chr(197).chr(132) => 'n', chr(197).chr(133) => 'N',
|
|
chr(197).chr(134) => 'n', chr(197).chr(135) => 'N',
|
|
chr(197).chr(136) => 'n', chr(197).chr(137) => 'N',
|
|
chr(197).chr(138) => 'n', chr(197).chr(139) => 'N',
|
|
chr(197).chr(140) => 'O', chr(197).chr(141) => 'o',
|
|
chr(197).chr(142) => 'O', chr(197).chr(143) => 'o',
|
|
chr(197).chr(144) => 'O', chr(197).chr(145) => 'o',
|
|
chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe',
|
|
chr(197).chr(148) => 'R',chr(197).chr(149) => 'r',
|
|
chr(197).chr(150) => 'R',chr(197).chr(151) => 'r',
|
|
chr(197).chr(152) => 'R',chr(197).chr(153) => 'r',
|
|
chr(197).chr(154) => 'S',chr(197).chr(155) => 's',
|
|
chr(197).chr(156) => 'S',chr(197).chr(157) => 's',
|
|
chr(197).chr(158) => 'S',chr(197).chr(159) => 's',
|
|
chr(197).chr(160) => 'S', chr(197).chr(161) => 's',
|
|
chr(197).chr(162) => 'T', chr(197).chr(163) => 't',
|
|
chr(197).chr(164) => 'T', chr(197).chr(165) => 't',
|
|
chr(197).chr(166) => 'T', chr(197).chr(167) => 't',
|
|
chr(197).chr(168) => 'U', chr(197).chr(169) => 'u',
|
|
chr(197).chr(170) => 'U', chr(197).chr(171) => 'u',
|
|
chr(197).chr(172) => 'U', chr(197).chr(173) => 'u',
|
|
chr(197).chr(174) => 'U', chr(197).chr(175) => 'u',
|
|
chr(197).chr(176) => 'U', chr(197).chr(177) => 'u',
|
|
chr(197).chr(178) => 'U', chr(197).chr(179) => 'u',
|
|
chr(197).chr(180) => 'W', chr(197).chr(181) => 'w',
|
|
chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y',
|
|
chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z',
|
|
chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z',
|
|
chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z',
|
|
chr(197).chr(190) => 'z', chr(197).chr(191) => 's'
|
|
);
|
|
|
|
$string = strtr($string, $chars);
|
|
|
|
return $string;
|
|
}
|
|
|
|
if (!function_exists('str_starts_with')) {
|
|
function str_starts_with($haystack, $needle) {
|
|
return (string)$needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0;
|
|
}
|
|
}
|
|
|
|
function normalize_for_search($str) {
|
|
if (trim($str) === '') return '';
|
|
$str = preg_replace('/\s\s+/', ' ', trim($str));
|
|
$words = explode(' ', $str);
|
|
$newwords = [];
|
|
foreach ($words as $word) {
|
|
$word = remove_accents($word);
|
|
$word = strtolower($word);
|
|
$word = preg_replace('/[^a-z0-9]+/', '', $word);
|
|
if (trim($word) === '')
|
|
continue;
|
|
$word = str_replace('4', 'a', $word);
|
|
$word = str_replace('3', 'e', $word);
|
|
$word = str_replace('1', 'i', $word);
|
|
$word = str_replace('0', 'o', $word);
|
|
$word = str_replace('5', 's', $word);
|
|
$word = str_replace('8', 'b', $word);
|
|
$nword = '';
|
|
for ($i = 0; $i < strlen($word); $i++) {
|
|
if ($i === 0) {
|
|
$nword .= $word[0];
|
|
continue;
|
|
}
|
|
if ($word[$i] !== $word[$i-1]) {
|
|
$nword .= $word[$i];
|
|
}
|
|
}
|
|
$newwords [] = $nword;
|
|
}
|
|
return trim(implode(' ', $newwords));
|
|
}
|
|
|
|
function parse_search_expression($q) {
|
|
var_dump($q);
|
|
die;
|
|
}
|
|
|
|
function content_cache__exists($key) {
|
|
$cache_dir = $GLOBALS['appconf']['data_dir'].'/cache';
|
|
if (!file_exists($cache_dir)) {
|
|
mkdir($cache_dir);
|
|
return false;
|
|
}
|
|
$key = md5($key);
|
|
$cache_file = null;
|
|
foreach (scandir($cache_dir) as $fil) {
|
|
if (strpos($fil, $key) !== false) {
|
|
$cache_file = $cache_dir.'/'.$fil;
|
|
$ps = explode(',',$fil);
|
|
array_splice($ps, 0, 1);
|
|
if ($ps[0] !== 'always' && count($ps) > 1)
|
|
$ps[1] = intval($ps[1]);
|
|
return (object)[
|
|
'file' => $cache_file,
|
|
'config' => $ps
|
|
];
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function content_cache__get($key) {
|
|
$cfg = content_cache__exists($key);
|
|
if ($cfg === false)
|
|
return null;
|
|
$ms = time() - filemtime($cfg->file);
|
|
if ($cfg->config[0] === 'ondemand' &&
|
|
$ms > $cfg->config[1]) {
|
|
unlink($cfg->file);
|
|
return null;
|
|
}
|
|
return unserialize(file_get_contents($cfg->file));
|
|
}
|
|
|
|
function content_cache__put($key, $config, $data) {
|
|
$cache_dir = $GLOBALS['appconf']['data_dir'].'/cache';
|
|
if (!file_exists($cache_dir))
|
|
mkdir($cache_dir);
|
|
$ps = explode(',', trim($config));
|
|
$cache_file = $cache_dir.'/'.md5($key);
|
|
if ($ps[0] === 'always')
|
|
$cache_file .= ','.$ps[0];
|
|
else if ($ps[0] === 'ondemand')
|
|
$cache_file .= $config;
|
|
file_put_contents($cache_file, serialize($data));
|
|
}
|
|
|
|
function cronjob_db_create__check_cachecfg($software, $instance, $sql, $cache=null) {
|
|
if ($cache === null)
|
|
return false;
|
|
$ps = explode(',',trim($cache));
|
|
if ($ps[0] !== 'always')
|
|
return false;
|
|
return cronjob_db_create($software, $instance, $sql, intval($ps[1]));
|
|
}
|
|
|
|
function cronjob_db_create($software, $instance, $sql, $time=3600) {
|
|
$job_key = md5($software.$instance.$sql);
|
|
$dir_crons = $GLOBALS['appconf']['data_dir'].'/cron';
|
|
if (!file_exists($dir_crons))
|
|
mkdir($dir_crons);
|
|
$dir_crons_db = $dir_crons.'/db';
|
|
if (!file_exists($dir_crons_db))
|
|
mkdir($dir_crons_db);
|
|
$cron_file = $software.','.$instance.','.$job_key;
|
|
foreach (scandir($dir_crons_db) as $fl) {
|
|
if (strpos($fl, $cron_file) !== false)
|
|
unlink($dir_crons_db.'/'.$fl);
|
|
}
|
|
file_put_contents($dir_crons_db.'/'.$cron_file.','.$time, $sql);
|
|
return $cron_file;
|
|
}
|
|
|
|
// classes
|
|
require 'classes/PgDatabase.php';
|