my website banner

made the dead drop code more readable...
authorDavid Polakovic <email@dpolakovic.space>
Thu, 1 May 2025 09:22:30 +0000 (11:22 +0200)
committerDavid Polakovic <email@dpolakovic.space>
Thu, 1 May 2025 09:22:30 +0000 (11:22 +0200)
dead-drop.php
php/captcha.php [new file with mode: 0644]
php/dd.php [deleted file]
php/dd2.php [new file with mode: 0644]
test.php

index bd51e795568faaa077f714f377a435eb105faff5..628dfe17f9c252a232999c996dfea063d6e6fa77 100755 (executable)
@@ -7,7 +7,8 @@
     <link rel="icon"         href="./Pictures/dot.png">
     <link rel="stylesheet"   href="./Styles/styles.css">
     <?php require_once('./php/config.php'); ?>
-    <?php require_once('./php/dd.php'); ?>
+    <?php require_once('./php/dd2.php'); ?>
+  
     <link rel="author"       href="mailto:email@dpolakovic.space">
     <meta name="description" content="personal website and git server">
     <meta name="author"      content="David Polakovic, 2023">
@@ -45,7 +46,7 @@
        <br>
     A dead drop is a spy technique used for anonymous information exchange. When you stash your 
     message in a dead drop, it will be hidden from anyone who doesn't know its location. It 
-    also uses MD5 hashing and AES-256-CBC encryption to keep it hidden from the hosting provider 
+    also uses SHA-256 hashing and AES-256-CBC encryption to keep it hidden from the hosting provider 
     and webmaster as well. Enter the coordinates of a dead drop to check if it's hot (has stashed message) 
     or if it's cold (empty).
     <!-- Still, it's a good idea to keep your message brief in case the dead drop location is ever compromised. -->
@@ -61,7 +62,7 @@
     <p>
           <i>
             <?php countActiveDrops(); ?> 
-            Every dead drop goes cold after 18 hours.
+            Every dead drop goes cold after one sol.
             <br><br>
           </i>
 </p>
