Link Partner Board (No-DB “Backlink Exchange” That’s Not Spammy)
What this is: A tiny “link partner board” that lets people request a listing, then you manually approve it. This is a safer alternative to sketchy “backlink exchangers” because it’s curated, not automated.
What it does:
- Public page: shows approved partners + a request form.
- Admin mode: approve/deny requests.
- Optional reciprocity check: fetches their “links” page and looks for your site URL/host.
- Outbound links default to
rel="nofollow"to avoid turning your site into a link scheme.
Install:
- Create a folder like
/partners/ - Save the script below as
index.phpin that folder - Edit the config at the top (
$SITE_URL,$ADMIN_TOKEN) - Make sure the folder is writable so it can create
partners.json - Visit:
- Public:
/partners/ - Admin:
/partners/?admin=YOUR_TOKEN
Note: This is meant for real resources + genuine partners. If you try to automate swaps at scale, you’re basically building a link farm. 🚫
<?php
declare(strict_types=1);
/**
* Tiny Link Partner Board (No DB)
* - One file + partners.json
* - Public: approved list + request form
* - Admin: approve/deny + optional reciprocal check
*
* Admin URL:
* /partners/?admin=YOUR_TOKEN
*/
// ---------------- CONFIG ----------------
$SITE_NAME = 'Your Site';
$SITE_URL = 'https://example.com/'; // your canonical URL (include https)
$ADMIN_TOKEN = 'CHANGE_ME_LONG_RANDOM'; // keep secret
$DATA_FILE = __DIR__ . '/partners.json';
$OUT_REL = 'nofollow noopener'; // keep nofollow by default
$MAX_DESC = 160;
// anti-spam
$HP_FIELD = 'companyfax'; // honeypot (must stay empty)
$MIN_SECONDS = 5; // user must wait this long before submit
// --------------------------------------
// ---------- helpers ----------
function h(string $s): string { return htmlspecialchars($s, ENT_QUOTES, 'UTF-8'); }
function is_valid_url(string $u): bool {
if (!filter_var($u, FILTER_VALIDATE_URL)) return false;
$p = parse_url($u);
if (!$p || empty($p['scheme']) || empty($p['host'])) return false;
$sch = strtolower((string)$p['scheme']);
return $sch === 'http' || $sch === 'https';
}
function load_data(string $file): array {
if (!is_file($file)) return ['requests'=>[], 'partners'=>[]];
$raw = @file_get_contents($file);
if ($raw === false) return ['requests'=>[], 'partners'=>[]];
$j = json_decode($raw, true);
if (!is_array($j)) return ['requests'=>[], 'partners'=>[]];
$j['requests'] = (isset($j['requests']) && is_array($j['requests'])) ? $j['requests'] : [];
$j['partners'] = (isset($j['partners']) && is_array($j['partners'])) ? $j['partners'] : [];
return $j;
}
function save_data(string $file, array $data): bool {
$out = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
if ($out === false) return false;
return @file_put_contents($file, $out, LOCK_EX) !== false;
}
function now_iso(): string { return gmdate('c'); }
function quick_fetch(string $url): ?string {
$ctx = stream_context_create([
'http' => [
'timeout' => 6,
'user_agent' => 'TinyPartnerBoard/1.0',
'follow_location' => 1,
'max_redirects' => 3,
],
]);
$html = @file_get_contents($url, false, $ctx);
if ($html === false || $html === '') return null;
return $html;
}
function reciprocal_check(string $theirLinkPage, string $yourUrl): array {
// returns [ok(bool|null), note(string)]
$theirLinkPage = trim($theirLinkPage);
if ($theirLinkPage === '') return [null, 'No link page provided'];
if (!is_valid_url($theirLinkPage)) return [false, 'Invalid link page URL'];
$html = quick_fetch($theirLinkPage);
if ($html === null) return [false, 'Fetch failed'];
$yourHost = (string)(parse_url($yourUrl, PHP_URL_HOST) ?? '');
$ok = (stripos($html, $yourUrl) !== false) || ($yourHost !== '' && stripos($html, $yourHost) !== false);
return [$ok, $ok ? 'Found your link' : 'No link found'];
}
// ---------- state ----------
session_start();
if (!isset($_SESSION['t_form'])) $_SESSION['t_form'] = time();
$data = load_data($DATA_FILE);
$isAdmin = isset($_GET['admin']) && hash_equals($ADMIN_TOKEN, (string)$_GET['admin']);
$notice = '';
$error = '';
// ---------- actions ----------
if (!$isAdmin && $_SERVER['REQUEST_METHOD'] === 'POST' && (string)($_POST['action'] ?? '') === 'request') {
$hp = (string)($_POST[$HP_FIELD] ?? '');
if ($hp !== '') $error = 'Spam blocked.';
else {
$elapsed = time() - (int)($_SESSION['t_form'] ?? time());
if ($elapsed < $MIN_SECONDS) $error = 'Please wait a moment and try again.';
}
$name = trim((string)($_POST['name'] ?? ''));
$site = trim((string)($_POST['site'] ?? ''));
$linkpage = trim((string)($_POST['link_page'] ?? ''));
$desc = trim((string)($_POST['desc'] ?? ''));
if ($error === '') {
if ($name === '' || strlen($name) > 80) $error = 'Site name is required (max 80 chars).';
elseif (!is_valid_url($site)) $error = 'Please enter a valid site URL.';
elseif ($linkpage !== '' && !is_valid_url($linkpage)) $error = 'Link page URL looks invalid.';
elseif (strlen($desc) > $MAX_DESC) $error = 'Description too long.';
}
if ($error === '') {
$data['requests'][] = [
'id' => bin2hex(random_bytes(8)),
'name' => $name,
'site' => $site,
'link_page' => $linkpage,
'desc' => $desc,
'created' => now_iso(),
'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
];
if (save_data($DATA_FILE, $data)) {
$notice = 'Request received — thanks! (Manual review.)';
$_SESSION['t_form'] = time();
} else {
$error = 'Could not save. Check folder permissions.';
}
}
}
if ($isAdmin && $_SERVER['REQUEST_METHOD'] === 'POST') {
$action = (string)($_POST['action'] ?? '');
$id = (string)($_POST['id'] ?? '');
if ($action === 'approve') {
foreach ($data['requests'] as $k => $r) {
if (($r['id'] ?? '') === $id) {
$data['partners'][] = [
'id' => $r['id'],
'name' => $r['name'],
'site' => $r['site'],
'desc' => $r['desc'],
'link_page' => $r['link_page'],
'approved' => now_iso(),
'rel' => $OUT_REL,
'check_ok' => null,
'check_note'=> '',
'checked' => '',
];
unset($data['requests'][$k]);
$data['requests'] = array_values($data['requests']);
$notice = 'Approved.';
break;
}
}
save_data($DATA_FILE, $data);
}
if ($action === 'deny') {
foreach ($data['requests'] as $k => $r) {
if (($r['id'] ?? '') === $id) {
unset($data['requests'][$k]);
$data['requests'] = array_values($data['requests']);
$notice = 'Denied/removed.';
break;
}
}
save_data($DATA_FILE, $data);
}
if ($action === 'check') {
foreach ($data['partners'] as &$p) {
if (($p['id'] ?? '') === $id) {
[$ok, $note] = reciprocal_check((string)($p['link_page'] ?? ''), $SITE_URL);
$p['check_ok'] = $ok;
$p['check_note'] = $note;
$p['checked'] = now_iso();
$notice = 'Checked.';
break;
}
}
unset($p);
save_data($DATA_FILE, $data);
}
}
// sort newest first
$partners = $data['partners'];
usort($partners, fn($a,$b) => strcmp((string)($b['approved'] ?? ''), (string)($a['approved'] ?? '')));
?><!doctype html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?php echo h($SITE_NAME); ?> — Partners</title>
<style>
body{margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;background:#0b0f16;color:#e8eef8}
.wrap{max-width:860px;margin:0 auto;padding:20px}
.card{background:#111a26;border:1px solid rgba(255,255,255,.08);border-radius:14px;padding:14px;margin:12px 0}
a{color:#8ad1ff}
.muted{color:rgba(232,238,248,.7)}
.row{display:flex;gap:10px;flex-wrap:wrap}
input,textarea{width:100%;padding:10px;border-radius:10px;border:1px solid rgba(255,255,255,.12);background:#0c1420;color:#e8eef8}
textarea{min-height:90px;resize:vertical}
button{padding:10px 12px;border:0;border-radius:10px;background:#2a8cff;color:#07101b;font-weight:800;cursor:pointer}
button.secondary{background:#243449;color:#e8eef8}
code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
.ok{color:#7CFF9A} .bad{color:#FF7C7C}
</style>
<div class="wrap">
<div class="card">
<h1 style="margin:0 0 6px;"><?php echo h($SITE_NAME); ?> Partners</h1>
<div class="muted">Curated listings (manual approvals). Outbound links are <code>nofollow</code> by default.</div>
<?php if ($notice): ?><div class="card" style="background:#0e2233;border-color:rgba(42,140,255,.25)"><?php echo h($notice); ?></div><?php endif; ?>
<?php if ($error): ?><div class="card" style="background:#2a0f14;border-color:rgba(255,124,124,.25)"><?php echo h($error); ?></div><?php endif; ?>
</div>
<?php if (!$partners): ?>
<div class="card"><span class="muted">No partners listed yet.</span></div>
<?php else: ?>
<?php foreach ($partners as $p): ?>
<div class="card">
<div style="display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap">
<div>
<strong><?php echo h((string)$p['name']); ?></strong>
<div class="muted" style="font-size:13px;margin-top:3px">Approved: <?php echo h((string)($p['approved'] ?? '')); ?></div>
</div>
<div>
<a href="<?php echo h((string)$p['site']); ?>" target="_blank" rel="<?php echo h((string)($p['rel'] ?? 'nofollow noopener')); ?>">Visit →</a>
</div>
</div>
<?php if (!empty($p['desc'])): ?><div style="margin-top:8px"><?php echo h((string)$p['desc']); ?></div><?php endif; ?>
</div>
<?php endforeach; ?>
<?php endif; ?>
<?php if (!$isAdmin): ?>
<div class="card">
<h2 style="margin:0 0 10px;font-size:18px;">Request a listing</h2>
<div class="muted" style="margin:0 0 10px;">Real resources only. Manual review.</div>
<form method="post">
<input type="hidden" name="action" value="request">
<div class="row">
<div style="flex:1;min-width:220px">
<div class="muted" style="font-size:13px;margin:0 0 6px">Site name</div>
<input name="name" required maxlength="80" autocomplete="off">
</div>
<div style="flex:1;min-width:260px">
<div class="muted" style="font-size:13px;margin:0 0 6px">Your URL</div>
<input name="site" required placeholder="https://yoursite.com/">
</div>
</div>
<div style="margin-top:10px">
<div class="muted" style="font-size:13px;margin:0 0 6px">Link page (optional)</div>
<input name="link_page" placeholder="https://yoursite.com/links/">
</div>
<div style="margin-top:10px">
<div class="muted" style="font-size:13px;margin:0 0 6px">Short description (optional)</div>
<textarea name="desc" maxlength="<?php echo (int)$MAX_DESC; ?>" placeholder="What is your site about? (max <?php echo (int)$MAX_DESC; ?> chars)"></textarea>
</div>
<!-- honeypot -->
<div style="position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden">
<label>Leave blank <input name="<?php echo h($HP_FIELD); ?>"></label>
</div>
<div style="margin-top:12px">
<button type="submit">Send request</button>
</div>
</form>
</div>
<div class="card">
<strong>Optional “link back” snippet</strong>
<div class="muted" style="margin-top:6px;">If you want to link to this page:</div>
<pre style="white-space:pre-wrap;background:#0c1420;border:1px solid rgba(255,255,255,.10);padding:10px;border-radius:10px;margin-top:10px"><code><a href="<?php echo h($SITE_URL); ?>" rel="nofollow"><?php echo h($SITE_NAME); ?></a></code></pre>
</div>
<?php else: ?>
<div class="card">
<h2 style="margin:0 0 10px;font-size:18px;">Admin</h2>
<div class="muted">Requests: <?php echo count($data['requests']); ?> • Partners: <?php echo count($data['partners']); ?></div>
</div>
<?php if (!empty($data['requests'])): ?>
<div class="card">
<h3 style="margin:0 0 10px;">Pending</h3>
<?php foreach ($data['requests'] as $r): ?>
<div class="card" style="background:#0c1420">
<strong><?php echo h((string)$r['name']); ?></strong>
<div class="muted" style="font-size:13px;margin-top:4px"><?php echo h((string)$r['site']); ?></div>
<?php if (!empty($r['link_page'])): ?>
<div class="muted" style="font-size:13px;margin-top:4px">Link page: <?php echo h((string)$r['link_page']); ?></div>
<?php endif; ?>
<?php if (!empty($r['desc'])): ?><div style="margin-top:8px"><?php echo h((string)$r['desc']); ?></div><?php endif; ?>
<form method="post" style="margin-top:10px;display:flex;gap:10px;flex-wrap:wrap">
<input type="hidden" name="id" value="<?php echo h((string)$r['id']); ?>">
<button name="action" value="approve">Approve</button>
<button class="secondary" name="action" value="deny" type="submit">Deny</button>
</form>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php if (!empty($data['partners'])): ?>
<div class="card">
<h3 style="margin:0 0 10px;">Reciprocal check</h3>
<?php foreach ($data['partners'] as $p): ?>
<div class="card" style="background:#0c1420">
<strong><?php echo h((string)$p['name']); ?></strong>
<div class="muted" style="font-size:13px;margin-top:4px">Link page: <?php echo h((string)($p['link_page'] ?? '')); ?></div>
<div class="muted" style="font-size:13px;margin-top:4px">
Last check: <?php echo h((string)($p['checked'] ?? '')); ?> •
Status:
<?php
$ok = $p['check_ok'] ?? null;
if ($ok === true) echo '<span class="ok">OK</span>';
elseif ($ok === false) echo '<span class="bad">Missing</span>';
else echo '<span class="muted">—</span>';
?>
<?php if (!empty($p['check_note'])) echo ' (' . h((string)$p['check_note']) . ')'; ?>
</div>
<form method="post" style="margin-top:10px">
<input type="hidden" name="id" value="<?php echo h((string)$p['id']); ?>">
<button name="action" value="check">Run check</button>
</form>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
Comments (0)
No comments yet — be the first.