#!/usr/bin/env php
<?php

define('ERR_OFFLINE', -1);
define('ERR_CONTENT', -2);

$cli = (php_sapi_name()=="cli");
if ($cli) {
	chdir(__DIR__);
} else {
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta content="text/html; charset=utf-8" http-equiv="content-type" />
		<title>Les RPM de Remi - Mirror check</title>
		<link href="enterprise/8/remi/x86_64/repoview/layout/repostyle.css" type="text/css" rel="stylesheet" />
		<meta content="index,follow" name="robots" />
		<link rel="shortcut icon" href="/favicon.ico" />
</head>
<body>
	<div id="page">
		<div id="top">
			<h1><span><a href="/">Les RPM de Remi - Mirror check</a></span></h1>
		</div>
		<p id="prelude">
			<a href="http://blog.famillecollet.com/">Blog</a> | 
			<a href="http://forums.famillecollet.com/">Forums</a> | 
			<a href="/">Repository</a>
		</p>
		<div id="wrapper">
			<div id="main">
				<div id="content">
					<h2>Mirror repository metadata check</h2>
<?php
}
$repos = [
	'enterprise/9'	=> 'Enterprise Linux 9',
	'enterprise/8'	=> 'Enterprise Linux 8',
	'enterprise/7'	=> 'Enterprise Linux 7',
	'fedora/41' 	=> 'Fedora 41',
	'fedora/40' 	=> 'Fedora 40',
	'fedora/39' 	=> 'Fedora 39',
];
$subs = [
	'remi',
	'test',
	'php56',
];
$archs = [
	'i386',
	'x86_64',
];

$mirrors = [
	'http://mirrors.neterra.net/remi/',
	'http://remi.schlundtech.de/',
	'http://mirror.cedia.org.ec/remi/',
	'http://ftp.arnes.si/mirrors/remi/',
	'http://mirrors.thzhost.com/remi/',
	'http://fr2.rpmfind.net/linux/remi/',
	'http://mirrors.netix.net/remi/',
	'http://remi.mirrors.cu.be/',
	'http://mirror.neolabs.kz/remi/',
	'https://remi.mirror.ate.info/',
	'https://mirrors.tuna.tsinghua.edu.cn/remi/',
	'https://mirror.23m.com/remi/',
	'https://mirror.oxilion.nl/remi/',
	'https://mirrors.uni-ruse.bg/remi/',
	'https://remi.mirror.karneval.cz/',
	'https://mirror.netsite.dk/remi/',
	'http://mirror.team-cymru.com/remi/',
	'https://mirror.netweaver.uk/remi/',
	'http://ftp.riken.jp/Linux/remi/',
	'https://mir01.syntis.net/remirepo/',
	'http://mirror.hoster.kz/remi/',
	'http://remirepo.reloumirrors.net/',
	'https://mirror.pit.teraswitch.com/remi/',
	'http://remi.mirror.liteserver.nl/',
	'https://mirror.marwan.ma/remi/',
	'https://remi.mirror.digitalpacific.com.au/',
	'http://merlin.fit.vutbr.cz/mirrors/remi/',
	'https://mirrors.ptisp.pt/remi/',
	'https://mirrors.chroot.ro/remi/',
	'https://mirrors.upr.edu/remi/',
	'http://mirror.digitalnova.at/remi/',
	'https://mirror.dk.team.blue/remi/',
	'https://mirror.dogado.de/remi/',
	'https://mirror.docker.ru/remi/',
	'https://repo.extreme-ix.org/remi/',
	'https://mirror.mangohost.net/remi/',
	'https://cdn.fjordos.no/remi/',
	'https://mirror.fjordos.no/remi/',
	'https://muug.ca/mirror/remi/',
	'https://mirror.netzwerge.de/remi/',
	'https://pit.mirror.jurassicinnovations.com/remi/',
	'http://mirror.yer.az/remi/',
	'https://mirror.raiolanetworks.com/remi/', 	// 2025-01-08
	'https://remi.mirror.wearetriple.com/',		// 2025-01-10
	'https://mirror.geo.yer.cloud/remi/',		// 2025-01-07
	'http://mirrors.bytes.ua/remi/',			// 2025-01-13
	'https://remi.mivzakim.net/',				// 2025-01-13
	'http://repo1.ash.innoscale.net/remi/',		// 2025-01-13
	'https://bd.mirror.vanehost.com/Remi/',		// 2025-01-17
];
$testing = [
	'http://mirrors.ukfast.co.uk/sites/remi/',	// 2025-01-28
	'http://remi.conetix.com.au/', 				// 2025-01-22
];
$disabled = [
	'https://repo1.vetta.net.nz/remi/',			// 2025-01-17 (too slow)
	'https://mirror.usi.edu/pub/remi/',			// 2024-04-03
	'http://mirror.xeonbd.com/remi/',
	'https://mirror.telkomuniversity.ac.id/remi/',
	'http://mirror.uta.edu.ec/remi/',
	'http://repo1.dal.innoscale.net/remi/',
	'http://repo1.sea.innoscale.net/remi/',
];
$deprecated = [
	'http://mirror.awanti.com/remi/',	// 2025-01-08
	'https://remi.srv.magticom.ge/',
	'https://mirror.sjc02.svwh.net/remi/',
	'http://mirror.upb.edu.co/remi/',
	'http://mirror.veriteknik.net.tr/remi/',
	'http://remi.mirrors.arminco.com/',
	'http://mirror.reconn.ru/remi/',
	'https://mirror.serverion.com/remi/',
	'http://mirror.innosol.asia/remi/',
	'http://mirror.nsw.coloau.com.au/remi/',
	'http://mirror.bebout.net/remi/',
	'http://mirrors.mediatemple.net/remi/',
	'http://remi.xpg.com.br/',
	'http://ap.stykers.moe/remi/',
	'http://mirrors.mivocloud.com/remi/',
	'http://nl.mirror.babylon.network/remi/',
	'http://fr.mirror.babylon.network/remi/',
	'http://ca.mirror.babylon.network/remi/',
	'http://mirror.h1host.ru/remi/',
	'http://mirror5.layerjet.com/remi/',
	'http://mirror.smartmedia.net.id/remi/',
	'http://remi.check-update.co.uk/',
	'http://iut-info.univ-reims.fr/remirpms/',
	'http://mirror.lablus.com/remi/',
	'http://remi.kazukioishi.net/',
	'http://remirpm.mirror.gymkl.ch/',
	'http://remi.mirror.net.in/',
	'http://remi-mirror.dedipower.com/',
	'http://mirror.beyondhosting.net/Remi/',
	'http://mirrors.cicku.me/remi/',
	'http://remi.mirrors.hostinginnederland.nl/',
	'http://mirror.1000mbps.com/remi/',
	'http://mirrors.hustunique.com/remi/',
	'http://mirror.pw/remi/',
];

