<?php // Error handling error_reporting(E_ALL); ini_set('display_errors', 1); // Constants and helper functions 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); // Remove all classes foreach ($xpath->query('//*[@class]') as $element) { $element->removeAttribute('class'); } // Handle pagination if ($is_pagination && ($div = $xpath->query("//div")[0])) { $div->setAttribute('class', 'pagination'); // Fix pagination links for subdirectory 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') : []; } // Get request info $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $query = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY); $term = $_GET['term'] ?? ''; // Fetch and handle redirects [$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; } // Parse HTML $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'; } // Set title $site_title = 'Rural Dictionary' . ($path === '/' ? ', ' . date('d F') : '') . ($path === '/random.php' ? ': Random words' : ($term ? ": $term" : '')); // Output HTML ?> <!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>