diff --git a/php/captcha.php b/php/captcha.php
new file mode 100644 (file)
index 0000000..213d1c6
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+// === captcha.php ===
+
+function captcha($token, $w3w) {
+    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['captchaTry'])) {
+        $userInput = strtolower(preg_replace('/[^a-z0-9]/', '', $_POST['captchaTry']));
+        if (isset($_SESSION['captcha']) && $userInput === $_SESSION['captcha']) {
+            return 'YAY';
+        }
+        echo "Wrong captcha. Try again.<br>";
+    }
+
+    echo "<form method='post'>";
+    echo "<input type='hidden' name='csrf_token' value='" . htmlentities($token) . "'>";
+    echo "<input type='hidden' name='inputString' value='" . htmlentities($w3w) . "'>";
+    generatePicture();
+    echo "<br><input type='text' name='captchaTry' placeholder='Type the characters' required>";
+    echo "<input type='submit' value='Verify'>";
+    echo "</form>";
+    return null;
+}
+
+function generatePicture() {
+    $width = 95;
+    $height = 30;
+
+    $image = imagecreatetruecolor($width, $height);
+
+    $isWhite = rand(0, 1) === 1;
+    $bgColor = $isWhite ? imagecolorallocate($image, 255, 255, 255) : imagecolorallocate($image, 0, 0, 0);
+    imagefilledrectangle($image, 0, 0, $width, $height, $bgColor);
+
+    $charset = 'abcdefghijklmnpqrstuvwxyz123456789';
+    $randomStr = '';
+    for ($i = 0; $i < 4; $i++) {
+        $randomStr .= $charset[rand(0, strlen($charset) - 1)];
+    }
+
+    $_SESSION['captcha'] = $randomStr;
+
+    $fontSize = 5;
+    $charWidth = imagefontwidth($fontSize);
+    $charHeight = imagefontheight($fontSize);
+    $textWidth = $charWidth * strlen($randomStr);
+    $x = ($width - $textWidth) / 2;
+    $y = ($height - $charHeight) / 2;
+
+    $colors = [
+        imagecolorallocate($image, 255, 0, 0),
+        imagecolorallocate($image, 0, 0, 255),
+        imagecolorallocate($image, 0, 255, 0),
+        imagecolorallocate($image, 255, 0, 255),
+        imagecolorallocate($image, 0, 255, 255)
+    ];
+
+    for ($i = 0; $i < strlen($randomStr); $i++) {
+        $char = $randomStr[$i];
+        $charColor = $colors[array_rand($colors)];
+        imagestring($image, $fontSize, $x + $i * $charWidth, $y, $char, $charColor);
+    }
+
+    ob_start();
+    imagepng($image);
+    $imageData = ob_get_clean();
+    imagedestroy($image);
+
+    $base64 = base64_encode($imageData);
+    echo '<img src="data:image/png;base64,' . $base64 . '" alt="Random Image">';
+}
diff --git a/php/dd.php b/php/dd.php
deleted file mode 100644 (file)
index eaade51..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-<?php
-
-function countActiveDrops() {
-    $directory = "./Dead-drops";
-
-    // Check if the directory exists
-    if (is_dir($directory)) {
-        // Scan the directory and get all files
-        $files = scandir($directory);
-        
-        // Filter out the current (.) and parent (..) directories
-        $files = array_diff($files, array('.', '..'));
-        
-        // Count the number of files
-        $fileCount = count($files);
-        
-        // Echo the result
-        if ($fileCount == 0){
-        echo "There is no hot drop on this domain right now.";
-        }
-
-        if ($fileCount == 1){
-        echo "There is exactly one hot drop on this domain right now.";
-            }
-
-        if ($fileCount > 1){
-        echo "There are $fileCount hot drops on this domain right now.";
-        }
-        
-    } else {
-        echo "Directory '$directory' does not exist.";
-    }
-
-}
-
-function cleanTheCity() {
-    $directory = "./Dead-drops";
-    $now = time();
-    $expiry = 18 * 3600;
-
-    if (is_dir($directory)) {
-        $files = scandir($directory);
-        foreach ($files as $file) {
-            // Skip the specific file by name
-            if ($file == '75cfce5a009d44910a23bd55a3f8f0bd') {
-                continue;
-            }
-
-            $filePath = $directory . DIRECTORY_SEPARATOR . $file;
-            if (is_file($filePath)) {
-                $fileAge = $now - filemtime($filePath);
-                if ($fileAge > $expiry) {
-                    unlink($filePath);
-                }
-            }
-        }
-    } else {
-        echo "<p><strong>Error:</strong> Folder <code>./Locations</code> not found.</p>";
-    }
-}
-
-
-
-function deadDropUI() {
-    session_start();
-    $csrf_lifetime = 600;
-    $session_id_key = 'csrf_token_session_id';
-
-    if (!isset($_SESSION['csrf_token'], $_SESSION['csrf_token_time'], $_SESSION[$session_id_key]) ||
-        session_id() !== $_SESSION[$session_id_key] ||
-        time() - $_SESSION['csrf_token_time'] > $csrf_lifetime) {
-        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
-        $_SESSION['csrf_token_time'] = time();
-        $_SESSION[$session_id_key] = session_id();
-    }
-
-    $token = $_SESSION['csrf_token'];
-    $result = deadDropLogic();
-    $dropCount = count(glob('./Dead-drops/*'));
-
-    if (($result['mode'] === 'initial' && $dropCount < 501) ||
-        ($result['mode'] === 'readonly' && $result['status'] === 'invalid')) {
-        echo <<<HTML
-    <style>input[type="text"],input[type="submit"] { font-size: 16.5px; }</style>
-    <form method="post">
-    <label><a href="https://en.wikipedia.org/wiki/W3w#Design" target="_blank">?</a>&nbsp;</label>
-    <input type="hidden" name="csrf_token" value="{$token}">
-    <input type="text" id="inputString" name="inputString" placeholder="///what.three.words" size="30" maxlength="50" required>
-    <input type="submit" value="Check">
-    </form>
-    HTML;
-        } elseif ($result['mode'] === 'initial' && $dropCount >= 501) {
-            echo "This domain is too hot. Come back later when there won't be so much heat";
-        }
-
-        if ($result['mode'] === 'readonly') {
-            if ($result['status'] === 'hot') {
-                echo "<pre>" . htmlspecialchars($result['decrypted'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') . "</pre>";
-                echo <<<HTML
-    <form method="post">
-    <input type="hidden" name="csrf_token" value="{$token}">
-    <input type="hidden" name="burnW3W" value="{$result['w3w']}">
-    <input type="submit" value="Burn message">
-    </form>
-    HTML;
-            } elseif ($result['status'] === 'cold') {
-                echo "<h3>" . htmlentities($result['w3w']) ."</h3>This drop is cold. You can stash your message here.<br><br>";
-                echo <<<HTML
-    <form method="post">
-    <input type="hidden" name="csrf_token" value="{$token}">
-    <input type="hidden" name="originalW3W" value="{$result['w3w']}">
-    <textarea name="stashContent" maxlength="4096" rows="10" cols="60" placeholder="max 4096 chars" required></textarea><br><br>
-    <input type="submit" value="Stash">
-    </form>
-    HTML;
-            } elseif ($result['status'] === 'invalid') {
-                echo "<br>{$result['message']}";
-            }
-        } elseif ($result['mode'] === 'stashed') {
-            echo "<h3>Message stashed at " . htmlentities($result['w3w']) ."</h3>Your dead drop is hot.";
-        }
-}
-
-function deadDropLogic() {
-    session_start();
-    $csrf_lifetime = 600;
-    $session_id_key = 'csrf_token_session_id';
-
-    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
-        if (!isset($_POST['csrf_token'], $_SESSION['csrf_token'], $_SESSION['csrf_token_time'], $_SESSION[$session_id_key]) ||
-            $_POST['csrf_token'] !== $_SESSION['csrf_token'] ||
-            session_id() !== $_SESSION[$session_id_key] ||
-            time() - $_SESSION['csrf_token_time'] > $csrf_lifetime) {
-            die('CSRF token invalid or expired. Reload the website, that usually helps...');
-        }
-
-        if (isset($_POST['burnW3W'])) {
-            $input = trim($_POST['burnW3W']);
-            $hashed = md5($input);
-            if (!isValidHash($hashed)) die('Invalid hash');
-            $file = './Dead-drops/' . $hashed;
-            if (file_exists($file)) unlink($file);
-            header("Location: https://www.dpolakovic.space/dead-drop");
-            exit;
-        }
-
-        if (isset($_POST['stashContent'], $_POST['originalW3W'])) {
-            $input = trim($_POST['originalW3W']);
-            $hashed_w3w = md5($input);
-            if (!isValidHash($hashed_w3w)) die('Invalid hash');
-            $plaintext = $_POST['stashContent'];
-
-            if (strlen($plaintext) > 4096) {
-                return ['mode' => 'readonly', 'w3w' => $input, 'status' => 'invalid', 'message' => 'ERROR: Message too long.'];
-            }
-
-            $filepath = "./Dead-drops/{$hashed_w3w}";
-            if (file_exists($filepath)) {
-                return ['mode' => 'readonly', 'w3w' => $input, 'status' => 'hot'];
-            }
-
-            $cipher = "AES-256-CBC";
-            $key = hash('sha256', $input);
-            $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher));
-            $encrypted = openssl_encrypt($plaintext, $cipher, $key, 0, $iv);
-            $output = base64_encode($iv . $encrypted);
-            file_put_contents($filepath, $output);
-            return ['mode' => 'stashed', 'w3w' => $input];
-        }
-
-        if (isset($_POST['inputString'])) {
-            $input = trim($_POST['inputString']);
-            if (!validateString($input)) {
-                return ['mode' => 'readonly', 'w3w' => $input, 'status' => 'invalid', 'message' => 'ERROR: Invalid coordinates format.'];
-            }
-            if (!validateStringW3W($input)) {
-                return ['mode' => 'readonly', 'w3w' => $input, 'status' => 'invalid', 'message' => 'ERROR: Place you are looking for doesn\'t exist.'];
-            }
-            $hashed = md5($input);
-            if (!isValidHash($hashed)) die('Invalid hash');
-            $dropPath = './Dead-drops/' . $hashed;
-            if (file_exists($dropPath)) {
-                $raw = file_get_contents($dropPath);
-                $data = base64_decode($raw);
-                $iv_len = openssl_cipher_iv_length("AES-256-CBC");
-                $iv = substr($data, 0, $iv_len);
-                $ciphertext = substr($data, $iv_len);
-                $key = hash('sha256', $input);
-                $decrypted = openssl_decrypt($ciphertext, "AES-256-CBC", $key, 0, $iv);
-                return [
-                    'mode' => 'readonly',
-                    'w3w' => $input,
-                    'status' => 'hot',
-                    'decrypted' => $decrypted
-                ];
-            } else {
-                return [
-                    'mode' => 'readonly',
-                    'w3w' => $input,
-                    'status' => 'cold'
-                ];
-            }
-        }
-    }
-
-    return ['mode' => 'initial'];
-}
-
-function isValidHash($hash) {
-    return preg_match('/^[a-f0-9]{32}$/', $hash) === 1;
-}
-
-
-
-
-
-
-
-
-
-
-
-function validateString($str) {
-        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
-            return false;
-        }
-
-        if (substr($str, 0, 3) !== "///") {
-            return false;
-        }
-
-        $parts = substr($str, 3);
-        if (substr_count($parts, ".") !== 2) {
-            return false;
-        }
-
-        if (!preg_match('/^[a-z]+\.[a-z]+\.[a-z]+$/', $parts)) {
-            return false;
-        }
-
-        return true;
-}
-
-function validateStringW3W($str) {
-    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
-        return false;
-    }
-
-    $API_KEY = '747757BO';
-    $cleaned = substr($str, 3);
-    $url = 'https://api.what3words.com/v3/autosuggest?input=' . urlencode($cleaned) . '&key=' . urlencode($API_KEY);
-
-    $ch = curl_init();
-    curl_setopt($ch, CURLOPT_URL, $url);
-    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-    $response = curl_exec($ch);
-
-    if (curl_errno($ch)) {
-        echo "Curl error: " . curl_error($ch);
-        return false;
-    }
-
-    curl_close($ch);
-    $result = json_decode($response, true);
-
-    if (isset($result['suggestions']) && count($result['suggestions']) > 0) {
-        foreach ($result['suggestions'] as $suggestion) {
-            if (strcasecmp($suggestion['words'], $cleaned) === 0) {
-                return true;
-            }
-        }
-    }
-
-    return false;
-}
\ No newline at end of file
diff --git a/php/dd2.php b/php/dd2.php
new file mode 100644 (file)
index 0000000..ab15d45
--- /dev/null
@@ -0,0 +1,260 @@
+<?php
+
+define('API_KEY', 'ABC123#@!');
+define('DROP_EXPIRY_SECONDS', (24 * 3600) + 2375); // 24h 39min 35sec (one martian day)
+define('DEAD_DROP_DIR', './Dead-drops');
+define('DROP_LIMIT', 1024);                        // maximum amount of hot dead drops
+define('CSRF_TOKEN_LIFETIME', 600);
+define('IGNORED_DROPS', [                          // list permanent drops (test purposes)
+    '62a5bced62e7219c8e164d64fdae67900476ed54f39c5851a07bb65b590e04df'
+]);
+
+require_once 'captcha.php';
+
+// === main.php ===
+
+function countActiveDrops() {
+    if (is_dir(DEAD_DROP_DIR)) {
+        $files = scandir(DEAD_DROP_DIR);
+        $files = array_diff($files, array('.', '..'));
+        $fileCount = count($files);
+
+        if ($fileCount == 0) {
+            echo "There is no hot drop on this domain right now.";
+        } elseif ($fileCount == 1) {
+            echo "There is exactly one hot drop on this domain right now.";
+        } else {
+            echo "There are $fileCount hot drops on this domain right now.";
+        }
+    } else {
+        echo "Directory '" . DEAD_DROP_DIR . "' does not exist.";
+    }
+}
+
+function cleanTheCity() {
+    $now = time();
+    if (is_dir(DEAD_DROP_DIR)) {
+        $files = scandir(DEAD_DROP_DIR);
+        foreach ($files as $file) {
+            if (in_array($file, IGNORED_DROPS)) continue;
+
+            $filePath = DEAD_DROP_DIR . DIRECTORY_SEPARATOR . $file;
+            if (is_file($filePath)) {
+                $fileAge = $now - filemtime($filePath);
+                if ($fileAge > DROP_EXPIRY_SECONDS) {
+                    unlink($filePath);
+                }
+            }
+        }
+    } else {
+        echo "<p><strong>Error:</strong> Folder <code>" . DEAD_DROP_DIR . "</code> not found.</p>";
+    }
+}
+
+function deadDropUI() {
+    session_start();
+    $session_id_key = 'csrf_token_session_id';
+
+    if (!isset($_SESSION['csrf_token'], $_SESSION['csrf_token_time'], $_SESSION[$session_id_key]) ||
+        session_id() !== $_SESSION[$session_id_key] ||
+        time() - $_SESSION['csrf_token_time'] > CSRF_TOKEN_LIFETIME) {
+        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
+        $_SESSION['csrf_token_time'] = time();
+        $_SESSION[$session_id_key] = session_id();
+    }
+
+    $token = $_SESSION['csrf_token'];
+    $result = deadDropLogic();
+    $dropFiles = glob(DEAD_DROP_DIR . '/*');
+    $dropCount = count($dropFiles);
+
+    if ($result['mode'] === 'readonly' && $result['status'] === 'cold') {
+        if ($dropCount > DROP_LIMIT) {
+            echo "There is too much heat on this domain right now to stash a new message. Come back later.";
+            return;
+        }
+        $slowDown = checkDropRate();
+        if ($slowDown) {
+            if (captcha($token, $result['w3w']) !== 'YAY') return;
+        }
+        echo "<h3>" . htmlentities($result['w3w']) ."</h3>This drop is cold. You can stash your message here.<br><br>";
+        echo <<<HTML
+<form method="post">
+<input type="hidden" name="csrf_token" value="{$token}">
+<input type="hidden" name="originalW3W" value="{$result['w3w']}">
+<textarea name="stashContent" maxlength="4096" rows="10" cols="60" placeholder="max 4096 chars" required></textarea><br>
+<input type="submit" value="Stash">
+</form>
+HTML;
+        return;
+    }
+
+    if ($result['mode'] === 'initial' ||
+        ($result['mode'] === 'readonly' && $result['status'] === 'invalid')) {
+        echo <<<HTML
+<style>input[type="text"],input[type="submit"] { font-size: 16.5px; }</style>
+<form method="post">
+<label><a href="https://www.what3words.com/" target="_blank">?</a>&nbsp;</label>
+<input type="hidden" name="csrf_token" value="{$token}">
+<input type="text" id="inputString" name="inputString" placeholder="///what.three.words (English)" size="30" maxlength="50" required>
+<input type="submit" value="Check">
+</form>
+HTML;
+    }
+
+    if ($result['mode'] === 'readonly') {
+        if ($result['status'] === 'hot') {
+            echo "<pre>" . htmlspecialchars($result['decrypted'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') . "</pre>";
+            echo <<<HTML
+<form method="post">
+<input type="hidden" name="csrf_token" value="{$token}">
+<input type="hidden" name="burnW3W" value="{$result['w3w']}">
+<input type="submit" value="Burn message">
+</form>
+HTML;
+        } elseif ($result['status'] === 'invalid') {
+            echo "<br>{$result['message']}";
+        }
+    } elseif ($result['mode'] === 'stashed') {
+        echo "<h3>Message stashed at " . htmlentities($result['w3w']) ."</h3>Your dead drop is hot.";
+    }
+}
+
+function deadDropLogic() {
+    session_start();
+    $session_id_key = 'csrf_token_session_id';
+
+    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+        if (!isset($_POST['csrf_token'], $_SESSION['csrf_token'], $_SESSION['csrf_token_time'], $_SESSION[$session_id_key]) ||
+            $_POST['csrf_token'] !== $_SESSION['csrf_token'] ||
+            session_id() !== $_SESSION[$session_id_key] ||
+            time() - $_SESSION['csrf_token_time'] > CSRF_TOKEN_LIFETIME) {
+            die('CSRF token invalid or expired. Reload the website, that usually helps...');
+        }
+
+        if (isset($_POST['burnW3W'])) {
+            $input = trim($_POST['burnW3W']);
+            $hashed = hash('sha256', $input);
+            if (!isValidHash($hashed)) die('Invalid hash');
+            $file = DEAD_DROP_DIR . '/' . $hashed;
+            if (file_exists($file)) unlink($file);
+            header("Location: https://www.dpolakovic.space/dead-drop");
+            exit;
+        }
+
+        if (isset($_POST['stashContent'], $_POST['originalW3W'])) {
+            $input = trim($_POST['originalW3W']);
+            $hashed_w3w = hash('sha256', $input);
+            if (!isValidHash($hashed_w3w)) die('Invalid hash');
+            $plaintext = $_POST['stashContent'];
+
+            if (strlen($plaintext) > 4096) {
+                return ['mode' => 'readonly', 'w3w' => $input, 'status' => 'invalid', 'message' => 'ERROR: Message too long.'];
+            }
+
+            $filepath = DEAD_DROP_DIR . "/{$hashed_w3w}";
+            if (file_exists($filepath)) {
+                return ['mode' => 'readonly', 'w3w' => $input, 'status' => 'hot'];
+            }
+
+            $cipher = "AES-256-CBC";
+            $key = hash('sha256', $input);
+            $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher));
+            $encrypted = openssl_encrypt($plaintext, $cipher, $key, 0, $iv);
+            $output = base64_encode($iv . $encrypted);
+            file_put_contents($filepath, $output);
+            return ['mode' => 'stashed', 'w3w' => $input];
+        }
+
+        if (isset($_POST['inputString'])) {
+            $input = trim($_POST['inputString']);
+            if (!validateString($input)) {
+                return ['mode' => 'readonly', 'w3w' => $input, 'status' => 'invalid', 'message' => 'ERROR: Invalid coordinates format.'];
+            }
+            if (!validateStringW3W($input)) {
+                return ['mode' => 'readonly', 'w3w' => $input, 'status' => 'invalid', 'message' => 'ERROR: Place you are looking for doesn\'t exist.'];
+            }
+            $hashed = hash('sha256', $input);
+            if (!isValidHash($hashed)) die('Invalid hash');
+            $dropPath = DEAD_DROP_DIR . '/' . $hashed;
+            if (file_exists($dropPath)) {
+                $raw = file_get_contents($dropPath);
+                $data = base64_decode($raw);
+                $iv_len = openssl_cipher_iv_length("AES-256-CBC");
+                $iv = substr($data, 0, $iv_len);
+                $ciphertext = substr($data, $iv_len);
+                $key = hash('sha256', $input);
+                $decrypted = openssl_decrypt($ciphertext, "AES-256-CBC", $key, 0, $iv);
+                return [
+                    'mode' => 'readonly',
+                    'w3w' => $input,
+                    'status' => 'hot',
+                    'decrypted' => $decrypted
+                ];
+            } else {
+                return [
+                    'mode' => 'readonly',
+                    'w3w' => $input,
+                    'status' => 'cold'
+                ];
+            }
+        }
+    }
+
+    return ['mode' => 'initial'];
+}
+
+function isValidHash($hash) {
+    return preg_match('/^[a-f0-9]{64}$/', $hash) === 1;
+}
+
+function validateString($str) {
+    if ($_SERVER['REQUEST_METHOD'] !== 'POST') return false;
+    if (substr($str, 0, 3) !== "///") return false;
+    $parts = substr($str, 3);
+    if (substr_count($parts, ".") !== 2) return false;
+    if (!preg_match('/^[a-z]+\.[a-z]+\.[a-z]+$/', $parts)) return false;
+    return true;
+}
+
+function validateStringW3W($str) {
+    if ($_SERVER['REQUEST_METHOD'] !== 'POST') return false;
+    $cleaned = substr($str, 3);
+    $url = 'https://api.what3words.com/v3/autosuggest?input=' . urlencode($cleaned) . '&key=' . urlencode(API_KEY);
+    $ch = curl_init();
+    curl_setopt($ch, CURLOPT_URL, $url);
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+    $response = curl_exec($ch);
+    if (curl_errno($ch)) {
+        echo "Curl error: " . curl_error($ch);
+        return false;
+    }
+    curl_close($ch);
+    $result = json_decode($response, true);
+    if (isset($result['suggestions']) && count($result['suggestions']) > 0) {
+        foreach ($result['suggestions'] as $suggestion) {
+            if (strcasecmp($suggestion['words'], $cleaned) === 0) return true;
+        }
+    }
+    return false;
+}
+
+function checkDropRate() {
+    $files = glob(DEAD_DROP_DIR . '/*');
+    usort($files, function($a, $b) {
+        return filemtime($b) - filemtime($a);
+    });
+
+    $now = time();
+    $recentFiles = array_filter($files, fn($f) => $now - filemtime($f) <= 60);
+
+    if (count($recentFiles) > 50) return true;
+
+    if (count($files) >= 2) {
+        $t1 = filemtime($files[0]);
+        $t2 = filemtime($files[1]);
+        if (abs($t1 - $t2) < 2) return true;
+    }
+
+    return false;
+}
index 6fbf846a93a7dc0772eb25ea738fb91ca772262f..0c1e86124aa862349cb4547a916cfffe28b2be84 100755 (executable)
--- a/test.php
+++ b/test.php
@@ -8,6 +8,7 @@
     <link rel="icon"         href="./Pictures/dot.png">
     <link rel="stylesheet"   href="./Styles/styles.css">
     <?php require_once('./php/config.php');?> 