function getRepoTime($uri) {
	$ctx = stream_context_create([
		'http' => [
			'timeout' => 7,
		]
	]);
	$txt = @file_get_contents($uri . '/repodata/repomd.xml', false, $ctx);
	if (!$txt) {
		return ERR_OFFLINE;
	}
	$xml = @simplexml_load_string($txt);
	if ($xml && $xml->revision>100000) {
		return intval($xml->revision);
	}
	return ERR_CONTENT;
}
if (isset($_GET['mirror']) && isset($repos[$_GET['mirror']])) {
	$path = $_GET['mirror'];
} else {
	$path = 'enterprise/9';
}
if (isset($_GET['repo']) && in_array($_GET['repo'], $subs)) {
	$repo = $_GET['repo'];
} else {
	$repo = 'remi';
}
if (isset($_GET['arch']) && in_array($_GET['arch'], $archs)) {
	$arch = $_GET['arch'];
} else {
	$arch = 'x86_64';
}
$name = $repos[$path];
$full = "$path/$repo/$arch";

if (!$cli) {
	echo "<ul class='pkglist'>\n";
	foreach ($repos as $rpath => $rname) {
		if ($path == $rpath) {
			printf("<li><b>%s</b></li>\n", $rname);
		} else {
			printf("<li><a href='?mirror=%s'>%s</a></li>", $rpath, $rname);
		}
	}
	echo "</ul>\n";
}
$pids = array();
$ref = getRepoTime($full);
if ($ref) {
	if (!$cli) echo "<ul class='pkglist'>\n";
	if (isset($_SERVER['argv'][1])) {
		switch ($_SERVER['argv'][1]) {
			case 'active':
				$tocheck = $mirrors;
				break;
			case 'testing':
				$tocheck = $testing;
				break;
			case 'disabled':
				$tocheck = $disabled;
				break;
			case 'deprecated':
				$tocheck = $deprecated;
				break;
			default:
				$tocheck = [];
				foreach ($mirrors as $mirror) {
					if (preg_match('|'.$_SERVER['argv'][1].'|', $mirror)) {
						$tocheck[] = $mirror;
					}
				}
				if (empty($tocheck)) {
					$tocheck[] = $_SERVER['argv'][1];
				}
		}
	} else {
		$tocheck = array_merge($mirrors, $testing);
	}
	printf(($cli ? "Check %d mirror(s) of %s (%s)\n" : "<h3>%s - %s</h3>\n"), count($tocheck), $name, date('r', $ref));
	foreach ($tocheck as $mirror) {
		if ($cli) {
			$pid = pcntl_fork();
			if ($pid<0) {
				die("Can't fork\n");
			} else if ($pid) {
				$pids[$pid] = $pid;
			} else { // Child
 				$pids = array();
				$loc = getRepoTime($mirror.$full);
				if ($loc == ERR_OFFLINE) {
					printf("%50.50s : ** Unreachable **\n", $mirror);
				} else if ($loc == ERR_CONTENT) {
					printf("%50.50s : ** Corrupted **\n", $mirror);
				} else if ($ref == $loc) {
					printf("%50.50s : Ok\n", $mirror);
					exit(0);
				} else if ($loc) {
					printf("%50.50s : %s\n", $mirror, date('r', $loc));
					exit(1);
				} else {
					printf("%50.50s : N/A\n", $mirror);
				}
				exit(2);
			}
			continue;
		}
		flush();
		$host = parse_url($mirror, PHP_URL_HOST);
		//printf("<li><a href='%s'>%s</a> ", $mirror, $host);
		$loc = getRepoTime($mirror.$full);
		if ($loc == ERR_OFFLINE) {
			printf("<li><a href='%s'>%s</a> <b>Unreachable</b></li>\n", $mirror, $mirror);
		} else if ($loc == ERR_CONTENT) {
			printf("<li><a href='%s'>%s</a> <b>Corrupted</b></li>\n", $mirror, $mirror);
		} else if ($ref == $loc) {
			printf("<li><a href='%s'>%s</a> Ok</li>\n", $mirror, $mirror);
		} else if ($loc) {
			printf("<li><a href='%s'>%s</a> %s</li>\n", $mirror, $mirror, date('r', $loc));
		} else {
			printf("<li><a href='%s'>%s</a> N/A</li>\n", $mirror, $mirror);
		}
	}
	if ($cli) {
		$nb = count($pids);
		$ok = $lack = 0;
		while (count($pids)) {
			if (posix_isatty(STDOUT)) {
				printf("Wait %d\r", count($pids));
			}
			$pid = pcntl_wait($status);
			if ($pid<0) {
				die("Cound not wait\n");
				exit (1);
			} else {
				switch (pcntl_wexitstatus($status)) {
					case 0:
						$ok++;
						break;
					case 1:
						$lack++;
						break;
				}
				unset($pids[$pid]);
			}
		}
		if ($nb) {
			printf("%3d mirrors checked on %s,\n%3d are OK\t(%d%%)\n%3d are late\t(%d%%)\n%3d are KO.\n",
				$nb, date("r"), $ok, $ok*100/$nb, $lack, $lack*100/$nb, $nb-$ok-$lack);
		}
	} else {
		echo "</ul>\n";
	}
} else {
	printf("<h3>%s - not found</h3>\n", $name);
}

if (!$cli) {
?>
				</div>
			</div>
			<div id="sidebar">
				<h2>Other links</h2>
				<ul class="levbarlist">
					<li><a href="http://www.amazon.com/wishlist/1AFH00IXFY6M0" class="nlink" title="My Amazon.com Wishlist">WishList</a></li>
					<li><a href="http://www.amazon.fr/wishlist/33P6MW6KQC8GX"  class="nlink" title="Mes Envies cadeaux sur Amazon.fr">Envies cadeaux</a></li>
				</ul>

			</div>
		</div>
	        <hr style="clear:both;"/>
	</div>
	<div id="footer">
		<ul id="w3c">
			<li>
				<a id="vxhtml" href="http://validator.w3.org/check/referer">XHTML 1.1 valide</a>
			</li>
			<li>
				<a id="vcss" href="http://jigsaw.w3.org/css-validator/check/referer">CSS 2.0 valide</a>
			</li>
		</ul>
		<p>
			Designed for <a href="http://blog.famillecoollet.com">Remi</a> by <a href="http://blog.ulysses.fr">Trashy</a>
		</p>
	</div>
</body>
</html>
<?php
}