123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- <?php
- error_reporting(E_ALL);
- ini_set('display_errors', 1);
- const URBAN_DICT_BASE = 'https://www.urbandictionary.com';
- const URBAN_API_BASE = 'https://api.urbandictionary.com/v0';
- const DOM_OPTIONS = LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD;
- function handle_dom($html, $is_pagination = false) {
- if (empty($html)) return $html;
-
- $dom = new DOMDocument();
- @$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), DOM_OPTIONS);
- $xpath = new DOMXPath($dom);
-
-
- foreach ($xpath->query('//*[@class]') as $element) {
- $element->removeAttribute('class');
- }
-
-
- if ($is_pagination && ($div = $xpath->query("//div")[0])) {
- $div->setAttribute('class', 'pagination');
-
-
- foreach ($xpath->query("//a[@href]") as $link) {
- $href = $link->getAttribute('href');
- if (str_starts_with($href, '/?')) {
- $link->setAttribute('href', './' . substr($href, 1));
- }
- }
- }
-
- return $dom->saveHTML();
- }
- function fetch_url($url) {
- static $ch = null;
- if (!$ch) {
- $ch = curl_init();
- curl_setopt_array($ch, [
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_FOLLOWLOCATION => true,
- CURLOPT_TIMEOUT => 10,
- CURLOPT_ENCODING => '',
- CURLOPT_USERAGENT => 'Mozilla/5.0 Rural Dictionary',
- CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
- CURLOPT_TCP_FASTOPEN => 1,
- ]);
- }
- curl_setopt($ch, CURLOPT_URL, $url);
- return [
- curl_exec($ch),
- curl_getinfo($ch, CURLINFO_HTTP_CODE),
- curl_getinfo($ch, CURLINFO_EFFECTIVE_URL)
- ];
- }
- function fetch_thumbs($def_ids) {
- if (empty($def_ids)) return [];
- $response = @file_get_contents(
- URBAN_API_BASE . '/uncacheable?ids=' . implode(',', $def_ids),
- false,
- stream_context_create(['http' => ['timeout' => 5, 'ignore_errors' => true]])
- );
- $data = $response ? json_decode($response, true) : [];
- return isset($data['thumbs']) ? array_column($data['thumbs'], null, 'defid') : [];
- }
- $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
- $query = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY);
- $term = $_GET['term'] ?? '';
- [$html, $status_code, $final_url] = fetch_url(URBAN_DICT_BASE . $path . ($query ? "?$query" : ''));
- if ($final_url !== URBAN_DICT_BASE . $path . ($query ? "?$query" : '')) {
- header('Location: ' . parse_url($final_url, PHP_URL_PATH) .
- (($q = parse_url($final_url, PHP_URL_QUERY)) ? "?$q" : ''));
- exit;
- }
- $dom = new DOMDocument();
- @$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), DOM_OPTIONS);
- $xpath = new DOMXPath($dom);
- $results = [];
- $site_description = null;
- $pagination = null;
- if ($status_code !== 200) {
- $similar_words = array_map(
- fn($word) => handle_dom($dom->saveHTML($word)),
- iterator_to_array($xpath->query("//div[contains(@class, 'try-these')]//li/a"))
- );
- $template = '404';
- } else {
- $definitions = $xpath->query("//div[@data-defid]");
- $def_ids = array_map(fn($def) => $def->getAttribute('data-defid'), iterator_to_array($definitions));
- $thumbs_data = fetch_thumbs($def_ids);
-
- foreach ($definitions as $def) {
- $def_id = $def->getAttribute('data-defid');
- $word = $xpath->query(".//a[contains(@class, 'word')]", $def)[0]->textContent;
- $meaning = handle_dom($dom->saveHTML($xpath->query(".//div[contains(@class, 'meaning')]", $def)[0]));
- $example = handle_dom($dom->saveHTML($xpath->query(".//div[contains(@class, 'example')]", $def)[0]));
- $contributor = handle_dom($dom->saveHTML($xpath->query(".//div[contains(@class, 'contributor')]", $def)[0]));
-
- if (!$site_description) {
- $site_description = preg_replace('/\s+/', ' ', strip_tags($meaning));
- }
-
- $thumbs = $thumbs_data[$def_id] ?? [];
- $results[] = [
- $def_id, $word, $meaning, $example, $contributor,
- $thumbs['up'] ?? null, $thumbs['down'] ?? null
- ];
- }
-
- if ($pagination_node = $xpath->query("//div[contains(@class, 'pagination')]")[0]) {
- $pagination = handle_dom($dom->saveHTML($pagination_node), true);
- }
-
- $template = 'index';
- }
- $site_title = 'Rural Dictionary' .
- ($path === '/' ? ', ' . date('d F') : '') .
- ($path === '/random.php' ? ': Random words' : ($term ? ": $term" : ''));
- ?>
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <link rel="stylesheet" href="./static/css/main.css">
- <link rel="icon" type="image/png" href="./static/img/favicon.png">
- <title><?= htmlspecialchars($site_title) ?></title>
- <meta name="description" content="<?= htmlspecialchars($site_description ?? '') ?>">
- <meta property="og:url" content="<?= htmlspecialchars($_SERVER['REQUEST_URI']) ?>">
- <meta property="og:type" content="website">
- <meta property="og:title" content="<?= htmlspecialchars($site_title) ?>">
- <meta property="og:description" content="<?= htmlspecialchars($site_description ?? '') ?>">
- <meta property="twitter:domain" content="<?= htmlspecialchars($_SERVER['HTTP_HOST']) ?>">
- <meta property="twitter:url" content="<?= htmlspecialchars($_SERVER['REQUEST_URI']) ?>">
- <meta name="twitter:title" content="<?= htmlspecialchars($site_title) ?>">
- <meta name="twitter:description" content="<?= htmlspecialchars($site_description ?? '') ?>">
- </head>
- <body>
- <div style="text-align: center">
- <a href="./">
- <img src="./static/img/logo.png" alt="logo">
- </a>
- <form id="search" role="search" method="get" action="./define.php">
- <input
- autocomplete="off"
- type="search"
- id="term"
- name="term"
- placeholder="Search"
- aria-label="Search"
- value="<?= $path === '/define.php' ? htmlspecialchars($term) : '' ?>"
- autofocus
- >
- <button>Go</button>
- </form>
- <a href="./random.php">Random</a>
- <br>
- <a href="https://git.qunn.eu/poesty/rural-dict/src/php-port">Source Code</a>
- </div>
- <br>
-
- <?php if ($template === '404'): ?>
- <div style="text-align: center">
- <h2>Definition not found: <?= htmlspecialchars($term) ?></h2>
- <?php if (!empty($similar_words)): ?>
- <?php foreach ($similar_words as $word): ?>
- <h3 class="underline-links"><?= $word ?></h3>
- <?php endforeach; ?>
- <?php else: ?>
- <p>There are no similar words. Try correcting your search.</p>
- <?php endif; ?>
- </div>
- <?php else: ?>
- <?php foreach ($results as [$definition_id, $word, $meaning, $example, $contributor, $thumbs_up, $thumbs_down]): ?>
- <div data-id="<?= htmlspecialchars($definition_id) ?>">
- <a href="./define.php?term=<?= urlencode($word) ?>">
- <h2><?= htmlspecialchars($word) ?></h2>
- </a>
- <div class="underline-links">
- <p><?= $meaning ?></p>
- <p><i><?= $example ?></i></p>
- </div>
- <div><?= $contributor ?></div>
- <?php if ($thumbs_up !== null && $thumbs_down !== null): ?>
- <p>
- <span title="thumbs up">👍<?= htmlspecialchars($thumbs_up) ?></span>
- <span title="thumbs down">👎<?= htmlspecialchars($thumbs_down) ?></span>
- </p>
- <?php endif; ?>
- </div>
- <br>
- <?php endforeach; ?>
- <?php if ($pagination): ?>
- <?= $pagination ?>
- <?php endif; ?>
- <?php endif; ?>
- </body>
- </html>
|