+    <?php require_once('./php/captcha.php');?> 
     <link rel="author"       href="mailto:email@dpolakovic.space">
     <meta name="description" content="personal website and git server">
     <meta name="author"      content="David Polakovic, 2023">
@@ -28,9 +29,9 @@
       <ul>
        <li><a href="https://dpolakovic.space">About</a></li>
        <li><a href="https://dpolakovic.space/blog.php">Blog</a></li>
-       <!-- <li><a href="https://dpolakovic.space/dir.html">My web directory</a></li> -->
-       <li><a href="https://dpolakovic.space/lib.html">My library</a></li> 
-       <li><a href="https://dpolakovic.space/test.html">TEST</a></li>
+       <li><a href="https://dpolakovic.space/mars-clock.html">Mars clock</a></li> 
+       <li><a href="https://dpolakovic.space/dead-drop.html">dead-drop</a></li> 
+  <li><a href="https://dpolakovic.space/test.html">TEST</a></li>
        <li><a class="gitserver" href="https://git.dpolakovic.space">Git server</a>
        </li>
       </ul>
@@ -78,7 +79,8 @@ if (isWebsiteOnline2($websiteUrl)) {
        
       </p>
       <p>
-       <img src="https://c.tenor.com/qKwcziL1dhAAAAAi/alien-dancing.gif" alt="cool dancing alien" class="bee-gifs">
+       <!-- <img src="https://dpolakovic.space/Pictures/donkey-kong-country-eyes.gif" alt="cool dancing alien"> -->
+        <img src="https://dpolakovic.space/Pictures/bonzi-buddy.gif" alt="cool dancing alien">
       </p>
       <p>
        <form action="https://www.paypal.com/donate" method="post" target="_top">
@@ -87,15 +89,12 @@ if (isWebsiteOnline2($websiteUrl)) {
 <img alt="" border="0" src="https://www.paypal.com/en_SK/i/scr/pixel.gif" width="1" height="1" />
 </form>
       </p>
-      <p>
-       <center>
-         <img src="./Pictures/6brickcombo.png"/>
-       </center>
+      <p> 
+        <a href="">DOWNLOAD NOW</a>
       </p>
-      
-      
-    <a href="https://www.dpolakovic.space/Mars24.jar">DOWNLOAD NOW</a>
 
+
+      <br><br>
       </main>
 
     <!-- footer  -->
@@ -103,11 +102,7 @@ if (isWebsiteOnline2($websiteUrl)) {
     Copyright <?php printYear() ?> David Polakovic - 
     Content of this web is licensed under
     <a href="https://creativecommons.org/licenses/by-nc-nd/3.0/">CC BY-NC-ND 3.0</a>.
-    <br>
-    This site is javascript and cookie free. The source code is available
-    <a href="https://git.dpolakovic.space/?p=my-website;a=tree">here</a>
-    under
-    <a href="https://www.gnu.org/licenses/gpl-3.0.en.html">GPLv3 license</a>.
+    <br>rubdeansheadwaitundernewton
     </footer>
     
   </body>