5. Find a friend
Any app can search for people by name, including people who have never used it.
rc_user_search($q) finds people by the start of their username or of any word of their name, across the whole platform.
This is the code serving the zoo right now: read from disk for this request, from commit
77ff74344d (staging). The zoo's own self-check fetches this
page and compares it byte for byte with the file it runs.
exhibits/05-find-a-friend.php sha256 d8ec5a3ed97c · raw
1<?php 2// Exhibit 5. The directory is open to every app, so a brand-new app can find people who have 3// never used it. The zoo only searches for signed-in people, so it is not an open directory 4// for the whole internet. 5return [ 6 "n" => 5, "try" => "find a friend", "wing" => "Identity", 7 "title" => "Find a friend", 8 "promise" => "Any app can search for people by name, including people who have never used it.", 9 "block" => "rc_user_search(\$q) finds people by the start of their username or of any word of their name, across the whole platform.", 10 "show" => function (?array $me): string { 11 if (!$me) return '<p class="muted"><a href="' . h(rc_signin_url()) . '">Sign in</a> to search for people.</p>'; 12 return '<form class="row" id="find"><input name="q" placeholder="A name or username" autocomplete="off" required><button>Search</button></form><div class="people" id="found"></div>'; 13 }, 14 "api" => function (string $do, ?array $me, array $in, bool $post): ?array { 15 if ($do !== "search") return null; 16 if (!$me) return ["error" => "sign in to search", "status" => 401]; 17 return ["users" => rc_user_search((string)($in["q"] ?? ""), 12)]; 18 }, 19 // rc-check is root's robot: it has an account but has never used the zoo. 20 "check" => function (): array { 21 $hits = array_column(rc_user_search("rc-check", 5), "username"); 22 if (!in_array("rc-check", $hits, true)) return [false, "searching \"rc-check\" did not find root's robot, who has an account" . ($hits ? " (found: " . implode(", ", $hits) . ")" : "")]; 23 return [true, "found @rc-check, who has an account but has never used the zoo"]; 24 }, 25 "script" => <<<'JS' 26document.getElementById("find")?.addEventListener("submit", async (ev) => { 27 ev.preventDefault(); 28 const out = document.getElementById("found"); 29 const j = await zoo.call("/api/5/search?q=" + encodeURIComponent(ev.target.q.value)); 30 out.innerHTML = j.error ? zoo.esc(j.error) : (j.users.length ? j.users.map(zoo.person).join("") : '<p class="muted">Nobody by that name.</p>'); 31}); 32 33JS, 34];