Rev 812 | Rev 1157 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php
/*
pkgnet interface
Copyright (C) 2021-2022 Mateusz Viste
=== API ===
?a=pull&p=PACKAGE downloads the zip archive (svp) containing PACKAGE
?a=pull&p=PACKAGE-VER downloads the zip (svp) containing PACKAGE in version VER
?a=search&p=PHRASE list packages that match PHRASE
?a=checkup list of packages+versions in $_POST
*/
// messages in different languages (and necessary mappings for codepage conversions)
include 'lang.php';
// convert a utf-8 string into codepage related to lang
function cp_conv($s, $lang) {
global $CP_UTF, $CP_ENC;
$res = str_replace($CP_UTF[$lang], $CP_ENC[$lang], $s);
return($res);
}
function get_msg($id, $lang) {
global $MSG;
if (!empty($MSG[$id][$lang])) {
return cp_conv($MSG[$id][$lang], $lang);
} else {
return $MSG[$id]['en'];
}
}
function nicesize($bytes) {
if ($bytes < 1024) return(round($bytes / 1024, 1) . "K");
if ($bytes < 1024 * 1024) return(round($bytes / 1024) . "K");
return(round($bytes / 1024 / 1024, 1) . "M");
}
function csv_to_array($filename = '', $delimiter = "\t") {
//if (! file_exists($filename) || ! is_readable($filename)) return FALSE;
$handle = fopen($filename, 'r');
if ($handle === false) return(false);
$rez = array();
while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE) {
$rez[] = $row;
}
fclose($handle);
return $rez;
}
function tabulprint($ar_data, $ar_width, $margin = true) {
$count = 0;
foreach ($ar_data as $item) {
if ($count == 0) {
echo '|';
if ($margin) echo ' ';
}
echo substr(str_pad($item, $ar_width[$count]), 0, $ar_width[$count]);
if ($margin) {
echo ' | ';
} else {
echo '|';
}
$count++;
}
echo "\r\n";
}
// *** MAIN START ************************************************************
if (empty($_GET['a'])) {
http_response_code(404);
echo "ERROR: no action specified\r\n";
exit(0);
}
$lang = 'en';
if ((!empty($_GET['lang'])) && (preg_match('/[a-zA-Z][a-zA-Z]/', $_GET['lang']))) $lang = strtolower($_GET['lang']);
// load pkg desc translations
$descdb = json_decode(file_get_contents("pkg_desc_{$lang}.json"), true);
// switch to the packages directory
if (chdir('../../packages') === false) {
http_response_code(404);
echo "ERROR: server-side error, cannot access packages\r\n";
exit(0);
}
$a = strtolower($_GET['a']);
$p = '';
$v = '';
if ($a != 'checkup') {
if (empty($_GET['p'])) {
http_response_code(404);
echo "ERROR: no package specified\r\n";
exit(0);
}
$pv = explode('-', strtolower($_GET['p']));
$p = $pv[0];
if (!empty($pv[1])) $v = $pv[1];
}
// is action valid?
if (($a !== 'search') && ($a !== 'checkup') && ($a !== 'pull') && ($a !== 'pullsrc')) {
http_response_code(404);
echo "ERROR: invalid action\r\n";
exit(0);
}
// load pkg db
$db = json_decode(file_get_contents('_index.json'), true);
if (empty($db)) {
http_response_code(404);
echo "ERROR: server error, database not found\n";
exit(0);
}
// pull or pullsrc action (svp / zip)
if (($a === 'pull') || ($a === 'pullsrc')) {
$fname = false;
if (empty($v)) { // take first version (that's the preferred one)
$fname = array_key_first($db[$p]['versions']);
} else {
// look for a specific version string
foreach ($db[$p]['versions'] as $f => $e) {
if (strcasecmp($e['ver'], $v) == 0) {
$fname = $f;
break;
}
}
}
if (file_exists($fname)) {
if ($a === 'pullsrc') { // is it about source?
$fname = preg_replace('/svp$/', 'zip', $fname); // replace *.svp by *.zip
if (file_exists($fname)) {
header('Content-Disposition: attachment; filename="' . $fname);
header('Content-Type: application/octet-stream');
readfile($fname);
} else {
http_response_code(404);
echo get_msg('PKG_NO_SRC', $lang) . "\r\n";
}
} else {
header('Content-Disposition: attachment; filename="' . $fname);
header('Content-Type: application/octet-stream');
readfile($fname);
}
} else {
http_response_code(404);
echo get_msg('PKG_NOT_FOUND', $lang) . "\r\n";
}
exit(0);
}
// search action
if ($a === 'search') {
$matches = 0;
header('Content-Type: text/plain');
foreach ($db as $pkg => $meta) {
if ((stristr($pkg, $p)) || (stristr($meta['desc'], $p))) {
// fetch first (preferred) version
$prefver_fname = array_key_first($meta['versions']);
$prefver = array_shift($meta['versions']);
echo str_pad(strtoupper($pkg), 12);
echo str_pad(get_msg('VER', $lang) . " {$prefver['ver']} ", 16);
echo str_pad(get_msg('SIZE', $lang) . ' ' . nicesize(filesize($prefver_fname)), 16) . "BSUM: " . sprintf("%04X", $prefver['bsum']) . "\r\n";
// do I have a localized version of the description?
if (!empty($descdb[$pkg])) {
echo wordwrap(cp_conv($descdb[$pkg], $lang), 79, "\r\n", true);
} else {
echo wordwrap($meta['desc'], 79, "\r\n", true);
}
echo "\r\n";
// do I have any alt versions?
$altlist = array();
foreach ($meta['versions'] as $altver) {
$altlist[] = $pkg . '-' . $altver['ver'];
}
if (!empty($altlist)) {
echo wordwrap('[' . get_msg('ALT_VERS', $lang) . ' ' . implode(', ', $altlist), 79, "\r\n", true) . "]\r\n";
}
echo "\r\n";
$matches++;
}
}
if ($matches == 0) echo get_msg('NO_MATCHING_PKG', $lang) . "\r\n";
}
// checkup action
if ($a === 'checkup') {
$found = 0;
$remote_pkgs = csv_to_array("php://input", "\t"); // [0] = pkgname ; [1] = version
foreach ($remote_pkgs as $rpkg) {
$rpkg[0] = strtolower($rpkg[0]);
if (empty($db[$rpkg[0]])) continue;
$dbpkg = $db[$rpkg[0]];
// compare user's version with preferred version in repo
$prefver = array_shift($dbpkg['versions']);
if (strcasecmp($prefver['ver'], $rpkg[1]) == 0) continue;
// found version mismatch
if ($found == 0) {
echo str_pad('', 78, '-') . "\r\n";
tabulprint(array(get_msg('PACKAGE', $lang), get_msg('INSTALLED', $lang), get_msg('AVAILABLE', $lang)), array(8, 30, 30));
tabulprint(array('----------', '--------------------------------', '--------------------------------'), array(10, 32, 32), false);
}
$found++;
tabulprint(array('' . $rpkg[0], $rpkg[1], $prefver['ver']), array(8, 30, 30));
}
if ($found == 0) {
echo get_msg('NO_UPDATES', $lang) . "\r\n";
} else {
echo str_pad('', 78, '-') . "\r\n";
echo get_msg('FOUND_DIFFER', $lang) . ' ' . $found . "\r\n";
}
}
?>